@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.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
- WorkbenchService: () => WorkbenchService
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.services = /* @__PURE__ */ new Map();
42
- }
43
- register(name, service) {
44
- this.services.set(name, service);
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(serviceName) {
48
- return this.services.get(serviceName);
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
- has(serviceName) {
51
- return this.services.has(serviceName);
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
- delete(serviceName) {
54
- this.services.delete(serviceName);
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
- var _a;
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 || !this.commandService) return void 0;
586
- return await this.commandService.executeCommand(commandId, ...args);
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
- init() {
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, _b, _c, _d, _e;
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 && this.toolRegistry && !this.toolRegistry.hasTool(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
- (_a = this.eventBus) == null ? void 0 : _a.emit("tool:switch:blocked", {
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 && this.sessionService) {
737
- const leaveResult = await this.sessionService.handleBeforeLeave(
738
- context.from
739
- );
772
+ if (context.from) {
773
+ const leaveResult = await sessionService.handleBeforeLeave(context.from);
740
774
  if (leaveResult.decision === "blocked") {
741
- (_b = this.eventBus) == null ? void 0 : _b.emit("tool:switch:blocked", {
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
- this.sessionService.deactivateSession(context.from);
786
+ sessionService.deactivateSession(context.from);
753
787
  }
754
- if (id && this.sessionService && this.toolRegistry) {
755
- const tool = this.toolRegistry.getTool(id);
756
- if ((tool == null ? void 0 : tool.interaction) === "session" && ((_c = tool.session) == null ? void 0 : _c.autoBegin) !== false) {
757
- await this.sessionService.begin(id);
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
- (_d = this.eventBus) == null ? void 0 : _d.emit("tool:activated", { id, previous, reason });
764
- (_e = this.eventBus) == null ? void 0 : _e.emit("tool:switch", { from: previous, to: id, reason });
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, "CommandService");
964
+ this.registerService(commandService, CORE_SERVICE_TOKENS.COMMAND);
784
965
  const configurationService = new ConfigurationService();
785
- this.registerService(configurationService, "ConfigurationService");
966
+ this.registerService(configurationService, CORE_SERVICE_TOKENS.CONFIGURATION);
786
967
  const toolRegistryService = new ToolRegistryService();
787
- this.registerService(toolRegistryService, "ToolRegistryService");
788
- const toolSessionService = new ToolSessionService();
789
- toolSessionService.setCommandService(commandService);
790
- toolSessionService.setToolRegistry(toolRegistryService);
791
- this.registerService(toolSessionService, "ToolSessionService");
792
- const workbenchService = new WorkbenchService();
793
- workbenchService.setEventBus(this.eventBus);
794
- workbenchService.setToolRegistry(toolRegistryService);
795
- workbenchService.setToolSessionService(toolSessionService);
796
- this.registerService(workbenchService, "WorkbenchService");
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: (serviceName) => this.services.get(serviceName)
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, id) {
833
- var _a;
834
- const serviceId = id || service.constructor.name;
1017
+ registerService(service, identifier, options = {}) {
1018
+ const serviceIdentifier = this.resolveServiceIdentifier(service, identifier);
1019
+ const serviceId = this.getServiceLabel(serviceIdentifier);
835
1020
  try {
836
- (_a = service == null ? void 0 : service.init) == null ? void 0 : _a.call(service);
837
- } catch (e) {
838
- console.error(`Error initializing service ${serviceId}:`, e);
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
- this.services.register(serviceId, service);
842
- this.eventBus.emit("service:register", service);
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
- unregisterService(service, id) {
846
- var _a;
847
- const serviceId = id || service.constructor.name;
848
- if (!this.services.has(serviceId)) {
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
- (_a = service == null ? void 0 : service.dispose) == null ? void 0 : _a.call(service);
854
- } catch (e) {
855
- console.error(`Error disposing service ${serviceId}:`, e);
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(serviceId);
859
- this.eventBus.emit("service:unregister", service);
1091
+ this.services.delete(resolvedIdentifier);
1092
+ this.eventBus.emit("service:unregister", registeredService, { id: serviceId });
860
1093
  return true;
861
1094
  }
862
- getService(id) {
863
- return this.services.get(id);
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
- WorkbenchService
1174
+ WORKBENCH_SERVICE,
1175
+ WorkbenchService,
1176
+ createServiceToken,
1177
+ isServiceToken
893
1178
  });