@codemation/host 0.1.6 → 0.1.7

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/{AppConfigFactory-BiFHnorf.d.ts → AppConfigFactory-BBEn2B-i.d.ts} +3 -3
  3. package/dist/{AppContainerFactory-BRU02PTm.js → AppContainerFactory-CeKsjo8L.js} +79 -19
  4. package/dist/AppContainerFactory-CeKsjo8L.js.map +1 -0
  5. package/dist/{CodemationConfig-DuGk7uN5.d.ts → CodemationConfig-9PkOBCh-.d.ts} +2 -2
  6. package/dist/{CodemationConfigNormalizer-BP2-0ZDE.d.ts → CodemationConfigNormalizer-DIc-LYqW.d.ts} +2 -2
  7. package/dist/{CodemationConsumerConfigLoader-D5CSz3TQ.d.ts → CodemationConsumerConfigLoader-CeW4bnOg.d.ts} +3 -2
  8. package/dist/{CodemationConsumerConfigLoader-C_ISRrpI.js → CodemationConsumerConfigLoader-D6LFSlp5.js} +20 -7
  9. package/dist/CodemationConsumerConfigLoader-D6LFSlp5.js.map +1 -0
  10. package/dist/{CodemationPluginListMerger-DFzGgfyI.d.ts → CodemationPluginListMerger-Cv7CaM5_.d.ts} +5 -5
  11. package/dist/{CredentialServices-Bhejvys-.d.ts → CredentialServices-Dp_jXTJo.d.ts} +3 -3
  12. package/dist/{PublicFrontendBootstrapFactory-CSgWyTra.d.ts → PublicFrontendBootstrapFactory-SQVHMxLg.d.ts} +5 -2
  13. package/dist/consumer.d.ts +4 -4
  14. package/dist/consumer.js +1 -1
  15. package/dist/credentials.d.ts +3 -3
  16. package/dist/devServerSidecar.d.ts +1 -1
  17. package/dist/{index-BQaZZmOm.d.ts → index-CLRTQLAp.d.ts} +42 -60
  18. package/dist/index.d.ts +97 -12
  19. package/dist/index.js +3 -3
  20. package/dist/nextServer.d.ts +14 -7
  21. package/dist/nextServer.js +1 -1
  22. package/dist/{persistenceServer-fdldtXJH.d.ts → persistenceServer-Dv7fg_Jf.d.ts} +2 -2
  23. package/dist/persistenceServer.d.ts +5 -5
  24. package/dist/{server-Cpzpy1Ar.d.ts → server-C5oqDnZQ.d.ts} +5 -5
  25. package/dist/{server-ChTCEc6R.js → server-CioY8PP3.js} +4 -5
  26. package/dist/{server-ChTCEc6R.js.map → server-CioY8PP3.js.map} +1 -1
  27. package/dist/server.d.ts +8 -8
  28. package/dist/server.js +3 -3
  29. package/package.json +6 -5
  30. package/playwright.config.ts +10 -6
  31. package/src/application/contracts/WorkflowViewContracts.ts +3 -0
  32. package/src/application/mapping/WorkflowDefinitionMapper.ts +117 -19
  33. package/src/bootstrap/AppContainerFactory.ts +2 -0
  34. package/src/presentation/http/routeHandlers/CredentialHttpRouteHandler.ts +2 -1
  35. package/src/presentation/http/routeHandlers/WorkflowHttpRouteHandler.ts +4 -2
  36. package/src/presentation/server/CodemationConsumerConfigLoader.ts +28 -5
  37. package/src/presentation/server/CodemationPluginDiscovery.ts +4 -6
  38. package/dist/AppContainerFactory-BRU02PTm.js.map +0 -1
  39. package/dist/CodemationConsumerConfigLoader-C_ISRrpI.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import type { AgentNodeConfig, NodeDefinition, WorkflowActivationPolicy, WorkflowDefinition } from "@codemation/core";
1
+ import type { NodeDefinition, WorkflowActivationPolicy, WorkflowDefinition } from "@codemation/core";
2
2
  import {
3
3
  AgentConfigInspector,
4
4
  AgentConnectionNodeCollector,
@@ -30,13 +30,14 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
30
30
  }
31
31
 
32
32
  mapSync(workflow: WorkflowDefinition): WorkflowDto {
33
+ const mapped = this.mapNodesAndEdges(workflow);
33
34
  return {
34
35
  id: workflow.id,
35
36
  name: workflow.name,
36
37
  active: this.workflowActivationPolicy.isActive(workflow.id),
37
38
  hasWorkflowErrorHandler: this.policyUi.workflowHasErrorHandler(workflow),
38
- nodes: this.toNodes(workflow),
39
- edges: this.toEdges(workflow),
39
+ nodes: mapped.nodes,
40
+ edges: mapped.edges,
40
41
  };
41
42
  }
42
43
 
@@ -61,19 +62,54 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
61
62
  return map;
62
63
  }
63
64
 
64
- private toNodes(workflow: WorkflowDefinition): ReadonlyArray<WorkflowNodeDto> {
65
+ private mapNodesAndEdges(
66
+ workflow: WorkflowDefinition,
67
+ ): Readonly<{ nodes: ReadonlyArray<WorkflowNodeDto>; edges: WorkflowDto["edges"] }> {
65
68
  const connectionChildMeta = this.buildConnectionChildMeta(workflow);
66
69
  const materializedConnectionNodeIds = new Set(connectionChildMeta.keys());
70
+ const nodesById = new Map(workflow.nodes.map((node) => [node.id, node] as const));
71
+ const agentConnectionDescriptors = this.buildAgentConnectionDescriptorIndex(workflow);
72
+ return {
73
+ nodes: this.toNodes({
74
+ workflow,
75
+ connectionChildMeta,
76
+ materializedConnectionNodeIds,
77
+ nodesById,
78
+ agentConnectionDescriptors,
79
+ }),
80
+ edges: this.toEdges({
81
+ workflow,
82
+ materializedConnectionNodeIds,
83
+ agentConnectionDescriptors,
84
+ }),
85
+ };
86
+ }
87
+
88
+ private toNodes(
89
+ args: Readonly<{
90
+ workflow: WorkflowDefinition;
91
+ connectionChildMeta: ReadonlyMap<string, Readonly<{ parentNodeId: string; connectionName: string }>>;
92
+ materializedConnectionNodeIds: ReadonlySet<string>;
93
+ nodesById: ReadonlyMap<string, WorkflowDefinition["nodes"][number]>;
94
+ agentConnectionDescriptors: Readonly<{
95
+ byAgentNodeId: ReadonlyMap<string, ReadonlyArray<AgentConnectionNodeDescriptor>>;
96
+ byChildNodeIdByAgentNodeId: ReadonlyMap<string, ReadonlyMap<string, AgentConnectionNodeDescriptor>>;
97
+ }>;
98
+ }>,
99
+ ): ReadonlyArray<WorkflowNodeDto> {
100
+ const workflow = args.workflow;
101
+ const connectionChildMeta = args.connectionChildMeta;
102
+ const materializedConnectionNodeIds = args.materializedConnectionNodeIds;
103
+ const nodesById = args.nodesById;
104
+ const agentConnectionDescriptors = args.agentConnectionDescriptors;
67
105
  const nodes: WorkflowNodeDto[] = [];
68
106
  for (const node of workflow.nodes) {
69
107
  const conn = connectionChildMeta.get(node.id);
70
108
  if (conn) {
71
- const parentNode = workflow.nodes.find((n) => n.id === conn.parentNodeId);
109
+ const parentNode = nodesById.get(conn.parentNodeId);
72
110
  let role: string = conn.connectionName === "llm" ? "languageModel" : "tool";
73
111
  if (parentNode && AgentConfigInspector.isAgentNodeConfig(parentNode.config)) {
74
- const descriptor = AgentConnectionNodeCollector.collect(conn.parentNodeId, parentNode.config).find(
75
- (d) => d.nodeId === node.id,
76
- );
112
+ const descriptor = agentConnectionDescriptors.byChildNodeIdByAgentNodeId.get(conn.parentNodeId)?.get(node.id);
77
113
  if (descriptor) {
78
114
  role = descriptor.role;
79
115
  }
@@ -87,6 +123,7 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
87
123
  icon: node.config?.icon,
88
124
  retryPolicySummary: this.policyUi.nodeRetrySummary(node.config),
89
125
  hasNodeErrorHandler: this.policyUi.nodeHasErrorHandler(node.config),
126
+ ...this.nodePortFieldsFromConfig(node.config),
90
127
  parentNodeId: conn.parentNodeId,
91
128
  });
92
129
  continue;
@@ -100,17 +137,32 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
100
137
  icon: node.config?.icon,
101
138
  retryPolicySummary: this.policyUi.nodeRetrySummary(node.config),
102
139
  hasNodeErrorHandler: this.policyUi.nodeHasErrorHandler(node.config),
140
+ ...this.nodePortFieldsFromConfig(node.config),
103
141
  });
104
142
  if (AgentConfigInspector.isAgentNodeConfig(node.config)) {
105
- this.appendVirtualConnectionNodes(node.id, node.config, materializedConnectionNodeIds, nodes);
143
+ this.appendVirtualConnectionNodes(
144
+ materializedConnectionNodeIds,
145
+ nodes,
146
+ agentConnectionDescriptors.byAgentNodeId.get(node.id) ?? [],
147
+ );
106
148
  }
107
149
  }
108
150
  return nodes;
109
151
  }
110
152
 
111
- private toEdges(workflow: WorkflowDefinition): WorkflowDto["edges"] {
112
- const connectionChildMeta = this.buildConnectionChildMeta(workflow);
113
- const materializedConnectionNodeIds = new Set(connectionChildMeta.keys());
153
+ private toEdges(
154
+ args: Readonly<{
155
+ workflow: WorkflowDefinition;
156
+ materializedConnectionNodeIds: ReadonlySet<string>;
157
+ agentConnectionDescriptors: Readonly<{
158
+ byAgentNodeId: ReadonlyMap<string, ReadonlyArray<AgentConnectionNodeDescriptor>>;
159
+ byChildNodeIdByAgentNodeId: ReadonlyMap<string, ReadonlyMap<string, AgentConnectionNodeDescriptor>>;
160
+ }>;
161
+ }>,
162
+ ): WorkflowDto["edges"] {
163
+ const workflow = args.workflow;
164
+ const materializedConnectionNodeIds = args.materializedConnectionNodeIds;
165
+ const agentConnectionDescriptors = args.agentConnectionDescriptors;
114
166
  const edges: WorkflowEdgeDto[] = [...workflow.edges];
115
167
  const edgeKeys = new Set(edges.map((edge) => this.edgeKey(edge.from.nodeId, edge.to.nodeId, edge.to.input)));
116
168
  this.appendMaterializedConnectionEdges(workflow, edgeKeys, edges);
@@ -118,7 +170,12 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
118
170
  if (!AgentConfigInspector.isAgentNodeConfig(node.config)) {
119
171
  continue;
120
172
  }
121
- this.appendVirtualConnectionEdges(node.id, node.config, materializedConnectionNodeIds, edgeKeys, edges);
173
+ this.appendVirtualConnectionEdges(
174
+ materializedConnectionNodeIds,
175
+ edgeKeys,
176
+ edges,
177
+ agentConnectionDescriptors.byAgentNodeId.get(node.id) ?? [],
178
+ );
122
179
  }
123
180
  return edges;
124
181
  }
@@ -143,13 +200,33 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
143
200
  }
144
201
  }
145
202
 
203
+ private buildAgentConnectionDescriptorIndex(workflow: WorkflowDefinition): Readonly<{
204
+ byAgentNodeId: ReadonlyMap<string, ReadonlyArray<AgentConnectionNodeDescriptor>>;
205
+ byChildNodeIdByAgentNodeId: ReadonlyMap<string, ReadonlyMap<string, AgentConnectionNodeDescriptor>>;
206
+ }> {
207
+ const byAgentNodeId = new Map<string, ReadonlyArray<AgentConnectionNodeDescriptor>>();
208
+ const byChildNodeIdByAgentNodeId = new Map<string, ReadonlyMap<string, AgentConnectionNodeDescriptor>>();
209
+ for (const node of workflow.nodes) {
210
+ if (!AgentConfigInspector.isAgentNodeConfig(node.config)) {
211
+ continue;
212
+ }
213
+ const descriptors = AgentConnectionNodeCollector.collect(node.id, node.config);
214
+ byAgentNodeId.set(node.id, descriptors);
215
+ const byChildId = new Map<string, AgentConnectionNodeDescriptor>();
216
+ for (const descriptor of descriptors) {
217
+ byChildId.set(descriptor.nodeId, descriptor);
218
+ }
219
+ byChildNodeIdByAgentNodeId.set(node.id, byChildId);
220
+ }
221
+ return { byAgentNodeId, byChildNodeIdByAgentNodeId };
222
+ }
223
+
146
224
  private appendVirtualConnectionNodes(
147
- rootAgentNodeId: string,
148
- agentConfig: AgentNodeConfig<any, any>,
149
225
  materializedConnectionNodeIds: ReadonlySet<string>,
150
226
  nodes: WorkflowNodeDto[],
227
+ descriptors: ReadonlyArray<AgentConnectionNodeDescriptor>,
151
228
  ): void {
152
- for (const connectionNode of AgentConnectionNodeCollector.collect(rootAgentNodeId, agentConfig)) {
229
+ for (const connectionNode of descriptors) {
153
230
  if (materializedConnectionNodeIds.has(connectionNode.nodeId)) {
154
231
  continue;
155
232
  }
@@ -158,13 +235,12 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
158
235
  }
159
236
 
160
237
  private appendVirtualConnectionEdges(
161
- rootAgentNodeId: string,
162
- agentConfig: AgentNodeConfig<any, any>,
163
238
  materializedConnectionNodeIds: ReadonlySet<string>,
164
239
  edgeKeys: Set<string>,
165
240
  edges: WorkflowEdgeDto[],
241
+ descriptors: ReadonlyArray<AgentConnectionNodeDescriptor>,
166
242
  ): void {
167
- for (const connectionNode of AgentConnectionNodeCollector.collect(rootAgentNodeId, agentConfig)) {
243
+ for (const connectionNode of descriptors) {
168
244
  if (materializedConnectionNodeIds.has(connectionNode.nodeId)) {
169
245
  continue;
170
246
  }
@@ -196,6 +272,28 @@ export class WorkflowDefinitionMapper implements DataMapper<WorkflowDefinition,
196
272
  };
197
273
  }
198
274
 
275
+ /**
276
+ * Omit optional port fields when undefined so persisted snapshot DTOs (which never serialize
277
+ * undefined keys) stay aligned with live workflow mapping.
278
+ */
279
+ private nodePortFieldsFromConfig(
280
+ config: NodeDefinition["config"] | undefined,
281
+ ): Pick<WorkflowNodeDto, "continueWhenEmptyOutput" | "declaredOutputPorts" | "declaredInputPorts"> {
282
+ if (!config || typeof config !== "object") {
283
+ return {};
284
+ }
285
+ const c = config as {
286
+ continueWhenEmptyOutput?: boolean;
287
+ declaredOutputPorts?: readonly string[];
288
+ declaredInputPorts?: readonly string[];
289
+ };
290
+ return {
291
+ ...(c.continueWhenEmptyOutput !== undefined && { continueWhenEmptyOutput: c.continueWhenEmptyOutput }),
292
+ ...(c.declaredOutputPorts !== undefined && { declaredOutputPorts: c.declaredOutputPorts }),
293
+ ...(c.declaredInputPorts !== undefined && { declaredInputPorts: c.declaredInputPorts }),
294
+ };
295
+ }
296
+
199
297
  private nodeTypeName(node: NodeDefinition): string {
200
298
  const configToken = node.config?.type as Readonly<{ name?: unknown }> | undefined;
201
299
  if (typeof configToken?.name === "string" && configToken.name) {
@@ -63,6 +63,7 @@ import {
63
63
  GetRunStateQueryHandler,
64
64
  GetWorkflowDebuggerOverlayQueryHandler,
65
65
  GetWorkflowDetailQueryHandler,
66
+ GetWorkflowRunDetailQueryHandler,
66
67
  GetWorkflowOverlayBinaryAttachmentQueryHandler,
67
68
  GetWorkflowSummariesQueryHandler,
68
69
  ListWorkflowRunsQueryHandler,
@@ -194,6 +195,7 @@ export class AppContainerFactory {
194
195
  VerifyUserInviteQueryHandler,
195
196
  GetRunBinaryAttachmentQueryHandler,
196
197
  GetRunStateQueryHandler,
198
+ GetWorkflowRunDetailQueryHandler,
197
199
  GetWorkflowDebuggerOverlayQueryHandler,
198
200
  GetWorkflowDetailQueryHandler,
199
201
  GetWorkflowOverlayBinaryAttachmentQueryHandler,
@@ -121,7 +121,8 @@ export class CredentialHttpRouteHandler {
121
121
 
122
122
  async getWorkflowCredentialHealth(_: Request, params: ServerHttpRouteParams): Promise<Response> {
123
123
  try {
124
- return Response.json(await this.queryBus.execute(new GetWorkflowCredentialHealthQuery(params.workflowId!)));
124
+ const health = await this.queryBus.execute(new GetWorkflowCredentialHealthQuery(params.workflowId!));
125
+ return Response.json(health);
125
126
  } catch (error) {
126
127
  return ServerHttpErrorResponseFactory.fromUnknown(error);
127
128
  }
@@ -66,7 +66,8 @@ export class WorkflowHttpRouteHandler {
66
66
 
67
67
  async getWorkflowRuns(_: Request, params: ServerHttpRouteParams): Promise<Response> {
68
68
  try {
69
- return Response.json(await this.queryBus.execute(new ListWorkflowRunsQuery(params.workflowId!)));
69
+ const runs = await this.queryBus.execute(new ListWorkflowRunsQuery(params.workflowId!));
70
+ return Response.json(runs);
70
71
  } catch (error) {
71
72
  return ServerHttpErrorResponseFactory.fromUnknown(error);
72
73
  }
@@ -74,7 +75,8 @@ export class WorkflowHttpRouteHandler {
74
75
 
75
76
  async getWorkflowDebuggerOverlay(_: Request, params: ServerHttpRouteParams): Promise<Response> {
76
77
  try {
77
- return Response.json(await this.queryBus.execute(new GetWorkflowDebuggerOverlayQuery(params.workflowId!)));
78
+ const overlay = await this.queryBus.execute(new GetWorkflowDebuggerOverlayQuery(params.workflowId!));
79
+ return Response.json(overlay);
78
80
  } catch (error) {
79
81
  return ServerHttpErrorResponseFactory.fromUnknown(error);
80
82
  }
@@ -20,6 +20,11 @@ export type CodemationConsumerConfigResolution = Readonly<{
20
20
  workflowSources: ReadonlyArray<string>;
21
21
  }>;
22
22
 
23
+ type ConsumerImportSession = Readonly<{
24
+ shouldResetImporter: boolean;
25
+ resetCacheKeys: Set<string>;
26
+ }>;
27
+
23
28
  export class CodemationConsumerConfigLoader {
24
29
  private static readonly importerRegistrationsByTsconfig = new Map<string, NamespacedUnregister>();
25
30
  private static readonly importerNamespaceVersionByTsconfig = new Map<string, number>();
@@ -38,10 +43,13 @@ export class CodemationConsumerConfigLoader {
38
43
  ): Promise<CodemationConsumerConfigResolution> {
39
44
  const loadStarted = performance.now();
40
45
  let mark = loadStarted;
46
+ const importSession = this.createImportSession();
47
+ const phaseDurations = new Map<string, number>();
41
48
  const phaseMs = (label: string): void => {
42
49
  const now = performance.now();
43
50
  const delta = now - mark;
44
51
  mark = now;
52
+ phaseDurations.set(label, delta);
45
53
  this.performanceDiagnosticsLogger.info(
46
54
  `load.${label} +${delta.toFixed(1)}ms (cumulative ${(now - loadStarted).toFixed(1)}ms)`,
47
55
  );
@@ -53,7 +61,7 @@ export class CodemationConsumerConfigLoader {
53
61
  'Codemation config not found. Expected "codemation.config.ts" in the consumer project root or "src/".',
54
62
  );
55
63
  }
56
- const moduleExports = await this.importModule(bootstrapSource);
64
+ const moduleExports = await this.importModule(bootstrapSource, importSession);
57
65
  phaseMs("importConfigModule");
58
66
  const rawConfig = this.configExportsResolver.resolveConfig(moduleExports);
59
67
  if (!rawConfig) {
@@ -64,7 +72,7 @@ export class CodemationConsumerConfigLoader {
64
72
  phaseMs("resolveWorkflowSources");
65
73
  const workflows = this.mergeWorkflows(
66
74
  config.workflows ?? [],
67
- await this.loadDiscoveredWorkflows(args.consumerRoot, config, workflowSources),
75
+ await this.loadDiscoveredWorkflows(args.consumerRoot, config, workflowSources, importSession),
68
76
  );
69
77
  phaseMs("loadDiscoveredWorkflows");
70
78
  const resolvedConfig: NormalizedCodemationConfig = {
@@ -125,6 +133,7 @@ export class CodemationConsumerConfigLoader {
125
133
  consumerRoot: string,
126
134
  config: CodemationConfig,
127
135
  workflowSources: ReadonlyArray<string>,
136
+ importSession: ConsumerImportSession,
128
137
  ): Promise<ReadonlyArray<WorkflowDefinition>> {
129
138
  const workflowDiscoveryDirectories = config.workflowDiscovery?.directories ?? [];
130
139
  const workflowsById = new Map<string, WorkflowDefinition>();
@@ -136,7 +145,7 @@ export class CodemationConsumerConfigLoader {
136
145
  workflowDiscoveryDirectories,
137
146
  absoluteWorkflowModulePath: workflowSource,
138
147
  }),
139
- moduleExports: await this.importModule(workflowSource),
148
+ moduleExports: await this.importModule(workflowSource, importSession),
140
149
  })),
141
150
  );
142
151
  for (const loadedWorkflowModule of loadedWorkflowModules) {
@@ -168,13 +177,20 @@ export class CodemationConsumerConfigLoader {
168
177
  return [...workflowsById.values()];
169
178
  }
170
179
 
171
- private async importModule(modulePath: string): Promise<Record<string, unknown>> {
180
+ private async importModule(
181
+ modulePath: string,
182
+ importSession: ConsumerImportSession,
183
+ ): Promise<Record<string, unknown>> {
172
184
  if (this.shouldUseNativeRuntimeImport()) {
173
185
  return await this.importModuleWithNativeRuntime(modulePath);
174
186
  }
175
187
  const tsconfigPath = await this.resolveTsconfigPath(modulePath);
176
- if (this.shouldResetImporterBeforeImport()) {
188
+ const cacheKey = tsconfigPath || "default";
189
+ const shouldResetImporter = importSession.shouldResetImporter;
190
+ const didResetImporterForThisImport = shouldResetImporter && !importSession.resetCacheKeys.has(cacheKey);
191
+ if (didResetImporterForThisImport) {
177
192
  await this.resetImporter(tsconfigPath);
193
+ importSession.resetCacheKeys.add(cacheKey);
178
194
  }
179
195
  const importSpecifier = await this.createImportSpecifier(modulePath);
180
196
  for (let attempt = 0; attempt < 3; attempt += 1) {
@@ -278,6 +294,13 @@ export class CodemationConsumerConfigLoader {
278
294
  return (process.env.CODEMATION_DEV_SERVER_TOKEN?.trim().length ?? 0) > 0;
279
295
  }
280
296
 
297
+ private createImportSession(): ConsumerImportSession {
298
+ return {
299
+ resetCacheKeys: new Set<string>(),
300
+ shouldResetImporter: this.shouldResetImporterBeforeImport(),
301
+ };
302
+ }
303
+
281
304
  private isStoppedTransformServiceError(error: unknown): boolean {
282
305
  return error instanceof Error && error.message.includes("The service is no longer running");
283
306
  }
@@ -142,14 +142,12 @@ export class CodemationPluginDiscovery {
142
142
  }
143
143
 
144
144
  private resolvePluginEntry(discoveredPackage: CodemationDiscoveredPluginPackage): string {
145
- if (
145
+ const preferSource =
146
146
  process.env.CODEMATION_PREFER_PLUGIN_SOURCE_ENTRY === "true" &&
147
147
  typeof discoveredPackage.developmentEntry === "string" &&
148
- discoveredPackage.developmentEntry.trim().length > 0
149
- ) {
150
- return discoveredPackage.developmentEntry;
151
- }
152
- return discoveredPackage.pluginEntry;
148
+ discoveredPackage.developmentEntry.trim().length > 0;
149
+ const selectedEntry = preferSource ? discoveredPackage.developmentEntry : discoveredPackage.pluginEntry;
150
+ return selectedEntry;
153
151
  }
154
152
 
155
153
  private async resolveDevelopmentPluginEntry(packageRoot: string): Promise<string | undefined> {