@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/dist/index.mjs CHANGED
@@ -1,20 +1,108 @@
1
1
  // src/service.ts
2
+ function createServiceToken(name) {
3
+ if (!name) {
4
+ throw new Error("Service token name is required.");
5
+ }
6
+ return Object.freeze({
7
+ kind: "service-token",
8
+ key: Symbol(name),
9
+ name
10
+ });
11
+ }
12
+ function isServiceToken(identifier) {
13
+ return typeof identifier === "object" && identifier !== null && "kind" in identifier && identifier.kind === "service-token";
14
+ }
2
15
  var ServiceRegistry = class {
3
16
  constructor() {
4
- this.services = /* @__PURE__ */ new Map();
5
- }
6
- register(name, service) {
7
- this.services.set(name, service);
17
+ this.servicesByName = /* @__PURE__ */ new Map();
18
+ this.servicesByToken = /* @__PURE__ */ new Map();
19
+ this.registrationOrder = [];
20
+ }
21
+ register(identifier, service, options = {}) {
22
+ const normalized = this.normalizeIdentifier(identifier);
23
+ const existing = this.findEntry(normalized);
24
+ if (existing && !options.allowOverride) {
25
+ throw new Error(`Service "${normalized.name}" is already registered.`);
26
+ }
27
+ if (existing) {
28
+ this.removeEntry(existing);
29
+ }
30
+ const entry = {
31
+ token: normalized.token,
32
+ name: normalized.name,
33
+ service
34
+ };
35
+ this.servicesByName.set(entry.name, entry);
36
+ if (entry.token) {
37
+ this.servicesByToken.set(entry.token.key, entry);
38
+ }
39
+ this.registrationOrder.push(entry);
8
40
  return service;
9
41
  }
10
- get(serviceName) {
11
- return this.services.get(serviceName);
42
+ get(identifier) {
43
+ const normalized = this.normalizeIdentifier(identifier);
44
+ const entry = this.findEntry(normalized);
45
+ return entry == null ? void 0 : entry.service;
12
46
  }
13
- has(serviceName) {
14
- return this.services.has(serviceName);
47
+ getOrThrow(identifier, errorMessage) {
48
+ const service = this.get(identifier);
49
+ if (service) {
50
+ return service;
51
+ }
52
+ const normalized = this.normalizeIdentifier(identifier);
53
+ throw new Error(errorMessage != null ? errorMessage : `Service "${normalized.name}" not found.`);
54
+ }
55
+ has(identifier) {
56
+ const normalized = this.normalizeIdentifier(identifier);
57
+ return Boolean(this.findEntry(normalized));
58
+ }
59
+ delete(identifier) {
60
+ const normalized = this.normalizeIdentifier(identifier);
61
+ const entry = this.findEntry(normalized);
62
+ if (!entry) {
63
+ return false;
64
+ }
65
+ this.removeEntry(entry);
66
+ return true;
15
67
  }
16
- delete(serviceName) {
17
- this.services.delete(serviceName);
68
+ list() {
69
+ return this.registrationOrder.map((entry) => ({
70
+ id: entry.name,
71
+ token: entry.token,
72
+ service: entry.service
73
+ }));
74
+ }
75
+ clear() {
76
+ this.servicesByName.clear();
77
+ this.servicesByToken.clear();
78
+ this.registrationOrder.length = 0;
79
+ }
80
+ findEntry(identifier) {
81
+ var _a;
82
+ if (identifier.token) {
83
+ return (_a = this.servicesByToken.get(identifier.token.key)) != null ? _a : this.servicesByName.get(identifier.name);
84
+ }
85
+ return this.servicesByName.get(identifier.name);
86
+ }
87
+ normalizeIdentifier(identifier) {
88
+ if (isServiceToken(identifier)) {
89
+ return { token: identifier, name: identifier.name };
90
+ }
91
+ const name = identifier.trim();
92
+ if (!name) {
93
+ throw new Error("Service identifier must be a non-empty string.");
94
+ }
95
+ return { name };
96
+ }
97
+ removeEntry(entry) {
98
+ this.servicesByName.delete(entry.name);
99
+ if (entry.token) {
100
+ this.servicesByToken.delete(entry.token.key);
101
+ }
102
+ const index = this.registrationOrder.lastIndexOf(entry);
103
+ if (index >= 0) {
104
+ this.registrationOrder.splice(index, 1);
105
+ }
18
106
  }
19
107
  };
20
108
 
@@ -172,127 +260,6 @@ var ContributionRegistry = class {
172
260
  }
173
261
  };
174
262
 
175
- // src/extension.ts
176
- var ExtensionRegistry = class extends Map {
177
- };
178
- var ExtensionManager = class {
179
- constructor(context) {
180
- this.extensionRegistry = new ExtensionRegistry();
181
- this.extensionDisposables = /* @__PURE__ */ new Map();
182
- this.context = context;
183
- }
184
- register(extension) {
185
- if (this.extensionRegistry.has(extension.id)) {
186
- console.warn(
187
- `Plugin "${extension.id}" already registered. It will be overwritten.`
188
- );
189
- }
190
- this.extensionDisposables.set(extension.id, []);
191
- const disposables = this.extensionDisposables.get(extension.id);
192
- if (extension.contribute) {
193
- for (const [pointId, items] of Object.entries(extension.contribute())) {
194
- if (Array.isArray(items)) {
195
- items.forEach((item, index) => {
196
- const contributionId = item.id || (item.command ? item.command : `${extension.id}.${pointId}.${index}`);
197
- const contribution = {
198
- id: contributionId,
199
- metadata: {
200
- extensionId: extension.id,
201
- ...item == null ? void 0 : item.metadata
202
- },
203
- data: item
204
- };
205
- const disposable = this.context.contributions.register(
206
- pointId,
207
- contribution
208
- );
209
- disposables.push(disposable);
210
- const dispose = this.collectContribution(pointId, contribution);
211
- if (dispose) {
212
- disposables.push(dispose);
213
- }
214
- });
215
- }
216
- }
217
- }
218
- try {
219
- this.extensionRegistry.set(extension.id, extension);
220
- this.context.eventBus.emit("extension:register", extension);
221
- } catch (error) {
222
- console.error(
223
- `Error in onCreate hook for plugin "${extension.id}":`,
224
- error
225
- );
226
- }
227
- try {
228
- extension.activate(this.context);
229
- } catch (error) {
230
- console.error(
231
- `Error in onActivate hook for plugin "${extension.id}":`,
232
- error
233
- );
234
- }
235
- console.log(`Plugin "${extension.id}" registered successfully`);
236
- }
237
- collectContribution(pointId, item) {
238
- if (pointId === ContributionPointIds.CONFIGURATIONS) {
239
- const configService = this.context.services.get(
240
- "ConfigurationService"
241
- );
242
- configService == null ? void 0 : configService.initializeDefaults([item.data]);
243
- }
244
- if (pointId === ContributionPointIds.COMMANDS && item.data.handler) {
245
- const commandService = this.context.services.get("CommandService");
246
- return commandService.registerCommand(item.id, item.data.handler);
247
- }
248
- if (pointId === ContributionPointIds.TOOLS) {
249
- const toolRegistry = this.context.services.get("ToolRegistryService");
250
- if (!toolRegistry) return;
251
- return toolRegistry.registerTool(item.data);
252
- }
253
- }
254
- unregister(name) {
255
- const extension = this.extensionRegistry.get(name);
256
- if (!extension) {
257
- console.warn(`Plugin "${name}" not found.`);
258
- return;
259
- }
260
- try {
261
- extension.deactivate(this.context);
262
- } catch (error) {
263
- console.error(`Error in deactivate for plugin "${name}":`, error);
264
- }
265
- const disposables = this.extensionDisposables.get(name);
266
- if (disposables) {
267
- disposables.forEach((d) => d.dispose());
268
- this.extensionDisposables.delete(name);
269
- }
270
- this.extensionRegistry.delete(name);
271
- console.log(`Plugin "${name}" unregistered`);
272
- return true;
273
- }
274
- enable(name) {
275
- const extension = this.extensionRegistry.get(name);
276
- if (!extension) {
277
- console.warn(`Plugin "${name}" not found.`);
278
- return;
279
- }
280
- }
281
- disable(name) {
282
- const extension = this.extensionRegistry.get(name);
283
- if (!extension) {
284
- console.warn(`Plugin "${name}" not found.`);
285
- return;
286
- }
287
- }
288
- update() {
289
- }
290
- destroy() {
291
- const extensionNames = Array.from(this.extensionRegistry.keys());
292
- extensionNames.forEach((name) => this.unregister(name));
293
- }
294
- };
295
-
296
263
  // src/services/CommandService.ts
297
264
  var CommandService = class {
298
265
  constructor() {
@@ -487,11 +454,42 @@ var ToolRegistryService = class {
487
454
  }
488
455
  };
489
456
 
457
+ // src/services/tokens.ts
458
+ var COMMAND_SERVICE = createServiceToken(
459
+ "CommandService"
460
+ );
461
+ var CONFIGURATION_SERVICE = createServiceToken(
462
+ "ConfigurationService"
463
+ );
464
+ var TOOL_REGISTRY_SERVICE = createServiceToken("ToolRegistryService");
465
+ var TOOL_SESSION_SERVICE = createServiceToken("ToolSessionService");
466
+ var WORKBENCH_SERVICE = createServiceToken("WorkbenchService");
467
+ var CORE_SERVICE_TOKENS = {
468
+ COMMAND: COMMAND_SERVICE,
469
+ CONFIGURATION: CONFIGURATION_SERVICE,
470
+ TOOL_REGISTRY: TOOL_REGISTRY_SERVICE,
471
+ TOOL_SESSION: TOOL_SESSION_SERVICE,
472
+ WORKBENCH: WORKBENCH_SERVICE
473
+ };
474
+
490
475
  // src/services/ToolSessionService.ts
491
476
  var ToolSessionService = class {
492
- constructor() {
477
+ constructor(dependencies = {}) {
493
478
  this.sessions = /* @__PURE__ */ new Map();
494
479
  this.dirtyTrackers = /* @__PURE__ */ new Map();
480
+ this.commandService = dependencies.commandService;
481
+ this.toolRegistry = dependencies.toolRegistry;
482
+ }
483
+ init(context) {
484
+ var _a, _b;
485
+ (_a = this.commandService) != null ? _a : this.commandService = context.get(COMMAND_SERVICE);
486
+ (_b = this.toolRegistry) != null ? _b : this.toolRegistry = context.get(TOOL_REGISTRY_SERVICE);
487
+ if (!this.commandService) {
488
+ throw new Error("ToolSessionService requires CommandService.");
489
+ }
490
+ if (!this.toolRegistry) {
491
+ throw new Error("ToolSessionService requires ToolRegistryService.");
492
+ }
495
493
  }
496
494
  setCommandService(commandService) {
497
495
  this.commandService = commandService;
@@ -541,12 +539,23 @@ var ToolSessionService = class {
541
539
  session.lastUpdatedAt = Date.now();
542
540
  }
543
541
  resolveTool(toolId) {
544
- var _a;
545
- return (_a = this.toolRegistry) == null ? void 0 : _a.getTool(toolId);
542
+ return this.getToolRegistry().getTool(toolId);
546
543
  }
547
544
  async runCommand(commandId, ...args) {
548
- if (!commandId || !this.commandService) return void 0;
549
- return await this.commandService.executeCommand(commandId, ...args);
545
+ if (!commandId) return void 0;
546
+ return await this.getCommandService().executeCommand(commandId, ...args);
547
+ }
548
+ getCommandService() {
549
+ if (!this.commandService) {
550
+ throw new Error("ToolSessionService is not initialized.");
551
+ }
552
+ return this.commandService;
553
+ }
554
+ getToolRegistry() {
555
+ if (!this.toolRegistry) {
556
+ throw new Error("ToolSessionService is not initialized.");
557
+ }
558
+ return this.toolRegistry;
550
559
  }
551
560
  async begin(toolId) {
552
561
  var _a;
@@ -626,11 +635,27 @@ var ToolSessionService = class {
626
635
 
627
636
  // src/services/WorkbenchService.ts
628
637
  var WorkbenchService = class {
629
- constructor() {
638
+ constructor(dependencies = {}) {
630
639
  this._activeToolId = null;
631
640
  this.guards = [];
632
- }
633
- init() {
641
+ this.eventBus = dependencies.eventBus;
642
+ this.toolRegistry = dependencies.toolRegistry;
643
+ this.sessionService = dependencies.sessionService;
644
+ }
645
+ init(context) {
646
+ var _a, _b, _c;
647
+ (_a = this.eventBus) != null ? _a : this.eventBus = context.eventBus;
648
+ (_b = this.toolRegistry) != null ? _b : this.toolRegistry = context.get(TOOL_REGISTRY_SERVICE);
649
+ (_c = this.sessionService) != null ? _c : this.sessionService = context.get(TOOL_SESSION_SERVICE);
650
+ if (!this.eventBus) {
651
+ throw new Error("WorkbenchService requires EventBus.");
652
+ }
653
+ if (!this.toolRegistry) {
654
+ throw new Error("WorkbenchService requires ToolRegistryService.");
655
+ }
656
+ if (!this.sessionService) {
657
+ throw new Error("WorkbenchService requires ToolSessionService.");
658
+ }
634
659
  }
635
660
  dispose() {
636
661
  this.guards = [];
@@ -666,11 +691,14 @@ var WorkbenchService = class {
666
691
  return true;
667
692
  }
668
693
  async switchTool(id, options) {
669
- var _a, _b, _c, _d, _e;
694
+ var _a;
695
+ const eventBus = this.getEventBus();
696
+ const toolRegistry = this.getToolRegistry();
697
+ const sessionService = this.getSessionService();
670
698
  if (this._activeToolId === id) {
671
699
  return { ok: true, from: this._activeToolId, to: id };
672
700
  }
673
- if (id && this.toolRegistry && !this.toolRegistry.hasTool(id)) {
701
+ if (id && !toolRegistry.hasTool(id)) {
674
702
  return {
675
703
  ok: false,
676
704
  from: this._activeToolId,
@@ -685,7 +713,7 @@ var WorkbenchService = class {
685
713
  };
686
714
  const guardAllowed = await this.runGuards(context);
687
715
  if (!guardAllowed) {
688
- (_a = this.eventBus) == null ? void 0 : _a.emit("tool:switch:blocked", {
716
+ eventBus.emit("tool:switch:blocked", {
689
717
  ...context,
690
718
  reason: "blocked-by-guard"
691
719
  });
@@ -696,12 +724,10 @@ var WorkbenchService = class {
696
724
  reason: "blocked-by-guard"
697
725
  };
698
726
  }
699
- if (context.from && this.sessionService) {
700
- const leaveResult = await this.sessionService.handleBeforeLeave(
701
- context.from
702
- );
727
+ if (context.from) {
728
+ const leaveResult = await sessionService.handleBeforeLeave(context.from);
703
729
  if (leaveResult.decision === "blocked") {
704
- (_b = this.eventBus) == null ? void 0 : _b.emit("tool:switch:blocked", {
730
+ eventBus.emit("tool:switch:blocked", {
705
731
  ...context,
706
732
  reason: leaveResult.reason || "session-blocked"
707
733
  });
@@ -712,19 +738,19 @@ var WorkbenchService = class {
712
738
  reason: leaveResult.reason || "session-blocked"
713
739
  };
714
740
  }
715
- this.sessionService.deactivateSession(context.from);
741
+ sessionService.deactivateSession(context.from);
716
742
  }
717
- if (id && this.sessionService && this.toolRegistry) {
718
- const tool = this.toolRegistry.getTool(id);
719
- if ((tool == null ? void 0 : tool.interaction) === "session" && ((_c = tool.session) == null ? void 0 : _c.autoBegin) !== false) {
720
- await this.sessionService.begin(id);
743
+ if (id) {
744
+ const tool = toolRegistry.getTool(id);
745
+ if ((tool == null ? void 0 : tool.interaction) === "session" && ((_a = tool.session) == null ? void 0 : _a.autoBegin) !== false) {
746
+ await sessionService.begin(id);
721
747
  }
722
748
  }
723
749
  const previous = this._activeToolId;
724
750
  this._activeToolId = id;
725
751
  const reason = options == null ? void 0 : options.reason;
726
- (_d = this.eventBus) == null ? void 0 : _d.emit("tool:activated", { id, previous, reason });
727
- (_e = this.eventBus) == null ? void 0 : _e.emit("tool:switch", { from: previous, to: id, reason });
752
+ eventBus.emit("tool:activated", { id, previous, reason });
753
+ eventBus.emit("tool:switch", { from: previous, to: id, reason });
728
754
  return { ok: true, from: previous, to: id };
729
755
  }
730
756
  async activate(id) {
@@ -733,6 +759,147 @@ var WorkbenchService = class {
733
759
  async deactivate() {
734
760
  return await this.switchTool(null, { reason: "deactivate" });
735
761
  }
762
+ getEventBus() {
763
+ if (!this.eventBus) {
764
+ throw new Error("WorkbenchService is not initialized.");
765
+ }
766
+ return this.eventBus;
767
+ }
768
+ getToolRegistry() {
769
+ if (!this.toolRegistry) {
770
+ throw new Error("WorkbenchService is not initialized.");
771
+ }
772
+ return this.toolRegistry;
773
+ }
774
+ getSessionService() {
775
+ if (!this.sessionService) {
776
+ throw new Error("WorkbenchService is not initialized.");
777
+ }
778
+ return this.sessionService;
779
+ }
780
+ };
781
+
782
+ // src/extension.ts
783
+ var ExtensionRegistry = class extends Map {
784
+ };
785
+ var ExtensionManager = class {
786
+ constructor(context) {
787
+ this.extensionRegistry = new ExtensionRegistry();
788
+ this.extensionDisposables = /* @__PURE__ */ new Map();
789
+ this.context = context;
790
+ }
791
+ register(extension) {
792
+ if (this.extensionRegistry.has(extension.id)) {
793
+ console.warn(
794
+ `Plugin "${extension.id}" already registered. It will be overwritten.`
795
+ );
796
+ }
797
+ this.extensionDisposables.set(extension.id, []);
798
+ const disposables = this.extensionDisposables.get(extension.id);
799
+ if (extension.contribute) {
800
+ for (const [pointId, items] of Object.entries(extension.contribute())) {
801
+ if (Array.isArray(items)) {
802
+ items.forEach((item, index) => {
803
+ const contributionId = item.id || (item.command ? item.command : `${extension.id}.${pointId}.${index}`);
804
+ const contribution = {
805
+ id: contributionId,
806
+ metadata: {
807
+ extensionId: extension.id,
808
+ ...item == null ? void 0 : item.metadata
809
+ },
810
+ data: item
811
+ };
812
+ const disposable = this.context.contributions.register(
813
+ pointId,
814
+ contribution
815
+ );
816
+ disposables.push(disposable);
817
+ const dispose = this.collectContribution(pointId, contribution);
818
+ if (dispose) {
819
+ disposables.push(dispose);
820
+ }
821
+ });
822
+ }
823
+ }
824
+ }
825
+ try {
826
+ this.extensionRegistry.set(extension.id, extension);
827
+ this.context.eventBus.emit("extension:register", extension);
828
+ } catch (error) {
829
+ console.error(
830
+ `Error in onCreate hook for plugin "${extension.id}":`,
831
+ error
832
+ );
833
+ }
834
+ try {
835
+ extension.activate(this.context);
836
+ } catch (error) {
837
+ console.error(
838
+ `Error in onActivate hook for plugin "${extension.id}":`,
839
+ error
840
+ );
841
+ }
842
+ console.log(`Plugin "${extension.id}" registered successfully`);
843
+ }
844
+ collectContribution(pointId, item) {
845
+ if (pointId === ContributionPointIds.CONFIGURATIONS) {
846
+ const configService = this.context.services.get(
847
+ CONFIGURATION_SERVICE
848
+ );
849
+ configService == null ? void 0 : configService.initializeDefaults([item.data]);
850
+ }
851
+ if (pointId === ContributionPointIds.COMMANDS && item.data.handler) {
852
+ const commandService = this.context.services.get(COMMAND_SERVICE);
853
+ return commandService.registerCommand(item.id, item.data.handler);
854
+ }
855
+ if (pointId === ContributionPointIds.TOOLS) {
856
+ const toolRegistry = this.context.services.get(
857
+ TOOL_REGISTRY_SERVICE
858
+ );
859
+ if (!toolRegistry) return;
860
+ return toolRegistry.registerTool(item.data);
861
+ }
862
+ }
863
+ unregister(name) {
864
+ const extension = this.extensionRegistry.get(name);
865
+ if (!extension) {
866
+ console.warn(`Plugin "${name}" not found.`);
867
+ return;
868
+ }
869
+ try {
870
+ extension.deactivate(this.context);
871
+ } catch (error) {
872
+ console.error(`Error in deactivate for plugin "${name}":`, error);
873
+ }
874
+ const disposables = this.extensionDisposables.get(name);
875
+ if (disposables) {
876
+ disposables.forEach((d) => d.dispose());
877
+ this.extensionDisposables.delete(name);
878
+ }
879
+ this.extensionRegistry.delete(name);
880
+ console.log(`Plugin "${name}" unregistered`);
881
+ return true;
882
+ }
883
+ enable(name) {
884
+ const extension = this.extensionRegistry.get(name);
885
+ if (!extension) {
886
+ console.warn(`Plugin "${name}" not found.`);
887
+ return;
888
+ }
889
+ }
890
+ disable(name) {
891
+ const extension = this.extensionRegistry.get(name);
892
+ if (!extension) {
893
+ console.warn(`Plugin "${name}" not found.`);
894
+ return;
895
+ }
896
+ }
897
+ update() {
898
+ }
899
+ destroy() {
900
+ const extensionNames = Array.from(this.extensionRegistry.keys());
901
+ extensionNames.forEach((name) => this.unregister(name));
902
+ }
736
903
  };
737
904
 
738
905
  // src/index.ts
@@ -740,27 +907,37 @@ var Pooder = class {
740
907
  constructor() {
741
908
  this.eventBus = new event_default();
742
909
  this.services = new ServiceRegistry();
910
+ this.serviceContext = {
911
+ eventBus: this.eventBus,
912
+ get: (identifier) => this.services.get(identifier),
913
+ getOrThrow: (identifier, errorMessage) => this.services.getOrThrow(identifier, errorMessage),
914
+ has: (identifier) => this.services.has(identifier)
915
+ };
743
916
  this.contributions = new ContributionRegistry();
744
917
  this.initDefaultContributionPoints();
745
918
  const commandService = new CommandService();
746
- this.registerService(commandService, "CommandService");
919
+ this.registerService(commandService, CORE_SERVICE_TOKENS.COMMAND);
747
920
  const configurationService = new ConfigurationService();
748
- this.registerService(configurationService, "ConfigurationService");
921
+ this.registerService(configurationService, CORE_SERVICE_TOKENS.CONFIGURATION);
749
922
  const toolRegistryService = new ToolRegistryService();
750
- this.registerService(toolRegistryService, "ToolRegistryService");
751
- const toolSessionService = new ToolSessionService();
752
- toolSessionService.setCommandService(commandService);
753
- toolSessionService.setToolRegistry(toolRegistryService);
754
- this.registerService(toolSessionService, "ToolSessionService");
755
- const workbenchService = new WorkbenchService();
756
- workbenchService.setEventBus(this.eventBus);
757
- workbenchService.setToolRegistry(toolRegistryService);
758
- workbenchService.setToolSessionService(toolSessionService);
759
- this.registerService(workbenchService, "WorkbenchService");
923
+ this.registerService(toolRegistryService, CORE_SERVICE_TOKENS.TOOL_REGISTRY);
924
+ const toolSessionService = new ToolSessionService({
925
+ commandService,
926
+ toolRegistry: toolRegistryService
927
+ });
928
+ this.registerService(toolSessionService, CORE_SERVICE_TOKENS.TOOL_SESSION);
929
+ const workbenchService = new WorkbenchService({
930
+ eventBus: this.eventBus,
931
+ toolRegistry: toolRegistryService,
932
+ sessionService: toolSessionService
933
+ });
934
+ this.registerService(workbenchService, CORE_SERVICE_TOKENS.WORKBENCH);
760
935
  const context = {
761
936
  eventBus: this.eventBus,
762
937
  services: {
763
- get: (serviceName) => this.services.get(serviceName)
938
+ get: (identifier) => this.services.get(identifier),
939
+ getOrThrow: (identifier, errorMessage) => this.services.getOrThrow(identifier, errorMessage),
940
+ has: (identifier) => this.services.has(identifier)
764
941
  },
765
942
  contributions: {
766
943
  get: (pointId) => this.getContributions(pointId),
@@ -792,38 +969,102 @@ var Pooder = class {
792
969
  });
793
970
  }
794
971
  // --- Service Management ---
795
- registerService(service, id) {
796
- var _a;
797
- const serviceId = id || service.constructor.name;
972
+ registerService(service, identifier, options = {}) {
973
+ const serviceIdentifier = this.resolveServiceIdentifier(service, identifier);
974
+ const serviceId = this.getServiceLabel(serviceIdentifier);
798
975
  try {
799
- (_a = service == null ? void 0 : service.init) == null ? void 0 : _a.call(service);
800
- } catch (e) {
801
- console.error(`Error initializing service ${serviceId}:`, e);
976
+ const initResult = this.invokeServiceHook(service, "init");
977
+ if (this.isPromiseLike(initResult)) {
978
+ throw new Error(
979
+ `Service "${serviceId}" init() is async. Use registerServiceAsync() instead.`
980
+ );
981
+ }
982
+ this.services.register(serviceIdentifier, service, options);
983
+ this.eventBus.emit("service:register", service, { id: serviceId });
984
+ return true;
985
+ } catch (error) {
986
+ console.error(`Error initializing service ${serviceId}:`, error);
802
987
  return false;
803
988
  }
804
- this.services.register(serviceId, service);
805
- this.eventBus.emit("service:register", service);
989
+ }
990
+ async registerServiceAsync(service, identifier, options = {}) {
991
+ const serviceIdentifier = this.resolveServiceIdentifier(service, identifier);
992
+ const serviceId = this.getServiceLabel(serviceIdentifier);
993
+ try {
994
+ await this.invokeServiceHookAsync(service, "init");
995
+ this.services.register(serviceIdentifier, service, options);
996
+ this.eventBus.emit("service:register", service, { id: serviceId });
997
+ return true;
998
+ } catch (error) {
999
+ console.error(`Error initializing service ${serviceId}:`, error);
1000
+ return false;
1001
+ }
1002
+ }
1003
+ unregisterService(serviceOrIdentifier, id) {
1004
+ const resolvedIdentifier = this.resolveUnregisterIdentifier(
1005
+ serviceOrIdentifier,
1006
+ id
1007
+ );
1008
+ const serviceId = this.getServiceLabel(resolvedIdentifier);
1009
+ const registeredService = this.services.get(resolvedIdentifier);
1010
+ if (!registeredService) {
1011
+ console.warn(`Service ${serviceId} is not registered.`);
1012
+ return true;
1013
+ }
1014
+ try {
1015
+ const disposeResult = this.invokeServiceHook(registeredService, "dispose");
1016
+ if (this.isPromiseLike(disposeResult)) {
1017
+ throw new Error(
1018
+ `Service "${serviceId}" dispose() is async. Use unregisterServiceAsync() instead.`
1019
+ );
1020
+ }
1021
+ } catch (error) {
1022
+ console.error(`Error disposing service ${serviceId}:`, error);
1023
+ return false;
1024
+ }
1025
+ this.services.delete(resolvedIdentifier);
1026
+ this.eventBus.emit("service:unregister", registeredService, { id: serviceId });
806
1027
  return true;
807
1028
  }
808
- unregisterService(service, id) {
809
- var _a;
810
- const serviceId = id || service.constructor.name;
811
- if (!this.services.has(serviceId)) {
1029
+ async unregisterServiceAsync(serviceOrIdentifier, id) {
1030
+ const resolvedIdentifier = this.resolveUnregisterIdentifier(
1031
+ serviceOrIdentifier,
1032
+ id
1033
+ );
1034
+ const serviceId = this.getServiceLabel(resolvedIdentifier);
1035
+ const registeredService = this.services.get(resolvedIdentifier);
1036
+ if (!registeredService) {
812
1037
  console.warn(`Service ${serviceId} is not registered.`);
813
1038
  return true;
814
1039
  }
815
1040
  try {
816
- (_a = service == null ? void 0 : service.dispose) == null ? void 0 : _a.call(service);
817
- } catch (e) {
818
- console.error(`Error disposing service ${serviceId}:`, e);
1041
+ await this.invokeServiceHookAsync(registeredService, "dispose");
1042
+ } catch (error) {
1043
+ console.error(`Error disposing service ${serviceId}:`, error);
819
1044
  return false;
820
1045
  }
821
- this.services.delete(serviceId);
822
- this.eventBus.emit("service:unregister", service);
1046
+ this.services.delete(resolvedIdentifier);
1047
+ this.eventBus.emit("service:unregister", registeredService, { id: serviceId });
823
1048
  return true;
824
1049
  }
825
- getService(id) {
826
- return this.services.get(id);
1050
+ getService(identifier) {
1051
+ return this.services.get(identifier);
1052
+ }
1053
+ getServiceOrThrow(identifier, errorMessage) {
1054
+ return this.services.getOrThrow(identifier, errorMessage);
1055
+ }
1056
+ hasService(identifier) {
1057
+ return this.services.has(identifier);
1058
+ }
1059
+ async dispose() {
1060
+ var _a;
1061
+ this.extensionManager.destroy();
1062
+ const registrations = this.services.list().slice().reverse();
1063
+ for (const item of registrations) {
1064
+ const identifier = (_a = item.token) != null ? _a : item.id;
1065
+ await this.unregisterServiceAsync(identifier);
1066
+ }
1067
+ this.services.clear();
827
1068
  }
828
1069
  // --- Contribution Management ---
829
1070
  registerContributionPoint(point) {
@@ -838,8 +1079,39 @@ var Pooder = class {
838
1079
  getContributions(pointId) {
839
1080
  return this.contributions.get(pointId);
840
1081
  }
1082
+ resolveServiceIdentifier(service, identifier) {
1083
+ return identifier != null ? identifier : service.constructor.name;
1084
+ }
1085
+ resolveUnregisterIdentifier(serviceOrIdentifier, id) {
1086
+ if (typeof serviceOrIdentifier === "string" || isServiceToken(serviceOrIdentifier)) {
1087
+ return serviceOrIdentifier;
1088
+ }
1089
+ return id != null ? id : serviceOrIdentifier.constructor.name;
1090
+ }
1091
+ getServiceLabel(identifier) {
1092
+ if (typeof identifier === "string") {
1093
+ return identifier;
1094
+ }
1095
+ return identifier.name;
1096
+ }
1097
+ invokeServiceHook(service, hook) {
1098
+ const handler = service[hook];
1099
+ if (!handler) {
1100
+ return;
1101
+ }
1102
+ return handler.call(service, this.serviceContext);
1103
+ }
1104
+ async invokeServiceHookAsync(service, hook) {
1105
+ await this.invokeServiceHook(service, hook);
1106
+ }
1107
+ isPromiseLike(value) {
1108
+ return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
1109
+ }
841
1110
  };
842
1111
  export {
1112
+ COMMAND_SERVICE,
1113
+ CONFIGURATION_SERVICE,
1114
+ CORE_SERVICE_TOKENS,
843
1115
  CommandService,
844
1116
  ConfigurationService,
845
1117
  ContributionPointIds,
@@ -849,7 +1121,12 @@ export {
849
1121
  ExtensionRegistry,
850
1122
  Pooder,
851
1123
  ServiceRegistry,
1124
+ TOOL_REGISTRY_SERVICE,
1125
+ TOOL_SESSION_SERVICE,
852
1126
  ToolRegistryService,
853
1127
  ToolSessionService,
854
- WorkbenchService
1128
+ WORKBENCH_SERVICE,
1129
+ WorkbenchService,
1130
+ createServiceToken,
1131
+ isServiceToken
855
1132
  };