@pi-harness/pi-harness 0.1.6 → 0.1.8
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/apps/web/dist/assets/index-CCZGqUaU.css +2 -0
- package/apps/web/dist/assets/index-DZjjpslQ.js +20 -0
- package/apps/web/dist/index.html +2 -2
- package/apps/web/package.json +6 -6
- package/apps/web/src/style.css +159 -45
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
- package/node_modules/@pi-harness/api-gateway/package.json +1 -1
- package/node_modules/@pi-harness/cli/package.json +1 -1
- package/node_modules/@pi-harness/core/package.json +1 -1
- package/node_modules/@pi-harness/host-webserver/package.json +1 -1
- package/node_modules/@pi-harness/web-app/package.json +1 -1
- package/package.json +6 -6
- package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/context.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
- package/packages/api-gateway/package.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/annotation.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/archify.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/at-file.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/context.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/genui.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/memory.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/modlens.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/module-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/openpets.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-export.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/synapse.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/web-research.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +1 -1
- package/packages/bundle-web-app/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/client-web/dist/plugin-card.d.ts +8 -0
- package/packages/client-web/dist/plugin-card.d.ts.map +1 -0
- package/packages/client-web/dist/plugin-card.js +15 -0
- package/packages/client-web/dist/plugin-card.js.map +1 -0
- package/packages/client-web/dist/react-room.d.ts.map +1 -1
- package/packages/client-web/dist/react-room.js +134 -42
- package/packages/client-web/dist/react-room.js.map +1 -1
- package/packages/client-web/package.json +1 -1
- package/packages/client-web/src/plugin-card.ts +22 -0
- package/packages/client-web/src/react-room.tsx +254 -102
- package/packages/client-web/test/plugin-card.test.ts +46 -0
- package/packages/core/package.json +1 -1
- package/packages/host-webserver/package.json +1 -1
- package/apps/web/dist/assets/index-CihATCjR.css +0 -2
- package/apps/web/dist/assets/index-CxqGqqZh.js +0 -20
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ClientMarketplacePlugin, ClientPlugin } from "./control-room.js";
|
|
2
|
+
|
|
3
|
+
export interface InstalledPluginCardContent {
|
|
4
|
+
readonly packageLabel: string;
|
|
5
|
+
readonly description: string;
|
|
6
|
+
readonly tags: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function installedPluginCardContent(plugin: ClientPlugin, metadata: ClientMarketplacePlugin | undefined): InstalledPluginCardContent {
|
|
10
|
+
if (metadata) {
|
|
11
|
+
return {
|
|
12
|
+
packageLabel: `${plugin.name} · v${metadata.version}`,
|
|
13
|
+
description: metadata.description,
|
|
14
|
+
tags: [...metadata.capabilities, ...metadata.hooks.map((hook) => `hook:${hook}`)],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
packageLabel: plugin.name,
|
|
19
|
+
description: plugin.enabled ? "由当前运行时加载并启用,能力与 hook 已注册。" : "由当前运行时加载但已停用。",
|
|
20
|
+
tags: ["loader", plugin.state === "active" ? "active" : `state:${plugin.state}`],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -26,7 +26,8 @@ import { loadMarketplaceCatalog } from "./marketplace-catalog.js";
|
|
|
26
26
|
import { pluginStarsRows } from "./plugin-stars-view.js";
|
|
27
27
|
import { browserSessionTabs } from "./browser-session-view.js";
|
|
28
28
|
import { matchesPluginQuery } from "./plugin-search.js";
|
|
29
|
-
import {
|
|
29
|
+
import { readInstalledPluginDetailId } from "./plugin-navigation.js";
|
|
30
|
+
import { installedPluginCardContent } from "./plugin-card.js";
|
|
30
31
|
|
|
31
32
|
export type { ClientApi } from "./control-room.js";
|
|
32
33
|
|
|
@@ -740,12 +741,12 @@ function Details({ event, onClose, onCopy }: { event: Record<string, unknown> |
|
|
|
740
741
|
<aside className="details-panel">
|
|
741
742
|
<header>
|
|
742
743
|
<strong>{eventLabel(event)}</strong>
|
|
743
|
-
<button aria-label="关闭事件详情" onClick={onClose} type="button">
|
|
744
|
+
<button aria-label={fileDetail ? "关闭文件差异" : "关闭事件详情"} onClick={onClose} type="button">
|
|
744
745
|
×
|
|
745
746
|
</button>
|
|
746
747
|
</header>
|
|
747
748
|
<div className="details-body">
|
|
748
|
-
<div className=
|
|
749
|
+
<div className={`detail-stats ${fileDetail ? "is-file" : ""}`}>
|
|
749
750
|
{stats.map(([key, item]) => (
|
|
750
751
|
<div key={key}>
|
|
751
752
|
<small>{key}</small>
|
|
@@ -844,11 +845,22 @@ function Trajectory({ events, onSelect }: { events: readonly Record<string, unkn
|
|
|
844
845
|
);
|
|
845
846
|
}
|
|
846
847
|
|
|
847
|
-
function Files({
|
|
848
|
+
function Files({
|
|
849
|
+
files,
|
|
850
|
+
api,
|
|
851
|
+
onDiff,
|
|
852
|
+
onRefresh,
|
|
853
|
+
}: {
|
|
854
|
+
files: readonly ClientFile[];
|
|
855
|
+
api: ClientApi;
|
|
856
|
+
onDiff: (path: string) => Promise<void>;
|
|
857
|
+
onRefresh: () => void;
|
|
858
|
+
}) {
|
|
848
859
|
const additions = files.filter((file) => file.status.includes("A") || file.status === "??").length;
|
|
849
860
|
const deletions = files.filter((file) => file.status.includes("D")).length;
|
|
850
861
|
const [message, setMessage] = useState("");
|
|
851
862
|
const [busy, setBusy] = useState(false);
|
|
863
|
+
const [diffPending, setDiffPending] = useState<string>();
|
|
852
864
|
const [error, setError] = useState("");
|
|
853
865
|
const [revertConfirmOpen, setRevertConfirmOpen] = useState(false);
|
|
854
866
|
const commit = () => {
|
|
@@ -879,6 +891,14 @@ function Files({ files, api, onDiff, onRefresh }: { files: readonly ClientFile[]
|
|
|
879
891
|
.catch((cause: unknown) => setError(cause instanceof Error ? cause.message : String(cause)))
|
|
880
892
|
.finally(() => setBusy(false));
|
|
881
893
|
};
|
|
894
|
+
const openDiff = (path: string) => {
|
|
895
|
+
if (busy || diffPending) return;
|
|
896
|
+
setDiffPending(path);
|
|
897
|
+
setError("");
|
|
898
|
+
void onDiff(path)
|
|
899
|
+
.catch((cause: unknown) => setError(cause instanceof Error ? cause.message : String(cause)))
|
|
900
|
+
.finally(() => setDiffPending(undefined));
|
|
901
|
+
};
|
|
882
902
|
return (
|
|
883
903
|
<section className="view-panel files-view">
|
|
884
904
|
<div className="files-content">
|
|
@@ -894,8 +914,14 @@ function Files({ files, api, onDiff, onRefresh }: { files: readonly ClientFile[]
|
|
|
894
914
|
<b className={`file-kind ${file.label === "untracked" ? "new" : ""}`}>{file.label}</b>
|
|
895
915
|
<code>{file.path}</code>
|
|
896
916
|
<span className={file.status.includes("D") ? "del" : "add"}>{file.status}</span>
|
|
897
|
-
<button
|
|
898
|
-
|
|
917
|
+
<button
|
|
918
|
+
aria-label={`${diffPending === file.path ? "正在读取" : "查看"}${file.path}的差异`}
|
|
919
|
+
className="diff-button"
|
|
920
|
+
disabled={busy || diffPending !== undefined}
|
|
921
|
+
onClick={() => openDiff(file.path)}
|
|
922
|
+
type="button"
|
|
923
|
+
>
|
|
924
|
+
{diffPending === file.path ? "读取中…" : "查看差异"}
|
|
899
925
|
</button>
|
|
900
926
|
</div>
|
|
901
927
|
))
|
|
@@ -4070,6 +4096,77 @@ function PluginUninstallDialog({
|
|
|
4070
4096
|
);
|
|
4071
4097
|
}
|
|
4072
4098
|
|
|
4099
|
+
function PluginCategoryNav({
|
|
4100
|
+
label,
|
|
4101
|
+
categories,
|
|
4102
|
+
activeCategory,
|
|
4103
|
+
onChange,
|
|
4104
|
+
}: {
|
|
4105
|
+
label: string;
|
|
4106
|
+
categories: readonly ClientMarketplaceCategory[];
|
|
4107
|
+
activeCategory: string;
|
|
4108
|
+
onChange: (category: string) => void;
|
|
4109
|
+
}) {
|
|
4110
|
+
const navRef = useRef<HTMLElement>(null);
|
|
4111
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
4112
|
+
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
4113
|
+
const updateScrollState = useCallback(() => {
|
|
4114
|
+
const nav = navRef.current;
|
|
4115
|
+
if (!nav) return;
|
|
4116
|
+
const maximum = Math.max(0, nav.scrollWidth - nav.clientWidth);
|
|
4117
|
+
setCanScrollLeft(nav.scrollLeft > 1);
|
|
4118
|
+
setCanScrollRight(nav.scrollLeft < maximum - 1);
|
|
4119
|
+
}, []);
|
|
4120
|
+
useEffect(() => {
|
|
4121
|
+
const nav = navRef.current;
|
|
4122
|
+
if (!nav) return;
|
|
4123
|
+
updateScrollState();
|
|
4124
|
+
const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(updateScrollState);
|
|
4125
|
+
observer?.observe(nav);
|
|
4126
|
+
window.addEventListener("resize", updateScrollState);
|
|
4127
|
+
return () => {
|
|
4128
|
+
observer?.disconnect();
|
|
4129
|
+
window.removeEventListener("resize", updateScrollState);
|
|
4130
|
+
};
|
|
4131
|
+
}, [categories, updateScrollState]);
|
|
4132
|
+
const scroll = (direction: -1 | 1) => {
|
|
4133
|
+
const nav = navRef.current;
|
|
4134
|
+
if (!nav) return;
|
|
4135
|
+
nav.scrollBy({ behavior: "smooth", left: direction * Math.max(180, nav.clientWidth * 0.72) });
|
|
4136
|
+
};
|
|
4137
|
+
return (
|
|
4138
|
+
<div className={`marketplace-categories-shell ${canScrollLeft ? "can-scroll-left" : ""} ${canScrollRight ? "can-scroll-right" : ""}`}>
|
|
4139
|
+
{canScrollLeft && (
|
|
4140
|
+
<button aria-label="向左查看更多分类" className="marketplace-category-scroll previous" onClick={() => scroll(-1)} type="button">
|
|
4141
|
+
‹
|
|
4142
|
+
</button>
|
|
4143
|
+
)}
|
|
4144
|
+
<nav aria-label={label} className="marketplace-categories" onScroll={updateScrollState} ref={navRef}>
|
|
4145
|
+
{categories.map((category) => {
|
|
4146
|
+
const active = activeCategory === category.id;
|
|
4147
|
+
return (
|
|
4148
|
+
<button
|
|
4149
|
+
aria-pressed={active}
|
|
4150
|
+
className={`marketplace-category ${active ? "active" : ""}`}
|
|
4151
|
+
key={category.id || "all"}
|
|
4152
|
+
onClick={() => onChange(category.id)}
|
|
4153
|
+
type="button"
|
|
4154
|
+
>
|
|
4155
|
+
<span>{category.label}</span>
|
|
4156
|
+
<span className={active ? "font-mono text-[10px] text-[#3565c5]" : "font-mono text-[10px] text-[#687381]"}>{category.count}</span>
|
|
4157
|
+
</button>
|
|
4158
|
+
);
|
|
4159
|
+
})}
|
|
4160
|
+
</nav>
|
|
4161
|
+
{canScrollRight && (
|
|
4162
|
+
<button aria-label="向右查看更多分类" className="marketplace-category-scroll next" onClick={() => scroll(1)} type="button">
|
|
4163
|
+
›
|
|
4164
|
+
</button>
|
|
4165
|
+
)}
|
|
4166
|
+
</div>
|
|
4167
|
+
);
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4073
4170
|
function Plugins({
|
|
4074
4171
|
plugins,
|
|
4075
4172
|
panels,
|
|
@@ -4178,23 +4275,7 @@ function Plugins({
|
|
|
4178
4275
|
{query.trim() || categoryFilter ? `${visiblePlugins.length} / ${installedPlugins.length}` : `${installedPlugins.length}`} 个插件
|
|
4179
4276
|
</span>
|
|
4180
4277
|
</div>
|
|
4181
|
-
<
|
|
4182
|
-
{installedCategories.map((category) => {
|
|
4183
|
-
const active = categoryFilter === category.id;
|
|
4184
|
-
return (
|
|
4185
|
-
<button
|
|
4186
|
-
aria-pressed={active}
|
|
4187
|
-
className={`marketplace-category ${active ? "active" : ""}`}
|
|
4188
|
-
key={category.id || "all"}
|
|
4189
|
-
onClick={() => setCategoryFilter(category.id)}
|
|
4190
|
-
type="button"
|
|
4191
|
-
>
|
|
4192
|
-
<span>{category.label}</span>
|
|
4193
|
-
<span className={active ? "font-mono text-[10px] text-[#3565c5]" : "font-mono text-[10px] text-[#687381]"}>{category.count}</span>
|
|
4194
|
-
</button>
|
|
4195
|
-
);
|
|
4196
|
-
})}
|
|
4197
|
-
</nav>
|
|
4278
|
+
<PluginCategoryNav activeCategory={categoryFilter} categories={installedCategories} label="已安装插件分类" onChange={setCategoryFilter} />
|
|
4198
4279
|
<div className="plugins-scroll" ref={scrollRef}>
|
|
4199
4280
|
<div className="plugins-list">
|
|
4200
4281
|
{visiblePlugins.map((plugin) => {
|
|
@@ -4202,6 +4283,7 @@ function Plugins({
|
|
|
4202
4283
|
const categoryLabel = metadata?.category.label ?? plugin.category?.label;
|
|
4203
4284
|
const capabilityLabel = capability(plugin.name);
|
|
4204
4285
|
const pluginTitle = metadata?.name ?? displayPluginName(plugin.name);
|
|
4286
|
+
const cardContent = installedPluginCardContent(plugin, metadata);
|
|
4205
4287
|
return (
|
|
4206
4288
|
<article className="catalog-card plugin-card" key={plugin.id}>
|
|
4207
4289
|
<div className="plugin-card-head">
|
|
@@ -4251,24 +4333,18 @@ function Plugins({
|
|
|
4251
4333
|
</div>
|
|
4252
4334
|
</div>
|
|
4253
4335
|
<div className="plugin-card-body">
|
|
4254
|
-
<code className="plugin-package">{
|
|
4255
|
-
<p className="plugin-description">{
|
|
4336
|
+
<code className="plugin-package">{cardContent.packageLabel}</code>
|
|
4337
|
+
<p className="plugin-description">{cardContent.description}</p>
|
|
4256
4338
|
<div className="hook-list">
|
|
4257
|
-
|
|
4258
|
-
|
|
4339
|
+
{cardContent.tags.map((tag, index) => (
|
|
4340
|
+
<span key={`${tag}-${index}`}>{tag}</span>
|
|
4341
|
+
))}
|
|
4259
4342
|
</div>
|
|
4260
4343
|
</div>
|
|
4261
4344
|
<footer className="plugin-card-footer">
|
|
4262
|
-
<
|
|
4263
|
-
className="plugin-detail-link"
|
|
4264
|
-
href={installedPluginDetailPath(plugin.name)}
|
|
4265
|
-
onClick={(event) => {
|
|
4266
|
-
event.preventDefault();
|
|
4267
|
-
onOpenDetail(plugin);
|
|
4268
|
-
}}
|
|
4269
|
-
>
|
|
4345
|
+
<button aria-label={`查看 ${pluginTitle} 详情`} className="plugin-detail-link" onClick={() => onOpenDetail(plugin)} type="button">
|
|
4270
4346
|
查看详情 →
|
|
4271
|
-
</
|
|
4347
|
+
</button>
|
|
4272
4348
|
{panelPluginIds.has(plugin.name) ? <span>实时面板</span> : null}
|
|
4273
4349
|
</footer>
|
|
4274
4350
|
</article>
|
|
@@ -4549,7 +4625,7 @@ function Marketplace({
|
|
|
4549
4625
|
const [installing, setInstalling] = useState<string>();
|
|
4550
4626
|
const [installError, setInstallError] = useState("");
|
|
4551
4627
|
const [installNotice, setInstallNotice] = useState("");
|
|
4552
|
-
const categoryTabs = marketplaceCategoryTabs(categories);
|
|
4628
|
+
const categoryTabs = useMemo(() => marketplaceCategoryTabs(categories), [categories]);
|
|
4553
4629
|
const install = async (plugin: ClientMarketplacePlugin) => {
|
|
4554
4630
|
setInstallError("");
|
|
4555
4631
|
setInstallNotice("");
|
|
@@ -4604,28 +4680,12 @@ function Marketplace({
|
|
|
4604
4680
|
</select>
|
|
4605
4681
|
<span className="marketplace-count">{total} 个已审核条目 · 推荐排序</span>
|
|
4606
4682
|
</div>
|
|
4607
|
-
<
|
|
4608
|
-
{categoryTabs.map((category) => {
|
|
4609
|
-
const active = categoryFilter === category.id;
|
|
4610
|
-
return (
|
|
4611
|
-
<button
|
|
4612
|
-
aria-pressed={active}
|
|
4613
|
-
className={`marketplace-category ${active ? "active" : ""}`}
|
|
4614
|
-
key={category.id || "all"}
|
|
4615
|
-
onClick={() => onCategoryChange(category.id)}
|
|
4616
|
-
type="button"
|
|
4617
|
-
>
|
|
4618
|
-
<span>{category.label}</span>
|
|
4619
|
-
<span className={active ? "font-mono text-[10px] text-[#3565c5]" : "font-mono text-[10px] text-[#687381]"}>{category.count}</span>
|
|
4620
|
-
</button>
|
|
4621
|
-
);
|
|
4622
|
-
})}
|
|
4623
|
-
</nav>
|
|
4683
|
+
<PluginCategoryNav activeCategory={categoryFilter} categories={categoryTabs} label="插件分类" onChange={onCategoryChange} />
|
|
4624
4684
|
<div className="marketplace-scroll">
|
|
4625
4685
|
<div className="marketplace-grid">
|
|
4626
4686
|
{plugins.map((plugin) => (
|
|
4627
4687
|
<article className="catalog-card marketplace-card" key={plugin.id}>
|
|
4628
|
-
<
|
|
4688
|
+
<header className="marketplace-card-head">
|
|
4629
4689
|
<div className="marketplace-card-mark">◈</div>
|
|
4630
4690
|
<div className="min-w-0 flex-1">
|
|
4631
4691
|
<div className="flex flex-wrap items-center gap-1.5">
|
|
@@ -4650,33 +4710,35 @@ function Marketplace({
|
|
|
4650
4710
|
</span>
|
|
4651
4711
|
<span className="rounded bg-[#f2edff] px-1.5 py-px text-[10px] text-[#6d4bc3]">{plugin.category.label}</span>
|
|
4652
4712
|
</div>
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4713
|
+
</div>
|
|
4714
|
+
</header>
|
|
4715
|
+
<div className="marketplace-card-body">
|
|
4716
|
+
<code className="marketplace-package">
|
|
4717
|
+
{displayPluginName(plugin.packageName)} · v{plugin.version}
|
|
4718
|
+
</code>
|
|
4719
|
+
<p className="marketplace-description">{plugin.description}</p>
|
|
4720
|
+
<div className="marketplace-tags">
|
|
4721
|
+
{plugin.capabilities.map((item) => (
|
|
4722
|
+
<span className="rounded bg-[#f1f4f9] px-1.5 py-px font-mono text-[10px] text-[#61666b]" key={item}>
|
|
4723
|
+
{item}
|
|
4724
|
+
</span>
|
|
4725
|
+
))}
|
|
4726
|
+
{plugin.hooks.map((item) => (
|
|
4727
|
+
<span className="rounded bg-[#f1f4f9] px-1.5 py-px font-mono text-[10px] text-[#61666b]" key={`hook:${item}`}>
|
|
4728
|
+
hook:{item}
|
|
4729
|
+
</span>
|
|
4730
|
+
))}
|
|
4731
|
+
</div>
|
|
4732
|
+
{plugin.statistics && (
|
|
4733
|
+
<div className="marketplace-statistics mt-3 grid grid-cols-3 divide-x divide-[#e3e7ee] rounded-md border border-[#e3e7ee] bg-[#f8f9fb]">
|
|
4734
|
+
{marketplaceStatisticItems(plugin.statistics).map((item) => (
|
|
4735
|
+
<span className="min-w-0 px-2 py-1.5" key={item.label} title={`${item.label} ${item.value}`}>
|
|
4736
|
+
<small className="block truncate text-[9px] text-[#687381]">{item.label}</small>
|
|
4737
|
+
<strong className="mt-0.5 block truncate font-mono text-[10px] font-medium text-[#3b424b]">{item.value}</strong>
|
|
4666
4738
|
</span>
|
|
4667
4739
|
))}
|
|
4668
4740
|
</div>
|
|
4669
|
-
|
|
4670
|
-
<div className="mt-3 grid grid-cols-3 divide-x divide-[#e3e7ee] rounded-md border border-[#e3e7ee] bg-[#f8f9fb]">
|
|
4671
|
-
{marketplaceStatisticItems(plugin.statistics).map((item) => (
|
|
4672
|
-
<span className="min-w-0 px-2 py-1.5" key={item.label} title={`${item.label} ${item.value}`}>
|
|
4673
|
-
<small className="block truncate text-[9px] text-[#687381]">{item.label}</small>
|
|
4674
|
-
<strong className="mt-0.5 block truncate font-mono text-[10px] font-medium text-[#3b424b]">{item.value}</strong>
|
|
4675
|
-
</span>
|
|
4676
|
-
))}
|
|
4677
|
-
</div>
|
|
4678
|
-
)}
|
|
4679
|
-
</div>
|
|
4741
|
+
)}
|
|
4680
4742
|
</div>
|
|
4681
4743
|
<footer className="marketplace-card-footer">
|
|
4682
4744
|
<span>
|
|
@@ -4700,7 +4762,7 @@ function Marketplace({
|
|
|
4700
4762
|
</footer>
|
|
4701
4763
|
</article>
|
|
4702
4764
|
))}
|
|
4703
|
-
{!plugins.length && <div className="
|
|
4765
|
+
{!plugins.length && <div className="empty-state">没有匹配的插件。</div>}
|
|
4704
4766
|
</div>
|
|
4705
4767
|
{installNotice && <p className="mt-2 text-[11px] text-[#3565c5]">{installNotice}</p>}
|
|
4706
4768
|
{installError && <p className="mt-2 text-[11px] text-[#b42318]">安装失败:{installError}</p>}
|
|
@@ -5617,7 +5679,7 @@ function PromptCompletionPopover({
|
|
|
5617
5679
|
? filterCommands(commands, query).slice(0, 12)
|
|
5618
5680
|
: files.filter((file) => `${file.path} ${file.label} ${file.status}`.toLowerCase().includes(query.trim().toLowerCase())).slice(0, 12);
|
|
5619
5681
|
return (
|
|
5620
|
-
<div aria-label={kind === "command" ? "命令补全" : "文件补全"} className="prompt-completion" role="listbox">
|
|
5682
|
+
<div aria-label={kind === "command" ? "命令补全" : "文件补全"} className="prompt-completion" id="prompt-completion-list" role="listbox">
|
|
5621
5683
|
<small>{kind === "command" ? "命令" : "文件"}</small>
|
|
5622
5684
|
{items.length ? (
|
|
5623
5685
|
items.slice(0, 12).map((item, index) => {
|
|
@@ -5627,6 +5689,7 @@ function PromptCompletionPopover({
|
|
|
5627
5689
|
return (
|
|
5628
5690
|
<button
|
|
5629
5691
|
aria-selected={index === activeIndex}
|
|
5692
|
+
id={`prompt-completion-option-${index}`}
|
|
5630
5693
|
key={`${kind}:${label}`}
|
|
5631
5694
|
onClick={() => onUse(label)}
|
|
5632
5695
|
onMouseEnter={() => onActiveIndexChange(index)}
|
|
@@ -5681,6 +5744,8 @@ function GlobalSearch({
|
|
|
5681
5744
|
.map((session) => ({ kind: "session" as const, session })),
|
|
5682
5745
|
...files.filter((file) => matches(`${file.path} ${file.label} ${file.status}`)).map((file) => ({ kind: "file" as const, file })),
|
|
5683
5746
|
];
|
|
5747
|
+
const selectedIndex = items.length ? Math.min(activeIndex, items.length - 1) : -1;
|
|
5748
|
+
const activeItemId = selectedIndex >= 0 ? `global-search-option-${selectedIndex}` : undefined;
|
|
5684
5749
|
useEffect(() => setActiveIndex(0), [query]);
|
|
5685
5750
|
const execute = (item: GlobalSearchItem | undefined) => {
|
|
5686
5751
|
if (!item) return;
|
|
@@ -5700,8 +5765,15 @@ function GlobalSearch({
|
|
|
5700
5765
|
<div className="global-search-heading">
|
|
5701
5766
|
<strong>全局搜索</strong>
|
|
5702
5767
|
<small>命令 · 会话 · 文件</small>
|
|
5768
|
+
<button aria-label="关闭全局搜索" onClick={onClose} type="button">
|
|
5769
|
+
×
|
|
5770
|
+
</button>
|
|
5703
5771
|
</div>
|
|
5704
5772
|
<input
|
|
5773
|
+
aria-activedescendant={activeItemId}
|
|
5774
|
+
aria-autocomplete="list"
|
|
5775
|
+
aria-controls="global-search-results"
|
|
5776
|
+
aria-expanded="true"
|
|
5705
5777
|
aria-label="全局搜索"
|
|
5706
5778
|
data-dialog-initial-focus
|
|
5707
5779
|
onChange={(event) => setQuery(event.target.value)}
|
|
@@ -5717,21 +5789,22 @@ function GlobalSearch({
|
|
|
5717
5789
|
setActiveIndex((index) => (index - 1 + items.length) % items.length);
|
|
5718
5790
|
} else if (event.key === "Enter") {
|
|
5719
5791
|
event.preventDefault();
|
|
5720
|
-
execute(items[
|
|
5792
|
+
execute(items[selectedIndex]);
|
|
5721
5793
|
}
|
|
5722
5794
|
}}
|
|
5723
5795
|
placeholder="搜索命令、会话或文件"
|
|
5796
|
+
role="combobox"
|
|
5724
5797
|
value={query}
|
|
5725
5798
|
/>
|
|
5726
|
-
<div className="global-search-results" role="listbox">
|
|
5799
|
+
<div className="global-search-results" id="global-search-results" role="listbox">
|
|
5727
5800
|
{items.length ? (
|
|
5728
5801
|
(["command", "session", "file"] as const).map((kind) => {
|
|
5729
5802
|
const group = items.filter((item) => item.kind === kind);
|
|
5730
5803
|
if (!group.length) return null;
|
|
5731
5804
|
const label = kind === "command" ? "命令" : kind === "session" ? "会话" : "文件";
|
|
5732
5805
|
return (
|
|
5733
|
-
<section className="global-search-group" key={kind}>
|
|
5734
|
-
<small>{label}</small>
|
|
5806
|
+
<section aria-label={label} className="global-search-group" key={kind} role="group">
|
|
5807
|
+
<small aria-hidden="true">{label}</small>
|
|
5735
5808
|
{group.map((item) => {
|
|
5736
5809
|
const index = items.indexOf(item);
|
|
5737
5810
|
const title =
|
|
@@ -5748,7 +5821,8 @@ function GlobalSearch({
|
|
|
5748
5821
|
: `${item.file.path} · ${item.file.status}`;
|
|
5749
5822
|
return (
|
|
5750
5823
|
<button
|
|
5751
|
-
aria-selected={index ===
|
|
5824
|
+
aria-selected={index === selectedIndex}
|
|
5825
|
+
id={`global-search-option-${index}`}
|
|
5752
5826
|
key={`${item.kind}:${title}:${index}`}
|
|
5753
5827
|
onClick={() => execute(item)}
|
|
5754
5828
|
onMouseEnter={() => setActiveIndex(index)}
|
|
@@ -5876,6 +5950,7 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
5876
5950
|
.slice(0, 12);
|
|
5877
5951
|
}, [data.commands, data.files, promptCompletion]);
|
|
5878
5952
|
const promptCompletionOpen = Boolean(promptCompletion && !promptCompletionSuppressed && promptCompletionItems.length);
|
|
5953
|
+
const promptCompletionActiveIndex = Math.min(promptCompletionIndex, Math.max(promptCompletionItems.length - 1, 0));
|
|
5879
5954
|
const installedPackages = useMemo(() => new Set(data.plugins.filter((plugin) => plugin.removable).map((plugin) => plugin.name)), [data.plugins]);
|
|
5880
5955
|
const workspaceReady =
|
|
5881
5956
|
!workspaceChooserOpen && Boolean(selectedWorkspacePath || data.status?.cwd || data.workspaces.find((workspace) => workspace.current)?.path || data.session);
|
|
@@ -6250,6 +6325,26 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6250
6325
|
setAnnotationSelection("");
|
|
6251
6326
|
setAnnotationNote("");
|
|
6252
6327
|
};
|
|
6328
|
+
const openCommandCompletion = () => {
|
|
6329
|
+
const input = promptInputRef.current;
|
|
6330
|
+
const caret = input?.selectionStart ?? draft.length;
|
|
6331
|
+
const existing = getPromptCompletion(draft, caret);
|
|
6332
|
+
let nextCaret = caret;
|
|
6333
|
+
if (existing?.kind !== "command") {
|
|
6334
|
+
const separator = caret > 0 && !/\s/.test(draft[caret - 1] ?? "") ? " " : "";
|
|
6335
|
+
const insertion = `${separator}/`;
|
|
6336
|
+
const nextDraft = `${draft.slice(0, caret)}${insertion}${draft.slice(caret)}`;
|
|
6337
|
+
nextCaret = caret + insertion.length;
|
|
6338
|
+
setDraft(nextDraft);
|
|
6339
|
+
}
|
|
6340
|
+
setPromptCaret(nextCaret);
|
|
6341
|
+
setPromptCompletionSuppressed(false);
|
|
6342
|
+
setPromptCompletionIndex(0);
|
|
6343
|
+
window.requestAnimationFrame(() => {
|
|
6344
|
+
input?.focus();
|
|
6345
|
+
input?.setSelectionRange(nextCaret, nextCaret);
|
|
6346
|
+
});
|
|
6347
|
+
};
|
|
6253
6348
|
const openSession = (session: Record<string, unknown>) => {
|
|
6254
6349
|
const path = typeof session.path === "string" ? session.path : "";
|
|
6255
6350
|
if (!path) return;
|
|
@@ -6294,6 +6389,7 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6294
6389
|
});
|
|
6295
6390
|
};
|
|
6296
6391
|
const openSessionMenu = (path: string, name?: string) => {
|
|
6392
|
+
setSessionToolsOpen(false);
|
|
6297
6393
|
setSelectedSessionPath(path);
|
|
6298
6394
|
setSessionNameDraft(name ?? "");
|
|
6299
6395
|
setSessionMenuPath(path);
|
|
@@ -6618,6 +6714,11 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6618
6714
|
) : null}
|
|
6619
6715
|
<form className="composer" onSubmit={submit}>
|
|
6620
6716
|
<textarea
|
|
6717
|
+
aria-activedescendant={promptCompletionOpen ? `prompt-completion-option-${promptCompletionActiveIndex}` : undefined}
|
|
6718
|
+
aria-autocomplete="list"
|
|
6719
|
+
aria-controls={promptCompletionOpen ? "prompt-completion-list" : undefined}
|
|
6720
|
+
aria-expanded={promptCompletionOpen}
|
|
6721
|
+
aria-haspopup="listbox"
|
|
6621
6722
|
aria-label="Prompt"
|
|
6622
6723
|
onChange={(event) => {
|
|
6623
6724
|
setDraft(event.target.value);
|
|
@@ -6644,7 +6745,7 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6644
6745
|
}
|
|
6645
6746
|
if (popupOpen && (event.key === "Enter" || event.key === "Tab")) {
|
|
6646
6747
|
event.preventDefault();
|
|
6647
|
-
const item = items[promptCompletionIndex];
|
|
6748
|
+
const item = items[Math.min(promptCompletionIndex, items.length - 1)];
|
|
6648
6749
|
if (item && completion) {
|
|
6649
6750
|
const value = completion.kind === "command" ? `/${(item as ClientCommand).invocationName}` : `@${(item as ClientFile).path}`;
|
|
6650
6751
|
const replacement = replacePromptCompletion(event.currentTarget.value, completion, `${value} `);
|
|
@@ -6686,7 +6787,7 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6686
6787
|
></textarea>
|
|
6687
6788
|
{promptCompletionOpen && promptCompletion && (
|
|
6688
6789
|
<PromptCompletionPopover
|
|
6689
|
-
activeIndex={
|
|
6790
|
+
activeIndex={promptCompletionActiveIndex}
|
|
6690
6791
|
commands={data.commands}
|
|
6691
6792
|
files={data.files}
|
|
6692
6793
|
kind={promptCompletion.kind}
|
|
@@ -6711,8 +6812,14 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6711
6812
|
disabled={!data.models.length || promptBusy}
|
|
6712
6813
|
value={data.status?.model ?? ""}
|
|
6713
6814
|
onChange={(event) => {
|
|
6714
|
-
const [provider,
|
|
6715
|
-
|
|
6815
|
+
const [provider, ...modelParts] = event.target.value.split("/");
|
|
6816
|
+
const model = modelParts.join("/");
|
|
6817
|
+
if (!provider || !model) return;
|
|
6818
|
+
setPromptError("");
|
|
6819
|
+
void api
|
|
6820
|
+
.selectModel(provider, model)
|
|
6821
|
+
.then(refresh)
|
|
6822
|
+
.catch((cause: unknown) => setPromptError(cause instanceof Error ? cause.message : String(cause)));
|
|
6716
6823
|
}}
|
|
6717
6824
|
>
|
|
6718
6825
|
{data.models.length ? (
|
|
@@ -6728,7 +6835,7 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6728
6835
|
<button className="tool-chip" onClick={() => setPermission((current) => !current)} type="button">
|
|
6729
6836
|
● {permission ? "改动前询问" : "自动允许"}
|
|
6730
6837
|
</button>
|
|
6731
|
-
<button className="tool-chip" onClick={
|
|
6838
|
+
<button className="tool-chip" onClick={openCommandCompletion} type="button">
|
|
6732
6839
|
/ 命令
|
|
6733
6840
|
</button>
|
|
6734
6841
|
<span className="composer-hint">⌘↵ 发送 · ⌘K 命令 · ⌃C 中断</span>
|
|
@@ -6752,7 +6859,14 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6752
6859
|
<Files
|
|
6753
6860
|
api={api}
|
|
6754
6861
|
files={data.files}
|
|
6755
|
-
onDiff={
|
|
6862
|
+
onDiff={async (file) => {
|
|
6863
|
+
const diff = await api.getFileDiff(file);
|
|
6864
|
+
setDetails({
|
|
6865
|
+
type: "file_diff",
|
|
6866
|
+
path: diff.path,
|
|
6867
|
+
output: diff.diff || "没有可显示的差异(工作区可能已更新)。",
|
|
6868
|
+
});
|
|
6869
|
+
}}
|
|
6756
6870
|
onRefresh={() => void refresh()}
|
|
6757
6871
|
/>
|
|
6758
6872
|
);
|
|
@@ -6866,8 +6980,10 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6866
6980
|
aria-pressed={sessionSelectionMode}
|
|
6867
6981
|
className={`session-tool-button ${sessionSelectionMode ? "active" : ""}`}
|
|
6868
6982
|
onClick={() => {
|
|
6869
|
-
setSessionSelectionMode(
|
|
6983
|
+
setSessionSelectionMode(!sessionSelectionMode);
|
|
6870
6984
|
setSelectedSessionPaths(new Set());
|
|
6985
|
+
setSessionToolsOpen(false);
|
|
6986
|
+
closeSessionMenu();
|
|
6871
6987
|
}}
|
|
6872
6988
|
type="button"
|
|
6873
6989
|
>
|
|
@@ -6878,7 +6994,10 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
6878
6994
|
aria-expanded={sessionToolsOpen}
|
|
6879
6995
|
aria-label="会话工具"
|
|
6880
6996
|
className="session-tool-button icon"
|
|
6881
|
-
onClick={() =>
|
|
6997
|
+
onClick={() => {
|
|
6998
|
+
closeSessionMenu();
|
|
6999
|
+
setSessionToolsOpen((current) => !current);
|
|
7000
|
+
}}
|
|
6882
7001
|
type="button"
|
|
6883
7002
|
>
|
|
6884
7003
|
⋯
|
|
@@ -7143,6 +7262,20 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
7143
7262
|
status <b>{value(data.status?.status, "connecting")}</b>
|
|
7144
7263
|
</span>
|
|
7145
7264
|
</div>
|
|
7265
|
+
<button
|
|
7266
|
+
aria-label="搜索会话、文件和命令"
|
|
7267
|
+
className="sidebar-link compact-session-search"
|
|
7268
|
+
onClick={() => {
|
|
7269
|
+
setCommandOpen(false);
|
|
7270
|
+
setSessionToolsOpen(false);
|
|
7271
|
+
closeSessionMenu();
|
|
7272
|
+
setGlobalSearchOpen(true);
|
|
7273
|
+
}}
|
|
7274
|
+
title="搜索会话、文件和命令"
|
|
7275
|
+
type="button"
|
|
7276
|
+
>
|
|
7277
|
+
⌕
|
|
7278
|
+
</button>
|
|
7146
7279
|
<button aria-label="新建会话" className="sidebar-link compact-new-session" onClick={beginNewSession} title="新建会话" type="button">
|
|
7147
7280
|
+
|
|
7148
7281
|
</button>
|
|
@@ -7211,7 +7344,17 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
7211
7344
|
<div className="run-indicator running">
|
|
7212
7345
|
<span className="run-dot"></span>
|
|
7213
7346
|
<span>运行中 · Pi agent</span>
|
|
7214
|
-
<button
|
|
7347
|
+
<button
|
|
7348
|
+
className="stop-button"
|
|
7349
|
+
onClick={() => {
|
|
7350
|
+
setPromptError("");
|
|
7351
|
+
void api
|
|
7352
|
+
.abort()
|
|
7353
|
+
.then(refresh)
|
|
7354
|
+
.catch((cause: unknown) => setPromptError(cause instanceof Error ? cause.message : String(cause)));
|
|
7355
|
+
}}
|
|
7356
|
+
type="button"
|
|
7357
|
+
>
|
|
7215
7358
|
停止
|
|
7216
7359
|
</button>
|
|
7217
7360
|
</div>
|
|
@@ -7248,8 +7391,14 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
7248
7391
|
>
|
|
7249
7392
|
⋯
|
|
7250
7393
|
</button>
|
|
7251
|
-
<button
|
|
7252
|
-
|
|
7394
|
+
<button
|
|
7395
|
+
aria-label={details !== undefined ? "关闭详情" : "打开详情"}
|
|
7396
|
+
aria-pressed={details !== undefined}
|
|
7397
|
+
className="details-toggle"
|
|
7398
|
+
onClick={() => setDetails(details ? undefined : {})}
|
|
7399
|
+
type="button"
|
|
7400
|
+
>
|
|
7401
|
+
<span aria-hidden="true">◨</span> <span className="details-toggle-label">详情</span>
|
|
7253
7402
|
</button>
|
|
7254
7403
|
</>
|
|
7255
7404
|
)}
|
|
@@ -7335,11 +7484,14 @@ export function ControlRoomView({ api = createClientApi(), appVersion }: { api?:
|
|
|
7335
7484
|
</div>
|
|
7336
7485
|
</section>
|
|
7337
7486
|
{!settings && page === "session" && details !== undefined && (
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7487
|
+
<>
|
|
7488
|
+
<button aria-label="关闭详情" className="details-backdrop" onClick={() => setDetails(undefined)} type="button" />
|
|
7489
|
+
<Details
|
|
7490
|
+
event={Object.keys(details).length ? details : undefined}
|
|
7491
|
+
onClose={() => setDetails(undefined)}
|
|
7492
|
+
onCopy={() => void navigator.clipboard?.writeText(JSON.stringify(details, null, 2))}
|
|
7493
|
+
/>
|
|
7494
|
+
</>
|
|
7343
7495
|
)}
|
|
7344
7496
|
{globalSearchOpen && (
|
|
7345
7497
|
<GlobalSearch
|