gsd-pi 2.43.0-next.8 → 2.44.0-dev.62b5d6c
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/dist/cli.js +13 -1
- package/dist/help-text.js +24 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +21 -8
- package/dist/resources/extensions/gsd/auto-prompts.js +130 -51
- package/dist/resources/extensions/gsd/auto-worktree.js +16 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +34 -10
- package/dist/resources/extensions/gsd/markdown-renderer.js +7 -5
- package/dist/resources/extensions/gsd/reactive-graph.js +13 -2
- package/dist/resources/extensions/gsd/skill-health.js +3 -1
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -11
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -10
- package/dist/resources/extensions/gsd/visualizer-data.js +45 -13
- package/dist/resources/extensions/gsd/workspace-index.js +46 -15
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +4 -4
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +4 -4
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -3
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +11 -34
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +3 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +11 -199
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +13 -37
- package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
- package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +23 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
- package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
- package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
- package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
- package/packages/pi-coding-agent/src/index.ts +7 -0
- package/packages/pi-coding-agent/src/main.ts +11 -232
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +22 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +109 -42
- package/src/resources/extensions/gsd/auto-worktree.ts +16 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +28 -10
- package/src/resources/extensions/gsd/markdown-renderer.ts +7 -5
- package/src/resources/extensions/gsd/reactive-graph.ts +12 -2
- package/src/resources/extensions/gsd/skill-health.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -18
- package/src/resources/extensions/gsd/tools/plan-slice.ts +1 -15
- package/src/resources/extensions/gsd/visualizer-data.ts +46 -14
- package/src/resources/extensions/gsd/workspace-index.ts +49 -18
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
- /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → fOnWQBjWXMKUs4bqTg530}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → fOnWQBjWXMKUs4bqTg530}/_ssgManifest.js +0 -0
|
@@ -94,6 +94,11 @@ export type {
|
|
|
94
94
|
// Provider Registration
|
|
95
95
|
ProviderConfig,
|
|
96
96
|
ProviderModelConfig,
|
|
97
|
+
LifecycleHookContext,
|
|
98
|
+
LifecycleHookHandler,
|
|
99
|
+
LifecycleHookMap,
|
|
100
|
+
LifecycleHookPhase,
|
|
101
|
+
LifecycleHookScope,
|
|
97
102
|
ReadToolCallEvent,
|
|
98
103
|
ReadToolResultEvent,
|
|
99
104
|
// Commands
|
|
@@ -42,6 +42,7 @@ import type {
|
|
|
42
42
|
Extension,
|
|
43
43
|
ExtensionAPI,
|
|
44
44
|
ExtensionFactory,
|
|
45
|
+
LifecycleHookHandler,
|
|
45
46
|
ExtensionRuntime,
|
|
46
47
|
LoadExtensionsResult,
|
|
47
48
|
MessageRenderer,
|
|
@@ -463,6 +464,22 @@ function createExtensionAPI(
|
|
|
463
464
|
extension.commands.set(name, { name, ...options });
|
|
464
465
|
},
|
|
465
466
|
|
|
467
|
+
registerBeforeInstall(handler: LifecycleHookHandler): void {
|
|
468
|
+
extension.lifecycleHooks.beforeInstall.push(handler);
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
registerAfterInstall(handler: LifecycleHookHandler): void {
|
|
472
|
+
extension.lifecycleHooks.afterInstall.push(handler);
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
registerBeforeRemove(handler: LifecycleHookHandler): void {
|
|
476
|
+
extension.lifecycleHooks.beforeRemove.push(handler);
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
registerAfterRemove(handler: LifecycleHookHandler): void {
|
|
480
|
+
extension.lifecycleHooks.afterRemove.push(handler);
|
|
481
|
+
},
|
|
482
|
+
|
|
466
483
|
registerShortcut(
|
|
467
484
|
shortcut: KeyId,
|
|
468
485
|
options: {
|
|
@@ -683,6 +700,12 @@ function createExtension(extensionPath: string, resolvedPath: string): Extension
|
|
|
683
700
|
commands: new Map(),
|
|
684
701
|
flags: new Map(),
|
|
685
702
|
shortcuts: new Map(),
|
|
703
|
+
lifecycleHooks: {
|
|
704
|
+
beforeInstall: [],
|
|
705
|
+
afterInstall: [],
|
|
706
|
+
beforeRemove: [],
|
|
707
|
+
afterRemove: [],
|
|
708
|
+
},
|
|
686
709
|
};
|
|
687
710
|
}
|
|
688
711
|
|
|
@@ -949,6 +949,33 @@ export interface RegisteredCommand {
|
|
|
949
949
|
handler: (args: string, ctx: ExtensionCommandContext) => Promise<void>;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
export type LifecycleHookScope = "user" | "project";
|
|
953
|
+
export type LifecycleHookPhase = "beforeInstall" | "afterInstall" | "beforeRemove" | "afterRemove";
|
|
954
|
+
|
|
955
|
+
export interface LifecycleHookContext {
|
|
956
|
+
/** Lifecycle phase currently being executed. */
|
|
957
|
+
phase: LifecycleHookPhase;
|
|
958
|
+
/** Package source string passed to install (npm:, git:, https://, local path). */
|
|
959
|
+
source: string;
|
|
960
|
+
/** Resolved installed package path (or resolved local path), when available for this phase. */
|
|
961
|
+
installedPath?: string;
|
|
962
|
+
/** Where the package was installed. */
|
|
963
|
+
scope: LifecycleHookScope;
|
|
964
|
+
/** Current working directory for the install invocation. */
|
|
965
|
+
cwd: string;
|
|
966
|
+
/** Whether install is running in an interactive TTY. */
|
|
967
|
+
interactive: boolean;
|
|
968
|
+
/** Info-level logging sink for install output. */
|
|
969
|
+
log(message: string): void;
|
|
970
|
+
/** Warning-level logging sink for install output. */
|
|
971
|
+
warn(message: string): void;
|
|
972
|
+
/** Error-level logging sink for install output. */
|
|
973
|
+
error(message: string): void;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
export type LifecycleHookHandler = (ctx: LifecycleHookContext) => Promise<void> | void;
|
|
977
|
+
export type LifecycleHookMap = Record<LifecycleHookPhase, LifecycleHookHandler[]>;
|
|
978
|
+
|
|
952
979
|
// ============================================================================
|
|
953
980
|
// Extension API
|
|
954
981
|
// ============================================================================
|
|
@@ -1019,6 +1046,18 @@ export interface ExtensionAPI {
|
|
|
1019
1046
|
/** Register a custom command. */
|
|
1020
1047
|
registerCommand(name: string, options: Omit<RegisteredCommand, "name">): void;
|
|
1021
1048
|
|
|
1049
|
+
/** Register a lifecycle hook run before package installation starts. */
|
|
1050
|
+
registerBeforeInstall(handler: LifecycleHookHandler): void;
|
|
1051
|
+
|
|
1052
|
+
/** Register a lifecycle hook run after package installation completes. */
|
|
1053
|
+
registerAfterInstall(handler: LifecycleHookHandler): void;
|
|
1054
|
+
|
|
1055
|
+
/** Register a lifecycle hook run before package removal starts. */
|
|
1056
|
+
registerBeforeRemove(handler: LifecycleHookHandler): void;
|
|
1057
|
+
|
|
1058
|
+
/** Register a lifecycle hook run after package removal completes. */
|
|
1059
|
+
registerAfterRemove(handler: LifecycleHookHandler): void;
|
|
1060
|
+
|
|
1022
1061
|
/** Register a keyboard shortcut. */
|
|
1023
1062
|
registerShortcut(
|
|
1024
1063
|
shortcut: KeyId,
|
|
@@ -1201,6 +1240,10 @@ export interface ExtensionAPI {
|
|
|
1201
1240
|
|
|
1202
1241
|
/** Configuration for registering a provider via pi.registerProvider(). */
|
|
1203
1242
|
export interface ProviderConfig {
|
|
1243
|
+
/** Auth behavior for provider availability and request key handling. Defaults to "apiKey". */
|
|
1244
|
+
authMode?: "apiKey" | "oauth" | "externalCli" | "none";
|
|
1245
|
+
/** Optional readiness check. Return false if the provider cannot accept requests (e.g., CLI not authenticated, API key invalid). Called before default auth checks. */
|
|
1246
|
+
isReady?: () => boolean;
|
|
1204
1247
|
/** Base URL for the API endpoint. Required when defining models. */
|
|
1205
1248
|
baseUrl?: string;
|
|
1206
1249
|
/** API key or environment variable name. Required when defining models (unless oauth provided). */
|
|
@@ -1382,6 +1425,7 @@ export interface Extension {
|
|
|
1382
1425
|
commands: Map<string, RegisteredCommand>;
|
|
1383
1426
|
flags: Map<string, ExtensionFlag>;
|
|
1384
1427
|
shortcuts: Map<KeyId, ExtensionShortcut>;
|
|
1428
|
+
lifecycleHooks: LifecycleHookMap;
|
|
1385
1429
|
}
|
|
1386
1430
|
|
|
1387
1431
|
/** Result of loading extensions. */
|
|
@@ -38,6 +38,7 @@ function createResolver(overrides?: {
|
|
|
38
38
|
enabled?: boolean;
|
|
39
39
|
isProviderAvailable?: (provider: string) => boolean;
|
|
40
40
|
hasAuth?: (provider: string) => boolean;
|
|
41
|
+
isProviderRequestReady?: (provider: string) => boolean;
|
|
41
42
|
find?: (provider: string, modelId: string) => Model<Api> | undefined;
|
|
42
43
|
}) {
|
|
43
44
|
const settingsManager = {
|
|
@@ -60,6 +61,7 @@ function createResolver(overrides?: {
|
|
|
60
61
|
if (provider === "openai" && modelId === "gpt-4.1") return openaiModel;
|
|
61
62
|
return undefined;
|
|
62
63
|
}),
|
|
64
|
+
isProviderRequestReady: overrides?.isProviderRequestReady ?? overrides?.hasAuth ?? (() => true),
|
|
63
65
|
} as unknown as ModelRegistry;
|
|
64
66
|
|
|
65
67
|
return { resolver: new FallbackResolver(settingsManager, authStorage, modelRegistry), authStorage };
|
|
@@ -122,9 +124,9 @@ describe("FallbackResolver — findFallback", () => {
|
|
|
122
124
|
assert.equal(result, null);
|
|
123
125
|
});
|
|
124
126
|
|
|
125
|
-
it("skips providers
|
|
127
|
+
it("skips providers that are not request-ready", async () => {
|
|
126
128
|
const { resolver } = createResolver({
|
|
127
|
-
|
|
129
|
+
isProviderRequestReady: (provider: string) => provider !== "alibaba",
|
|
128
130
|
});
|
|
129
131
|
|
|
130
132
|
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
@@ -133,6 +135,17 @@ describe("FallbackResolver — findFallback", () => {
|
|
|
133
135
|
assert.equal(result!.model.provider, "openai");
|
|
134
136
|
});
|
|
135
137
|
|
|
138
|
+
it("allows fallback to external-cli style providers without stored auth", async () => {
|
|
139
|
+
const { resolver } = createResolver({
|
|
140
|
+
hasAuth: () => false,
|
|
141
|
+
isProviderRequestReady: (provider: string) => provider === "alibaba",
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
145
|
+
assert.notEqual(result, null);
|
|
146
|
+
assert.equal(result!.model.provider, "alibaba");
|
|
147
|
+
});
|
|
148
|
+
|
|
136
149
|
it("skips providers with no model in registry", async () => {
|
|
137
150
|
const { resolver } = createResolver({
|
|
138
151
|
find: (provider: string, modelId: string) => {
|
|
@@ -149,9 +149,8 @@ export class FallbackResolver {
|
|
|
149
149
|
const model = this.modelRegistry.find(entry.provider, entry.model);
|
|
150
150
|
if (!model) continue;
|
|
151
151
|
|
|
152
|
-
// Check if
|
|
153
|
-
|
|
154
|
-
if (!hasAuth) continue;
|
|
152
|
+
// Check if provider is request-ready for fallback (authMode-aware)
|
|
153
|
+
if (!this.modelRegistry.isProviderRequestReady(entry.provider)) continue;
|
|
155
154
|
|
|
156
155
|
return {
|
|
157
156
|
model,
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { parseGitUrl } from "../utils/git.js";
|
|
7
|
+
import {
|
|
8
|
+
importExtensionModule,
|
|
9
|
+
loadExtensions,
|
|
10
|
+
type LifecycleHookContext,
|
|
11
|
+
type LifecycleHookMap,
|
|
12
|
+
type LifecycleHookHandler,
|
|
13
|
+
type LifecycleHookPhase,
|
|
14
|
+
type LifecycleHookScope,
|
|
15
|
+
} from "./extensions/index.js";
|
|
16
|
+
import type { DefaultPackageManager } from "./package-manager.js";
|
|
17
|
+
|
|
18
|
+
interface ExtensionManifest {
|
|
19
|
+
dependencies?: {
|
|
20
|
+
runtime?: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PackageLifecycleHooksOptions {
|
|
25
|
+
source: string;
|
|
26
|
+
local: boolean;
|
|
27
|
+
cwd: string;
|
|
28
|
+
agentDir: string;
|
|
29
|
+
appName: string;
|
|
30
|
+
packageManager: DefaultPackageManager;
|
|
31
|
+
stdout: NodeJS.WriteStream;
|
|
32
|
+
stderr: NodeJS.WriteStream;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type LifecycleHooksTarget = "source" | "installed";
|
|
36
|
+
|
|
37
|
+
export interface PrepareLifecycleHooksOptions {
|
|
38
|
+
verifyRuntimeDependencies?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface LifecycleHooksRunResult {
|
|
42
|
+
phase: LifecycleHookPhase;
|
|
43
|
+
hooksRun: number;
|
|
44
|
+
hookErrors: number;
|
|
45
|
+
legacyHooksRun: number;
|
|
46
|
+
entryPathCount: number;
|
|
47
|
+
skipped: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface LoadedLifecycleHooks {
|
|
51
|
+
source: string;
|
|
52
|
+
scope: LifecycleHookScope;
|
|
53
|
+
installedPath?: string;
|
|
54
|
+
cwd: string;
|
|
55
|
+
stdout: NodeJS.WriteStream;
|
|
56
|
+
stderr: NodeJS.WriteStream;
|
|
57
|
+
entryPaths: string[];
|
|
58
|
+
hooksByPath: Map<string, LifecycleHookMap>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function toScope(local: boolean): LifecycleHookScope {
|
|
62
|
+
return local ? "project" : "user";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readManifestRuntimeDeps(dir: string): string[] {
|
|
66
|
+
const manifestPath = join(dir, "extension-manifest.json");
|
|
67
|
+
if (!existsSync(manifestPath)) return [];
|
|
68
|
+
try {
|
|
69
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8")) as ExtensionManifest;
|
|
70
|
+
return manifest.dependencies?.runtime?.filter((dep): dep is string => typeof dep === "string") ?? [];
|
|
71
|
+
} catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function collectRuntimeDependencies(installedPath: string, entryPaths: string[]): string[] {
|
|
77
|
+
const deps = new Set<string>();
|
|
78
|
+
const candidateDirs = new Set<string>([installedPath, ...entryPaths.map((entryPath) => dirname(entryPath))]);
|
|
79
|
+
for (const dir of candidateDirs) {
|
|
80
|
+
for (const dep of readManifestRuntimeDeps(dir)) {
|
|
81
|
+
deps.add(dep);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return Array.from(deps);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function verifyRuntimeDependencies(runtimeDeps: string[], source: string, appName: string): void {
|
|
88
|
+
const missing: string[] = [];
|
|
89
|
+
for (const dep of runtimeDeps) {
|
|
90
|
+
const result = spawnSync(dep, ["--version"], { encoding: "utf-8", timeout: 5000 });
|
|
91
|
+
if (result.error || result.status !== 0) {
|
|
92
|
+
missing.push(dep);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (missing.length === 0) return;
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Missing runtime dependencies: ${missing.join(", ")}.\n` +
|
|
98
|
+
`Install them and retry: ${appName} install ${source}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function resolveLocalSourcePath(source: string, cwd: string): string | undefined {
|
|
103
|
+
const trimmed = source.trim();
|
|
104
|
+
if (!trimmed) return undefined;
|
|
105
|
+
if (trimmed.startsWith("npm:")) return undefined;
|
|
106
|
+
if (parseGitUrl(trimmed)) return undefined;
|
|
107
|
+
|
|
108
|
+
let normalized = trimmed;
|
|
109
|
+
if (normalized === "~") {
|
|
110
|
+
normalized = homedir();
|
|
111
|
+
} else if (normalized.startsWith("~/")) {
|
|
112
|
+
normalized = join(homedir(), normalized.slice(2));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const absolutePath = resolve(cwd, normalized);
|
|
116
|
+
return existsSync(absolutePath) ? absolutePath : undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function resolveEntryPathsFromTarget(
|
|
120
|
+
options: PackageLifecycleHooksOptions,
|
|
121
|
+
target: LifecycleHooksTarget,
|
|
122
|
+
scope: LifecycleHookScope,
|
|
123
|
+
): Promise<{ entryPaths: string[]; installedPath?: string }> {
|
|
124
|
+
if (target === "source") {
|
|
125
|
+
const localSourcePath = resolveLocalSourcePath(options.source, options.cwd);
|
|
126
|
+
if (!localSourcePath) return { entryPaths: [] };
|
|
127
|
+
const resolved = await options.packageManager.resolveExtensionSources([localSourcePath], { local: true });
|
|
128
|
+
const entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);
|
|
129
|
+
return { entryPaths, installedPath: localSourcePath };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const installedPath = options.packageManager.getInstalledPath(options.source, scope);
|
|
133
|
+
if (!installedPath) return { entryPaths: [] };
|
|
134
|
+
const resolved = await options.packageManager.resolveExtensionSources([installedPath], { local: true });
|
|
135
|
+
const entryPaths = resolved.extensions.filter((resource) => resource.enabled).map((resource) => resource.path);
|
|
136
|
+
return { entryPaths, installedPath };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function prepareLifecycleHooks(
|
|
140
|
+
options: PackageLifecycleHooksOptions,
|
|
141
|
+
target: LifecycleHooksTarget,
|
|
142
|
+
prepareOptions?: PrepareLifecycleHooksOptions,
|
|
143
|
+
): Promise<LoadedLifecycleHooks | null> {
|
|
144
|
+
const scope = toScope(options.local);
|
|
145
|
+
const { entryPaths, installedPath } = await resolveEntryPathsFromTarget(options, target, scope);
|
|
146
|
+
if (entryPaths.length === 0) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (prepareOptions?.verifyRuntimeDependencies && installedPath) {
|
|
151
|
+
const runtimeDeps = collectRuntimeDependencies(installedPath, entryPaths);
|
|
152
|
+
verifyRuntimeDependencies(runtimeDeps, options.source, options.appName);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const loaded = await loadExtensions(entryPaths, options.cwd);
|
|
156
|
+
for (const { path, error } of loaded.errors) {
|
|
157
|
+
options.stderr.write(`[lifecycle-hooks] Failed to load extension "${path}": ${error}\n`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const hooksByPath = new Map<string, LifecycleHookMap>();
|
|
161
|
+
for (const extension of loaded.extensions) {
|
|
162
|
+
hooksByPath.set(extension.path, extension.lifecycleHooks);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
source: options.source,
|
|
167
|
+
scope,
|
|
168
|
+
installedPath,
|
|
169
|
+
cwd: options.cwd,
|
|
170
|
+
stdout: options.stdout,
|
|
171
|
+
stderr: options.stderr,
|
|
172
|
+
entryPaths,
|
|
173
|
+
hooksByPath,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function runHookSafe(
|
|
178
|
+
hook: LifecycleHookHandler,
|
|
179
|
+
context: LifecycleHookContext,
|
|
180
|
+
stderr: NodeJS.WriteStream,
|
|
181
|
+
): Promise<boolean> {
|
|
182
|
+
try {
|
|
183
|
+
await hook(context);
|
|
184
|
+
return true;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
187
|
+
stderr.write(`[lifecycle-hooks:${context.phase}] Hook failed: ${message}\n`);
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function getLegacyExportCandidates(phase: LifecycleHookPhase): string[] {
|
|
193
|
+
return [phase];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function runLegacyExportHook(
|
|
197
|
+
entryPath: string,
|
|
198
|
+
phase: LifecycleHookPhase,
|
|
199
|
+
context: LifecycleHookContext,
|
|
200
|
+
): Promise<LifecycleHookHandler | null> {
|
|
201
|
+
try {
|
|
202
|
+
const module = await importExtensionModule<Record<string, unknown>>(import.meta.url, pathToFileURL(entryPath).href);
|
|
203
|
+
for (const exportName of getLegacyExportCandidates(phase)) {
|
|
204
|
+
const candidate = module[exportName];
|
|
205
|
+
if (typeof candidate === "function") {
|
|
206
|
+
return candidate as LifecycleHookHandler;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
} catch {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export async function runLifecycleHooks(
|
|
216
|
+
loaded: LoadedLifecycleHooks | null,
|
|
217
|
+
phase: LifecycleHookPhase,
|
|
218
|
+
): Promise<LifecycleHooksRunResult> {
|
|
219
|
+
if (!loaded) {
|
|
220
|
+
return {
|
|
221
|
+
phase,
|
|
222
|
+
hooksRun: 0,
|
|
223
|
+
hookErrors: 0,
|
|
224
|
+
legacyHooksRun: 0,
|
|
225
|
+
entryPathCount: 0,
|
|
226
|
+
skipped: true,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const context: LifecycleHookContext = {
|
|
231
|
+
phase,
|
|
232
|
+
source: loaded.source,
|
|
233
|
+
installedPath: loaded.installedPath,
|
|
234
|
+
scope: loaded.scope,
|
|
235
|
+
cwd: loaded.cwd,
|
|
236
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
237
|
+
log: (message) => loaded.stdout.write(`${message}\n`),
|
|
238
|
+
warn: (message) => loaded.stderr.write(`${message}\n`),
|
|
239
|
+
error: (message) => loaded.stderr.write(`${message}\n`),
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
let hooksRun = 0;
|
|
243
|
+
let hookErrors = 0;
|
|
244
|
+
let legacyHooksRun = 0;
|
|
245
|
+
|
|
246
|
+
for (const entryPath of loaded.entryPaths) {
|
|
247
|
+
const hookMap = loaded.hooksByPath.get(entryPath);
|
|
248
|
+
const registeredHooks = hookMap?.[phase] ?? [];
|
|
249
|
+
if (registeredHooks.length > 0) {
|
|
250
|
+
for (const hook of registeredHooks) {
|
|
251
|
+
hooksRun += 1;
|
|
252
|
+
const ok = await runHookSafe(hook, context, loaded.stderr);
|
|
253
|
+
if (!ok) hookErrors += 1;
|
|
254
|
+
}
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const legacyHook = await runLegacyExportHook(entryPath, phase, context);
|
|
259
|
+
if (!legacyHook) continue;
|
|
260
|
+
|
|
261
|
+
legacyHooksRun += 1;
|
|
262
|
+
const ok = await runHookSafe(legacyHook, context, loaded.stderr);
|
|
263
|
+
if (!ok) hookErrors += 1;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
phase,
|
|
268
|
+
hooksRun,
|
|
269
|
+
hookErrors,
|
|
270
|
+
legacyHooksRun,
|
|
271
|
+
entryPathCount: loaded.entryPaths.length,
|
|
272
|
+
skipped: false,
|
|
273
|
+
};
|
|
274
|
+
}
|