@pooder/core 2.1.0 → 2.2.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 +6 -0
- package/dist/index.d.mts +97 -18
- package/dist/index.d.ts +97 -18
- package/dist/index.js +473 -188
- package/dist/index.mjs +464 -187
- package/package.json +1 -1
- package/src/context.ts +7 -2
- package/src/extension.ts +10 -4
- package/src/index.ts +209 -32
- package/src/service.ts +191 -11
- package/src/services/ToolSessionService.ts +41 -4
- package/src/services/WorkbenchService.ts +65 -15
- package/src/services/index.ts +14 -0
- package/src/services/tokens.ts +27 -0
package/dist/index.js
CHANGED
|
@@ -20,6 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
COMMAND_SERVICE: () => COMMAND_SERVICE,
|
|
24
|
+
CONFIGURATION_SERVICE: () => CONFIGURATION_SERVICE,
|
|
25
|
+
CORE_SERVICE_TOKENS: () => CORE_SERVICE_TOKENS,
|
|
23
26
|
CommandService: () => CommandService,
|
|
24
27
|
ConfigurationService: () => ConfigurationService,
|
|
25
28
|
ContributionPointIds: () => ContributionPointIds,
|
|
@@ -29,29 +32,122 @@ __export(index_exports, {
|
|
|
29
32
|
ExtensionRegistry: () => ExtensionRegistry,
|
|
30
33
|
Pooder: () => Pooder,
|
|
31
34
|
ServiceRegistry: () => ServiceRegistry,
|
|
35
|
+
TOOL_REGISTRY_SERVICE: () => TOOL_REGISTRY_SERVICE,
|
|
36
|
+
TOOL_SESSION_SERVICE: () => TOOL_SESSION_SERVICE,
|
|
32
37
|
ToolRegistryService: () => ToolRegistryService,
|
|
33
38
|
ToolSessionService: () => ToolSessionService,
|
|
34
|
-
|
|
39
|
+
WORKBENCH_SERVICE: () => WORKBENCH_SERVICE,
|
|
40
|
+
WorkbenchService: () => WorkbenchService,
|
|
41
|
+
createServiceToken: () => createServiceToken,
|
|
42
|
+
isServiceToken: () => isServiceToken
|
|
35
43
|
});
|
|
36
44
|
module.exports = __toCommonJS(index_exports);
|
|
37
45
|
|
|
38
46
|
// src/service.ts
|
|
47
|
+
function createServiceToken(name) {
|
|
48
|
+
if (!name) {
|
|
49
|
+
throw new Error("Service token name is required.");
|
|
50
|
+
}
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
kind: "service-token",
|
|
53
|
+
key: Symbol(name),
|
|
54
|
+
name
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function isServiceToken(identifier) {
|
|
58
|
+
return typeof identifier === "object" && identifier !== null && "kind" in identifier && identifier.kind === "service-token";
|
|
59
|
+
}
|
|
39
60
|
var ServiceRegistry = class {
|
|
40
61
|
constructor() {
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
this.servicesByName = /* @__PURE__ */ new Map();
|
|
63
|
+
this.servicesByToken = /* @__PURE__ */ new Map();
|
|
64
|
+
this.registrationOrder = [];
|
|
65
|
+
}
|
|
66
|
+
register(identifier, service, options = {}) {
|
|
67
|
+
const normalized = this.normalizeIdentifier(identifier);
|
|
68
|
+
const existing = this.findEntry(normalized);
|
|
69
|
+
if (existing && !options.allowOverride) {
|
|
70
|
+
throw new Error(`Service "${normalized.name}" is already registered.`);
|
|
71
|
+
}
|
|
72
|
+
if (existing) {
|
|
73
|
+
this.removeEntry(existing);
|
|
74
|
+
}
|
|
75
|
+
const entry = {
|
|
76
|
+
token: normalized.token,
|
|
77
|
+
name: normalized.name,
|
|
78
|
+
service
|
|
79
|
+
};
|
|
80
|
+
this.servicesByName.set(entry.name, entry);
|
|
81
|
+
if (entry.token) {
|
|
82
|
+
this.servicesByToken.set(entry.token.key, entry);
|
|
83
|
+
}
|
|
84
|
+
this.registrationOrder.push(entry);
|
|
45
85
|
return service;
|
|
46
86
|
}
|
|
47
|
-
get(
|
|
48
|
-
|
|
87
|
+
get(identifier) {
|
|
88
|
+
const normalized = this.normalizeIdentifier(identifier);
|
|
89
|
+
const entry = this.findEntry(normalized);
|
|
90
|
+
return entry == null ? void 0 : entry.service;
|
|
49
91
|
}
|
|
50
|
-
|
|
51
|
-
|
|
92
|
+
getOrThrow(identifier, errorMessage) {
|
|
93
|
+
const service = this.get(identifier);
|
|
94
|
+
if (service) {
|
|
95
|
+
return service;
|
|
96
|
+
}
|
|
97
|
+
const normalized = this.normalizeIdentifier(identifier);
|
|
98
|
+
throw new Error(errorMessage != null ? errorMessage : `Service "${normalized.name}" not found.`);
|
|
99
|
+
}
|
|
100
|
+
has(identifier) {
|
|
101
|
+
const normalized = this.normalizeIdentifier(identifier);
|
|
102
|
+
return Boolean(this.findEntry(normalized));
|
|
103
|
+
}
|
|
104
|
+
delete(identifier) {
|
|
105
|
+
const normalized = this.normalizeIdentifier(identifier);
|
|
106
|
+
const entry = this.findEntry(normalized);
|
|
107
|
+
if (!entry) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
this.removeEntry(entry);
|
|
111
|
+
return true;
|
|
52
112
|
}
|
|
53
|
-
|
|
54
|
-
this.
|
|
113
|
+
list() {
|
|
114
|
+
return this.registrationOrder.map((entry) => ({
|
|
115
|
+
id: entry.name,
|
|
116
|
+
token: entry.token,
|
|
117
|
+
service: entry.service
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
clear() {
|
|
121
|
+
this.servicesByName.clear();
|
|
122
|
+
this.servicesByToken.clear();
|
|
123
|
+
this.registrationOrder.length = 0;
|
|
124
|
+
}
|
|
125
|
+
findEntry(identifier) {
|
|
126
|
+
var _a;
|
|
127
|
+
if (identifier.token) {
|
|
128
|
+
return (_a = this.servicesByToken.get(identifier.token.key)) != null ? _a : this.servicesByName.get(identifier.name);
|
|
129
|
+
}
|
|
130
|
+
return this.servicesByName.get(identifier.name);
|
|
131
|
+
}
|
|
132
|
+
normalizeIdentifier(identifier) {
|
|
133
|
+
if (isServiceToken(identifier)) {
|
|
134
|
+
return { token: identifier, name: identifier.name };
|
|
135
|
+
}
|
|
136
|
+
const name = identifier.trim();
|
|
137
|
+
if (!name) {
|
|
138
|
+
throw new Error("Service identifier must be a non-empty string.");
|
|
139
|
+
}
|
|
140
|
+
return { name };
|
|
141
|
+
}
|
|
142
|
+
removeEntry(entry) {
|
|
143
|
+
this.servicesByName.delete(entry.name);
|
|
144
|
+
if (entry.token) {
|
|
145
|
+
this.servicesByToken.delete(entry.token.key);
|
|
146
|
+
}
|
|
147
|
+
const index = this.registrationOrder.lastIndexOf(entry);
|
|
148
|
+
if (index >= 0) {
|
|
149
|
+
this.registrationOrder.splice(index, 1);
|
|
150
|
+
}
|
|
55
151
|
}
|
|
56
152
|
};
|
|
57
153
|
|
|
@@ -209,127 +305,6 @@ var ContributionRegistry = class {
|
|
|
209
305
|
}
|
|
210
306
|
};
|
|
211
307
|
|
|
212
|
-
// src/extension.ts
|
|
213
|
-
var ExtensionRegistry = class extends Map {
|
|
214
|
-
};
|
|
215
|
-
var ExtensionManager = class {
|
|
216
|
-
constructor(context) {
|
|
217
|
-
this.extensionRegistry = new ExtensionRegistry();
|
|
218
|
-
this.extensionDisposables = /* @__PURE__ */ new Map();
|
|
219
|
-
this.context = context;
|
|
220
|
-
}
|
|
221
|
-
register(extension) {
|
|
222
|
-
if (this.extensionRegistry.has(extension.id)) {
|
|
223
|
-
console.warn(
|
|
224
|
-
`Plugin "${extension.id}" already registered. It will be overwritten.`
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
this.extensionDisposables.set(extension.id, []);
|
|
228
|
-
const disposables = this.extensionDisposables.get(extension.id);
|
|
229
|
-
if (extension.contribute) {
|
|
230
|
-
for (const [pointId, items] of Object.entries(extension.contribute())) {
|
|
231
|
-
if (Array.isArray(items)) {
|
|
232
|
-
items.forEach((item, index) => {
|
|
233
|
-
const contributionId = item.id || (item.command ? item.command : `${extension.id}.${pointId}.${index}`);
|
|
234
|
-
const contribution = {
|
|
235
|
-
id: contributionId,
|
|
236
|
-
metadata: {
|
|
237
|
-
extensionId: extension.id,
|
|
238
|
-
...item == null ? void 0 : item.metadata
|
|
239
|
-
},
|
|
240
|
-
data: item
|
|
241
|
-
};
|
|
242
|
-
const disposable = this.context.contributions.register(
|
|
243
|
-
pointId,
|
|
244
|
-
contribution
|
|
245
|
-
);
|
|
246
|
-
disposables.push(disposable);
|
|
247
|
-
const dispose = this.collectContribution(pointId, contribution);
|
|
248
|
-
if (dispose) {
|
|
249
|
-
disposables.push(dispose);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
try {
|
|
256
|
-
this.extensionRegistry.set(extension.id, extension);
|
|
257
|
-
this.context.eventBus.emit("extension:register", extension);
|
|
258
|
-
} catch (error) {
|
|
259
|
-
console.error(
|
|
260
|
-
`Error in onCreate hook for plugin "${extension.id}":`,
|
|
261
|
-
error
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
try {
|
|
265
|
-
extension.activate(this.context);
|
|
266
|
-
} catch (error) {
|
|
267
|
-
console.error(
|
|
268
|
-
`Error in onActivate hook for plugin "${extension.id}":`,
|
|
269
|
-
error
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
console.log(`Plugin "${extension.id}" registered successfully`);
|
|
273
|
-
}
|
|
274
|
-
collectContribution(pointId, item) {
|
|
275
|
-
if (pointId === ContributionPointIds.CONFIGURATIONS) {
|
|
276
|
-
const configService = this.context.services.get(
|
|
277
|
-
"ConfigurationService"
|
|
278
|
-
);
|
|
279
|
-
configService == null ? void 0 : configService.initializeDefaults([item.data]);
|
|
280
|
-
}
|
|
281
|
-
if (pointId === ContributionPointIds.COMMANDS && item.data.handler) {
|
|
282
|
-
const commandService = this.context.services.get("CommandService");
|
|
283
|
-
return commandService.registerCommand(item.id, item.data.handler);
|
|
284
|
-
}
|
|
285
|
-
if (pointId === ContributionPointIds.TOOLS) {
|
|
286
|
-
const toolRegistry = this.context.services.get("ToolRegistryService");
|
|
287
|
-
if (!toolRegistry) return;
|
|
288
|
-
return toolRegistry.registerTool(item.data);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
unregister(name) {
|
|
292
|
-
const extension = this.extensionRegistry.get(name);
|
|
293
|
-
if (!extension) {
|
|
294
|
-
console.warn(`Plugin "${name}" not found.`);
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
try {
|
|
298
|
-
extension.deactivate(this.context);
|
|
299
|
-
} catch (error) {
|
|
300
|
-
console.error(`Error in deactivate for plugin "${name}":`, error);
|
|
301
|
-
}
|
|
302
|
-
const disposables = this.extensionDisposables.get(name);
|
|
303
|
-
if (disposables) {
|
|
304
|
-
disposables.forEach((d) => d.dispose());
|
|
305
|
-
this.extensionDisposables.delete(name);
|
|
306
|
-
}
|
|
307
|
-
this.extensionRegistry.delete(name);
|
|
308
|
-
console.log(`Plugin "${name}" unregistered`);
|
|
309
|
-
return true;
|
|
310
|
-
}
|
|
311
|
-
enable(name) {
|
|
312
|
-
const extension = this.extensionRegistry.get(name);
|
|
313
|
-
if (!extension) {
|
|
314
|
-
console.warn(`Plugin "${name}" not found.`);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
disable(name) {
|
|
319
|
-
const extension = this.extensionRegistry.get(name);
|
|
320
|
-
if (!extension) {
|
|
321
|
-
console.warn(`Plugin "${name}" not found.`);
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
update() {
|
|
326
|
-
}
|
|
327
|
-
destroy() {
|
|
328
|
-
const extensionNames = Array.from(this.extensionRegistry.keys());
|
|
329
|
-
extensionNames.forEach((name) => this.unregister(name));
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
|
|
333
308
|
// src/services/CommandService.ts
|
|
334
309
|
var CommandService = class {
|
|
335
310
|
constructor() {
|
|
@@ -524,11 +499,42 @@ var ToolRegistryService = class {
|
|
|
524
499
|
}
|
|
525
500
|
};
|
|
526
501
|
|
|
502
|
+
// src/services/tokens.ts
|
|
503
|
+
var COMMAND_SERVICE = createServiceToken(
|
|
504
|
+
"CommandService"
|
|
505
|
+
);
|
|
506
|
+
var CONFIGURATION_SERVICE = createServiceToken(
|
|
507
|
+
"ConfigurationService"
|
|
508
|
+
);
|
|
509
|
+
var TOOL_REGISTRY_SERVICE = createServiceToken("ToolRegistryService");
|
|
510
|
+
var TOOL_SESSION_SERVICE = createServiceToken("ToolSessionService");
|
|
511
|
+
var WORKBENCH_SERVICE = createServiceToken("WorkbenchService");
|
|
512
|
+
var CORE_SERVICE_TOKENS = {
|
|
513
|
+
COMMAND: COMMAND_SERVICE,
|
|
514
|
+
CONFIGURATION: CONFIGURATION_SERVICE,
|
|
515
|
+
TOOL_REGISTRY: TOOL_REGISTRY_SERVICE,
|
|
516
|
+
TOOL_SESSION: TOOL_SESSION_SERVICE,
|
|
517
|
+
WORKBENCH: WORKBENCH_SERVICE
|
|
518
|
+
};
|
|
519
|
+
|
|
527
520
|
// src/services/ToolSessionService.ts
|
|
528
521
|
var ToolSessionService = class {
|
|
529
|
-
constructor() {
|
|
522
|
+
constructor(dependencies = {}) {
|
|
530
523
|
this.sessions = /* @__PURE__ */ new Map();
|
|
531
524
|
this.dirtyTrackers = /* @__PURE__ */ new Map();
|
|
525
|
+
this.commandService = dependencies.commandService;
|
|
526
|
+
this.toolRegistry = dependencies.toolRegistry;
|
|
527
|
+
}
|
|
528
|
+
init(context) {
|
|
529
|
+
var _a, _b;
|
|
530
|
+
(_a = this.commandService) != null ? _a : this.commandService = context.get(COMMAND_SERVICE);
|
|
531
|
+
(_b = this.toolRegistry) != null ? _b : this.toolRegistry = context.get(TOOL_REGISTRY_SERVICE);
|
|
532
|
+
if (!this.commandService) {
|
|
533
|
+
throw new Error("ToolSessionService requires CommandService.");
|
|
534
|
+
}
|
|
535
|
+
if (!this.toolRegistry) {
|
|
536
|
+
throw new Error("ToolSessionService requires ToolRegistryService.");
|
|
537
|
+
}
|
|
532
538
|
}
|
|
533
539
|
setCommandService(commandService) {
|
|
534
540
|
this.commandService = commandService;
|
|
@@ -578,12 +584,23 @@ var ToolSessionService = class {
|
|
|
578
584
|
session.lastUpdatedAt = Date.now();
|
|
579
585
|
}
|
|
580
586
|
resolveTool(toolId) {
|
|
581
|
-
|
|
582
|
-
return (_a = this.toolRegistry) == null ? void 0 : _a.getTool(toolId);
|
|
587
|
+
return this.getToolRegistry().getTool(toolId);
|
|
583
588
|
}
|
|
584
589
|
async runCommand(commandId, ...args) {
|
|
585
|
-
if (!commandId
|
|
586
|
-
return await this.
|
|
590
|
+
if (!commandId) return void 0;
|
|
591
|
+
return await this.getCommandService().executeCommand(commandId, ...args);
|
|
592
|
+
}
|
|
593
|
+
getCommandService() {
|
|
594
|
+
if (!this.commandService) {
|
|
595
|
+
throw new Error("ToolSessionService is not initialized.");
|
|
596
|
+
}
|
|
597
|
+
return this.commandService;
|
|
598
|
+
}
|
|
599
|
+
getToolRegistry() {
|
|
600
|
+
if (!this.toolRegistry) {
|
|
601
|
+
throw new Error("ToolSessionService is not initialized.");
|
|
602
|
+
}
|
|
603
|
+
return this.toolRegistry;
|
|
587
604
|
}
|
|
588
605
|
async begin(toolId) {
|
|
589
606
|
var _a;
|
|
@@ -663,11 +680,27 @@ var ToolSessionService = class {
|
|
|
663
680
|
|
|
664
681
|
// src/services/WorkbenchService.ts
|
|
665
682
|
var WorkbenchService = class {
|
|
666
|
-
constructor() {
|
|
683
|
+
constructor(dependencies = {}) {
|
|
667
684
|
this._activeToolId = null;
|
|
668
685
|
this.guards = [];
|
|
669
|
-
|
|
670
|
-
|
|
686
|
+
this.eventBus = dependencies.eventBus;
|
|
687
|
+
this.toolRegistry = dependencies.toolRegistry;
|
|
688
|
+
this.sessionService = dependencies.sessionService;
|
|
689
|
+
}
|
|
690
|
+
init(context) {
|
|
691
|
+
var _a, _b, _c;
|
|
692
|
+
(_a = this.eventBus) != null ? _a : this.eventBus = context.eventBus;
|
|
693
|
+
(_b = this.toolRegistry) != null ? _b : this.toolRegistry = context.get(TOOL_REGISTRY_SERVICE);
|
|
694
|
+
(_c = this.sessionService) != null ? _c : this.sessionService = context.get(TOOL_SESSION_SERVICE);
|
|
695
|
+
if (!this.eventBus) {
|
|
696
|
+
throw new Error("WorkbenchService requires EventBus.");
|
|
697
|
+
}
|
|
698
|
+
if (!this.toolRegistry) {
|
|
699
|
+
throw new Error("WorkbenchService requires ToolRegistryService.");
|
|
700
|
+
}
|
|
701
|
+
if (!this.sessionService) {
|
|
702
|
+
throw new Error("WorkbenchService requires ToolSessionService.");
|
|
703
|
+
}
|
|
671
704
|
}
|
|
672
705
|
dispose() {
|
|
673
706
|
this.guards = [];
|
|
@@ -703,11 +736,14 @@ var WorkbenchService = class {
|
|
|
703
736
|
return true;
|
|
704
737
|
}
|
|
705
738
|
async switchTool(id, options) {
|
|
706
|
-
var _a
|
|
739
|
+
var _a;
|
|
740
|
+
const eventBus = this.getEventBus();
|
|
741
|
+
const toolRegistry = this.getToolRegistry();
|
|
742
|
+
const sessionService = this.getSessionService();
|
|
707
743
|
if (this._activeToolId === id) {
|
|
708
744
|
return { ok: true, from: this._activeToolId, to: id };
|
|
709
745
|
}
|
|
710
|
-
if (id &&
|
|
746
|
+
if (id && !toolRegistry.hasTool(id)) {
|
|
711
747
|
return {
|
|
712
748
|
ok: false,
|
|
713
749
|
from: this._activeToolId,
|
|
@@ -722,7 +758,7 @@ var WorkbenchService = class {
|
|
|
722
758
|
};
|
|
723
759
|
const guardAllowed = await this.runGuards(context);
|
|
724
760
|
if (!guardAllowed) {
|
|
725
|
-
|
|
761
|
+
eventBus.emit("tool:switch:blocked", {
|
|
726
762
|
...context,
|
|
727
763
|
reason: "blocked-by-guard"
|
|
728
764
|
});
|
|
@@ -733,12 +769,10 @@ var WorkbenchService = class {
|
|
|
733
769
|
reason: "blocked-by-guard"
|
|
734
770
|
};
|
|
735
771
|
}
|
|
736
|
-
if (context.from
|
|
737
|
-
const leaveResult = await
|
|
738
|
-
context.from
|
|
739
|
-
);
|
|
772
|
+
if (context.from) {
|
|
773
|
+
const leaveResult = await sessionService.handleBeforeLeave(context.from);
|
|
740
774
|
if (leaveResult.decision === "blocked") {
|
|
741
|
-
|
|
775
|
+
eventBus.emit("tool:switch:blocked", {
|
|
742
776
|
...context,
|
|
743
777
|
reason: leaveResult.reason || "session-blocked"
|
|
744
778
|
});
|
|
@@ -749,19 +783,19 @@ var WorkbenchService = class {
|
|
|
749
783
|
reason: leaveResult.reason || "session-blocked"
|
|
750
784
|
};
|
|
751
785
|
}
|
|
752
|
-
|
|
786
|
+
sessionService.deactivateSession(context.from);
|
|
753
787
|
}
|
|
754
|
-
if (id
|
|
755
|
-
const tool =
|
|
756
|
-
if ((tool == null ? void 0 : tool.interaction) === "session" && ((
|
|
757
|
-
await
|
|
788
|
+
if (id) {
|
|
789
|
+
const tool = toolRegistry.getTool(id);
|
|
790
|
+
if ((tool == null ? void 0 : tool.interaction) === "session" && ((_a = tool.session) == null ? void 0 : _a.autoBegin) !== false) {
|
|
791
|
+
await sessionService.begin(id);
|
|
758
792
|
}
|
|
759
793
|
}
|
|
760
794
|
const previous = this._activeToolId;
|
|
761
795
|
this._activeToolId = id;
|
|
762
796
|
const reason = options == null ? void 0 : options.reason;
|
|
763
|
-
|
|
764
|
-
|
|
797
|
+
eventBus.emit("tool:activated", { id, previous, reason });
|
|
798
|
+
eventBus.emit("tool:switch", { from: previous, to: id, reason });
|
|
765
799
|
return { ok: true, from: previous, to: id };
|
|
766
800
|
}
|
|
767
801
|
async activate(id) {
|
|
@@ -770,6 +804,147 @@ var WorkbenchService = class {
|
|
|
770
804
|
async deactivate() {
|
|
771
805
|
return await this.switchTool(null, { reason: "deactivate" });
|
|
772
806
|
}
|
|
807
|
+
getEventBus() {
|
|
808
|
+
if (!this.eventBus) {
|
|
809
|
+
throw new Error("WorkbenchService is not initialized.");
|
|
810
|
+
}
|
|
811
|
+
return this.eventBus;
|
|
812
|
+
}
|
|
813
|
+
getToolRegistry() {
|
|
814
|
+
if (!this.toolRegistry) {
|
|
815
|
+
throw new Error("WorkbenchService is not initialized.");
|
|
816
|
+
}
|
|
817
|
+
return this.toolRegistry;
|
|
818
|
+
}
|
|
819
|
+
getSessionService() {
|
|
820
|
+
if (!this.sessionService) {
|
|
821
|
+
throw new Error("WorkbenchService is not initialized.");
|
|
822
|
+
}
|
|
823
|
+
return this.sessionService;
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
// src/extension.ts
|
|
828
|
+
var ExtensionRegistry = class extends Map {
|
|
829
|
+
};
|
|
830
|
+
var ExtensionManager = class {
|
|
831
|
+
constructor(context) {
|
|
832
|
+
this.extensionRegistry = new ExtensionRegistry();
|
|
833
|
+
this.extensionDisposables = /* @__PURE__ */ new Map();
|
|
834
|
+
this.context = context;
|
|
835
|
+
}
|
|
836
|
+
register(extension) {
|
|
837
|
+
if (this.extensionRegistry.has(extension.id)) {
|
|
838
|
+
console.warn(
|
|
839
|
+
`Plugin "${extension.id}" already registered. It will be overwritten.`
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
this.extensionDisposables.set(extension.id, []);
|
|
843
|
+
const disposables = this.extensionDisposables.get(extension.id);
|
|
844
|
+
if (extension.contribute) {
|
|
845
|
+
for (const [pointId, items] of Object.entries(extension.contribute())) {
|
|
846
|
+
if (Array.isArray(items)) {
|
|
847
|
+
items.forEach((item, index) => {
|
|
848
|
+
const contributionId = item.id || (item.command ? item.command : `${extension.id}.${pointId}.${index}`);
|
|
849
|
+
const contribution = {
|
|
850
|
+
id: contributionId,
|
|
851
|
+
metadata: {
|
|
852
|
+
extensionId: extension.id,
|
|
853
|
+
...item == null ? void 0 : item.metadata
|
|
854
|
+
},
|
|
855
|
+
data: item
|
|
856
|
+
};
|
|
857
|
+
const disposable = this.context.contributions.register(
|
|
858
|
+
pointId,
|
|
859
|
+
contribution
|
|
860
|
+
);
|
|
861
|
+
disposables.push(disposable);
|
|
862
|
+
const dispose = this.collectContribution(pointId, contribution);
|
|
863
|
+
if (dispose) {
|
|
864
|
+
disposables.push(dispose);
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
try {
|
|
871
|
+
this.extensionRegistry.set(extension.id, extension);
|
|
872
|
+
this.context.eventBus.emit("extension:register", extension);
|
|
873
|
+
} catch (error) {
|
|
874
|
+
console.error(
|
|
875
|
+
`Error in onCreate hook for plugin "${extension.id}":`,
|
|
876
|
+
error
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
extension.activate(this.context);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
console.error(
|
|
883
|
+
`Error in onActivate hook for plugin "${extension.id}":`,
|
|
884
|
+
error
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
console.log(`Plugin "${extension.id}" registered successfully`);
|
|
888
|
+
}
|
|
889
|
+
collectContribution(pointId, item) {
|
|
890
|
+
if (pointId === ContributionPointIds.CONFIGURATIONS) {
|
|
891
|
+
const configService = this.context.services.get(
|
|
892
|
+
CONFIGURATION_SERVICE
|
|
893
|
+
);
|
|
894
|
+
configService == null ? void 0 : configService.initializeDefaults([item.data]);
|
|
895
|
+
}
|
|
896
|
+
if (pointId === ContributionPointIds.COMMANDS && item.data.handler) {
|
|
897
|
+
const commandService = this.context.services.get(COMMAND_SERVICE);
|
|
898
|
+
return commandService.registerCommand(item.id, item.data.handler);
|
|
899
|
+
}
|
|
900
|
+
if (pointId === ContributionPointIds.TOOLS) {
|
|
901
|
+
const toolRegistry = this.context.services.get(
|
|
902
|
+
TOOL_REGISTRY_SERVICE
|
|
903
|
+
);
|
|
904
|
+
if (!toolRegistry) return;
|
|
905
|
+
return toolRegistry.registerTool(item.data);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
unregister(name) {
|
|
909
|
+
const extension = this.extensionRegistry.get(name);
|
|
910
|
+
if (!extension) {
|
|
911
|
+
console.warn(`Plugin "${name}" not found.`);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
try {
|
|
915
|
+
extension.deactivate(this.context);
|
|
916
|
+
} catch (error) {
|
|
917
|
+
console.error(`Error in deactivate for plugin "${name}":`, error);
|
|
918
|
+
}
|
|
919
|
+
const disposables = this.extensionDisposables.get(name);
|
|
920
|
+
if (disposables) {
|
|
921
|
+
disposables.forEach((d) => d.dispose());
|
|
922
|
+
this.extensionDisposables.delete(name);
|
|
923
|
+
}
|
|
924
|
+
this.extensionRegistry.delete(name);
|
|
925
|
+
console.log(`Plugin "${name}" unregistered`);
|
|
926
|
+
return true;
|
|
927
|
+
}
|
|
928
|
+
enable(name) {
|
|
929
|
+
const extension = this.extensionRegistry.get(name);
|
|
930
|
+
if (!extension) {
|
|
931
|
+
console.warn(`Plugin "${name}" not found.`);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
disable(name) {
|
|
936
|
+
const extension = this.extensionRegistry.get(name);
|
|
937
|
+
if (!extension) {
|
|
938
|
+
console.warn(`Plugin "${name}" not found.`);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
update() {
|
|
943
|
+
}
|
|
944
|
+
destroy() {
|
|
945
|
+
const extensionNames = Array.from(this.extensionRegistry.keys());
|
|
946
|
+
extensionNames.forEach((name) => this.unregister(name));
|
|
947
|
+
}
|
|
773
948
|
};
|
|
774
949
|
|
|
775
950
|
// src/index.ts
|
|
@@ -777,27 +952,37 @@ var Pooder = class {
|
|
|
777
952
|
constructor() {
|
|
778
953
|
this.eventBus = new event_default();
|
|
779
954
|
this.services = new ServiceRegistry();
|
|
955
|
+
this.serviceContext = {
|
|
956
|
+
eventBus: this.eventBus,
|
|
957
|
+
get: (identifier) => this.services.get(identifier),
|
|
958
|
+
getOrThrow: (identifier, errorMessage) => this.services.getOrThrow(identifier, errorMessage),
|
|
959
|
+
has: (identifier) => this.services.has(identifier)
|
|
960
|
+
};
|
|
780
961
|
this.contributions = new ContributionRegistry();
|
|
781
962
|
this.initDefaultContributionPoints();
|
|
782
963
|
const commandService = new CommandService();
|
|
783
|
-
this.registerService(commandService,
|
|
964
|
+
this.registerService(commandService, CORE_SERVICE_TOKENS.COMMAND);
|
|
784
965
|
const configurationService = new ConfigurationService();
|
|
785
|
-
this.registerService(configurationService,
|
|
966
|
+
this.registerService(configurationService, CORE_SERVICE_TOKENS.CONFIGURATION);
|
|
786
967
|
const toolRegistryService = new ToolRegistryService();
|
|
787
|
-
this.registerService(toolRegistryService,
|
|
788
|
-
const toolSessionService = new ToolSessionService(
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
workbenchService
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
968
|
+
this.registerService(toolRegistryService, CORE_SERVICE_TOKENS.TOOL_REGISTRY);
|
|
969
|
+
const toolSessionService = new ToolSessionService({
|
|
970
|
+
commandService,
|
|
971
|
+
toolRegistry: toolRegistryService
|
|
972
|
+
});
|
|
973
|
+
this.registerService(toolSessionService, CORE_SERVICE_TOKENS.TOOL_SESSION);
|
|
974
|
+
const workbenchService = new WorkbenchService({
|
|
975
|
+
eventBus: this.eventBus,
|
|
976
|
+
toolRegistry: toolRegistryService,
|
|
977
|
+
sessionService: toolSessionService
|
|
978
|
+
});
|
|
979
|
+
this.registerService(workbenchService, CORE_SERVICE_TOKENS.WORKBENCH);
|
|
797
980
|
const context = {
|
|
798
981
|
eventBus: this.eventBus,
|
|
799
982
|
services: {
|
|
800
|
-
get: (
|
|
983
|
+
get: (identifier) => this.services.get(identifier),
|
|
984
|
+
getOrThrow: (identifier, errorMessage) => this.services.getOrThrow(identifier, errorMessage),
|
|
985
|
+
has: (identifier) => this.services.has(identifier)
|
|
801
986
|
},
|
|
802
987
|
contributions: {
|
|
803
988
|
get: (pointId) => this.getContributions(pointId),
|
|
@@ -829,38 +1014,102 @@ var Pooder = class {
|
|
|
829
1014
|
});
|
|
830
1015
|
}
|
|
831
1016
|
// --- Service Management ---
|
|
832
|
-
registerService(service,
|
|
833
|
-
|
|
834
|
-
const serviceId =
|
|
1017
|
+
registerService(service, identifier, options = {}) {
|
|
1018
|
+
const serviceIdentifier = this.resolveServiceIdentifier(service, identifier);
|
|
1019
|
+
const serviceId = this.getServiceLabel(serviceIdentifier);
|
|
835
1020
|
try {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1021
|
+
const initResult = this.invokeServiceHook(service, "init");
|
|
1022
|
+
if (this.isPromiseLike(initResult)) {
|
|
1023
|
+
throw new Error(
|
|
1024
|
+
`Service "${serviceId}" init() is async. Use registerServiceAsync() instead.`
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
this.services.register(serviceIdentifier, service, options);
|
|
1028
|
+
this.eventBus.emit("service:register", service, { id: serviceId });
|
|
1029
|
+
return true;
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
console.error(`Error initializing service ${serviceId}:`, error);
|
|
839
1032
|
return false;
|
|
840
1033
|
}
|
|
841
|
-
|
|
842
|
-
|
|
1034
|
+
}
|
|
1035
|
+
async registerServiceAsync(service, identifier, options = {}) {
|
|
1036
|
+
const serviceIdentifier = this.resolveServiceIdentifier(service, identifier);
|
|
1037
|
+
const serviceId = this.getServiceLabel(serviceIdentifier);
|
|
1038
|
+
try {
|
|
1039
|
+
await this.invokeServiceHookAsync(service, "init");
|
|
1040
|
+
this.services.register(serviceIdentifier, service, options);
|
|
1041
|
+
this.eventBus.emit("service:register", service, { id: serviceId });
|
|
1042
|
+
return true;
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
console.error(`Error initializing service ${serviceId}:`, error);
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
unregisterService(serviceOrIdentifier, id) {
|
|
1049
|
+
const resolvedIdentifier = this.resolveUnregisterIdentifier(
|
|
1050
|
+
serviceOrIdentifier,
|
|
1051
|
+
id
|
|
1052
|
+
);
|
|
1053
|
+
const serviceId = this.getServiceLabel(resolvedIdentifier);
|
|
1054
|
+
const registeredService = this.services.get(resolvedIdentifier);
|
|
1055
|
+
if (!registeredService) {
|
|
1056
|
+
console.warn(`Service ${serviceId} is not registered.`);
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
try {
|
|
1060
|
+
const disposeResult = this.invokeServiceHook(registeredService, "dispose");
|
|
1061
|
+
if (this.isPromiseLike(disposeResult)) {
|
|
1062
|
+
throw new Error(
|
|
1063
|
+
`Service "${serviceId}" dispose() is async. Use unregisterServiceAsync() instead.`
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
console.error(`Error disposing service ${serviceId}:`, error);
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
this.services.delete(resolvedIdentifier);
|
|
1071
|
+
this.eventBus.emit("service:unregister", registeredService, { id: serviceId });
|
|
843
1072
|
return true;
|
|
844
1073
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1074
|
+
async unregisterServiceAsync(serviceOrIdentifier, id) {
|
|
1075
|
+
const resolvedIdentifier = this.resolveUnregisterIdentifier(
|
|
1076
|
+
serviceOrIdentifier,
|
|
1077
|
+
id
|
|
1078
|
+
);
|
|
1079
|
+
const serviceId = this.getServiceLabel(resolvedIdentifier);
|
|
1080
|
+
const registeredService = this.services.get(resolvedIdentifier);
|
|
1081
|
+
if (!registeredService) {
|
|
849
1082
|
console.warn(`Service ${serviceId} is not registered.`);
|
|
850
1083
|
return true;
|
|
851
1084
|
}
|
|
852
1085
|
try {
|
|
853
|
-
(
|
|
854
|
-
} catch (
|
|
855
|
-
console.error(`Error disposing service ${serviceId}:`,
|
|
1086
|
+
await this.invokeServiceHookAsync(registeredService, "dispose");
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
console.error(`Error disposing service ${serviceId}:`, error);
|
|
856
1089
|
return false;
|
|
857
1090
|
}
|
|
858
|
-
this.services.delete(
|
|
859
|
-
this.eventBus.emit("service:unregister",
|
|
1091
|
+
this.services.delete(resolvedIdentifier);
|
|
1092
|
+
this.eventBus.emit("service:unregister", registeredService, { id: serviceId });
|
|
860
1093
|
return true;
|
|
861
1094
|
}
|
|
862
|
-
getService(
|
|
863
|
-
return this.services.get(
|
|
1095
|
+
getService(identifier) {
|
|
1096
|
+
return this.services.get(identifier);
|
|
1097
|
+
}
|
|
1098
|
+
getServiceOrThrow(identifier, errorMessage) {
|
|
1099
|
+
return this.services.getOrThrow(identifier, errorMessage);
|
|
1100
|
+
}
|
|
1101
|
+
hasService(identifier) {
|
|
1102
|
+
return this.services.has(identifier);
|
|
1103
|
+
}
|
|
1104
|
+
async dispose() {
|
|
1105
|
+
var _a;
|
|
1106
|
+
this.extensionManager.destroy();
|
|
1107
|
+
const registrations = this.services.list().slice().reverse();
|
|
1108
|
+
for (const item of registrations) {
|
|
1109
|
+
const identifier = (_a = item.token) != null ? _a : item.id;
|
|
1110
|
+
await this.unregisterServiceAsync(identifier);
|
|
1111
|
+
}
|
|
1112
|
+
this.services.clear();
|
|
864
1113
|
}
|
|
865
1114
|
// --- Contribution Management ---
|
|
866
1115
|
registerContributionPoint(point) {
|
|
@@ -875,9 +1124,40 @@ var Pooder = class {
|
|
|
875
1124
|
getContributions(pointId) {
|
|
876
1125
|
return this.contributions.get(pointId);
|
|
877
1126
|
}
|
|
1127
|
+
resolveServiceIdentifier(service, identifier) {
|
|
1128
|
+
return identifier != null ? identifier : service.constructor.name;
|
|
1129
|
+
}
|
|
1130
|
+
resolveUnregisterIdentifier(serviceOrIdentifier, id) {
|
|
1131
|
+
if (typeof serviceOrIdentifier === "string" || isServiceToken(serviceOrIdentifier)) {
|
|
1132
|
+
return serviceOrIdentifier;
|
|
1133
|
+
}
|
|
1134
|
+
return id != null ? id : serviceOrIdentifier.constructor.name;
|
|
1135
|
+
}
|
|
1136
|
+
getServiceLabel(identifier) {
|
|
1137
|
+
if (typeof identifier === "string") {
|
|
1138
|
+
return identifier;
|
|
1139
|
+
}
|
|
1140
|
+
return identifier.name;
|
|
1141
|
+
}
|
|
1142
|
+
invokeServiceHook(service, hook) {
|
|
1143
|
+
const handler = service[hook];
|
|
1144
|
+
if (!handler) {
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
return handler.call(service, this.serviceContext);
|
|
1148
|
+
}
|
|
1149
|
+
async invokeServiceHookAsync(service, hook) {
|
|
1150
|
+
await this.invokeServiceHook(service, hook);
|
|
1151
|
+
}
|
|
1152
|
+
isPromiseLike(value) {
|
|
1153
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
1154
|
+
}
|
|
878
1155
|
};
|
|
879
1156
|
// Annotate the CommonJS export names for ESM import in node:
|
|
880
1157
|
0 && (module.exports = {
|
|
1158
|
+
COMMAND_SERVICE,
|
|
1159
|
+
CONFIGURATION_SERVICE,
|
|
1160
|
+
CORE_SERVICE_TOKENS,
|
|
881
1161
|
CommandService,
|
|
882
1162
|
ConfigurationService,
|
|
883
1163
|
ContributionPointIds,
|
|
@@ -887,7 +1167,12 @@ var Pooder = class {
|
|
|
887
1167
|
ExtensionRegistry,
|
|
888
1168
|
Pooder,
|
|
889
1169
|
ServiceRegistry,
|
|
1170
|
+
TOOL_REGISTRY_SERVICE,
|
|
1171
|
+
TOOL_SESSION_SERVICE,
|
|
890
1172
|
ToolRegistryService,
|
|
891
1173
|
ToolSessionService,
|
|
892
|
-
|
|
1174
|
+
WORKBENCH_SERVICE,
|
|
1175
|
+
WorkbenchService,
|
|
1176
|
+
createServiceToken,
|
|
1177
|
+
isServiceToken
|
|
893
1178
|
});
|