@synap-core/cli 1.12.2 → 1.13.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/LICENSE +21 -0
- package/README.md +25 -8
- package/dist/build-info.json +2 -2
- package/dist/commands/agents.d.ts +0 -1
- package/dist/commands/agents.js +1 -1
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/app.js +2 -1
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/automation.js +46 -41
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/box.d.ts +42 -0
- package/dist/commands/box.js +89 -0
- package/dist/commands/box.js.map +1 -0
- package/dist/commands/bridge-setup.js +3 -1
- package/dist/commands/bridge-setup.js.map +1 -1
- package/dist/commands/capability.d.ts +1 -1
- package/dist/commands/capability.js +57 -34
- package/dist/commands/capability.js.map +1 -1
- package/dist/commands/close-questions.d.ts +27 -0
- package/dist/commands/close-questions.js +49 -0
- package/dist/commands/close-questions.js.map +1 -0
- package/dist/commands/close-questions.test.d.ts +1 -0
- package/dist/commands/close-questions.test.js +52 -0
- package/dist/commands/close-questions.test.js.map +1 -0
- package/dist/commands/connect.d.ts +1 -3
- package/dist/commands/connect.js +2 -2
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/context.js +72 -43
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.js +12 -4
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.js +2 -1
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/doctor.d.ts +21 -0
- package/dist/commands/doctor.js +108 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hooks.d.ts +19 -0
- package/dist/commands/hooks.js +70 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/import.d.ts +25 -0
- package/dist/commands/import.js +98 -12
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.js +59 -19
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/knowledge.js +4 -2
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/lens.js +2 -1
- package/dist/commands/lens.js.map +1 -1
- package/dist/commands/market-authoring.js +1 -1
- package/dist/commands/market-authoring.js.map +1 -1
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/observe.category.test.d.ts +1 -0
- package/dist/commands/observe.category.test.js +59 -0
- package/dist/commands/observe.category.test.js.map +1 -0
- package/dist/commands/observe.d.ts +3 -0
- package/dist/commands/observe.js +7 -5
- package/dist/commands/observe.js.map +1 -1
- package/dist/commands/observe.title.test.d.ts +1 -0
- package/dist/commands/observe.title.test.js +37 -0
- package/dist/commands/observe.title.test.js.map +1 -0
- package/dist/commands/playbook.js +9 -0
- package/dist/commands/playbook.js.map +1 -1
- package/dist/commands/pods.d.ts +6 -1
- package/dist/commands/pods.js +32 -15
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proton-setup.js +3 -1
- package/dist/commands/proton-setup.js.map +1 -1
- package/dist/commands/session-feed-wait.d.ts +48 -0
- package/dist/commands/session-feed-wait.js +261 -0
- package/dist/commands/session-feed-wait.js.map +1 -0
- package/dist/commands/session-post.d.ts +40 -0
- package/dist/commands/session-post.js +96 -0
- package/dist/commands/session-post.js.map +1 -0
- package/dist/commands/session-wait.d.ts +9 -4
- package/dist/commands/session-wait.js +20 -5
- package/dist/commands/session-wait.js.map +1 -1
- package/dist/commands/sessions.d.ts +2 -0
- package/dist/commands/sessions.js +23 -0
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/skills-commands.d.ts +2 -0
- package/dist/commands/skills-commands.js +9 -1
- package/dist/commands/skills-commands.js.map +1 -1
- package/dist/commands/skills-commands.test.d.ts +1 -0
- package/dist/commands/skills-commands.test.js +57 -0
- package/dist/commands/skills-commands.test.js.map +1 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/template.d.ts +42 -0
- package/dist/commands/template.js +191 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/tracks.d.ts +67 -6
- package/dist/commands/tracks.js +268 -16
- package/dist/commands/tracks.js.map +1 -1
- package/dist/commands/whoami.d.ts +7 -0
- package/dist/commands/whoami.js +17 -0
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/worker-accounts.d.ts +149 -0
- package/dist/commands/worker-accounts.js +339 -0
- package/dist/commands/worker-accounts.js.map +1 -0
- package/dist/commands/worker-accounts.test.d.ts +1 -0
- package/dist/commands/worker-accounts.test.js +224 -0
- package/dist/commands/worker-accounts.test.js.map +1 -0
- package/dist/commands/worker.d.ts +219 -10
- package/dist/commands/worker.js +749 -117
- package/dist/commands/worker.js.map +1 -1
- package/dist/commands/worker.test.js +321 -10
- package/dist/commands/worker.test.js.map +1 -1
- package/dist/index.js +164 -27
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-door.d.ts +1 -3
- package/dist/lib/agent-door.js +10 -7
- package/dist/lib/agent-door.js.map +1 -1
- package/dist/lib/auth.d.ts +3 -2
- package/dist/lib/auth.js +3 -3
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/box/egress.d.ts +82 -0
- package/dist/lib/box/egress.js +264 -0
- package/dist/lib/box/egress.js.map +1 -0
- package/dist/lib/box/evidence.d.ts +86 -0
- package/dist/lib/box/evidence.js +121 -0
- package/dist/lib/box/evidence.js.map +1 -0
- package/dist/lib/box/job-server.d.ts +72 -0
- package/dist/lib/box/job-server.js +246 -0
- package/dist/lib/box/job-server.js.map +1 -0
- package/dist/lib/box/provisioner.d.ts +83 -0
- package/dist/lib/box/provisioner.js +312 -0
- package/dist/lib/box/provisioner.js.map +1 -0
- package/dist/lib/box/proxmox.d.ts +112 -0
- package/dist/lib/box/proxmox.js +211 -0
- package/dist/lib/box/proxmox.js.map +1 -0
- package/dist/lib/box/wire.d.ts +98 -0
- package/dist/lib/box/wire.js +70 -0
- package/dist/lib/box/wire.js.map +1 -0
- 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/client-header.test.d.ts +1 -0
- package/dist/lib/client-header.test.js +85 -0
- package/dist/lib/client-header.test.js.map +1 -0
- package/dist/lib/conversation-headers.d.ts +24 -9
- package/dist/lib/conversation-headers.js +40 -3
- package/dist/lib/conversation-headers.js.map +1 -1
- package/dist/lib/credential-class.d.ts +28 -1
- package/dist/lib/credential-class.js +28 -6
- package/dist/lib/credential-class.js.map +1 -1
- package/dist/lib/exporter-coverage.d.ts +1 -1
- package/dist/lib/exporter-coverage.js +1 -1
- package/dist/lib/goal-words.d.ts +38 -0
- package/dist/lib/goal-words.js +112 -0
- package/dist/lib/goal-words.js.map +1 -0
- package/dist/lib/hub-client.d.ts +28 -7
- package/dist/lib/hub-client.js +75 -34
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/init-handoff.d.ts +8 -0
- package/dist/lib/init-handoff.js +9 -2
- package/dist/lib/init-handoff.js.map +1 -1
- package/dist/lib/key-source.d.ts +3 -1
- package/dist/lib/key-source.js +7 -4
- package/dist/lib/key-source.js.map +1 -1
- package/dist/lib/knowledge-title.d.ts +3 -2
- package/dist/lib/knowledge-title.js +3 -2
- package/dist/lib/knowledge-title.js.map +1 -1
- package/dist/lib/mcp-bridge.d.ts +7 -0
- package/dist/lib/mcp-bridge.js +34 -1
- package/dist/lib/mcp-bridge.js.map +1 -1
- package/dist/lib/mcp-bridge.test.js +31 -3
- package/dist/lib/mcp-bridge.test.js.map +1 -1
- package/dist/lib/openclaw.d.ts +32 -0
- package/dist/lib/openclaw.js +165 -0
- package/dist/lib/openclaw.js.map +1 -0
- package/dist/lib/pod-moved.d.ts +70 -0
- package/dist/lib/pod-moved.js +146 -0
- package/dist/lib/pod-moved.js.map +1 -0
- package/dist/lib/pod-reach.d.ts +39 -0
- package/dist/lib/pod-reach.js +117 -0
- package/dist/lib/pod-reach.js.map +1 -0
- package/dist/lib/pod-reach.test.d.ts +1 -0
- package/dist/lib/pod-reach.test.js +67 -0
- package/dist/lib/pod-reach.test.js.map +1 -0
- package/dist/lib/pod.d.ts +8 -0
- package/dist/lib/pod.js +12 -3
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
- package/dist/lib/register-claude-code-mcp.test.js +78 -0
- package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
- package/dist/lib/review-credential.js +3 -1
- package/dist/lib/review-credential.js.map +1 -1
- 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/session-feed.d.ts +185 -0
- package/dist/lib/session-feed.js +257 -0
- package/dist/lib/session-feed.js.map +1 -0
- package/dist/lib/targets.d.ts +21 -3
- package/dist/lib/targets.js +52 -107
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/wake-hook-settings.d.ts +57 -0
- package/dist/lib/wake-hook-settings.js +153 -0
- package/dist/lib/wake-hook-settings.js.map +1 -0
- package/dist/lib/wake-state.d.ts +65 -0
- package/dist/lib/wake-state.js +122 -0
- package/dist/lib/wake-state.js.map +1 -0
- package/package.json +5 -2
- package/skills/README.md +1 -1
- package/skills/agent-os/SKILL.md +8 -8
- package/skills/synap/SKILL.md +141 -84
- package/skills/synap/code-skills.md +70 -0
- package/skills/synap/concepts.md +28 -20
- package/skills/synap/creative-loop.md +1 -1
- package/skills/synap/document-embeds.md +3 -1
- package/skills/synap/focus-sessions.md +16 -7
- package/skills/synap/from-intent.md +32 -16
- package/skills/synap/governance-rules.md +1 -1
- package/skills/synap/lenses.md +4 -4
- package/skills/synap/linking.md +2 -2
- package/skills/synap/mental-model.md +1 -1
- package/skills/synap/operating-mode-rules.md +1 -1
- package/skills/synap/quick-reference.md +2 -1
- package/skills/synap/reflexes.md +6 -6
- package/skills/synap/viewframe-cells.md +1 -1
- package/skills/synap/work-model.md +24 -10
- package/skills/synap/workspace-design.md +5 -5
- package/skills/synap/writes.md +16 -9
- package/skills/synap-app/SKILL.md +148 -66
- package/skills/synap-app/creating-the-base-app.md +12 -7
- package/skills/synap-app/governance.md +27 -16
- package/skills/synap-app/install-commands.md +18 -9
- package/skills/synap-app/overview.md +16 -9
- package/skills/synap-app/using-the-sdk.md +75 -25
- package/skills/synap-schema/SKILL.md +21 -21
- package/skills/synap-schema/intent-vocabulary-ssot.md +21 -21
- package/templates/box/runner.py +206 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxmox.js","sourceRoot":"","sources":["../../../src/lib/box/proxmox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pod side of a box run, as the provisioner sees it: lease, heartbeat,
|
|
3
|
+
* upload, finish. ONE module, so the wire shape lives in one place. Contract:
|
|
4
|
+
* lanes/code-runtime/BOX-CONTRACT.md v2 (2026-10-26, owned by the pod lane),
|
|
5
|
+
* Hub routes `/api/hub/box-runs/*`.
|
|
6
|
+
*
|
|
7
|
+
* Every call carries the COMPUTER's own key (device flow, scope `box.runner`):
|
|
8
|
+
* the provisioner is a computer that pulls runs, never an agent.
|
|
9
|
+
*/
|
|
10
|
+
import type { HubConfig } from "../hub-client.js";
|
|
11
|
+
import type { BlockedEgress } from "./egress.js";
|
|
12
|
+
import type { InstalledPackage, RunLog } from "./evidence.js";
|
|
13
|
+
export type BoxLanguage = "python" | "node";
|
|
14
|
+
export interface BoxLimits {
|
|
15
|
+
wallSeconds: number;
|
|
16
|
+
cpus: number;
|
|
17
|
+
memoryMb: number;
|
|
18
|
+
diskMb: number;
|
|
19
|
+
outMb: number;
|
|
20
|
+
}
|
|
21
|
+
export interface BoxScript {
|
|
22
|
+
skillId: string;
|
|
23
|
+
name: string;
|
|
24
|
+
language: BoxLanguage;
|
|
25
|
+
entrypoint: string;
|
|
26
|
+
code: string;
|
|
27
|
+
packages: Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
version: string;
|
|
30
|
+
}>;
|
|
31
|
+
/** Run-phase egress allowlist: host names, optionally `host:port`. */
|
|
32
|
+
hosts: string[];
|
|
33
|
+
limits: BoxLimits;
|
|
34
|
+
}
|
|
35
|
+
export interface LeasedRun {
|
|
36
|
+
id: string;
|
|
37
|
+
leaseId: string;
|
|
38
|
+
leaseExpiresAt: string;
|
|
39
|
+
heartbeatIntervalSeconds: number;
|
|
40
|
+
script: BoxScript;
|
|
41
|
+
parameters: unknown;
|
|
42
|
+
queuedAt: string;
|
|
43
|
+
attempt: number;
|
|
44
|
+
}
|
|
45
|
+
export interface HeartbeatReply {
|
|
46
|
+
leaseExpiresAt: string;
|
|
47
|
+
stopRequested: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface UploadTicket {
|
|
50
|
+
uploadUrl: string;
|
|
51
|
+
method: string;
|
|
52
|
+
headers: Record<string, string>;
|
|
53
|
+
uploadToken: string;
|
|
54
|
+
expiresAt: string;
|
|
55
|
+
maxBytes: number;
|
|
56
|
+
}
|
|
57
|
+
/** BOX-CONTRACT v2: timeout and infra are stored as failed with the verdict kept. */
|
|
58
|
+
export type FinishStatus = "done" | "failed" | "stopped" | "timeout" | "infra";
|
|
59
|
+
export interface FinishedFile {
|
|
60
|
+
path: string;
|
|
61
|
+
size: number;
|
|
62
|
+
sha256: string;
|
|
63
|
+
/** Absent when the file could not be uploaded: it is recorded in the evidence only. */
|
|
64
|
+
uploadToken?: string;
|
|
65
|
+
title?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface FinishBody {
|
|
68
|
+
leaseId: string;
|
|
69
|
+
status: FinishStatus;
|
|
70
|
+
exitCode: number | null;
|
|
71
|
+
durationMs: number;
|
|
72
|
+
/** Required when status = infra. */
|
|
73
|
+
infraReason?: string;
|
|
74
|
+
log: RunLog;
|
|
75
|
+
files: FinishedFile[];
|
|
76
|
+
blockedEgress: BlockedEgress[];
|
|
77
|
+
installedPackages: InstalledPackage[];
|
|
78
|
+
}
|
|
79
|
+
/** 404 / 409: the pod no longer holds this lease for us. Stop, destroy, never finish. */
|
|
80
|
+
export declare class LeaseLostError extends Error {
|
|
81
|
+
constructor(runId: string, status: number);
|
|
82
|
+
}
|
|
83
|
+
/** The run has no workspace: its files cannot be stored (record them `stored: false`). */
|
|
84
|
+
export declare class WorkspaceRequiredError extends Error {
|
|
85
|
+
constructor();
|
|
86
|
+
}
|
|
87
|
+
export interface BoxHub {
|
|
88
|
+
lease(): Promise<LeasedRun | null>;
|
|
89
|
+
heartbeat(run: LeasedRun, phase: "setup" | "running"): Promise<HeartbeatReply>;
|
|
90
|
+
upload(run: LeasedRun, file: {
|
|
91
|
+
filename: string;
|
|
92
|
+
mimeType: string;
|
|
93
|
+
bytes: Buffer;
|
|
94
|
+
}): Promise<string>;
|
|
95
|
+
finish(run: LeasedRun, body: FinishBody): Promise<unknown>;
|
|
96
|
+
}
|
|
97
|
+
export type FetchLike = (url: string, init: RequestInit) => Promise<Response>;
|
|
98
|
+
export declare function createBoxHub(cfg: Pick<HubConfig, "podUrl" | "apiKey">, fetchImpl?: FetchLike): BoxHub;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pod side of a box run, as the provisioner sees it: lease, heartbeat,
|
|
3
|
+
* upload, finish. ONE module, so the wire shape lives in one place. Contract:
|
|
4
|
+
* lanes/code-runtime/BOX-CONTRACT.md v2 (2026-10-26, owned by the pod lane),
|
|
5
|
+
* Hub routes `/api/hub/box-runs/*`.
|
|
6
|
+
*
|
|
7
|
+
* Every call carries the COMPUTER's own key (device flow, scope `box.runner`):
|
|
8
|
+
* the provisioner is a computer that pulls runs, never an agent.
|
|
9
|
+
*/
|
|
10
|
+
/** 404 / 409: the pod no longer holds this lease for us. Stop, destroy, never finish. */
|
|
11
|
+
export class LeaseLostError extends Error {
|
|
12
|
+
constructor(runId, status) {
|
|
13
|
+
super(`lease on box run ${runId} lost (HTTP ${status})`);
|
|
14
|
+
this.name = "LeaseLostError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** The run has no workspace: its files cannot be stored (record them `stored: false`). */
|
|
18
|
+
export class WorkspaceRequiredError extends Error {
|
|
19
|
+
constructor() {
|
|
20
|
+
super("the run has no workspace: its files cannot be stored");
|
|
21
|
+
this.name = "WorkspaceRequiredError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function createBoxHub(cfg, fetchImpl = fetch) {
|
|
25
|
+
const base = `${cfg.podUrl.replace(/\/+$/, "")}/api/hub/box-runs`;
|
|
26
|
+
async function post(path, body, runId) {
|
|
27
|
+
const res = await fetchImpl(`${base}${path}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}`, "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify(body),
|
|
31
|
+
signal: AbortSignal.timeout(30_000),
|
|
32
|
+
});
|
|
33
|
+
if (runId && (res.status === 404 || res.status === 409))
|
|
34
|
+
throw new LeaseLostError(runId, res.status);
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
const text = await res.text().catch(() => "");
|
|
37
|
+
if (res.status === 400 && /WORKSPACE_REQUIRED/.test(text))
|
|
38
|
+
throw new WorkspaceRequiredError();
|
|
39
|
+
throw new Error(`POST box-runs${path} failed (HTTP ${res.status})${text ? `: ${text.slice(0, 300)}` : ""}`);
|
|
40
|
+
}
|
|
41
|
+
return res.json();
|
|
42
|
+
}
|
|
43
|
+
const runPath = (run, verb) => `/${encodeURIComponent(run.id)}/${verb}`;
|
|
44
|
+
return {
|
|
45
|
+
async lease() {
|
|
46
|
+
const body = (await post("/lease", {}));
|
|
47
|
+
return body.run ?? null;
|
|
48
|
+
},
|
|
49
|
+
async heartbeat(run, phase) {
|
|
50
|
+
return (await post(runPath(run, "heartbeat"), { leaseId: run.leaseId, phase }, run.id));
|
|
51
|
+
},
|
|
52
|
+
async upload(run, file) {
|
|
53
|
+
const ticket = (await post(runPath(run, "uploads"), { leaseId: run.leaseId, filename: file.filename, mimeType: file.mimeType, size: file.bytes.length }, run.id));
|
|
54
|
+
// Straight to object storage with exactly the headers the pod signed.
|
|
55
|
+
const put = await fetchImpl(ticket.uploadUrl, {
|
|
56
|
+
method: ticket.method || "PUT",
|
|
57
|
+
headers: ticket.headers,
|
|
58
|
+
body: new Uint8Array(file.bytes),
|
|
59
|
+
signal: AbortSignal.timeout(10 * 60_000),
|
|
60
|
+
});
|
|
61
|
+
if (!put.ok)
|
|
62
|
+
throw new Error(`storing ${file.filename} failed (HTTP ${put.status})`);
|
|
63
|
+
return ticket.uploadToken;
|
|
64
|
+
},
|
|
65
|
+
async finish(run, body) {
|
|
66
|
+
return post(runPath(run, "finish"), body, run.id);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=wire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire.js","sourceRoot":"","sources":["../../../src/lib/box/wire.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every call names its client program (`X-Synap-Client: <name>/<version>`), so
|
|
3
|
+
* the pod's usage telemetry can tell the CLI, its stdio MCP bridge and the
|
|
4
|
+
* synap-bridge mod apart on one key and one conversation.
|
|
5
|
+
*
|
|
6
|
+
* Driven through the real doors: `hubGet` (every Hub call goes through
|
|
7
|
+
* `sessionHeaders`), the real bridge pump, and the `synap mcp bridge` command.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { PassThrough } from "node:stream";
|
|
11
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
12
|
+
const captured = vi.hoisted(() => ({ opts: undefined }));
|
|
13
|
+
vi.mock("./mcp-bridge.js", async (orig) => {
|
|
14
|
+
const real = await orig();
|
|
15
|
+
return {
|
|
16
|
+
...real,
|
|
17
|
+
runMcpBridge: vi.fn(async (opts) => {
|
|
18
|
+
captured.opts = opts;
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
import { hubGet } from "./hub-client.js";
|
|
23
|
+
import { mcpBridgeHeaders, CLIENT_HEADER, clientHeader } from "./conversation-headers.js";
|
|
24
|
+
import { mcpBridge } from "../commands/mcp.js";
|
|
25
|
+
const VERSION = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8")).version;
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
vi.unstubAllGlobals();
|
|
28
|
+
vi.unstubAllEnvs();
|
|
29
|
+
});
|
|
30
|
+
describe("X-Synap-Client", () => {
|
|
31
|
+
it("names the package version; an unusable version says unknown", () => {
|
|
32
|
+
expect(VERSION).toMatch(/^\d+\.\d+\.\d+/);
|
|
33
|
+
expect(clientHeader("synap-cli")).toEqual({ [CLIENT_HEADER]: `synap-cli/${VERSION}` });
|
|
34
|
+
expect(clientHeader("synap-cli", "1 2")).toEqual({ [CLIENT_HEADER]: "synap-cli/unknown" });
|
|
35
|
+
});
|
|
36
|
+
it("every Hub call sends synap-cli/<version>", async () => {
|
|
37
|
+
const seen = [];
|
|
38
|
+
vi.stubGlobal("fetch", vi.fn(async (_url, init) => {
|
|
39
|
+
seen.push(init.headers);
|
|
40
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
41
|
+
status: 200,
|
|
42
|
+
headers: { "content-type": "application/json" },
|
|
43
|
+
});
|
|
44
|
+
}));
|
|
45
|
+
await hubGet("/workspaces", {}, { podUrl: "https://pod.example", apiKey: "k" });
|
|
46
|
+
expect(seen).toHaveLength(1);
|
|
47
|
+
expect(seen[0][CLIENT_HEADER]).toBe(`synap-cli/${VERSION}`);
|
|
48
|
+
});
|
|
49
|
+
it("the stdio MCP bridge sends synap-cli-mcp/<version> on every request", async () => {
|
|
50
|
+
const { runMcpBridge } = await vi.importActual("./mcp-bridge.js");
|
|
51
|
+
const input = new PassThrough();
|
|
52
|
+
const output = new PassThrough();
|
|
53
|
+
const sent = [];
|
|
54
|
+
const fetchImpl = (async (_u, init) => {
|
|
55
|
+
sent.push(init.headers);
|
|
56
|
+
return new Response(JSON.stringify({ jsonrpc: "2.0", id: sent.length, result: {} }), {
|
|
57
|
+
status: 200,
|
|
58
|
+
headers: { "content-type": "application/json" },
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
const done = runMcpBridge({
|
|
62
|
+
url: "https://pod/mcp",
|
|
63
|
+
apiKey: "k",
|
|
64
|
+
headers: mcpBridgeHeaders(undefined, "/x"),
|
|
65
|
+
input,
|
|
66
|
+
output,
|
|
67
|
+
fetchImpl,
|
|
68
|
+
log: () => { },
|
|
69
|
+
});
|
|
70
|
+
input.write(JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: {} }) + "\n");
|
|
71
|
+
input.write(JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }) + "\n");
|
|
72
|
+
input.end();
|
|
73
|
+
await done;
|
|
74
|
+
expect(sent.length).toBe(2);
|
|
75
|
+
for (const h of sent)
|
|
76
|
+
expect(h[CLIENT_HEADER]).toBe(`synap-cli-mcp/${VERSION}`);
|
|
77
|
+
});
|
|
78
|
+
it("`synap mcp bridge` hands the bridge those headers", async () => {
|
|
79
|
+
vi.stubEnv("SYNAP_HUB_API_KEY", "k");
|
|
80
|
+
await mcpBridge({ url: "https://pod/mcp" });
|
|
81
|
+
expect(captured.opts?.headers?.[CLIENT_HEADER]).toBe(`synap-cli-mcp/${VERSION}`);
|
|
82
|
+
expect(captured.opts?.headers?.["X-Synap-Conversation"]).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=client-header.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-header.test.js","sourceRoot":"","sources":["../../src/lib/client-header.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The headers that name the calling CONVERSATION to the pod — the agent's own
|
|
3
|
-
* id, the one a person can reopen (`claude --resume <id>`). The pod reads
|
|
4
|
-
* `X-Synap-Conversation` as the conversation half of the client key, so every
|
|
5
|
-
* session the conversation touches records it (`resolveAgentConversation`,
|
|
6
|
-
* @synap-core/types/agents). Sent by every Hub call (`hub-client.ts`) and by
|
|
7
|
-
* the stdio MCP bridge (`mcp-bridge.ts`). Empty outside Claude Code.
|
|
8
|
-
*/
|
|
9
1
|
export declare const CONVERSATION_HEADER = "X-Synap-Conversation";
|
|
10
2
|
export declare const CONVERSATION_CWD_HEADER = "X-Synap-Conversation-Cwd";
|
|
3
|
+
/**
|
|
4
|
+
* Which CLIENT program makes the call, `<name>/<version>`: `synap-cli/<v>` for
|
|
5
|
+
* the CLI's Hub calls, `synap-cli-mcp/<v>` for the stdio MCP bridge (and
|
|
6
|
+
* `synap-bridge/<v>` from the Claude Code mod). The pod counts calls per client
|
|
7
|
+
* in its usage telemetry, so two programs sharing one key and one conversation
|
|
8
|
+
* can be told apart. Never an identity: it only labels the count.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CLIENT_HEADER = "X-Synap-Client";
|
|
11
|
+
export type SynapClientName = "synap-cli" | "synap-cli-mcp";
|
|
12
|
+
/** `{ "X-Synap-Client": "<name>/<version>" }`; the version is the package's. */
|
|
13
|
+
export declare function clientHeader(name: SynapClientName, version?: string): Record<string, string>;
|
|
14
|
+
/** The same two values in a request's `params._meta` (reverse-DNS vendor keys; `io.modelcontextprotocol/` is reserved). */
|
|
15
|
+
export declare const CONVERSATION_META_KEY = "live.synap/conversation";
|
|
16
|
+
export declare const CONVERSATION_CWD_META_KEY = "live.synap/conversationCwd";
|
|
11
17
|
/** `claude-code:<uuid>` for the Claude Code conversation we run in, if any. */
|
|
12
18
|
export declare function claudeCodeConversation(sessionId: string | undefined): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* `synap-cli:<id>` for a run outside Claude Code: `SYNAP_RUN_ID` when the caller
|
|
21
|
+
* names one (a multi-command script), else a UUID minted once per process. An
|
|
22
|
+
* unusable `SYNAP_RUN_ID` falls back to the process id rather than failing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function cliConversation(env?: NodeJS.ProcessEnv): string;
|
|
13
25
|
/**
|
|
14
26
|
* The headers for `sessionId` (pass it explicitly: the CLI's live id is
|
|
15
27
|
* `getClaudeSessionId()`, a stdio server's is its spawn env). Empty without a
|
|
16
|
-
* real Claude Code id
|
|
28
|
+
* real Claude Code id the run names itself (`cliConversation`); the cwd rides
|
|
29
|
+
* only with a Claude Code conversation (the one a person can reopen).
|
|
17
30
|
*/
|
|
18
31
|
export declare function conversationHeaders(sessionId: string | undefined, cwd?: string): Record<string, string>;
|
|
32
|
+
/** Every header the stdio MCP bridge sends: its client name plus the conversation. */
|
|
33
|
+
export declare function mcpBridgeHeaders(sessionId: string | undefined, cwd?: string): Record<string, string>;
|
|
@@ -4,29 +4,66 @@
|
|
|
4
4
|
* `X-Synap-Conversation` as the conversation half of the client key, so every
|
|
5
5
|
* session the conversation touches records it (`resolveAgentConversation`,
|
|
6
6
|
* @synap-core/types/agents). Sent by every Hub call (`hub-client.ts`) and by
|
|
7
|
-
* the stdio MCP bridge (`mcp-bridge.ts`).
|
|
7
|
+
* the stdio MCP bridge (`mcp-bridge.ts`). Outside Claude Code the conversation is
|
|
8
|
+
* this process's own run (`synap-cli:<uuid>`, or `SYNAP_RUN_ID` to span a script).
|
|
8
9
|
*/
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { cliBuild } from "./cli-build.js";
|
|
9
12
|
export const CONVERSATION_HEADER = "X-Synap-Conversation";
|
|
10
13
|
export const CONVERSATION_CWD_HEADER = "X-Synap-Conversation-Cwd";
|
|
14
|
+
/**
|
|
15
|
+
* Which CLIENT program makes the call, `<name>/<version>`: `synap-cli/<v>` for
|
|
16
|
+
* the CLI's Hub calls, `synap-cli-mcp/<v>` for the stdio MCP bridge (and
|
|
17
|
+
* `synap-bridge/<v>` from the Claude Code mod). The pod counts calls per client
|
|
18
|
+
* in its usage telemetry, so two programs sharing one key and one conversation
|
|
19
|
+
* can be told apart. Never an identity: it only labels the count.
|
|
20
|
+
*/
|
|
21
|
+
export const CLIENT_HEADER = "X-Synap-Client";
|
|
22
|
+
/** `{ "X-Synap-Client": "<name>/<version>" }`; the version is the package's. */
|
|
23
|
+
export function clientHeader(name, version = cliBuild().version) {
|
|
24
|
+
// A header value must be visible ASCII; an odd version never fails the call.
|
|
25
|
+
const v = /^[\x21-\x7E]{1,64}$/.test(version) ? version : "unknown";
|
|
26
|
+
return { [CLIENT_HEADER]: `${name}/${v}` };
|
|
27
|
+
}
|
|
28
|
+
/** The same two values in a request's `params._meta` (reverse-DNS vendor keys; `io.modelcontextprotocol/` is reserved). */
|
|
29
|
+
export const CONVERSATION_META_KEY = "live.synap/conversation";
|
|
30
|
+
export const CONVERSATION_CWD_META_KEY = "live.synap/conversationCwd";
|
|
11
31
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12
32
|
/** `claude-code:<uuid>` for the Claude Code conversation we run in, if any. */
|
|
13
33
|
export function claudeCodeConversation(sessionId) {
|
|
14
34
|
const id = sessionId?.trim();
|
|
15
35
|
return id && UUID.test(id) ? `claude-code:${id.toLowerCase()}` : undefined;
|
|
16
36
|
}
|
|
37
|
+
const RUN_ID = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
38
|
+
/** One id per process, so every Hub call of one CLI run lands in one conversation. */
|
|
39
|
+
const PROCESS_RUN_ID = randomUUID();
|
|
40
|
+
/**
|
|
41
|
+
* `synap-cli:<id>` for a run outside Claude Code: `SYNAP_RUN_ID` when the caller
|
|
42
|
+
* names one (a multi-command script), else a UUID minted once per process. An
|
|
43
|
+
* unusable `SYNAP_RUN_ID` falls back to the process id rather than failing.
|
|
44
|
+
*/
|
|
45
|
+
export function cliConversation(env = process.env) {
|
|
46
|
+
const named = env.SYNAP_RUN_ID?.trim();
|
|
47
|
+
return `synap-cli:${named && RUN_ID.test(named) ? named : PROCESS_RUN_ID}`;
|
|
48
|
+
}
|
|
17
49
|
/**
|
|
18
50
|
* The headers for `sessionId` (pass it explicitly: the CLI's live id is
|
|
19
51
|
* `getClaudeSessionId()`, a stdio server's is its spawn env). Empty without a
|
|
20
|
-
* real Claude Code id
|
|
52
|
+
* real Claude Code id the run names itself (`cliConversation`); the cwd rides
|
|
53
|
+
* only with a Claude Code conversation (the one a person can reopen).
|
|
21
54
|
*/
|
|
22
55
|
export function conversationHeaders(sessionId, cwd = process.cwd()) {
|
|
23
56
|
const conversation = claudeCodeConversation(sessionId);
|
|
24
57
|
if (!conversation)
|
|
25
|
-
return {};
|
|
58
|
+
return { [CONVERSATION_HEADER]: cliConversation() };
|
|
26
59
|
// HTTP header values must be ByteStrings; a non-ASCII cwd is dropped rather
|
|
27
60
|
// than letting fetch throw and take the whole request down with it.
|
|
28
61
|
return /^[\x20-\x7E]{1,1024}$/.test(cwd)
|
|
29
62
|
? { [CONVERSATION_HEADER]: conversation, [CONVERSATION_CWD_HEADER]: cwd }
|
|
30
63
|
: { [CONVERSATION_HEADER]: conversation };
|
|
31
64
|
}
|
|
65
|
+
/** Every header the stdio MCP bridge sends: its client name plus the conversation. */
|
|
66
|
+
export function mcpBridgeHeaders(sessionId, cwd = process.cwd()) {
|
|
67
|
+
return { ...clientHeader("synap-cli-mcp"), ...conversationHeaders(sessionId, cwd) };
|
|
68
|
+
}
|
|
32
69
|
//# sourceMappingURL=conversation-headers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-headers.js","sourceRoot":"","sources":["../../src/lib/conversation-headers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"conversation-headers.js","sourceRoot":"","sources":["../../src/lib/conversation-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAC1D,MAAM,CAAC,MAAM,uBAAuB,GAAG,0BAA0B,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAG9C,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAC1B,IAAqB,EACrB,UAAkB,QAAQ,EAAE,CAAC,OAAO;IAEpC,6EAA6E;IAC7E,MAAM,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;AAC7C,CAAC;AAED,2HAA2H;AAC3H,MAAM,CAAC,MAAM,qBAAqB,GAAG,yBAAyB,CAAC;AAC/D,MAAM,CAAC,MAAM,yBAAyB,GAAG,4BAA4B,CAAC;AAEtE,MAAM,IAAI,GAAG,iEAAiE,CAAC;AAE/E,+EAA+E;AAC/E,MAAM,UAAU,sBAAsB,CAAC,SAA6B;IAClE,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7B,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7E,CAAC;AAED,MAAM,MAAM,GAAG,yBAAyB,CAAC;AAEzC,sFAAsF;AACtF,MAAM,cAAc,GAAG,UAAU,EAAE,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAyB,OAAO,CAAC,GAAG;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACvC,OAAO,aAAa,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAA6B,EAC7B,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,YAAY,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC;IACvE,4EAA4E;IAC5E,oEAAoE;IACpE,OAAO,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC;QACtC,CAAC,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC,uBAAuB,CAAC,EAAE,GAAG,EAAE;QACzE,CAAC,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC;AAGD,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAC9B,SAA6B,EAC7B,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,OAAO,EAAE,GAAG,YAAY,CAAC,eAAe,CAAC,EAAE,GAAG,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;AACtF,CAAC"}
|