@synap-core/cli 0.9.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 +250 -0
- package/dist/commands/connect.d.ts +11 -0
- package/dist/commands/connect.js +96 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/finish.d.ts +16 -0
- package/dist/commands/finish.js +82 -0
- package/dist/commands/finish.js.map +1 -0
- package/dist/commands/init.d.ts +21 -0
- package/dist/commands/init.js +865 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/security-audit.d.ts +12 -0
- package/dist/commands/security-audit.js +100 -0
- package/dist/commands/security-audit.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.js +216 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +6 -0
- package/dist/commands/update.js +34 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +138 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth.d.ts +57 -0
- package/dist/lib/auth.js +322 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/hardening.d.ts +18 -0
- package/dist/lib/hardening.js +203 -0
- package/dist/lib/hardening.js.map +1 -0
- package/dist/lib/openclaw.d.ts +28 -0
- package/dist/lib/openclaw.js +106 -0
- package/dist/lib/openclaw.js.map +1 -0
- package/dist/lib/pod.d.ts +91 -0
- package/dist/lib/pod.js +305 -0
- package/dist/lib/pod.js.map +1 -0
- package/dist/lib/seed.d.ts +13 -0
- package/dist/lib/seed.js +135 -0
- package/dist/lib/seed.js.map +1 -0
- package/dist/lib/templates.d.ts +11 -0
- package/dist/lib/templates.js +13 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/templates/agent-os.json +3090 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.js +31 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw detection and configuration utilities.
|
|
3
|
+
* Reads/writes OpenClaw config without modifying unrelated settings.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, statSync } from "fs";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
const OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
10
|
+
const OPENCLAW_CONFIG = join(OPENCLAW_DIR, "openclaw.json");
|
|
11
|
+
const OPENCLAW_SKILLS = join(OPENCLAW_DIR, "skills");
|
|
12
|
+
export function detectOpenClaw() {
|
|
13
|
+
const info = { found: false };
|
|
14
|
+
// Check if OpenClaw directory exists
|
|
15
|
+
if (!existsSync(OPENCLAW_DIR))
|
|
16
|
+
return info;
|
|
17
|
+
info.found = true;
|
|
18
|
+
info.configPath = OPENCLAW_CONFIG;
|
|
19
|
+
info.skillsDir = OPENCLAW_SKILLS;
|
|
20
|
+
// Try to get version
|
|
21
|
+
try {
|
|
22
|
+
const out = execSync("openclaw --version 2>/dev/null", {
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
timeout: 5000,
|
|
25
|
+
}).trim();
|
|
26
|
+
const match = out.match(/\d+\.\d+\.\d+/);
|
|
27
|
+
if (match)
|
|
28
|
+
info.version = match[0];
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// openclaw binary not in PATH — might still be installed via npx
|
|
32
|
+
}
|
|
33
|
+
// Read config
|
|
34
|
+
if (existsSync(OPENCLAW_CONFIG)) {
|
|
35
|
+
try {
|
|
36
|
+
info.config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf-8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// corrupted config
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Check if gateway is running
|
|
43
|
+
try {
|
|
44
|
+
const port = info.config?.gateway?.port ?? 18789;
|
|
45
|
+
info.gatewayPort = port;
|
|
46
|
+
execSync(`curl -sf http://127.0.0.1:${port}/health >/dev/null 2>&1`, {
|
|
47
|
+
timeout: 3000,
|
|
48
|
+
});
|
|
49
|
+
info.gatewayRunning = true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
info.gatewayRunning = false;
|
|
53
|
+
}
|
|
54
|
+
return info;
|
|
55
|
+
}
|
|
56
|
+
export function readOpenClawConfig() {
|
|
57
|
+
if (!existsSync(OPENCLAW_CONFIG))
|
|
58
|
+
return null;
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf-8"));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function writeOpenClawConfig(config) {
|
|
67
|
+
writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
68
|
+
}
|
|
69
|
+
export function getConfigPermissions() {
|
|
70
|
+
try {
|
|
71
|
+
const stat = statSync(OPENCLAW_DIR);
|
|
72
|
+
const mode = (stat.mode & 0o777).toString(8);
|
|
73
|
+
return { mode, safe: (stat.mode & 0o077) === 0 }; // safe = no group/world perms
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return { mode: "???", safe: false };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get a nested config value safely.
|
|
81
|
+
*/
|
|
82
|
+
export function getConfigValue(config, path) {
|
|
83
|
+
const parts = path.split(".");
|
|
84
|
+
let current = config;
|
|
85
|
+
for (const part of parts) {
|
|
86
|
+
if (current == null || typeof current !== "object")
|
|
87
|
+
return undefined;
|
|
88
|
+
current = current[part];
|
|
89
|
+
}
|
|
90
|
+
return current;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set a nested config value.
|
|
94
|
+
*/
|
|
95
|
+
export function setConfigValue(config, path, value) {
|
|
96
|
+
const parts = path.split(".");
|
|
97
|
+
let current = config;
|
|
98
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
99
|
+
if (!(parts[i] in current) || typeof current[parts[i]] !== "object") {
|
|
100
|
+
current[parts[i]] = {};
|
|
101
|
+
}
|
|
102
|
+
current = current[parts[i]];
|
|
103
|
+
}
|
|
104
|
+
current[parts[parts.length - 1]] = value;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=openclaw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/lib/openclaw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synap pod connection and management utilities.
|
|
3
|
+
*/
|
|
4
|
+
export interface LocalPodConfig {
|
|
5
|
+
podUrl: string;
|
|
6
|
+
podId?: string;
|
|
7
|
+
workspaceId: string;
|
|
8
|
+
agentUserId: string;
|
|
9
|
+
hubApiKey: string;
|
|
10
|
+
savedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function saveLocalPodConfig(config: LocalPodConfig): void;
|
|
13
|
+
export declare function getLocalPodConfig(): LocalPodConfig | null;
|
|
14
|
+
export interface PodStatus {
|
|
15
|
+
url: string;
|
|
16
|
+
healthy: boolean;
|
|
17
|
+
version?: string;
|
|
18
|
+
entityCount?: number;
|
|
19
|
+
workspaceId?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a Synap pod is healthy.
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkPodHealth(podUrl: string): Promise<PodStatus>;
|
|
25
|
+
/**
|
|
26
|
+
* Create an agent user and API key on the pod.
|
|
27
|
+
* Uses the PROVISIONING_TOKEN for auth.
|
|
28
|
+
*/
|
|
29
|
+
export declare function setupAgent(podUrl: string, provisioningToken: string, agentType?: string): Promise<{
|
|
30
|
+
hubApiKey: string;
|
|
31
|
+
agentUserId: string;
|
|
32
|
+
workspaceId: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Install Docker and start a self-hosted Synap pod.
|
|
36
|
+
*/
|
|
37
|
+
export declare function startSelfHostedPod(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Install the synap skill into OpenClaw.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* Provision the CP-authenticated user on their pod.
|
|
43
|
+
* Calls the CP to get a handshake JWT, then calls /api/handshake on the pod.
|
|
44
|
+
* This ensures the user exists in the pod's users table before setup/agent runs.
|
|
45
|
+
* Safe to call multiple times — idempotent (Kratos upserts by email).
|
|
46
|
+
*/
|
|
47
|
+
export declare function provisionUserOnPod(podUrl: string, cpToken: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Generate an API key via the Control Plane (for authenticated users).
|
|
50
|
+
* The CP relays the request to the pod using its own authority.
|
|
51
|
+
*/
|
|
52
|
+
export declare function setupAgentViaCp(podUrl: string, cpToken: string, agentType?: string): Promise<{
|
|
53
|
+
hubApiKey: string;
|
|
54
|
+
agentUserId: string;
|
|
55
|
+
workspaceId: string;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Enable OpenClaw as a free addon on a SELF-HOSTED pod.
|
|
59
|
+
* Uses the PROVISIONING_TOKEN directly against the pod.
|
|
60
|
+
*/
|
|
61
|
+
export declare function enableOpenClawAddon(podUrl: string, provisioningToken: string): Promise<{
|
|
62
|
+
hubApiKey: string;
|
|
63
|
+
agentUserId: string;
|
|
64
|
+
workspaceId: string;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Enable OpenClaw as an addon on a MANAGED pod via the Control Plane.
|
|
68
|
+
* Calls POST /openclaw/provision on the CP (requires CP session token).
|
|
69
|
+
* Returns the podId so the caller can poll status if needed.
|
|
70
|
+
*/
|
|
71
|
+
export declare function enableOpenClawAddonManaged(cpToken: string, podUrl: string): Promise<{
|
|
72
|
+
podId: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Check server resources (RAM, disk).
|
|
76
|
+
*/
|
|
77
|
+
export declare function checkServerResources(): {
|
|
78
|
+
ramTotal: number;
|
|
79
|
+
ramFree: number;
|
|
80
|
+
diskFree: string;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Start OpenClaw as a Docker addon on the local server.
|
|
84
|
+
* Writes env vars to the pod's .env file and runs docker compose --profile openclaw.
|
|
85
|
+
* Only works when the CLI is running ON the pod server.
|
|
86
|
+
*/
|
|
87
|
+
export declare function startOpenClawOnServer(hubApiKey: string, agentUserId: string, workspaceId: string, podUrl: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Install the synap skill into OpenClaw.
|
|
90
|
+
*/
|
|
91
|
+
export declare function installSynapSkill(): void;
|
package/dist/lib/pod.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synap pod connection and management utilities.
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import os from "node:os";
|
|
8
|
+
const CP_URL = process.env.SYNAP_CP_URL ?? "https://api.synap.live";
|
|
9
|
+
// ─── Local CLI config (persists pod connection even without OpenClaw) ─────────
|
|
10
|
+
const CONFIG_DIR = path.join(os.homedir(), ".synap");
|
|
11
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, "pod-config.json");
|
|
12
|
+
export function saveLocalPodConfig(config) {
|
|
13
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
14
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
15
|
+
}
|
|
16
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
17
|
+
}
|
|
18
|
+
export function getLocalPodConfig() {
|
|
19
|
+
try {
|
|
20
|
+
if (!fs.existsSync(CONFIG_FILE))
|
|
21
|
+
return null;
|
|
22
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a Synap pod is healthy.
|
|
30
|
+
*/
|
|
31
|
+
export async function checkPodHealth(podUrl) {
|
|
32
|
+
const status = { url: podUrl, healthy: false };
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(`${podUrl}/health`, {
|
|
35
|
+
signal: AbortSignal.timeout(5000),
|
|
36
|
+
});
|
|
37
|
+
if (res.ok) {
|
|
38
|
+
status.healthy = true;
|
|
39
|
+
const data = (await res.json());
|
|
40
|
+
status.version = data.version;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// pod unreachable
|
|
45
|
+
}
|
|
46
|
+
return status;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create an agent user and API key on the pod.
|
|
50
|
+
* Uses the PROVISIONING_TOKEN for auth.
|
|
51
|
+
*/
|
|
52
|
+
export async function setupAgent(podUrl, provisioningToken, agentType = "openclaw") {
|
|
53
|
+
const res = await fetch(`${podUrl}/api/hub/setup/agent`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
Authorization: `Bearer ${provisioningToken}`,
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ agentType }),
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
const body = await res.text();
|
|
63
|
+
throw new Error(`Setup failed (HTTP ${res.status}): ${body}`);
|
|
64
|
+
}
|
|
65
|
+
return (await res.json());
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Install Docker and start a self-hosted Synap pod.
|
|
69
|
+
*/
|
|
70
|
+
export function startSelfHostedPod() {
|
|
71
|
+
execSync('curl -fsSL https://raw.githubusercontent.com/Synap-core/backend/main/install.sh | bash', { stdio: "inherit" });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Install the synap skill into OpenClaw.
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* Provision the CP-authenticated user on their pod.
|
|
78
|
+
* Calls the CP to get a handshake JWT, then calls /api/handshake on the pod.
|
|
79
|
+
* This ensures the user exists in the pod's users table before setup/agent runs.
|
|
80
|
+
* Safe to call multiple times — idempotent (Kratos upserts by email).
|
|
81
|
+
*/
|
|
82
|
+
export async function provisionUserOnPod(podUrl, cpToken) {
|
|
83
|
+
// Step 1: Get handshake JWT from CP
|
|
84
|
+
const jwtRes = await fetch(`${CP_URL}/pods/handshake-jwt`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
Authorization: `Bearer ${cpToken}`,
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify({ podUrl }),
|
|
91
|
+
signal: AbortSignal.timeout(10000),
|
|
92
|
+
});
|
|
93
|
+
if (!jwtRes.ok) {
|
|
94
|
+
const body = await jwtRes.text().catch(() => "");
|
|
95
|
+
throw new Error(`Could not get handshake JWT (HTTP ${jwtRes.status}): ${body.slice(0, 200)}`);
|
|
96
|
+
}
|
|
97
|
+
const { token } = (await jwtRes.json());
|
|
98
|
+
// Step 2: Call /api/handshake on the pod
|
|
99
|
+
const handshakeRes = await fetch(`${podUrl}/api/handshake`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
102
|
+
body: JSON.stringify({ token }),
|
|
103
|
+
signal: AbortSignal.timeout(15000),
|
|
104
|
+
});
|
|
105
|
+
// 200 = created/logged in, 409 = already exists (both are fine)
|
|
106
|
+
if (!handshakeRes.ok && handshakeRes.status !== 409) {
|
|
107
|
+
const body = await handshakeRes.text().catch(() => "");
|
|
108
|
+
throw new Error(`Pod handshake failed (HTTP ${handshakeRes.status}): ${body.slice(0, 200)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Generate an API key via the Control Plane (for authenticated users).
|
|
113
|
+
* The CP relays the request to the pod using its own authority.
|
|
114
|
+
*/
|
|
115
|
+
export async function setupAgentViaCp(podUrl, cpToken, agentType = "openclaw") {
|
|
116
|
+
// Call the CP which will relay to the pod
|
|
117
|
+
// The CP knows the pod's PROVISIONING_TOKEN (it provisioned the pod)
|
|
118
|
+
const res = await fetch(`${CP_URL}/pods/setup-agent`, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: {
|
|
121
|
+
"Content-Type": "application/json",
|
|
122
|
+
Authorization: `Bearer ${cpToken}`,
|
|
123
|
+
},
|
|
124
|
+
body: JSON.stringify({ podUrl, agentType }),
|
|
125
|
+
});
|
|
126
|
+
if (!res.ok) {
|
|
127
|
+
const body = await res.text();
|
|
128
|
+
throw new Error(`CP relay failed (HTTP ${res.status}): ${body}`);
|
|
129
|
+
}
|
|
130
|
+
return (await res.json());
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Enable OpenClaw as a free addon on a SELF-HOSTED pod.
|
|
134
|
+
* Uses the PROVISIONING_TOKEN directly against the pod.
|
|
135
|
+
*/
|
|
136
|
+
export async function enableOpenClawAddon(podUrl, provisioningToken) {
|
|
137
|
+
return await setupAgent(podUrl, provisioningToken, "openclaw");
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Enable OpenClaw as an addon on a MANAGED pod via the Control Plane.
|
|
141
|
+
* Calls POST /openclaw/provision on the CP (requires CP session token).
|
|
142
|
+
* Returns the podId so the caller can poll status if needed.
|
|
143
|
+
*/
|
|
144
|
+
export async function enableOpenClawAddonManaged(cpToken, podUrl) {
|
|
145
|
+
// Find the pod ID from the CP
|
|
146
|
+
const podsRes = await fetch(`${CP_URL}/pods`, {
|
|
147
|
+
headers: { Authorization: `Bearer ${cpToken}` },
|
|
148
|
+
signal: AbortSignal.timeout(10000),
|
|
149
|
+
});
|
|
150
|
+
if (!podsRes.ok)
|
|
151
|
+
throw new Error(`Could not fetch pods (HTTP ${podsRes.status})`);
|
|
152
|
+
const { pods } = (await podsRes.json());
|
|
153
|
+
const appDomain = "synap.live";
|
|
154
|
+
const pod = pods.find((p) => {
|
|
155
|
+
const url = p.customDomain ? `https://${p.customDomain}` : `https://${p.subdomain}.${appDomain}`;
|
|
156
|
+
return url === podUrl || podUrl.includes(p.subdomain);
|
|
157
|
+
});
|
|
158
|
+
if (!pod)
|
|
159
|
+
throw new Error("Pod not found on your account");
|
|
160
|
+
const provRes = await fetch(`${CP_URL}/openclaw/provision`, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
Authorization: `Bearer ${cpToken}`,
|
|
165
|
+
},
|
|
166
|
+
body: JSON.stringify({ podId: pod.id }),
|
|
167
|
+
signal: AbortSignal.timeout(15000),
|
|
168
|
+
});
|
|
169
|
+
if (!provRes.ok) {
|
|
170
|
+
const body = await provRes.text().catch(() => "");
|
|
171
|
+
throw new Error(`OpenClaw provision failed (HTTP ${provRes.status}): ${body.slice(0, 200)}`);
|
|
172
|
+
}
|
|
173
|
+
return { podId: pod.id };
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check server resources (RAM, disk).
|
|
177
|
+
*/
|
|
178
|
+
export function checkServerResources() {
|
|
179
|
+
let ramTotal = 0;
|
|
180
|
+
let ramFree = 0;
|
|
181
|
+
let diskFree = "unknown";
|
|
182
|
+
try {
|
|
183
|
+
const mem = execSync("free -m 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
184
|
+
encoding: "utf-8",
|
|
185
|
+
timeout: 3000,
|
|
186
|
+
});
|
|
187
|
+
const lines = mem.trim().split("\n");
|
|
188
|
+
if (lines.length > 1) {
|
|
189
|
+
const parts = lines[1].split(/\s+/);
|
|
190
|
+
ramTotal = parseInt(parts[1], 10) || 0;
|
|
191
|
+
ramFree = parseInt(parts[6] || parts[3], 10) || 0;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const bytes = parseInt(lines[0], 10);
|
|
195
|
+
if (bytes > 0) {
|
|
196
|
+
ramTotal = Math.round(bytes / 1024 / 1024);
|
|
197
|
+
ramFree = Math.round(ramTotal * 0.5);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch { /* can't detect */ }
|
|
202
|
+
try {
|
|
203
|
+
const df = execSync("df -h / 2>/dev/null | tail -1", {
|
|
204
|
+
encoding: "utf-8",
|
|
205
|
+
timeout: 3000,
|
|
206
|
+
});
|
|
207
|
+
diskFree = df.trim().split(/\s+/)[3] || "unknown";
|
|
208
|
+
}
|
|
209
|
+
catch { /* can't detect */ }
|
|
210
|
+
return { ramTotal, ramFree, diskFree };
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Start OpenClaw as a Docker addon on the local server.
|
|
214
|
+
* Writes env vars to the pod's .env file and runs docker compose --profile openclaw.
|
|
215
|
+
* Only works when the CLI is running ON the pod server.
|
|
216
|
+
*/
|
|
217
|
+
export function startOpenClawOnServer(hubApiKey, agentUserId, workspaceId, podUrl) {
|
|
218
|
+
// Find the deploy directory — try standard locations
|
|
219
|
+
const deployDirs = ["/srv/synap", "/opt/synap", process.cwd()];
|
|
220
|
+
const deployDir = deployDirs.find((d) => {
|
|
221
|
+
try {
|
|
222
|
+
return (fs.existsSync(path.join(d, "docker-compose.standalone.yml")) ||
|
|
223
|
+
fs.existsSync(path.join(d, "docker-compose.yml")));
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
if (!deployDir) {
|
|
230
|
+
throw new Error("Could not find Synap deploy directory. Expected at /srv/synap or /opt/synap.\n" +
|
|
231
|
+
"Run manually: docker compose --profile openclaw up -d openclaw");
|
|
232
|
+
}
|
|
233
|
+
// Update .env with OpenClaw vars (create or append)
|
|
234
|
+
const envFile = path.join(deployDir, ".env");
|
|
235
|
+
const envVars = {
|
|
236
|
+
OPENCLAW_HUB_API_KEY: hubApiKey,
|
|
237
|
+
SYNAP_AGENT_USER_ID: agentUserId,
|
|
238
|
+
SYNAP_WORKSPACE_ID: workspaceId,
|
|
239
|
+
SYNAP_POD_URL: podUrl,
|
|
240
|
+
};
|
|
241
|
+
let envContent = "";
|
|
242
|
+
try {
|
|
243
|
+
envContent = fs.existsSync(envFile) ? fs.readFileSync(envFile, "utf-8") : "";
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
/* start fresh */
|
|
247
|
+
}
|
|
248
|
+
// Update or append each var
|
|
249
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
250
|
+
const regex = new RegExp(`^${key}=.*`, "m");
|
|
251
|
+
const line = `${key}=${value}`;
|
|
252
|
+
if (regex.test(envContent)) {
|
|
253
|
+
envContent = envContent.replace(regex, line);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
envContent =
|
|
257
|
+
envContent.endsWith("\n") || envContent === ""
|
|
258
|
+
? envContent + line + "\n"
|
|
259
|
+
: envContent + "\n" + line + "\n";
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
fs.writeFileSync(envFile, envContent, { mode: 0o600 });
|
|
263
|
+
// Start OpenClaw container
|
|
264
|
+
const composeFile = fs.existsSync(path.join(deployDir, "docker-compose.standalone.yml"))
|
|
265
|
+
? "docker-compose.standalone.yml"
|
|
266
|
+
: "docker-compose.yml";
|
|
267
|
+
execSync(`docker compose -f ${composeFile} --profile openclaw up -d openclaw`, { stdio: "inherit", cwd: deployDir, timeout: 60000 });
|
|
268
|
+
// Poll health (up to 30s)
|
|
269
|
+
let healthy = false;
|
|
270
|
+
for (let i = 0; i < 6; i++) {
|
|
271
|
+
try {
|
|
272
|
+
const result = execSync("curl -sf http://localhost:18789/health", {
|
|
273
|
+
encoding: "utf-8",
|
|
274
|
+
timeout: 5000,
|
|
275
|
+
});
|
|
276
|
+
if (result.includes("ok") || result.includes("healthy")) {
|
|
277
|
+
healthy = true;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
/* not ready yet */
|
|
283
|
+
}
|
|
284
|
+
if (i < 5)
|
|
285
|
+
execSync("sleep 5");
|
|
286
|
+
}
|
|
287
|
+
if (!healthy) {
|
|
288
|
+
throw new Error("OpenClaw started but health check didn't pass in 30s.\n" +
|
|
289
|
+
"Check logs: docker compose logs openclaw");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Install the synap skill into OpenClaw.
|
|
294
|
+
*/
|
|
295
|
+
export function installSynapSkill() {
|
|
296
|
+
try {
|
|
297
|
+
execSync("openclaw skills install https://raw.githubusercontent.com/Synap-core/backend/main/skills/synap/SKILL.md", { stdio: "inherit", timeout: 30000 });
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// openclaw CLI might not be in PATH — provide manual command
|
|
301
|
+
throw new Error("Could not install skill automatically. Run manually:\n" +
|
|
302
|
+
" openclaw skills install https://raw.githubusercontent.com/Synap-core/backend/main/skills/synap/SKILL.md");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=pod.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pod.js","sourceRoot":"","sources":["../../src/lib/pod.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed Agent OS entities from OpenClaw config.
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects the OpenClaw agent, installed skills, and model provider,
|
|
5
|
+
* then creates corresponding entities in the Synap pod so the dashboard
|
|
6
|
+
* is pre-populated on first open.
|
|
7
|
+
*/
|
|
8
|
+
import type { OpenClawInfo } from "./openclaw.js";
|
|
9
|
+
/**
|
|
10
|
+
* Detect OpenClaw config and create Agent, Skill, Provider entities.
|
|
11
|
+
* Returns the number of entities created.
|
|
12
|
+
*/
|
|
13
|
+
export declare function seedAgentEntities(podUrl: string, apiKey: string, oc: OpenClawInfo): Promise<number>;
|
package/dist/lib/seed.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed Agent OS entities from OpenClaw config.
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects the OpenClaw agent, installed skills, and model provider,
|
|
5
|
+
* then creates corresponding entities in the Synap pod so the dashboard
|
|
6
|
+
* is pre-populated on first open.
|
|
7
|
+
*/
|
|
8
|
+
import { getConfigValue } from "./openclaw.js";
|
|
9
|
+
/**
|
|
10
|
+
* Detect OpenClaw config and create Agent, Skill, Provider entities.
|
|
11
|
+
* Returns the number of entities created.
|
|
12
|
+
*/
|
|
13
|
+
export async function seedAgentEntities(podUrl, apiKey, oc) {
|
|
14
|
+
const entities = [];
|
|
15
|
+
// 1. Agent entity — the OpenClaw instance itself
|
|
16
|
+
const agentProps = {
|
|
17
|
+
"agent-status": oc.gatewayRunning ? "Active" : "Idle",
|
|
18
|
+
"agent-runtime": "OpenClaw",
|
|
19
|
+
"agent-deployment": "Local Machine",
|
|
20
|
+
};
|
|
21
|
+
if (oc.version)
|
|
22
|
+
agentProps["agent-version"] = oc.version;
|
|
23
|
+
// Detect channels from config
|
|
24
|
+
if (oc.config) {
|
|
25
|
+
const channels = [];
|
|
26
|
+
const channelConfig = getConfigValue(oc.config, "channels");
|
|
27
|
+
if (channelConfig) {
|
|
28
|
+
if (channelConfig.telegram)
|
|
29
|
+
channels.push("Telegram");
|
|
30
|
+
if (channelConfig.discord)
|
|
31
|
+
channels.push("Discord");
|
|
32
|
+
if (channelConfig.slack)
|
|
33
|
+
channels.push("Slack");
|
|
34
|
+
if (channelConfig.whatsapp)
|
|
35
|
+
channels.push("WhatsApp");
|
|
36
|
+
if (channelConfig.email)
|
|
37
|
+
channels.push("Email");
|
|
38
|
+
}
|
|
39
|
+
// Always has CLI/TUI
|
|
40
|
+
channels.push("CLI");
|
|
41
|
+
agentProps["agent-channels"] = channels;
|
|
42
|
+
if (channels.length > 0)
|
|
43
|
+
agentProps["agent-channel"] = channels[0];
|
|
44
|
+
}
|
|
45
|
+
// Detect model
|
|
46
|
+
const model = oc.config
|
|
47
|
+
? getConfigValue(oc.config, "models.default") ??
|
|
48
|
+
getConfigValue(oc.config, "models.primary")
|
|
49
|
+
: undefined;
|
|
50
|
+
if (model)
|
|
51
|
+
agentProps["agent-model"] = model;
|
|
52
|
+
entities.push({
|
|
53
|
+
profileSlug: "agent",
|
|
54
|
+
title: `OpenClaw Agent${oc.version ? ` v${oc.version}` : ""}`,
|
|
55
|
+
properties: agentProps,
|
|
56
|
+
});
|
|
57
|
+
// 2. Skill entities — from installed skills
|
|
58
|
+
if (oc.config) {
|
|
59
|
+
const skills = getConfigValue(oc.config, "skills.installed");
|
|
60
|
+
if (Array.isArray(skills)) {
|
|
61
|
+
for (const skill of skills.slice(0, 10)) {
|
|
62
|
+
// cap at 10
|
|
63
|
+
const name = skill.name ?? skill.id ?? "Unknown Skill";
|
|
64
|
+
entities.push({
|
|
65
|
+
profileSlug: "skill",
|
|
66
|
+
title: name,
|
|
67
|
+
properties: {
|
|
68
|
+
"skill-category": "community",
|
|
69
|
+
"skill-source-url": skill.id
|
|
70
|
+
? `https://clawhub.io/skills/${skill.id}`
|
|
71
|
+
: undefined,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Always add synap skill
|
|
78
|
+
entities.push({
|
|
79
|
+
profileSlug: "skill",
|
|
80
|
+
title: "synap",
|
|
81
|
+
properties: {
|
|
82
|
+
"skill-category": "infrastructure",
|
|
83
|
+
"skill-source-url": "https://github.com/synap-core/backend/tree/main/skills/synap",
|
|
84
|
+
"skill-trust": "Verified",
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
// 3. Provider entity — model provider
|
|
88
|
+
if (oc.config) {
|
|
89
|
+
const providers = getConfigValue(oc.config, "models.providers");
|
|
90
|
+
if (providers) {
|
|
91
|
+
for (const [name, config] of Object.entries(providers).slice(0, 5)) {
|
|
92
|
+
const providerConfig = config;
|
|
93
|
+
entities.push({
|
|
94
|
+
profileSlug: "provider",
|
|
95
|
+
title: name.charAt(0).toUpperCase() + name.slice(1),
|
|
96
|
+
properties: {
|
|
97
|
+
"provider-type": name,
|
|
98
|
+
"provider-base-url": providerConfig.baseUrl,
|
|
99
|
+
"provider-key-health": providerConfig.apiKey
|
|
100
|
+
? "Healthy"
|
|
101
|
+
: "Missing",
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Create entities via Hub Protocol
|
|
108
|
+
let created = 0;
|
|
109
|
+
for (const entity of entities) {
|
|
110
|
+
try {
|
|
111
|
+
const res = await fetch(`${podUrl}/api/hub/entities`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: {
|
|
114
|
+
"Content-Type": "application/json",
|
|
115
|
+
Authorization: `Bearer ${apiKey}`,
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
userId: "system",
|
|
119
|
+
agentUserId: "system",
|
|
120
|
+
profileSlug: entity.profileSlug,
|
|
121
|
+
title: entity.title,
|
|
122
|
+
properties: entity.properties,
|
|
123
|
+
reasoning: "Auto-seeded by synap init",
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
if (res.ok)
|
|
127
|
+
created++;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// skip failed entities silently
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return created;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=seed.js.map
|