@looopy-ai/core 1.0.1

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 (132) hide show
  1. package/LICENSE +9 -0
  2. package/dist/core/agent.d.ts +53 -0
  3. package/dist/core/agent.js +416 -0
  4. package/dist/core/cleanup.d.ts +12 -0
  5. package/dist/core/cleanup.js +45 -0
  6. package/dist/core/index.d.ts +3 -0
  7. package/dist/core/index.js +3 -0
  8. package/dist/core/iteration.d.ts +5 -0
  9. package/dist/core/iteration.js +60 -0
  10. package/dist/core/logger.d.ts +11 -0
  11. package/dist/core/logger.js +31 -0
  12. package/dist/core/loop.d.ts +5 -0
  13. package/dist/core/loop.js +125 -0
  14. package/dist/core/tools.d.ts +4 -0
  15. package/dist/core/tools.js +78 -0
  16. package/dist/core/types.d.ts +30 -0
  17. package/dist/core/types.js +1 -0
  18. package/dist/events/index.d.ts +3 -0
  19. package/dist/events/index.js +2 -0
  20. package/dist/events/utils.d.ts +250 -0
  21. package/dist/events/utils.js +263 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.js +8 -0
  24. package/dist/observability/index.d.ts +1 -0
  25. package/dist/observability/index.js +1 -0
  26. package/dist/observability/spans/agent-turn.d.ts +31 -0
  27. package/dist/observability/spans/agent-turn.js +94 -0
  28. package/dist/observability/spans/index.d.ts +5 -0
  29. package/dist/observability/spans/index.js +5 -0
  30. package/dist/observability/spans/iteration.d.ts +14 -0
  31. package/dist/observability/spans/iteration.js +41 -0
  32. package/dist/observability/spans/llm-call.d.ts +14 -0
  33. package/dist/observability/spans/llm-call.js +50 -0
  34. package/dist/observability/spans/loop.d.ts +14 -0
  35. package/dist/observability/spans/loop.js +40 -0
  36. package/dist/observability/spans/tool.d.ts +14 -0
  37. package/dist/observability/spans/tool.js +44 -0
  38. package/dist/observability/tracing.d.ts +58 -0
  39. package/dist/observability/tracing.js +203 -0
  40. package/dist/providers/chat-completions/aggregate.d.ts +4 -0
  41. package/dist/providers/chat-completions/aggregate.js +152 -0
  42. package/dist/providers/chat-completions/content.d.ts +25 -0
  43. package/dist/providers/chat-completions/content.js +229 -0
  44. package/dist/providers/chat-completions/index.d.ts +4 -0
  45. package/dist/providers/chat-completions/index.js +4 -0
  46. package/dist/providers/chat-completions/streaming.d.ts +12 -0
  47. package/dist/providers/chat-completions/streaming.js +3 -0
  48. package/dist/providers/chat-completions/types.d.ts +39 -0
  49. package/dist/providers/chat-completions/types.js +1 -0
  50. package/dist/providers/index.d.ts +2 -0
  51. package/dist/providers/index.js +1 -0
  52. package/dist/providers/litellm-provider.d.ts +43 -0
  53. package/dist/providers/litellm-provider.js +377 -0
  54. package/dist/server/event-buffer.d.ts +37 -0
  55. package/dist/server/event-buffer.js +116 -0
  56. package/dist/server/event-router.d.ts +31 -0
  57. package/dist/server/event-router.js +91 -0
  58. package/dist/server/index.d.ts +3 -0
  59. package/dist/server/index.js +3 -0
  60. package/dist/server/sse.d.ts +60 -0
  61. package/dist/server/sse.js +159 -0
  62. package/dist/stores/artifacts/artifact-scheduler.d.ts +50 -0
  63. package/dist/stores/artifacts/artifact-scheduler.js +86 -0
  64. package/dist/stores/artifacts/index.d.ts +3 -0
  65. package/dist/stores/artifacts/index.js +3 -0
  66. package/dist/stores/artifacts/internal-event-artifact-store.d.ts +54 -0
  67. package/dist/stores/artifacts/internal-event-artifact-store.js +126 -0
  68. package/dist/stores/artifacts/memory-artifact-store.d.ts +52 -0
  69. package/dist/stores/artifacts/memory-artifact-store.js +268 -0
  70. package/dist/stores/filesystem/filesystem-agent-store.d.ts +18 -0
  71. package/dist/stores/filesystem/filesystem-agent-store.js +61 -0
  72. package/dist/stores/filesystem/filesystem-artifact-store.d.ts +59 -0
  73. package/dist/stores/filesystem/filesystem-artifact-store.js +325 -0
  74. package/dist/stores/filesystem/filesystem-context-store.d.ts +37 -0
  75. package/dist/stores/filesystem/filesystem-context-store.js +245 -0
  76. package/dist/stores/filesystem/filesystem-message-store.d.ts +28 -0
  77. package/dist/stores/filesystem/filesystem-message-store.js +149 -0
  78. package/dist/stores/filesystem/filesystem-task-state-store.d.ts +27 -0
  79. package/dist/stores/filesystem/filesystem-task-state-store.js +220 -0
  80. package/dist/stores/filesystem/index.d.ts +10 -0
  81. package/dist/stores/filesystem/index.js +5 -0
  82. package/dist/stores/index.d.ts +5 -0
  83. package/dist/stores/index.js +5 -0
  84. package/dist/stores/memory/memory-state-store.d.ts +15 -0
  85. package/dist/stores/memory/memory-state-store.js +55 -0
  86. package/dist/stores/messages/hybrid-message-store.d.ts +29 -0
  87. package/dist/stores/messages/hybrid-message-store.js +72 -0
  88. package/dist/stores/messages/index.d.ts +4 -0
  89. package/dist/stores/messages/index.js +4 -0
  90. package/dist/stores/messages/interfaces.d.ts +42 -0
  91. package/dist/stores/messages/interfaces.js +18 -0
  92. package/dist/stores/messages/mem0-message-store.d.ts +34 -0
  93. package/dist/stores/messages/mem0-message-store.js +218 -0
  94. package/dist/stores/messages/memory-message-store.d.ts +27 -0
  95. package/dist/stores/messages/memory-message-store.js +183 -0
  96. package/dist/tools/artifact-tools.d.ts +4 -0
  97. package/dist/tools/artifact-tools.js +277 -0
  98. package/dist/tools/client-tool-provider.d.ts +25 -0
  99. package/dist/tools/client-tool-provider.js +139 -0
  100. package/dist/tools/index.d.ts +4 -0
  101. package/dist/tools/index.js +4 -0
  102. package/dist/tools/local-tools.d.ts +13 -0
  103. package/dist/tools/local-tools.js +70 -0
  104. package/dist/tools/mcp-client.d.ts +29 -0
  105. package/dist/tools/mcp-client.js +62 -0
  106. package/dist/tools/mcp-tool-provider.d.ts +22 -0
  107. package/dist/tools/mcp-tool-provider.js +86 -0
  108. package/dist/types/a2a.d.ts +36 -0
  109. package/dist/types/a2a.js +1 -0
  110. package/dist/types/agent.d.ts +14 -0
  111. package/dist/types/agent.js +1 -0
  112. package/dist/types/artifact.d.ts +126 -0
  113. package/dist/types/artifact.js +1 -0
  114. package/dist/types/context.d.ts +13 -0
  115. package/dist/types/context.js +1 -0
  116. package/dist/types/event.d.ts +360 -0
  117. package/dist/types/event.js +30 -0
  118. package/dist/types/index.d.ts +9 -0
  119. package/dist/types/index.js +9 -0
  120. package/dist/types/llm.d.ts +24 -0
  121. package/dist/types/llm.js +1 -0
  122. package/dist/types/message.d.ts +9 -0
  123. package/dist/types/message.js +1 -0
  124. package/dist/types/state.d.ts +86 -0
  125. package/dist/types/state.js +1 -0
  126. package/dist/types/tools.d.ts +57 -0
  127. package/dist/types/tools.js +53 -0
  128. package/dist/utils/error.d.ts +8 -0
  129. package/dist/utils/error.js +23 -0
  130. package/dist/utils/process-signals.d.ts +3 -0
  131. package/dist/utils/process-signals.js +67 -0
  132. package/package.json +54 -0
@@ -0,0 +1,24 @@
1
+ import type { Observable } from 'rxjs';
2
+ import type { AnyEvent, LLMEvent } from './event';
3
+ import type { Message } from './message';
4
+ import type { ToolCall, ToolDefinition } from './tools';
5
+ export interface LLMProvider {
6
+ call(request: {
7
+ messages: Message[];
8
+ tools?: ToolDefinition[];
9
+ stream?: boolean;
10
+ sessionId?: string;
11
+ }): Observable<LLMEvent<AnyEvent>>;
12
+ }
13
+ export interface LLMResponse {
14
+ message: Message;
15
+ toolCalls?: ToolCall[];
16
+ finished: boolean;
17
+ finishReason?: 'stop' | 'length' | 'tool_calls' | 'content_filter';
18
+ model?: string;
19
+ usage?: {
20
+ promptTokens?: number;
21
+ completionTokens?: number;
22
+ totalTokens?: number;
23
+ };
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { ToolCall } from './tools';
2
+ export interface Message {
3
+ role: 'system' | 'user' | 'assistant' | 'tool';
4
+ content: string;
5
+ name?: string;
6
+ toolCallId?: string;
7
+ toolCalls?: ToolCall[];
8
+ contentDelta?: string;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,86 @@
1
+ import type { LLMResponse } from './llm';
2
+ import type { Message } from './message';
3
+ import type { ToolCall, ToolDefinition, ToolResult } from './tools';
4
+ export interface PersistedLoopState {
5
+ taskId: string;
6
+ agentId: string;
7
+ parentTaskId?: string;
8
+ contextId: string;
9
+ messages: Message[];
10
+ systemPrompt: string;
11
+ iteration: number;
12
+ completed: boolean;
13
+ availableTools: ToolDefinition[];
14
+ pendingToolCalls: ToolCall[];
15
+ completedToolCalls: Record<string, ToolResult>;
16
+ artifactIds: string[];
17
+ lastLLMResponse?: LLMResponse;
18
+ lastActivity: string;
19
+ resumeFrom: 'llm-call' | 'tool-execution' | 'sub-agent' | 'completed';
20
+ checkpointMetadata?: Record<string, unknown>;
21
+ }
22
+ export interface TaskStateStore {
23
+ save(taskId: string, state: PersistedLoopState): Promise<void>;
24
+ load(taskId: string): Promise<PersistedLoopState | null>;
25
+ exists(taskId: string): Promise<boolean>;
26
+ delete(taskId: string): Promise<void>;
27
+ listTasks(filter?: {
28
+ agentId?: string;
29
+ contextId?: string;
30
+ completedAfter?: Date;
31
+ }): Promise<string[]>;
32
+ setTTL(taskId: string, ttlSeconds: number): Promise<void>;
33
+ }
34
+ export interface ContextState {
35
+ contextId: string;
36
+ agentId: string;
37
+ title?: string;
38
+ description?: string;
39
+ tags?: string[];
40
+ status: 'active' | 'paused' | 'locked' | 'completed' | 'abandoned';
41
+ createdAt: string;
42
+ updatedAt: string;
43
+ lastActivityAt: string;
44
+ turnCount: number;
45
+ currentTurnId?: string;
46
+ pendingToolCalls?: ToolCall[];
47
+ pendingSubAgents?: string[];
48
+ lockedBy?: string;
49
+ lockedAt?: string;
50
+ lockExpiresAt?: string;
51
+ ownerId?: string;
52
+ sharedWith?: string[];
53
+ permissions?: Record<string, string[]>;
54
+ systemPrompt?: string;
55
+ preferredModel?: string;
56
+ messageCount?: number;
57
+ artifactCount?: number;
58
+ totalTokensUsed?: number;
59
+ metadata?: Record<string, unknown>;
60
+ }
61
+ export interface ContextStore {
62
+ save(state: ContextState): Promise<void>;
63
+ load(contextId: string): Promise<ContextState | null>;
64
+ exists(contextId: string): Promise<boolean>;
65
+ delete(contextId: string): Promise<void>;
66
+ list(filter?: {
67
+ agentId?: string;
68
+ ownerId?: string;
69
+ status?: ContextState['status'];
70
+ tags?: string[];
71
+ createdAfter?: Date;
72
+ createdBefore?: Date;
73
+ updatedAfter?: Date;
74
+ limit?: number;
75
+ offset?: number;
76
+ }): Promise<ContextState[]>;
77
+ search(query: string, filter?: {
78
+ agentId?: string;
79
+ ownerId?: string;
80
+ }): Promise<ContextState[]>;
81
+ acquireLock(contextId: string, lockOwnerId: string, ttlSeconds?: number): Promise<boolean>;
82
+ releaseLock(contextId: string, lockOwnerId: string): Promise<void>;
83
+ refreshLock(contextId: string, lockOwnerId: string, ttlSeconds?: number): Promise<boolean>;
84
+ isLocked(contextId: string): Promise<boolean>;
85
+ update(contextId: string, updates: Partial<Omit<ContextState, 'contextId' | 'agentId' | 'createdAt'>>): Promise<void>;
86
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ import { z } from 'zod';
2
+ import type { ExecutionContext } from './context';
3
+ export interface ToolCall {
4
+ id: string;
5
+ type: 'function';
6
+ function: {
7
+ name: string;
8
+ arguments: Record<string, unknown>;
9
+ };
10
+ }
11
+ export interface ToolResult {
12
+ toolCallId: string;
13
+ toolName: string;
14
+ success: boolean;
15
+ result: unknown;
16
+ error?: string;
17
+ }
18
+ export declare const JsonSchemaPropertySchema: z.ZodType<unknown>;
19
+ export type JsonSchemaProperty = z.infer<typeof JsonSchemaPropertySchema>;
20
+ export declare const FunctionParametersSchema: z.ZodObject<{
21
+ type: z.ZodLiteral<"object">;
22
+ properties: z.ZodRecord<z.ZodString, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
23
+ required: z.ZodOptional<z.ZodArray<z.ZodString>>;
24
+ additionalProperties: z.ZodOptional<z.ZodBoolean>;
25
+ }, z.core.$strip>;
26
+ export type FunctionParameters = z.infer<typeof FunctionParametersSchema>;
27
+ export declare const ToolDefinitionSchema: z.ZodObject<{
28
+ name: z.ZodString;
29
+ description: z.ZodString;
30
+ parameters: z.ZodObject<{
31
+ type: z.ZodLiteral<"object">;
32
+ properties: z.ZodRecord<z.ZodString, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
33
+ required: z.ZodOptional<z.ZodArray<z.ZodString>>;
34
+ additionalProperties: z.ZodOptional<z.ZodBoolean>;
35
+ }, z.core.$strip>;
36
+ }, z.core.$strip>;
37
+ export type ToolDefinition = z.infer<typeof ToolDefinitionSchema>;
38
+ export declare function validateToolDefinitions(tools: unknown): ToolDefinition[];
39
+ export declare function safeValidateToolDefinitions(tools: unknown): {
40
+ success: boolean;
41
+ data?: ToolDefinition[];
42
+ errors?: z.ZodIssue[];
43
+ };
44
+ export declare const ToolCallSchema: z.ZodObject<{
45
+ id: z.ZodString;
46
+ type: z.ZodLiteral<"function">;
47
+ function: z.ZodObject<{
48
+ name: z.ZodString;
49
+ arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
50
+ }, z.core.$strip>;
51
+ }, z.core.$strip>;
52
+ export type ToolProvider = {
53
+ getTools(): Promise<ToolDefinition[]>;
54
+ execute(toolCall: ToolCall, context: ExecutionContext): Promise<ToolResult>;
55
+ canHandle(toolName: string): boolean;
56
+ executeBatch?(toolCalls: ToolCall[], context: ExecutionContext): Promise<ToolResult[]>;
57
+ };
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ export const JsonSchemaPropertySchema = z.lazy(() => z.object({
3
+ type: z.enum(['string', 'number', 'integer', 'boolean', 'array', 'object', 'null']),
4
+ description: z.string().optional(),
5
+ enum: z.array(z.union([z.string(), z.number()])).optional(),
6
+ default: z.unknown().optional(),
7
+ items: JsonSchemaPropertySchema.optional(),
8
+ minItems: z.number().optional(),
9
+ maxItems: z.number().optional(),
10
+ properties: z.record(z.string(), JsonSchemaPropertySchema).optional(),
11
+ required: z.array(z.string()).optional(),
12
+ additionalProperties: z.union([z.boolean(), JsonSchemaPropertySchema]).optional(),
13
+ minLength: z.number().optional(),
14
+ maxLength: z.number().optional(),
15
+ pattern: z.string().optional(),
16
+ format: z.string().optional(),
17
+ minimum: z.number().optional(),
18
+ maximum: z.number().optional(),
19
+ multipleOf: z.number().optional(),
20
+ }));
21
+ export const FunctionParametersSchema = z.object({
22
+ type: z.literal('object'),
23
+ properties: z.record(z.string(), JsonSchemaPropertySchema),
24
+ required: z.array(z.string()).optional(),
25
+ additionalProperties: z.boolean().optional(),
26
+ });
27
+ export const ToolDefinitionSchema = z.object({
28
+ name: z
29
+ .string()
30
+ .min(1)
31
+ .max(64)
32
+ .regex(/^[a-zA-Z0-9_-]+$/, 'Tool name must contain only alphanumeric characters, underscores, and hyphens'),
33
+ description: z.string().min(1).max(1024),
34
+ parameters: FunctionParametersSchema,
35
+ });
36
+ export function validateToolDefinitions(tools) {
37
+ return z.array(ToolDefinitionSchema).parse(tools);
38
+ }
39
+ export function safeValidateToolDefinitions(tools) {
40
+ const result = z.array(ToolDefinitionSchema).safeParse(tools);
41
+ if (result.success) {
42
+ return { success: true, data: result.data };
43
+ }
44
+ return { success: false, errors: result.error.issues };
45
+ }
46
+ export const ToolCallSchema = z.object({
47
+ id: z.string(),
48
+ type: z.literal('function'),
49
+ function: z.object({
50
+ name: z.string(),
51
+ arguments: z.record(z.string(), z.unknown()),
52
+ }),
53
+ });
@@ -0,0 +1,8 @@
1
+ export type SerializedError = {
2
+ name: string;
3
+ message: string;
4
+ stack?: string;
5
+ cause?: SerializedError;
6
+ [key: string]: unknown;
7
+ };
8
+ export declare const serializeError: (error: unknown) => SerializedError;
@@ -0,0 +1,23 @@
1
+ export const serializeError = (error) => {
2
+ if (error instanceof Error) {
3
+ return {
4
+ ...error,
5
+ name: error.name,
6
+ message: error.message,
7
+ stack: error.stack,
8
+ cause: error.cause ? serializeError(error.cause) : undefined,
9
+ };
10
+ }
11
+ if (typeof error === 'object' && error !== null) {
12
+ return {
13
+ name: 'NonErrorObject',
14
+ message: 'An error occurred, but it is not an instance of Error.',
15
+ ...error,
16
+ cause: 'cause' in error && error.cause ? serializeError(error.cause) : undefined,
17
+ };
18
+ }
19
+ return {
20
+ name: 'NonObjectError',
21
+ message: JSON.stringify(error),
22
+ };
23
+ };
@@ -0,0 +1,3 @@
1
+ export type SignalListener = () => void | Promise<void>;
2
+ export declare function registerSignalListener(signal: NodeJS.Signals, listener: SignalListener): void;
3
+ export declare function unregisterSignalListener(signal: NodeJS.Signals, listener: SignalListener): void;
@@ -0,0 +1,67 @@
1
+ import { getLogger } from '../core/logger';
2
+ import { serializeError } from './error';
3
+ const listeners = new Map();
4
+ const processHandlers = new Map();
5
+ const signalLogger = getLogger({ component: 'process-signal-coordinator' });
6
+ function isProcessAvailable() {
7
+ return typeof process !== 'undefined' && typeof process.on === 'function';
8
+ }
9
+ export function registerSignalListener(signal, listener) {
10
+ if (!isProcessAvailable()) {
11
+ return;
12
+ }
13
+ const signalListeners = listeners.get(signal) ?? new Set();
14
+ signalListeners.add(listener);
15
+ listeners.set(signal, signalListeners);
16
+ ensureProcessHandler(signal);
17
+ }
18
+ export function unregisterSignalListener(signal, listener) {
19
+ if (!isProcessAvailable()) {
20
+ return;
21
+ }
22
+ const signalListeners = listeners.get(signal);
23
+ if (!signalListeners) {
24
+ return;
25
+ }
26
+ signalListeners.delete(listener);
27
+ if (signalListeners.size === 0) {
28
+ listeners.delete(signal);
29
+ removeProcessHandler(signal);
30
+ }
31
+ }
32
+ function ensureProcessHandler(signal) {
33
+ if (processHandlers.has(signal)) {
34
+ return;
35
+ }
36
+ const handler = () => {
37
+ const signalListeners = listeners.get(signal);
38
+ if (!signalListeners || signalListeners.size === 0) {
39
+ return;
40
+ }
41
+ signalLogger.info({ signal, listenerCount: signalListeners.size }, 'Received process signal; notifying registered listeners');
42
+ const listenersSnapshot = Array.from(signalListeners);
43
+ void Promise.allSettled(listenersSnapshot.map(async (listener) => {
44
+ try {
45
+ await listener();
46
+ }
47
+ catch (error) {
48
+ signalLogger.error({ signal, error: serializeError(error) }, 'Signal listener failed');
49
+ }
50
+ }));
51
+ };
52
+ process.on(signal, handler);
53
+ processHandlers.set(signal, handler);
54
+ }
55
+ function removeProcessHandler(signal) {
56
+ const handler = processHandlers.get(signal);
57
+ if (!handler) {
58
+ return;
59
+ }
60
+ if (typeof process.off === 'function') {
61
+ process.off(signal, handler);
62
+ }
63
+ else if (typeof process.removeListener === 'function') {
64
+ process.removeListener(signal, handler);
65
+ }
66
+ processHandlers.delete(signal);
67
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@looopy-ai/core",
3
+ "version": "1.0.1",
4
+ "description": "RxJS-based AI agent framework",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./package.json": "./package.json",
14
+ "./ts": "./src/index.ts"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "keywords": [
21
+ "agent",
22
+ "ai",
23
+ "rxjs",
24
+ "a2a",
25
+ "llm"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.207.0",
31
+ "@opentelemetry/exporter-trace-otlp-http": "^0.207.0",
32
+ "@opentelemetry/instrumentation": "^0.207.0",
33
+ "@opentelemetry/resources": "^2.2.0",
34
+ "@opentelemetry/sdk-metrics": "^2.2.0",
35
+ "@opentelemetry/sdk-trace-base": "^2.2.0",
36
+ "@opentelemetry/sdk-trace-node": "^2.2.0",
37
+ "@opentelemetry/semantic-conventions": "^1.37.0",
38
+ "pino-pretty": "^13.1.2"
39
+ },
40
+ "devDependencies": {},
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "scripts": {
45
+ "check:exports": "pnpx ts-unused-exports ./tsconfig.json --excludePathsFromReport='index'",
46
+ "check:types": "tsc --noEmit",
47
+ "test": "CI=true vitest",
48
+ "test:watch": "vitest --watch",
49
+ "test:coverage": "vitest --coverage",
50
+ "build": "tsc -p tsconfig.esm.json",
51
+ "lint": "biome check src tests",
52
+ "lint:fix": "biome check --write src tests"
53
+ }
54
+ }