Skip to content

Commit 55d1990

Browse files
fix: keep lifecycle helpers runtime-free
1 parent e024155 commit 55d1990

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

‎packages/agent-bundle/src/install/state-root.ts‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1+
import { createHash } from 'node:crypto';
12
import { readFile, realpath } from 'node:fs/promises';
2-
import { isAbsolute, join, resolve } from 'node:path';
3-
4-
import {
5-
PLUGIN_STATE_ROOT_ENV_ANCHOR,
6-
userDataStateRoot,
7-
} from '@agent-bundle/runtime';
3+
import { basename, isAbsolute, join, resolve } from 'node:path';
84

95
import { isErrno } from '../core/errors.ts';
6+
import { pluginStateRootEnvAnchor } from '../core/types.ts';
107
import { webPluginDataRoot } from '../web-host/launch.ts';
118
import type { InstallHost } from './install.ts';
129

@@ -33,6 +30,24 @@ const manifestCandidates = (host: InstallHost): readonly string[] => {
3330
const isRecord = (value: unknown): value is Record<string, unknown> =>
3431
value !== null && typeof value === 'object' && !Array.isArray(value);
3532

33+
const safePluginSegment = /^[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?$/u;
34+
35+
// The CLI cannot load the optional React runtime. Uninstall tests pin this spelling against
36+
// `userDataStateRoot` from @agent-bundle/runtime for real installed roots.
37+
const installedUserDataStateRoot = (
38+
canonicalRoot: string,
39+
environment: Readonly<NodeJS.ProcessEnv>,
40+
home: string,
41+
): string => {
42+
const xdgStateHome = environment.XDG_STATE_HOME ?? '';
43+
const stateHome = isAbsolute(xdgStateHome)
44+
? join(xdgStateHome, 'agent-bundle')
45+
: join(home, '.agent-bundle', 'state');
46+
const digest = createHash('sha256').update(canonicalRoot).digest('hex').slice(0, 16);
47+
const name = basename(canonicalRoot);
48+
return join(stateHome, safePluginSegment.test(name) ? `${name}-${digest}` : `plugin-${digest}`);
49+
};
50+
3651
const declaredStateRoot = async (pluginRoot: string, host: InstallHost): Promise<string | undefined> => {
3752
for (const relativePath of manifestCandidates(host)) {
3853
let document: unknown;
@@ -45,7 +60,7 @@ const declaredStateRoot = async (pluginRoot: string, host: InstallHost): Promise
4560
if (!isRecord(document) || !isRecord(document['mcpServers'])) continue;
4661
for (const server of Object.values(document['mcpServers'])) {
4762
if (!isRecord(server) || !isRecord(server['env'])) continue;
48-
const declared = server['env'][PLUGIN_STATE_ROOT_ENV_ANCHOR];
63+
const declared = server['env'][pluginStateRootEnvAnchor];
4964
if (typeof declared !== 'string' || declared.trim() === '') continue;
5065
const expanded = declared
5166
.replaceAll('${CLAUDE_PLUGIN_ROOT}', pluginRoot)
@@ -69,13 +84,13 @@ export const resolveInstalledStateRoot = async (
6984
throw error;
7085
});
7186
const fromManifest = await declaredStateRoot(canonicalRoot, host);
72-
const inherited = environment[PLUGIN_STATE_ROOT_ENV_ANCHOR] ?? '';
87+
const inherited = environment[pluginStateRootEnvAnchor] ?? '';
7388
const expandedInherited = inherited.trim() === '' || /\$\{[^}]*\}/u.test(inherited)
7489
? undefined
7590
: isAbsolute(inherited) ? resolve(inherited) : resolve(canonicalRoot, inherited);
7691
const declared = fromManifest ?? expandedInherited;
7792
return Object.freeze(declared === undefined
78-
? { root: userDataStateRoot(canonicalRoot, environment, home), source: 'derived' as const }
93+
? { root: installedUserDataStateRoot(canonicalRoot, environment, home), source: 'derived' as const }
7994
: { root: declared, source: 'native' as const });
8095
};
8196

‎packages/agent-bundle/tests/host-install-proof.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ codexPluginIt(
561561
keepData: 'unavailable',
562562
plan: 'no-op',
563563
proofLevel: proofLabel,
564-
purgeData: 'removed-by-host',
564+
purgeData: 'purged',
565565
refusals: { foreignOrMismatch: 'AB7007', missingReceipt: 'AB7009', unconfirmedPurge: 'AB7008' },
566566
registrations: { 'codex-marketplace': 'removed', 'codex-plugin': 'removed' },
567567
rerun: 'not-installed',

0 commit comments

Comments
 (0)