@clawling/clawchat-plugin-openclaw 2026.9.13-1 → 2026.9.13-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/account-config-writes.js +10 -9
- package/dist/src/account-removal.js +27 -4
- package/dist/src/channel.js +8 -1
- package/dist/src/channel.setup.js +9 -0
- package/dist/src/config.js +1 -1
- package/dist/src/liveware-cli.js +11 -0
- package/dist/src/login.runtime.js +2 -4
- package/package.json +1 -1
- package/src/account-config-writes.ts +10 -12
- package/src/account-removal.ts +28 -4
- package/src/channel.setup.ts +9 -0
- package/src/channel.ts +7 -1
- package/src/config.ts +2 -2
- package/src/liveware-cli.ts +12 -0
- package/src/liveware-sample.ts +4 -3
- package/src/login.runtime.ts +2 -4
|
@@ -19,19 +19,20 @@ function applyPatch(target, patch) {
|
|
|
19
19
|
return next;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* `
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* Dotted config path of the slot {@link patchOpenclawClawlingAccountSection}
|
|
23
|
+
* writes `accountId` into, for operator-facing logs. Default:
|
|
24
|
+
* `channels.<channel>` — or `channels.<channel>.accounts.default` once the
|
|
25
|
+
* host's single-account promotion created that entry. Named:
|
|
26
|
+
* `channels.<channel>.accounts.<key>` with the existing key spelling.
|
|
26
27
|
*/
|
|
27
|
-
export function
|
|
28
|
+
export function openclawClawlingAccountSlotPath(cfg, accountId) {
|
|
28
29
|
const id = normalizeOpenclawClawlingAccountId(accountId);
|
|
29
30
|
const section = readRecord(readRecord(cfg.channels)[CHANNEL_ID]);
|
|
30
|
-
const
|
|
31
|
-
const
|
|
31
|
+
const key = findAccountKey(readRecord(section.accounts), id);
|
|
32
|
+
const base = `channels.${CHANNEL_ID}`;
|
|
32
33
|
if (key !== undefined)
|
|
33
|
-
return
|
|
34
|
-
return id === DEFAULT_ACCOUNT_ID ?
|
|
34
|
+
return `${base}.accounts.${key}`;
|
|
35
|
+
return id === DEFAULT_ACCOUNT_ID ? base : `${base}.accounts.${id}`;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* The single config write point. Pure. Default → root section (or
|
|
@@ -1,21 +1,44 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import { normalizeOpenclawClawlingAccountId } from "./config.js";
|
|
3
|
+
import { livewareNamedAccountRootDir } from "./liveware-cli.js";
|
|
2
4
|
/**
|
|
3
5
|
* `openclaw channels remove --account <id> [--delete]` — the host has already
|
|
4
6
|
* rewritten the config (hybrid adapter) and stopped the account. Blank that
|
|
5
7
|
* account's SQLite credentials so a later start of the same id cannot resume
|
|
6
8
|
* the old identity from the row. Identity columns are kept (re-pair mode).
|
|
9
|
+
*
|
|
10
|
+
* A NAMED account also owns a private liveware root
|
|
11
|
+
* (`<stateDir>/clawchat/accounts/<id>/`: the CLI home holding the
|
|
12
|
+
* `$HOME/.clawling` login session, and the sample tree); the whole root is
|
|
13
|
+
* removed so the identity does not linger on disk. The `default` account's
|
|
14
|
+
* paths are the shared pre-multi-account layout and are never touched here.
|
|
15
|
+
* The host stops the account before this hook (best effort), so a still-open
|
|
16
|
+
* file only costs a log line.
|
|
7
17
|
*/
|
|
8
18
|
export function clearOpenclawClawlingAccountOnRemoval(params) {
|
|
9
19
|
const accountId = normalizeOpenclawClawlingAccountId(params.accountId);
|
|
10
20
|
if (!params.store) {
|
|
11
21
|
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite unavailable, nothing to clear`);
|
|
12
|
-
return;
|
|
13
22
|
}
|
|
23
|
+
else {
|
|
24
|
+
try {
|
|
25
|
+
params.store.clearActivationCredentials({ platform: "openclaw", accountId });
|
|
26
|
+
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite credentials cleared`);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite clear failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!params.stateDir)
|
|
33
|
+
return;
|
|
34
|
+
const dir = livewareNamedAccountRootDir(params.stateDir, accountId);
|
|
35
|
+
if (dir === null)
|
|
36
|
+
return;
|
|
37
|
+
const rm = params.rmFn ?? ((target) => fs.rmSync(target, { recursive: true, force: true }));
|
|
14
38
|
try {
|
|
15
|
-
|
|
16
|
-
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite credentials cleared`);
|
|
39
|
+
rm(dir);
|
|
17
40
|
}
|
|
18
41
|
catch (err) {
|
|
19
|
-
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed;
|
|
42
|
+
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; liveware directory ${dir} not removed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20
43
|
}
|
|
21
44
|
}
|
package/dist/src/channel.js
CHANGED
|
@@ -28,8 +28,14 @@ export const openclawClawlingPlugin = createChatChannelPlugin({
|
|
|
28
28
|
lifecycle: {
|
|
29
29
|
onAccountRemoved: ({ accountId, runtime }) => {
|
|
30
30
|
let store = null;
|
|
31
|
+
let stateDir;
|
|
32
|
+
try {
|
|
33
|
+
stateDir = getOpenclawClawlingRuntime().state?.resolveStateDir?.();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
stateDir = undefined;
|
|
37
|
+
}
|
|
31
38
|
try {
|
|
32
|
-
const stateDir = getOpenclawClawlingRuntime().state?.resolveStateDir?.();
|
|
33
39
|
store = getClawChatStore({
|
|
34
40
|
...(stateDir ? { dbPath: clawChatDbPathForStateDir(stateDir) } : {}),
|
|
35
41
|
log: { error: (message) => runtime.error(message) },
|
|
@@ -41,6 +47,7 @@ export const openclawClawlingPlugin = createChatChannelPlugin({
|
|
|
41
47
|
clearOpenclawClawlingAccountOnRemoval({
|
|
42
48
|
accountId,
|
|
43
49
|
store,
|
|
50
|
+
stateDir,
|
|
44
51
|
log: (message) => runtime.log(message),
|
|
45
52
|
});
|
|
46
53
|
},
|
|
@@ -46,14 +46,23 @@ const configAdapter = {
|
|
|
46
46
|
* `configured: true` again on the next gateway start. Clear the same keys
|
|
47
47
|
* from the promoted entry so `--delete` actually deletes. Named ids are the
|
|
48
48
|
* SDK's alone — it removes the whole `accounts.<id>` entry.
|
|
49
|
+
*
|
|
50
|
+
* Guard: a config with no channel section has nothing to clear, and the
|
|
51
|
+
* patch write would otherwise materialize an empty section out of nothing.
|
|
49
52
|
*/
|
|
50
53
|
deleteAccount: (args) => {
|
|
51
54
|
const next = hybridConfigAdapter.deleteAccount?.(args) ?? args.cfg;
|
|
52
55
|
if (normalizeOpenclawClawlingAccountId(args.accountId) !== DEFAULT_ACCOUNT_ID)
|
|
53
56
|
return next;
|
|
57
|
+
if (!hasOpenclawClawlingChannelSection(next))
|
|
58
|
+
return next;
|
|
54
59
|
return patchOpenclawClawlingAccountSection(next, DEFAULT_ACCOUNT_ID, CLEAR_BASE_FIELDS_PATCH);
|
|
55
60
|
},
|
|
56
61
|
};
|
|
62
|
+
function hasOpenclawClawlingChannelSection(cfg) {
|
|
63
|
+
const section = cfg.channels?.[CHANNEL_ID];
|
|
64
|
+
return Boolean(section) && typeof section === "object" && !Array.isArray(section);
|
|
65
|
+
}
|
|
57
66
|
function readInviteCode(input) {
|
|
58
67
|
return typeof input.code === "string" && input.code.trim()
|
|
59
68
|
? input.code.trim()
|
package/dist/src/config.js
CHANGED
|
@@ -230,7 +230,7 @@ export function readOpenclawClawlingAccountSection(cfg, accountId) {
|
|
|
230
230
|
channelConfig: root,
|
|
231
231
|
accountConfig: entry ?? {},
|
|
232
232
|
omitKeys,
|
|
233
|
-
nestedObjectKeys: NESTED_ACCOUNT_OBJECT_KEYS,
|
|
233
|
+
nestedObjectKeys: [...NESTED_ACCOUNT_OBJECT_KEYS],
|
|
234
234
|
});
|
|
235
235
|
}
|
|
236
236
|
const accountListHelpers = createAccountListHelpers(CHANNEL_ID, {
|
package/dist/src/liveware-cli.js
CHANGED
|
@@ -26,6 +26,17 @@ function livewareAccountRoot(stateDir, accountId) {
|
|
|
26
26
|
? path.join(root, "clawchat")
|
|
27
27
|
: path.join(root, "clawchat", "accounts", id);
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Root of a NAMED account's private liveware state
|
|
31
|
+
* (`<stateDir>/clawchat/accounts/<id>`), the directory account removal
|
|
32
|
+
* deletes wholesale. Returns null for `default`, whose root is the shared
|
|
33
|
+
* `<stateDir>/clawchat` and must never be removed this way.
|
|
34
|
+
*/
|
|
35
|
+
export function livewareNamedAccountRootDir(stateDir, accountId) {
|
|
36
|
+
return normalizeOpenclawClawlingAccountId(accountId) === DEFAULT_ACCOUNT_ID
|
|
37
|
+
? null
|
|
38
|
+
: livewareAccountRoot(stateDir, accountId);
|
|
39
|
+
}
|
|
29
40
|
/**
|
|
30
41
|
* Private HOME for the liveware CLI: `<stateDir>/clawchat/liveware-home` for
|
|
31
42
|
* the default account, `<stateDir>/clawchat/accounts/<id>/liveware-home` for a
|
|
@@ -2,7 +2,7 @@ import { createInterface } from "node:readline/promises";
|
|
|
2
2
|
import { createOpenclawClawlingApiClient } from "./api-client.js";
|
|
3
3
|
import { ClawlingApiError } from "./api-types.js";
|
|
4
4
|
import { resolvePluginVersion } from "./plugin-report.js";
|
|
5
|
-
import { patchOpenclawClawlingAccountSection } from "./account-config-writes.js";
|
|
5
|
+
import { openclawClawlingAccountSlotPath, patchOpenclawClawlingAccountSection } from "./account-config-writes.js";
|
|
6
6
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
|
|
7
7
|
import { CHANNEL_ID, mergeOpenclawClawchatRuntimePluginActivation, mergeOpenclawClawchatToolAllow, normalizeOpenclawClawlingAccountId, readOpenclawClawlingAccountSection, resolveOpenclawClawlingAccount, } from "./config.js";
|
|
8
8
|
import { getClawChatStore } from "./storage.js";
|
|
@@ -310,9 +310,7 @@ export async function runOpenclawClawlingLogin(params) {
|
|
|
310
310
|
}
|
|
311
311
|
: {}),
|
|
312
312
|
};
|
|
313
|
-
const configPath = accountId
|
|
314
|
-
? `channels.${CHANNEL_ID}`
|
|
315
|
-
: `channels.${CHANNEL_ID}.accounts.${accountId}`;
|
|
313
|
+
const configPath = openclawClawlingAccountSlotPath(params.cfg, accountId);
|
|
316
314
|
runtime.log(`Updating config: ${configPath}.token=[REDACTED] agentId=${normalizedResult.agent.id || "-"} userId=${normalizedResult.agent.user_id} ownerUserId=${normalizedResult.agent.owner_id}${normalizedResult.refresh_token ? " refreshToken=[REDACTED]" : ""} plugins.entries.${CHANNEL_ID}.enabled=true plugins.allow+=${CHANNEL_ID} …`);
|
|
317
315
|
await persistLoginConfig(accountId, params, normalizedResult);
|
|
318
316
|
try {
|
package/package.json
CHANGED
|
@@ -22,21 +22,19 @@ function applyPatch(target: Record<string, unknown>, patch: Record<string, unkno
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* `
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* Dotted config path of the slot {@link patchOpenclawClawlingAccountSection}
|
|
26
|
+
* writes `accountId` into, for operator-facing logs. Default:
|
|
27
|
+
* `channels.<channel>` — or `channels.<channel>.accounts.default` once the
|
|
28
|
+
* host's single-account promotion created that entry. Named:
|
|
29
|
+
* `channels.<channel>.accounts.<key>` with the existing key spelling.
|
|
29
30
|
*/
|
|
30
|
-
export function
|
|
31
|
-
cfg: OpenClawConfig,
|
|
32
|
-
accountId?: string | null,
|
|
33
|
-
): Record<string, unknown> {
|
|
31
|
+
export function openclawClawlingAccountSlotPath(cfg: OpenClawConfig, accountId?: string | null): string {
|
|
34
32
|
const id = normalizeOpenclawClawlingAccountId(accountId);
|
|
35
33
|
const section = readRecord(readRecord((cfg as { channels?: unknown }).channels)[CHANNEL_ID]);
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
if (key !== undefined) return
|
|
39
|
-
return id === DEFAULT_ACCOUNT_ID ?
|
|
34
|
+
const key = findAccountKey(readRecord(section.accounts), id);
|
|
35
|
+
const base = `channels.${CHANNEL_ID}`;
|
|
36
|
+
if (key !== undefined) return `${base}.accounts.${key}`;
|
|
37
|
+
return id === DEFAULT_ACCOUNT_ID ? base : `${base}.accounts.${id}`;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
/**
|
package/src/account-removal.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import { normalizeOpenclawClawlingAccountId } from "./config.ts";
|
|
3
|
+
import { livewareNamedAccountRootDir } from "./liveware-cli.ts";
|
|
2
4
|
import type { ClawChatStore } from "./storage.ts";
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -6,23 +8,45 @@ import type { ClawChatStore } from "./storage.ts";
|
|
|
6
8
|
* rewritten the config (hybrid adapter) and stopped the account. Blank that
|
|
7
9
|
* account's SQLite credentials so a later start of the same id cannot resume
|
|
8
10
|
* the old identity from the row. Identity columns are kept (re-pair mode).
|
|
11
|
+
*
|
|
12
|
+
* A NAMED account also owns a private liveware root
|
|
13
|
+
* (`<stateDir>/clawchat/accounts/<id>/`: the CLI home holding the
|
|
14
|
+
* `$HOME/.clawling` login session, and the sample tree); the whole root is
|
|
15
|
+
* removed so the identity does not linger on disk. The `default` account's
|
|
16
|
+
* paths are the shared pre-multi-account layout and are never touched here.
|
|
17
|
+
* The host stops the account before this hook (best effort), so a still-open
|
|
18
|
+
* file only costs a log line.
|
|
9
19
|
*/
|
|
10
20
|
export function clearOpenclawClawlingAccountOnRemoval(params: {
|
|
11
21
|
accountId: string;
|
|
12
22
|
store: Pick<ClawChatStore, "clearActivationCredentials"> | null;
|
|
23
|
+
/** Resolved OpenClaw state dir; absent → liveware directories are left alone. */
|
|
24
|
+
stateDir?: string | null;
|
|
13
25
|
log?: (message: string) => void;
|
|
26
|
+
rmFn?: (dir: string) => void;
|
|
14
27
|
}): void {
|
|
15
28
|
const accountId = normalizeOpenclawClawlingAccountId(params.accountId);
|
|
16
29
|
if (!params.store) {
|
|
17
30
|
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite unavailable, nothing to clear`);
|
|
18
|
-
|
|
31
|
+
} else {
|
|
32
|
+
try {
|
|
33
|
+
params.store.clearActivationCredentials({ platform: "openclaw", accountId });
|
|
34
|
+
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite credentials cleared`);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
params.log?.(
|
|
37
|
+
`[${accountId}] clawchat-plugin-openclaw account removed; sqlite clear failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
19
40
|
}
|
|
41
|
+
if (!params.stateDir) return;
|
|
42
|
+
const dir = livewareNamedAccountRootDir(params.stateDir, accountId);
|
|
43
|
+
if (dir === null) return;
|
|
44
|
+
const rm = params.rmFn ?? ((target: string) => fs.rmSync(target, { recursive: true, force: true }));
|
|
20
45
|
try {
|
|
21
|
-
|
|
22
|
-
params.log?.(`[${accountId}] clawchat-plugin-openclaw account removed; sqlite credentials cleared`);
|
|
46
|
+
rm(dir);
|
|
23
47
|
} catch (err) {
|
|
24
48
|
params.log?.(
|
|
25
|
-
`[${accountId}] clawchat-plugin-openclaw account removed;
|
|
49
|
+
`[${accountId}] clawchat-plugin-openclaw account removed; liveware directory ${dir} not removed: ${err instanceof Error ? err.message : String(err)}`,
|
|
26
50
|
);
|
|
27
51
|
}
|
|
28
52
|
}
|
package/src/channel.setup.ts
CHANGED
|
@@ -67,14 +67,23 @@ const configAdapter: typeof hybridConfigAdapter = {
|
|
|
67
67
|
* `configured: true` again on the next gateway start. Clear the same keys
|
|
68
68
|
* from the promoted entry so `--delete` actually deletes. Named ids are the
|
|
69
69
|
* SDK's alone — it removes the whole `accounts.<id>` entry.
|
|
70
|
+
*
|
|
71
|
+
* Guard: a config with no channel section has nothing to clear, and the
|
|
72
|
+
* patch write would otherwise materialize an empty section out of nothing.
|
|
70
73
|
*/
|
|
71
74
|
deleteAccount: (args) => {
|
|
72
75
|
const next = hybridConfigAdapter.deleteAccount?.(args) ?? args.cfg;
|
|
73
76
|
if (normalizeOpenclawClawlingAccountId(args.accountId) !== DEFAULT_ACCOUNT_ID) return next;
|
|
77
|
+
if (!hasOpenclawClawlingChannelSection(next)) return next;
|
|
74
78
|
return patchOpenclawClawlingAccountSection(next, DEFAULT_ACCOUNT_ID, CLEAR_BASE_FIELDS_PATCH);
|
|
75
79
|
},
|
|
76
80
|
};
|
|
77
81
|
|
|
82
|
+
function hasOpenclawClawlingChannelSection(cfg: OpenClawConfig): boolean {
|
|
83
|
+
const section = (cfg as { channels?: Record<string, unknown> }).channels?.[CHANNEL_ID];
|
|
84
|
+
return Boolean(section) && typeof section === "object" && !Array.isArray(section);
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
function readInviteCode(input: ChannelSetupInput): string {
|
|
79
88
|
return typeof input.code === "string" && input.code.trim()
|
|
80
89
|
? input.code.trim()
|
package/src/channel.ts
CHANGED
|
@@ -38,8 +38,13 @@ export const openclawClawlingPlugin: ChannelPlugin<ResolvedOpenclawClawlingAccou
|
|
|
38
38
|
lifecycle: {
|
|
39
39
|
onAccountRemoved: ({ accountId, runtime }) => {
|
|
40
40
|
let store: ReturnType<typeof getClawChatStore> | null = null;
|
|
41
|
+
let stateDir: string | undefined;
|
|
42
|
+
try {
|
|
43
|
+
stateDir = getOpenclawClawlingRuntime().state?.resolveStateDir?.();
|
|
44
|
+
} catch {
|
|
45
|
+
stateDir = undefined;
|
|
46
|
+
}
|
|
41
47
|
try {
|
|
42
|
-
const stateDir = getOpenclawClawlingRuntime().state?.resolveStateDir?.();
|
|
43
48
|
store = getClawChatStore({
|
|
44
49
|
...(stateDir ? { dbPath: clawChatDbPathForStateDir(stateDir) } : {}),
|
|
45
50
|
log: { error: (message: string) => runtime.error(message) },
|
|
@@ -50,6 +55,7 @@ export const openclawClawlingPlugin: ChannelPlugin<ResolvedOpenclawClawlingAccou
|
|
|
50
55
|
clearOpenclawClawlingAccountOnRemoval({
|
|
51
56
|
accountId,
|
|
52
57
|
store,
|
|
58
|
+
stateDir,
|
|
53
59
|
log: (message) => runtime.log(message),
|
|
54
60
|
});
|
|
55
61
|
},
|
package/src/config.ts
CHANGED
|
@@ -342,7 +342,7 @@ function readChannelSection(cfg: OpenClawConfig): Record<string, unknown> {
|
|
|
342
342
|
/** Keys that identify a ClawChat account. Never inherited by a named account from the root. */
|
|
343
343
|
export const ACCOUNT_CREDENTIAL_KEYS = ["token", "refreshToken", "agentId", "userId", "ownerUserId"] as const;
|
|
344
344
|
const ACCOUNT_MAP_KEYS = ["accounts", "defaultAccount"] as const;
|
|
345
|
-
const NESTED_ACCOUNT_OBJECT_KEYS = ["reconnect", "heartbeat", "ack"];
|
|
345
|
+
const NESTED_ACCOUNT_OBJECT_KEYS = ["reconnect", "heartbeat", "ack"] as const;
|
|
346
346
|
|
|
347
347
|
/** Host-identical account id normalization (lowercase, `[^a-z0-9_-]` → `-`, blank → `default`). */
|
|
348
348
|
export function normalizeOpenclawClawlingAccountId(value?: string | null): string {
|
|
@@ -381,7 +381,7 @@ export function readOpenclawClawlingAccountSection(
|
|
|
381
381
|
channelConfig: root,
|
|
382
382
|
accountConfig: entry ?? {},
|
|
383
383
|
omitKeys,
|
|
384
|
-
nestedObjectKeys: NESTED_ACCOUNT_OBJECT_KEYS,
|
|
384
|
+
nestedObjectKeys: [...NESTED_ACCOUNT_OBJECT_KEYS],
|
|
385
385
|
});
|
|
386
386
|
}
|
|
387
387
|
|
package/src/liveware-cli.ts
CHANGED
|
@@ -37,6 +37,18 @@ function livewareAccountRoot(stateDir: string | undefined, accountId?: string |
|
|
|
37
37
|
: path.join(root, "clawchat", "accounts", id);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Root of a NAMED account's private liveware state
|
|
42
|
+
* (`<stateDir>/clawchat/accounts/<id>`), the directory account removal
|
|
43
|
+
* deletes wholesale. Returns null for `default`, whose root is the shared
|
|
44
|
+
* `<stateDir>/clawchat` and must never be removed this way.
|
|
45
|
+
*/
|
|
46
|
+
export function livewareNamedAccountRootDir(stateDir: string, accountId?: string | null): string | null {
|
|
47
|
+
return normalizeOpenclawClawlingAccountId(accountId) === DEFAULT_ACCOUNT_ID
|
|
48
|
+
? null
|
|
49
|
+
: livewareAccountRoot(stateDir, accountId);
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
/**
|
|
41
53
|
* Private HOME for the liveware CLI: `<stateDir>/clawchat/liveware-home` for
|
|
42
54
|
* the default account, `<stateDir>/clawchat/accounts/<id>/liveware-home` for a
|
package/src/liveware-sample.ts
CHANGED
|
@@ -716,9 +716,10 @@ export type LivewareSampleSupervisorDeps = {
|
|
|
716
716
|
ref?: string;
|
|
717
717
|
spawnFn?: SpawnLike;
|
|
718
718
|
execFileFn?: ExecFileLike;
|
|
719
|
-
/** Private HOME for the liveware CLI (`livewareCliHomeDir(stateDir)`),
|
|
720
|
-
* instances on one host
|
|
721
|
-
* inherits the ambient HOME, which
|
|
719
|
+
/** Private HOME for the liveware CLI (`livewareCliHomeDir(stateDir, accountId)`),
|
|
720
|
+
* so two instances on one host — or two accounts in one gateway — do not
|
|
721
|
+
* share `$HOME/.clawling`. Absent → the CLI inherits the ambient HOME, which
|
|
722
|
+
* is the pre-isolation behavior. */
|
|
722
723
|
cliHome?: string;
|
|
723
724
|
probePortFn?: ProbePortLike;
|
|
724
725
|
log?: LivewareLogger;
|
package/src/login.runtime.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
|
3
3
|
import { createOpenclawClawlingApiClient } from "./api-client.ts";
|
|
4
4
|
import { ClawlingApiError, type AgentConnectResult } from "./api-types.ts";
|
|
5
5
|
import { resolvePluginVersion } from "./plugin-report.ts";
|
|
6
|
-
import { patchOpenclawClawlingAccountSection } from "./account-config-writes.ts";
|
|
6
|
+
import { openclawClawlingAccountSlotPath, patchOpenclawClawlingAccountSection } from "./account-config-writes.ts";
|
|
7
7
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
|
|
8
8
|
import {
|
|
9
9
|
CHANNEL_ID,
|
|
@@ -408,9 +408,7 @@ export async function runOpenclawClawlingLogin(params: LoginParams): Promise<voi
|
|
|
408
408
|
: {}),
|
|
409
409
|
};
|
|
410
410
|
|
|
411
|
-
const configPath = accountId
|
|
412
|
-
? `channels.${CHANNEL_ID}`
|
|
413
|
-
: `channels.${CHANNEL_ID}.accounts.${accountId}`;
|
|
411
|
+
const configPath = openclawClawlingAccountSlotPath(params.cfg, accountId);
|
|
414
412
|
runtime.log(
|
|
415
413
|
`Updating config: ${configPath}.token=[REDACTED] agentId=${normalizedResult.agent.id || "-"} userId=${normalizedResult.agent.user_id} ownerUserId=${normalizedResult.agent.owner_id}${
|
|
416
414
|
normalizedResult.refresh_token ? " refreshToken=[REDACTED]" : ""
|