@gt-fe/eap-runtime 0.0.18 → 0.0.20

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 (38) hide show
  1. package/dist/api/handlers/invoke.handler.js +10 -16
  2. package/dist/api/handlers/stream.handler.js +3 -0
  3. package/dist/checkpoint/checkpoint-ref-notify.js +5 -4
  4. package/dist/contracts/index.d.ts +1 -1
  5. package/dist/contracts/trace-collector.d.ts +16 -8
  6. package/dist/graph/adapters/langgraph.adapter.d.ts +5 -12
  7. package/dist/graph/adapters/langgraph.adapter.js +109 -64
  8. package/dist/graph/adapters/skill-entry-span.d.ts +37 -0
  9. package/dist/graph/adapters/skill-entry-span.js +78 -0
  10. package/dist/graph/adapters/skill-read.d.ts +10 -0
  11. package/dist/graph/adapters/skill-read.js +33 -0
  12. package/dist/graph/adapters/subgraph-compiler.js +22 -11
  13. package/dist/graph/contracts/executable-graph.d.ts +4 -1
  14. package/dist/graph/execution-trace-context.d.ts +38 -0
  15. package/dist/graph/execution-trace-context.js +62 -0
  16. package/dist/graph/hitl/hitl-handler.d.ts +2 -1
  17. package/dist/graph/hitl/hitl-handler.js +24 -6
  18. package/dist/graph/nodes/tool-node.d.ts +6 -0
  19. package/dist/graph/nodes/tool-node.js +51 -8
  20. package/dist/graph/skill-audit-recorder.d.ts +4 -4
  21. package/dist/graph/skill-audit-recorder.js +3 -3
  22. package/dist/graph/trace-span.d.ts +2 -9
  23. package/dist/graph/trace-span.js +9 -7
  24. package/dist/index.d.ts +1 -1
  25. package/dist/runtime/agent-runtime.js +22 -0
  26. package/dist/runtime/types.d.ts +1 -1
  27. package/dist/sse/trace-collector.d.ts +2 -9
  28. package/dist/token/index.d.ts +2 -0
  29. package/dist/token/index.js +1 -0
  30. package/dist/token/record-task-token-usage.d.ts +21 -0
  31. package/dist/token/record-task-token-usage.js +52 -0
  32. package/dist/token/token-stats.service.d.ts +2 -0
  33. package/dist/token/token-stats.service.js +4 -0
  34. package/dist/tool/index.d.ts +1 -1
  35. package/dist/tool/index.js +1 -1
  36. package/dist/tool/mcp-list.d.ts +12 -0
  37. package/dist/tool/mcp-list.js +15 -0
  38. package/package.json +1 -1
@@ -1,21 +1,14 @@
1
1
  /**
2
2
  * Graph 节点 Span 辅助:createNode / completeNode 失败不挡主路径。
3
3
  */
4
- import type { ITraceCollector, ExecutionNodeEvent } from '../contracts/trace-collector.js';
4
+ import type { ITraceCollector, ExecutionNodeEvent, CompleteNodeParams } from '../contracts/trace-collector.js';
5
5
  export declare function startGraphSpan(state: Record<string, unknown>, input: {
6
6
  name: string;
7
7
  type: ExecutionNodeEvent['type'];
8
8
  parentSpanId?: string;
9
9
  extra?: Partial<Omit<ExecutionNodeEvent, 'traceId' | 'name' | 'type' | 'parentNodeId'>>;
10
10
  }): Promise<string | undefined>;
11
- export declare function completeGraphSpan(state: Record<string, unknown>, spanId: string | undefined, params: {
12
- status: 'completed' | 'failed';
13
- output?: unknown;
14
- error?: string;
15
- inputTokens?: number;
16
- outputTokens?: number;
17
- totalTokens?: number;
18
- }, collectorOverride?: ITraceCollector): Promise<void>;
11
+ export declare function completeGraphSpan(state: Record<string, unknown>, spanId: string | undefined, params: CompleteNodeParams, collectorOverride?: ITraceCollector): Promise<void>;
19
12
  export declare function withGraphSpan(state: Record<string, unknown>, spec: {
20
13
  name: string;
21
14
  type: ExecutionNodeEvent['type'];
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Graph 节点 Span 辅助:createNode / completeNode 失败不挡主路径。
3
3
  */
4
- import { resolveTraceId } from '../common/trace-id.js';
4
+ import { resolveExecutionTrace, warnTraceSpanFailure, } from './execution-trace-context.js';
5
5
  export async function startGraphSpan(state, input) {
6
- const collector = state['traceCollector'];
7
- const traceId = resolveTraceId(state);
6
+ // collector 只从这次调用链取;state 只用来拼 parent/task 元数据。
7
+ const { collector, traceId } = resolveExecutionTrace(state);
8
8
  if (!collector || !traceId)
9
9
  return undefined;
10
10
  const parentNodeId = input.parentSpanId ??
@@ -27,19 +27,20 @@ export async function startGraphSpan(state, input) {
27
27
  },
28
28
  });
29
29
  }
30
- catch {
30
+ catch (err) {
31
+ warnTraceSpanFailure('createNode', { type: input.type, name: input.name, traceId }, err);
31
32
  return undefined;
32
33
  }
33
34
  }
34
35
  export async function completeGraphSpan(state, spanId, params, collectorOverride) {
35
- const collector = collectorOverride ?? state['traceCollector'];
36
+ const collector = collectorOverride ?? resolveExecutionTrace(state).collector;
36
37
  if (!collector?.completeNode || !spanId)
37
38
  return;
38
39
  try {
39
40
  await collector.completeNode(spanId, params);
40
41
  }
41
- catch {
42
- // Trace 失败不影响主路径
42
+ catch (err) {
43
+ warnTraceSpanFailure('completeNode', { spanId, traceId: resolveExecutionTrace(state).traceId }, err);
43
44
  }
44
45
  }
45
46
  export async function withGraphSpan(state, spec, run) {
@@ -56,6 +57,7 @@ export async function withGraphSpan(state, spec, run) {
56
57
  totalTokens: usage?.inputTokens != null || usage?.outputTokens != null
57
58
  ? (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
58
59
  : undefined,
60
+ ...(typeof usage?.model === 'string' && usage.model ? { model: usage.model } : {}),
59
61
  });
60
62
  return spanId ? { ...result, lastSpanId: spanId } : result;
61
63
  }
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export * from './memory/index.js';
15
15
  export * from './common/index.js';
16
16
  export * from './registry/index.js';
17
17
  export * from './providers/index.js';
18
- export type { ITraceCollector, TraceEvent, TraceSession, ExecutionFlowEvent, ExecutionNodeEvent, TraceLinkEvent, TraceLinkNodeEvent, } from './contracts/trace-collector.js';
18
+ export type { ITraceCollector, CompleteNodeParams, TraceEvent, TraceSession, ExecutionFlowEvent, ExecutionNodeEvent, TraceLinkEvent, TraceLinkNodeEvent, } from './contracts/trace-collector.js';
19
19
  export type { ExecutionContext, CallerType, GovernancePermissionCheckParams, GovernancePermissionCheckResult, PermissionDenyReason, } from '@gt-fe/eap-contracts';
20
20
  export { HttpGovernanceClient, AllowAllGovernanceClient, resolveExecutionContext, assertToolPermission, assertSkillPermission, permissionMessage, PermissionDeniedError, GovernanceUnavailableError, } from './governance/index.js';
21
21
  export type { IGovernanceClient } from './governance/index.js';
@@ -17,6 +17,7 @@ import { AppError, ErrorCodes } from '@gt-fe/eap-contracts';
17
17
  import { resolveExecutionContext } from '../governance/governance-client.js';
18
18
  import { resolveAgentCode } from '../common/agent-code.js';
19
19
  import { resolveTraceId } from '../common/trace-id.js';
20
+ import { collectStreamNodeTokenUsage, recordTaskTokenUsages, } from '../token/record-task-token-usage.js';
20
21
  import { resolveSkillInputFromInvokeInput } from '../registry/skill-io-guard.js';
21
22
  const HITL_TERMINAL_STATUSES = [
22
23
  'success',
@@ -286,6 +287,7 @@ export class AgentRuntime {
286
287
  let assistantReasoningContent;
287
288
  const pendingToolCalls = [];
288
289
  const toolResults = [];
290
+ const nodeTokenUsages = [];
289
291
  try {
290
292
  for await (const runtimeEvent of this.deps.graphEngine.stream(graph, {
291
293
  messages,
@@ -345,8 +347,10 @@ export class AgentRuntime {
345
347
  assistantText += delta;
346
348
  }
347
349
  }
350
+ collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
348
351
  yield this.runtimeEventToSSE(runtimeEvent, correlationId, task.id);
349
352
  }
353
+ await recordTaskTokenUsages(this.deps.taskService, task.id, nodeTokenUsages);
350
354
  await this.deps.taskService.updateStatus(task.id, 'success');
351
355
  await persistTurnTranscript(this.deps.messageService, {
352
356
  sessionId,
@@ -368,6 +372,7 @@ export class AgentRuntime {
368
372
  catch (err) {
369
373
  const hitlPaused = unwrapHitlPaused(err);
370
374
  if (hitlPaused) {
375
+ await recordTaskTokenUsages(this.deps.taskService, task.id, nodeTokenUsages);
371
376
  await this.deps.taskService.updateStatus(task.id, 'waiting_hitl', buildHitlWaitingTaskOutput({
372
377
  threadId: hitlPaused.threadId,
373
378
  question: hitlPaused.question,
@@ -516,6 +521,7 @@ export class AgentRuntime {
516
521
  let assistantReasoningContent;
517
522
  const pendingToolCalls = [];
518
523
  const toolResults = [];
524
+ const nodeTokenUsages = [];
519
525
  try {
520
526
  for await (const runtimeEvent of this.deps.graphEngine.stream(graph, continueState)) {
521
527
  if (runtimeEvent.type === 'tool.called') {
@@ -555,8 +561,10 @@ export class AgentRuntime {
555
561
  assistantText += delta;
556
562
  }
557
563
  }
564
+ collectStreamNodeTokenUsage(runtimeEvent, nodeTokenUsages);
558
565
  yield this.runtimeEventToSSE(runtimeEvent, correlationId, taskId);
559
566
  }
567
+ await recordTaskTokenUsages(this.deps.taskService, taskId, nodeTokenUsages);
560
568
  await this.deps.taskService.updateStatus(taskId, 'success', assistantText || undefined);
561
569
  if (sessionId) {
562
570
  await persistTurnTranscript(this.deps.messageService, {
@@ -580,6 +588,7 @@ export class AgentRuntime {
580
588
  catch (err) {
581
589
  const hitlPaused = unwrapHitlPaused(err);
582
590
  if (hitlPaused) {
591
+ await recordTaskTokenUsages(this.deps.taskService, taskId, nodeTokenUsages);
583
592
  await this.deps.taskService.updateStatus(taskId, 'waiting_hitl', buildHitlWaitingTaskOutput({
584
593
  threadId: hitlPaused.threadId,
585
594
  question: hitlPaused.question,
@@ -676,6 +685,19 @@ export class AgentRuntime {
676
685
  traceId,
677
686
  traceCollector: this.deps.traceCollector,
678
687
  });
688
+ if (result.tokenUsage.perNode && result.tokenUsage.perNode.length > 0) {
689
+ await recordTaskTokenUsages(this.deps.taskService, task.id, result.tokenUsage.perNode);
690
+ }
691
+ else if (result.tokenUsage.total > 0) {
692
+ await recordTaskTokenUsages(this.deps.taskService, task.id, [
693
+ {
694
+ nodeId: 'graph',
695
+ model: 'unknown',
696
+ inputTokens: result.tokenUsage.input,
697
+ outputTokens: result.tokenUsage.output,
698
+ },
699
+ ]);
700
+ }
679
701
  await this.deps.taskService.updateStatus(task.id, 'success', result.output);
680
702
  if (this.deps.recordForkRelation) {
681
703
  try {
@@ -24,7 +24,7 @@ export interface ExecuteParams {
24
24
  agentVersion?: string;
25
25
  /**
26
26
  * Hosting 已创建的 Trace id(Foundation `POST /traces` / TraceLinker.createTrace 的返回值)。
27
- * 写入 GraphState 供 Skill/Tool span。
27
+ * 与装配期 `traceCollector` 同时存在时,invoke/stream 入口绑定到本次执行上下文供图内 span。
28
28
  */
29
29
  traceId?: string;
30
30
  config?: InvokeConfig;
@@ -6,7 +6,7 @@
6
6
  * @see contracts/trace-collector.ts
7
7
  * @see sse/sse-emitter.ts
8
8
  */
9
- import type { ExecutionFlowEvent, ExecutionNodeEvent, ITraceCollector, TraceEvent, TraceLinkEvent, TraceLinkNodeEvent, TraceSession } from '../contracts/trace-collector.js';
9
+ import type { CompleteNodeParams, ExecutionFlowEvent, ExecutionNodeEvent, ITraceCollector, TraceEvent, TraceLinkEvent, TraceLinkNodeEvent, TraceSession } from '../contracts/trace-collector.js';
10
10
  /**
11
11
  * InMemoryTraceCollector — 内存 Trace 采集器(测试用)
12
12
  */
@@ -18,14 +18,7 @@ export declare class InMemoryTraceCollector implements ITraceCollector {
18
18
  getSession(sessionId: string): Promise<TraceSession | null>;
19
19
  createFlow(_event: ExecutionFlowEvent): Promise<string>;
20
20
  createNode(_event: ExecutionNodeEvent): Promise<string>;
21
- completeNode(_nodeId: string, _params: {
22
- status: 'completed' | 'failed';
23
- output?: unknown;
24
- error?: string;
25
- inputTokens?: number;
26
- outputTokens?: number;
27
- totalTokens?: number;
28
- }): Promise<void>;
21
+ completeNode(_nodeId: string, _params: CompleteNodeParams): Promise<void>;
29
22
  createLink(_event: TraceLinkEvent): Promise<string>;
30
23
  createLinkNode(_event: TraceLinkNodeEvent): Promise<string>;
31
24
  completeLinkNode(_nodeId: string, _params: {
@@ -6,6 +6,8 @@ export { TokenBudgetGuard, TokenBudgetExhaustedError, } from './token-budget-gua
6
6
  export { SessionBudgetChecker, SessionBudgetExhaustedError, } from './session-budget-checker.js';
7
7
  export type { NodeTokenUsage, TokenBreakdown, TaskTokenSummary, } from './token-stats.service.js';
8
8
  export { TokenStatsService } from './token-stats.service.js';
9
+ export { recordTaskTokenUsages, tokenUsageFromNodePayload, collectStreamNodeTokenUsage, } from './record-task-token-usage.js';
10
+ export type { TaskTokenUsageWriter } from './record-task-token-usage.js';
9
11
  export type { TokenDetailMode } from './token-detail-mode.js';
10
12
  export { contextWindowUsage, buildContextUsage, splitContextUsage, turnSectionChars, pickContextFields, type ContextWindowUsage, type ContextUsageParts, } from './context-window.js';
11
13
  export { TokenStatsEmitter } from './token-detail-mode.js';
@@ -3,6 +3,7 @@ export { PostgresTokenBudgetRepository } from './pg-token-budget.repository.js';
3
3
  export { TokenBudgetGuard, TokenBudgetExhaustedError, } from './token-budget-guard.js';
4
4
  export { SessionBudgetChecker, SessionBudgetExhaustedError, } from './session-budget-checker.js';
5
5
  export { TokenStatsService } from './token-stats.service.js';
6
+ export { recordTaskTokenUsages, tokenUsageFromNodePayload, collectStreamNodeTokenUsage, } from './record-task-token-usage.js';
6
7
  export { contextWindowUsage, buildContextUsage, splitContextUsage, turnSectionChars, pickContextFields, } from './context-window.js';
7
8
  export { TokenStatsEmitter } from './token-detail-mode.js';
8
9
  // 上下文窗口预算分配
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Task.token_usage 写入:invoke / stream / HITL resume / fork 同一收口。
3
+ *
4
+ * 假设:一次 LLM 调用产生一条 TokenUsageRecord(nodeId + model + in/out)。
5
+ * 来源可以是 Graph.perNode,也可以是 SSE stats.node_token_usage,字段同一套。
6
+ * 写入失败只 warn,不挡 Task 终态 / HITL(与 Span 采集同一策略)。
7
+ */
8
+ import type { RuntimeEvent } from '../graph/contracts/executable-graph.js';
9
+ import type { TokenUsageRecord } from '../task/contracts/task-manager.contract.js';
10
+ export interface TaskTokenUsageWriter {
11
+ recordTokenUsage(taskId: string, usage: TokenUsageRecord): Promise<void>;
12
+ }
13
+ export declare function tokenUsageFromNodePayload(payload: unknown): TokenUsageRecord | undefined;
14
+ export declare function collectStreamNodeTokenUsage(event: Pick<RuntimeEvent, 'type' | 'payload'>, bucket: TokenUsageRecord[]): void;
15
+ export declare function recordTaskTokenUsages(taskService: TaskTokenUsageWriter, taskId: string, usages: Array<{
16
+ nodeId: string;
17
+ model: string;
18
+ inputTokens: number;
19
+ outputTokens: number;
20
+ costEstimate?: number;
21
+ }>): Promise<void>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Task.token_usage 写入:invoke / stream / HITL resume / fork 同一收口。
3
+ *
4
+ * 假设:一次 LLM 调用产生一条 TokenUsageRecord(nodeId + model + in/out)。
5
+ * 来源可以是 Graph.perNode,也可以是 SSE stats.node_token_usage,字段同一套。
6
+ * 写入失败只 warn,不挡 Task 终态 / HITL(与 Span 采集同一策略)。
7
+ */
8
+ import { emitRuntimeLog } from '../common/logger.js';
9
+ export function tokenUsageFromNodePayload(payload) {
10
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload))
11
+ return undefined;
12
+ const record = payload;
13
+ const inputTokens = Number(record['inputTokens'] ?? 0);
14
+ const outputTokens = Number(record['outputTokens'] ?? 0);
15
+ if (!Number.isFinite(inputTokens) || !Number.isFinite(outputTokens))
16
+ return undefined;
17
+ return {
18
+ nodeId: typeof record['nodeId'] === 'string' && record['nodeId'] ? record['nodeId'] : 'unknown',
19
+ model: typeof record['model'] === 'string' && record['model'] ? record['model'] : 'unknown',
20
+ inputTokens,
21
+ outputTokens,
22
+ costEstimate: Number(record['costEstimate'] ?? 0) || 0,
23
+ };
24
+ }
25
+ export function collectStreamNodeTokenUsage(event, bucket) {
26
+ if (event.type !== 'stats.node_token_usage')
27
+ return;
28
+ const usage = tokenUsageFromNodePayload(event.payload);
29
+ if (usage)
30
+ bucket.push(usage);
31
+ }
32
+ export async function recordTaskTokenUsages(taskService, taskId, usages) {
33
+ for (const usage of usages) {
34
+ try {
35
+ await taskService.recordTokenUsage(taskId, {
36
+ nodeId: usage.nodeId,
37
+ model: usage.model,
38
+ inputTokens: usage.inputTokens,
39
+ outputTokens: usage.outputTokens,
40
+ costEstimate: usage.costEstimate ?? 0,
41
+ });
42
+ }
43
+ catch (err) {
44
+ emitRuntimeLog('warn', 'runtime.token', 'task token usage persist failed', {
45
+ event: 'runtime.token.persist_failed',
46
+ taskId,
47
+ nodeId: usage.nodeId,
48
+ error: err instanceof Error ? err.message : String(err),
49
+ });
50
+ }
51
+ }
52
+ }
@@ -67,6 +67,8 @@ export declare class TokenStatsService {
67
67
  * @param usage - 本次调用的 Token 消耗数据
68
68
  */
69
69
  record(taskId: string, usage: NodeTokenUsage): void;
70
+ /** 按记录顺序返回本 Task 的每次 LLM 用量(写入 Task.token_usage 用) */
71
+ list(taskId: string): NodeTokenUsage[];
70
72
  /**
71
73
  * 获取 Task 级聚合统计
72
74
  *
@@ -35,6 +35,10 @@ export class TokenStatsService {
35
35
  this.usageStore.set(taskId, [usage]);
36
36
  }
37
37
  }
38
+ /** 按记录顺序返回本 Task 的每次 LLM 用量(写入 Task.token_usage 用) */
39
+ list(taskId) {
40
+ return [...(this.usageStore.get(taskId) ?? [])];
41
+ }
38
42
  /**
39
43
  * 获取 Task 级聚合统计
40
44
  *
@@ -1,5 +1,5 @@
1
1
  export type { AuthContext, ToolCallRequest, ToolCallResult, LLMToolCall, LLMToolCallResponse, IToolExecutor, McpListedTool, } from './tool-executor.interface.js';
2
- export { hydrateMcpTools, isMcpDiscoverStub, needsMcpHydration, parseListedTools, } from './mcp-list.js';
2
+ export { hydrateMcpTools, isMcpDiscoverStub, needsMcpHydration, parseListedTools, toolsetCodeFromLoaded, toolTraceIdentity, } from './mcp-list.js';
3
3
  export { toLoadedToolMap, type LoadedToolDefinition, type LoadedToolMap, type LoadedToolManifestRef, } from './loaded-tool-definition.js';
4
4
  export { ToolOrchestrator } from './tool-orchestrator.js';
5
5
  export { HttpToolExecutor, type HttpToolExecutorOptions, } from './http-tool-executor.js';
@@ -1,4 +1,4 @@
1
- export { hydrateMcpTools, isMcpDiscoverStub, needsMcpHydration, parseListedTools, } from './mcp-list.js';
1
+ export { hydrateMcpTools, isMcpDiscoverStub, needsMcpHydration, parseListedTools, toolsetCodeFromLoaded, toolTraceIdentity, } from './mcp-list.js';
2
2
  export { toLoadedToolMap, } from './loaded-tool-definition.js';
3
3
  export { ToolOrchestrator } from './tool-orchestrator.js';
4
4
  export { HttpToolExecutor, } from './http-tool-executor.js';
@@ -32,6 +32,18 @@ export declare function toolsetCodeFromLoaded(loaded: {
32
32
  id?: string;
33
33
  };
34
34
  } | undefined): string | undefined;
35
+ /** Tool Span:工具集 code + 声明版本。与 Skill 的 skillSpace/version 同一假设。 */
36
+ export declare function toolTraceIdentity(loaded: {
37
+ toolId?: string;
38
+ name?: string;
39
+ manifest?: {
40
+ id?: string;
41
+ version?: string;
42
+ };
43
+ } | undefined, toolName: string): {
44
+ toolset?: string;
45
+ toolVersion?: string;
46
+ };
35
47
  export interface HydrateMcpToolsAuth {
36
48
  authContext: AuthContext;
37
49
  correlationId?: string;
@@ -84,6 +84,21 @@ export function toolsetCodeFromLoaded(loaded) {
84
84
  }
85
85
  return undefined;
86
86
  }
87
+ function declaredToolVersion(toolName, version) {
88
+ const raw = version?.trim();
89
+ if (!raw || raw === toolName)
90
+ return undefined;
91
+ return raw;
92
+ }
93
+ /** Tool Span:工具集 code + 声明版本。与 Skill 的 skillSpace/version 同一假设。 */
94
+ export function toolTraceIdentity(loaded, toolName) {
95
+ const toolset = toolsetCodeFromLoaded(loaded);
96
+ const toolVersion = declaredToolVersion(toolName, loaded?.manifest?.version);
97
+ return {
98
+ ...(toolset ? { toolset } : {}),
99
+ ...(toolVersion ? { toolVersion } : {}),
100
+ };
101
+ }
87
102
  /**
88
103
  * 将 MCP discover stub 替换为 tools/list 结果。
89
104
  * 无 stub 时原样返回(同一引用)。按 endpoint+user+agent 在执行器内缓存 list。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gt-fe/eap-runtime",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "Enterprise Agent Platform — Runtime核心:Graph执行引擎、Task生命周期、Session管理、Checkpoint持久化",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",