@easynet-run/node 0.36.9 → 0.39.29

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.
@@ -2,29 +2,28 @@
2
2
  // =========================
3
3
  //
4
4
  // File: sdk/node/src/dendrite_bridge/ffi.ts
5
- // Description: FFI loading and JSON calling layer for the Dendrite native bridge; resolves the shared library, binds koffi function pointers, and provides the callJson helper.
5
+ // Description: Node FFI loader and raw JSON-call bindings for the native Axon dendrite bridge.
6
6
  //
7
7
  // Protocol Responsibility:
8
- // - Loads the native dendrite bridge shared library and exposes typed function bindings.
9
- // - Provides the low-level callJson helper that handles JSON serialization/error mapping.
8
+ // - Loads the native dendrite shared library and exposes the raw JSON-call symbol set to Node code.
9
+ // - Normalizes low-level FFI failures into stable Node-side error contracts.
10
10
  //
11
11
  // Implementation Approach:
12
- // - Uses koffi for native FFI binding.
13
- // - Keeps library resolution and error handling explicit.
12
+ // - Keeps library path resolution, symbol binding, and JSON marshalling isolated from higher-level SDK classes.
13
+ // - Defines timeout and transport constants close to the native boundary for consistent reuse.
14
14
  //
15
15
  // Usage Contract:
16
- // - Callers should use loadDendriteLib to obtain function bindings, then callJson to invoke them.
17
- // - Errors are surfaced as DendriteError instances.
16
+ // - Treat this module as the lowest-level Node native binding layer and avoid embedding application logic here.
17
+ // - Regenerate or update bindings here before adding new native bridge capabilities to higher layers.
18
18
  //
19
19
  // Architectural Position:
20
- // - Part of the Node SDK dendrite_bridge submodule layer.
21
- // - Should not embed class or interface logic outside FFI concerns.
20
+ // - Native binding boundary underneath the Node SDK bridge facade.
22
21
  //
23
22
  // Author: Silan.Hu
24
23
  // Email: silan.hu@u.nus.edu
25
24
  // Copyright (c) 2026-2027 easynet. All rights reserved.
26
25
  import { createRequire } from "node:module";
27
- import { existsSync } from "node:fs";
26
+ import { existsSync, readFileSync } from "node:fs";
28
27
  import { dirname, resolve } from "node:path";
29
28
  import { fileURLToPath } from "node:url";
30
29
  import { DendriteError } from "../capability_request.js";
@@ -34,22 +33,196 @@ export const DEFAULT_TIMEOUT_MS = 30000;
34
33
  export const DEFAULT_CONNECT_TIMEOUT_MS = 5000;
35
34
  export const DEFAULT_MCP_TOOL_STREAM_TIMEOUT_MS = 60_000;
36
35
  export { DendriteError };
36
+ function bridgeDebugLog(tried) {
37
+ if ((process.env.EASYNET_DENDRITE_BRIDGE_DEBUG || "").trim() === "1") {
38
+ process.stderr.write(`[dendrite-bridge] tried ${tried.length} candidate(s):\n`);
39
+ for (const p of tried) {
40
+ process.stderr.write(` - ${p}\n`);
41
+ }
42
+ }
43
+ }
37
44
  export function resolveLibraryPath(explicitPath) {
38
45
  if (explicitPath)
39
46
  return explicitPath;
40
47
  if (process.env.EASYNET_DENDRITE_BRIDGE_LIB)
41
48
  return process.env.EASYNET_DENDRITE_BRIDGE_LIB;
42
- const here = dirname(fileURLToPath(import.meta.url));
43
- const candidates = [
44
- resolve(here, "../../native/libaxon_dendrite_bridge.dylib"),
45
- resolve(here, "../../native/libaxon_dendrite_bridge.so"),
46
- resolve(here, "../../native/axon_dendrite_bridge.dll"),
47
- ];
48
- for (const c of candidates) {
49
+ const names = libraryFileNames();
50
+ const versions = sdkVersionCandidates();
51
+ const tried = [];
52
+ for (const c of homeLibraryCandidates(names, versions)) {
53
+ tried.push(c);
54
+ if (existsSync(c))
55
+ return c;
56
+ }
57
+ if (useLocalSource()) {
58
+ for (const c of sourceLibraryCandidates(names, versions)) {
59
+ tried.push(c);
60
+ if (existsSync(c))
61
+ return c;
62
+ }
63
+ }
64
+ for (const c of packageLibraryCandidates(names, versions)) {
65
+ tried.push(c);
49
66
  if (existsSync(c))
50
67
  return c;
51
68
  }
52
- throw new DendriteError("dendrite bridge library not found; set EASYNET_DENDRITE_BRIDGE_LIB or ensure package contains native/libaxon_dendrite_bridge.*");
69
+ bridgeDebugLog(tried);
70
+ throw new DendriteError("dendrite bridge library not found; set EASYNET_DENDRITE_BRIDGE_LIB or EASYNET_DENDRITE_BRIDGE_HOME — run with EASYNET_DENDRITE_BRIDGE_DEBUG=1 for candidate details");
71
+ }
72
+ function dedupeCandidates(values) {
73
+ const seen = new Set();
74
+ const out = [];
75
+ for (const value of values) {
76
+ if (seen.has(value)) {
77
+ continue;
78
+ }
79
+ seen.add(value);
80
+ out.push(value);
81
+ }
82
+ return out;
83
+ }
84
+ function libraryFileNames() {
85
+ const rawHint = (process.env.EASYNET_DENDRITE_BRIDGE_PLATFORM || "").trim().toLowerCase();
86
+ if (rawHint === "ios") {
87
+ return [
88
+ "libaxon_dendrite_bridge.dylib",
89
+ "libaxon_dendrite_bridge.so",
90
+ "axon_dendrite_bridge.dll",
91
+ ];
92
+ }
93
+ if (["android", "linux", "linux-gnu"].includes(rawHint)) {
94
+ return [
95
+ "libaxon_dendrite_bridge.so",
96
+ "libaxon_dendrite_bridge.dylib",
97
+ "axon_dendrite_bridge.dll",
98
+ ];
99
+ }
100
+ if (["macos", "darwin", "mac"].includes(rawHint)) {
101
+ return [
102
+ "libaxon_dendrite_bridge.dylib",
103
+ "libaxon_dendrite_bridge.so",
104
+ "axon_dendrite_bridge.dll",
105
+ ];
106
+ }
107
+ if (["windows", "win", "win32", "win64"].includes(rawHint)) {
108
+ return [
109
+ "axon_dendrite_bridge.dll",
110
+ "libaxon_dendrite_bridge.dylib",
111
+ "libaxon_dendrite_bridge.so",
112
+ ];
113
+ }
114
+ const primary = process.platform === "win32"
115
+ ? "axon_dendrite_bridge.dll"
116
+ : process.platform === "darwin"
117
+ ? "libaxon_dendrite_bridge.dylib"
118
+ : "libaxon_dendrite_bridge.so";
119
+ const all = [
120
+ "libaxon_dendrite_bridge.dylib",
121
+ "libaxon_dendrite_bridge.so",
122
+ "axon_dendrite_bridge.dll",
123
+ ];
124
+ return [primary, ...all.filter((n) => n !== primary)];
125
+ }
126
+ function projectRoot() {
127
+ let cursor = process.cwd();
128
+ for (let depth = 0; depth < 12; depth += 1) {
129
+ if (existsSync(resolve(cursor, "core/runtime-rs"))) {
130
+ return cursor;
131
+ }
132
+ const parent = dirname(cursor);
133
+ if (parent === cursor)
134
+ break;
135
+ cursor = parent;
136
+ }
137
+ return undefined;
138
+ }
139
+ function sdkVersionCandidates() {
140
+ const versions = [];
141
+ const envVersion = (process.env.SDK_VERSION || "").trim();
142
+ if (envVersion) {
143
+ versions.push(envVersion);
144
+ }
145
+ const root = projectRoot();
146
+ if (root) {
147
+ try {
148
+ const raw = readFileSync(resolve(root, "VERSION"), "utf8").trim();
149
+ if (raw) {
150
+ versions.push(raw.split("\n")[0].trim());
151
+ }
152
+ }
153
+ catch {
154
+ // no-op
155
+ }
156
+ }
157
+ if (versions.length === 0) {
158
+ if ((process.env.EASYNET_DENDRITE_BRIDGE_DEBUG || "").trim() === "1") {
159
+ console.error("warning: no SDK version detected, falling back to 0.1.0");
160
+ }
161
+ }
162
+ versions.push("0.1.0");
163
+ return dedupeCandidates(versions).filter(Boolean);
164
+ }
165
+ function addLibraryCandidates(targets, names, roots) {
166
+ for (const root of roots) {
167
+ for (const name of names) {
168
+ targets.push(resolve(root, name));
169
+ }
170
+ }
171
+ }
172
+ function homeLibraryCandidates(names, versions) {
173
+ const raw = (process.env.EASYNET_DENDRITE_BRIDGE_HOME || "").trim();
174
+ if (!raw)
175
+ return [];
176
+ const homeRoot = resolve(raw);
177
+ const candidateRoots = [
178
+ homeRoot,
179
+ resolve(homeRoot, "native"),
180
+ ...versions.map((version) => resolve(homeRoot, "dist", "sdk-packs", version, "native")),
181
+ ];
182
+ const candidates = [];
183
+ addLibraryCandidates(candidates, names, candidateRoots);
184
+ return dedupeCandidates(candidates);
185
+ }
186
+ function useLocalSource() {
187
+ const raw = (process.env.EASYNET_DENDRITE_BRIDGE_SOURCE || "").trim().toLowerCase();
188
+ return new Set(["1", "true", "yes", "on", "local", "source"]).has(raw);
189
+ }
190
+ function sourceLibraryCandidates(names, versions) {
191
+ const root = projectRoot();
192
+ if (!root)
193
+ return [];
194
+ const candidates = [];
195
+ // Versioned dist paths
196
+ for (const version of versions) {
197
+ addLibraryCandidates(candidates, names, [resolve(root, "dist", "sdk-packs", version, "native")]);
198
+ }
199
+ // Build artifacts
200
+ const bridgeTarget = resolve(root, "core/runtime-rs/dendrite-bridge/target");
201
+ const roots = [
202
+ resolve(bridgeTarget, "release"),
203
+ resolve(bridgeTarget, "debug"),
204
+ ];
205
+ const sdkTarget = (process.env.SDK_TARGET || "").trim();
206
+ if (sdkTarget) {
207
+ roots.push(resolve(bridgeTarget, sdkTarget, "release"));
208
+ roots.push(resolve(bridgeTarget, sdkTarget, "debug"));
209
+ }
210
+ addLibraryCandidates(candidates, names, roots);
211
+ return dedupeCandidates(candidates);
212
+ }
213
+ function packageLibraryCandidates(names, versions) {
214
+ const here = dirname(fileURLToPath(import.meta.url));
215
+ const pkgBase = resolve(here, "../..");
216
+ const roots = [
217
+ pkgBase,
218
+ resolve(pkgBase, "native"),
219
+ ];
220
+ for (const version of versions) {
221
+ roots.push(resolve(pkgBase, "dist", "sdk-packs", version, "native"));
222
+ }
223
+ const candidates = [];
224
+ addLibraryCandidates(candidates, names, roots);
225
+ return dedupeCandidates(candidates);
53
226
  }
54
227
  export function loadDendriteLib(libraryPath) {
55
228
  const lib = koffi.load(libraryPath);
@@ -79,6 +252,7 @@ export function loadDendriteLib(libraryPath) {
79
252
  axon_dendrite_list_nodes_json: lib.func("axon_dendrite_list_nodes_json", bridgeString, ["uint64_t", "str"]),
80
253
  axon_dendrite_register_node_json: lib.func("axon_dendrite_register_node_json", bridgeString, ["uint64_t", "str"]),
81
254
  axon_dendrite_deregister_node_json: optionalJsonFn("axon_dendrite_deregister_node_json", ["uint64_t", "str"]),
255
+ axon_dendrite_drain_node_json: optionalJsonFn("axon_dendrite_drain_node_json", ["uint64_t", "str"]),
82
256
  axon_dendrite_heartbeat_json: lib.func("axon_dendrite_heartbeat_json", bridgeString, ["uint64_t", "str"]),
83
257
  axon_dendrite_publish_capability_json: lib.func("axon_dendrite_publish_capability_json", bridgeString, ["uint64_t", "str"]),
84
258
  axon_dendrite_install_capability_json: lib.func("axon_dendrite_install_capability_json", bridgeString, ["uint64_t", "str"]),
package/src/index.d.ts CHANGED
@@ -48,7 +48,7 @@ export declare class Client {
48
48
  callRaw(payload: JsonValue): Promise<Record<string, unknown>>;
49
49
  }
50
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";
51
+ export { buildAbilityDescriptor, 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
52
  export { AxonError, AxonConfigError, AxonBridgeError, AxonNotInstalledError, AxonNotActivatedError, AxonInvocationError, AxonStreamError, AxonPolicyDeniedError, AxonMcpError, AxonPartialSuccessError, AxonJsonError, AxonIoError, AxonSymbolNotFoundError, } from "./errors.js";
53
53
  export { beginPhase, skippedReceipt, buildDeployTrace, phaseFromTrace, PhaseReceiptBuilder, type Phase, type PhaseStatus, type PhaseReceipt, type DeployTrace, } from "./receipt.js";
54
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";
package/src/index.js CHANGED
@@ -2,23 +2,22 @@
2
2
  // =========================
3
3
  //
4
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.
5
+ // Description: Node SDK package-root facade for tenant-aware clients, sidecar transport, MCP helpers, and bridge exports.
6
6
  //
7
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.
8
+ // - Defines the package-root SDK facade and re-export surface consumed by application code.
9
+ // - Keeps tenant-aware client, bridge, and tool APIs reachable through one stable import boundary.
10
10
  //
11
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.
12
+ // - Composes smaller modules rather than re-implementing transport or protocol logic at the package root.
13
+ // - Uses explicit exports so public surface changes remain auditable.
14
14
  //
15
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.
16
+ // - Prefer importing from this boundary when consuming the SDK from application code.
17
+ // - Public export changes here should be synchronized with language-specific packaging and documentation.
18
18
  //
19
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.
20
+ // - Top-level SDK package boundary for application-facing imports.
22
21
  //
23
22
  // Author: Silan.Hu
24
23
  // Email: silan.hu@u.nus.edu
@@ -157,7 +156,7 @@ export class Client {
157
156
  export function client(transport) {
158
157
  return new Client(transport);
159
158
  }
160
- export { createAbility, exportAbility, deployToNode, listAbilities, invokeAbility, uninstallAbility, discoverNodes, executeCommand, forgetAll, disconnectDevice, drainDevice, listRemoteTools, buildDeployPackage, deployPackage, startServer, toToolSpec, } from "./ability_lifecycle.js";
159
+ export { buildAbilityDescriptor, exportAbility, deployToNode, listAbilities, invokeAbility, uninstallAbility, discoverNodes, executeCommand, forgetAll, disconnectDevice, drainDevice, listRemoteTools, buildDeployPackage, deployPackage, startServer, toToolSpec, } from "./ability_lifecycle.js";
161
160
  export { AxonError, AxonConfigError, AxonBridgeError, AxonNotInstalledError, AxonNotActivatedError, AxonInvocationError, AxonStreamError, AxonPolicyDeniedError, AxonMcpError, AxonPartialSuccessError, AxonJsonError, AxonIoError, AxonSymbolNotFoundError, } from "./errors.js";
162
161
  export { beginPhase, skippedReceipt, buildDeployTrace, phaseFromTrace, PhaseReceiptBuilder, } from "./receipt.js";
163
162
  export { AbilityToolAdapter, } from "./tool_adapter.js";
@@ -1,3 +1,28 @@
1
+ // EasyNet Axon for AgentNet
2
+ // =========================
3
+ //
4
+ // File: sdk/node/src/mcp/server.test.js
5
+ // Description: JavaScript runtime mirror for `sdk/node/src/mcp/server.test.js` in the published Node SDK artifact set.
6
+ //
7
+ // Protocol Responsibility:
8
+ // - Preserves the exported API surface generated from the canonical TypeScript source module.
9
+ // - Keeps the distributable Node package consistent for consumers that import built artifacts directly.
10
+ //
11
+ // Implementation Approach:
12
+ // - Mirrors the canonical `.ts` module output and should not diverge semantically from source.
13
+ // - Exists as a distribution artifact so package consumers do not need the TypeScript authoring tree at runtime.
14
+ //
15
+ // Usage Contract:
16
+ // - Update this file through the Node SDK build pipeline when the corresponding TypeScript source changes.
17
+ // - Treat manual edits here as temporary at most; source-of-truth behavior lives in the `.ts` module.
18
+ //
19
+ // Architectural Position:
20
+ // - Published artifact boundary for the Node SDK distribution.
21
+ //
22
+ // Author: Silan.Hu
23
+ // Email: silan.hu@u.nus.edu
24
+ // Copyright (c) 2026-2027 easynet. All rights reserved.
25
+
1
26
  import assert from "node:assert/strict";
2
27
  import { describe, it } from "node:test";
3
28
  import { PassThrough } from "node:stream";
@@ -6,34 +31,47 @@ import { StdioMcpServer } from "./server.js";
6
31
 
7
32
  describe("StdioMcpServer", () => {
8
33
  it("keeps buffered stream responses intact when close throws", async () => {
34
+ const originalConsoleError = console.error;
35
+ const consoleErrors = [];
36
+ console.error = (...args) => {
37
+ consoleErrors.push(args);
38
+ };
39
+
9
40
  const server = new StdioMcpServer({
10
41
  toolSpecs: () => [],
11
42
  handleToolCall: () => ({ payload: { ok: true }, isError: false }),
12
43
  handleToolCallStream: () => ({
44
+ stream: {
45
+ async *[Symbol.asyncIterator]() {
46
+ yield Buffer.from("chunk-1");
47
+ },
48
+ },
13
49
  close() {
14
50
  throw new Error("close failed");
15
51
  },
16
- async *[Symbol.asyncIterator]() {
17
- yield Buffer.from("chunk-1");
18
- },
19
52
  }),
20
53
  });
21
54
 
22
- const response = await server.handleRequest({
23
- jsonrpc: "2.0",
24
- id: 1,
25
- method: "tools/call",
26
- params: {
27
- name: "streamed_tool",
28
- arguments: {},
29
- },
30
- });
55
+ try {
56
+ const response = await server.handleRequest({
57
+ jsonrpc: "2.0",
58
+ id: 1,
59
+ method: "tools/call",
60
+ params: {
61
+ name: "streamed_tool",
62
+ arguments: {},
63
+ },
64
+ });
31
65
 
32
- assert.equal(response.jsonrpc, "2.0");
33
- const payload = JSON.parse(response.result.content[0].text);
34
- assert.equal(payload.ok, true);
35
- assert.deepEqual(payload.chunks, ["chunk-1"]);
36
- assert.equal(response.result.isError, undefined);
66
+ assert.equal(response.jsonrpc, "2.0");
67
+ const payload = JSON.parse(response.result.content[0].text);
68
+ assert.equal(payload.ok, true);
69
+ assert.deepEqual(payload.chunks, ["chunk-1"]);
70
+ assert.equal(response.result.isError, undefined);
71
+ assert.equal(consoleErrors.length, 1);
72
+ } finally {
73
+ console.error = originalConsoleError;
74
+ }
37
75
  });
38
76
 
39
77
  it("serializes writes through drain backpressure", async () => {
@@ -24,9 +24,9 @@
24
24
  // Copyright (c) 2026-2027 easynet. All rights reserved.
25
25
  // Node server flow: publish/install/activate media capability on selected client and invoke tasks.
26
26
  import { Orchestrator } from "./orchestrator.js";
27
- import { existsSync, mkdirSync, readFileSync } from "node:fs";
28
- import { dirname, resolve } from "node:path";
29
- import { fileURLToPath } from "node:url";
27
+ import { resolveLibraryPath } from "../../dendrite_bridge/ffi.js";
28
+ import { mkdirSync, readFileSync } from "node:fs";
29
+ import { resolve } from "node:path";
30
30
  import { parseArgs, parsePositiveInt } from "./args.js";
31
31
  import { readBundleVersion, resolveBundlePath, sha256Prefixed } from "./bundle.js";
32
32
  import { decodeMediaBase64, defaultOutputDir, persistMediaFile } from "./media.js";
@@ -53,36 +53,14 @@ function resolveConfig(cfg) {
53
53
  taskPayloadBuilder: cfg?.taskPayloadBuilder ?? mediaCaptureTaskPayload,
54
54
  };
55
55
  }
56
- function defaultBridgeLibName() {
57
- if (process.platform === "darwin")
58
- return "libaxon_dendrite_bridge.dylib";
59
- if (process.platform === "win32")
60
- return "axon_dendrite_bridge.dll";
61
- return "libaxon_dendrite_bridge.so";
62
- }
63
- function findRepoRootForBridge(startDir) {
64
- let current = resolve(startDir);
65
- for (let steps = 0; steps < 10; steps += 1) {
66
- const candidate = resolve(current, "core/runtime-rs/dendrite-bridge/target/release", defaultBridgeLibName());
67
- if (existsSync(candidate)) {
68
- return current;
69
- }
70
- const parent = dirname(current);
71
- if (parent === current) {
72
- break;
73
- }
74
- current = parent;
75
- }
76
- return "";
77
- }
78
56
  function ensureBridgeLibEnv() {
79
57
  if (process.env.EASYNET_DENDRITE_BRIDGE_LIB)
80
58
  return;
81
- const here = dirname(fileURLToPath(import.meta.url));
82
- const repoRoot = findRepoRootForBridge(here) || process.cwd();
83
- const candidate = resolve(repoRoot, "core/runtime-rs/dendrite-bridge/target/release", defaultBridgeLibName());
84
- if (existsSync(candidate)) {
85
- process.env.EASYNET_DENDRITE_BRIDGE_LIB = candidate;
59
+ try {
60
+ process.env.EASYNET_DENDRITE_BRIDGE_LIB = resolveLibraryPath();
61
+ }
62
+ catch {
63
+ // Non-fatal: library may be resolved later by the bridge constructor.
86
64
  }
87
65
  }
88
66
  function extractInstallId(lifecycle) {
@@ -7,9 +7,7 @@
7
7
  // Author: Silan.Hu
8
8
  // Email: silan.hu@u.nus.edu
9
9
  // Copyright (c) 2026-2027 easynet. All rights reserved.
10
- import { existsSync } from "node:fs";
11
- import { dirname, resolve } from "node:path";
12
- import { fileURLToPath } from "node:url";
10
+ import { resolveLibraryPath } from "../../dendrite_bridge/ffi.js";
13
11
  export const DEFAULT_SIGNATURE = "__AXON_EPHEMERAL_DO_NOT_USE_IN_PROD__";
14
12
  export const DEFAULT_VERSION = "1.0.0";
15
13
  export const DEFAULT_INSTALL_TIMEOUT_SECONDS = 45;
@@ -30,16 +28,11 @@ export function ensureRemoteControlNativeLibEnv() {
30
28
  if (process.env.EASYNET_DENDRITE_BRIDGE_LIB) {
31
29
  return;
32
30
  }
33
- const moduleDir = dirname(fileURLToPath(import.meta.url));
34
- const candidates = [
35
- resolve(moduleDir, "..", "..", "core", "runtime-rs", "dendrite-bridge", "target", "release", defaultNativeLibName()),
36
- resolve(moduleDir, "..", "..", "core", "runtime-rs", "dendrite-bridge", "target", "debug", defaultNativeLibName()),
37
- ];
38
- for (const candidate of candidates) {
39
- if (existsSync(candidate)) {
40
- process.env.EASYNET_DENDRITE_BRIDGE_LIB = candidate;
41
- return;
42
- }
31
+ try {
32
+ process.env.EASYNET_DENDRITE_BRIDGE_LIB = resolveLibraryPath();
33
+ }
34
+ catch {
35
+ // Non-fatal: library may be resolved later by the bridge constructor.
43
36
  }
44
37
  }
45
38
  export function ensureNativeLibEnv() {
@@ -66,12 +59,3 @@ export function asNumber(raw) {
66
59
  const value = Number.parseInt(String(raw ?? "0"), 10);
67
60
  return Number.isFinite(value) ? value : 0;
68
61
  }
69
- function defaultNativeLibName() {
70
- if (process.platform === "darwin") {
71
- return "libaxon_dendrite_bridge.dylib";
72
- }
73
- if (process.platform === "win32") {
74
- return "axon_dendrite_bridge.dll";
75
- }
76
- return "libaxon_dendrite_bridge.so";
77
- }
@@ -1,3 +1,25 @@
1
+ export type AbilityTarget = "claude" | "codex" | "openclaw" | "agent_skills";
2
+ export interface AbilityDescriptorLite {
3
+ name: string;
4
+ toolName: string;
5
+ description: string;
6
+ commandTemplate: string;
7
+ inputSchema: JsonRecord;
8
+ outputSchema: JsonRecord;
9
+ version: string;
10
+ tags: string[];
11
+ resourceUri: string;
12
+ instructions: string;
13
+ inputExamples: JsonRecord[];
14
+ prerequisites: string[];
15
+ contextBindings: Record<string, string>;
16
+ category: string;
17
+ }
18
+ export interface AbilityExportResult {
19
+ abilityName: string;
20
+ abilityMd: string;
21
+ invokeScript: string;
22
+ }
1
23
  export interface JsonRecord {
2
24
  [key: string]: unknown;
3
25
  }
@@ -31,4 +53,18 @@ export declare function defaultOutputSchema(): JsonRecord;
31
53
  export declare function serializeDescriptor(descriptor: AbilityPackageDescriptor): JsonRecord;
32
54
  export declare function requireString(payload: JsonRecord, key: string): string;
33
55
  export declare function parseDescriptor(raw: unknown): AbilityPackageDescriptor;
56
+ /**
57
+ * Build an `AbilityPackageDescriptor` from handler arguments.
58
+ *
59
+ * Normalises names, generates a package ID, encodes the command template
60
+ * into Base64 package bytes, and serialises agent extension properties
61
+ * (instructions, input_examples, prerequisites, context_bindings, category)
62
+ * into the metadata map under the `mcp.*` prefix.
63
+ *
64
+ * @throws {Error} If `ability_name`, `command_template`, or `signature_base64` is missing.
65
+ */
34
66
  export declare function buildDescriptor(args: JsonRecord, defaultSignature: string): AbilityPackageDescriptor;
67
+ export declare function createAbilityDescriptor(args: JsonRecord): AbilityDescriptorLite;
68
+ declare function parseAbilityTarget(raw: string): AbilityTarget;
69
+ export declare function exportAbilitySkill(descriptor: AbilityDescriptorLite, target?: AbilityTarget, axonEndpoint?: string): AbilityExportResult;
70
+ export { parseAbilityTarget };