@pooder/core 1.2.0 → 2.1.0
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/CHANGELOG.md +12 -0
- package/dist/index.d.mts +109 -3
- package/dist/index.d.ts +109 -3
- package/dist/index.js +309 -2
- package/dist/index.mjs +304 -1
- package/package.json +1 -1
- package/src/contribution/points.ts +27 -3
- package/src/extension.ts +7 -0
- package/src/index.ts +22 -1
- package/src/services/ToolRegistryService.ts +41 -0
- package/src/services/ToolSessionService.ts +176 -0
- package/src/services/WorkbenchService.ts +159 -0
- package/src/services/index.ts +10 -1
- package/src/test-extension-full.ts +3 -3
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import Disposable from "../disposable";
|
|
2
|
+
import EventBus from "../event";
|
|
3
|
+
import { Service } from "../service";
|
|
4
|
+
import ToolRegistryService from "./ToolRegistryService";
|
|
5
|
+
import ToolSessionService from "./ToolSessionService";
|
|
6
|
+
|
|
7
|
+
export interface ToolSwitchContext {
|
|
8
|
+
from: string | null;
|
|
9
|
+
to: string | null;
|
|
10
|
+
reason?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ToolSwitchResult {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
from: string | null;
|
|
16
|
+
to: string | null;
|
|
17
|
+
reason?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ToolSwitchGuard = (
|
|
21
|
+
context: ToolSwitchContext,
|
|
22
|
+
) => boolean | Promise<boolean>;
|
|
23
|
+
|
|
24
|
+
interface GuardItem {
|
|
25
|
+
guard: ToolSwitchGuard;
|
|
26
|
+
priority: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default class WorkbenchService implements Service {
|
|
30
|
+
private _activeToolId: string | null = null;
|
|
31
|
+
private eventBus?: EventBus;
|
|
32
|
+
private toolRegistry?: ToolRegistryService;
|
|
33
|
+
private sessionService?: ToolSessionService;
|
|
34
|
+
private guards: GuardItem[] = [];
|
|
35
|
+
|
|
36
|
+
init() {}
|
|
37
|
+
|
|
38
|
+
dispose() {
|
|
39
|
+
this.guards = [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setEventBus(bus: EventBus) {
|
|
43
|
+
this.eventBus = bus;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setToolRegistry(toolRegistry: ToolRegistryService) {
|
|
47
|
+
this.toolRegistry = toolRegistry;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setToolSessionService(sessionService: ToolSessionService) {
|
|
51
|
+
this.sessionService = sessionService;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get activeToolId(): string | null {
|
|
55
|
+
return this._activeToolId;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
registerSwitchGuard(
|
|
59
|
+
guard: ToolSwitchGuard,
|
|
60
|
+
priority: number = 0,
|
|
61
|
+
): Disposable {
|
|
62
|
+
const item: GuardItem = { guard, priority };
|
|
63
|
+
this.guards.push(item);
|
|
64
|
+
this.guards.sort((a, b) => b.priority - a.priority);
|
|
65
|
+
return {
|
|
66
|
+
dispose: () => {
|
|
67
|
+
const index = this.guards.indexOf(item);
|
|
68
|
+
if (index >= 0) this.guards.splice(index, 1);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private async runGuards(context: ToolSwitchContext): Promise<boolean> {
|
|
74
|
+
for (const { guard } of this.guards) {
|
|
75
|
+
const allowed = await Promise.resolve(guard(context));
|
|
76
|
+
if (!allowed) return false;
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async switchTool(
|
|
82
|
+
id: string | null,
|
|
83
|
+
options?: { reason?: string },
|
|
84
|
+
): Promise<ToolSwitchResult> {
|
|
85
|
+
if (this._activeToolId === id) {
|
|
86
|
+
return { ok: true, from: this._activeToolId, to: id };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (id && this.toolRegistry && !this.toolRegistry.hasTool(id)) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
from: this._activeToolId,
|
|
93
|
+
to: id,
|
|
94
|
+
reason: `tool-not-registered:${id}`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const context: ToolSwitchContext = {
|
|
99
|
+
from: this._activeToolId,
|
|
100
|
+
to: id,
|
|
101
|
+
reason: options?.reason,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const guardAllowed = await this.runGuards(context);
|
|
105
|
+
if (!guardAllowed) {
|
|
106
|
+
this.eventBus?.emit("tool:switch:blocked", {
|
|
107
|
+
...context,
|
|
108
|
+
reason: "blocked-by-guard",
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
from: this._activeToolId,
|
|
113
|
+
to: id,
|
|
114
|
+
reason: "blocked-by-guard",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (context.from && this.sessionService) {
|
|
119
|
+
const leaveResult = await this.sessionService.handleBeforeLeave(
|
|
120
|
+
context.from,
|
|
121
|
+
);
|
|
122
|
+
if (leaveResult.decision === "blocked") {
|
|
123
|
+
this.eventBus?.emit("tool:switch:blocked", {
|
|
124
|
+
...context,
|
|
125
|
+
reason: leaveResult.reason || "session-blocked",
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
ok: false,
|
|
129
|
+
from: this._activeToolId,
|
|
130
|
+
to: id,
|
|
131
|
+
reason: leaveResult.reason || "session-blocked",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
this.sessionService.deactivateSession(context.from);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (id && this.sessionService && this.toolRegistry) {
|
|
138
|
+
const tool = this.toolRegistry.getTool(id);
|
|
139
|
+
if (tool?.interaction === "session" && tool.session?.autoBegin !== false) {
|
|
140
|
+
await this.sessionService.begin(id);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const previous = this._activeToolId;
|
|
145
|
+
this._activeToolId = id;
|
|
146
|
+
const reason = options?.reason;
|
|
147
|
+
this.eventBus?.emit("tool:activated", { id, previous, reason });
|
|
148
|
+
this.eventBus?.emit("tool:switch", { from: previous, to: id, reason });
|
|
149
|
+
return { ok: true, from: previous, to: id };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async activate(id: string | null): Promise<ToolSwitchResult> {
|
|
153
|
+
return await this.switchTool(id, { reason: "activate" });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async deactivate(): Promise<ToolSwitchResult> {
|
|
157
|
+
return await this.switchTool(null, { reason: "deactivate" });
|
|
158
|
+
}
|
|
159
|
+
}
|
package/src/services/index.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import CommandService from "./CommandService";
|
|
2
2
|
import ConfigurationService from "./ConfigurationService";
|
|
3
|
+
import ToolRegistryService from "./ToolRegistryService";
|
|
4
|
+
import ToolSessionService from "./ToolSessionService";
|
|
5
|
+
import WorkbenchService from "./WorkbenchService";
|
|
3
6
|
|
|
4
|
-
export {
|
|
7
|
+
export {
|
|
8
|
+
CommandService,
|
|
9
|
+
ConfigurationService,
|
|
10
|
+
ToolRegistryService,
|
|
11
|
+
ToolSessionService,
|
|
12
|
+
WorkbenchService,
|
|
13
|
+
};
|
|
@@ -57,9 +57,9 @@ export const fullExtension: Extension = {
|
|
|
57
57
|
id: "test.tool.calculator",
|
|
58
58
|
name: "Calculator",
|
|
59
59
|
description: "Simple calculator",
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
interaction: "instant",
|
|
61
|
+
commands: {
|
|
62
|
+
execute: "test.declarative.auto",
|
|
63
63
|
},
|
|
64
64
|
} as ToolContribution,
|
|
65
65
|
],
|