merge: integrate remote and local main histories

# Conflicts:
#	.project-docs/20-architecture/module-map.md
#	.project-docs/30-worklog/current-state.md
#	.project-docs/50-evidence/evidence-index.md
#	src/pages/MyPlugins/index.tsx
#	tests/unit/pi-agent-server-process-real.test.ts
#	tests/unit/pi-managed-worker-opener.test.ts
#	tests/unit/plugin-marketplace-pages.test.tsx
This commit is contained in:
inman
2026-09-03 10:44:04 +08:00
122 changed files with 10866 additions and 436 deletions

View File

@@ -85,6 +85,9 @@ import {
} from './session-projector';
import { PiManagedExtensionHost } from './extension-host';
import type { PiSubagentScheduler } from './subagent';
import type { ModelToolRegistryPort } from './model-tools/model-tool-registry';
import type { DevicePackageManager } from '../../coding-packages/device-package-manager';
import type { CodingPluginToolDefinition } from '../../../shared/coding-plugins';
import type { CodingCapabilityRegistry, ResolvedWorkerResources } from '../../coding-plugins/registry';
import {
PiInteractionStore,
@@ -152,6 +155,9 @@ export interface PiManagedWorkerOpenerOptions {
onTelemetry?: (event: PiRuntimeTelemetryEvent) => void;
extensionHost: PiManagedExtensionHost;
capabilityRegistry?: CodingCapabilityRegistry;
modelToolRegistry?: ModelToolRegistryPort;
devicePackageManager?: Pick<DevicePackageManager, 'resolveEnabledResources' | 'registerActiveWorker'>;
devicePackageTools?: readonly CodingPluginToolDefinition[];
}
interface PiRpcSessionStateProjection {
@@ -253,12 +259,19 @@ export function createPiManagedWorkerOpener(
role: 'parent',
})
: fallbackWorkerResources(registered.agent.skillIds);
const deviceResources = options.devicePackageManager
? await options.devicePackageManager.resolveEnabledResources()
: undefined;
const combinedSkillEntries = [
...workerResources.skillEntries,
...(deviceResources?.skillEntries ?? []),
];
const resources = await materializePiAgentResources({
userDataDir: options.userDataDir,
projectId: input.conversation.projectId,
agentId: registered.agent.id,
prompt: registered.agent.prompt,
skillEntries: workerResources.skillEntries,
skillEntries: combinedSkillEntries,
catalogRevision: workerResources.catalogRevision,
bundledSkillsDir: options.bundledSkillsDir,
...(workerResources.skillRoots
@@ -267,6 +280,12 @@ export function createPiManagedWorkerOpener(
...(workerResources.effectiveSnapshot
? { effectiveSnapshot: workerResources.effectiveSnapshot }
: {}),
...(deviceResources
? {
devicePackageGeneration: deviceResources.generation,
devicePackageIds: deviceResources.packageIds,
}
: {}),
revision: input.revision,
});
const credential = await buildPiWorkerCredentialProjection({
@@ -277,19 +296,43 @@ export function createPiManagedWorkerOpener(
? { localProxyCredential: await options.getLocalProxyCredential() }
: {}),
});
const extension = await options.extensionHost.registerWorker({
const modelTools = options.modelToolRegistry?.registerWorker({
conversationId: input.conversation.conversationId,
generation: input.generation,
projectId: input.conversation.projectId,
projectPath: registered.projectPath,
skillEntries: workerResources.skillEntries,
catalogRevision: workerResources.catalogRevision,
tools: workerResources.tools,
...(workerResources.effectiveSnapshot
? { effectiveSnapshot: workerResources.effectiveSnapshot }
: {}),
extensionsDir: managedPaths.extensionsDir,
account,
descriptor,
selection,
credential,
});
let extension;
try {
extension = await options.extensionHost.registerWorker({
conversationId: input.conversation.conversationId,
generation: input.generation,
projectId: input.conversation.projectId,
projectPath: registered.projectPath,
skillEntries: combinedSkillEntries,
catalogRevision: workerResources.catalogRevision,
tools: [
...workerResources.tools,
...(modelTools?.tools ?? []),
...(options.devicePackageTools ?? []),
],
...(workerResources.effectiveSnapshot
? { effectiveSnapshot: workerResources.effectiveSnapshot }
: {}),
...(deviceResources
? {
devicePackageGeneration: deviceResources.generation,
devicePackageIds: deviceResources.packageIds,
}
: {}),
extensionsDir: managedPaths.extensionsDir,
});
} catch (error) {
modelTools?.dispose();
throw error;
}
recordManagedMilestone(
options.onTelemetry,
input,
@@ -317,6 +360,9 @@ export function createPiManagedWorkerOpener(
additionalArgs: [
...buildPiManagedInputArgs(selection, resources),
'--extension', extension.extensionPath,
...(deviceResources?.extensionPaths.flatMap((extensionPath) => [
'--extension', extensionPath,
]) ?? []),
...(input.fork ? ['--fork', input.fork.sourceSession.piSessionId] : []),
'--session-id', sessionKey,
],
@@ -328,6 +374,9 @@ export function createPiManagedWorkerOpener(
const releaseActivePluginReleases = workerResources.effectiveSnapshot
? options.registerActivePluginReleases?.(workerResources.effectiveSnapshot.pluginReleaseIds)
: undefined;
const releaseActiveDevicePackages = deviceResources
? options.devicePackageManager?.registerActiveWorker(deviceResources.packageRefs)
: undefined;
let managedResourcesDisposed = false;
const disposeManagedResources = async (): Promise<void> => {
if (managedResourcesDisposed) return;
@@ -335,7 +384,15 @@ export function createPiManagedWorkerOpener(
try {
await extension.dispose();
} finally {
await releaseActivePluginReleases?.();
try {
modelTools?.dispose();
} finally {
try {
await releaseActiveDevicePackages?.();
} finally {
await releaseActivePluginReleases?.();
}
}
}
};
let unsubscribeExtensionInvalidation = process.subscribeInvalidation(() => {
@@ -459,6 +516,7 @@ const PRODUCT_THINKING_LEVELS = new Set<ProductModelRef['thinkingLevel']>([
'low',
'medium',
'high',
'max',
]);
function productThinkingLevel(value: unknown): ProductModelRef['thinkingLevel'] | null {
@@ -1213,6 +1271,10 @@ export class PiConversationRuntime implements CodingConversationRuntime {
this.pool.markResourcesStale();
}
async refreshResources(): Promise<void> {
await this.pool.refreshResources();
}
subscribe(listener: (patch: ConversationPatchEnvelope) => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);