@clawnexus/sdk 0.1.0

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/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @clawnexus/sdk
2
+
3
+ ClawLink Protocol SDK — programmatic client for the ClawNexus daemon API.
4
+
5
+ Discover and manage OpenClaw-compatible AI instances from your Node.js applications.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @clawnexus/sdk
11
+ ```
12
+
13
+ Requires Node.js >= 22 and a running `clawnexus` daemon.
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { ClawNexusClient } from "@clawnexus/sdk";
19
+
20
+ const client = new ClawNexusClient();
21
+
22
+ // List all discovered instances
23
+ const { instances } = await client.listInstances();
24
+ console.log(instances);
25
+
26
+ // Get a specific instance by name or alias
27
+ const inst = await client.getInstance("home");
28
+ console.log(`${inst.alias} @ ${inst.address}:${inst.gateway_port}`);
29
+
30
+ // Scan the network
31
+ const scan = await client.scan();
32
+ console.log(`Found ${scan.discovered} instance(s)`);
33
+
34
+ // Set an alias
35
+ await client.setAlias("my-agent-id", "office");
36
+ ```
37
+
38
+ ## API Reference
39
+
40
+ ### Constructor
41
+
42
+ ```typescript
43
+ const client = new ClawNexusClient({
44
+ apiUrl: "http://localhost:17890", // default
45
+ timeout: 5000, // default, in ms
46
+ });
47
+ ```
48
+
49
+ ### Instance Methods
50
+
51
+ | Method | Returns | Description |
52
+ |--------|---------|-------------|
53
+ | `health()` | `Record<string, unknown>` | Daemon health status |
54
+ | `listInstances()` | `{ count, instances }` | List all known instances |
55
+ | `getInstance(id)` | `ClawInstance` | Get instance by ID, alias, or address |
56
+ | `setAlias(id, alias)` | `{ status, agent_id, alias }` | Set or update instance alias |
57
+ | `removeInstance(id)` | `{ status, removed }` | Remove instance from registry |
58
+ | `scan()` | `{ status, discovered, instances }` | Trigger network scan |
59
+ | `relayConnect(clawId)` | `{ status, target }` | Connect via relay |
60
+ | `relayStatus()` | `Record<string, unknown>` | Relay connection status |
61
+ | `relayDisconnect(roomId)` | `{ status, room_id }` | Disconnect relay room |
62
+
63
+ ### Error Handling
64
+
65
+ ```typescript
66
+ import { ClawNexusClient, ClawNexusApiError } from "@clawnexus/sdk";
67
+
68
+ const client = new ClawNexusClient();
69
+
70
+ try {
71
+ const inst = await client.getInstance("unknown");
72
+ } catch (err) {
73
+ if (err instanceof ClawNexusApiError) {
74
+ console.log(err.statusCode); // 404
75
+ console.log(err.message); // "Instance not found"
76
+ }
77
+ }
78
+ ```
79
+
80
+ ### Types
81
+
82
+ The SDK re-exports all core types:
83
+
84
+ ```typescript
85
+ import type {
86
+ ClawInstance,
87
+ PolicyConfig,
88
+ TaskRecord,
89
+ TaskStats,
90
+ InboxItem,
91
+ } from "@clawnexus/sdk";
92
+ ```
93
+
94
+ ## License
95
+
96
+ MIT
@@ -0,0 +1,97 @@
1
+ import type { ClawInstance, RegistryStatus, WhoamiResponse, PolicyConfig, TaskRecord, TaskStats, TaskDirection, TaskState, TaskSpec, InboxItem } from "./types.js";
2
+ export interface ClawNexusClientOptions {
3
+ apiUrl?: string;
4
+ timeout?: number;
5
+ }
6
+ export declare class ClawNexusClient {
7
+ private readonly apiUrl;
8
+ private readonly timeout;
9
+ constructor(options?: ClawNexusClientOptions);
10
+ health(): Promise<Record<string, unknown>>;
11
+ listInstances(): Promise<{
12
+ count: number;
13
+ instances: ClawInstance[];
14
+ }>;
15
+ getInstance(idOrName: string): Promise<ClawInstance>;
16
+ setAlias(idOrName: string, alias: string): Promise<{
17
+ status: string;
18
+ agent_id: string;
19
+ alias: string;
20
+ }>;
21
+ removeInstance(idOrName: string): Promise<{
22
+ status: string;
23
+ removed: string;
24
+ }>;
25
+ scan(): Promise<{
26
+ status: string;
27
+ discovered: number;
28
+ instances: ClawInstance[];
29
+ }>;
30
+ register(): Promise<{
31
+ status: string;
32
+ claw_name: string | null;
33
+ pubkey: string | null;
34
+ }>;
35
+ registryStatus(): Promise<RegistryStatus>;
36
+ resolve(name: string): Promise<ClawInstance>;
37
+ whoami(): Promise<WhoamiResponse>;
38
+ relayConnect(targetClawId: string): Promise<{
39
+ status: string;
40
+ target: string;
41
+ }>;
42
+ relayStatus(): Promise<Record<string, unknown>>;
43
+ relayDisconnect(roomId: string): Promise<{
44
+ status: string;
45
+ room_id: string;
46
+ }>;
47
+ getPolicy(): Promise<PolicyConfig>;
48
+ updatePolicy(policy: PolicyConfig): Promise<{
49
+ status: string;
50
+ }>;
51
+ patchPolicy(partial: Partial<PolicyConfig>): Promise<{
52
+ status: string;
53
+ policy: PolicyConfig;
54
+ }>;
55
+ resetPolicy(): Promise<{
56
+ status: string;
57
+ policy: PolicyConfig;
58
+ }>;
59
+ listTasks(opts?: {
60
+ all?: boolean;
61
+ direction?: TaskDirection;
62
+ state?: TaskState;
63
+ }): Promise<{
64
+ count: number;
65
+ tasks: TaskRecord[];
66
+ }>;
67
+ getTask(taskId: string): Promise<TaskRecord>;
68
+ cancelTask(taskId: string, reason?: string): Promise<{
69
+ status: string;
70
+ task: TaskRecord;
71
+ }>;
72
+ getTaskStats(): Promise<TaskStats>;
73
+ propose(targetClawId: string, roomId: string, task: TaskSpec): Promise<{
74
+ status: string;
75
+ task: TaskRecord;
76
+ }>;
77
+ query(targetClawId: string, roomId: string, queryType: "capabilities" | "status" | "availability"): Promise<{
78
+ status: string;
79
+ message_id: string;
80
+ }>;
81
+ getInbox(): Promise<{
82
+ count: number;
83
+ items: InboxItem[];
84
+ }>;
85
+ approveInbox(messageId: string): Promise<{
86
+ status: string;
87
+ task: TaskRecord;
88
+ }>;
89
+ denyInbox(messageId: string, reason?: string): Promise<{
90
+ status: string;
91
+ }>;
92
+ private request;
93
+ }
94
+ export declare class ClawNexusApiError extends Error {
95
+ readonly statusCode: number;
96
+ constructor(message: string, statusCode: number);
97
+ }
package/dist/client.js ADDED
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ // ClawNexus SDK — HTTP client for clawnexus daemon API
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ClawNexusApiError = exports.ClawNexusClient = void 0;
5
+ class ClawNexusClient {
6
+ apiUrl;
7
+ timeout;
8
+ constructor(options = {}) {
9
+ this.apiUrl = options.apiUrl ?? "http://localhost:17890";
10
+ this.timeout = options.timeout ?? 5000;
11
+ }
12
+ async health() {
13
+ return this.request("GET", "/health");
14
+ }
15
+ async listInstances() {
16
+ return this.request("GET", "/instances");
17
+ }
18
+ async getInstance(idOrName) {
19
+ return this.request("GET", `/instances/${encodeURIComponent(idOrName)}`);
20
+ }
21
+ async setAlias(idOrName, alias) {
22
+ return this.request("PUT", `/instances/${encodeURIComponent(idOrName)}/alias`, { alias });
23
+ }
24
+ async removeInstance(idOrName) {
25
+ return this.request("DELETE", `/instances/${encodeURIComponent(idOrName)}`);
26
+ }
27
+ async scan() {
28
+ return this.request("POST", "/scan");
29
+ }
30
+ // --- Registry (v0.2) ---
31
+ async register() {
32
+ return this.request("POST", "/registry/register");
33
+ }
34
+ async registryStatus() {
35
+ return this.request("GET", "/registry/status");
36
+ }
37
+ async resolve(name) {
38
+ return this.request("GET", `/resolve/${encodeURIComponent(name)}`);
39
+ }
40
+ async whoami() {
41
+ return this.request("GET", "/whoami");
42
+ }
43
+ // --- Relay ---
44
+ async relayConnect(targetClawId) {
45
+ return this.request("POST", "/relay/connect", { target_claw_id: targetClawId });
46
+ }
47
+ async relayStatus() {
48
+ return this.request("GET", "/relay/status");
49
+ }
50
+ async relayDisconnect(roomId) {
51
+ return this.request("DELETE", `/relay/disconnect/${encodeURIComponent(roomId)}`);
52
+ }
53
+ // --- Layer B: Agent / Policy ---
54
+ async getPolicy() {
55
+ return this.request("GET", "/agent/policy");
56
+ }
57
+ async updatePolicy(policy) {
58
+ return this.request("PUT", "/agent/policy", policy);
59
+ }
60
+ async patchPolicy(partial) {
61
+ return this.request("PATCH", "/agent/policy", partial);
62
+ }
63
+ async resetPolicy() {
64
+ return this.request("POST", "/agent/policy/reset");
65
+ }
66
+ // --- Layer B: Tasks ---
67
+ async listTasks(opts) {
68
+ const params = new URLSearchParams();
69
+ if (opts?.all)
70
+ params.set("all", "true");
71
+ if (opts?.direction)
72
+ params.set("direction", opts.direction);
73
+ if (opts?.state)
74
+ params.set("state", opts.state);
75
+ const qs = params.toString() ? `?${params.toString()}` : "";
76
+ return this.request("GET", `/agent/tasks${qs}`);
77
+ }
78
+ async getTask(taskId) {
79
+ return this.request("GET", `/agent/tasks/${encodeURIComponent(taskId)}`);
80
+ }
81
+ async cancelTask(taskId, reason) {
82
+ return this.request("POST", `/agent/tasks/${encodeURIComponent(taskId)}/cancel`, { reason });
83
+ }
84
+ async getTaskStats() {
85
+ return this.request("GET", "/agent/tasks/stats");
86
+ }
87
+ // --- Layer B: Propose / Query ---
88
+ async propose(targetClawId, roomId, task) {
89
+ return this.request("POST", "/agent/propose", { target_claw_id: targetClawId, room_id: roomId, task });
90
+ }
91
+ async query(targetClawId, roomId, queryType) {
92
+ return this.request("POST", "/agent/query", { target_claw_id: targetClawId, room_id: roomId, query_type: queryType });
93
+ }
94
+ // --- Layer B: Inbox ---
95
+ async getInbox() {
96
+ return this.request("GET", "/agent/inbox");
97
+ }
98
+ async approveInbox(messageId) {
99
+ return this.request("POST", `/agent/inbox/${encodeURIComponent(messageId)}/approve`);
100
+ }
101
+ async denyInbox(messageId, reason) {
102
+ return this.request("POST", `/agent/inbox/${encodeURIComponent(messageId)}/deny`, { reason });
103
+ }
104
+ async request(method, urlPath, body) {
105
+ const res = await fetch(`${this.apiUrl}${urlPath}`, {
106
+ method,
107
+ headers: body ? { "Content-Type": "application/json" } : undefined,
108
+ body: body ? JSON.stringify(body) : undefined,
109
+ signal: AbortSignal.timeout(this.timeout),
110
+ });
111
+ const data = await res.json();
112
+ if (!res.ok) {
113
+ const error = data.error ?? `HTTP ${res.status}`;
114
+ throw new ClawNexusApiError(error, res.status);
115
+ }
116
+ return data;
117
+ }
118
+ }
119
+ exports.ClawNexusClient = ClawNexusClient;
120
+ class ClawNexusApiError extends Error {
121
+ statusCode;
122
+ constructor(message, statusCode) {
123
+ super(message);
124
+ this.statusCode = statusCode;
125
+ this.name = "ClawNexusApiError";
126
+ }
127
+ }
128
+ exports.ClawNexusApiError = ClawNexusApiError;
@@ -0,0 +1,3 @@
1
+ export { ClawNexusClient, ClawNexusApiError } from './client.js';
2
+ export type { ClawNexusClientOptions } from './client.js';
3
+ export type { ClawInstance, RegistryFile, ControlUiConfig, PolicyConfig, TaskSpec, TaskState, TaskDirection, TaskRecord, TaskStats, InboxItem, } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // @clawnexus/sdk — ClawNexus SDK
3
+ // Discover and identify OpenClaw-compatible AI instances
4
+ // See: DESIGN_010_ecosystem_compatibility.md
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ClawNexusApiError = exports.ClawNexusClient = void 0;
7
+ var client_js_1 = require("./client.js");
8
+ Object.defineProperty(exports, "ClawNexusClient", { enumerable: true, get: function () { return client_js_1.ClawNexusClient; } });
9
+ Object.defineProperty(exports, "ClawNexusApiError", { enumerable: true, get: function () { return client_js_1.ClawNexusApiError; } });
@@ -0,0 +1,119 @@
1
+ export interface ClawInstance {
2
+ agent_id: string;
3
+ auto_name: string;
4
+ alias?: string;
5
+ assistant_name: string;
6
+ display_name: string;
7
+ lan_host: string;
8
+ address: string;
9
+ gateway_port: number;
10
+ tls: boolean;
11
+ tls_fingerprint?: string;
12
+ discovery_source: "mdns" | "scan" | "manual" | "local" | "registry";
13
+ network_scope: "local" | "vpn" | "public";
14
+ status: "online" | "offline" | "unknown";
15
+ last_seen: string;
16
+ discovered_at: string;
17
+ connectivity?: Connectivity;
18
+ is_self?: boolean;
19
+ claw_name?: string;
20
+ owner_pubkey?: string;
21
+ labels?: Record<string, string>;
22
+ }
23
+ export interface Connectivity {
24
+ lan_reachable: boolean;
25
+ relay_available: boolean;
26
+ preferred_channel: "lan" | "relay" | "local" | "unknown";
27
+ lan_latency_ms?: number;
28
+ last_lan_check: string;
29
+ unreachable_reason?: string;
30
+ }
31
+ export interface UnreachableInstance {
32
+ address: string;
33
+ port: number;
34
+ lan_host: string;
35
+ display_name: string;
36
+ reason: string;
37
+ discovered_at: string;
38
+ }
39
+ export interface RegistryFile {
40
+ schema_version: "2" | "3" | "4" | "5";
41
+ updated_at: string;
42
+ instances: ClawInstance[];
43
+ }
44
+ export interface ControlUiConfig {
45
+ assistantAgentId: string;
46
+ assistantName: string;
47
+ displayName?: string;
48
+ [key: string]: unknown;
49
+ }
50
+ export interface RegistryStatus {
51
+ registered: boolean;
52
+ claw_name: string | null;
53
+ pubkey: string | null;
54
+ }
55
+ export interface WhoamiResponse {
56
+ pubkey: string | null;
57
+ claw_name: string | null;
58
+ }
59
+ export interface PolicyConfig {
60
+ mode: "auto" | "queue" | "hybrid";
61
+ trust_threshold: number;
62
+ rate_limit: {
63
+ max_per_minute: number;
64
+ max_per_peer_minute: number;
65
+ };
66
+ delegation: {
67
+ allow: boolean;
68
+ max_depth: number;
69
+ };
70
+ capability_filter: string[];
71
+ access_control: {
72
+ whitelist: string[];
73
+ blacklist: string[];
74
+ };
75
+ auto_approve_types: string[];
76
+ max_concurrent_tasks: number;
77
+ }
78
+ export interface TaskSpec {
79
+ task_type: string;
80
+ description: string;
81
+ input?: Record<string, unknown>;
82
+ constraints?: {
83
+ max_duration_s?: number;
84
+ max_cost?: number;
85
+ priority?: "low" | "normal" | "high" | "critical";
86
+ };
87
+ delegation_depth?: number;
88
+ }
89
+ export type TaskState = "pending" | "accepted" | "executing" | "completed" | "failed" | "rejected" | "cancelled" | "timeout";
90
+ export type TaskDirection = "outbound" | "inbound";
91
+ export interface TaskRecord {
92
+ task_id: string;
93
+ direction: TaskDirection;
94
+ peer_claw_id: string;
95
+ task: TaskSpec;
96
+ state: TaskState;
97
+ created_at: string;
98
+ updated_at: string;
99
+ accepted_at?: string;
100
+ completed_at?: string;
101
+ result?: unknown;
102
+ error?: string;
103
+ progress_pct?: number;
104
+ message_id: string;
105
+ room_id?: string;
106
+ }
107
+ export interface TaskStats {
108
+ total: number;
109
+ by_state: Record<TaskState, number>;
110
+ by_direction: Record<TaskDirection, number>;
111
+ active: number;
112
+ }
113
+ export interface InboxItem {
114
+ message_id: string;
115
+ from: string;
116
+ type: string;
117
+ task?: TaskSpec;
118
+ timestamp: string;
119
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // Core types — mirrored from daemon for SDK consumers
3
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@clawnexus/sdk",
3
+ "version": "0.1.0",
4
+ "description": "ClawNexus SDK — programmatic client for discovering and managing OpenClaw instances",
5
+ "license": "MIT",
6
+ "author": "alan-silverstreams <alan@silverstream.tech>",
7
+ "homepage": "https://github.com/alan-silverstreams/ClawNexus",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/alan-silverstreams/ClawNexus.git",
11
+ "directory": "packages/sdk"
12
+ },
13
+ "bugs": "https://github.com/alan-silverstreams/ClawNexus/issues",
14
+ "keywords": [
15
+ "openclaw",
16
+ "ai",
17
+ "agent",
18
+ "sdk",
19
+ "clawlink",
20
+ "protocol",
21
+ "discovery",
22
+ "clawnexus"
23
+ ],
24
+ "main": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.json",
32
+ "dev": "tsc -p tsconfig.json --watch",
33
+ "test": "vitest run",
34
+ "prepublishOnly": "pnpm build"
35
+ },
36
+ "engines": {
37
+ "node": ">=22"
38
+ },
39
+ "devDependencies": {
40
+ "typescript": "^5.7.0",
41
+ "@types/node": "^22.0.0"
42
+ }
43
+ }