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

@@ -63,6 +63,7 @@ async function installCodingFirstChatHost(
captured: CapturedRequest[];
conversationCreated: boolean;
interactionAnswered: boolean;
abortRequested: boolean;
releaseSnapshot: (() => void) | null;
snapshotPending: boolean;
};
@@ -73,6 +74,7 @@ async function installCodingFirstChatHost(
captured: [],
conversationCreated: false,
interactionAnswered: false,
abortRequested: false,
releaseSnapshot: null,
snapshotPending: false,
};
@@ -509,9 +511,44 @@ async function installCodingFirstChatHost(
state.snapshotPending = false;
}
return respond({
snapshot: state.interactionAnswered
? { ...snapshot, pendingInteractions: [] }
: snapshot,
snapshot: state.abortRequested
? {
...snapshot,
nodes: snapshot.nodes.map((node) => {
if (node.kind === 'message' && node.role === 'assistant') {
return {
...node,
status: 'aborted',
blocks: node.blocks.map((block) => ({ ...block, status: 'complete' })),
};
}
if (node.kind === 'subagent') {
return {
...node,
details: {
...node.details,
tasks: node.details.tasks.map((task) => (
task.status === 'running' ? { ...task, status: 'aborted' } : task
)),
},
};
}
return node;
}),
run: {
status: 'idle',
runId: 'run-e2e-feature',
mode: 'prompt',
settledAt: 12_000,
terminalReason: 'aborted',
},
queue: { items: [] },
pendingInteractions: [],
cursor: { workerGeneration: 1, seq: 1 },
}
: state.interactionAnswered
? { ...snapshot, pendingInteractions: [] }
: snapshot,
});
}
if (path === `/api/coding/conversations/${secondConversation.id}/snapshot`) {
@@ -531,7 +568,11 @@ async function installCodingFirstChatHost(
},
}, 202);
}
if (/^\/api\/coding\/conversations\/[^/]+\/(abort|compact|recover)$/.test(path) && method === 'POST') {
if (/^\/api\/coding\/conversations\/[^/]+\/abort$/.test(path) && method === 'POST') {
state.abortRequested = true;
return respond({});
}
if (/^\/api\/coding\/conversations\/[^/]+\/(compact|recover)$/.test(path) && method === 'POST') {
return respond({});
}
if (/^\/api\/coding\/conversations\/[^/]+\/model$/.test(path) && method === 'POST') {
@@ -712,9 +753,15 @@ test('PI feature UI isolates Conversations and exposes queue, interaction, model
]);
expect(titlebarBounds.every((bounds) => bounds?.y === 0 && bounds.height === 40)).toBe(true);
const logoBounds = await page.getByTestId('titlebar-logo').boundingBox();
const windowWidth = await page.evaluate(() => window.innerWidth);
expect(logoBounds).not.toBeNull();
expect(Math.abs((logoBounds!.x + logoBounds!.width) - windowWidth)).toBeLessThanOrEqual(1);
if (await page.evaluate(() => window.electron.platform === 'win32')) {
const minimizeBounds = await page.getByTitle('Minimize').boundingBox();
expect(minimizeBounds).not.toBeNull();
expect(logoBounds!.x + logoBounds!.width).toBeLessThanOrEqual(minimizeBounds!.x);
} else {
const windowWidth = await page.evaluate(() => window.innerWidth);
expect(Math.abs((logoBounds!.x + logoBounds!.width) - windowWidth)).toBeLessThanOrEqual(1);
}
const conversationHeader = page.getByTestId('coding-conversation-header');
await expect(conversationHeader).toContainText('新对话');
await expect(conversationHeader).not.toContainText('Pi ·');
@@ -837,6 +884,9 @@ test('PI feature UI isolates Conversations and exposes queue, interaction, model
await expect(runtimeSettings).not.toHaveClass(/bg-surface-subtle\/75/);
await expect(runtimeSettings).toBeDisabled();
await page.getByRole('button', { name: '中止', exact: true }).click();
await expect(page.getByRole('button', { name: '中止', exact: true })).toHaveCount(0);
await expect(composer.getByRole('button', { name: '中止生成' })).toHaveCount(0);
await expect(runtimeSettings).toBeEnabled();
const builderConversations = page.getByRole('group', { name: 'Builder 的对话' });
await expect(builderConversations).toBeVisible();
@@ -848,6 +898,7 @@ test('PI feature UI isolates Conversations and exposes queue, interaction, model
await expect(page.getByText('本地编程运行时暂时不可用')).toHaveCount(0);
await builderConversations.getByRole('button', { name: /^新对话/ }).click();
await expect(page.getByText('Durable user fork source')).toBeVisible();
await page.getByTestId('coding-process-group').locator('summary').first().click();
await expect(page.getByText('Durable assistant response')).toBeVisible();
await expect(page.getByRole('button', { name: '从这里创建新对话分支' })).toHaveCount(1);
await builderConversations.getByRole('button', { name: 'Second Conversation' }).click();