@awcp/sdk 0.0.0-dev-202601300724
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/delegator/admission.d.ts +49 -0
- package/dist/delegator/admission.d.ts.map +1 -0
- package/dist/delegator/admission.js +117 -0
- package/dist/delegator/admission.js.map +1 -0
- package/dist/delegator/bin/client.d.ts +102 -0
- package/dist/delegator/bin/client.d.ts.map +1 -0
- package/dist/delegator/bin/client.js +116 -0
- package/dist/delegator/bin/client.js.map +1 -0
- package/dist/delegator/bin/daemon.d.ts +78 -0
- package/dist/delegator/bin/daemon.d.ts.map +1 -0
- package/dist/delegator/bin/daemon.js +245 -0
- package/dist/delegator/bin/daemon.js.map +1 -0
- package/dist/delegator/config.d.ts +168 -0
- package/dist/delegator/config.d.ts.map +1 -0
- package/dist/delegator/config.js +54 -0
- package/dist/delegator/config.js.map +1 -0
- package/dist/delegator/executor-client.d.ts +36 -0
- package/dist/delegator/executor-client.d.ts.map +1 -0
- package/dist/delegator/executor-client.js +77 -0
- package/dist/delegator/executor-client.js.map +1 -0
- package/dist/delegator/export-view.d.ts +43 -0
- package/dist/delegator/export-view.d.ts.map +1 -0
- package/dist/delegator/export-view.js +108 -0
- package/dist/delegator/export-view.js.map +1 -0
- package/dist/delegator/index.d.ts +8 -0
- package/dist/delegator/index.d.ts.map +1 -0
- package/dist/delegator/index.js +11 -0
- package/dist/delegator/index.js.map +1 -0
- package/dist/delegator/service.d.ts +120 -0
- package/dist/delegator/service.d.ts.map +1 -0
- package/dist/delegator/service.js +323 -0
- package/dist/delegator/service.js.map +1 -0
- package/dist/executor/config.d.ts +126 -0
- package/dist/executor/config.d.ts.map +1 -0
- package/dist/executor/config.js +38 -0
- package/dist/executor/config.js.map +1 -0
- package/dist/executor/delegator-client.d.ts +18 -0
- package/dist/executor/delegator-client.d.ts.map +1 -0
- package/dist/executor/delegator-client.js +37 -0
- package/dist/executor/delegator-client.js.map +1 -0
- package/dist/executor/index.d.ts +5 -0
- package/dist/executor/index.d.ts.map +1 -0
- package/dist/executor/index.js +7 -0
- package/dist/executor/index.js.map +1 -0
- package/dist/executor/policy.d.ts +55 -0
- package/dist/executor/policy.d.ts.map +1 -0
- package/dist/executor/policy.js +100 -0
- package/dist/executor/policy.js.map +1 -0
- package/dist/executor/service.d.ts +84 -0
- package/dist/executor/service.d.ts.map +1 -0
- package/dist/executor/service.js +322 -0
- package/dist/executor/service.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/server/express/awcp-delegator-handler.d.ts +67 -0
- package/dist/server/express/awcp-delegator-handler.d.ts.map +1 -0
- package/dist/server/express/awcp-delegator-handler.js +99 -0
- package/dist/server/express/awcp-delegator-handler.js.map +1 -0
- package/dist/server/express/awcp-executor-handler.d.ts +47 -0
- package/dist/server/express/awcp-executor-handler.d.ts.map +1 -0
- package/dist/server/express/awcp-executor-handler.js +104 -0
- package/dist/server/express/awcp-executor-handler.js.map +1 -0
- package/dist/server/express/index.d.ts +6 -0
- package/dist/server/express/index.d.ts.map +1 -0
- package/dist/server/express/index.js +8 -0
- package/dist/server/express/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWCP Executor Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configuration for enabling AWCP support in an A2A agent.
|
|
5
|
+
*/
|
|
6
|
+
import type { InviteMessage, SandboxProfile, AccessMode } from '@awcp/core';
|
|
7
|
+
/**
|
|
8
|
+
* Mount configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface MountConfig {
|
|
11
|
+
/** Root directory for mount points, e.g., '/tmp/awcp/mounts' */
|
|
12
|
+
root: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Policy constraints for accepting delegations
|
|
16
|
+
*/
|
|
17
|
+
export interface PolicyConstraints {
|
|
18
|
+
/** Max concurrent delegations (default: 5) */
|
|
19
|
+
maxConcurrentDelegations?: number;
|
|
20
|
+
/** Max TTL in seconds to accept (default: 3600) */
|
|
21
|
+
maxTtlSeconds?: number;
|
|
22
|
+
/** Allowed access modes (default: ['ro', 'rw']) */
|
|
23
|
+
allowedAccessModes?: AccessMode[];
|
|
24
|
+
/** Auto-accept INVITEs without confirmation (default: true) */
|
|
25
|
+
autoAccept?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Lifecycle hooks for AWCP events
|
|
29
|
+
*/
|
|
30
|
+
export interface ExecutorHooks {
|
|
31
|
+
/** Called when INVITE received. Return false to decline. */
|
|
32
|
+
onInvite?: (invite: InviteMessage) => Promise<boolean>;
|
|
33
|
+
/** Called when task execution starts */
|
|
34
|
+
onTaskStart?: (delegationId: string, mountPoint: string) => void;
|
|
35
|
+
/** Called when task completes successfully */
|
|
36
|
+
onTaskComplete?: (delegationId: string, summary: string) => void;
|
|
37
|
+
/** Called on error */
|
|
38
|
+
onError?: (delegationId: string, error: Error) => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* AWCP Executor Configuration
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const awcpConfig: ExecutorConfig = {
|
|
46
|
+
* mount: {
|
|
47
|
+
* root: '/tmp/awcp/mounts',
|
|
48
|
+
* },
|
|
49
|
+
* sandbox: {
|
|
50
|
+
* cwdOnly: true,
|
|
51
|
+
* allowNetwork: true,
|
|
52
|
+
* allowExec: true,
|
|
53
|
+
* },
|
|
54
|
+
* policy: {
|
|
55
|
+
* maxConcurrentDelegations: 3,
|
|
56
|
+
* autoAccept: true,
|
|
57
|
+
* },
|
|
58
|
+
* };
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export interface ExecutorConfig {
|
|
62
|
+
/**
|
|
63
|
+
* Mount configuration (required)
|
|
64
|
+
*
|
|
65
|
+
* Specifies where delegator workspaces will be mounted.
|
|
66
|
+
*/
|
|
67
|
+
mount: MountConfig;
|
|
68
|
+
/**
|
|
69
|
+
* Sandbox profile (optional)
|
|
70
|
+
*
|
|
71
|
+
* Capability declaration sent in ACCEPT message to inform Delegator
|
|
72
|
+
* about this agent's execution constraints.
|
|
73
|
+
*/
|
|
74
|
+
sandbox?: SandboxProfile;
|
|
75
|
+
/**
|
|
76
|
+
* Policy constraints (optional)
|
|
77
|
+
*
|
|
78
|
+
* Rules for accepting or rejecting delegation requests.
|
|
79
|
+
*/
|
|
80
|
+
policy?: PolicyConstraints;
|
|
81
|
+
/**
|
|
82
|
+
* Lifecycle hooks (optional)
|
|
83
|
+
*
|
|
84
|
+
* Callbacks for various AWCP lifecycle events.
|
|
85
|
+
*/
|
|
86
|
+
hooks?: ExecutorHooks;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Default configuration values
|
|
90
|
+
*/
|
|
91
|
+
export declare const DEFAULT_EXECUTOR_CONFIG: {
|
|
92
|
+
readonly policy: {
|
|
93
|
+
readonly maxConcurrentDelegations: 5;
|
|
94
|
+
readonly maxTtlSeconds: 3600;
|
|
95
|
+
readonly allowedAccessModes: AccessMode[];
|
|
96
|
+
readonly autoAccept: true;
|
|
97
|
+
};
|
|
98
|
+
readonly sandbox: {
|
|
99
|
+
readonly cwdOnly: true;
|
|
100
|
+
readonly allowNetwork: true;
|
|
101
|
+
readonly allowExec: true;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Resolved policy with all fields required
|
|
106
|
+
*/
|
|
107
|
+
export interface ResolvedPolicyConstraints {
|
|
108
|
+
maxConcurrentDelegations: number;
|
|
109
|
+
maxTtlSeconds: number;
|
|
110
|
+
allowedAccessModes: AccessMode[];
|
|
111
|
+
autoAccept: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Resolved configuration with all defaults applied
|
|
115
|
+
*/
|
|
116
|
+
export interface ResolvedExecutorConfig {
|
|
117
|
+
mount: MountConfig;
|
|
118
|
+
sandbox: SandboxProfile;
|
|
119
|
+
policy: ResolvedPolicyConstraints;
|
|
120
|
+
hooks: ExecutorHooks;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Merge user config with defaults
|
|
124
|
+
*/
|
|
125
|
+
export declare function resolveExecutorConfig(config: ExecutorConfig): ResolvedExecutorConfig;
|
|
126
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/executor/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,UAAU,EAAE,CAAC;IAClC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,wCAAwC;IACxC,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,8CAA8C;IAC9C,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE,sBAAsB;IACtB,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,KAAK,EAAE,WAAW,CAAC;IAEnB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;qCAII,UAAU,EAAE;;;;;;;;CAQ1C,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,wBAAwB,EAAE,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,sBAAsB,CAYpF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWCP Executor Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configuration for enabling AWCP support in an A2A agent.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Default configuration values
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_EXECUTOR_CONFIG = {
|
|
10
|
+
policy: {
|
|
11
|
+
maxConcurrentDelegations: 5,
|
|
12
|
+
maxTtlSeconds: 3600,
|
|
13
|
+
allowedAccessModes: ['ro', 'rw'],
|
|
14
|
+
autoAccept: true,
|
|
15
|
+
},
|
|
16
|
+
sandbox: {
|
|
17
|
+
cwdOnly: true,
|
|
18
|
+
allowNetwork: true,
|
|
19
|
+
allowExec: true,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Merge user config with defaults
|
|
24
|
+
*/
|
|
25
|
+
export function resolveExecutorConfig(config) {
|
|
26
|
+
return {
|
|
27
|
+
mount: config.mount,
|
|
28
|
+
sandbox: config.sandbox ?? { ...DEFAULT_EXECUTOR_CONFIG.sandbox },
|
|
29
|
+
policy: {
|
|
30
|
+
maxConcurrentDelegations: config.policy?.maxConcurrentDelegations ?? DEFAULT_EXECUTOR_CONFIG.policy.maxConcurrentDelegations,
|
|
31
|
+
maxTtlSeconds: config.policy?.maxTtlSeconds ?? DEFAULT_EXECUTOR_CONFIG.policy.maxTtlSeconds,
|
|
32
|
+
allowedAccessModes: config.policy?.allowedAccessModes ?? [...DEFAULT_EXECUTOR_CONFIG.policy.allowedAccessModes],
|
|
33
|
+
autoAccept: config.policy?.autoAccept ?? DEFAULT_EXECUTOR_CONFIG.policy.autoAccept,
|
|
34
|
+
},
|
|
35
|
+
hooks: config.hooks ?? {},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/executor/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4FH;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,MAAM,EAAE;QACN,wBAAwB,EAAE,CAAC;QAC3B,aAAa,EAAE,IAAI;QACnB,kBAAkB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAiB;QAChD,UAAU,EAAE,IAAI;KACjB;IACD,OAAO,EAAE;QACP,OAAO,EAAE,IAAI;QACb,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,IAAI;KAChB;CACO,CAAC;AAsBX;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAsB;IAC1D,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,GAAG,uBAAuB,CAAC,OAAO,EAAE;QACjE,MAAM,EAAE;YACN,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,IAAI,uBAAuB,CAAC,MAAM,CAAC,wBAAwB;YAC5H,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,IAAI,uBAAuB,CAAC,MAAM,CAAC,aAAa;YAC3F,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,IAAI,CAAC,GAAG,uBAAuB,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC/G,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,IAAI,uBAAuB,CAAC,MAAM,CAAC,UAAU;SACnF;QACD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Client for sending AWCP messages to Delegator
|
|
3
|
+
*/
|
|
4
|
+
import type { AwcpMessage } from '@awcp/core';
|
|
5
|
+
/**
|
|
6
|
+
* Client for sending AWCP messages back to the Delegator daemon
|
|
7
|
+
*/
|
|
8
|
+
export declare class DelegatorClient {
|
|
9
|
+
private timeout;
|
|
10
|
+
constructor(options?: {
|
|
11
|
+
timeout?: number;
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Send an AWCP message to the Delegator
|
|
15
|
+
*/
|
|
16
|
+
send(delegatorUrl: string, message: AwcpMessage): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=delegator-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegator-client.d.ts","sourceRoot":"","sources":["../../src/executor/delegator-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAI1C;;OAEG;IACG,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAwBtE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Client for sending AWCP messages to Delegator
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Client for sending AWCP messages back to the Delegator daemon
|
|
6
|
+
*/
|
|
7
|
+
export class DelegatorClient {
|
|
8
|
+
timeout;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.timeout = options?.timeout ?? 30000;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Send an AWCP message to the Delegator
|
|
14
|
+
*/
|
|
15
|
+
async send(delegatorUrl, message) {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
18
|
+
try {
|
|
19
|
+
const response = await fetch(delegatorUrl, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify(message),
|
|
25
|
+
signal: controller.signal,
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const text = await response.text().catch(() => '');
|
|
29
|
+
throw new Error(`Failed to send ${message.type} to delegator: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=delegator-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegator-client.js","sourceRoot":"","sources":["../../src/executor/delegator-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IAExB,YAAY,OAA8B;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,YAAoB,EAAE,OAAoB;QACnD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAErE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE;gBACzC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAC7B,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnD,MAAM,IAAI,KAAK,CACb,kBAAkB,OAAO,CAAC,IAAI,kBAAkB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACpH,CAAC;YACJ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ExecutorService, type ExecutorServiceOptions, type ExecutorServiceStatus } from './service.js';
|
|
2
|
+
export { type ExecutorConfig, type MountConfig, type PolicyConstraints, type ExecutorHooks, type ResolvedExecutorConfig, DEFAULT_EXECUTOR_CONFIG, resolveExecutorConfig, } from './config.js';
|
|
3
|
+
export { LocalPolicy, type PolicyConfig, type MountPointValidation } from './policy.js';
|
|
4
|
+
export { DelegatorClient } from './delegator-client.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// High-level API
|
|
2
|
+
export { ExecutorService } from './service.js';
|
|
3
|
+
export { DEFAULT_EXECUTOR_CONFIG, resolveExecutorConfig, } from './config.js';
|
|
4
|
+
// Utilities (can be used independently)
|
|
5
|
+
export { LocalPolicy } from './policy.js';
|
|
6
|
+
export { DelegatorClient } from './delegator-client.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,OAAO,EAAE,eAAe,EAA2D,MAAM,cAAc,CAAC;AACxG,OAAO,EAML,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,wCAAwC;AACxC,OAAO,EAAE,WAAW,EAAgD,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local policy configuration
|
|
3
|
+
*/
|
|
4
|
+
export interface PolicyConfig {
|
|
5
|
+
/** Base directory for mount points (default: /tmp/awcp/mounts) */
|
|
6
|
+
mountRoot?: string;
|
|
7
|
+
/** Maximum concurrent delegations */
|
|
8
|
+
maxConcurrent?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Mount point validation result
|
|
12
|
+
*/
|
|
13
|
+
export interface MountPointValidation {
|
|
14
|
+
valid: boolean;
|
|
15
|
+
reason?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Local Policy - Enforces security constraints on the Executor side.
|
|
19
|
+
*
|
|
20
|
+
* Security: startsWith(root) check prevents path traversal attacks.
|
|
21
|
+
*/
|
|
22
|
+
export declare class LocalPolicy {
|
|
23
|
+
private config;
|
|
24
|
+
private allocatedMounts;
|
|
25
|
+
constructor(config?: PolicyConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Allocate a mount point for a delegation
|
|
28
|
+
*/
|
|
29
|
+
allocateMountPoint(delegationId: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Validate that a mount point is safe to use
|
|
32
|
+
*/
|
|
33
|
+
validateMountPoint(mountPoint: string): Promise<MountPointValidation>;
|
|
34
|
+
/**
|
|
35
|
+
* Prepare a mount point (create directory, ensure empty)
|
|
36
|
+
*/
|
|
37
|
+
prepareMountPoint(mountPoint: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Release a mount point and remove the directory
|
|
40
|
+
*/
|
|
41
|
+
releaseMountPoint(mountPoint: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Cleanup stale mount directories from previous runs
|
|
44
|
+
*/
|
|
45
|
+
cleanupStaleMounts(): Promise<number>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if concurrent limit is reached
|
|
48
|
+
*/
|
|
49
|
+
canAcceptMore(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Get currently allocated mount points
|
|
52
|
+
*/
|
|
53
|
+
getAllocatedMounts(): string[];
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/executor/policy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAAqB;gBAEhC,MAAM,CAAC,EAAE,YAAY;IAIjC;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAOhD;;OAEG;IACG,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAa3E;;OAEG;IACG,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D;;OAEG;IACG,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;IAuB3C;;OAEG;IACH,aAAa,IAAI,OAAO;IAKxB;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;CAG/B"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { mkdir, readdir, rm } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Default mount root directory
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_MOUNT_ROOT = '/tmp/awcp/mounts';
|
|
7
|
+
/**
|
|
8
|
+
* Local Policy - Enforces security constraints on the Executor side.
|
|
9
|
+
*
|
|
10
|
+
* Security: startsWith(root) check prevents path traversal attacks.
|
|
11
|
+
*/
|
|
12
|
+
export class LocalPolicy {
|
|
13
|
+
config;
|
|
14
|
+
allocatedMounts = new Set();
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config ?? {};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Allocate a mount point for a delegation
|
|
20
|
+
*/
|
|
21
|
+
allocateMountPoint(delegationId) {
|
|
22
|
+
const root = this.config.mountRoot ?? DEFAULT_MOUNT_ROOT;
|
|
23
|
+
const mountPoint = join(root, delegationId);
|
|
24
|
+
this.allocatedMounts.add(mountPoint);
|
|
25
|
+
return mountPoint;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate that a mount point is safe to use
|
|
29
|
+
*/
|
|
30
|
+
async validateMountPoint(mountPoint) {
|
|
31
|
+
const root = this.config.mountRoot ?? DEFAULT_MOUNT_ROOT;
|
|
32
|
+
if (!mountPoint.startsWith(root)) {
|
|
33
|
+
return {
|
|
34
|
+
valid: false,
|
|
35
|
+
reason: `Mount point must be under ${root}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { valid: true };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Prepare a mount point (create directory, ensure empty)
|
|
42
|
+
*/
|
|
43
|
+
async prepareMountPoint(mountPoint) {
|
|
44
|
+
await mkdir(mountPoint, { recursive: true });
|
|
45
|
+
const entries = await readdir(mountPoint);
|
|
46
|
+
if (entries.length > 0) {
|
|
47
|
+
throw new Error(`Mount point ${mountPoint} is not empty`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Release a mount point and remove the directory
|
|
52
|
+
*/
|
|
53
|
+
async releaseMountPoint(mountPoint) {
|
|
54
|
+
this.allocatedMounts.delete(mountPoint);
|
|
55
|
+
try {
|
|
56
|
+
await rm(mountPoint, { recursive: true, force: true });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Ignore errors - directory may already be gone
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Cleanup stale mount directories from previous runs
|
|
64
|
+
*/
|
|
65
|
+
async cleanupStaleMounts() {
|
|
66
|
+
const root = this.config.mountRoot ?? DEFAULT_MOUNT_ROOT;
|
|
67
|
+
let cleaned = 0;
|
|
68
|
+
try {
|
|
69
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
const mountPath = join(root, entry.name);
|
|
73
|
+
// Only clean directories not currently allocated
|
|
74
|
+
if (!this.allocatedMounts.has(mountPath)) {
|
|
75
|
+
await rm(mountPath, { recursive: true, force: true });
|
|
76
|
+
cleaned++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Root directory may not exist yet
|
|
83
|
+
}
|
|
84
|
+
return cleaned;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if concurrent limit is reached
|
|
88
|
+
*/
|
|
89
|
+
canAcceptMore() {
|
|
90
|
+
const max = this.config.maxConcurrent ?? Infinity;
|
|
91
|
+
return this.allocatedMounts.size < max;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get currently allocated mount points
|
|
95
|
+
*/
|
|
96
|
+
getAllocatedMounts() {
|
|
97
|
+
return Array.from(this.allocatedMounts);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/executor/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC;;GAEG;AACH,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,OAAO,WAAW;IACd,MAAM,CAAe;IACrB,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE5C,YAAY,MAAqB;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,YAAoB;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,kBAAkB,CAAC;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC5C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,UAAkB;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,kBAAkB,CAAC;QAEzD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,6BAA6B,IAAI,EAAE;aAC5C,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,UAAkB;QACxC,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,eAAe,UAAU,eAAe,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,UAAkB;QACxC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,kBAAkB,CAAC;QACzD,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBACzC,iDAAiD;oBACjD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;wBACzC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;wBACtD,OAAO,EAAE,CAAC;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,aAAa;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,QAAQ,CAAC;QAClD,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,GAAG,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWCP Executor Service
|
|
3
|
+
*
|
|
4
|
+
* Handles the AWCP delegation protocol on the Executor (Collaborator) side.
|
|
5
|
+
* Integrates with A2A SDK executor for task execution.
|
|
6
|
+
*/
|
|
7
|
+
import { type AgentExecutor } from '@a2a-js/sdk/server';
|
|
8
|
+
import { type AwcpMessage } from '@awcp/core';
|
|
9
|
+
import { type ExecutorConfig } from './config.js';
|
|
10
|
+
/**
|
|
11
|
+
* Executor service status
|
|
12
|
+
*/
|
|
13
|
+
export interface ExecutorServiceStatus {
|
|
14
|
+
pendingInvitations: number;
|
|
15
|
+
activeDelegations: number;
|
|
16
|
+
delegations: Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
mountPoint: string;
|
|
19
|
+
startedAt: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Options for creating the service
|
|
24
|
+
*/
|
|
25
|
+
export interface ExecutorServiceOptions {
|
|
26
|
+
/** A2A agent executor */
|
|
27
|
+
executor: AgentExecutor;
|
|
28
|
+
/** AWCP configuration */
|
|
29
|
+
config: ExecutorConfig;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* AWCP Executor Service
|
|
33
|
+
*
|
|
34
|
+
* Manages the AWCP delegation lifecycle:
|
|
35
|
+
* 1. Receives INVITE from Delegator
|
|
36
|
+
* 2. Sends ACCEPT back
|
|
37
|
+
* 3. Receives START with credentials
|
|
38
|
+
* 4. Mounts workspace via SSHFS
|
|
39
|
+
* 5. Executes task via A2A executor
|
|
40
|
+
* 6. Unmounts and sends DONE/ERROR
|
|
41
|
+
*/
|
|
42
|
+
export declare class ExecutorService {
|
|
43
|
+
private executor;
|
|
44
|
+
private config;
|
|
45
|
+
private policy;
|
|
46
|
+
private sshfsClient;
|
|
47
|
+
private delegatorClient;
|
|
48
|
+
private pendingInvitations;
|
|
49
|
+
private activeDelegations;
|
|
50
|
+
constructor(options: ExecutorServiceOptions);
|
|
51
|
+
/**
|
|
52
|
+
* Handle incoming AWCP message from Delegator
|
|
53
|
+
*/
|
|
54
|
+
handleMessage(message: AwcpMessage, delegatorUrl: string): Promise<AwcpMessage | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Handle INVITE message
|
|
57
|
+
*/
|
|
58
|
+
private handleInvite;
|
|
59
|
+
/**
|
|
60
|
+
* Handle START message
|
|
61
|
+
*/
|
|
62
|
+
private handleStart;
|
|
63
|
+
/**
|
|
64
|
+
* Handle ERROR message from Delegator
|
|
65
|
+
*/
|
|
66
|
+
private handleError;
|
|
67
|
+
/**
|
|
68
|
+
* Cancel a delegation (called by Delegator via /cancel endpoint)
|
|
69
|
+
*/
|
|
70
|
+
cancelDelegation(delegationId: string): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Execute task via A2A executor
|
|
73
|
+
*/
|
|
74
|
+
private executeViaA2A;
|
|
75
|
+
/**
|
|
76
|
+
* Get service status
|
|
77
|
+
*/
|
|
78
|
+
getStatus(): ExecutorServiceStatus;
|
|
79
|
+
/**
|
|
80
|
+
* Create an error message
|
|
81
|
+
*/
|
|
82
|
+
private createErrorMessage;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/executor/service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAML,KAAK,WAAW,EAMjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,cAAc,EAAsD,MAAM,aAAa,CAAC;AAwBtG;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,yBAAyB;IACzB,QAAQ,EAAE,aAAa,CAAC;IACxB,yBAAyB;IACzB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,kBAAkB,CAAwC;IAClE,OAAO,CAAC,iBAAiB,CAAuC;gBAEpD,OAAO,EAAE,sBAAsB;IAW3C;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAe9B;;OAEG;YACW,YAAY;IAqH1B;;OAEG;YACW,WAAW;IAsFzB;;OAEG;YACW,WAAW;IAqBzB;;OAEG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB3D;;OAEG;YACW,aAAa;IAgD3B;;OAEG;IACH,SAAS,IAAI,qBAAqB;IAYlC;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAe3B"}
|