@easynet-run/node 0.27.14

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 (61) hide show
  1. package/README.md +135 -0
  2. package/native/dendrite-bridge-manifest.json +38 -0
  3. package/native/dendrite-bridge.json +15 -0
  4. package/native/include/axon_dendrite_bridge.h +460 -0
  5. package/native/libaxon_dendrite_bridge.so +0 -0
  6. package/package.json +67 -0
  7. package/runtime/easynet-runtime-rs-0.27.14-x86_64-unknown-linux-gnu.tar.gz +0 -0
  8. package/runtime/runtime-bridge-manifest.json +20 -0
  9. package/runtime/runtime-bridge.json +9 -0
  10. package/src/ability_lifecycle.d.ts +140 -0
  11. package/src/ability_lifecycle.js +525 -0
  12. package/src/capability_request.d.ts +14 -0
  13. package/src/capability_request.js +247 -0
  14. package/src/dendrite_bridge/bridge.d.ts +98 -0
  15. package/src/dendrite_bridge/bridge.js +712 -0
  16. package/src/dendrite_bridge/ffi.d.ts +60 -0
  17. package/src/dendrite_bridge/ffi.js +139 -0
  18. package/src/dendrite_bridge/index.d.ts +3 -0
  19. package/src/dendrite_bridge/index.js +25 -0
  20. package/src/dendrite_bridge/types.d.ts +179 -0
  21. package/src/dendrite_bridge/types.js +23 -0
  22. package/src/dendrite_bridge.d.ts +1 -0
  23. package/src/dendrite_bridge.js +27 -0
  24. package/src/errors.d.ts +83 -0
  25. package/src/errors.js +146 -0
  26. package/src/index.d.ts +55 -0
  27. package/src/index.js +164 -0
  28. package/src/koffi.d.ts +34 -0
  29. package/src/mcp/server.d.ts +29 -0
  30. package/src/mcp/server.js +190 -0
  31. package/src/presets/ability_dispatch/args.d.ts +5 -0
  32. package/src/presets/ability_dispatch/args.js +36 -0
  33. package/src/presets/ability_dispatch/bundle.d.ts +7 -0
  34. package/src/presets/ability_dispatch/bundle.js +102 -0
  35. package/src/presets/ability_dispatch/media.d.ts +6 -0
  36. package/src/presets/ability_dispatch/media.js +48 -0
  37. package/src/presets/ability_dispatch/orchestrator.d.ts +21 -0
  38. package/src/presets/ability_dispatch/orchestrator.js +117 -0
  39. package/src/presets/ability_dispatch/workflow.d.ts +50 -0
  40. package/src/presets/ability_dispatch/workflow.js +333 -0
  41. package/src/presets/ability_dispatch.d.ts +1 -0
  42. package/src/presets/ability_dispatch.js +2 -0
  43. package/src/presets/remote_control/config.d.ts +16 -0
  44. package/src/presets/remote_control/config.js +63 -0
  45. package/src/presets/remote_control/descriptor.d.ts +34 -0
  46. package/src/presets/remote_control/descriptor.js +183 -0
  47. package/src/presets/remote_control/handlers.d.ts +12 -0
  48. package/src/presets/remote_control/handlers.js +279 -0
  49. package/src/presets/remote_control/kit.d.ts +22 -0
  50. package/src/presets/remote_control/kit.js +72 -0
  51. package/src/presets/remote_control/kit.test.js +87 -0
  52. package/src/presets/remote_control/orchestrator.d.ts +28 -0
  53. package/src/presets/remote_control/orchestrator.js +118 -0
  54. package/src/presets/remote_control/specs.d.ts +2 -0
  55. package/src/presets/remote_control/specs.js +152 -0
  56. package/src/presets/remote_control_case.d.ts +7 -0
  57. package/src/presets/remote_control_case.js +3 -0
  58. package/src/receipt.d.ts +46 -0
  59. package/src/receipt.js +98 -0
  60. package/src/tool_adapter.d.ts +90 -0
  61. package/src/tool_adapter.js +169 -0
package/src/errors.js ADDED
@@ -0,0 +1,146 @@
1
+ // sdk/node/src/errors.ts — Canonical error taxonomy for the Axon SDK.
2
+ //
3
+ // Terminology:
4
+ // Ability — network-addressable governed execution contract
5
+ // Skill — packaged implementation artifact (SKILL.md + invoke.sh)
6
+ // Tool — export projection for LLM ecosystems (OpenAI / Anthropic)
7
+ //
8
+ // Each error class exposes a `code` property for cross-SDK mapping.
9
+ // See the Rust reference: sdk/rust/src/error.rs
10
+ //
11
+ // Copyright (c) 2026-2027 easynet. All rights reserved.
12
+ /** Base error for all Axon SDK errors. */
13
+ export class AxonError extends Error {
14
+ /** Canonical error code for cross-SDK mapping. */
15
+ code = "UNKNOWN";
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = "AxonError";
19
+ }
20
+ }
21
+ // -- Input / config errors ---------------------------------------------------
22
+ /** Input validation or configuration error (before any network call). */
23
+ export class AxonConfigError extends AxonError {
24
+ code = "VALIDATION";
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "AxonConfigError";
28
+ }
29
+ }
30
+ // -- Bridge errors -----------------------------------------------------------
31
+ /** Native bridge initialization or connection to the Axon runtime failed. */
32
+ export class AxonBridgeError extends AxonError {
33
+ code = "BRIDGE";
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = "AxonBridgeError";
37
+ }
38
+ }
39
+ // -- Lifecycle state errors --------------------------------------------------
40
+ /** The requested ability is not installed on the target node. */
41
+ export class AxonNotInstalledError extends AxonError {
42
+ code = "NOT_INSTALLED";
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "AxonNotInstalledError";
46
+ }
47
+ }
48
+ /** The ability is installed but not yet activated. */
49
+ export class AxonNotActivatedError extends AxonError {
50
+ code = "NOT_ACTIVATED";
51
+ constructor(message) {
52
+ super(message);
53
+ this.name = "AxonNotActivatedError";
54
+ }
55
+ }
56
+ // -- Execution errors --------------------------------------------------------
57
+ /**
58
+ * Remote invocation or deploy operation failed.
59
+ *
60
+ * When thrown from a deploy pipeline the optional `trace` field carries the
61
+ * {@link DeployTrace} collected before the failure, so callers can inspect
62
+ * per-phase timing even on error:
63
+ *
64
+ * ```ts
65
+ * try { await deployToNode(bridge, tenant, nodeId, desc, sig); }
66
+ * catch (e) { if (e instanceof AxonInvocationError && e.trace) console.log(e.trace); }
67
+ * ```
68
+ */
69
+ export class AxonInvocationError extends AxonError {
70
+ code = "INVOCATION";
71
+ remotePayload;
72
+ /** Deploy trace collected before the failure (if available). */
73
+ trace;
74
+ constructor(message, remotePayload, trace) {
75
+ super(message);
76
+ this.name = "AxonInvocationError";
77
+ this.remotePayload = remotePayload;
78
+ this.trace = trace;
79
+ }
80
+ }
81
+ /** Streaming transport was interrupted before completion. */
82
+ export class AxonStreamError extends AxonError {
83
+ code = "STREAM";
84
+ constructor(message) {
85
+ super(message);
86
+ this.name = "AxonStreamError";
87
+ }
88
+ }
89
+ /** A governance policy rejected the operation. */
90
+ export class AxonPolicyDeniedError extends AxonError {
91
+ code = "POLICY_DENIED";
92
+ constructor(message) {
93
+ super(message);
94
+ this.name = "AxonPolicyDeniedError";
95
+ }
96
+ }
97
+ // -- MCP transport errors -----------------------------------------------------
98
+ /** MCP transport or protocol error. */
99
+ export class AxonMcpError extends AxonError {
100
+ code = "MCP";
101
+ constructor(message) {
102
+ super(message);
103
+ this.name = "AxonMcpError";
104
+ }
105
+ }
106
+ // -- Batch / partial errors --------------------------------------------------
107
+ /** Operation completed with partial failures (e.g. `forgetAll`). */
108
+ export class AxonPartialSuccessError extends AxonError {
109
+ code = "PARTIAL_SUCCESS";
110
+ succeeded;
111
+ failed;
112
+ details;
113
+ constructor(message, succeeded, failed, details) {
114
+ super(message);
115
+ this.name = "AxonPartialSuccessError";
116
+ this.succeeded = succeeded;
117
+ this.failed = failed;
118
+ this.details = details;
119
+ }
120
+ }
121
+ // -- Serialization / IO errors -----------------------------------------------
122
+ /** JSON serialization or deserialization error. */
123
+ export class AxonJsonError extends AxonError {
124
+ code = "JSON";
125
+ constructor(message) {
126
+ super(message);
127
+ this.name = "AxonJsonError";
128
+ }
129
+ }
130
+ /** Filesystem or general I/O error. */
131
+ export class AxonIoError extends AxonError {
132
+ code = "IO";
133
+ constructor(message) {
134
+ super(message);
135
+ this.name = "AxonIoError";
136
+ }
137
+ }
138
+ // -- FFI symbol errors --------------------------------------------------------
139
+ /** A required FFI symbol was not found in the native library. */
140
+ export class AxonSymbolNotFoundError extends AxonError {
141
+ code = "SYMBOL_NOT_FOUND";
142
+ constructor(message) {
143
+ super(message);
144
+ this.name = "AxonSymbolNotFoundError";
145
+ }
146
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ export { validateUninstallCapabilityRequest, buildUninstallCapabilityPayload, } from "./capability_request.js";
2
+ export type { McpToolProvider, McpToolResult, } from "./mcp/server.js";
3
+ export { StdioMcpServer } from "./mcp/server.js";
4
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
5
+ [k: string]: JsonValue;
6
+ };
7
+ export interface ClientCallOptions {
8
+ principalId?: string;
9
+ }
10
+ export interface Transport {
11
+ call(tenantId: string, resourceUri: string, payload: JsonValue, options?: ClientCallOptions): Promise<JsonValue>;
12
+ callRaw?(tenantId: string, resourceUri: string, payload: JsonValue, options?: ClientCallOptions): Promise<Record<string, unknown>>;
13
+ }
14
+ export declare class SidecarTransport implements Transport {
15
+ endpoint: string;
16
+ private readonly timeoutMs;
17
+ private bridge;
18
+ private readonly connectTimeoutMs;
19
+ private readonly libraryPath?;
20
+ constructor(endpoint?: string, connectTimeoutMs?: number, timeoutMs?: number, libraryPath?: string);
21
+ private ensureBridge;
22
+ /**
23
+ * Invoke an ability via the sidecar FFI bridge.
24
+ *
25
+ * WARNING: The underlying FFI call is synchronous and blocks the event loop.
26
+ * Returns a resolved Promise for Transport interface compatibility.
27
+ */
28
+ call(tenantId: string, resourceUri: string, payload: JsonValue, options?: ClientCallOptions): Promise<JsonValue>;
29
+ /**
30
+ * Invoke an ability and return the raw envelope via FFI.
31
+ *
32
+ * WARNING: The underlying FFI call is synchronous and blocks the event loop.
33
+ * Returns a resolved Promise for Transport interface compatibility.
34
+ */
35
+ callRaw(tenantId: string, resourceUri: string, payload: JsonValue, options?: ClientCallOptions): Promise<Record<string, unknown>>;
36
+ close(): void;
37
+ }
38
+ export declare class Client {
39
+ private readonly transport;
40
+ private readonly tenantId;
41
+ private readonly resourceUri;
42
+ private readonly principalId;
43
+ constructor(transport?: Transport, tenantId?: string, resourceUri?: string, principalId?: string);
44
+ tenant(tenantId: string): Client;
45
+ ability(resourceUri: string): Client;
46
+ principal(principalId: string): Client;
47
+ call(payload: JsonValue): Promise<JsonValue>;
48
+ callRaw(payload: JsonValue): Promise<Record<string, unknown>>;
49
+ }
50
+ export declare function client(transport?: Transport): Client;
51
+ export { createAbility, exportAbility, deployToNode, listAbilities, invokeAbility, uninstallAbility, discoverNodes, executeCommand, forgetAll, disconnectDevice, drainDevice, listRemoteTools, buildDeployPackage, deployPackage, startServer, toToolSpec, type AbilityDescriptor, type AbilityTarget, type AbilityExportResult, type ServerHandle, type BridgeInterface, type ForgetAllResult, type ForgetAllFailure, type DeployResult, } from "./ability_lifecycle.js";
52
+ export { AxonError, AxonConfigError, AxonBridgeError, AxonNotInstalledError, AxonNotActivatedError, AxonInvocationError, AxonStreamError, AxonPolicyDeniedError, AxonMcpError, AxonPartialSuccessError, AxonJsonError, AxonIoError, AxonSymbolNotFoundError, } from "./errors.js";
53
+ export { beginPhase, skippedReceipt, buildDeployTrace, phaseFromTrace, PhaseReceiptBuilder, type Phase, type PhaseStatus, type PhaseReceipt, type DeployTrace, } from "./receipt.js";
54
+ export { AbilityToolAdapter, type ToolSpec as AdapterToolSpec, type OpenAITool, type OpenAIChatTool, type AnthropicTool, type ToolParameters, type LocalHandler, type RegisterOptions, type AbilityToolAdapterOptions, } from "./tool_adapter.js";
55
+ export { DendriteBridge, DendriteServerStream, DendriteBidiStream, type DendriteBridgeOptions, DendriteError, type DendriteUnaryCallOptions, type DendriteAbilityCallOptions, type DendriteStreamCallOptions, type DendriteClientStreamCallOptions, type DendriteBidiStreamCallOptions, type DendriteListNodesOptions, type DendriteRegisterNodeOptions, type DendritePublishCapabilityOptions, type DendriteInstallCapabilityOptions, type DendriteListA2aAgentsOptions, type DendriteSendA2aTaskOptions, type DendriteDeployMcpListDirOptions, type DendriteListMcpToolsOptions, type DendriteCallMcpToolOptions, type DendriteUninstallCapabilityOptions, type DendriteUpdateMcpListDirOptions, type DendriteVoiceCodecProfileOptions, type DendriteVoiceMetricsOptions, type DendriteVoiceDescriptionOptions, type DendriteVoiceCandidateOptions, type DendriteVoiceCreateCallOptions, type DendriteVoiceJoinCallOptions, type DendriteVoiceUpdateMediaPathOptions, type DendriteVoiceEndCallOptions, type DendriteVoiceWatchOptions, type DendriteVoiceCreateTransportSessionOptions, type DendriteVoiceEndTransportSessionOptions, type DendriteProtocolInvokeOptions, } from "./dendrite_bridge.js";
package/src/index.js ADDED
@@ -0,0 +1,164 @@
1
+ // EasyNet Axon for AgentNet
2
+ // =========================
3
+ //
4
+ // File: sdk/node/src/index.ts
5
+ // Description: Source file for Node SDK facade and Dendrite integration; keeps behavior explicit and interoperable across language/runtime boundaries with tenant/principal fluent context.
6
+ //
7
+ // Protocol Responsibility:
8
+ // - Implements Node SDK facade and Dendrite integration contracts required by current Axon service and SDK surfaces.
9
+ // - Preserves stable request/response semantics and error mapping for index.ts call paths.
10
+ //
11
+ // Implementation Approach:
12
+ // - Uses small typed helpers and explicit control flow to avoid hidden side effects.
13
+ // - Keeps protocol translation and transport details close to this module boundary.
14
+ //
15
+ // Usage Contract:
16
+ // - Callers should provide valid tenant/resource/runtime context before invoking exported APIs; principal context is optional and, when provided, is mapped to EasyNet subject context.
17
+ // - Errors should be treated as typed protocol/runtime outcomes rather than silently ignored.
18
+ //
19
+ // Architectural Position:
20
+ // - Part of the Node SDK facade and Dendrite integration layer.
21
+ // - Should not embed unrelated orchestration logic outside this file's responsibility.
22
+ //
23
+ // Author: Silan.Hu
24
+ // Email: silan.hu@u.nus.edu
25
+ // Copyright (c) 2026-2027 easynet. All rights reserved.
26
+ import { DendriteBridge } from "./dendrite_bridge.js";
27
+ import { AxonConfigError, AxonInvocationError } from "./errors.js";
28
+ export { validateUninstallCapabilityRequest, buildUninstallCapabilityPayload, } from "./capability_request.js";
29
+ export { StdioMcpServer } from "./mcp/server.js";
30
+ function visibilityFromResourceUri(resourceUri) {
31
+ const normalized = resourceUri.trim().toLowerCase();
32
+ if (normalized.startsWith("easynet:///r/pub/")) {
33
+ return "pub";
34
+ }
35
+ if (normalized.startsWith("easynet:///r/prv/")) {
36
+ return "prv";
37
+ }
38
+ return "org";
39
+ }
40
+ function principalToSubjectId(principalId, resourceUri) {
41
+ const normalized = principalId.trim();
42
+ if (!normalized) {
43
+ throw new AxonConfigError("principal(...) cannot be blank");
44
+ }
45
+ if (normalized.startsWith("easynet:")) {
46
+ return normalized;
47
+ }
48
+ const visibility = visibilityFromResourceUri(resourceUri);
49
+ return `easynet:${visibility}:reg:agent.${normalized}`;
50
+ }
51
+ function extractResultJson(raw) {
52
+ if (!raw || typeof raw !== "object" || !Object.prototype.hasOwnProperty.call(raw, "result_json")) {
53
+ throw new AxonInvocationError("invoke response missing result_json");
54
+ }
55
+ return raw.result_json;
56
+ }
57
+ export class SidecarTransport {
58
+ endpoint;
59
+ timeoutMs;
60
+ bridge = null;
61
+ connectTimeoutMs;
62
+ libraryPath;
63
+ constructor(endpoint = process.env.EASYNET_AXON_ENDPOINT ?? "http://127.0.0.1:50051", connectTimeoutMs = 5000, timeoutMs = 30000, libraryPath) {
64
+ this.endpoint = endpoint;
65
+ this.timeoutMs = timeoutMs;
66
+ this.connectTimeoutMs = connectTimeoutMs;
67
+ this.libraryPath = libraryPath;
68
+ }
69
+ ensureBridge() {
70
+ if (!this.bridge) {
71
+ this.bridge = new DendriteBridge({
72
+ endpoint: this.endpoint,
73
+ connectTimeoutMs: this.connectTimeoutMs,
74
+ libraryPath: this.libraryPath,
75
+ });
76
+ }
77
+ return this.bridge;
78
+ }
79
+ /**
80
+ * Invoke an ability via the sidecar FFI bridge.
81
+ *
82
+ * WARNING: The underlying FFI call is synchronous and blocks the event loop.
83
+ * Returns a resolved Promise for Transport interface compatibility.
84
+ */
85
+ call(tenantId, resourceUri, payload, options = {}) {
86
+ const subjectId = options.principalId
87
+ ? principalToSubjectId(options.principalId, resourceUri)
88
+ : undefined;
89
+ const raw = this.ensureBridge().abilityCallRaw(tenantId, resourceUri, payload, {
90
+ timeoutMs: this.timeoutMs,
91
+ subjectId,
92
+ });
93
+ return Promise.resolve(extractResultJson(raw));
94
+ }
95
+ /**
96
+ * Invoke an ability and return the raw envelope via FFI.
97
+ *
98
+ * WARNING: The underlying FFI call is synchronous and blocks the event loop.
99
+ * Returns a resolved Promise for Transport interface compatibility.
100
+ */
101
+ callRaw(tenantId, resourceUri, payload, options = {}) {
102
+ const subjectId = options.principalId
103
+ ? principalToSubjectId(options.principalId, resourceUri)
104
+ : undefined;
105
+ return Promise.resolve(this.ensureBridge().abilityCallRaw(tenantId, resourceUri, payload, {
106
+ timeoutMs: this.timeoutMs,
107
+ subjectId,
108
+ }));
109
+ }
110
+ close() {
111
+ this.bridge?.close();
112
+ this.bridge = null;
113
+ }
114
+ }
115
+ export class Client {
116
+ transport;
117
+ tenantId;
118
+ resourceUri;
119
+ principalId;
120
+ constructor(transport = new SidecarTransport(), tenantId = "", resourceUri = "", principalId = "") {
121
+ this.transport = transport;
122
+ this.tenantId = tenantId;
123
+ this.resourceUri = resourceUri;
124
+ this.principalId = principalId;
125
+ }
126
+ tenant(tenantId) {
127
+ return new Client(this.transport, tenantId, this.resourceUri, this.principalId);
128
+ }
129
+ ability(resourceUri) {
130
+ return new Client(this.transport, this.tenantId, resourceUri, this.principalId);
131
+ }
132
+ principal(principalId) {
133
+ return new Client(this.transport, this.tenantId, this.resourceUri, principalId);
134
+ }
135
+ async call(payload) {
136
+ if (!this.tenantId)
137
+ throw new AxonConfigError("tenant(...) is required before call(...)");
138
+ if (!this.resourceUri)
139
+ throw new AxonConfigError("ability(...) is required before call(...)");
140
+ return this.transport.call(this.tenantId, this.resourceUri, payload, {
141
+ principalId: this.principalId || undefined,
142
+ });
143
+ }
144
+ async callRaw(payload) {
145
+ if (!this.tenantId)
146
+ throw new AxonConfigError("tenant(...) is required before callRaw(...)");
147
+ if (!this.resourceUri)
148
+ throw new AxonConfigError("ability(...) is required before callRaw(...)");
149
+ if (!this.transport.callRaw) {
150
+ throw new AxonConfigError("configured transport does not support callRaw(...)");
151
+ }
152
+ return this.transport.callRaw(this.tenantId, this.resourceUri, payload, {
153
+ principalId: this.principalId || undefined,
154
+ });
155
+ }
156
+ }
157
+ export function client(transport) {
158
+ return new Client(transport);
159
+ }
160
+ export { createAbility, exportAbility, deployToNode, listAbilities, invokeAbility, uninstallAbility, discoverNodes, executeCommand, forgetAll, disconnectDevice, drainDevice, listRemoteTools, buildDeployPackage, deployPackage, startServer, toToolSpec, } from "./ability_lifecycle.js";
161
+ export { AxonError, AxonConfigError, AxonBridgeError, AxonNotInstalledError, AxonNotActivatedError, AxonInvocationError, AxonStreamError, AxonPolicyDeniedError, AxonMcpError, AxonPartialSuccessError, AxonJsonError, AxonIoError, AxonSymbolNotFoundError, } from "./errors.js";
162
+ export { beginPhase, skippedReceipt, buildDeployTrace, phaseFromTrace, PhaseReceiptBuilder, } from "./receipt.js";
163
+ export { AbilityToolAdapter, } from "./tool_adapter.js";
164
+ export { DendriteBridge, DendriteServerStream, DendriteBidiStream, DendriteError, } from "./dendrite_bridge.js";
package/src/koffi.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ // EasyNet Axon for AgentNet
2
+ // =========================
3
+ //
4
+ // File: sdk/node/src/koffi.d.ts
5
+ // Description: Ambient type declaration for the koffi native FFI module; provides minimal type surface consumed by the DendriteBridge FFI layer to load and call native library symbols.
6
+ //
7
+ // Protocol Responsibility:
8
+ // - Declares TypeScript types for the koffi module's load, func, and disposable APIs used across the dendrite_bridge FFI binding.
9
+ // - Enables type-safe FFI symbol resolution without bundling koffi's full type definitions.
10
+ //
11
+ // Implementation Approach:
12
+ // - Uses a `declare module` ambient declaration so TypeScript resolves koffi imports without requiring @types/koffi.
13
+ // - Keeps the surface minimal — only APIs actually consumed by this SDK are declared.
14
+ //
15
+ // Usage Contract:
16
+ // - This file is consumed by the TypeScript compiler only; it has no runtime effect.
17
+ // - If koffi publishes official type definitions in the future, this file can be removed.
18
+ //
19
+ // Architectural Position:
20
+ // - Part of the Node SDK type layer; supports the dendrite_bridge FFI binding.
21
+ // - Should not declare types unrelated to koffi FFI interop.
22
+ //
23
+ // Author: Silan.Hu
24
+ // Email: silan.hu@u.nus.edu
25
+ // Copyright (c) 2026-2027 easynet. All rights reserved.
26
+
27
+ declare module "koffi" {
28
+ export interface KoffiLibrary {
29
+ func(...args: unknown[]): unknown;
30
+ }
31
+
32
+ export function load(path: string): KoffiLibrary;
33
+ export function disposable(typeName: string, disposer: (ptr: unknown) => void): unknown;
34
+ }
@@ -0,0 +1,29 @@
1
+ export interface McpToolResult {
2
+ payload: Record<string, unknown>;
3
+ isError: boolean;
4
+ }
5
+ export interface McpToolProvider {
6
+ toolSpecs(): Array<Record<string, unknown>>;
7
+ handleToolCall(name: string, args: Record<string, unknown>): McpToolResult | Promise<McpToolResult>;
8
+ }
9
+ interface McpTransportOptions {
10
+ protocolVersion?: string;
11
+ serverName?: string;
12
+ serverVersion?: string;
13
+ }
14
+ interface JsonMessage {
15
+ [key: string]: unknown;
16
+ }
17
+ export declare class StdioMcpServer {
18
+ private readonly provider;
19
+ private readonly protocolVersion;
20
+ private readonly serverName;
21
+ private readonly serverVersion;
22
+ private _closed;
23
+ constructor(provider: McpToolProvider, options?: McpTransportOptions);
24
+ close(): void;
25
+ run(input: NodeJS.ReadableStream, output: NodeJS.WritableStream): void;
26
+ handleRawLine(raw: string): JsonMessage | Promise<JsonMessage> | null;
27
+ handleRequest(request: JsonMessage): JsonMessage | Promise<JsonMessage> | null;
28
+ }
29
+ export {};
@@ -0,0 +1,190 @@
1
+ const DEFAULT_PROTOCOL_VERSION = "2026-02-26";
2
+ const DEFAULT_SERVER_NAME = "easynet-axon-remote-node";
3
+ const DEFAULT_SERVER_VERSION = "0.2.0";
4
+ const MAX_LINE_LENGTH = 4 * 1024 * 1024; // 4 MiB per JSON-RPC message
5
+ export class StdioMcpServer {
6
+ provider;
7
+ protocolVersion;
8
+ serverName;
9
+ serverVersion;
10
+ _closed = false;
11
+ constructor(provider, options = {}) {
12
+ this.provider = provider;
13
+ this.protocolVersion = options.protocolVersion?.trim() || DEFAULT_PROTOCOL_VERSION;
14
+ this.serverName = options.serverName?.trim() || DEFAULT_SERVER_NAME;
15
+ this.serverVersion = options.serverVersion?.trim() || DEFAULT_SERVER_VERSION;
16
+ }
17
+ close() {
18
+ this._closed = true;
19
+ }
20
+ run(input, output) {
21
+ let cache = "";
22
+ input.setEncoding("utf8");
23
+ input.on("error", (error) => {
24
+ if (this._closed)
25
+ return;
26
+ const payload = jsonrpcError(null, -32000, `stream error: ${String(error)}`);
27
+ write(output, payload);
28
+ });
29
+ input.on("close", () => {
30
+ // no-op: caller controls lifecycle
31
+ });
32
+ input.on("data", (chunk) => {
33
+ if (this._closed)
34
+ return;
35
+ cache += chunk.toString();
36
+ if (cache.length > MAX_LINE_LENGTH && !cache.includes("\n")) {
37
+ write(output, jsonrpcError(null, -32000, `input line exceeds maximum length (${MAX_LINE_LENGTH} bytes)`));
38
+ cache = "";
39
+ return;
40
+ }
41
+ const lines = cache.split("\n");
42
+ cache = lines.pop() ?? "";
43
+ for (const raw of lines) {
44
+ if (!raw.trim()) {
45
+ continue;
46
+ }
47
+ if (this._closed)
48
+ break;
49
+ if (raw.length > MAX_LINE_LENGTH) {
50
+ write(output, jsonrpcError(null, -32000, `input line exceeds maximum length (${MAX_LINE_LENGTH} bytes)`));
51
+ continue;
52
+ }
53
+ const requestId = parseJson(raw)?.id ?? null;
54
+ const response = this.handleRawLine(raw);
55
+ if (response !== null) {
56
+ if (typeof response.then === "function") {
57
+ response.then((resolved) => { if (resolved !== null)
58
+ write(output, resolved); }, (error) => { write(output, jsonrpcError(requestId, -32000, String(error))); });
59
+ }
60
+ else {
61
+ write(output, response);
62
+ }
63
+ }
64
+ }
65
+ });
66
+ }
67
+ handleRawLine(raw) {
68
+ const request = parseJson(raw);
69
+ if (request === null) {
70
+ return jsonrpcError(null, -32700, "parse error");
71
+ }
72
+ return this.handleRequest(request);
73
+ }
74
+ handleRequest(request) {
75
+ const id = request.id;
76
+ const method = typeof request.method === "string" ? request.method : "";
77
+ const params = asMap(request.params);
78
+ // JSON-RPC 2.0 requires "jsonrpc": "2.0" on every request.
79
+ if (request.jsonrpc !== "2.0" && id !== undefined) {
80
+ return jsonrpcError(id, -32600, "invalid request: missing jsonrpc version");
81
+ }
82
+ if (method === "notifications/initialized") {
83
+ return null;
84
+ }
85
+ if (method === "initialize") {
86
+ if (id === undefined) {
87
+ return null;
88
+ }
89
+ return jsonrpcSuccess(id, {
90
+ protocolVersion: this.protocolVersion,
91
+ capabilities: { tools: {} },
92
+ serverInfo: {
93
+ name: this.serverName,
94
+ version: this.serverVersion,
95
+ },
96
+ });
97
+ }
98
+ if (method === "tools/list") {
99
+ if (id === undefined) {
100
+ return null;
101
+ }
102
+ return jsonrpcSuccess(id, { tools: this.provider.toolSpecs() });
103
+ }
104
+ if (method === "tools/call") {
105
+ if (id === undefined) {
106
+ return null;
107
+ }
108
+ const name = asString(params.name);
109
+ if (!name) {
110
+ return jsonrpcError(id, -32602, "tool name is required");
111
+ }
112
+ let args = params.arguments;
113
+ if (typeof args !== "object" || args === null || Array.isArray(args)) {
114
+ args = {};
115
+ }
116
+ const typedArgs = args;
117
+ let maybeResult;
118
+ try {
119
+ maybeResult = this.provider.handleToolCall(name, typedArgs);
120
+ }
121
+ catch (error) {
122
+ return jsonrpcSuccess(id, toolResponse({
123
+ payload: { ok: false, error: String(error) },
124
+ isError: true,
125
+ }));
126
+ }
127
+ if (maybeResult && typeof maybeResult.then === "function") {
128
+ return maybeResult.then((result) => jsonrpcSuccess(id, toolResponse(result)), (error) => jsonrpcSuccess(id, toolResponse({
129
+ payload: { ok: false, error: String(error) },
130
+ isError: true,
131
+ })));
132
+ }
133
+ return jsonrpcSuccess(id, toolResponse(maybeResult));
134
+ }
135
+ if (method === "ping" && id !== undefined) {
136
+ return jsonrpcSuccess(id, {});
137
+ }
138
+ if (id === undefined) {
139
+ return null;
140
+ }
141
+ return jsonrpcError(id, -32601, `method not found: ${method}`);
142
+ }
143
+ }
144
+ function parseJson(raw) {
145
+ try {
146
+ const value = JSON.parse(raw);
147
+ if (value === null || typeof value !== "object") {
148
+ return null;
149
+ }
150
+ return value;
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ function asMap(value) {
157
+ if (value && typeof value === "object" && !Array.isArray(value)) {
158
+ return value;
159
+ }
160
+ return {};
161
+ }
162
+ function asString(value) {
163
+ if (typeof value !== "string") {
164
+ return "";
165
+ }
166
+ return value.trim();
167
+ }
168
+ function write(stream, payload) {
169
+ stream.write(`${JSON.stringify(payload)}\n`);
170
+ }
171
+ function toolResponse(result) {
172
+ const payload = {
173
+ content: [{ type: "text", text: JSON.stringify(result.payload, null, 2) }],
174
+ };
175
+ return result.isError ? { ...payload, isError: true } : payload;
176
+ }
177
+ function jsonrpcSuccess(id, result) {
178
+ return {
179
+ jsonrpc: "2.0",
180
+ id,
181
+ result,
182
+ };
183
+ }
184
+ function jsonrpcError(id, code, message) {
185
+ return {
186
+ jsonrpc: "2.0",
187
+ id,
188
+ error: { code, message },
189
+ };
190
+ }
@@ -0,0 +1,5 @@
1
+ type ArgMap = Record<string, string | boolean>;
2
+ export declare const BOOL_FLAGS: Set<string>;
3
+ export declare function parseArgs(argv: string[]): ArgMap;
4
+ export declare function parsePositiveInt(raw: string | undefined, fallback: number, field: string): number;
5
+ export {};
@@ -0,0 +1,36 @@
1
+ // EasyNet Axon for AgentNet -- argument parsing helpers for ability-dispatch workflow.
2
+ export const BOOL_FLAGS = new Set([
3
+ "auto-request-permission",
4
+ "no-write-media-files",
5
+ "keep-installed",
6
+ "require-real",
7
+ "allow-mock-fallback",
8
+ ]);
9
+ export function parseArgs(argv) {
10
+ const out = {};
11
+ for (let i = 0; i < argv.length; i += 1) {
12
+ const token = argv[i];
13
+ if (!token.startsWith("--")) {
14
+ continue;
15
+ }
16
+ const key = token.slice(2);
17
+ if (BOOL_FLAGS.has(key)) {
18
+ out[key] = true;
19
+ continue;
20
+ }
21
+ const value = argv[i + 1];
22
+ if (!value || value.startsWith("--")) {
23
+ throw new Error(`missing value for --${key}`);
24
+ }
25
+ out[key] = value;
26
+ i += 1;
27
+ }
28
+ return out;
29
+ }
30
+ export function parsePositiveInt(raw, fallback, field) {
31
+ const parsed = Number.parseInt(raw ?? `${fallback}`, 10);
32
+ if (!Number.isFinite(parsed) || parsed <= 0) {
33
+ throw new Error(`--${field} must be > 0`);
34
+ }
35
+ return parsed;
36
+ }
@@ -0,0 +1,7 @@
1
+ export declare function sha256Prefixed(payload: Uint8Array): string;
2
+ export declare function parseTarSize(raw: Buffer): number;
3
+ export declare function isZeroBlock(block: Buffer): boolean;
4
+ export declare function readBundleVersion(bundleBytes: Buffer): string;
5
+ export declare function resolveBundlePath(raw: string, cfg: {
6
+ bundleFilePrefixes: string[];
7
+ }): string;