@synap-core/cli 1.2.0 → 1.5.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 +26 -0
- package/dist/commands/agents.d.ts +31 -0
- package/dist/commands/agents.js +478 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/connect.d.ts +18 -1
- package/dist/commands/connect.js +154 -74
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.d.ts +9 -0
- package/dist/commands/connections.js +161 -0
- package/dist/commands/connections.js.map +1 -0
- package/dist/commands/data.d.ts +43 -0
- package/dist/commands/data.js +387 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/finish.js +41 -8
- package/dist/commands/finish.js.map +1 -1
- package/dist/commands/infra.d.ts +21 -0
- package/dist/commands/infra.js +262 -0
- package/dist/commands/infra.js.map +1 -0
- package/dist/commands/init.js +188 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/knowledge.d.ts +36 -0
- package/dist/commands/knowledge.js +123 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/openclaw.d.ts +2 -0
- package/dist/commands/openclaw.js +300 -23
- package/dist/commands/openclaw.js.map +1 -1
- package/dist/commands/pods.d.ts +17 -0
- package/dist/commands/pods.js +371 -0
- package/dist/commands/pods.js.map +1 -0
- package/dist/commands/status.d.ts +14 -1
- package/dist/commands/status.js +78 -220
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts +11 -2
- package/dist/commands/update.js +116 -5
- package/dist/commands/update.js.map +1 -1
- package/dist/index.js +370 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/agents-config.d.ts +20 -0
- package/dist/lib/agents-config.js +45 -0
- package/dist/lib/agents-config.js.map +1 -0
- package/dist/lib/auth.d.ts +4 -0
- package/dist/lib/auth.js +4 -0
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/browser-auth.d.ts +35 -0
- package/dist/lib/browser-auth.js +170 -0
- package/dist/lib/browser-auth.js.map +1 -0
- package/dist/lib/hub-client.d.ts +17 -0
- package/dist/lib/hub-client.js +115 -0
- package/dist/lib/hub-client.js.map +1 -0
- package/dist/lib/openclaw.js +30 -19
- package/dist/lib/openclaw.js.map +1 -1
- package/dist/lib/pod.d.ts +32 -1
- package/dist/lib/pod.js +121 -9
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/skills-installer.d.ts +18 -0
- package/dist/lib/skills-installer.js +97 -0
- package/dist/lib/skills-installer.js.map +1 -0
- package/dist/lib/targets.d.ts +65 -0
- package/dist/lib/targets.js +673 -0
- package/dist/lib/targets.js.map +1 -0
- package/package.json +5 -3
- package/skills/README.md +91 -0
- package/skills/synap/README.md +76 -0
- package/skills/synap/SKILL.md +882 -0
- package/skills/synap/capture.md +170 -0
- package/skills/synap/governance.md +206 -0
- package/skills/synap/linking.md +128 -0
- package/skills/synap/scripts/orient.sh +28 -0
- package/skills/synap-schema/SKILL.md +231 -0
- package/skills/synap-schema/property-types.md +228 -0
- package/skills/synap-ui/SKILL.md +295 -0
- package/skills/synap-ui/bento-recipes.md +608 -0
- package/skills/synap-ui/view-types.md +259 -0
- package/skills/synap-ui/widget-catalog.md +305 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based connect flow — the recommended provisioning path.
|
|
3
|
+
*
|
|
4
|
+
* 1. Start a local HTTP server on an ephemeral port.
|
|
5
|
+
* 2. Build `{podUrl}/admin/connect?integration=cli&redirect_uri=http://127.0.0.1:<port>/callback`.
|
|
6
|
+
* 3. Open the user's default browser at that URL.
|
|
7
|
+
* 4. Admin UI authenticates the user (Kratos session), mints a scoped Hub
|
|
8
|
+
* Protocol API key via `trpc.apiKeys.connectIntegration`, and redirects
|
|
9
|
+
* to `http://127.0.0.1:<port>/callback?context={apiKey,podUrl,workspaceId}`.
|
|
10
|
+
* 5. Local server receives the callback, extracts credentials, shuts down.
|
|
11
|
+
*
|
|
12
|
+
* This is the same flow Raycast uses (via a `raycast://` deeplink) — for CLI
|
|
13
|
+
* we just swap the deeplink for a loopback HTTP URL. The admin UI's redirect
|
|
14
|
+
* whitelist accepts both.
|
|
15
|
+
*
|
|
16
|
+
* Security notes:
|
|
17
|
+
* - Loopback only (127.0.0.1) — no external network can intercept.
|
|
18
|
+
* - One-shot: server only handles the first /callback, then exits.
|
|
19
|
+
* - 5-minute timeout.
|
|
20
|
+
* - No CSRF token: single-use, host-local, bound to the process.
|
|
21
|
+
*/
|
|
22
|
+
export interface BrowserAuthResult {
|
|
23
|
+
apiKey: string;
|
|
24
|
+
podUrl: string;
|
|
25
|
+
workspaceId?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface BrowserAuthOptions {
|
|
28
|
+
podUrl: string;
|
|
29
|
+
integration: "cli" | "raycast" | "openclaw" | "custom";
|
|
30
|
+
/** Milliseconds to wait for the callback. Default 5min. */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
/** Hook invoked with the admin-panel URL right before opening the browser. */
|
|
33
|
+
onUrlReady?: (url: string) => void;
|
|
34
|
+
}
|
|
35
|
+
export declare function runBrowserAuth(opts: BrowserAuthOptions): Promise<BrowserAuthResult>;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-based connect flow — the recommended provisioning path.
|
|
3
|
+
*
|
|
4
|
+
* 1. Start a local HTTP server on an ephemeral port.
|
|
5
|
+
* 2. Build `{podUrl}/admin/connect?integration=cli&redirect_uri=http://127.0.0.1:<port>/callback`.
|
|
6
|
+
* 3. Open the user's default browser at that URL.
|
|
7
|
+
* 4. Admin UI authenticates the user (Kratos session), mints a scoped Hub
|
|
8
|
+
* Protocol API key via `trpc.apiKeys.connectIntegration`, and redirects
|
|
9
|
+
* to `http://127.0.0.1:<port>/callback?context={apiKey,podUrl,workspaceId}`.
|
|
10
|
+
* 5. Local server receives the callback, extracts credentials, shuts down.
|
|
11
|
+
*
|
|
12
|
+
* This is the same flow Raycast uses (via a `raycast://` deeplink) — for CLI
|
|
13
|
+
* we just swap the deeplink for a loopback HTTP URL. The admin UI's redirect
|
|
14
|
+
* whitelist accepts both.
|
|
15
|
+
*
|
|
16
|
+
* Security notes:
|
|
17
|
+
* - Loopback only (127.0.0.1) — no external network can intercept.
|
|
18
|
+
* - One-shot: server only handles the first /callback, then exits.
|
|
19
|
+
* - 5-minute timeout.
|
|
20
|
+
* - No CSRF token: single-use, host-local, bound to the process.
|
|
21
|
+
*/
|
|
22
|
+
import http from "node:http";
|
|
23
|
+
import { URL } from "node:url";
|
|
24
|
+
import { spawn } from "node:child_process";
|
|
25
|
+
export async function runBrowserAuth(opts) {
|
|
26
|
+
const podUrl = opts.podUrl.replace(/\/$/, "");
|
|
27
|
+
const timeoutMs = opts.timeoutMs ?? 5 * 60_000;
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const server = http.createServer();
|
|
30
|
+
let settled = false;
|
|
31
|
+
const settle = (fn) => {
|
|
32
|
+
if (settled)
|
|
33
|
+
return;
|
|
34
|
+
settled = true;
|
|
35
|
+
fn();
|
|
36
|
+
server.close();
|
|
37
|
+
clearTimeout(timeout);
|
|
38
|
+
};
|
|
39
|
+
const timeout = setTimeout(() => {
|
|
40
|
+
settle(() => reject(new Error("Timed out waiting for browser approval. Run again, or use --manual-key.")));
|
|
41
|
+
}, timeoutMs);
|
|
42
|
+
server.on("request", (req, res) => {
|
|
43
|
+
// Only accept GET /callback — reject anything else.
|
|
44
|
+
const reqUrl = new URL(req.url ?? "/", `http://127.0.0.1`);
|
|
45
|
+
if (reqUrl.pathname !== "/callback") {
|
|
46
|
+
res.writeHead(404).end("Not found");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const raw = reqUrl.searchParams.get("context");
|
|
50
|
+
if (!raw) {
|
|
51
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
52
|
+
res.end(errorHtml("No context received — try again."));
|
|
53
|
+
settle(() => reject(new Error("Callback missing `context` parameter")));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(raw);
|
|
58
|
+
if (!parsed.apiKey || !parsed.podUrl) {
|
|
59
|
+
throw new Error("Callback missing apiKey or podUrl");
|
|
60
|
+
}
|
|
61
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
62
|
+
res.end(successHtml(opts.integration));
|
|
63
|
+
settle(() => resolve({
|
|
64
|
+
apiKey: parsed.apiKey,
|
|
65
|
+
podUrl: parsed.podUrl,
|
|
66
|
+
workspaceId: parsed.workspaceId ?? undefined,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
71
|
+
res.end(errorHtml("Invalid callback payload."));
|
|
72
|
+
settle(() => reject(err instanceof Error ? err : new Error(String(err))));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
server.on("error", (err) => {
|
|
76
|
+
settle(() => reject(err));
|
|
77
|
+
});
|
|
78
|
+
server.listen(0, "127.0.0.1", () => {
|
|
79
|
+
const port = server.address().port;
|
|
80
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
81
|
+
const adminUrl = new URL(`${podUrl}/admin/connect`);
|
|
82
|
+
adminUrl.searchParams.set("integration", opts.integration);
|
|
83
|
+
adminUrl.searchParams.set("redirect_uri", redirectUri);
|
|
84
|
+
const fullUrl = adminUrl.toString();
|
|
85
|
+
opts.onUrlReady?.(fullUrl);
|
|
86
|
+
openBrowser(fullUrl).catch(() => {
|
|
87
|
+
// Browser open failure is non-fatal — user can paste the URL themselves.
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Cross-platform browser open. Returns when the launcher has been kicked off,
|
|
94
|
+
* not when the user has actually seen the page.
|
|
95
|
+
*/
|
|
96
|
+
async function openBrowser(url) {
|
|
97
|
+
const platform = process.platform;
|
|
98
|
+
const [command, args] = platform === "darwin"
|
|
99
|
+
? ["open", [url]]
|
|
100
|
+
: platform === "win32"
|
|
101
|
+
? ["cmd", ["/c", "start", "", url]]
|
|
102
|
+
: ["xdg-open", [url]];
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const child = spawn(command, args, {
|
|
105
|
+
stdio: "ignore",
|
|
106
|
+
detached: true,
|
|
107
|
+
});
|
|
108
|
+
child.once("error", reject);
|
|
109
|
+
child.once("spawn", () => {
|
|
110
|
+
child.unref();
|
|
111
|
+
resolve();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// ─── Page HTML ──────────────────────────────────────────────────────────────
|
|
116
|
+
// Short, no external deps, CLI-tool vibe. Shown once per connect.
|
|
117
|
+
function successHtml(integration) {
|
|
118
|
+
const label = integration.charAt(0).toUpperCase() + integration.slice(1);
|
|
119
|
+
return `<!doctype html>
|
|
120
|
+
<html lang="en">
|
|
121
|
+
<head><meta charset="utf-8"><title>Synap connected</title>
|
|
122
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
123
|
+
<style>
|
|
124
|
+
:root { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }
|
|
125
|
+
body { margin: 0; background: #0A0A0A; color: #FAFAFA; display: grid; place-items: center; min-height: 100vh; }
|
|
126
|
+
.card { max-width: 420px; padding: 32px; text-align: center; }
|
|
127
|
+
.check { width: 48px; height: 48px; margin: 0 auto 16px; border-radius: 9999px; background: rgba(16, 185, 129, 0.12); display: grid; place-items: center; color: #10B981; }
|
|
128
|
+
h1 { font-size: 20px; margin: 0 0 8px; font-weight: 600; letter-spacing: -0.01em; }
|
|
129
|
+
p { margin: 0; color: rgba(250, 250, 250, 0.6); font-size: 14px; line-height: 1.5; }
|
|
130
|
+
code { background: rgba(250, 250, 250, 0.08); padding: 2px 6px; border-radius: 4px; font-size: 12px; }
|
|
131
|
+
</style>
|
|
132
|
+
</head>
|
|
133
|
+
<body>
|
|
134
|
+
<div class="card">
|
|
135
|
+
<div class="check">
|
|
136
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
|
137
|
+
</div>
|
|
138
|
+
<h1>${label} connected</h1>
|
|
139
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
140
|
+
</div>
|
|
141
|
+
<script>setTimeout(() => window.close(), 3000);</script>
|
|
142
|
+
</body>
|
|
143
|
+
</html>`;
|
|
144
|
+
}
|
|
145
|
+
function errorHtml(reason) {
|
|
146
|
+
return `<!doctype html>
|
|
147
|
+
<html lang="en">
|
|
148
|
+
<head><meta charset="utf-8"><title>Synap connect failed</title>
|
|
149
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
150
|
+
<style>
|
|
151
|
+
:root { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }
|
|
152
|
+
body { margin: 0; background: #0A0A0A; color: #FAFAFA; display: grid; place-items: center; min-height: 100vh; }
|
|
153
|
+
.card { max-width: 420px; padding: 32px; text-align: center; }
|
|
154
|
+
.x { width: 48px; height: 48px; margin: 0 auto 16px; border-radius: 9999px; background: rgba(239, 68, 68, 0.12); display: grid; place-items: center; color: #EF4444; }
|
|
155
|
+
h1 { font-size: 20px; margin: 0 0 8px; font-weight: 600; }
|
|
156
|
+
p { margin: 0; color: rgba(250, 250, 250, 0.6); font-size: 14px; line-height: 1.5; }
|
|
157
|
+
</style>
|
|
158
|
+
</head>
|
|
159
|
+
<body>
|
|
160
|
+
<div class="card">
|
|
161
|
+
<div class="x">
|
|
162
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
163
|
+
</div>
|
|
164
|
+
<h1>Connect failed</h1>
|
|
165
|
+
<p>${reason}</p>
|
|
166
|
+
</div>
|
|
167
|
+
</body>
|
|
168
|
+
</html>`;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=browser-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-auth.js","sourceRoot":"","sources":["../../src/lib/browser-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface HubConfig {
|
|
2
|
+
podUrl: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
userId: string;
|
|
5
|
+
/** Active workspace — from `synap use`, pod default, or env var. Undefined if none configured. */
|
|
6
|
+
workspaceId?: string;
|
|
7
|
+
scopes?: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveUserId(cfg: HubConfig): Promise<string>;
|
|
10
|
+
export declare function assertScope(cfg: HubConfig, required: string): void;
|
|
11
|
+
export declare function resolveHubConfig(opts?: {
|
|
12
|
+
podUrl?: string;
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
}): Promise<HubConfig>;
|
|
15
|
+
export declare function hubGet(path: string, params: Record<string, string | number | undefined>, cfg: HubConfig): Promise<unknown>;
|
|
16
|
+
export declare function hubPost(path: string, body: unknown, cfg: HubConfig): Promise<unknown>;
|
|
17
|
+
export declare function hubPatch(path: string, body: unknown, cfg: HubConfig): Promise<unknown>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { getActivePodConfig, getActiveWorkspaceId, listPodProfiles } from "./pod.js";
|
|
2
|
+
import { resolveAgentOverride } from "./agents-config.js";
|
|
3
|
+
const userIdCache = new Map();
|
|
4
|
+
export async function resolveUserId(cfg) {
|
|
5
|
+
if (cfg.userId && cfg.userId !== "cli")
|
|
6
|
+
return cfg.userId;
|
|
7
|
+
const cached = userIdCache.get(cfg.apiKey);
|
|
8
|
+
if (cached)
|
|
9
|
+
return cached;
|
|
10
|
+
const me = await hubGet("/users/me", {}, cfg);
|
|
11
|
+
const id = String(me.id ?? cfg.userId);
|
|
12
|
+
userIdCache.set(cfg.apiKey, id);
|
|
13
|
+
return id;
|
|
14
|
+
}
|
|
15
|
+
export function assertScope(cfg, required) {
|
|
16
|
+
// scopes are on the HubConfig only if we fetched them; skip check if unknown
|
|
17
|
+
if (!cfg.scopes)
|
|
18
|
+
return;
|
|
19
|
+
if (!cfg.scopes.includes(required)) {
|
|
20
|
+
throw new Error(`API key is missing required scope: ${required}\n` +
|
|
21
|
+
`Re-run: synap connect --target=<surface> to get a key with the right scopes.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function resolveHubConfig(opts) {
|
|
25
|
+
// 1. Explicit flags (escape hatch)
|
|
26
|
+
if (opts?.podUrl && opts?.apiKey) {
|
|
27
|
+
return {
|
|
28
|
+
podUrl: opts.podUrl,
|
|
29
|
+
apiKey: opts.apiKey,
|
|
30
|
+
userId: process.env.SYNAP_USER_ID ?? "cli",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// 2. Agent override: SYNAP_AGENT env var selects a named identity
|
|
34
|
+
const agentOverride = resolveAgentOverride();
|
|
35
|
+
if (agentOverride) {
|
|
36
|
+
const profiles = listPodProfiles();
|
|
37
|
+
const podProfile = profiles.find(p => p.name === agentOverride.podName);
|
|
38
|
+
const podUrl = podProfile?.config.podUrl ?? getActivePodConfig()?.podUrl ?? "";
|
|
39
|
+
const envScopes = process.env.SYNAP_KEY_SCOPES;
|
|
40
|
+
return {
|
|
41
|
+
podUrl,
|
|
42
|
+
apiKey: agentOverride.apiKey,
|
|
43
|
+
userId: agentOverride.podName ?? "agent",
|
|
44
|
+
scopes: envScopes ? envScopes.split(",") : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// 3. Env vars — set by `synap connect --target=claude-code`
|
|
48
|
+
const envPod = process.env.SYNAP_POD_URL;
|
|
49
|
+
const envKey = process.env.SYNAP_HUB_API_KEY;
|
|
50
|
+
const envUser = process.env.SYNAP_USER_ID;
|
|
51
|
+
const envScopes = process.env.SYNAP_KEY_SCOPES;
|
|
52
|
+
const envWorkspace = process.env.SYNAP_WORKSPACE_ID;
|
|
53
|
+
if (envPod && envKey && envUser) {
|
|
54
|
+
return {
|
|
55
|
+
podUrl: envPod,
|
|
56
|
+
apiKey: envKey,
|
|
57
|
+
userId: envUser,
|
|
58
|
+
workspaceId: envWorkspace || getActiveWorkspaceId(),
|
|
59
|
+
scopes: envScopes ? envScopes.split(",") : undefined,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// 4. Active CLI pod profile
|
|
63
|
+
const config = getActivePodConfig();
|
|
64
|
+
if (!config)
|
|
65
|
+
throw new Error("No pod configured. Run: synap pods add");
|
|
66
|
+
return {
|
|
67
|
+
podUrl: config.podUrl,
|
|
68
|
+
apiKey: config.hubApiKey,
|
|
69
|
+
userId: config.agentUserId,
|
|
70
|
+
workspaceId: getActiveWorkspaceId(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export async function hubGet(path, params, cfg) {
|
|
74
|
+
const url = new URL(`${cfg.podUrl}/api/hub${path}`);
|
|
75
|
+
for (const [k, v] of Object.entries(params)) {
|
|
76
|
+
if (v !== undefined)
|
|
77
|
+
url.searchParams.set(k, String(v));
|
|
78
|
+
}
|
|
79
|
+
const res = await fetch(url.toString(), {
|
|
80
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}` },
|
|
81
|
+
signal: AbortSignal.timeout(15_000),
|
|
82
|
+
});
|
|
83
|
+
if (!res.ok) {
|
|
84
|
+
const body = await res.text().catch(() => "");
|
|
85
|
+
throw new Error(`Hub API error (HTTP ${res.status}): ${body.slice(0, 300)}`);
|
|
86
|
+
}
|
|
87
|
+
return res.json();
|
|
88
|
+
}
|
|
89
|
+
export async function hubPost(path, body, cfg) {
|
|
90
|
+
const res = await fetch(`${cfg.podUrl}/api/hub${path}`, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}`, "Content-Type": "application/json" },
|
|
93
|
+
body: JSON.stringify(body),
|
|
94
|
+
signal: AbortSignal.timeout(15_000),
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const bodyText = await res.text().catch(() => "");
|
|
98
|
+
throw new Error(`Hub API error (HTTP ${res.status}): ${bodyText.slice(0, 300)}`);
|
|
99
|
+
}
|
|
100
|
+
return res.json();
|
|
101
|
+
}
|
|
102
|
+
export async function hubPatch(path, body, cfg) {
|
|
103
|
+
const res = await fetch(`${cfg.podUrl}/api/hub${path}`, {
|
|
104
|
+
method: "PATCH",
|
|
105
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}`, "Content-Type": "application/json" },
|
|
106
|
+
body: JSON.stringify(body),
|
|
107
|
+
signal: AbortSignal.timeout(15_000),
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
const bodyText = await res.text().catch(() => "");
|
|
111
|
+
throw new Error(`Hub API error (HTTP ${res.status}): ${bodyText.slice(0, 300)}`);
|
|
112
|
+
}
|
|
113
|
+
return res.json();
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=hub-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-client.js","sourceRoot":"","sources":["../../src/lib/hub-client.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/openclaw.js
CHANGED
|
@@ -10,25 +10,42 @@ const OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
|
10
10
|
const OPENCLAW_CONFIG = join(OPENCLAW_DIR, "openclaw.json");
|
|
11
11
|
const OPENCLAW_SKILLS = join(OPENCLAW_DIR, "skills");
|
|
12
12
|
export function detectOpenClaw() {
|
|
13
|
-
//
|
|
14
|
-
|
|
13
|
+
// Detection priority:
|
|
14
|
+
// 1. Docker container (most reliable — actively running state)
|
|
15
|
+
// 2. Local install (openclaw binary in PATH + ~/.openclaw dir)
|
|
16
|
+
//
|
|
17
|
+
// Why Docker first: the presence of ~/.openclaw on the host doesn't prove
|
|
18
|
+
// OpenClaw is installed locally — it may be a stray directory, or the
|
|
19
|
+
// Synap deploy dir may live in the same home. A running Docker container
|
|
20
|
+
// is a much stronger signal.
|
|
21
|
+
// ── Path 1: Docker container ───────────────────────────────────────────
|
|
22
|
+
const dockerInfo = detectOpenClawDocker();
|
|
23
|
+
if (dockerInfo)
|
|
24
|
+
return dockerInfo;
|
|
25
|
+
// ── Path 2: Local install (npm -g or npx) ─────────────────────────────
|
|
26
|
+
// Require BOTH ~/.openclaw AND an `openclaw` binary in PATH.
|
|
27
|
+
// ~/.openclaw alone is not enough (could be a leftover dir).
|
|
28
|
+
let localBinaryVersion;
|
|
29
|
+
try {
|
|
30
|
+
const out = execSync("openclaw --version 2>/dev/null", {
|
|
31
|
+
encoding: "utf-8",
|
|
32
|
+
timeout: 5000,
|
|
33
|
+
}).trim();
|
|
34
|
+
const match = out.match(/\d+\.\d+\.\d+/);
|
|
35
|
+
if (match)
|
|
36
|
+
localBinaryVersion = match[0];
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// binary not in PATH — not a local install
|
|
40
|
+
}
|
|
41
|
+
if (existsSync(OPENCLAW_DIR) && localBinaryVersion) {
|
|
15
42
|
const info = {
|
|
16
43
|
found: true,
|
|
17
44
|
runtime: "local",
|
|
18
45
|
configPath: OPENCLAW_CONFIG,
|
|
19
46
|
skillsDir: OPENCLAW_SKILLS,
|
|
47
|
+
version: localBinaryVersion,
|
|
20
48
|
};
|
|
21
|
-
// Version
|
|
22
|
-
try {
|
|
23
|
-
const out = execSync("openclaw --version 2>/dev/null", {
|
|
24
|
-
encoding: "utf-8",
|
|
25
|
-
timeout: 5000,
|
|
26
|
-
}).trim();
|
|
27
|
-
const match = out.match(/\d+\.\d+\.\d+/);
|
|
28
|
-
if (match)
|
|
29
|
-
info.version = match[0];
|
|
30
|
-
}
|
|
31
|
-
catch { /* binary not in PATH */ }
|
|
32
49
|
// Config
|
|
33
50
|
if (existsSync(OPENCLAW_CONFIG)) {
|
|
34
51
|
try {
|
|
@@ -48,12 +65,6 @@ export function detectOpenClaw() {
|
|
|
48
65
|
}
|
|
49
66
|
return info;
|
|
50
67
|
}
|
|
51
|
-
// ── Path 2: Docker container ───────────────────────────────────────────
|
|
52
|
-
// OpenClaw may be running in Docker (no host ~/.openclaw dir).
|
|
53
|
-
// Detect by: (a) docker ps, (b) gateway health probe on port 18789.
|
|
54
|
-
const dockerInfo = detectOpenClawDocker();
|
|
55
|
-
if (dockerInfo)
|
|
56
|
-
return dockerInfo;
|
|
57
68
|
return { found: false };
|
|
58
69
|
}
|
|
59
70
|
function detectOpenClawDocker() {
|
package/dist/lib/openclaw.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/lib/openclaw.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAgBzC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAClD,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;AAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AAErD,MAAM,UAAU,cAAc;IAC5B,
|
|
1
|
+
{"version":3,"file":"openclaw.js","sourceRoot":"","sources":["../../src/lib/openclaw.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/pod.d.ts
CHANGED
|
@@ -7,10 +7,41 @@ export interface LocalPodConfig {
|
|
|
7
7
|
workspaceId: string;
|
|
8
8
|
agentUserId: string;
|
|
9
9
|
hubApiKey: string;
|
|
10
|
+
label?: string;
|
|
10
11
|
savedAt: string;
|
|
11
12
|
}
|
|
12
|
-
export
|
|
13
|
+
export type SurfaceName = "raycast" | "claude-code" | "claude-desktop" | "cursor" | "openclaw";
|
|
14
|
+
export interface MultiPodConfig {
|
|
15
|
+
activePod: string;
|
|
16
|
+
/** Per-surface pod overrides. When set, takes priority over activePod for that surface. */
|
|
17
|
+
surfaces?: Partial<Record<SurfaceName, string>>;
|
|
18
|
+
pods: Record<string, LocalPodConfig>;
|
|
19
|
+
/** Active workspace override — set by `synap use <workspaceId>`. Takes priority over the pod's default workspaceId. */
|
|
20
|
+
activeWorkspaceId?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Get the pod config for a specific surface, falling back to the global activePod. */
|
|
23
|
+
export declare function getSurfacePod(surface: SurfaceName): LocalPodConfig | null;
|
|
24
|
+
/** Get the name of the pod assigned to a surface (or the global active pod name). */
|
|
25
|
+
export declare function getSurfacePodName(surface: SurfaceName): string | null;
|
|
26
|
+
/** Assign a pod to a specific surface without changing the global activePod. */
|
|
27
|
+
export declare function setSurfacePod(surface: SurfaceName, podName: string): LocalPodConfig;
|
|
28
|
+
export declare function getActivePodConfig(surface?: SurfaceName): LocalPodConfig | null;
|
|
29
|
+
/** @deprecated Use getActivePodConfig() */
|
|
13
30
|
export declare function getLocalPodConfig(): LocalPodConfig | null;
|
|
31
|
+
export declare function listPodProfiles(): Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
config: LocalPodConfig;
|
|
34
|
+
active: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function addPodProfile(name: string, podConfig: LocalPodConfig): void;
|
|
37
|
+
export declare function setActivePod(name: string): LocalPodConfig;
|
|
38
|
+
/** Get the active workspace ID: explicit override first, then the pod default. */
|
|
39
|
+
export declare function getActiveWorkspaceId(): string | undefined;
|
|
40
|
+
/** Persist a workspace as the active context for all subsequent commands. */
|
|
41
|
+
export declare function setActiveWorkspaceId(workspaceId: string): void;
|
|
42
|
+
export declare function removePodProfile(name: string): void;
|
|
43
|
+
/** @deprecated Use addPodProfile("default", config) */
|
|
44
|
+
export declare function saveLocalPodConfig(podConfig: LocalPodConfig): void;
|
|
14
45
|
export interface PodStatus {
|
|
15
46
|
url: string;
|
|
16
47
|
healthy: boolean;
|
package/dist/lib/pod.js
CHANGED
|
@@ -6,24 +6,136 @@ import fs from "node:fs";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
const CP_URL = process.env.SYNAP_CP_URL ?? "https://api.synap.live";
|
|
9
|
-
// ─── Local CLI config (persists pod
|
|
9
|
+
// ─── Local CLI config (persists pod connections) ──────────────────────────────
|
|
10
10
|
const CONFIG_DIR = path.join(os.homedir(), ".synap");
|
|
11
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, "
|
|
12
|
-
|
|
11
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
12
|
+
const LEGACY_CONFIG_FILE = path.join(CONFIG_DIR, "pod-config.json");
|
|
13
|
+
function ensureConfigDir() {
|
|
13
14
|
if (!fs.existsSync(CONFIG_DIR)) {
|
|
14
15
|
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
15
16
|
}
|
|
16
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function readMultiConfig() {
|
|
19
|
+
// Read new format
|
|
19
20
|
try {
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
22
|
+
const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
|
|
23
|
+
if (parsed.pods)
|
|
24
|
+
return { activePod: parsed.activePod ?? "", pods: parsed.pods };
|
|
25
|
+
// File exists but has old/unrecognized shape — fall through to migration
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
|
-
catch {
|
|
28
|
+
catch { /* fall through */ }
|
|
29
|
+
// Migrate from legacy flat format
|
|
30
|
+
try {
|
|
31
|
+
if (fs.existsSync(LEGACY_CONFIG_FILE)) {
|
|
32
|
+
const legacy = JSON.parse(fs.readFileSync(LEGACY_CONFIG_FILE, "utf-8"));
|
|
33
|
+
if (legacy.podUrl) {
|
|
34
|
+
const migrated = { activePod: "default", pods: { default: legacy } };
|
|
35
|
+
writeMultiConfig(migrated);
|
|
36
|
+
return migrated;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch { /* fall through */ }
|
|
41
|
+
return { activePod: "", pods: {} };
|
|
42
|
+
}
|
|
43
|
+
function writeMultiConfig(config) {
|
|
44
|
+
ensureConfigDir();
|
|
45
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
46
|
+
}
|
|
47
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
48
|
+
/** Get the pod config for a specific surface, falling back to the global activePod. */
|
|
49
|
+
export function getSurfacePod(surface) {
|
|
50
|
+
const config = readMultiConfig();
|
|
51
|
+
const podName = config.surfaces?.[surface] ?? config.activePod;
|
|
52
|
+
if (!podName || !config.pods[podName])
|
|
53
|
+
return null;
|
|
54
|
+
return config.pods[podName];
|
|
55
|
+
}
|
|
56
|
+
/** Get the name of the pod assigned to a surface (or the global active pod name). */
|
|
57
|
+
export function getSurfacePodName(surface) {
|
|
58
|
+
const config = readMultiConfig();
|
|
59
|
+
return config.surfaces?.[surface] ?? config.activePod ?? null;
|
|
60
|
+
}
|
|
61
|
+
/** Assign a pod to a specific surface without changing the global activePod. */
|
|
62
|
+
export function setSurfacePod(surface, podName) {
|
|
63
|
+
const config = readMultiConfig();
|
|
64
|
+
if (!config.pods[podName])
|
|
65
|
+
throw new Error(`Pod profile '${podName}' not found`);
|
|
66
|
+
config.surfaces = config.surfaces ?? {};
|
|
67
|
+
config.surfaces[surface] = podName;
|
|
68
|
+
writeMultiConfig(config);
|
|
69
|
+
return config.pods[podName];
|
|
70
|
+
}
|
|
71
|
+
export function getActivePodConfig(surface) {
|
|
72
|
+
if (surface)
|
|
73
|
+
return getSurfacePod(surface);
|
|
74
|
+
const config = readMultiConfig();
|
|
75
|
+
if (!config.activePod || !config.pods[config.activePod])
|
|
25
76
|
return null;
|
|
77
|
+
return config.pods[config.activePod];
|
|
78
|
+
}
|
|
79
|
+
/** @deprecated Use getActivePodConfig() */
|
|
80
|
+
export function getLocalPodConfig() {
|
|
81
|
+
return getActivePodConfig();
|
|
82
|
+
}
|
|
83
|
+
export function listPodProfiles() {
|
|
84
|
+
const config = readMultiConfig();
|
|
85
|
+
return Object.entries(config.pods).map(([name, podConfig]) => ({
|
|
86
|
+
name,
|
|
87
|
+
config: podConfig,
|
|
88
|
+
active: name === config.activePod,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
export function addPodProfile(name, podConfig) {
|
|
92
|
+
const config = readMultiConfig();
|
|
93
|
+
config.pods[name] = podConfig;
|
|
94
|
+
if (!config.activePod)
|
|
95
|
+
config.activePod = name;
|
|
96
|
+
writeMultiConfig(config);
|
|
97
|
+
}
|
|
98
|
+
export function setActivePod(name) {
|
|
99
|
+
const config = readMultiConfig();
|
|
100
|
+
if (!config.pods[name])
|
|
101
|
+
throw new Error(`Pod profile '${name}' not found`);
|
|
102
|
+
config.activePod = name;
|
|
103
|
+
writeMultiConfig(config);
|
|
104
|
+
return config.pods[name];
|
|
105
|
+
}
|
|
106
|
+
/** Get the active workspace ID: explicit override first, then the pod default. */
|
|
107
|
+
export function getActiveWorkspaceId() {
|
|
108
|
+
const config = readMultiConfig();
|
|
109
|
+
if (config.activeWorkspaceId)
|
|
110
|
+
return config.activeWorkspaceId;
|
|
111
|
+
const pod = config.activePod ? config.pods[config.activePod] : undefined;
|
|
112
|
+
return pod?.workspaceId || undefined;
|
|
113
|
+
}
|
|
114
|
+
/** Persist a workspace as the active context for all subsequent commands. */
|
|
115
|
+
export function setActiveWorkspaceId(workspaceId) {
|
|
116
|
+
const config = readMultiConfig();
|
|
117
|
+
config.activeWorkspaceId = workspaceId;
|
|
118
|
+
writeMultiConfig(config);
|
|
119
|
+
}
|
|
120
|
+
export function removePodProfile(name) {
|
|
121
|
+
const config = readMultiConfig();
|
|
122
|
+
if (!config.pods[name])
|
|
123
|
+
throw new Error(`Pod profile '${name}' not found`);
|
|
124
|
+
delete config.pods[name];
|
|
125
|
+
if (config.activePod === name) {
|
|
126
|
+
const remaining = Object.keys(config.pods);
|
|
127
|
+
config.activePod = remaining[0] ?? "";
|
|
26
128
|
}
|
|
129
|
+
writeMultiConfig(config);
|
|
130
|
+
}
|
|
131
|
+
/** @deprecated Use addPodProfile("default", config) */
|
|
132
|
+
export function saveLocalPodConfig(podConfig) {
|
|
133
|
+
const config = readMultiConfig();
|
|
134
|
+
const name = config.activePod || "default";
|
|
135
|
+
config.pods[name] = podConfig;
|
|
136
|
+
if (!config.activePod)
|
|
137
|
+
config.activePod = name;
|
|
138
|
+
writeMultiConfig(config);
|
|
27
139
|
}
|
|
28
140
|
/**
|
|
29
141
|
* Check if a Synap pod is healthy.
|