@pi-harness/pi-harness 0.1.2 → 0.1.4
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/LICENSE +9 -0
- package/README.md +31 -7
- package/apps/web/dist/assets/index-CihATCjR.css +2 -0
- package/apps/web/dist/assets/index-NzapJoGa.js +20 -0
- package/apps/web/dist/assets/markdown-vendor-DUdMWn0M.js +66 -0
- package/apps/web/dist/assets/react-vendor-BD7-wQo9.js +9 -0
- package/apps/web/dist/icons/app/android-192.png +0 -0
- package/apps/web/dist/icons/app/android-512.png +0 -0
- package/apps/web/dist/icons/app/app-blue-512.png +0 -0
- package/apps/web/dist/icons/app/app-store-1024.png +0 -0
- package/apps/web/dist/icons/app/apple-touch-icon-180.png +0 -0
- package/apps/web/dist/icons/app/maskable-512.png +0 -0
- package/apps/web/dist/icons/favicon/favicon-16.png +0 -0
- package/apps/web/dist/icons/favicon/favicon-32.png +0 -0
- package/apps/web/dist/icons/favicon/favicon-48.png +0 -0
- package/apps/web/dist/icons/png-blue/pi-256.png +0 -0
- package/apps/web/dist/icons/png-blue/pi-512.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-1024.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-128.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-16.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-24.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-256.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-32.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-48.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-512.png +0 -0
- package/apps/web/dist/icons/png-ink/pi-64.png +0 -0
- package/apps/web/dist/icons/png-white/pi-1024.png +0 -0
- package/apps/web/dist/icons/png-white/pi-128.png +0 -0
- package/apps/web/dist/icons/png-white/pi-16.png +0 -0
- package/apps/web/dist/icons/png-white/pi-24.png +0 -0
- package/apps/web/dist/icons/png-white/pi-256.png +0 -0
- package/apps/web/dist/icons/png-white/pi-32.png +0 -0
- package/apps/web/dist/icons/png-white/pi-48.png +0 -0
- package/apps/web/dist/icons/png-white/pi-512.png +0 -0
- package/apps/web/dist/icons/png-white/pi-64.png +0 -0
- package/apps/web/dist/icons/social/og-1200x630.png +0 -0
- package/apps/web/dist/icons/svg/app-icon-blue.svg +13 -0
- package/apps/web/dist/icons/svg/app-icon-ink.svg +13 -0
- package/apps/web/dist/icons/svg/favicon.svg +10 -0
- package/apps/web/dist/icons/svg/lockup-horizontal.svg +13 -0
- package/apps/web/dist/icons/svg/mark-blue.svg +10 -0
- package/apps/web/dist/icons/svg/mark-compact.svg +10 -0
- package/apps/web/dist/icons/svg/mark-ink.svg +10 -0
- package/apps/web/dist/icons/svg/mark-white.svg +10 -0
- package/apps/web/dist/icons/svg/mark.svg +10 -0
- package/apps/web/dist/index.html +18 -6
- package/apps/web/dist/manifest.webmanifest +14 -0
- package/apps/web/index.html +14 -4
- package/apps/web/package.json +11 -9
- package/apps/web/profile/cordis.yml +222 -1
- package/apps/web/public/icons/app/android-192.png +0 -0
- package/apps/web/public/icons/app/android-512.png +0 -0
- package/apps/web/public/icons/app/app-blue-512.png +0 -0
- package/apps/web/public/icons/app/app-store-1024.png +0 -0
- package/apps/web/public/icons/app/apple-touch-icon-180.png +0 -0
- package/apps/web/public/icons/app/maskable-512.png +0 -0
- package/apps/web/public/icons/favicon/favicon-16.png +0 -0
- package/apps/web/public/icons/favicon/favicon-32.png +0 -0
- package/apps/web/public/icons/favicon/favicon-48.png +0 -0
- package/apps/web/public/icons/png-blue/pi-256.png +0 -0
- package/apps/web/public/icons/png-blue/pi-512.png +0 -0
- package/apps/web/public/icons/png-ink/pi-1024.png +0 -0
- package/apps/web/public/icons/png-ink/pi-128.png +0 -0
- package/apps/web/public/icons/png-ink/pi-16.png +0 -0
- package/apps/web/public/icons/png-ink/pi-24.png +0 -0
- package/apps/web/public/icons/png-ink/pi-256.png +0 -0
- package/apps/web/public/icons/png-ink/pi-32.png +0 -0
- package/apps/web/public/icons/png-ink/pi-48.png +0 -0
- package/apps/web/public/icons/png-ink/pi-512.png +0 -0
- package/apps/web/public/icons/png-ink/pi-64.png +0 -0
- package/apps/web/public/icons/png-white/pi-1024.png +0 -0
- package/apps/web/public/icons/png-white/pi-128.png +0 -0
- package/apps/web/public/icons/png-white/pi-16.png +0 -0
- package/apps/web/public/icons/png-white/pi-24.png +0 -0
- package/apps/web/public/icons/png-white/pi-256.png +0 -0
- package/apps/web/public/icons/png-white/pi-32.png +0 -0
- package/apps/web/public/icons/png-white/pi-48.png +0 -0
- package/apps/web/public/icons/png-white/pi-512.png +0 -0
- package/apps/web/public/icons/png-white/pi-64.png +0 -0
- package/apps/web/public/icons/social/og-1200x630.png +0 -0
- package/apps/web/public/icons/svg/app-icon-blue.svg +13 -0
- package/apps/web/public/icons/svg/app-icon-ink.svg +13 -0
- package/apps/web/public/icons/svg/favicon.svg +10 -0
- package/apps/web/public/icons/svg/lockup-horizontal.svg +13 -0
- package/apps/web/public/icons/svg/mark-blue.svg +10 -0
- package/apps/web/public/icons/svg/mark-compact.svg +10 -0
- package/apps/web/public/icons/svg/mark-ink.svg +10 -0
- package/apps/web/public/icons/svg/mark-white.svg +10 -0
- package/apps/web/public/icons/svg/mark.svg +10 -0
- package/apps/web/public/manifest.webmanifest +14 -0
- package/apps/web/server-dist/bin.js +19 -6
- package/apps/web/server-dist/bin.js.map +1 -1
- package/apps/web/src/command-palette.ts +28 -7
- package/apps/web/src/file-diff.ts +15 -10
- package/apps/web/src/main.ts +4 -1
- package/apps/web/src/runtime.css +17 -4
- package/apps/web/src/server/bin.ts +24 -7
- package/apps/web/src/style.css +2618 -8
- package/apps/web/src/tailwind.css +25 -0
- package/apps/web/tsconfig.build.json +5 -1
- package/apps/web/tsconfig.json +1 -1
- package/apps/web/vite.config.ts +20 -0
- package/package.json +29 -17
- package/packages/api-gateway/LICENSE +9 -0
- package/packages/api-gateway/dist/index.d.ts.map +1 -1
- package/packages/api-gateway/dist/index.js +1188 -42
- package/packages/api-gateway/dist/index.js.map +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/archify.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/context.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cordis-group.json +16 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cordis-logger-console.json +16 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cordis-timer.json +16 -0
- package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/genui.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +33 -0
- package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/memory.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +33 -0
- package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +30 -0
- package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +31 -0
- package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +28 -0
- package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +32 -0
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +29 -0
- package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +29 -0
- package/packages/api-gateway/dist/marketplace.d.ts +40 -2
- package/packages/api-gateway/dist/marketplace.d.ts.map +1 -1
- package/packages/api-gateway/dist/marketplace.js +225 -19
- package/packages/api-gateway/dist/marketplace.js.map +1 -1
- package/packages/api-gateway/dist/workspaces.d.ts +8 -0
- package/packages/api-gateway/dist/workspaces.d.ts.map +1 -0
- package/packages/api-gateway/dist/workspaces.js +14 -0
- package/packages/api-gateway/dist/workspaces.js.map +1 -0
- package/packages/api-gateway/package.json +20 -10
- package/packages/api-gateway/scripts/copy-marketplace-entries.mjs +13 -0
- package/packages/api-gateway/src/index.ts +1258 -61
- package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/annotation.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/archify.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/at-file.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/context.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/cordis-group.json +16 -0
- package/packages/api-gateway/src/marketplace-entries/official/cordis-logger-console.json +16 -0
- package/packages/api-gateway/src/marketplace-entries/official/cordis-timer.json +16 -0
- package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/genui.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +33 -0
- package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/memory.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +33 -0
- package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/modlens.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/module-search.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/openpets.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-export.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/session-search.json +30 -0
- package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +31 -0
- package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/synapse.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +28 -0
- package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/web-research.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +32 -0
- package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +29 -0
- package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +29 -0
- package/packages/api-gateway/src/marketplace.ts +267 -22
- package/packages/api-gateway/src/workspaces.ts +20 -0
- package/packages/api-gateway/test/index.test.ts +483 -33
- package/packages/api-gateway/test/marketplace.test.ts +282 -3
- package/packages/api-gateway/test/release-version.test.ts +71 -0
- package/packages/api-gateway/test/workspaces.test.ts +13 -0
- package/packages/api-gateway/tsconfig.build.json +1 -1
- package/packages/api-gateway/tsconfig.json +1 -1
- package/packages/bundle-web-app/LICENSE +9 -0
- package/packages/bundle-web-app/package.json +19 -9
- package/packages/bundle-web-app/tsconfig.build.json +1 -1
- package/packages/bundle-web-app/tsconfig.json +1 -1
- package/packages/cli/LICENSE +9 -0
- package/packages/cli/dist/args.d.ts.map +1 -1
- package/packages/cli/dist/args.js +16 -9
- package/packages/cli/dist/args.js.map +1 -1
- package/packages/cli/dist/bin.js +12 -3
- package/packages/cli/dist/bin.js.map +1 -1
- package/packages/cli/dist/main.d.ts +1 -0
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +49 -9
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/cli/dist/node-stdio.d.ts +3 -1
- package/packages/cli/dist/node-stdio.d.ts.map +1 -1
- package/packages/cli/dist/node-stdio.js +91 -13
- package/packages/cli/dist/node-stdio.js.map +1 -1
- package/packages/cli/dist/relaunch.d.ts.map +1 -1
- package/packages/cli/dist/relaunch.js +23 -10
- package/packages/cli/dist/relaunch.js.map +1 -1
- package/packages/cli/package.json +18 -8
- package/packages/cli/src/args.ts +16 -10
- package/packages/cli/src/bin.ts +12 -3
- package/packages/cli/src/main.ts +54 -10
- package/packages/cli/src/node-stdio.ts +85 -13
- package/packages/cli/src/relaunch.ts +19 -6
- package/packages/cli/test/args.test.ts +22 -3
- package/packages/cli/test/binary.test.ts +58 -0
- package/packages/cli/test/broken-pipe.test.ts +32 -0
- package/packages/cli/test/cli.test.ts +57 -8
- package/packages/cli/test/node-stdio.test.ts +89 -0
- package/packages/cli/test/relaunch.test.ts +30 -2
- package/packages/cli/test/stdin-shutdown.test.ts +59 -0
- package/packages/cli/tsconfig.build.json +1 -3
- package/packages/cli/tsconfig.json +1 -4
- package/packages/client-web/LICENSE +9 -0
- package/packages/client-web/dist/annotation-ui.d.ts +11 -0
- package/packages/client-web/dist/annotation-ui.d.ts.map +1 -0
- package/packages/client-web/dist/annotation-ui.js +24 -0
- package/packages/client-web/dist/annotation-ui.js.map +1 -0
- package/packages/client-web/dist/browser-session-view.d.ts +7 -0
- package/packages/client-web/dist/browser-session-view.d.ts.map +1 -0
- package/packages/client-web/dist/browser-session-view.js +8 -0
- package/packages/client-web/dist/browser-session-view.js.map +1 -0
- package/packages/client-web/dist/control-room.d.ts +151 -6
- package/packages/client-web/dist/control-room.d.ts.map +1 -1
- package/packages/client-web/dist/control-room.js +156 -11
- package/packages/client-web/dist/control-room.js.map +1 -1
- package/packages/client-web/dist/design-contract.d.ts.map +1 -1
- package/packages/client-web/dist/design-contract.js +178 -19
- package/packages/client-web/dist/design-contract.js.map +1 -1
- package/packages/client-web/dist/index.d.ts +4 -1
- package/packages/client-web/dist/index.d.ts.map +1 -1
- package/packages/client-web/dist/index.js +11 -3
- package/packages/client-web/dist/index.js.map +1 -1
- package/packages/client-web/dist/markdown.d.ts +5 -0
- package/packages/client-web/dist/markdown.d.ts.map +1 -0
- package/packages/client-web/dist/markdown.js +20 -0
- package/packages/client-web/dist/markdown.js.map +1 -0
- package/packages/client-web/dist/marketplace-catalog.d.ts +3 -0
- package/packages/client-web/dist/marketplace-catalog.d.ts.map +1 -0
- package/packages/client-web/dist/marketplace-catalog.js +10 -0
- package/packages/client-web/dist/marketplace-catalog.js.map +1 -0
- package/packages/client-web/dist/marketplace-navigation.d.ts +19 -0
- package/packages/client-web/dist/marketplace-navigation.d.ts.map +1 -0
- package/packages/client-web/dist/marketplace-navigation.js +31 -0
- package/packages/client-web/dist/marketplace-navigation.js.map +1 -0
- package/packages/client-web/dist/message-content.d.ts +9 -0
- package/packages/client-web/dist/message-content.d.ts.map +1 -0
- package/packages/client-web/dist/message-content.js +54 -0
- package/packages/client-web/dist/message-content.js.map +1 -0
- package/packages/client-web/dist/plugin-navigation.d.ts +3 -0
- package/packages/client-web/dist/plugin-navigation.d.ts.map +1 -0
- package/packages/client-web/dist/plugin-navigation.js +10 -0
- package/packages/client-web/dist/plugin-navigation.js.map +1 -0
- package/packages/client-web/dist/plugin-search.d.ts +2 -0
- package/packages/client-web/dist/plugin-search.d.ts.map +1 -0
- package/packages/client-web/dist/plugin-search.js +7 -0
- package/packages/client-web/dist/plugin-search.js.map +1 -0
- package/packages/client-web/dist/plugin-stars-view.d.ts +12 -0
- package/packages/client-web/dist/plugin-stars-view.d.ts.map +1 -0
- package/packages/client-web/dist/plugin-stars-view.js +8 -0
- package/packages/client-web/dist/plugin-stars-view.js.map +1 -0
- package/packages/client-web/dist/prompt-completion.d.ts +13 -0
- package/packages/client-web/dist/prompt-completion.d.ts.map +1 -0
- package/packages/client-web/dist/prompt-completion.js +17 -0
- package/packages/client-web/dist/prompt-completion.js.map +1 -0
- package/packages/client-web/dist/react-room.d.ts +2 -1
- package/packages/client-web/dist/react-room.d.ts.map +1 -1
- package/packages/client-web/dist/react-room.js +2347 -93
- package/packages/client-web/dist/react-room.js.map +1 -1
- package/packages/client-web/dist/runtime-events.d.ts +4 -0
- package/packages/client-web/dist/runtime-events.d.ts.map +1 -0
- package/packages/client-web/dist/runtime-events.js +29 -0
- package/packages/client-web/dist/runtime-events.js.map +1 -0
- package/packages/client-web/package.json +19 -7
- package/packages/client-web/src/annotation-ui.ts +29 -0
- package/packages/client-web/src/browser-session-view.ts +13 -0
- package/packages/client-web/src/control-room.ts +359 -11
- package/packages/client-web/src/design-contract.ts +248 -26
- package/packages/client-web/src/index.ts +17 -4
- package/packages/client-web/src/markdown.tsx +22 -0
- package/packages/client-web/src/marketplace-catalog.ts +10 -0
- package/packages/client-web/src/marketplace-navigation.ts +46 -0
- package/packages/client-web/src/message-content.ts +51 -0
- package/packages/client-web/src/plugin-navigation.ts +9 -0
- package/packages/client-web/src/plugin-search.ts +5 -0
- package/packages/client-web/src/plugin-stars-view.ts +19 -0
- package/packages/client-web/src/prompt-completion.ts +24 -0
- package/packages/client-web/src/react-room.tsx +7360 -54
- package/packages/client-web/src/runtime-events.ts +29 -0
- package/packages/client-web/test/annotation-ui.test.ts +21 -0
- package/packages/client-web/test/browser-session-view.test.ts +17 -0
- package/packages/client-web/test/design-contract.test.ts +46 -1
- package/packages/client-web/test/marketplace-catalog.test.ts +52 -0
- package/packages/client-web/test/message-content.test.ts +43 -0
- package/packages/client-web/test/plugin-navigation.test.ts +16 -0
- package/packages/client-web/test/plugin-search.test.ts +22 -0
- package/packages/client-web/test/plugin-stars-view.test.ts +20 -0
- package/packages/client-web/test/prompt-completion.test.ts +21 -0
- package/packages/client-web/test/runtime-events.test.ts +28 -0
- package/packages/client-web/tsconfig.build.json +13 -1
- package/packages/client-web/tsconfig.json +11 -1
- package/packages/core/LICENSE +9 -0
- package/packages/core/dist/boot.d.ts.map +1 -1
- package/packages/core/dist/boot.js +42 -3
- package/packages/core/dist/boot.js.map +1 -1
- package/packages/core/dist/config.d.ts +2 -0
- package/packages/core/dist/config.d.ts.map +1 -0
- package/packages/core/dist/config.js +8 -0
- package/packages/core/dist/config.js.map +1 -0
- package/packages/core/dist/http.d.ts +8 -0
- package/packages/core/dist/http.d.ts.map +1 -0
- package/packages/core/dist/http.js +27 -0
- package/packages/core/dist/http.js.map +1 -0
- package/packages/core/dist/index.d.ts +2 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +2 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/plugins/agent-teams.d.ts +17 -0
- package/packages/core/dist/plugins/agent-teams.d.ts.map +1 -0
- package/packages/core/dist/plugins/agent-teams.js +298 -0
- package/packages/core/dist/plugins/agent-teams.js.map +1 -0
- package/packages/core/dist/plugins/anchored-standard.d.ts +14 -0
- package/packages/core/dist/plugins/anchored-standard.d.ts.map +1 -0
- package/packages/core/dist/plugins/anchored-standard.js +84 -0
- package/packages/core/dist/plugins/anchored-standard.js.map +1 -0
- package/packages/core/dist/plugins/annotation.d.ts +18 -0
- package/packages/core/dist/plugins/annotation.d.ts.map +1 -0
- package/packages/core/dist/plugins/annotation.js +94 -0
- package/packages/core/dist/plugins/annotation.js.map +1 -0
- package/packages/core/dist/plugins/archify.d.ts +23 -0
- package/packages/core/dist/plugins/archify.d.ts.map +1 -0
- package/packages/core/dist/plugins/archify.js +98 -0
- package/packages/core/dist/plugins/archify.js.map +1 -0
- package/packages/core/dist/plugins/at-file.d.ts +8 -0
- package/packages/core/dist/plugins/at-file.d.ts.map +1 -0
- package/packages/core/dist/plugins/at-file.js +52 -0
- package/packages/core/dist/plugins/at-file.js.map +1 -0
- package/packages/core/dist/plugins/auto-mode.d.ts +15 -0
- package/packages/core/dist/plugins/auto-mode.d.ts.map +1 -0
- package/packages/core/dist/plugins/auto-mode.js +114 -0
- package/packages/core/dist/plugins/auto-mode.js.map +1 -0
- package/packages/core/dist/plugins/better-sidebar.d.ts +37 -0
- package/packages/core/dist/plugins/better-sidebar.d.ts.map +1 -0
- package/packages/core/dist/plugins/better-sidebar.js +89 -0
- package/packages/core/dist/plugins/better-sidebar.js.map +1 -0
- package/packages/core/dist/plugins/browser-fetch.d.ts +14 -0
- package/packages/core/dist/plugins/browser-fetch.d.ts.map +1 -0
- package/packages/core/dist/plugins/browser-fetch.js +167 -0
- package/packages/core/dist/plugins/browser-fetch.js.map +1 -0
- package/packages/core/dist/plugins/browser-session.d.ts +14 -0
- package/packages/core/dist/plugins/browser-session.d.ts.map +1 -0
- package/packages/core/dist/plugins/browser-session.js +265 -0
- package/packages/core/dist/plugins/browser-session.js.map +1 -0
- package/packages/core/dist/plugins/canvas-draw.d.ts +8 -0
- package/packages/core/dist/plugins/canvas-draw.d.ts.map +1 -0
- package/packages/core/dist/plugins/canvas-draw.js +88 -0
- package/packages/core/dist/plugins/canvas-draw.js.map +1 -0
- package/packages/core/dist/plugins/change-verifier.d.ts +8 -0
- package/packages/core/dist/plugins/change-verifier.d.ts.map +1 -0
- package/packages/core/dist/plugins/change-verifier.js +67 -0
- package/packages/core/dist/plugins/change-verifier.js.map +1 -0
- package/packages/core/dist/plugins/cleaner.d.ts +8 -0
- package/packages/core/dist/plugins/cleaner.d.ts.map +1 -0
- package/packages/core/dist/plugins/cleaner.js +56 -0
- package/packages/core/dist/plugins/cleaner.js.map +1 -0
- package/packages/core/dist/plugins/cli-notifier.d.ts +15 -0
- package/packages/core/dist/plugins/cli-notifier.d.ts.map +1 -0
- package/packages/core/dist/plugins/cli-notifier.js +110 -0
- package/packages/core/dist/plugins/cli-notifier.js.map +1 -0
- package/packages/core/dist/plugins/code2skill.d.ts +8 -0
- package/packages/core/dist/plugins/code2skill.d.ts.map +1 -0
- package/packages/core/dist/plugins/code2skill.js +95 -0
- package/packages/core/dist/plugins/code2skill.js.map +1 -0
- package/packages/core/dist/plugins/colleague-skill.d.ts +27 -0
- package/packages/core/dist/plugins/colleague-skill.d.ts.map +1 -0
- package/packages/core/dist/plugins/colleague-skill.js +99 -0
- package/packages/core/dist/plugins/colleague-skill.js.map +1 -0
- package/packages/core/dist/plugins/context-doctor.d.ts +30 -0
- package/packages/core/dist/plugins/context-doctor.d.ts.map +1 -0
- package/packages/core/dist/plugins/context-doctor.js +95 -0
- package/packages/core/dist/plugins/context-doctor.js.map +1 -0
- package/packages/core/dist/plugins/context.d.ts +8 -0
- package/packages/core/dist/plugins/context.d.ts.map +1 -0
- package/packages/core/dist/plugins/context.js +87 -0
- package/packages/core/dist/plugins/context.js.map +1 -0
- package/packages/core/dist/plugins/cost-meter.d.ts +32 -0
- package/packages/core/dist/plugins/cost-meter.d.ts.map +1 -0
- package/packages/core/dist/plugins/cost-meter.js +204 -0
- package/packages/core/dist/plugins/cost-meter.js.map +1 -0
- package/packages/core/dist/plugins/dependency-checker.d.ts +27 -0
- package/packages/core/dist/plugins/dependency-checker.d.ts.map +1 -0
- package/packages/core/dist/plugins/dependency-checker.js +221 -0
- package/packages/core/dist/plugins/dependency-checker.js.map +1 -0
- package/packages/core/dist/plugins/docker-sandbox.d.ts +8 -0
- package/packages/core/dist/plugins/docker-sandbox.d.ts.map +1 -0
- package/packages/core/dist/plugins/docker-sandbox.js +102 -0
- package/packages/core/dist/plugins/docker-sandbox.js.map +1 -0
- package/packages/core/dist/plugins/fail-logger.d.ts +8 -0
- package/packages/core/dist/plugins/fail-logger.d.ts.map +1 -0
- package/packages/core/dist/plugins/fail-logger.js +51 -0
- package/packages/core/dist/plugins/fail-logger.js.map +1 -0
- package/packages/core/dist/plugins/genui.d.ts +8 -0
- package/packages/core/dist/plugins/genui.d.ts.map +1 -0
- package/packages/core/dist/plugins/genui.js +79 -0
- package/packages/core/dist/plugins/genui.js.map +1 -0
- package/packages/core/dist/plugins/git-time-capsule.d.ts +9 -0
- package/packages/core/dist/plugins/git-time-capsule.d.ts.map +1 -0
- package/packages/core/dist/plugins/git-time-capsule.js +90 -0
- package/packages/core/dist/plugins/git-time-capsule.js.map +1 -0
- package/packages/core/dist/plugins/graph-memory.d.ts +16 -0
- package/packages/core/dist/plugins/graph-memory.d.ts.map +1 -0
- package/packages/core/dist/plugins/graph-memory.js +382 -0
- package/packages/core/dist/plugins/graph-memory.js.map +1 -0
- package/packages/core/dist/plugins/history-compressor.d.ts +15 -0
- package/packages/core/dist/plugins/history-compressor.d.ts.map +1 -0
- package/packages/core/dist/plugins/history-compressor.js +80 -0
- package/packages/core/dist/plugins/history-compressor.js.map +1 -0
- package/packages/core/dist/plugins/hol-guard.d.ts +29 -0
- package/packages/core/dist/plugins/hol-guard.d.ts.map +1 -0
- package/packages/core/dist/plugins/hol-guard.js +139 -0
- package/packages/core/dist/plugins/hol-guard.js.map +1 -0
- package/packages/core/dist/plugins/i18n-pair.d.ts +8 -0
- package/packages/core/dist/plugins/i18n-pair.d.ts.map +1 -0
- package/packages/core/dist/plugins/i18n-pair.js +76 -0
- package/packages/core/dist/plugins/i18n-pair.js.map +1 -0
- package/packages/core/dist/plugins/image-compressor.d.ts +8 -0
- package/packages/core/dist/plugins/image-compressor.d.ts.map +1 -0
- package/packages/core/dist/plugins/image-compressor.js +150 -0
- package/packages/core/dist/plugins/image-compressor.js.map +1 -0
- package/packages/core/dist/plugins/llm-verifier.d.ts +42 -0
- package/packages/core/dist/plugins/llm-verifier.d.ts.map +1 -0
- package/packages/core/dist/plugins/llm-verifier.js +128 -0
- package/packages/core/dist/plugins/llm-verifier.js.map +1 -0
- package/packages/core/dist/plugins/mcp-client.d.ts +19 -0
- package/packages/core/dist/plugins/mcp-client.d.ts.map +1 -0
- package/packages/core/dist/plugins/mcp-client.js +534 -0
- package/packages/core/dist/plugins/mcp-client.js.map +1 -0
- package/packages/core/dist/plugins/mcp-panel.d.ts +14 -0
- package/packages/core/dist/plugins/mcp-panel.d.ts.map +1 -0
- package/packages/core/dist/plugins/mcp-panel.js +180 -0
- package/packages/core/dist/plugins/mcp-panel.js.map +1 -0
- package/packages/core/dist/plugins/memory.d.ts +15 -0
- package/packages/core/dist/plugins/memory.d.ts.map +1 -0
- package/packages/core/dist/plugins/memory.js +161 -0
- package/packages/core/dist/plugins/memory.js.map +1 -0
- package/packages/core/dist/plugins/mirage-bridge.d.ts +23 -0
- package/packages/core/dist/plugins/mirage-bridge.d.ts.map +1 -0
- package/packages/core/dist/plugins/mirage-bridge.js +149 -0
- package/packages/core/dist/plugins/mirage-bridge.js.map +1 -0
- package/packages/core/dist/plugins/mock-server.d.ts +22 -0
- package/packages/core/dist/plugins/mock-server.d.ts.map +1 -0
- package/packages/core/dist/plugins/mock-server.js +149 -0
- package/packages/core/dist/plugins/mock-server.js.map +1 -0
- package/packages/core/dist/plugins/model.d.ts +1 -1
- package/packages/core/dist/plugins/model.d.ts.map +1 -1
- package/packages/core/dist/plugins/model.js +3 -1
- package/packages/core/dist/plugins/model.js.map +1 -1
- package/packages/core/dist/plugins/models.d.ts.map +1 -1
- package/packages/core/dist/plugins/models.js +5 -2
- package/packages/core/dist/plugins/models.js.map +1 -1
- package/packages/core/dist/plugins/modlens.d.ts +8 -0
- package/packages/core/dist/plugins/modlens.d.ts.map +1 -0
- package/packages/core/dist/plugins/modlens.js +63 -0
- package/packages/core/dist/plugins/modlens.js.map +1 -0
- package/packages/core/dist/plugins/module-search.d.ts +27 -0
- package/packages/core/dist/plugins/module-search.d.ts.map +1 -0
- package/packages/core/dist/plugins/module-search.js +174 -0
- package/packages/core/dist/plugins/module-search.js.map +1 -0
- package/packages/core/dist/plugins/obsidian-sync.d.ts +14 -0
- package/packages/core/dist/plugins/obsidian-sync.d.ts.map +1 -0
- package/packages/core/dist/plugins/obsidian-sync.js +79 -0
- package/packages/core/dist/plugins/obsidian-sync.js.map +1 -0
- package/packages/core/dist/plugins/openpets.d.ts +14 -0
- package/packages/core/dist/plugins/openpets.d.ts.map +1 -0
- package/packages/core/dist/plugins/openpets.js +99 -0
- package/packages/core/dist/plugins/openpets.js.map +1 -0
- package/packages/core/dist/plugins/plan-execute.d.ts +8 -0
- package/packages/core/dist/plugins/plan-execute.d.ts.map +1 -0
- package/packages/core/dist/plugins/plan-execute.js +70 -0
- package/packages/core/dist/plugins/plan-execute.js.map +1 -0
- package/packages/core/dist/plugins/plugin-check.d.ts +38 -0
- package/packages/core/dist/plugins/plugin-check.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-check.js +227 -0
- package/packages/core/dist/plugins/plugin-check.js.map +1 -0
- package/packages/core/dist/plugins/plugin-dev.d.ts +8 -0
- package/packages/core/dist/plugins/plugin-dev.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-dev.js +44 -0
- package/packages/core/dist/plugins/plugin-dev.js.map +1 -0
- package/packages/core/dist/plugins/plugin-finder.d.ts +16 -0
- package/packages/core/dist/plugins/plugin-finder.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-finder.js +98 -0
- package/packages/core/dist/plugins/plugin-finder.js.map +1 -0
- package/packages/core/dist/plugins/plugin-radar.d.ts +29 -0
- package/packages/core/dist/plugins/plugin-radar.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-radar.js +146 -0
- package/packages/core/dist/plugins/plugin-radar.js.map +1 -0
- package/packages/core/dist/plugins/plugin-stars.d.ts +45 -0
- package/packages/core/dist/plugins/plugin-stars.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-stars.js +165 -0
- package/packages/core/dist/plugins/plugin-stars.js.map +1 -0
- package/packages/core/dist/plugins/prompt-guard.d.ts +8 -0
- package/packages/core/dist/plugins/prompt-guard.d.ts.map +1 -0
- package/packages/core/dist/plugins/prompt-guard.js +114 -0
- package/packages/core/dist/plugins/prompt-guard.js.map +1 -0
- package/packages/core/dist/plugins/prompt-library.d.ts +25 -0
- package/packages/core/dist/plugins/prompt-library.d.ts.map +1 -0
- package/packages/core/dist/plugins/prompt-library.js +142 -0
- package/packages/core/dist/plugins/prompt-library.js.map +1 -0
- package/packages/core/dist/plugins/readme-gen.d.ts +25 -0
- package/packages/core/dist/plugins/readme-gen.d.ts.map +1 -0
- package/packages/core/dist/plugins/readme-gen.js +139 -0
- package/packages/core/dist/plugins/readme-gen.js.map +1 -0
- package/packages/core/dist/plugins/recall-unread.d.ts +24 -0
- package/packages/core/dist/plugins/recall-unread.d.ts.map +1 -0
- package/packages/core/dist/plugins/recall-unread.js +124 -0
- package/packages/core/dist/plugins/recall-unread.js.map +1 -0
- package/packages/core/dist/plugins/resources.d.ts +1 -0
- package/packages/core/dist/plugins/resources.d.ts.map +1 -1
- package/packages/core/dist/plugins/resources.js +31 -22
- package/packages/core/dist/plugins/resources.js.map +1 -1
- package/packages/core/dist/plugins/reverse-skill.d.ts +23 -0
- package/packages/core/dist/plugins/reverse-skill.d.ts.map +1 -0
- package/packages/core/dist/plugins/reverse-skill.js +60 -0
- package/packages/core/dist/plugins/reverse-skill.js.map +1 -0
- package/packages/core/dist/plugins/reviewer-bot.d.ts +14 -0
- package/packages/core/dist/plugins/reviewer-bot.d.ts.map +1 -0
- package/packages/core/dist/plugins/reviewer-bot.js +133 -0
- package/packages/core/dist/plugins/reviewer-bot.js.map +1 -0
- package/packages/core/dist/plugins/runtime-doctor.d.ts +33 -0
- package/packages/core/dist/plugins/runtime-doctor.d.ts.map +1 -0
- package/packages/core/dist/plugins/runtime-doctor.js +114 -0
- package/packages/core/dist/plugins/runtime-doctor.js.map +1 -0
- package/packages/core/dist/plugins/runtime.d.ts.map +1 -1
- package/packages/core/dist/plugins/runtime.js +63 -14
- package/packages/core/dist/plugins/runtime.js.map +1 -1
- package/packages/core/dist/plugins/secure-audit.d.ts +31 -0
- package/packages/core/dist/plugins/secure-audit.d.ts.map +1 -0
- package/packages/core/dist/plugins/secure-audit.js +121 -0
- package/packages/core/dist/plugins/secure-audit.js.map +1 -0
- package/packages/core/dist/plugins/session-bookmarks.d.ts +15 -0
- package/packages/core/dist/plugins/session-bookmarks.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-bookmarks.js +87 -0
- package/packages/core/dist/plugins/session-bookmarks.js.map +1 -0
- package/packages/core/dist/plugins/session-bridge.d.ts +44 -0
- package/packages/core/dist/plugins/session-bridge.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-bridge.js +265 -0
- package/packages/core/dist/plugins/session-bridge.js.map +1 -0
- package/packages/core/dist/plugins/session-compare.d.ts +33 -0
- package/packages/core/dist/plugins/session-compare.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-compare.js +150 -0
- package/packages/core/dist/plugins/session-compare.js.map +1 -0
- package/packages/core/dist/plugins/session-export.d.ts +9 -0
- package/packages/core/dist/plugins/session-export.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-export.js +93 -0
- package/packages/core/dist/plugins/session-export.js.map +1 -0
- package/packages/core/dist/plugins/session-insights.d.ts +8 -0
- package/packages/core/dist/plugins/session-insights.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-insights.js +47 -0
- package/packages/core/dist/plugins/session-insights.js.map +1 -0
- package/packages/core/dist/plugins/session-search.d.ts +20 -0
- package/packages/core/dist/plugins/session-search.d.ts.map +1 -0
- package/packages/core/dist/plugins/session-search.js +122 -0
- package/packages/core/dist/plugins/session-search.js.map +1 -0
- package/packages/core/dist/plugins/session.d.ts.map +1 -1
- package/packages/core/dist/plugins/session.js +4 -2
- package/packages/core/dist/plugins/session.js.map +1 -1
- package/packages/core/dist/plugins/skill-catalog.d.ts +26 -0
- package/packages/core/dist/plugins/skill-catalog.d.ts.map +1 -0
- package/packages/core/dist/plugins/skill-catalog.js +97 -0
- package/packages/core/dist/plugins/skill-catalog.js.map +1 -0
- package/packages/core/dist/plugins/skill-guard.d.ts +26 -0
- package/packages/core/dist/plugins/skill-guard.d.ts.map +1 -0
- package/packages/core/dist/plugins/skill-guard.js +139 -0
- package/packages/core/dist/plugins/skill-guard.js.map +1 -0
- package/packages/core/dist/plugins/sql-lens.d.ts +8 -0
- package/packages/core/dist/plugins/sql-lens.d.ts.map +1 -0
- package/packages/core/dist/plugins/sql-lens.js +85 -0
- package/packages/core/dist/plugins/sql-lens.js.map +1 -0
- package/packages/core/dist/plugins/stdio.d.ts +1 -1
- package/packages/core/dist/plugins/stdio.d.ts.map +1 -1
- package/packages/core/dist/plugins/stdio.js +3 -1
- package/packages/core/dist/plugins/stdio.js.map +1 -1
- package/packages/core/dist/plugins/synapse.d.ts +38 -0
- package/packages/core/dist/plugins/synapse.d.ts.map +1 -0
- package/packages/core/dist/plugins/synapse.js +93 -0
- package/packages/core/dist/plugins/synapse.js.map +1 -0
- package/packages/core/dist/plugins/tab-manager.d.ts +8 -0
- package/packages/core/dist/plugins/tab-manager.d.ts.map +1 -0
- package/packages/core/dist/plugins/tab-manager.js +135 -0
- package/packages/core/dist/plugins/tab-manager.js.map +1 -0
- package/packages/core/dist/plugins/taskboard.d.ts +15 -0
- package/packages/core/dist/plugins/taskboard.d.ts.map +1 -0
- package/packages/core/dist/plugins/taskboard.js +347 -0
- package/packages/core/dist/plugins/taskboard.js.map +1 -0
- package/packages/core/dist/plugins/telemetry-blocker.d.ts +8 -0
- package/packages/core/dist/plugins/telemetry-blocker.d.ts.map +1 -0
- package/packages/core/dist/plugins/telemetry-blocker.js +57 -0
- package/packages/core/dist/plugins/telemetry-blocker.js.map +1 -0
- package/packages/core/dist/plugins/test-harness.d.ts +8 -0
- package/packages/core/dist/plugins/test-harness.d.ts.map +1 -0
- package/packages/core/dist/plugins/test-harness.js +64 -0
- package/packages/core/dist/plugins/test-harness.js.map +1 -0
- package/packages/core/dist/plugins/theme-studio.d.ts +29 -0
- package/packages/core/dist/plugins/theme-studio.d.ts.map +1 -0
- package/packages/core/dist/plugins/theme-studio.js +141 -0
- package/packages/core/dist/plugins/theme-studio.js.map +1 -0
- package/packages/core/dist/plugins/token-guard.d.ts +15 -0
- package/packages/core/dist/plugins/token-guard.d.ts.map +1 -0
- package/packages/core/dist/plugins/token-guard.js +78 -0
- package/packages/core/dist/plugins/token-guard.js.map +1 -0
- package/packages/core/dist/plugins/tools.d.ts.map +1 -1
- package/packages/core/dist/plugins/tools.js +5 -2
- package/packages/core/dist/plugins/tools.js.map +1 -1
- package/packages/core/dist/plugins/turn-rewind.d.ts +19 -0
- package/packages/core/dist/plugins/turn-rewind.d.ts.map +1 -0
- package/packages/core/dist/plugins/turn-rewind.js +74 -0
- package/packages/core/dist/plugins/turn-rewind.js.map +1 -0
- package/packages/core/dist/plugins/undo-savepoint.d.ts +17 -0
- package/packages/core/dist/plugins/undo-savepoint.d.ts.map +1 -0
- package/packages/core/dist/plugins/undo-savepoint.js +247 -0
- package/packages/core/dist/plugins/undo-savepoint.js.map +1 -0
- package/packages/core/dist/plugins/vision-toolkit.d.ts +17 -0
- package/packages/core/dist/plugins/vision-toolkit.d.ts.map +1 -0
- package/packages/core/dist/plugins/vision-toolkit.js +145 -0
- package/packages/core/dist/plugins/vision-toolkit.js.map +1 -0
- package/packages/core/dist/plugins/web-research.d.ts +17 -0
- package/packages/core/dist/plugins/web-research.d.ts.map +1 -0
- package/packages/core/dist/plugins/web-research.js +275 -0
- package/packages/core/dist/plugins/web-research.js.map +1 -0
- package/packages/core/dist/plugins/workspace-navigator.d.ts +36 -0
- package/packages/core/dist/plugins/workspace-navigator.d.ts.map +1 -0
- package/packages/core/dist/plugins/workspace-navigator.js +150 -0
- package/packages/core/dist/plugins/workspace-navigator.js.map +1 -0
- package/packages/core/dist/plugins/workspace-search.d.ts +8 -0
- package/packages/core/dist/plugins/workspace-search.d.ts.map +1 -0
- package/packages/core/dist/plugins/workspace-search.js +134 -0
- package/packages/core/dist/plugins/workspace-search.js.map +1 -0
- package/packages/core/dist/plugins/yaml-validator.d.ts +8 -0
- package/packages/core/dist/plugins/yaml-validator.d.ts.map +1 -0
- package/packages/core/dist/plugins/yaml-validator.js +94 -0
- package/packages/core/dist/plugins/yaml-validator.js.map +1 -0
- package/packages/core/dist/profile.d.ts +1 -0
- package/packages/core/dist/profile.d.ts.map +1 -1
- package/packages/core/dist/profile.js +3 -0
- package/packages/core/dist/profile.js.map +1 -1
- package/packages/core/dist/runtime.d.ts.map +1 -1
- package/packages/core/dist/runtime.js +13 -4
- package/packages/core/dist/runtime.js.map +1 -1
- package/packages/core/dist/services.d.ts +55 -0
- package/packages/core/dist/services.d.ts.map +1 -1
- package/packages/core/dist/services.js +58 -2
- package/packages/core/dist/services.js.map +1 -1
- package/packages/core/dist/stdio.d.ts +13 -2
- package/packages/core/dist/stdio.d.ts.map +1 -1
- package/packages/core/dist/stdio.js +75 -9
- package/packages/core/dist/stdio.js.map +1 -1
- package/packages/core/dist/workspace-path.d.ts +12 -0
- package/packages/core/dist/workspace-path.d.ts.map +1 -0
- package/packages/core/dist/workspace-path.js +62 -0
- package/packages/core/dist/workspace-path.js.map +1 -0
- package/packages/core/package.json +18 -8
- package/packages/core/profiles/default/cordis.yml +85 -0
- package/packages/core/profiles/development/cordis.yml +1 -1
- package/packages/core/src/boot.ts +38 -2
- package/packages/core/src/config.ts +5 -0
- package/packages/core/src/http.ts +32 -0
- package/packages/core/src/index.ts +2 -0
- package/packages/core/src/plugins/agent-teams.ts +291 -0
- package/packages/core/src/plugins/anchored-standard.ts +88 -0
- package/packages/core/src/plugins/annotation.ts +106 -0
- package/packages/core/src/plugins/archify.ts +124 -0
- package/packages/core/src/plugins/at-file.ts +54 -0
- package/packages/core/src/plugins/auto-mode.ts +123 -0
- package/packages/core/src/plugins/better-sidebar.ts +117 -0
- package/packages/core/src/plugins/browser-fetch.ts +171 -0
- package/packages/core/src/plugins/browser-session.ts +287 -0
- package/packages/core/src/plugins/canvas-draw.ts +90 -0
- package/packages/core/src/plugins/change-verifier.ts +79 -0
- package/packages/core/src/plugins/cleaner.ts +61 -0
- package/packages/core/src/plugins/cli-notifier.ts +125 -0
- package/packages/core/src/plugins/code2skill.ts +96 -0
- package/packages/core/src/plugins/colleague-skill.ts +122 -0
- package/packages/core/src/plugins/context-doctor.ts +117 -0
- package/packages/core/src/plugins/context.ts +102 -0
- package/packages/core/src/plugins/cost-meter.ts +231 -0
- package/packages/core/src/plugins/dependency-checker.ts +241 -0
- package/packages/core/src/plugins/docker-sandbox.ts +100 -0
- package/packages/core/src/plugins/fail-logger.ts +51 -0
- package/packages/core/src/plugins/genui.ts +88 -0
- package/packages/core/src/plugins/git-time-capsule.ts +97 -0
- package/packages/core/src/plugins/graph-memory.ts +394 -0
- package/packages/core/src/plugins/history-compressor.ts +81 -0
- package/packages/core/src/plugins/hol-guard.ts +153 -0
- package/packages/core/src/plugins/i18n-pair.ts +82 -0
- package/packages/core/src/plugins/image-compressor.ts +144 -0
- package/packages/core/src/plugins/llm-verifier.ts +164 -0
- package/packages/core/src/plugins/mcp-client.ts +559 -0
- package/packages/core/src/plugins/mcp-panel.ts +190 -0
- package/packages/core/src/plugins/memory.ts +176 -0
- package/packages/core/src/plugins/mirage-bridge.ts +179 -0
- package/packages/core/src/plugins/mock-server.ts +158 -0
- package/packages/core/src/plugins/model.ts +3 -1
- package/packages/core/src/plugins/models.ts +5 -2
- package/packages/core/src/plugins/modlens.ts +63 -0
- package/packages/core/src/plugins/module-search.ts +201 -0
- package/packages/core/src/plugins/obsidian-sync.ts +83 -0
- package/packages/core/src/plugins/openpets.ts +109 -0
- package/packages/core/src/plugins/plan-execute.ts +76 -0
- package/packages/core/src/plugins/plugin-check.ts +232 -0
- package/packages/core/src/plugins/plugin-dev.ts +47 -0
- package/packages/core/src/plugins/plugin-finder.ts +108 -0
- package/packages/core/src/plugins/plugin-radar.ts +179 -0
- package/packages/core/src/plugins/plugin-stars.ts +205 -0
- package/packages/core/src/plugins/prompt-guard.ts +122 -0
- package/packages/core/src/plugins/prompt-library.ts +165 -0
- package/packages/core/src/plugins/readme-gen.ts +147 -0
- package/packages/core/src/plugins/recall-unread.ts +142 -0
- package/packages/core/src/plugins/resources.ts +28 -21
- package/packages/core/src/plugins/reverse-skill.ts +79 -0
- package/packages/core/src/plugins/reviewer-bot.ts +146 -0
- package/packages/core/src/plugins/runtime-doctor.ts +137 -0
- package/packages/core/src/plugins/runtime.ts +61 -14
- package/packages/core/src/plugins/secure-audit.ts +146 -0
- package/packages/core/src/plugins/session-bookmarks.ts +89 -0
- package/packages/core/src/plugins/session-bridge.ts +299 -0
- package/packages/core/src/plugins/session-compare.ts +180 -0
- package/packages/core/src/plugins/session-export.ts +99 -0
- package/packages/core/src/plugins/session-insights.ts +47 -0
- package/packages/core/src/plugins/session-search.ts +126 -0
- package/packages/core/src/plugins/session.ts +4 -2
- package/packages/core/src/plugins/skill-catalog.ts +117 -0
- package/packages/core/src/plugins/skill-guard.ts +152 -0
- package/packages/core/src/plugins/sql-lens.ts +92 -0
- package/packages/core/src/plugins/stdio.ts +3 -1
- package/packages/core/src/plugins/synapse.ts +130 -0
- package/packages/core/src/plugins/tab-manager.ts +135 -0
- package/packages/core/src/plugins/taskboard.ts +412 -0
- package/packages/core/src/plugins/telemetry-blocker.ts +62 -0
- package/packages/core/src/plugins/test-harness.ts +67 -0
- package/packages/core/src/plugins/theme-studio.ts +165 -0
- package/packages/core/src/plugins/token-guard.ts +84 -0
- package/packages/core/src/plugins/tools.ts +5 -2
- package/packages/core/src/plugins/turn-rewind.ts +86 -0
- package/packages/core/src/plugins/undo-savepoint.ts +284 -0
- package/packages/core/src/plugins/vision-toolkit.ts +153 -0
- package/packages/core/src/plugins/web-research.ts +289 -0
- package/packages/core/src/plugins/workspace-navigator.ts +164 -0
- package/packages/core/src/plugins/workspace-search.ts +139 -0
- package/packages/core/src/plugins/yaml-validator.ts +97 -0
- package/packages/core/src/profile.ts +3 -0
- package/packages/core/src/runtime.ts +11 -4
- package/packages/core/src/services.ts +110 -3
- package/packages/core/src/stdio.ts +79 -9
- package/packages/core/src/workspace-path.ts +69 -0
- package/packages/core/test/agent-teams.test.ts +24 -0
- package/packages/core/test/archify.test.ts +33 -0
- package/packages/core/test/better-sidebar.test.ts +125 -0
- package/packages/core/test/boot.test.ts +49 -6
- package/packages/core/test/colleague-skill.test.ts +74 -0
- package/packages/core/test/config.test.ts +121 -0
- package/packages/core/test/context-doctor.test.ts +32 -0
- package/packages/core/test/dependency-checker.test.ts +60 -0
- package/packages/core/test/git-time-capsule.test.ts +115 -0
- package/packages/core/test/http.test.ts +34 -0
- package/packages/core/test/llm-verifier.test.ts +72 -0
- package/packages/core/test/mirage-bridge.test.ts +54 -0
- package/packages/core/test/module-search.test.ts +78 -0
- package/packages/core/test/plugin-check.test.ts +16 -0
- package/packages/core/test/plugin-stars.test.ts +55 -0
- package/packages/core/test/profiles.integration.test.ts +49 -15
- package/packages/core/test/prompt-library.test.ts +56 -0
- package/packages/core/test/readme-gen.test.ts +45 -0
- package/packages/core/test/recall-unread.test.ts +35 -0
- package/packages/core/test/registry.test.ts +48 -0
- package/packages/core/test/reverse-skill.test.ts +40 -0
- package/packages/core/test/runtime-doctor.test.ts +55 -0
- package/packages/core/test/runtime-fixture.ts +4 -4
- package/packages/core/test/runtime.test.ts +90 -1
- package/packages/core/test/secure-audit.test.ts +16 -0
- package/packages/core/test/services.test.ts +2024 -5
- package/packages/core/test/session-bookmarks.test.ts +62 -0
- package/packages/core/test/session-bridge.test.ts +103 -0
- package/packages/core/test/session-compare.test.ts +94 -0
- package/packages/core/test/session-export.test.ts +54 -0
- package/packages/core/test/session-search.test.ts +30 -0
- package/packages/core/test/skill-catalog.test.ts +18 -0
- package/packages/core/test/skill-guard.test.ts +21 -0
- package/packages/core/test/stdio-args.test.ts +178 -0
- package/packages/core/test/theme-studio.test.ts +39 -0
- package/packages/core/test/token-guard.test.ts +34 -0
- package/packages/core/test/turn-rewind.test.ts +19 -0
- package/packages/core/test/vision-toolkit.test.ts +38 -0
- package/packages/core/test/workspace-git-status.test.ts +37 -0
- package/packages/core/test/workspace-navigator.test.ts +33 -0
- package/packages/core/test/workspace-path.test.ts +34 -0
- package/packages/core/tsconfig.build.json +1 -3
- package/packages/core/tsconfig.json +1 -4
- package/packages/host-webserver/LICENSE +9 -0
- package/packages/host-webserver/dist/index.js +1 -1
- package/packages/host-webserver/dist/index.js.map +1 -1
- package/packages/host-webserver/package.json +17 -7
- package/packages/host-webserver/src/index.ts +1 -1
- package/packages/host-webserver/test/index.test.ts +4 -1
- package/packages/host-webserver/tsconfig.build.json +1 -1
- package/packages/host-webserver/tsconfig.json +1 -1
- package/apps/web/dist/assets/index-Bwqek8LF.js +0 -20
- package/apps/web/dist/assets/index-DCHSASjq.css +0 -1
- package/packages/api-gateway/dist/marketplace-registry.json +0 -62
- package/packages/api-gateway/src/marketplace-registry.json +0 -62
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { rm } from "node:fs/promises";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
4
|
-
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { basename, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
5
6
|
import type { Context } from "@deepseek-ai/cordis";
|
|
6
|
-
import { SessionManager, type AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { SessionManager, type AgentSessionEvent, type ExtensionUIContext } from "@earendil-works/pi-coding-agent";
|
|
7
8
|
import type Loader from "@deepseek-ai/cordis-plugin-loader";
|
|
8
|
-
import type { PiRuntimeService, PiModelsService, PiHarnessLaunch } from "@pi-harness/core";
|
|
9
|
+
import type { PiPluginUiRegistry, PiRuntimeService, PiModelsService, PiHarnessLaunch } from "@pi-harness/core";
|
|
9
10
|
import type { WebServer } from "@pi-harness/host-webserver";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
MARKETPLACE_CAPABILITIES,
|
|
13
|
+
MARKETPLACE_CATEGORIES,
|
|
14
|
+
MARKETPLACE_PLUGINS,
|
|
15
|
+
attachMarketplaceStatistics,
|
|
16
|
+
createMarketplaceStatisticsLoader,
|
|
17
|
+
paginateMarketplace,
|
|
18
|
+
searchMarketplace,
|
|
19
|
+
needsMarketplacePackageInstall,
|
|
20
|
+
sortMarketplaceByRecommendation,
|
|
21
|
+
type MarketplacePlugin,
|
|
22
|
+
} from "./marketplace.js";
|
|
23
|
+
import { parseGitWorktrees, type WorkspaceSummary } from "./workspaces.js";
|
|
11
24
|
|
|
12
25
|
interface ApiServices {
|
|
13
26
|
readonly runtime: PiRuntimeService;
|
|
@@ -15,8 +28,11 @@ interface ApiServices {
|
|
|
15
28
|
readonly launch: PiHarnessLaunch;
|
|
16
29
|
readonly webServer: WebServer;
|
|
17
30
|
readonly loader: Loader | undefined;
|
|
31
|
+
readonly pluginUi: PiPluginUiRegistry | undefined;
|
|
18
32
|
}
|
|
19
33
|
|
|
34
|
+
const loadMarketplaceStatistics = createMarketplaceStatisticsLoader();
|
|
35
|
+
|
|
20
36
|
function sendJson(response: ServerResponse, status: number, payload: unknown): void {
|
|
21
37
|
const body = JSON.stringify(payload);
|
|
22
38
|
response.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "content-length": Buffer.byteLength(body) });
|
|
@@ -55,6 +71,7 @@ function jsonSafe(value: unknown, seen = new WeakSet<object>()): unknown {
|
|
|
55
71
|
|
|
56
72
|
function createStatus(services: ApiServices, events: readonly AgentSessionEvent[]) {
|
|
57
73
|
const activeModel = services.runtime.session.model ?? services.models.model;
|
|
74
|
+
const cwd = activeCwd(services);
|
|
58
75
|
return {
|
|
59
76
|
status: services.runtime.session.isStreaming ? "running" : "ready",
|
|
60
77
|
model: activeModel.provider + "/" + activeModel.id,
|
|
@@ -62,21 +79,292 @@ function createStatus(services: ApiServices, events: readonly AgentSessionEvent[
|
|
|
62
79
|
events: events.length,
|
|
63
80
|
sessionId: services.runtime.session.sessionId,
|
|
64
81
|
sessionFile: services.runtime.session.sessionFile,
|
|
65
|
-
cwd
|
|
82
|
+
cwd,
|
|
66
83
|
agentDir: services.launch.agentDir,
|
|
67
84
|
plugins: services.loader ? [...services.loader.entries()].filter((entry) => !entry.disabled).map((entry) => entry.options.name) : [],
|
|
68
85
|
};
|
|
69
86
|
}
|
|
70
87
|
|
|
88
|
+
function activeCwd(services: ApiServices): string {
|
|
89
|
+
const runtimeCwd = services.runtime.sessionRuntime?.cwd;
|
|
90
|
+
return typeof runtimeCwd === "string" && runtimeCwd.length > 0 ? runtimeCwd : services.launch.cwd;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function piConfig(services: ApiServices) {
|
|
94
|
+
const settings = services.runtime.session.settingsManager;
|
|
95
|
+
const global = settings.getGlobalSettings();
|
|
96
|
+
const compaction = settings.getCompactionSettings();
|
|
97
|
+
return {
|
|
98
|
+
path: join(services.launch.agentDir, "settings.json"),
|
|
99
|
+
scope: "global" as const,
|
|
100
|
+
source: JSON.stringify(global, null, 2) + "\n",
|
|
101
|
+
settings: {
|
|
102
|
+
defaultProvider: global.defaultProvider,
|
|
103
|
+
defaultModel: global.defaultModel,
|
|
104
|
+
defaultThinkingLevel: global.defaultThinkingLevel,
|
|
105
|
+
transport: settings.getTransport(),
|
|
106
|
+
steeringMode: settings.getSteeringMode(),
|
|
107
|
+
followUpMode: settings.getFollowUpMode(),
|
|
108
|
+
hideThinkingBlock: settings.getHideThinkingBlock(),
|
|
109
|
+
compaction,
|
|
110
|
+
retry: settings.getRetrySettings(),
|
|
111
|
+
terminal: {
|
|
112
|
+
showImages: settings.getShowImages(),
|
|
113
|
+
imageAutoResize: settings.getImageAutoResize(),
|
|
114
|
+
autocompleteMaxVisible: settings.getAutocompleteMaxVisible(),
|
|
115
|
+
},
|
|
116
|
+
advanced: {
|
|
117
|
+
quietStartup: settings.getQuietStartup(),
|
|
118
|
+
projectTrust: settings.getDefaultProjectTrust(),
|
|
119
|
+
showCacheMissNotices: settings.getShowCacheMissNotices(),
|
|
120
|
+
enableAnalytics: settings.getEnableAnalytics(),
|
|
121
|
+
enableInstallTelemetry: settings.getEnableInstallTelemetry(),
|
|
122
|
+
shellPath: settings.getShellPath(),
|
|
123
|
+
doubleEscapeAction: settings.getDoubleEscapeAction(),
|
|
124
|
+
treeFilterMode: settings.getTreeFilterMode(),
|
|
125
|
+
mermaid: settings.getMermaidRenderingMode(),
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface SessionMetadata {
|
|
132
|
+
readonly archived?: boolean;
|
|
133
|
+
readonly pinned?: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type SessionMetadataMap = Record<string, SessionMetadata>;
|
|
137
|
+
|
|
138
|
+
function sessionMetadataFile(manager: SessionManager): string {
|
|
139
|
+
return resolve(manager.getSessionDir(), ".pi-harness-session-meta.json");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function readSessionMetadata(manager: SessionManager): Promise<SessionMetadataMap> {
|
|
143
|
+
try {
|
|
144
|
+
const parsed: unknown = JSON.parse(await readFile(sessionMetadataFile(manager), "utf8"));
|
|
145
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
146
|
+
return parsed as SessionMetadataMap;
|
|
147
|
+
} catch {
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function writeSessionMetadata(manager: SessionManager, metadata: SessionMetadataMap): Promise<void> {
|
|
153
|
+
await mkdir(manager.getSessionDir(), { recursive: true });
|
|
154
|
+
await writeFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", "utf8");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function sessionPathInDirectory(path: string, manager: SessionManager): boolean {
|
|
158
|
+
const root = resolve(manager.getSessionDir());
|
|
159
|
+
const target = resolve(path);
|
|
160
|
+
const relativePath = relative(root, target);
|
|
161
|
+
return relativePath !== "" && !isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(".." + "/") && target.endsWith(".jsonl");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const webSessionUi = {
|
|
165
|
+
select: (_title: string, options: string[]) => Promise.resolve(options[0]),
|
|
166
|
+
confirm: () => Promise.resolve(true),
|
|
167
|
+
input: () => Promise.resolve(undefined),
|
|
168
|
+
notify: () => {},
|
|
169
|
+
onTerminalInput: () => () => {},
|
|
170
|
+
setStatus: () => {},
|
|
171
|
+
setWorkingMessage: () => {},
|
|
172
|
+
setWorkingVisible: () => {},
|
|
173
|
+
setWorkingIndicator: () => {},
|
|
174
|
+
setHiddenThinkingLabel: () => {},
|
|
175
|
+
setWidget: () => {},
|
|
176
|
+
setFooter: () => {},
|
|
177
|
+
setHeader: () => {},
|
|
178
|
+
setTitle: () => {},
|
|
179
|
+
} as unknown as ExtensionUIContext;
|
|
180
|
+
|
|
181
|
+
async function runWebSessionChange<T>(services: ApiServices, action: () => Promise<T & { cancelled: boolean }>): Promise<T & { cancelled: boolean }> {
|
|
182
|
+
const runner = services.runtime.session.extensionRunner;
|
|
183
|
+
runner.setUIContext(webSessionUi, "rpc");
|
|
184
|
+
try {
|
|
185
|
+
const result = await action();
|
|
186
|
+
if (result.cancelled) runner.setUIContext(undefined, "print");
|
|
187
|
+
return result;
|
|
188
|
+
} catch (error) {
|
|
189
|
+
runner.setUIContext(undefined, "print");
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
71
194
|
function modelSummary(model: { provider: string; id: string; name?: string; reasoning?: boolean; contextWindow?: number }, active: boolean) {
|
|
72
|
-
return {
|
|
195
|
+
return {
|
|
196
|
+
provider: model.provider,
|
|
197
|
+
id: model.id,
|
|
198
|
+
name: model.name ?? model.id,
|
|
199
|
+
reasoning: model.reasoning ?? false,
|
|
200
|
+
contextWindow: model.contextWindow ?? null,
|
|
201
|
+
active,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function visibleProviderIds(
|
|
206
|
+
runtime: Pick<PiModelsService["runtime"], "getModels"> &
|
|
207
|
+
Partial<Pick<PiModelsService["runtime"], "getProviders" | "getProviderAuthStatus" | "getRegisteredProviderConfig">>,
|
|
208
|
+
activeProvider: string,
|
|
209
|
+
): Set<string> {
|
|
210
|
+
const providers = typeof runtime.getProviders === "function" ? runtime.getProviders() : [{ id: activeProvider, name: activeProvider }];
|
|
211
|
+
return new Set(
|
|
212
|
+
providers
|
|
213
|
+
.filter((provider) => {
|
|
214
|
+
if (provider.id === activeProvider) return true;
|
|
215
|
+
if (typeof runtime.getProviderAuthStatus !== "function") return false;
|
|
216
|
+
const auth = runtime.getProviderAuthStatus(provider.id);
|
|
217
|
+
if (typeof auth !== "object" || auth === null || (auth as { configured?: unknown }).configured !== true) return false;
|
|
218
|
+
if (typeof runtime.getRegisteredProviderConfig === "function") return runtime.getRegisteredProviderConfig(provider.id) !== undefined;
|
|
219
|
+
return true;
|
|
220
|
+
})
|
|
221
|
+
.map((provider) => provider.id),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
type LoaderEntrySummary = { options: { id: string; name: string; disabled?: boolean | null }; fiber?: { state: unknown } };
|
|
226
|
+
|
|
227
|
+
function marketplacePluginForEntry(entry: LoaderEntrySummary): MarketplacePlugin | undefined {
|
|
228
|
+
return MARKETPLACE_PLUGINS.find((plugin) => plugin.packageName === entry.options.name);
|
|
73
229
|
}
|
|
74
230
|
|
|
75
|
-
function pluginSummary(entry:
|
|
231
|
+
function pluginSummary(entry: LoaderEntrySummary) {
|
|
76
232
|
const states = ["pending", "loading", "active", "failed", "disposed", "unloading"];
|
|
233
|
+
const marketplacePlugin = marketplacePluginForEntry(entry);
|
|
77
234
|
const rawState = entry.fiber?.state;
|
|
78
|
-
const state =
|
|
79
|
-
|
|
235
|
+
const state =
|
|
236
|
+
typeof rawState === "number"
|
|
237
|
+
? (states[rawState] ?? String(rawState))
|
|
238
|
+
: typeof rawState === "string"
|
|
239
|
+
? rawState
|
|
240
|
+
: rawState === undefined || rawState === null
|
|
241
|
+
? "unloaded"
|
|
242
|
+
: "unknown";
|
|
243
|
+
return {
|
|
244
|
+
id: entry.options.id,
|
|
245
|
+
name: entry.options.name,
|
|
246
|
+
enabled: !entry.options.disabled,
|
|
247
|
+
state,
|
|
248
|
+
removable: entry.options.id.startsWith("marketplace-") || marketplacePlugin !== undefined,
|
|
249
|
+
category: marketplacePlugin?.category,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function pluginLoaded(services: ApiServices, packageName: string): boolean {
|
|
254
|
+
return services.loader !== undefined && [...services.loader.entries()].some((entry) => entry.options.name === packageName && !entry.disabled);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function registerPluginPanels(context: Context, services: ApiServices): () => void {
|
|
258
|
+
if (services.pluginUi === undefined) return () => {};
|
|
259
|
+
const disposers = [
|
|
260
|
+
services.pluginUi.register({
|
|
261
|
+
id: "console-logger-panel",
|
|
262
|
+
pluginId: "@deepseek-ai/cordis-plugin-logger-console",
|
|
263
|
+
title: "运行时日志",
|
|
264
|
+
description: "查看最近的生命周期和运行时诊断输出。",
|
|
265
|
+
icon: "▤",
|
|
266
|
+
visible: () => pluginLoaded(services, "@deepseek-ai/cordis-plugin-logger-console"),
|
|
267
|
+
read: () => ({
|
|
268
|
+
total: context.logger.buffer.length,
|
|
269
|
+
items: context.logger.buffer.slice(-40).map((message) => ({
|
|
270
|
+
time: new Date(message.ts).toISOString(),
|
|
271
|
+
level: message.type,
|
|
272
|
+
source: message.name,
|
|
273
|
+
args: message.args,
|
|
274
|
+
})),
|
|
275
|
+
}),
|
|
276
|
+
}),
|
|
277
|
+
services.pluginUi.register({
|
|
278
|
+
id: "plugin-group-panel",
|
|
279
|
+
pluginId: "@deepseek-ai/cordis-plugin-group",
|
|
280
|
+
title: "插件树",
|
|
281
|
+
description: "查看当前运行时加载的插件树和生命周期状态。",
|
|
282
|
+
icon: "⌘",
|
|
283
|
+
visible: () => pluginLoaded(services, "@deepseek-ai/cordis-plugin-group"),
|
|
284
|
+
read: () => ({
|
|
285
|
+
entries:
|
|
286
|
+
services.loader === undefined
|
|
287
|
+
? []
|
|
288
|
+
: [...services.loader.entries()].map((entry) => ({
|
|
289
|
+
id: entry.id,
|
|
290
|
+
name: entry.options.name.replace(/^@deepseek-ai\/cordis-plugin-/i, "plugin-").replace(/^cordis:/i, "runtime:"),
|
|
291
|
+
state: pluginSummary(entry).state,
|
|
292
|
+
enabled: !entry.disabled,
|
|
293
|
+
})),
|
|
294
|
+
}),
|
|
295
|
+
}),
|
|
296
|
+
services.pluginUi.register({
|
|
297
|
+
id: "timer-service-panel",
|
|
298
|
+
pluginId: "@deepseek-ai/cordis-plugin-timer",
|
|
299
|
+
title: "定时器服务",
|
|
300
|
+
description: "确认定时器服务已注册,并查看可用的生命周期绑定 API。",
|
|
301
|
+
icon: "◷",
|
|
302
|
+
visible: () => pluginLoaded(services, "@deepseek-ai/cordis-plugin-timer"),
|
|
303
|
+
read: () => ({
|
|
304
|
+
registered: context.reflect.get("timer") !== undefined,
|
|
305
|
+
capabilities: ["timeout", "interval", "throttle", "debounce"],
|
|
306
|
+
}),
|
|
307
|
+
}),
|
|
308
|
+
];
|
|
309
|
+
return () => disposers.reverse().forEach((dispose) => dispose());
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function runProcess(executable: string, args: readonly string[], cwd: string): Promise<{ stdout: string; stderr: string }> {
|
|
313
|
+
return new Promise((resolveProcess, rejectProcess) => {
|
|
314
|
+
execFile(executable, [...args], { cwd, timeout: 120_000, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
315
|
+
if (error) {
|
|
316
|
+
rejectProcess(new Error(`${executable} ${args.join(" ")} failed: ${stderr || error.message}`, { cause: error }));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
resolveProcess({ stdout, stderr });
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function appendMarketplaceProfile(configPath: string, plugin: MarketplacePlugin): Promise<string> {
|
|
325
|
+
const source = await readFile(configPath, "utf8");
|
|
326
|
+
if (source.includes(`name: ${JSON.stringify(plugin.packageName)}`)) return source;
|
|
327
|
+
const entryId = `marketplace-${plugin.id}`;
|
|
328
|
+
const config = JSON.stringify(plugin.profile.config);
|
|
329
|
+
const group = plugin.profile.group === true ? "\n group: true" : "";
|
|
330
|
+
const entry = `\n- id: ${entryId}\n name: ${JSON.stringify(plugin.packageName)}${group}\n config: ${config}\n`;
|
|
331
|
+
await writeFile(configPath, source.replace(/\s*$/, "") + entry, "utf8");
|
|
332
|
+
return source;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function updateMarketplaceProfile(configPath: string, entryId: string, update: { disabled?: boolean; remove?: boolean }): Promise<string> {
|
|
336
|
+
const source = await readFile(configPath, "utf8");
|
|
337
|
+
const escapedId = entryId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
338
|
+
const pattern = new RegExp(`^([ \\t]*)- id: ${escapedId}[ \\t]*(?:\\r?\\n|$)`, "m");
|
|
339
|
+
const match = source.match(pattern);
|
|
340
|
+
if (match === null) throw new Error(`Installed plugin profile entry was not found: ${entryId}`);
|
|
341
|
+
const indent = match[1] ?? "";
|
|
342
|
+
const start = match.index ?? 0;
|
|
343
|
+
let end = source.length;
|
|
344
|
+
const linePattern = /^([ \t]*)(?=\S)/gm;
|
|
345
|
+
linePattern.lastIndex = start + match[0].length;
|
|
346
|
+
for (let line = linePattern.exec(source); line !== null; line = linePattern.exec(source)) {
|
|
347
|
+
const lineIndent = line[1] ?? "";
|
|
348
|
+
const content = source.slice(line.index + lineIndent.length);
|
|
349
|
+
if (lineIndent.length < indent.length || (lineIndent === indent && content.startsWith("- "))) {
|
|
350
|
+
end = line.index;
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const originalBlock = source.slice(start, end);
|
|
355
|
+
if (update.remove === true) {
|
|
356
|
+
await writeFile(configPath, source.slice(0, start) + source.slice(end), "utf8");
|
|
357
|
+
return source;
|
|
358
|
+
}
|
|
359
|
+
const childIndent = `${indent} `;
|
|
360
|
+
const disabledPattern = new RegExp(`^${childIndent}disabled: .*\\r?\\n`, "m");
|
|
361
|
+
let block = originalBlock.replace(disabledPattern, "");
|
|
362
|
+
if (update.disabled === true) {
|
|
363
|
+
const namePattern = new RegExp(`^(${childIndent}name: .*\\r?\\n)`, "m");
|
|
364
|
+
block = block.replace(namePattern, `$1${childIndent}disabled: true\n`);
|
|
365
|
+
}
|
|
366
|
+
await writeFile(configPath, source.slice(0, start) + block + source.slice(end), "utf8");
|
|
367
|
+
return source;
|
|
80
368
|
}
|
|
81
369
|
|
|
82
370
|
function writeSse(response: ServerResponse, payload: unknown): void {
|
|
@@ -91,7 +379,9 @@ function gitStatus(cwd: string): Promise<string> {
|
|
|
91
379
|
|
|
92
380
|
function gitDiff(cwd: string, path: string): Promise<string> {
|
|
93
381
|
return new Promise((resolveOutput) => {
|
|
94
|
-
execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, maxBuffer: 1024 * 1024 }, (error, stdout) =>
|
|
382
|
+
execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, maxBuffer: 1024 * 1024 }, (error, stdout) =>
|
|
383
|
+
resolveOutput(error && stdout.length === 0 ? "" : stdout),
|
|
384
|
+
);
|
|
95
385
|
});
|
|
96
386
|
}
|
|
97
387
|
|
|
@@ -104,8 +394,62 @@ function gitCommand(cwd: string, args: readonly string[]): Promise<{ stdout: str
|
|
|
104
394
|
});
|
|
105
395
|
}
|
|
106
396
|
|
|
397
|
+
interface EveryApiCliAuthStatus {
|
|
398
|
+
configured: false;
|
|
399
|
+
source: "everyapi-cli";
|
|
400
|
+
label: string;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function probeEveryApiCliAuth(): Promise<EveryApiCliAuthStatus> {
|
|
404
|
+
const executable = process.env.EVERYAPI_CLI_PATH?.trim() || "everyapi";
|
|
405
|
+
return new Promise((resolveStatus) => {
|
|
406
|
+
execFile(executable, ["auth", "status"], { timeout: 3_000, maxBuffer: 128 * 1024 }, (error) => {
|
|
407
|
+
resolveStatus({
|
|
408
|
+
configured: false,
|
|
409
|
+
source: "everyapi-cli",
|
|
410
|
+
label: error ? "未检测到 EveryAPI CLI 登录" : "EveryAPI CLI 已登录,但 relay key 未注入当前进程",
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async function listWorkspaces(cwd: string): Promise<readonly WorkspaceSummary[]> {
|
|
417
|
+
const result = await gitCommand(cwd, ["worktree", "list", "--porcelain"]);
|
|
418
|
+
const parsed = result.code === 0 ? parseGitWorktrees(result.stdout, cwd) : [];
|
|
419
|
+
if (parsed.some((item) => item.current)) return parsed;
|
|
420
|
+
return [{ path: resolve(cwd), branch: "current", current: true, name: resolve(cwd).split("/").pop() ?? resolve(cwd) }, ...parsed];
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function isDirectory(path: string): Promise<boolean> {
|
|
424
|
+
try {
|
|
425
|
+
return (await stat(path)).isDirectory();
|
|
426
|
+
} catch {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function pickDirectory(): Promise<string> {
|
|
432
|
+
return new Promise((resolvePath, reject) => {
|
|
433
|
+
execFile(
|
|
434
|
+
"osascript",
|
|
435
|
+
["-e", 'POSIX path of (choose folder with prompt "选择 Pi 工作区")'],
|
|
436
|
+
{ timeout: 120_000, maxBuffer: 64 * 1024 },
|
|
437
|
+
(error, stdout, stderr) => {
|
|
438
|
+
if (error) {
|
|
439
|
+
reject(new Error(stderr.trim() || "目录选择已取消"));
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const path = stdout.trim();
|
|
443
|
+
if (!path) reject(new Error("目录选择已取消"));
|
|
444
|
+
else resolvePath(path);
|
|
445
|
+
},
|
|
446
|
+
);
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
107
450
|
function workspacePaths(root: string, paths: unknown): string[] | Error {
|
|
108
|
-
if (!Array.isArray(paths) || paths.length === 0 || paths.some((path) => typeof path !== "string" || path.trim() === ""))
|
|
451
|
+
if (!Array.isArray(paths) || paths.length === 0 || paths.some((path) => typeof path !== "string" || path.trim() === ""))
|
|
452
|
+
return new Error("paths must be a non-empty array of strings");
|
|
109
453
|
const normalized: string[] = [];
|
|
110
454
|
for (const path of paths) {
|
|
111
455
|
const requested = path as string;
|
|
@@ -122,12 +466,14 @@ export default {
|
|
|
122
466
|
inject: ["webServer", "piRuntime", "piModels", "piHarnessLaunch"],
|
|
123
467
|
apply(context: Context) {
|
|
124
468
|
const services: ApiServices = {
|
|
125
|
-
runtime: context.piRuntime,
|
|
126
|
-
models: context.piModels,
|
|
127
|
-
launch: context.piHarnessLaunch,
|
|
469
|
+
runtime: context.reflect.get("piRuntime") as PiRuntimeService,
|
|
470
|
+
models: context.reflect.get("piModels") as PiModelsService,
|
|
471
|
+
launch: context.reflect.get("piHarnessLaunch") as PiHarnessLaunch,
|
|
128
472
|
webServer: context.webServer,
|
|
129
473
|
loader: context.reflect.get("loader") as Loader | undefined,
|
|
474
|
+
pluginUi: context.reflect.get("piPluginUi") as PiPluginUiRegistry | undefined,
|
|
130
475
|
};
|
|
476
|
+
const disposePluginPanels = registerPluginPanels(context, services);
|
|
131
477
|
let busy = false;
|
|
132
478
|
const events: AgentSessionEvent[] = [];
|
|
133
479
|
const eventClients = new Set<ServerResponse>();
|
|
@@ -142,7 +488,7 @@ export default {
|
|
|
142
488
|
}
|
|
143
489
|
};
|
|
144
490
|
const unsubscribeEvents = services.runtime.sessionRuntime
|
|
145
|
-
? context.on("pi/session-event", handleEvent)
|
|
491
|
+
? context.on("pi/session-event" as never, handleEvent as never)
|
|
146
492
|
: services.runtime.session.subscribe(handleEvent);
|
|
147
493
|
const disposeStatus = services.webServer.register({
|
|
148
494
|
path: "/api/status",
|
|
@@ -150,26 +496,238 @@ export default {
|
|
|
150
496
|
sendJson(response, 200, createStatus(services, events));
|
|
151
497
|
},
|
|
152
498
|
});
|
|
499
|
+
const disposeConfig = services.webServer.register({
|
|
500
|
+
path: "/api/config",
|
|
501
|
+
async handler(request, response) {
|
|
502
|
+
if (request.method === "GET") {
|
|
503
|
+
sendJson(response, 200, piConfig(services));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (request.method !== "POST") {
|
|
507
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
try {
|
|
511
|
+
const payload = JSON.parse(await bodyText(request)) as Record<string, unknown>;
|
|
512
|
+
const settings = services.runtime.session.settingsManager;
|
|
513
|
+
if (typeof payload.defaultProvider === "string" && payload.defaultProvider.trim()) settings.setDefaultProvider(payload.defaultProvider.trim());
|
|
514
|
+
if (typeof payload.defaultModel === "string" && payload.defaultModel.trim()) settings.setDefaultModel(payload.defaultModel.trim());
|
|
515
|
+
if (
|
|
516
|
+
payload.defaultThinkingLevel === "off" ||
|
|
517
|
+
payload.defaultThinkingLevel === "minimal" ||
|
|
518
|
+
payload.defaultThinkingLevel === "low" ||
|
|
519
|
+
payload.defaultThinkingLevel === "medium" ||
|
|
520
|
+
payload.defaultThinkingLevel === "high" ||
|
|
521
|
+
payload.defaultThinkingLevel === "xhigh" ||
|
|
522
|
+
payload.defaultThinkingLevel === "max"
|
|
523
|
+
)
|
|
524
|
+
settings.setDefaultThinkingLevel(payload.defaultThinkingLevel);
|
|
525
|
+
if (payload.transport === "sse" || payload.transport === "websocket" || payload.transport === "auto") settings.setTransport(payload.transport);
|
|
526
|
+
if (payload.steeringMode === "all" || payload.steeringMode === "one-at-a-time") settings.setSteeringMode(payload.steeringMode);
|
|
527
|
+
if (payload.followUpMode === "all" || payload.followUpMode === "one-at-a-time") settings.setFollowUpMode(payload.followUpMode);
|
|
528
|
+
if (typeof payload.hideThinkingBlock === "boolean") settings.setHideThinkingBlock(payload.hideThinkingBlock);
|
|
529
|
+
if (typeof payload.retry === "object" && payload.retry !== null) {
|
|
530
|
+
const retry = payload.retry as Record<string, unknown>;
|
|
531
|
+
if (typeof retry.enabled === "boolean") settings.setRetryEnabled(retry.enabled);
|
|
532
|
+
}
|
|
533
|
+
if (typeof payload.terminal === "object" && payload.terminal !== null) {
|
|
534
|
+
const terminal = payload.terminal as Record<string, unknown>;
|
|
535
|
+
if (typeof terminal.showImages === "boolean") settings.setShowImages(terminal.showImages);
|
|
536
|
+
if (typeof terminal.imageAutoResize === "boolean") settings.setImageAutoResize(terminal.imageAutoResize);
|
|
537
|
+
if (typeof terminal.autocompleteMaxVisible === "number" && Number.isInteger(terminal.autocompleteMaxVisible))
|
|
538
|
+
settings.setAutocompleteMaxVisible(Math.min(20, Math.max(3, terminal.autocompleteMaxVisible)));
|
|
539
|
+
}
|
|
540
|
+
if (typeof payload.advanced === "object" && payload.advanced !== null) {
|
|
541
|
+
const advanced = payload.advanced as Record<string, unknown>;
|
|
542
|
+
if (typeof advanced.quietStartup === "boolean") settings.setQuietStartup(advanced.quietStartup);
|
|
543
|
+
if (advanced.projectTrust === "ask" || advanced.projectTrust === "always" || advanced.projectTrust === "never")
|
|
544
|
+
settings.setDefaultProjectTrust(advanced.projectTrust);
|
|
545
|
+
if (typeof advanced.showCacheMissNotices === "boolean") settings.setShowCacheMissNotices(advanced.showCacheMissNotices);
|
|
546
|
+
if (typeof advanced.enableInstallTelemetry === "boolean") settings.setEnableInstallTelemetry(advanced.enableInstallTelemetry);
|
|
547
|
+
if (typeof advanced.shellPath === "string") settings.setShellPath(advanced.shellPath.trim() || undefined);
|
|
548
|
+
if (advanced.doubleEscapeAction === "fork" || advanced.doubleEscapeAction === "tree" || advanced.doubleEscapeAction === "none")
|
|
549
|
+
settings.setDoubleEscapeAction(advanced.doubleEscapeAction);
|
|
550
|
+
if (
|
|
551
|
+
advanced.treeFilterMode === "default" ||
|
|
552
|
+
advanced.treeFilterMode === "no-tools" ||
|
|
553
|
+
advanced.treeFilterMode === "user-only" ||
|
|
554
|
+
advanced.treeFilterMode === "labeled-only" ||
|
|
555
|
+
advanced.treeFilterMode === "all"
|
|
556
|
+
)
|
|
557
|
+
settings.setTreeFilterMode(advanced.treeFilterMode);
|
|
558
|
+
if (advanced.mermaid === "off" || advanced.mermaid === "final" || advanced.mermaid === "streaming")
|
|
559
|
+
settings.setMermaidRenderingMode(advanced.mermaid);
|
|
560
|
+
}
|
|
561
|
+
if (
|
|
562
|
+
typeof payload.compaction === "object" &&
|
|
563
|
+
payload.compaction !== null &&
|
|
564
|
+
typeof (payload.compaction as Record<string, unknown>).enabled === "boolean"
|
|
565
|
+
)
|
|
566
|
+
settings.setCompactionEnabled((payload.compaction as Record<string, boolean>).enabled === true);
|
|
567
|
+
await settings.flush();
|
|
568
|
+
sendJson(response, 200, piConfig(services));
|
|
569
|
+
} catch (error) {
|
|
570
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
const disposeConfigReload = services.webServer.register({
|
|
575
|
+
path: "/api/config/reload",
|
|
576
|
+
async handler(request, response) {
|
|
577
|
+
if (request.method !== "POST") {
|
|
578
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
await services.runtime.session.settingsManager.reload();
|
|
583
|
+
sendJson(response, 200, piConfig(services));
|
|
584
|
+
} catch (error) {
|
|
585
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
});
|
|
589
|
+
const disposeConfigSource = services.webServer.register({
|
|
590
|
+
path: "/api/config/source",
|
|
591
|
+
async handler(request, response) {
|
|
592
|
+
if (request.method !== "POST") {
|
|
593
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
const payload = JSON.parse(await bodyText(request)) as { source?: unknown };
|
|
598
|
+
if (typeof payload.source !== "string" || payload.source.length > 128 * 1024) {
|
|
599
|
+
sendJson(response, 400, { error: "source must be a JSON document smaller than 128 KiB" });
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const parsed: unknown = JSON.parse(payload.source);
|
|
603
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
604
|
+
sendJson(response, 400, { error: "settings source must contain a JSON object" });
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const path = join(services.launch.agentDir, "settings.json");
|
|
608
|
+
await writeFile(path, JSON.stringify(parsed, null, 2) + "\n", "utf8");
|
|
609
|
+
await services.runtime.session.settingsManager.reload();
|
|
610
|
+
sendJson(response, 200, piConfig(services));
|
|
611
|
+
} catch (error) {
|
|
612
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
});
|
|
153
616
|
const disposeModels = services.webServer.register({
|
|
154
617
|
path: "/api/models",
|
|
155
618
|
handler(_request, response) {
|
|
156
619
|
const active = services.runtime.session.model ?? services.models.model;
|
|
157
|
-
|
|
620
|
+
const visible = visibleProviderIds(services.models.runtime, active.provider);
|
|
621
|
+
sendJson(
|
|
622
|
+
response,
|
|
623
|
+
200,
|
|
624
|
+
jsonSafe({
|
|
625
|
+
items: services.models.runtime
|
|
626
|
+
.getModels()
|
|
627
|
+
.filter((model) => visible.has(model.provider))
|
|
628
|
+
.map((model) => modelSummary(model, model.provider === active.provider && model.id === active.id)),
|
|
629
|
+
}),
|
|
630
|
+
);
|
|
158
631
|
},
|
|
159
632
|
});
|
|
160
633
|
const disposeProviders = services.webServer.register({
|
|
161
634
|
path: "/api/providers",
|
|
162
635
|
handler(_request, response) {
|
|
163
636
|
const active = services.runtime.session.model ?? services.models.model;
|
|
164
|
-
const runtime = services.models.runtime as typeof services.models.runtime & {
|
|
637
|
+
const runtime = services.models.runtime as typeof services.models.runtime & {
|
|
638
|
+
getProviders?: () => readonly { id: string; name?: string }[];
|
|
639
|
+
getProviderAuthStatus?: (provider: string) => unknown;
|
|
640
|
+
};
|
|
165
641
|
const providers = typeof runtime.getProviders === "function" ? runtime.getProviders() : [{ id: active.provider, name: active.provider }];
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
642
|
+
const visibleIds = visibleProviderIds(runtime, active.provider);
|
|
643
|
+
const visible = providers.filter((provider) => visibleIds.has(provider.id));
|
|
644
|
+
sendJson(
|
|
645
|
+
response,
|
|
646
|
+
200,
|
|
647
|
+
jsonSafe({
|
|
648
|
+
items: visible.map((provider) => ({
|
|
649
|
+
provider: provider.id,
|
|
650
|
+
name: provider.name ?? provider.id,
|
|
651
|
+
active: provider.id === active.provider,
|
|
652
|
+
auth: typeof runtime.getProviderAuthStatus === "function" ? runtime.getProviderAuthStatus(provider.id) : undefined,
|
|
653
|
+
activeModel: provider.id === active.provider ? modelSummary(active, true) : undefined,
|
|
654
|
+
models: services.models.runtime
|
|
655
|
+
.getModels(provider.id)
|
|
656
|
+
.map((model) => modelSummary(model, model.provider === active.provider && model.id === active.id)),
|
|
657
|
+
})),
|
|
658
|
+
}),
|
|
659
|
+
);
|
|
660
|
+
},
|
|
661
|
+
});
|
|
662
|
+
const disposeProviderAdd = services.webServer.register({
|
|
663
|
+
path: "/api/providers/add",
|
|
664
|
+
async handler(request, response) {
|
|
665
|
+
if (request.method !== "POST") {
|
|
666
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
try {
|
|
670
|
+
const payload = JSON.parse(await bodyText(request)) as {
|
|
671
|
+
provider?: unknown;
|
|
672
|
+
name?: unknown;
|
|
673
|
+
baseUrl?: unknown;
|
|
674
|
+
api?: unknown;
|
|
675
|
+
apiKey?: unknown;
|
|
676
|
+
model?: unknown;
|
|
677
|
+
};
|
|
678
|
+
const provider = typeof payload.provider === "string" ? payload.provider.trim() : "";
|
|
679
|
+
const name = typeof payload.name === "string" && payload.name.trim() !== "" ? payload.name.trim() : provider;
|
|
680
|
+
const baseUrl = typeof payload.baseUrl === "string" ? payload.baseUrl.trim() : "";
|
|
681
|
+
const apiKey = typeof payload.apiKey === "string" ? payload.apiKey.trim() : "";
|
|
682
|
+
const model = typeof payload.model === "string" ? payload.model.trim() : "";
|
|
683
|
+
const api = payload.api === "openai-responses" ? "openai-responses" : "openai-completions";
|
|
684
|
+
if (!/^[a-z0-9][a-z0-9._-]{1,63}$/i.test(provider)) {
|
|
685
|
+
sendJson(response, 400, { error: "provider must be 2-64 characters using letters, numbers, ., _, or -" });
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (!/^https?:\/\/[^\s]+$/i.test(baseUrl)) {
|
|
689
|
+
sendJson(response, 400, { error: "baseUrl must be an http(s) URL" });
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
if (!apiKey || !model) {
|
|
693
|
+
sendJson(response, 400, { error: "apiKey and model are required" });
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const runtime = services.models.runtime;
|
|
697
|
+
if (runtime.getProvider(provider) !== undefined) {
|
|
698
|
+
sendJson(response, 409, { error: `Provider already exists: ${provider}` });
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
runtime.registerProvider(provider, {
|
|
702
|
+
name,
|
|
703
|
+
baseUrl,
|
|
704
|
+
api,
|
|
705
|
+
models: [
|
|
706
|
+
{
|
|
707
|
+
id: model,
|
|
708
|
+
name: model,
|
|
709
|
+
api,
|
|
710
|
+
reasoning: false,
|
|
711
|
+
input: ["text"],
|
|
712
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
713
|
+
contextWindow: 128000,
|
|
714
|
+
maxTokens: 8192,
|
|
715
|
+
},
|
|
716
|
+
],
|
|
717
|
+
});
|
|
718
|
+
await runtime.setRuntimeApiKey(provider, apiKey);
|
|
719
|
+
sendJson(response, 201, {
|
|
720
|
+
provider: {
|
|
721
|
+
provider,
|
|
722
|
+
name,
|
|
723
|
+
active: false,
|
|
724
|
+
auth: runtime.getProviderAuthStatus(provider),
|
|
725
|
+
models: runtime.getModels(provider).map((item) => modelSummary(item, false)),
|
|
726
|
+
},
|
|
727
|
+
});
|
|
728
|
+
} catch (error) {
|
|
729
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
730
|
+
}
|
|
173
731
|
},
|
|
174
732
|
});
|
|
175
733
|
const disposeProviderTest = services.webServer.register({
|
|
@@ -191,6 +749,11 @@ export default {
|
|
|
191
749
|
return;
|
|
192
750
|
}
|
|
193
751
|
const auth = await runtime.checkAuth(payload.provider);
|
|
752
|
+
if (payload.provider === "everyapi" && auth === undefined && !process.env.EVERYAPI_RELAY_KEY?.trim()) {
|
|
753
|
+
const cliAuth = await probeEveryApiCliAuth();
|
|
754
|
+
sendJson(response, 200, { provider: payload.provider, reachable: false, auth: cliAuth });
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
194
757
|
sendJson(response, 200, jsonSafe({ provider: payload.provider, reachable: auth !== undefined, auth }));
|
|
195
758
|
} catch (error) {
|
|
196
759
|
sendJson(response, 502, { error: errorText(error) });
|
|
@@ -229,9 +792,24 @@ export default {
|
|
|
229
792
|
sendJson(response, 200, jsonSafe({ items }));
|
|
230
793
|
},
|
|
231
794
|
});
|
|
795
|
+
const disposePluginUi = services.webServer.register({
|
|
796
|
+
path: "/api/plugin-ui",
|
|
797
|
+
async handler(request, response) {
|
|
798
|
+
if (request.method !== "GET") {
|
|
799
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
try {
|
|
803
|
+
const items = services.pluginUi === undefined ? [] : await services.pluginUi.snapshot();
|
|
804
|
+
sendJson(response, 200, jsonSafe({ items }));
|
|
805
|
+
} catch (error) {
|
|
806
|
+
sendJson(response, 500, { error: errorText(error) });
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
});
|
|
232
810
|
const disposeMarketplace = services.webServer.register({
|
|
233
811
|
path: "/api/marketplace",
|
|
234
|
-
handler(request, response) {
|
|
812
|
+
async handler(request, response) {
|
|
235
813
|
if (request.method !== "GET") {
|
|
236
814
|
sendJson(response, 405, { error: "Method not allowed" });
|
|
237
815
|
return;
|
|
@@ -239,21 +817,264 @@ export default {
|
|
|
239
817
|
const url = new URL(request.url ?? "/api/marketplace", "http://localhost");
|
|
240
818
|
const query = url.searchParams.get("q") ?? "";
|
|
241
819
|
const capability = url.searchParams.get("capability") ?? "";
|
|
242
|
-
|
|
243
|
-
|
|
820
|
+
const category = url.searchParams.get("category") ?? "";
|
|
821
|
+
const page = Number(url.searchParams.get("page") ?? "0");
|
|
822
|
+
const pageSize = Number(url.searchParams.get("pageSize") ?? "24");
|
|
823
|
+
const sort = url.searchParams.get("sort") ?? "";
|
|
824
|
+
if (
|
|
825
|
+
query.length > 120 ||
|
|
826
|
+
capability.length > 80 ||
|
|
827
|
+
category.length > 80 ||
|
|
828
|
+
!Number.isInteger(page) ||
|
|
829
|
+
page < 0 ||
|
|
830
|
+
!Number.isInteger(pageSize) ||
|
|
831
|
+
pageSize < 1 ||
|
|
832
|
+
pageSize > 100 ||
|
|
833
|
+
(sort !== "" && sort !== "recommended")
|
|
834
|
+
) {
|
|
835
|
+
sendJson(response, 400, { error: "Invalid marketplace query" });
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
const filtered = searchMarketplace(query, capability, category);
|
|
839
|
+
const items =
|
|
840
|
+
sort === "recommended"
|
|
841
|
+
? sortMarketplaceByRecommendation(attachMarketplaceStatistics(filtered, await loadMarketplaceStatistics(MARKETPLACE_PLUGINS)))
|
|
842
|
+
: filtered;
|
|
843
|
+
sendJson(response, 200, {
|
|
844
|
+
...paginateMarketplace(items, page, pageSize),
|
|
845
|
+
capabilities: MARKETPLACE_CAPABILITIES,
|
|
846
|
+
categories: MARKETPLACE_CATEGORIES,
|
|
847
|
+
});
|
|
848
|
+
},
|
|
849
|
+
});
|
|
850
|
+
let marketplaceMutationInFlight = false;
|
|
851
|
+
const disposeMarketplaceInstall = services.webServer.register({
|
|
852
|
+
path: "/api/marketplace/install",
|
|
853
|
+
async handler(request, response) {
|
|
854
|
+
if (request.method !== "POST") {
|
|
855
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (marketplaceMutationInFlight) {
|
|
859
|
+
sendJson(response, 409, { error: "Another marketplace plugin change is already running" });
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const loader = services.loader;
|
|
863
|
+
const configPath = services.launch.configPath;
|
|
864
|
+
if (loader === undefined || configPath === undefined) {
|
|
865
|
+
sendJson(response, 501, { error: "Plugin installation is unavailable for this runtime" });
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
marketplaceMutationInFlight = true;
|
|
869
|
+
try {
|
|
870
|
+
const payload = JSON.parse(await bodyText(request)) as { id?: unknown };
|
|
871
|
+
if (typeof payload.id !== "string" || payload.id.trim() === "") {
|
|
872
|
+
sendJson(response, 400, { error: "id is required" });
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
const plugin = MARKETPLACE_PLUGINS.find((item) => item.id === payload.id);
|
|
876
|
+
if (plugin === undefined) {
|
|
877
|
+
sendJson(response, 404, { error: "Marketplace plugin was not found" });
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
const existing = [...loader.entries()].find((entry) => entry.options.name === plugin.packageName);
|
|
881
|
+
if (existing !== undefined) {
|
|
882
|
+
sendJson(response, 409, { error: "Plugin is already installed", plugin });
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const packageJsonPath = join(services.launch.cwd, "package.json");
|
|
886
|
+
const packageLockPath = join(services.launch.cwd, "package-lock.json");
|
|
887
|
+
const packageJsonBefore = await readFile(packageJsonPath, "utf8").catch(() => undefined);
|
|
888
|
+
const packageLockBefore = await readFile(packageLockPath, "utf8").catch(() => undefined);
|
|
889
|
+
let profileBefore: string | undefined;
|
|
890
|
+
let entryId: string | undefined;
|
|
891
|
+
try {
|
|
892
|
+
if (needsMarketplacePackageInstall(plugin)) {
|
|
893
|
+
await runProcess("npm", ["install", "--save-exact", "--package-lock=false", `${plugin.packageName}@${plugin.version}`], services.launch.cwd);
|
|
894
|
+
}
|
|
895
|
+
profileBefore = await appendMarketplaceProfile(configPath, plugin);
|
|
896
|
+
if (!needsMarketplacePackageInstall(plugin)) {
|
|
897
|
+
sendJson(response, 200, { plugin, installed: false, restartRequired: true });
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
entryId = await loader.create({
|
|
901
|
+
id: `marketplace-${plugin.id}`,
|
|
902
|
+
name: plugin.packageName,
|
|
903
|
+
...(plugin.profile.group === true ? { group: true } : {}),
|
|
904
|
+
config: plugin.profile.config,
|
|
905
|
+
} as never);
|
|
906
|
+
const entry = loader.resolve(entryId);
|
|
907
|
+
if (entry.fiber === undefined) throw new Error(`Plugin ${plugin.packageName} did not create a runtime fiber`);
|
|
908
|
+
await entry.fiber.await();
|
|
909
|
+
sendJson(response, 200, { plugin, installed: true });
|
|
910
|
+
} catch (error) {
|
|
911
|
+
if (entryId !== undefined) await loader.remove(entryId).catch(() => {});
|
|
912
|
+
if (profileBefore !== undefined) await writeFile(configPath, profileBefore, "utf8").catch(() => {});
|
|
913
|
+
if (packageJsonBefore !== undefined) await writeFile(packageJsonPath, packageJsonBefore, "utf8").catch(() => {});
|
|
914
|
+
if (packageLockBefore !== undefined) await writeFile(packageLockPath, packageLockBefore, "utf8").catch(() => {});
|
|
915
|
+
sendJson(response, 502, { error: errorText(error) });
|
|
916
|
+
}
|
|
917
|
+
} catch (error) {
|
|
918
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
919
|
+
} finally {
|
|
920
|
+
marketplaceMutationInFlight = false;
|
|
921
|
+
}
|
|
922
|
+
},
|
|
923
|
+
});
|
|
924
|
+
const disposePluginToggle = services.webServer.register({
|
|
925
|
+
path: "/api/plugins/toggle",
|
|
926
|
+
async handler(request, response) {
|
|
927
|
+
if (request.method !== "POST") {
|
|
928
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const configPath = services.launch.configPath;
|
|
932
|
+
const loader = services.loader;
|
|
933
|
+
if (configPath === undefined || loader === undefined) {
|
|
934
|
+
sendJson(response, 501, { error: "Plugin configuration is unavailable for this runtime" });
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (marketplaceMutationInFlight) {
|
|
938
|
+
sendJson(response, 409, { error: "Another marketplace plugin change is already running" });
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
marketplaceMutationInFlight = true;
|
|
942
|
+
try {
|
|
943
|
+
const payload = JSON.parse(await bodyText(request)) as { id?: unknown; enabled?: unknown };
|
|
944
|
+
if (typeof payload.id !== "string" || typeof payload.enabled !== "boolean") {
|
|
945
|
+
sendJson(response, 400, { error: "A marketplace plugin id and enabled boolean are required" });
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const entry = [...loader.entries()].find((item) => item.id === payload.id || item.options.id === payload.id);
|
|
949
|
+
if (entry === undefined) {
|
|
950
|
+
sendJson(response, 404, { error: "Installed plugin was not found" });
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
const plugin = marketplacePluginForEntry(entry);
|
|
954
|
+
if (plugin === undefined) {
|
|
955
|
+
sendJson(response, 403, { error: "Built-in plugins cannot be changed" });
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const profileEntryId = entry.options.id;
|
|
959
|
+
const before = await updateMarketplaceProfile(configPath, profileEntryId, { disabled: !payload.enabled });
|
|
960
|
+
try {
|
|
961
|
+
await entry.update({ disabled: !payload.enabled });
|
|
962
|
+
sendJson(response, 200, { plugin: pluginSummary(entry) });
|
|
963
|
+
} catch (error) {
|
|
964
|
+
await writeFile(configPath, before, "utf8").catch(() => {});
|
|
965
|
+
sendJson(response, 502, { error: errorText(error) });
|
|
966
|
+
}
|
|
967
|
+
} catch (error) {
|
|
968
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
969
|
+
} finally {
|
|
970
|
+
marketplaceMutationInFlight = false;
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
});
|
|
974
|
+
const disposePluginUninstall = services.webServer.register({
|
|
975
|
+
path: "/api/plugins/uninstall",
|
|
976
|
+
async handler(request, response) {
|
|
977
|
+
if (request.method !== "POST") {
|
|
978
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const configPath = services.launch.configPath;
|
|
982
|
+
const loader = services.loader;
|
|
983
|
+
if (configPath === undefined || loader === undefined) {
|
|
984
|
+
sendJson(response, 501, { error: "Plugin configuration is unavailable for this runtime" });
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (marketplaceMutationInFlight) {
|
|
988
|
+
sendJson(response, 409, { error: "Another marketplace plugin change is already running" });
|
|
244
989
|
return;
|
|
245
990
|
}
|
|
246
|
-
|
|
991
|
+
marketplaceMutationInFlight = true;
|
|
992
|
+
try {
|
|
993
|
+
const payload = JSON.parse(await bodyText(request)) as { id?: unknown };
|
|
994
|
+
if (typeof payload.id !== "string") {
|
|
995
|
+
sendJson(response, 400, { error: "A marketplace plugin id is required" });
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const entry = [...loader.entries()].find((item) => item.id === payload.id || item.options.id === payload.id);
|
|
999
|
+
if (entry === undefined) {
|
|
1000
|
+
sendJson(response, 404, { error: "Installed plugin was not found" });
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const plugin = marketplacePluginForEntry(entry);
|
|
1004
|
+
if (plugin === undefined) {
|
|
1005
|
+
sendJson(response, 403, { error: "Only marketplace plugins can be uninstalled" });
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
const profileEntryId = entry.options.id;
|
|
1009
|
+
const profileBefore = await readFile(configPath, "utf8");
|
|
1010
|
+
const packageJsonPath = join(services.launch.cwd, "package.json");
|
|
1011
|
+
const packageLockPath = join(services.launch.cwd, "package-lock.json");
|
|
1012
|
+
const packageJsonBefore = await readFile(packageJsonPath, "utf8").catch(() => undefined);
|
|
1013
|
+
const packageLockBefore = await readFile(packageLockPath, "utf8").catch(() => undefined);
|
|
1014
|
+
await entry.parent.remove(entry.options.id);
|
|
1015
|
+
entry.parent.tree.write();
|
|
1016
|
+
try {
|
|
1017
|
+
await updateMarketplaceProfile(configPath, profileEntryId, { remove: true });
|
|
1018
|
+
if (needsMarketplacePackageInstall(plugin)) await runProcess("npm", ["uninstall", "--package-lock=false", plugin.packageName], services.launch.cwd);
|
|
1019
|
+
sendJson(response, 200, { uninstalled: true, id: payload.id });
|
|
1020
|
+
} catch (error) {
|
|
1021
|
+
await writeFile(configPath, profileBefore, "utf8").catch(() => {});
|
|
1022
|
+
if (packageJsonBefore !== undefined) await writeFile(packageJsonPath, packageJsonBefore, "utf8").catch(() => {});
|
|
1023
|
+
if (packageLockBefore !== undefined) await writeFile(packageLockPath, packageLockBefore, "utf8").catch(() => {});
|
|
1024
|
+
const options = entry.options as { name: string; config?: unknown; group?: boolean | null };
|
|
1025
|
+
await loader
|
|
1026
|
+
.create({ id: entry.options.id, name: options.name, config: options.config, ...(options.group ? { group: true } : {}) } as never)
|
|
1027
|
+
.catch(() => {});
|
|
1028
|
+
sendJson(response, 502, { error: errorText(error) });
|
|
1029
|
+
}
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1032
|
+
} finally {
|
|
1033
|
+
marketplaceMutationInFlight = false;
|
|
1034
|
+
}
|
|
247
1035
|
},
|
|
248
1036
|
});
|
|
249
1037
|
const disposeCommands = services.webServer.register({
|
|
250
1038
|
path: "/api/commands",
|
|
251
1039
|
handler(_request, response) {
|
|
252
1040
|
const commands = services.runtime.session.extensionRunner.getRegisteredCommands();
|
|
253
|
-
const items = commands.map((command) => ({
|
|
1041
|
+
const items = commands.map((command) => ({
|
|
1042
|
+
name: command.name,
|
|
1043
|
+
invocationName: command.invocationName,
|
|
1044
|
+
description: command.description,
|
|
1045
|
+
source: command.sourceInfo.path,
|
|
1046
|
+
}));
|
|
254
1047
|
sendJson(response, 200, jsonSafe({ items }));
|
|
255
1048
|
},
|
|
256
1049
|
});
|
|
1050
|
+
const disposeWorkspaces = services.webServer.register({
|
|
1051
|
+
path: "/api/workspaces",
|
|
1052
|
+
async handler(_request, response) {
|
|
1053
|
+
try {
|
|
1054
|
+
sendJson(response, 200, { items: await listWorkspaces(activeCwd(services)) });
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
sendJson(response, 500, { error: errorText(error) });
|
|
1057
|
+
}
|
|
1058
|
+
},
|
|
1059
|
+
});
|
|
1060
|
+
const disposePickDirectory = services.webServer.register({
|
|
1061
|
+
path: "/api/workspaces/pick",
|
|
1062
|
+
async handler(request, response) {
|
|
1063
|
+
if (request.method !== "POST") {
|
|
1064
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
if (process.platform !== "darwin") {
|
|
1068
|
+
sendJson(response, 501, { error: "Native directory picker is only available on macOS" });
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
sendJson(response, 200, { path: await pickDirectory() });
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
sendJson(response, 409, { error: errorText(error) });
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
});
|
|
257
1078
|
const disposeModel = services.webServer.register({
|
|
258
1079
|
path: "/api/model",
|
|
259
1080
|
async handler(request, response) {
|
|
@@ -290,11 +1111,19 @@ export default {
|
|
|
290
1111
|
const disposeFiles = services.webServer.register({
|
|
291
1112
|
path: "/api/files",
|
|
292
1113
|
async handler(_request, response) {
|
|
293
|
-
const output = await gitStatus(services
|
|
294
|
-
const items = output
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
1114
|
+
const output = await gitStatus(activeCwd(services));
|
|
1115
|
+
const items = output
|
|
1116
|
+
.split("\n")
|
|
1117
|
+
.map((line) => line.trimEnd())
|
|
1118
|
+
.filter((line) => line.length > 0)
|
|
1119
|
+
.map((line) => {
|
|
1120
|
+
const status = line.slice(0, 2).trim() || "??";
|
|
1121
|
+
return {
|
|
1122
|
+
path: line.slice(3),
|
|
1123
|
+
status,
|
|
1124
|
+
label: status === "??" ? "untracked" : status.includes("D") ? "deleted" : status.includes("A") ? "added" : "modified",
|
|
1125
|
+
};
|
|
1126
|
+
});
|
|
298
1127
|
sendJson(response, 200, { items });
|
|
299
1128
|
},
|
|
300
1129
|
});
|
|
@@ -311,7 +1140,7 @@ export default {
|
|
|
311
1140
|
sendJson(response, 400, { error: "path is required" });
|
|
312
1141
|
return;
|
|
313
1142
|
}
|
|
314
|
-
const root = resolve(services
|
|
1143
|
+
const root = resolve(activeCwd(services));
|
|
315
1144
|
const absolute = resolve(root, requested);
|
|
316
1145
|
const relativePath = relative(root, absolute);
|
|
317
1146
|
if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + "/")) {
|
|
@@ -330,7 +1159,7 @@ export default {
|
|
|
330
1159
|
}
|
|
331
1160
|
try {
|
|
332
1161
|
const payload = JSON.parse(await bodyText(request)) as { paths?: unknown; message?: unknown };
|
|
333
|
-
const paths = workspacePaths(resolve(services
|
|
1162
|
+
const paths = workspacePaths(resolve(activeCwd(services)), payload.paths);
|
|
334
1163
|
if (paths instanceof Error) {
|
|
335
1164
|
sendJson(response, 400, { error: paths.message });
|
|
336
1165
|
return;
|
|
@@ -339,7 +1168,7 @@ export default {
|
|
|
339
1168
|
sendJson(response, 400, { error: "message is required" });
|
|
340
1169
|
return;
|
|
341
1170
|
}
|
|
342
|
-
const root = resolve(services
|
|
1171
|
+
const root = resolve(activeCwd(services));
|
|
343
1172
|
const add = await gitCommand(root, ["add", "-A", "--", ...paths]);
|
|
344
1173
|
if (add.code !== 0) {
|
|
345
1174
|
sendJson(response, 409, { error: add.stderr.trim() || "Unable to stage workspace files" });
|
|
@@ -370,7 +1199,7 @@ export default {
|
|
|
370
1199
|
sendJson(response, 400, { error: "confirm must be true to discard workspace changes" });
|
|
371
1200
|
return;
|
|
372
1201
|
}
|
|
373
|
-
const root = resolve(services
|
|
1202
|
+
const root = resolve(activeCwd(services));
|
|
374
1203
|
const paths = workspacePaths(root, payload.paths);
|
|
375
1204
|
if (paths instanceof Error) {
|
|
376
1205
|
sendJson(response, 400, { error: paths.message });
|
|
@@ -382,7 +1211,10 @@ export default {
|
|
|
382
1211
|
sendJson(response, 409, { error: restore.stderr.trim() || "Unable to restore workspace files" });
|
|
383
1212
|
return;
|
|
384
1213
|
}
|
|
385
|
-
for (const path of untracked.stdout
|
|
1214
|
+
for (const path of untracked.stdout
|
|
1215
|
+
.split("\n")
|
|
1216
|
+
.map((item) => item.trim())
|
|
1217
|
+
.filter(Boolean)) {
|
|
386
1218
|
await rm(resolve(root, path), { recursive: true, force: true });
|
|
387
1219
|
}
|
|
388
1220
|
sendJson(response, 200, { reverted: true, paths });
|
|
@@ -394,7 +1226,12 @@ export default {
|
|
|
394
1226
|
const disposeEvents = services.webServer.register({
|
|
395
1227
|
path: "/api/events",
|
|
396
1228
|
handler(_request, response) {
|
|
397
|
-
response.writeHead(200, {
|
|
1229
|
+
response.writeHead(200, {
|
|
1230
|
+
"content-type": "text/event-stream; charset=utf-8",
|
|
1231
|
+
"cache-control": "no-cache, no-store",
|
|
1232
|
+
connection: "keep-alive",
|
|
1233
|
+
"x-accel-buffering": "no",
|
|
1234
|
+
});
|
|
398
1235
|
writeSse(response, { type: "snapshot", sessionId: services.runtime.session.sessionId, events });
|
|
399
1236
|
eventClients.add(response);
|
|
400
1237
|
const heartbeat = setInterval(() => {
|
|
@@ -466,13 +1303,17 @@ export default {
|
|
|
466
1303
|
handler(_request, response) {
|
|
467
1304
|
const session = services.runtime.session;
|
|
468
1305
|
const sessionManager = session.sessionManager;
|
|
469
|
-
sendJson(
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
1306
|
+
sendJson(
|
|
1307
|
+
response,
|
|
1308
|
+
200,
|
|
1309
|
+
jsonSafe({
|
|
1310
|
+
sessionId: session.sessionId,
|
|
1311
|
+
sessionFile: session.sessionFile,
|
|
1312
|
+
messages: session.messages,
|
|
1313
|
+
entries: typeof sessionManager?.getEntries === "function" ? sessionManager.getEntries() : [],
|
|
1314
|
+
events,
|
|
1315
|
+
}),
|
|
1316
|
+
);
|
|
476
1317
|
},
|
|
477
1318
|
});
|
|
478
1319
|
const disposeNewSession = services.webServer.register({
|
|
@@ -487,14 +1328,40 @@ export default {
|
|
|
487
1328
|
return;
|
|
488
1329
|
}
|
|
489
1330
|
try {
|
|
1331
|
+
const raw = await bodyText(request);
|
|
1332
|
+
const payload = raw.trim() ? (JSON.parse(raw) as { cwd?: unknown }) : {};
|
|
1333
|
+
const currentCwd = activeCwd(services);
|
|
1334
|
+
const requestedCwd = typeof payload.cwd === "string" ? resolve(payload.cwd) : resolve(currentCwd);
|
|
1335
|
+
const workspaces = await listWorkspaces(currentCwd);
|
|
1336
|
+
const workspace =
|
|
1337
|
+
workspaces.find((item) => item.path === requestedCwd) ??
|
|
1338
|
+
(typeof payload.cwd === "string" && (await isDirectory(requestedCwd))
|
|
1339
|
+
? { path: requestedCwd, branch: "directory", current: false, name: basename(requestedCwd) || requestedCwd }
|
|
1340
|
+
: undefined);
|
|
1341
|
+
if (!workspace) {
|
|
1342
|
+
sendJson(response, 400, { error: "Workspace is not available" });
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
490
1345
|
if (services.runtime.sessionRuntime) {
|
|
491
|
-
|
|
1346
|
+
let result;
|
|
1347
|
+
if (workspace.current) {
|
|
1348
|
+
result = await runWebSessionChange(services, () => services.runtime.sessionRuntime.newSession());
|
|
1349
|
+
} else {
|
|
1350
|
+
const manager = services.runtime.session.sessionManager;
|
|
1351
|
+
if (!manager || typeof manager.isPersisted !== "function" || !manager.isPersisted()) {
|
|
1352
|
+
sendJson(response, 409, { error: "Workspace switching requires JSONL session storage" });
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const created = SessionManager.create(workspace.path, manager.getSessionDir());
|
|
1356
|
+
const sessionFile = created.newSession();
|
|
1357
|
+
if (!sessionFile) throw new Error("Unable to create a workspace session");
|
|
1358
|
+
result = await runWebSessionChange(services, () => services.runtime.sessionRuntime.switchSession(sessionFile, { cwdOverride: workspace.path }));
|
|
1359
|
+
}
|
|
492
1360
|
if (result.cancelled) {
|
|
493
1361
|
sendJson(response, 409, { error: "Session creation was cancelled by an extension" });
|
|
494
1362
|
return;
|
|
495
1363
|
}
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
1364
|
+
} else {
|
|
498
1365
|
const session = services.runtime.session;
|
|
499
1366
|
session.sessionManager.newSession();
|
|
500
1367
|
session.agent.state.messages = [];
|
|
@@ -502,7 +1369,16 @@ export default {
|
|
|
502
1369
|
events.length = 0;
|
|
503
1370
|
const session = services.runtime.session;
|
|
504
1371
|
for (const client of eventClients) writeSse(client, { type: "session", sessionId: session.sessionId, events: [] });
|
|
505
|
-
sendJson(
|
|
1372
|
+
sendJson(
|
|
1373
|
+
response,
|
|
1374
|
+
200,
|
|
1375
|
+
jsonSafe({
|
|
1376
|
+
sessionId: session.sessionId,
|
|
1377
|
+
sessionFile: session.sessionFile,
|
|
1378
|
+
messages: services.runtime.sessionRuntime ? session.messages : [],
|
|
1379
|
+
events: [],
|
|
1380
|
+
}),
|
|
1381
|
+
);
|
|
506
1382
|
} catch (error) {
|
|
507
1383
|
sendJson(response, 500, { error: errorText(error) });
|
|
508
1384
|
}
|
|
@@ -527,41 +1403,344 @@ export default {
|
|
|
527
1403
|
return;
|
|
528
1404
|
}
|
|
529
1405
|
const items = await SessionManager.list(services.launch.cwd, manager.getSessionDir());
|
|
530
|
-
const target = items.find(
|
|
1406
|
+
const target = items.find(
|
|
1407
|
+
(item) =>
|
|
1408
|
+
(typeof payload.path === "string" && item.path === payload.path) || (typeof payload.sessionId === "string" && item.id === payload.sessionId),
|
|
1409
|
+
);
|
|
531
1410
|
if (target === undefined) {
|
|
532
1411
|
sendJson(response, 404, { error: "Session not found" });
|
|
533
1412
|
return;
|
|
534
1413
|
}
|
|
535
1414
|
if (services.runtime.sessionRuntime) {
|
|
536
|
-
const result = await services.runtime.sessionRuntime.switchSession(target.path, { cwdOverride: target.cwd });
|
|
1415
|
+
const result = await runWebSessionChange(services, () => services.runtime.sessionRuntime.switchSession(target.path, { cwdOverride: target.cwd }));
|
|
537
1416
|
if (result.cancelled) {
|
|
538
1417
|
sendJson(response, 409, { error: "Session switch was cancelled by an extension" });
|
|
539
1418
|
return;
|
|
540
1419
|
}
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
1420
|
+
} else {
|
|
543
1421
|
manager.setSessionFile(target.path);
|
|
544
1422
|
if (typeof services.runtime.session.reload === "function") await services.runtime.session.reload();
|
|
545
1423
|
else services.runtime.session.agent.state.messages = manager.buildSessionContext().messages;
|
|
546
1424
|
}
|
|
547
1425
|
events.length = 0;
|
|
548
1426
|
for (const client of eventClients) writeSse(client, { type: "session", sessionId: services.runtime.session.sessionId, events: [] });
|
|
549
|
-
sendJson(
|
|
1427
|
+
sendJson(
|
|
1428
|
+
response,
|
|
1429
|
+
200,
|
|
1430
|
+
jsonSafe({
|
|
1431
|
+
sessionId: services.runtime.session.sessionId,
|
|
1432
|
+
sessionFile: services.runtime.session.sessionFile,
|
|
1433
|
+
messages: services.runtime.session.messages,
|
|
1434
|
+
events: [],
|
|
1435
|
+
}),
|
|
1436
|
+
);
|
|
550
1437
|
} catch (error) {
|
|
551
1438
|
sendJson(response, 400, { error: errorText(error) });
|
|
552
1439
|
}
|
|
553
1440
|
},
|
|
554
1441
|
});
|
|
1442
|
+
const disposeRenameSession = services.webServer.register({
|
|
1443
|
+
path: "/api/session/rename",
|
|
1444
|
+
async handler(request, response) {
|
|
1445
|
+
if (request.method !== "POST") {
|
|
1446
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
try {
|
|
1450
|
+
const payload = JSON.parse(await bodyText(request)) as { path?: unknown; name?: unknown };
|
|
1451
|
+
const manager = services.runtime.session.sessionManager;
|
|
1452
|
+
const path = typeof payload.path === "string" ? payload.path : services.runtime.session.sessionFile;
|
|
1453
|
+
const name = typeof payload.name === "string" ? payload.name.trim() : "";
|
|
1454
|
+
if (!path || !sessionPathInDirectory(path, manager)) {
|
|
1455
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
if (name.length > 120) {
|
|
1459
|
+
sendJson(response, 400, { error: "Session name must be at most 120 characters" });
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
SessionManager.open(path, manager.getSessionDir()).appendSessionInfo(name);
|
|
1463
|
+
sendJson(response, 200, { path, name: name || undefined });
|
|
1464
|
+
} catch (error) {
|
|
1465
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1466
|
+
}
|
|
1467
|
+
},
|
|
1468
|
+
});
|
|
1469
|
+
const disposeDeleteSession = services.webServer.register({
|
|
1470
|
+
path: "/api/session/delete",
|
|
1471
|
+
async handler(request, response) {
|
|
1472
|
+
if (request.method !== "POST") {
|
|
1473
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
try {
|
|
1477
|
+
const payload = JSON.parse(await bodyText(request)) as { path?: unknown; confirm?: unknown };
|
|
1478
|
+
const manager = services.runtime.session.sessionManager;
|
|
1479
|
+
const path = typeof payload.path === "string" ? payload.path : "";
|
|
1480
|
+
if (payload.confirm !== true) {
|
|
1481
|
+
sendJson(response, 400, { error: "confirm must be true to delete a session" });
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
if (!sessionPathInDirectory(path, manager)) {
|
|
1485
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
if (path === services.runtime.session.sessionFile) {
|
|
1489
|
+
if (services.runtime.session.isStreaming) {
|
|
1490
|
+
sendJson(response, 409, { error: "Cannot delete the active session while a prompt is running" });
|
|
1491
|
+
return;
|
|
1492
|
+
}
|
|
1493
|
+
const result = await runWebSessionChange(services, () => services.runtime.sessionRuntime.newSession());
|
|
1494
|
+
if (result.cancelled) {
|
|
1495
|
+
sendJson(response, 409, { error: "Session deletion was cancelled by an extension" });
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
events.length = 0;
|
|
1499
|
+
}
|
|
1500
|
+
await unlink(path);
|
|
1501
|
+
const metadata = await readSessionMetadata(manager);
|
|
1502
|
+
delete metadata[path];
|
|
1503
|
+
await writeSessionMetadata(manager, metadata);
|
|
1504
|
+
sendJson(response, 200, { deleted: true, path, sessionFile: services.runtime.session.sessionFile });
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1507
|
+
}
|
|
1508
|
+
},
|
|
1509
|
+
});
|
|
1510
|
+
const disposeSessionMetadata = services.webServer.register({
|
|
1511
|
+
path: "/api/session/metadata",
|
|
1512
|
+
async handler(request, response) {
|
|
1513
|
+
if (request.method !== "POST") {
|
|
1514
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
try {
|
|
1518
|
+
const payload = JSON.parse(await bodyText(request)) as { path?: unknown; archived?: unknown; pinned?: unknown };
|
|
1519
|
+
const manager = services.runtime.session.sessionManager;
|
|
1520
|
+
const path = typeof payload.path === "string" ? payload.path : "";
|
|
1521
|
+
if (!sessionPathInDirectory(path, manager)) {
|
|
1522
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
const metadata = await readSessionMetadata(manager);
|
|
1526
|
+
const currentMetadata = metadata[path] ?? {};
|
|
1527
|
+
const nextMetadata: SessionMetadata = {
|
|
1528
|
+
...currentMetadata,
|
|
1529
|
+
...(payload.archived === undefined ? {} : { archived: payload.archived === true }),
|
|
1530
|
+
...(payload.pinned === undefined ? {} : { pinned: payload.pinned === true }),
|
|
1531
|
+
};
|
|
1532
|
+
metadata[path] = nextMetadata;
|
|
1533
|
+
await writeSessionMetadata(manager, metadata);
|
|
1534
|
+
sendJson(response, 200, { path, metadata: metadata[path] });
|
|
1535
|
+
} catch (error) {
|
|
1536
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
});
|
|
1540
|
+
const disposeBatchSessions = services.webServer.register({
|
|
1541
|
+
path: "/api/sessions/batch",
|
|
1542
|
+
async handler(request, response) {
|
|
1543
|
+
if (request.method !== "POST") {
|
|
1544
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
try {
|
|
1548
|
+
const payload = JSON.parse(await bodyText(request)) as { action?: unknown; paths?: unknown; confirm?: unknown };
|
|
1549
|
+
const action = payload.action;
|
|
1550
|
+
const paths = Array.isArray(payload.paths) ? payload.paths.filter((path): path is string => typeof path === "string") : [];
|
|
1551
|
+
const manager = services.runtime.session.sessionManager;
|
|
1552
|
+
if (
|
|
1553
|
+
(action !== "delete" && action !== "archive" && action !== "unarchive" && action !== "pin" && action !== "unpin") ||
|
|
1554
|
+
paths.length === 0 ||
|
|
1555
|
+
paths.length > 100
|
|
1556
|
+
) {
|
|
1557
|
+
sendJson(response, 400, { error: "action and 1-100 session paths are required" });
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
if (action === "delete" && payload.confirm !== true) {
|
|
1561
|
+
sendJson(response, 400, { error: "confirm must be true to delete sessions" });
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
if (paths.some((path) => !sessionPathInDirectory(path, manager))) {
|
|
1565
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
if (action === "delete" && paths.includes(services.runtime.session.sessionFile ?? "")) {
|
|
1569
|
+
sendJson(response, 409, { error: "Cannot batch-delete the active session" });
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
const metadata = await readSessionMetadata(manager);
|
|
1573
|
+
for (const path of paths) {
|
|
1574
|
+
if (action === "delete") {
|
|
1575
|
+
await unlink(path);
|
|
1576
|
+
delete metadata[path];
|
|
1577
|
+
} else {
|
|
1578
|
+
const current = metadata[path] ?? {};
|
|
1579
|
+
metadata[path] = {
|
|
1580
|
+
...current,
|
|
1581
|
+
...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
|
|
1582
|
+
...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
await writeSessionMetadata(manager, metadata);
|
|
1587
|
+
sendJson(response, 200, { action, count: paths.length });
|
|
1588
|
+
} catch (error) {
|
|
1589
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
});
|
|
1593
|
+
const disposeForkSession = services.webServer.register({
|
|
1594
|
+
path: "/api/session/fork",
|
|
1595
|
+
async handler(request, response) {
|
|
1596
|
+
if (request.method !== "POST") {
|
|
1597
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
try {
|
|
1601
|
+
const payload = JSON.parse(await bodyText(request)) as { path?: unknown; cwd?: unknown };
|
|
1602
|
+
const manager = services.runtime.session.sessionManager;
|
|
1603
|
+
const sourcePath = typeof payload.path === "string" ? payload.path : "";
|
|
1604
|
+
if (!sessionPathInDirectory(sourcePath, manager)) {
|
|
1605
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
const sessions = await SessionManager.list(services.launch.cwd, manager.getSessionDir());
|
|
1609
|
+
const source = sessions.find((item) => item.path === sourcePath);
|
|
1610
|
+
if (!source) {
|
|
1611
|
+
sendJson(response, 404, { error: "Session not found" });
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
const targetCwd = typeof payload.cwd === "string" && payload.cwd.trim() ? resolve(payload.cwd) : source.cwd || activeCwd(services);
|
|
1615
|
+
const forked = SessionManager.forkFrom(source.path, targetCwd, manager.getSessionDir());
|
|
1616
|
+
sendJson(response, 200, { sessionId: forked.getSessionId(), sessionFile: forked.getSessionFile(), cwd: targetCwd });
|
|
1617
|
+
} catch (error) {
|
|
1618
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1619
|
+
}
|
|
1620
|
+
},
|
|
1621
|
+
});
|
|
1622
|
+
const disposeImportSession = services.webServer.register({
|
|
1623
|
+
path: "/api/session/import",
|
|
1624
|
+
async handler(request, response) {
|
|
1625
|
+
if (request.method !== "POST") {
|
|
1626
|
+
sendJson(response, 405, { error: "Method not allowed" });
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
if (services.runtime.session.isStreaming) {
|
|
1630
|
+
sendJson(response, 409, { error: "Cannot import a session while a prompt is running" });
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
try {
|
|
1634
|
+
const payload = JSON.parse(await bodyText(request)) as { path?: unknown; content?: unknown; filename?: unknown; cwd?: unknown };
|
|
1635
|
+
const suppliedPath = typeof payload.path === "string" ? payload.path : "";
|
|
1636
|
+
const content = typeof payload.content === "string" ? payload.content : undefined;
|
|
1637
|
+
if ((!suppliedPath || !isAbsolute(suppliedPath)) && content === undefined) {
|
|
1638
|
+
sendJson(response, 400, { error: "A JSONL file path or file content is required" });
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
const manager = services.runtime.session.sessionManager;
|
|
1642
|
+
if (!manager.isPersisted()) {
|
|
1643
|
+
sendJson(response, 409, { error: "Session importing requires JSONL session storage" });
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
const targetCwd = typeof payload.cwd === "string" && payload.cwd.trim() ? resolve(payload.cwd) : activeCwd(services);
|
|
1647
|
+
const temporaryDirectory = content === undefined ? undefined : await mkdtemp(join(tmpdir(), "pi-harness-import-"));
|
|
1648
|
+
const importPath =
|
|
1649
|
+
suppliedPath ||
|
|
1650
|
+
join(temporaryDirectory as string, basename(typeof payload.filename === "string" && payload.filename.trim() ? payload.filename : "import.jsonl"));
|
|
1651
|
+
try {
|
|
1652
|
+
if (content !== undefined) {
|
|
1653
|
+
if (Buffer.byteLength(content, "utf8") > 10 * 1024 * 1024) {
|
|
1654
|
+
sendJson(response, 413, { error: "Imported session must be at most 10 MiB" });
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
await writeFile(importPath, content, "utf8");
|
|
1658
|
+
}
|
|
1659
|
+
const imported = SessionManager.forkFrom(importPath, targetCwd, manager.getSessionDir());
|
|
1660
|
+
const importedPath = imported.getSessionFile();
|
|
1661
|
+
if (!importedPath) throw new Error("Unable to persist imported session");
|
|
1662
|
+
const result = await runWebSessionChange(services, () => services.runtime.sessionRuntime.switchSession(importedPath, { cwdOverride: targetCwd }));
|
|
1663
|
+
if (result.cancelled) {
|
|
1664
|
+
sendJson(response, 409, { error: "Session import was cancelled by an extension" });
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
events.length = 0;
|
|
1668
|
+
sendJson(response, 200, {
|
|
1669
|
+
sessionId: services.runtime.session.sessionId,
|
|
1670
|
+
sessionFile: services.runtime.session.sessionFile,
|
|
1671
|
+
messages: services.runtime.session.messages.length,
|
|
1672
|
+
});
|
|
1673
|
+
} finally {
|
|
1674
|
+
if (temporaryDirectory) await rm(temporaryDirectory, { recursive: true, force: true });
|
|
1675
|
+
}
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
sendJson(response, 400, { error: errorText(error) });
|
|
1678
|
+
}
|
|
1679
|
+
},
|
|
1680
|
+
});
|
|
1681
|
+
const disposeExportSession = services.webServer.register({
|
|
1682
|
+
path: "/api/session/export",
|
|
1683
|
+
async handler(request, response) {
|
|
1684
|
+
try {
|
|
1685
|
+
const url = new URL(request.url ?? "/api/session/export", "http://localhost");
|
|
1686
|
+
const manager = services.runtime.session.sessionManager;
|
|
1687
|
+
const path = url.searchParams.get("path") ?? services.runtime.session.sessionFile;
|
|
1688
|
+
if (!path || !sessionPathInDirectory(path, manager)) {
|
|
1689
|
+
sendJson(response, 400, { error: "Invalid session path" });
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
const content = await readFile(path, "utf8");
|
|
1693
|
+
response.writeHead(200, {
|
|
1694
|
+
"content-type": "application/x-ndjson; charset=utf-8",
|
|
1695
|
+
"content-disposition": `attachment; filename="${basename(path)}"`,
|
|
1696
|
+
"cache-control": "no-store",
|
|
1697
|
+
});
|
|
1698
|
+
response.end(content);
|
|
1699
|
+
} catch (error) {
|
|
1700
|
+
sendJson(response, 404, { error: errorText(error) });
|
|
1701
|
+
}
|
|
1702
|
+
},
|
|
1703
|
+
});
|
|
555
1704
|
const disposeSessions = services.webServer.register({
|
|
556
1705
|
path: "/api/sessions",
|
|
557
1706
|
async handler(_request, response) {
|
|
558
1707
|
try {
|
|
559
1708
|
const session = services.runtime.session;
|
|
560
1709
|
const manager = session.sessionManager;
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
1710
|
+
const url = new URL(_request.url ?? "/api/sessions", "http://localhost");
|
|
1711
|
+
const page = Math.max(0, Number.parseInt(url.searchParams.get("page") ?? "0", 10) || 0);
|
|
1712
|
+
const pageSize = Math.min(100, Math.max(1, Number.parseInt(url.searchParams.get("pageSize") ?? "50", 10) || 50));
|
|
1713
|
+
const includeArchived = url.searchParams.get("includeArchived") === "true";
|
|
1714
|
+
const metadata = await readSessionMetadata(manager);
|
|
1715
|
+
const items =
|
|
1716
|
+
typeof manager.isPersisted === "function" && manager.isPersisted() ? await SessionManager.list(services.launch.cwd, manager.getSessionDir()) : [];
|
|
1717
|
+
const filtered = items.filter((item) => includeArchived || metadata[item.path]?.archived !== true);
|
|
1718
|
+
const sorted = filtered.sort(
|
|
1719
|
+
(a, b) => Number(metadata[b.path]?.pinned === true) - Number(metadata[a.path]?.pinned === true) || b.modified.getTime() - a.modified.getTime(),
|
|
1720
|
+
);
|
|
1721
|
+
const paged = sorted.slice(page * pageSize, (page + 1) * pageSize);
|
|
1722
|
+
sendJson(
|
|
1723
|
+
response,
|
|
1724
|
+
200,
|
|
1725
|
+
jsonSafe({
|
|
1726
|
+
items: paged.map((item) => ({
|
|
1727
|
+
sessionId: item.id,
|
|
1728
|
+
path: item.path,
|
|
1729
|
+
name: item.name,
|
|
1730
|
+
cwd: item.cwd,
|
|
1731
|
+
created: item.created,
|
|
1732
|
+
modified: item.modified,
|
|
1733
|
+
messageCount: item.messageCount,
|
|
1734
|
+
firstMessage: item.firstMessage,
|
|
1735
|
+
archived: metadata[item.path]?.archived === true,
|
|
1736
|
+
pinned: metadata[item.path]?.pinned === true,
|
|
1737
|
+
})),
|
|
1738
|
+
total: sorted.length,
|
|
1739
|
+
page,
|
|
1740
|
+
pageSize,
|
|
1741
|
+
hasNext: (page + 1) * pageSize < sorted.length,
|
|
1742
|
+
}),
|
|
1743
|
+
);
|
|
565
1744
|
} catch (error) {
|
|
566
1745
|
sendJson(response, 500, { error: errorText(error) });
|
|
567
1746
|
}
|
|
@@ -569,15 +1748,26 @@ export default {
|
|
|
569
1748
|
});
|
|
570
1749
|
context.effect(() => () => {
|
|
571
1750
|
disposeStatus();
|
|
1751
|
+
disposeConfig();
|
|
1752
|
+
disposeConfigReload();
|
|
1753
|
+
disposeConfigSource();
|
|
572
1754
|
disposeEvents();
|
|
573
1755
|
disposeModels();
|
|
574
1756
|
disposeProviders();
|
|
575
1757
|
disposeProviderTest();
|
|
576
1758
|
disposeProviderRefresh();
|
|
1759
|
+
disposeProviderAdd();
|
|
577
1760
|
disposePlugins();
|
|
1761
|
+
disposePluginUi();
|
|
1762
|
+
disposePluginPanels();
|
|
578
1763
|
disposeMarketplace();
|
|
1764
|
+
disposeMarketplaceInstall();
|
|
1765
|
+
disposePluginToggle();
|
|
1766
|
+
disposePluginUninstall();
|
|
579
1767
|
disposeCommands();
|
|
580
1768
|
disposeModel();
|
|
1769
|
+
disposeWorkspaces();
|
|
1770
|
+
disposePickDirectory();
|
|
581
1771
|
disposeFiles();
|
|
582
1772
|
disposeFileDiff();
|
|
583
1773
|
disposeFileCommit();
|
|
@@ -587,6 +1777,13 @@ export default {
|
|
|
587
1777
|
disposeSession();
|
|
588
1778
|
disposeNewSession();
|
|
589
1779
|
disposeOpenSession();
|
|
1780
|
+
disposeRenameSession();
|
|
1781
|
+
disposeDeleteSession();
|
|
1782
|
+
disposeSessionMetadata();
|
|
1783
|
+
disposeBatchSessions();
|
|
1784
|
+
disposeForkSession();
|
|
1785
|
+
disposeImportSession();
|
|
1786
|
+
disposeExportSession();
|
|
590
1787
|
disposeSessions();
|
|
591
1788
|
unsubscribeEvents();
|
|
592
1789
|
for (const response of eventClients) response.end();
|