From 6605c4de48227148b29ee15a9bcd6a1a5b278179 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Tue, 8 Sep 2026 13:16:03 +0800 Subject: [PATCH] feat(plugin-manager): name the profile directory on install-log chunks Every chunk now carries the directory pnpm ran in beside its argv, so a renderer can say where the install lands. The generated event graph and the cordis API catalog follow the chunk type. --- ...-09-04-plugin-manager-over-the-profile-runtime.i18n.yaml | 4 ++-- .../2026-09-04-plugin-manager-over-the-profile-runtime.md | 2 +- ...2026-09-04-plugin-manager-over-the-profile-runtime.zh.md | 2 +- docs/event-producer-consumer.i18n.yaml | 4 ++-- docs/event-producer-consumer.md | 4 ++-- docs/event-producer-consumer.zh.md | 4 ++-- packages/boot/plugin-manager/README.i18n.yaml | 4 ++-- packages/boot/plugin-manager/README.md | 2 +- packages/boot/plugin-manager/README.zh.md | 2 +- packages/boot/plugin-manager/src/installer.ts | 6 +++--- packages/boot/plugin-manager/src/types.ts | 2 ++ packages/boot/plugin-manager/tests/plugin-manager.spec.ts | 6 +++--- packages/extensions/tool-cordis/src/api-catalog.ts | 2 +- 13 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.i18n.yaml b/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.i18n.yaml index eebfad4ff7..026e6b974c 100644 --- a/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.md -2026-09-04-plugin-manager-over-the-profile-runtime.md: 95153138b7d10ea6d13b96e815bd0a52c15d663e -2026-09-04-plugin-manager-over-the-profile-runtime.zh.md: 8f6794568f7aced809b44454b5192415c2ae097c +2026-09-04-plugin-manager-over-the-profile-runtime.md: 472d5655c069e45b8c966d82423558808862a48b +2026-09-04-plugin-manager-over-the-profile-runtime.zh.md: a5c368bacffd4c1b4668b48fa21c27052b1709c9 diff --git a/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.md b/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.md index 95153138b7..472d5655c0 100644 --- a/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.md +++ b/.agents/notes/implemented/architecture/2026-09-04-plugin-manager-over-the-profile-runtime.md @@ -14,7 +14,7 @@ Installing a plugin was a terminal-only act: `dsh plugin --profile web add config.installLogTailBytes && tail.length > 1) { tailBytes -= Buffer.byteLength(tail.shift() as string) } - this.options.installLog({ jobId, argv, spec, stream, text }) + this.options.installLog({ jobId, argv, cwd: profileDir, spec, stream, text }) } // Windows resolves pnpm through its .cmd shim, which spawn() refuses // without a shell since the CVE-2024-27980 hardening. The parent @@ -287,10 +287,10 @@ export class PluginInstaller { ).catch((error: unknown) => { const message = messageOf(error) record('stderr', `${message}\n`) - this.options.installLog({ jobId, argv, spec, stream: 'stderr', text: '', exitCode: null }) + this.options.installLog({ jobId, argv, cwd: profileDir, spec, stream: 'stderr', text: '', exitCode: null }) throw new PluginOperationError('plugins/install-failed', `${NAME}: ${message}`, { spec, exitCode: null, log: tail.join('') }, { cause: error }) }) - this.options.installLog({ jobId, argv, spec, stream: 'stdout', text: '', exitCode }) + this.options.installLog({ jobId, argv, cwd: profileDir, spec, stream: 'stdout', text: '', exitCode }) if (exitCode !== 0) { throw new PluginOperationError( 'plugins/install-failed', diff --git a/packages/boot/plugin-manager/src/types.ts b/packages/boot/plugin-manager/src/types.ts index a9521892f5..de0288a27e 100644 --- a/packages/boot/plugin-manager/src/types.ts +++ b/packages/boot/plugin-manager/src/types.ts @@ -190,6 +190,8 @@ export interface PluginInstallLogChunk { readonly jobId: string /** The command line the run executes: pnpm's command name, then its arguments. */ readonly argv: readonly string[] + /** The directory the run executes in: the profile directory. */ + readonly cwd: string /** The package spec the run installs or removes. */ readonly spec: string readonly stream: 'stdout' | 'stderr' diff --git a/packages/boot/plugin-manager/tests/plugin-manager.spec.ts b/packages/boot/plugin-manager/tests/plugin-manager.spec.ts index dfef45eb75..4e5ef782f7 100644 --- a/packages/boot/plugin-manager/tests/plugin-manager.spec.ts +++ b/packages/boot/plugin-manager/tests/plugin-manager.spec.ts @@ -575,9 +575,9 @@ describe('PluginManager', () => { // The fake pnpm records the spec itself as the dependency name, which // resolves to nothing: a plain dependency whose probe cannot run. expect(result).toEqual({ installed: ['github:acme/ext-new'], removed: [], enabled: [], installedOnly: [], plain: ['github:acme/ext-new'], jobId: expect.any(String) as string }) - expect(log.map(chunk => [chunk.argv, chunk.stream, chunk.text, chunk.exitCode])).toEqual([ - [['pnpm', 'add', 'github:acme/ext-new'], 'stdout', '+ github:acme/ext-new 1.0.0\n', undefined], - [['pnpm', 'add', 'github:acme/ext-new'], 'stdout', '', 0], + expect(log.map(chunk => [chunk.argv, chunk.cwd, chunk.stream, chunk.text, chunk.exitCode])).toEqual([ + [['pnpm', 'add', 'github:acme/ext-new'], staged.profileDir, 'stdout', '+ github:acme/ext-new 1.0.0\n', undefined], + [['pnpm', 'add', 'github:acme/ext-new'], staged.profileDir, 'stdout', '', 0], ]) expect(changes).toEqual([{ reason: 'install' }]) }) diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index 72a9b11413..1c7f60a910 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -4798,7 +4798,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'PluginInstallLogChunk', - declaration: 'export interface PluginInstallLogChunk {\n readonly jobId: string;\n readonly spec: string;\n readonly stream: \'stdout\' | \'stderr\';\n readonly text: string;\n readonly exitCode?: number | null;\n}', + declaration: 'export interface PluginInstallLogChunk {\n readonly jobId: string;\n readonly argv: readonly string[];\n readonly cwd: string;\n readonly spec: string;\n readonly stream: \'stdout\' | \'stderr\';\n readonly text: string;\n readonly exitCode?: number | null;\n}', }, { name: 'PluginInstallRejection',