@pi-harness/pi-harness 0.1.23 → 0.1.25
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/README.md +14 -9
- package/apps/web/dist/assets/index-Deo3hxmM.js +25 -0
- package/apps/web/dist/assets/index-xF647pQJ.css +2 -0
- package/apps/web/dist/index.html +2 -2
- package/apps/web/package.json +6 -6
- package/apps/web/profile/cordis.yml +1 -0
- package/apps/web/server-dist/bin.js +27 -2
- package/apps/web/server-dist/bin.js.map +1 -1
- package/apps/web/src/server/bin.ts +27 -2
- package/apps/web/test/bin.test.ts +228 -5
- package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/index.js +160 -69
- package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/context.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
- package/node_modules/@pi-harness/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
- package/node_modules/@pi-harness/api-gateway/package.json +1 -1
- package/node_modules/@pi-harness/cli/dist/main.d.ts +1 -0
- package/node_modules/@pi-harness/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@pi-harness/cli/dist/main.js +11 -0
- package/node_modules/@pi-harness/cli/dist/main.js.map +1 -1
- package/node_modules/@pi-harness/cli/dist/relaunch.d.ts.map +1 -1
- package/node_modules/@pi-harness/cli/dist/relaunch.js +2 -4
- package/node_modules/@pi-harness/cli/dist/relaunch.js.map +1 -1
- package/node_modules/@pi-harness/cli/package.json +1 -1
- package/node_modules/@pi-harness/host-webserver/dist/index.d.ts +1 -0
- package/node_modules/@pi-harness/host-webserver/dist/index.d.ts.map +1 -1
- package/node_modules/@pi-harness/host-webserver/dist/index.js +43 -7
- package/node_modules/@pi-harness/host-webserver/dist/index.js.map +1 -1
- package/node_modules/@pi-harness/host-webserver/package.json +1 -1
- package/node_modules/@pi-harness/web-app/dist/index.d.ts.map +1 -1
- package/node_modules/@pi-harness/web-app/dist/index.js +12 -3
- package/node_modules/@pi-harness/web-app/dist/index.js.map +1 -1
- package/node_modules/@pi-harness/web-app/package.json +1 -1
- package/package.json +7 -7
- package/packages/api-gateway/dist/index.d.ts.map +1 -1
- package/packages/api-gateway/dist/index.js +160 -69
- package/packages/api-gateway/dist/index.js.map +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/agent-teams.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/anchored-standard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/annotation.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/archify.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/at-file.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/auto-mode.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/better-sidebar.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/browser-fetch.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/browser-session.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/canvas-draw.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/change-verifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cleaner.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cli-notifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/code2skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/colleague-skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/context-doctor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/context.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/cost-meter.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/dependency-checker.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/docker-sandbox.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/fail-logger.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/genui.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/git-time-capsule.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/graph-memory.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/history-compressor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/hol-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/i18n-pair.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/image-compressor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/llm-verifier.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-client.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mcp-panel.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/memory.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mirage-bridge.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/mock-server.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/modlens.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/module-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/obsidian-sync.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/openpets.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plan-execute.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-check.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-dev.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-finder.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-radar.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/plugin-stars.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/prompt-library.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/readme-gen.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/recall-unread.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/reverse-skill.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/reviewer-bot.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/runtime-doctor.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/secure-audit.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-bookmarks.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-bridge.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-compare.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-export.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-insights.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/session-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/skill-catalog.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/skill-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/sql-lens.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/synapse.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/tab-manager.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/taskboard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/test-harness.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/theme-studio.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/token-guard.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/turn-rewind.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/undo-savepoint.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/vision-toolkit.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/web-research.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-navigator.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/workspace-search.json +1 -1
- package/packages/api-gateway/dist/marketplace-entries/official/yaml-validator.json +1 -1
- package/packages/api-gateway/package.json +1 -1
- package/packages/api-gateway/src/index.ts +186 -88
- package/packages/api-gateway/src/marketplace-entries/official/agent-teams.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/anchored-standard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/annotation.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/archify.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/at-file.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/auto-mode.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/better-sidebar.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/browser-fetch.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/browser-session.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/canvas-draw.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/change-verifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cleaner.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cli-notifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/code2skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/colleague-skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/context-doctor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/context.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/cost-meter.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/dependency-checker.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/docker-sandbox.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/fail-logger.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/genui.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/git-time-capsule.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/graph-memory.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/history-compressor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/hol-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/i18n-pair.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/image-compressor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/llm-verifier.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mcp-client.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mcp-panel.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/memory.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mirage-bridge.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/mock-server.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/modlens.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/module-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/obsidian-sync.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/openpets.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plan-execute.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-check.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-dev.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-finder.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-radar.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/plugin-stars.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/prompt-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/prompt-library.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/readme-gen.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/recall-unread.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/reverse-skill.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/reviewer-bot.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/runtime-doctor.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/secure-audit.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-bookmarks.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-bridge.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-compare.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-export.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-insights.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/session-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/skill-catalog.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/skill-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/sql-lens.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/synapse.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/tab-manager.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/taskboard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/telemetry-blocker.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/test-harness.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/theme-studio.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/token-guard.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/turn-rewind.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/undo-savepoint.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/vision-toolkit.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/web-research.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/workspace-navigator.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/workspace-search.json +1 -1
- package/packages/api-gateway/src/marketplace-entries/official/yaml-validator.json +1 -1
- package/packages/api-gateway/test/index.test.ts +656 -4
- package/packages/api-gateway/test/packed-package.test.ts +70 -0
- package/packages/api-gateway/test/reference-docs.test.ts +50 -0
- package/packages/api-gateway/test/release-package.test.ts +32 -1
- package/packages/api-gateway/test/release-version.test.ts +40 -0
- package/packages/bundle-web-app/dist/index.d.ts.map +1 -1
- package/packages/bundle-web-app/dist/index.js +12 -3
- package/packages/bundle-web-app/dist/index.js.map +1 -1
- package/packages/bundle-web-app/package.json +1 -1
- package/packages/bundle-web-app/src/index.ts +13 -3
- package/packages/bundle-web-app/test/index.test.ts +83 -2
- 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 +11 -0
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/cli/dist/relaunch.d.ts.map +1 -1
- package/packages/cli/dist/relaunch.js +2 -4
- package/packages/cli/dist/relaunch.js.map +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/main.ts +11 -0
- package/packages/cli/src/relaunch.ts +2 -3
- package/packages/cli/test/cli.test.ts +3 -1
- package/packages/cli/test/main.test.ts +134 -0
- package/packages/cli/test/relaunch.test.ts +86 -11
- package/packages/host-webserver/dist/index.d.ts +1 -0
- package/packages/host-webserver/dist/index.d.ts.map +1 -1
- package/packages/host-webserver/dist/index.js +43 -7
- package/packages/host-webserver/dist/index.js.map +1 -1
- package/packages/host-webserver/package.json +1 -1
- package/packages/host-webserver/src/index.ts +48 -8
- package/packages/host-webserver/test/index.test.ts +58 -5
- package/apps/web/dist/assets/index-BVI_IS-R.css +0 -2
- package/apps/web/dist/assets/index-Bo9CNI_U.js +0 -22
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { mkdir, mkdtemp, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
-
import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { atomicWriteFile } from "@pi-harness/core";
|
|
7
|
-
import { MARKETPLACE_CAPABILITIES, MARKETPLACE_CATEGORIES, MARKETPLACE_PLUGINS, attachMarketplaceStatistics, createMarketplaceStatisticsLoader, paginateMarketplace, searchMarketplace, needsMarketplacePackageInstall, sortMarketplaceByRecommendation, } from "./marketplace.js";
|
|
7
|
+
import { MARKETPLACE_CAPABILITIES, MARKETPLACE_CATEGORIES, MARKETPLACE_PLUGINS, attachMarketplaceStatistics, createMarketplaceStatisticsLoader, paginateMarketplace, searchMarketplace, needsMarketplacePackageInstall, marketplaceNpmPackageName, sortMarketplaceByRecommendation, } from "./marketplace.js";
|
|
8
8
|
import { parseGitWorktrees } from "./workspaces.js";
|
|
9
9
|
const loadMarketplaceStatistics = createMarketplaceStatisticsLoader();
|
|
10
10
|
const DEFAULT_BODY_LIMIT_BYTES = 64 * 1024;
|
|
@@ -14,6 +14,8 @@ const IMPORT_BODY_LIMIT_BYTES = 16 * 1024 * 1024;
|
|
|
14
14
|
// Retained trajectory events are replayed to every SSE client and returned by /api/session, so the array must stay bounded.
|
|
15
15
|
const MAX_RETAINED_EVENTS = 2000;
|
|
16
16
|
const GIT_TIMEOUT_MS = 15_000;
|
|
17
|
+
// Mutating commands run user hooks (pre-commit, lint-staged, test suites) and may stage large trees; killing them part-way leaves index.lock and a half-finished operation behind, so they get a far more generous bound than read-only queries.
|
|
18
|
+
const GIT_MUTATION_TIMEOUT_MS = 120_000;
|
|
17
19
|
class PayloadTooLargeError extends Error {
|
|
18
20
|
constructor() {
|
|
19
21
|
super("Request body is too large");
|
|
@@ -25,18 +27,19 @@ function sendJson(response, status, payload) {
|
|
|
25
27
|
response.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store", "content-length": Buffer.byteLength(body) });
|
|
26
28
|
response.end(body);
|
|
27
29
|
}
|
|
30
|
+
// A multi-byte UTF-8 sequence can straddle a chunk boundary, so the raw bytes are collected and decoded once; decoding each chunk on its own would replace the split sequence with U+FFFD.
|
|
28
31
|
async function bodyText(request, maxBytes = DEFAULT_BODY_LIMIT_BYTES) {
|
|
29
32
|
const chunks = [];
|
|
30
33
|
let length = 0;
|
|
31
34
|
for await (const chunk of request) {
|
|
32
35
|
const input = chunk;
|
|
33
|
-
const
|
|
34
|
-
length +=
|
|
36
|
+
const buffer = typeof input === "string" ? Buffer.from(input, "utf8") : Buffer.isBuffer(input) ? input : Buffer.from(input);
|
|
37
|
+
length += buffer.length;
|
|
35
38
|
if (length > maxBytes)
|
|
36
39
|
throw new PayloadTooLargeError();
|
|
37
|
-
chunks.push(
|
|
40
|
+
chunks.push(buffer);
|
|
38
41
|
}
|
|
39
|
-
return chunks.
|
|
42
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
40
43
|
}
|
|
41
44
|
function errorText(error) {
|
|
42
45
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -56,10 +59,16 @@ function jsonSafe(value, seen = new WeakSet()) {
|
|
|
56
59
|
return Object.prototype.toString.call(value);
|
|
57
60
|
if (seen.has(value))
|
|
58
61
|
return "[Circular]";
|
|
62
|
+
// Only the ancestors of the current node stay marked: a sibling that repeats the same object (Pi pushes one AgentMessage instance into both the message list and its events) is legitimate data, not a cycle.
|
|
59
63
|
seen.add(value);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
try {
|
|
65
|
+
if (Array.isArray(value))
|
|
66
|
+
return value.map((item) => jsonSafe(item, seen));
|
|
67
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, jsonSafe(item, seen)]));
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
seen.delete(value);
|
|
71
|
+
}
|
|
63
72
|
}
|
|
64
73
|
function createStatus(services, events) {
|
|
65
74
|
const activeModel = services.runtime.session.model ?? services.models.model;
|
|
@@ -120,7 +129,7 @@ function piConfig(services) {
|
|
|
120
129
|
function sessionMetadataFile(manager) {
|
|
121
130
|
return resolve(manager.getSessionDir(), ".pi-harness-session-meta.json");
|
|
122
131
|
}
|
|
123
|
-
// A missing file is the normal first-run state.
|
|
132
|
+
// A missing file is the normal first-run state. A parse or shape failure means the file exists but is unusable; it is renamed aside so the wreckage survives for recovery and the next write cannot silently replace the only copy. Any other read error (EMFILE, EBUSY, EISDIR, permissions) says nothing about the content, so it propagates and the caller's write is skipped instead of replacing a valid map with an empty one.
|
|
124
133
|
async function readSessionMetadata(manager, logger) {
|
|
125
134
|
const file = sessionMetadataFile(manager);
|
|
126
135
|
let raw;
|
|
@@ -130,8 +139,7 @@ async function readSessionMetadata(manager, logger) {
|
|
|
130
139
|
catch (error) {
|
|
131
140
|
if (error.code === "ENOENT")
|
|
132
141
|
return {};
|
|
133
|
-
|
|
134
|
-
return {};
|
|
142
|
+
throw error;
|
|
135
143
|
}
|
|
136
144
|
try {
|
|
137
145
|
const parsed = JSON.parse(raw);
|
|
@@ -158,25 +166,33 @@ async function writeSessionMetadata(manager, metadata) {
|
|
|
158
166
|
await mkdir(manager.getSessionDir(), { recursive: true });
|
|
159
167
|
await atomicWriteFile(sessionMetadataFile(manager), JSON.stringify(metadata, null, 2) + "\n", { encoding: "utf8" });
|
|
160
168
|
}
|
|
161
|
-
// Every
|
|
169
|
+
// Every access to the metadata file runs through this chain so concurrent requests cannot interleave and drop each other's updates. Plain reads take the lock too: a read that finds corrupt bytes quarantines the file, and doing that outside the lock could rename away a valid map that a concurrent mutation had just written.
|
|
162
170
|
let sessionMetadataQueue = Promise.resolve();
|
|
171
|
+
function withSessionMetadataLock(operation) {
|
|
172
|
+
const next = sessionMetadataQueue.catch(() => undefined).then(operation);
|
|
173
|
+
sessionMetadataQueue = next;
|
|
174
|
+
return next;
|
|
175
|
+
}
|
|
176
|
+
function readSessionMetadataLocked(manager, logger) {
|
|
177
|
+
return withSessionMetadataLock(() => readSessionMetadata(manager, logger));
|
|
178
|
+
}
|
|
163
179
|
function mutateSessionMetadata(manager, logger, mutate) {
|
|
164
|
-
|
|
165
|
-
.catch(() => undefined)
|
|
166
|
-
.then(async () => {
|
|
180
|
+
return withSessionMetadataLock(async () => {
|
|
167
181
|
const metadata = await readSessionMetadata(manager, logger);
|
|
168
182
|
const result = await mutate(metadata);
|
|
169
183
|
await writeSessionMetadata(manager, metadata);
|
|
170
184
|
return result;
|
|
171
185
|
});
|
|
172
|
-
|
|
173
|
-
|
|
186
|
+
}
|
|
187
|
+
// True when a path.relative() result points outside the directory it was computed from. All containment checks share this predicate so they agree on every platform separator.
|
|
188
|
+
function escapesRoot(relativePath) {
|
|
189
|
+
return isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(".." + sep);
|
|
174
190
|
}
|
|
175
191
|
function sessionPathInDirectory(path, manager) {
|
|
176
192
|
const root = resolve(manager.getSessionDir());
|
|
177
193
|
const target = resolve(path);
|
|
178
194
|
const relativePath = relative(root, target);
|
|
179
|
-
return relativePath !== "" && !
|
|
195
|
+
return relativePath !== "" && !escapesRoot(relativePath) && target.endsWith(".jsonl");
|
|
180
196
|
}
|
|
181
197
|
const webSessionUi = {
|
|
182
198
|
select: (_title, options) => Promise.resolve(options[0]),
|
|
@@ -306,6 +322,7 @@ function sanitizeLogValue(value, state, depth = 0) {
|
|
|
306
322
|
return "[Max Depth]";
|
|
307
323
|
if (state.seen.has(value))
|
|
308
324
|
return "[Circular]";
|
|
325
|
+
// Unmarked once its subtree is done, so an object logged twice as a sibling is rendered twice instead of being mistaken for a cycle.
|
|
309
326
|
state.seen.add(value);
|
|
310
327
|
try {
|
|
311
328
|
if (value instanceof Date)
|
|
@@ -339,6 +356,9 @@ function sanitizeLogValue(value, state, depth = 0) {
|
|
|
339
356
|
catch {
|
|
340
357
|
return "[Unavailable]";
|
|
341
358
|
}
|
|
359
|
+
finally {
|
|
360
|
+
state.seen.delete(value);
|
|
361
|
+
}
|
|
342
362
|
}
|
|
343
363
|
function sanitizeLogArguments(args) {
|
|
344
364
|
const sanitized = sanitizeLogValue(args, { remaining: loggerPanelNodeLimit, seen: new WeakSet() });
|
|
@@ -473,22 +493,38 @@ function gitTermination(error) {
|
|
|
473
493
|
return "timeout";
|
|
474
494
|
return undefined;
|
|
475
495
|
}
|
|
476
|
-
function gitTerminationMessage(command, termination) {
|
|
496
|
+
function gitTerminationMessage(command, termination, timeoutMs = GIT_TIMEOUT_MS) {
|
|
477
497
|
return termination === "timeout"
|
|
478
|
-
? `git ${command} timed out after ${
|
|
498
|
+
? `git ${command} timed out after ${timeoutMs / 1000} seconds`
|
|
479
499
|
: `git ${command} produced more output than the buffer limit allows`;
|
|
480
500
|
}
|
|
481
|
-
|
|
501
|
+
// `-z` output is NUL-separated and never C-quoted, so non-ASCII names arrive verbatim and a rename carries its original path as the following field instead of an `old -> new` pair. The paths are relative to the repository root regardless of cwd, so they are rebased onto the cwd prefix to keep the contract with /api/files/diff, /api/files/commit and /api/files/revert, which resolve paths against the same cwd.
|
|
502
|
+
function parseGitStatus(output, prefix) {
|
|
503
|
+
const fields = output.split("\0");
|
|
504
|
+
const entries = [];
|
|
505
|
+
for (let index = 0; index < fields.length; index += 1) {
|
|
506
|
+
const field = fields[index] ?? "";
|
|
507
|
+
if (field.length < 4)
|
|
508
|
+
continue;
|
|
509
|
+
const code = field.slice(0, 2);
|
|
510
|
+
const path = field.slice(3);
|
|
511
|
+
if (code.startsWith("R") || code.startsWith("C"))
|
|
512
|
+
index += 1;
|
|
513
|
+
entries.push({ path: prefix === "" ? path : posix.relative("/" + prefix, "/" + path), status: code.trim() || "??" });
|
|
514
|
+
}
|
|
515
|
+
return entries;
|
|
516
|
+
}
|
|
517
|
+
function gitStatusOutput(cwd) {
|
|
482
518
|
return new Promise((resolveStatus, rejectStatus) => {
|
|
483
|
-
execFile("git", ["status", "--
|
|
519
|
+
execFile("git", ["status", "--porcelain", "-z", "--untracked-files=all"], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 512 * 1024 }, (error, stdout, stderr) => {
|
|
484
520
|
if (error === null) {
|
|
485
521
|
resolveStatus({ output: stdout, truncated: false });
|
|
486
522
|
return;
|
|
487
523
|
}
|
|
488
524
|
const termination = gitTermination(error);
|
|
489
525
|
if (termination === "output-limit") {
|
|
490
|
-
// Keep the complete
|
|
491
|
-
resolveStatus({ output: stdout.slice(0, stdout.lastIndexOf("\
|
|
526
|
+
// Keep the complete entries that arrived before the kill; the final entry may have been cut mid-path.
|
|
527
|
+
resolveStatus({ output: stdout.slice(0, stdout.lastIndexOf("\0") + 1), truncated: true });
|
|
492
528
|
return;
|
|
493
529
|
}
|
|
494
530
|
if (termination === undefined && error.code === 128 && /not a git repository/i.test(stderr)) {
|
|
@@ -499,14 +535,21 @@ function gitStatus(cwd) {
|
|
|
499
535
|
});
|
|
500
536
|
});
|
|
501
537
|
}
|
|
538
|
+
async function gitStatus(cwd) {
|
|
539
|
+
const { output, truncated } = await gitStatusOutput(cwd);
|
|
540
|
+
if (output === "")
|
|
541
|
+
return { entries: [], truncated };
|
|
542
|
+
const prefix = await gitCommand(cwd, ["rev-parse", "--show-prefix"]);
|
|
543
|
+
return { entries: parseGitStatus(output, prefix.code === 0 ? prefix.stdout.trim() : ""), truncated };
|
|
544
|
+
}
|
|
502
545
|
function gitDiff(cwd, path) {
|
|
503
546
|
return new Promise((resolveOutput) => {
|
|
504
547
|
execFile("git", ["diff", "--no-ext-diff", "--", path], { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout) => resolveOutput(error && stdout.length === 0 ? "" : stdout));
|
|
505
548
|
});
|
|
506
549
|
}
|
|
507
|
-
function gitCommand(cwd, args) {
|
|
550
|
+
function gitCommand(cwd, args, timeoutMs = GIT_TIMEOUT_MS) {
|
|
508
551
|
return new Promise((resolveResult) => {
|
|
509
|
-
execFile("git", [...args], { cwd, timeout:
|
|
552
|
+
execFile("git", [...args], { cwd, timeout: timeoutMs, maxBuffer: 2 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
510
553
|
const code = error && typeof error.code === "number" ? error.code : error ? 1 : 0;
|
|
511
554
|
resolveResult({ stdout, stderr, code, terminated: gitTermination(error) });
|
|
512
555
|
});
|
|
@@ -539,6 +582,26 @@ async function isDirectory(path) {
|
|
|
539
582
|
return false;
|
|
540
583
|
}
|
|
541
584
|
}
|
|
585
|
+
async function isFile(path) {
|
|
586
|
+
try {
|
|
587
|
+
return (await stat(path)).isFile();
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
// The loader resolves a bare plugin specifier from the profile file upwards (`createRequire(profilePath).resolve(name)`), never from the shell the harness was started in, so a marketplace package has to land in the package that owns the profile or it installs successfully and then fails to load.
|
|
594
|
+
async function marketplaceInstallDirectory(configPath, fallback) {
|
|
595
|
+
let directory = dirname(resolve(configPath));
|
|
596
|
+
let parent = dirname(directory);
|
|
597
|
+
while (parent !== directory) {
|
|
598
|
+
if (await isFile(join(directory, "package.json")))
|
|
599
|
+
return directory;
|
|
600
|
+
directory = parent;
|
|
601
|
+
parent = dirname(directory);
|
|
602
|
+
}
|
|
603
|
+
return fallback;
|
|
604
|
+
}
|
|
542
605
|
function pickDirectory() {
|
|
543
606
|
return new Promise((resolvePath, reject) => {
|
|
544
607
|
execFile("osascript", ["-e", 'POSIX path of (choose folder with prompt "选择 Pi 工作区")'], { timeout: 120_000, maxBuffer: 64 * 1024 }, (error, stdout, stderr) => {
|
|
@@ -562,7 +625,7 @@ function workspacePaths(root, paths) {
|
|
|
562
625
|
const requested = path;
|
|
563
626
|
const absolute = resolve(root, requested);
|
|
564
627
|
const relativePath = relative(root, absolute);
|
|
565
|
-
if (
|
|
628
|
+
if (escapesRoot(relativePath))
|
|
566
629
|
return new Error("path must stay inside the workspace");
|
|
567
630
|
normalized.push(relativePath);
|
|
568
631
|
}
|
|
@@ -725,8 +788,8 @@ export default {
|
|
|
725
788
|
sendJson(response, 400, { error: "settings source must contain a JSON object" });
|
|
726
789
|
return;
|
|
727
790
|
}
|
|
728
|
-
|
|
729
|
-
|
|
791
|
+
// Replace the file atomically so an interrupted write never leaves a truncated settings.json behind; keep the existing permission bits. The rename must land on the resolved target, otherwise a symlinked settings.json (dotfiles repositories) would be replaced by a detached regular file.
|
|
792
|
+
const path = await realpath(join(services.launch.agentDir, "settings.json")).catch(() => join(services.launch.agentDir, "settings.json"));
|
|
730
793
|
const mode = await stat(path).then((info) => info.mode & 0o777, () => 0o644);
|
|
731
794
|
await atomicWriteFile(path, JSON.stringify(parsed, null, 2) + "\n", { encoding: "utf8", mode });
|
|
732
795
|
await services.runtime.session.settingsManager.reload();
|
|
@@ -989,15 +1052,17 @@ export default {
|
|
|
989
1052
|
sendJson(response, 409, { error: "Plugin is already installed", plugin });
|
|
990
1053
|
return;
|
|
991
1054
|
}
|
|
992
|
-
const
|
|
993
|
-
const
|
|
1055
|
+
const installDirectory = await marketplaceInstallDirectory(configPath, services.launch.cwd);
|
|
1056
|
+
const packageJsonPath = join(installDirectory, "package.json");
|
|
1057
|
+
const packageLockPath = join(installDirectory, "package-lock.json");
|
|
994
1058
|
const packageJsonBefore = await readFile(packageJsonPath, "utf8").catch(() => undefined);
|
|
995
1059
|
const packageLockBefore = await readFile(packageLockPath, "utf8").catch(() => undefined);
|
|
996
1060
|
let profileBefore;
|
|
997
1061
|
let entryId;
|
|
998
1062
|
try {
|
|
999
1063
|
if (needsMarketplacePackageInstall(plugin)) {
|
|
1000
|
-
|
|
1064
|
+
const specifier = `${marketplaceNpmPackageName(plugin.packageName)}@${plugin.version}`;
|
|
1065
|
+
await runProcess("npm", ["install", "--save-exact", "--package-lock=false", specifier], installDirectory);
|
|
1001
1066
|
}
|
|
1002
1067
|
profileBefore = await appendMarketplaceProfile(configPath, plugin);
|
|
1003
1068
|
if (!needsMarketplacePackageInstall(plugin)) {
|
|
@@ -1021,9 +1086,14 @@ export default {
|
|
|
1021
1086
|
await loader.remove(entryId).catch(() => { });
|
|
1022
1087
|
if (profileBefore !== undefined)
|
|
1023
1088
|
await writeFile(configPath, profileBefore, "utf8").catch(() => { });
|
|
1024
|
-
|
|
1089
|
+
// A manifest npm created for this install is removed rather than left behind; restoring is only possible when one existed before.
|
|
1090
|
+
if (packageJsonBefore === undefined)
|
|
1091
|
+
await unlink(packageJsonPath).catch(() => { });
|
|
1092
|
+
else
|
|
1025
1093
|
await writeFile(packageJsonPath, packageJsonBefore, "utf8").catch(() => { });
|
|
1026
|
-
if (packageLockBefore
|
|
1094
|
+
if (packageLockBefore === undefined)
|
|
1095
|
+
await unlink(packageLockPath).catch(() => { });
|
|
1096
|
+
else
|
|
1027
1097
|
await writeFile(packageLockPath, packageLockBefore, "utf8").catch(() => { });
|
|
1028
1098
|
sendJson(response, 502, { error: errorText(error) });
|
|
1029
1099
|
}
|
|
@@ -1125,8 +1195,9 @@ export default {
|
|
|
1125
1195
|
}
|
|
1126
1196
|
const profileEntryId = entry.options.id;
|
|
1127
1197
|
const profileBefore = await readFile(configPath, "utf8");
|
|
1128
|
-
const
|
|
1129
|
-
const
|
|
1198
|
+
const installDirectory = await marketplaceInstallDirectory(configPath, services.launch.cwd);
|
|
1199
|
+
const packageJsonPath = join(installDirectory, "package.json");
|
|
1200
|
+
const packageLockPath = join(installDirectory, "package-lock.json");
|
|
1130
1201
|
const packageJsonBefore = await readFile(packageJsonPath, "utf8").catch(() => undefined);
|
|
1131
1202
|
const packageLockBefore = await readFile(packageLockPath, "utf8").catch(() => undefined);
|
|
1132
1203
|
await entry.parent.remove(entry.options.id);
|
|
@@ -1134,7 +1205,7 @@ export default {
|
|
|
1134
1205
|
try {
|
|
1135
1206
|
await updateMarketplaceProfile(configPath, profileEntryId, { remove: true });
|
|
1136
1207
|
if (needsMarketplacePackageInstall(plugin))
|
|
1137
|
-
await runProcess("npm", ["uninstall", "--package-lock=false", plugin.packageName],
|
|
1208
|
+
await runProcess("npm", ["uninstall", "--package-lock=false", marketplaceNpmPackageName(plugin.packageName)], installDirectory);
|
|
1138
1209
|
sendJson(response, 200, { uninstalled: true, id: payload.id });
|
|
1139
1210
|
}
|
|
1140
1211
|
catch (error) {
|
|
@@ -1246,18 +1317,11 @@ export default {
|
|
|
1246
1317
|
sendJson(response, 500, { error: errorText(error) });
|
|
1247
1318
|
return;
|
|
1248
1319
|
}
|
|
1249
|
-
const items = status.
|
|
1250
|
-
.
|
|
1251
|
-
|
|
1252
|
-
.
|
|
1253
|
-
|
|
1254
|
-
const status = line.slice(0, 2).trim() || "??";
|
|
1255
|
-
return {
|
|
1256
|
-
path: line.slice(3),
|
|
1257
|
-
status,
|
|
1258
|
-
label: status === "??" ? "untracked" : status.includes("D") ? "deleted" : status.includes("A") ? "added" : "modified",
|
|
1259
|
-
};
|
|
1260
|
-
});
|
|
1320
|
+
const items = status.entries.map((entry) => ({
|
|
1321
|
+
path: entry.path,
|
|
1322
|
+
status: entry.status,
|
|
1323
|
+
label: entry.status === "??" ? "untracked" : entry.status.includes("D") ? "deleted" : entry.status.includes("A") ? "added" : "modified",
|
|
1324
|
+
}));
|
|
1261
1325
|
sendJson(response, 200, { items, ...(status.truncated ? { truncated: true } : {}) });
|
|
1262
1326
|
},
|
|
1263
1327
|
});
|
|
@@ -1277,7 +1341,7 @@ export default {
|
|
|
1277
1341
|
const root = resolve(activeCwd(services));
|
|
1278
1342
|
const absolute = resolve(root, requested);
|
|
1279
1343
|
const relativePath = relative(root, absolute);
|
|
1280
|
-
if (
|
|
1344
|
+
if (escapesRoot(relativePath)) {
|
|
1281
1345
|
sendJson(response, 400, { error: "path must stay inside the workspace" });
|
|
1282
1346
|
return;
|
|
1283
1347
|
}
|
|
@@ -1303,18 +1367,18 @@ export default {
|
|
|
1303
1367
|
return;
|
|
1304
1368
|
}
|
|
1305
1369
|
const root = resolve(activeCwd(services));
|
|
1306
|
-
const add = await gitCommand(root, ["add", "-A", "--", ...paths]);
|
|
1370
|
+
const add = await gitCommand(root, ["add", "-A", "--", ...paths], GIT_MUTATION_TIMEOUT_MS);
|
|
1307
1371
|
if (add.terminated) {
|
|
1308
|
-
sendJson(response, 500, { error: gitTerminationMessage("add", add.terminated) });
|
|
1372
|
+
sendJson(response, 500, { error: gitTerminationMessage("add", add.terminated, GIT_MUTATION_TIMEOUT_MS) });
|
|
1309
1373
|
return;
|
|
1310
1374
|
}
|
|
1311
1375
|
if (add.code !== 0) {
|
|
1312
1376
|
sendJson(response, 409, { error: add.stderr.trim() || "Unable to stage workspace files" });
|
|
1313
1377
|
return;
|
|
1314
1378
|
}
|
|
1315
|
-
const commit = await gitCommand(root, ["commit", "-m", payload.message.trim(), "--", ...paths]);
|
|
1379
|
+
const commit = await gitCommand(root, ["commit", "-m", payload.message.trim(), "--", ...paths], GIT_MUTATION_TIMEOUT_MS);
|
|
1316
1380
|
if (commit.terminated) {
|
|
1317
|
-
sendJson(response, 500, { error: gitTerminationMessage("commit", commit.terminated) });
|
|
1381
|
+
sendJson(response, 500, { error: gitTerminationMessage("commit", commit.terminated, GIT_MUTATION_TIMEOUT_MS) });
|
|
1318
1382
|
return;
|
|
1319
1383
|
}
|
|
1320
1384
|
if (commit.code !== 0) {
|
|
@@ -1370,9 +1434,9 @@ export default {
|
|
|
1370
1434
|
return;
|
|
1371
1435
|
}
|
|
1372
1436
|
if (trackedPaths.length > 0) {
|
|
1373
|
-
const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...trackedPaths]);
|
|
1437
|
+
const restore = await gitCommand(root, ["restore", "--worktree", "--staged", "--", ...trackedPaths], GIT_MUTATION_TIMEOUT_MS);
|
|
1374
1438
|
if (restore.terminated) {
|
|
1375
|
-
sendJson(response, 500, { error: gitTerminationMessage("restore", restore.terminated) });
|
|
1439
|
+
sendJson(response, 500, { error: gitTerminationMessage("restore", restore.terminated, GIT_MUTATION_TIMEOUT_MS) });
|
|
1376
1440
|
return;
|
|
1377
1441
|
}
|
|
1378
1442
|
if (restore.code !== 0) {
|
|
@@ -1744,21 +1808,48 @@ export default {
|
|
|
1744
1808
|
sendJson(response, 409, { error: "Cannot batch-delete the active session" });
|
|
1745
1809
|
return;
|
|
1746
1810
|
}
|
|
1747
|
-
|
|
1811
|
+
if (action === "delete") {
|
|
1812
|
+
// The unlinks run outside the metadata mutation: a failure halfway through must not discard the key removals for the files that are already gone from disk.
|
|
1813
|
+
const removed = [];
|
|
1814
|
+
const failed = [];
|
|
1748
1815
|
for (const path of paths) {
|
|
1749
|
-
|
|
1816
|
+
try {
|
|
1750
1817
|
await unlink(path);
|
|
1751
|
-
|
|
1818
|
+
removed.push(path);
|
|
1752
1819
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
};
|
|
1820
|
+
catch (error) {
|
|
1821
|
+
// A session another tab already deleted leaves nothing to unlink, but its metadata entry still has to go.
|
|
1822
|
+
if (error.code === "ENOENT")
|
|
1823
|
+
removed.push(path);
|
|
1824
|
+
else
|
|
1825
|
+
failed.push({ path, error: errorText(error) });
|
|
1760
1826
|
}
|
|
1761
1827
|
}
|
|
1828
|
+
await mutateSessionMetadata(manager, context.logger, (metadata) => {
|
|
1829
|
+
for (const path of removed)
|
|
1830
|
+
delete metadata[path];
|
|
1831
|
+
});
|
|
1832
|
+
if (failed.length > 0) {
|
|
1833
|
+
sendJson(response, 409, {
|
|
1834
|
+
error: `Some sessions could not be deleted: ${failed.map((item) => item.path).join(", ")}`,
|
|
1835
|
+
action,
|
|
1836
|
+
count: removed.length,
|
|
1837
|
+
failed,
|
|
1838
|
+
});
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
sendJson(response, 200, { action, count: removed.length });
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
await mutateSessionMetadata(manager, context.logger, (metadata) => {
|
|
1845
|
+
for (const path of paths) {
|
|
1846
|
+
const current = metadata[path] ?? {};
|
|
1847
|
+
metadata[path] = {
|
|
1848
|
+
...current,
|
|
1849
|
+
...(action === "archive" || action === "unarchive" ? { archived: action === "archive" } : {}),
|
|
1850
|
+
...(action === "pin" || action === "unpin" ? { pinned: action === "pin" } : {}),
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1762
1853
|
});
|
|
1763
1854
|
sendJson(response, 200, { action, count: paths.length });
|
|
1764
1855
|
}
|
|
@@ -1899,7 +1990,7 @@ export default {
|
|
|
1899
1990
|
const page = Math.max(0, Number.parseInt(url.searchParams.get("page") ?? "0", 10) || 0);
|
|
1900
1991
|
const pageSize = Math.min(100, Math.max(1, Number.parseInt(url.searchParams.get("pageSize") ?? "50", 10) || 50));
|
|
1901
1992
|
const includeArchived = url.searchParams.get("includeArchived") === "true";
|
|
1902
|
-
const metadata = await
|
|
1993
|
+
const metadata = await readSessionMetadataLocked(manager, context.logger);
|
|
1903
1994
|
const items = typeof manager.isPersisted === "function" && manager.isPersisted() ? await SessionManager.list(services.launch.cwd, manager.getSessionDir()) : [];
|
|
1904
1995
|
const filtered = items.filter((item) => includeArchived || metadata[item.path]?.archived !== true);
|
|
1905
1996
|
const sorted = filtered.sort((a, b) => Number(metadata[b.path]?.pinned === true) - Number(metadata[a.path]?.pinned === true) || b.modified.getTime() - a.modified.getTime());
|