frely-cli 0.23.8 → 0.23.10
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 +50 -20
- package/README.zh-CN.md +47 -19
- package/dist/agent/local/approvals.d.ts +24 -0
- package/dist/agent/local/approvals.js +79 -0
- package/dist/agent/local/approvals.js.map +1 -0
- package/dist/agent/local/command.d.ts +10 -0
- package/dist/agent/local/command.js +292 -0
- package/dist/agent/local/command.js.map +1 -0
- package/dist/agent/local/confine.d.ts +20 -0
- package/dist/agent/local/confine.js +52 -0
- package/dist/agent/local/confine.js.map +1 -0
- package/dist/agent/local/manifest.d.ts +17 -0
- package/dist/agent/local/manifest.js +55 -0
- package/dist/agent/local/manifest.js.map +1 -0
- package/dist/agent/local/model-proxy.d.ts +18 -0
- package/dist/agent/local/model-proxy.js +111 -0
- package/dist/agent/local/model-proxy.js.map +1 -0
- package/dist/agent/local/source.d.ts +28 -0
- package/dist/agent/local/source.js +64 -0
- package/dist/agent/local/source.js.map +1 -0
- package/dist/agent/local/store.d.ts +45 -0
- package/dist/agent/local/store.js +78 -0
- package/dist/agent/local/store.js.map +1 -0
- package/dist/agent/local/supervisor.d.ts +9 -0
- package/dist/agent/local/supervisor.js +62 -0
- package/dist/agent/local/supervisor.js.map +1 -0
- package/dist/agent-help.d.ts +294 -18
- package/dist/agent-help.js +56 -7
- package/dist/agent-help.js.map +1 -1
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +36 -0
- package/dist/auth.js.map +1 -1
- package/dist/cloud.d.ts +2 -0
- package/dist/cloud.js +38 -0
- package/dist/cloud.js.map +1 -1
- package/dist/controller/args.d.ts +25 -0
- package/dist/controller/args.js +61 -0
- package/dist/controller/args.js.map +1 -0
- package/dist/controller/client.d.ts +52 -0
- package/dist/controller/client.js +124 -0
- package/dist/controller/client.js.map +1 -0
- package/dist/controller/commands.d.ts +16 -0
- package/dist/controller/commands.js +411 -0
- package/dist/controller/commands.js.map +1 -0
- package/dist/controller/dpop.d.ts +24 -0
- package/dist/controller/dpop.js +26 -0
- package/dist/controller/dpop.js.map +1 -0
- package/dist/controller/session.d.ts +53 -0
- package/dist/controller/session.js +211 -0
- package/dist/controller/session.js.map +1 -0
- package/dist/device/protocol.d.ts +1 -1
- package/dist/device/protocol.js +1 -1
- package/dist/device/protocol.js.map +1 -1
- package/dist/device/relay-client.d.ts +14 -0
- package/dist/device/relay-client.js +34 -14
- package/dist/device/relay-client.js.map +1 -1
- package/dist/index.js +79 -8
- package/dist/index.js.map +1 -1
- package/dist/provider/control.d.ts +10 -0
- package/dist/provider/control.js +19 -0
- package/dist/provider/control.js.map +1 -1
- package/dist/provider/share.js +4 -1
- package/dist/provider/share.js.map +1 -1
- package/dist/runtime/sandbox.d.ts +20 -0
- package/dist/runtime/sandbox.js +39 -1
- package/dist/runtime/sandbox.js.map +1 -1
- package/dist/share/allowance.d.ts +8 -0
- package/dist/share/allowance.js +22 -0
- package/dist/share/allowance.js.map +1 -0
- package/dist/share/control.d.ts +18 -0
- package/dist/share/control.js +53 -0
- package/dist/share/control.js.map +1 -0
- package/dist/share/frpc-config.d.ts +24 -0
- package/dist/share/frpc-config.js +63 -0
- package/dist/share/frpc-config.js.map +1 -0
- package/dist/share/frpc.d.ts +30 -0
- package/dist/share/frpc.js +108 -0
- package/dist/share/frpc.js.map +1 -0
- package/dist/share/gateway.d.ts +26 -0
- package/dist/share/gateway.js +100 -0
- package/dist/share/gateway.js.map +1 -0
- package/dist/share/run.d.ts +43 -0
- package/dist/share/run.js +163 -0
- package/dist/share/run.js.map +1 -0
- package/dist/share/service-config.d.ts +39 -0
- package/dist/share/service-config.js +85 -0
- package/dist/share/service-config.js.map +1 -0
- package/dist/share/service-control.d.ts +15 -0
- package/dist/share/service-control.js +31 -0
- package/dist/share/service-control.js.map +1 -0
- package/dist/share/service-run.d.ts +55 -0
- package/dist/share/service-run.js +285 -0
- package/dist/share/service-run.js.map +1 -0
- package/dist/share/service-state.d.ts +16 -0
- package/dist/share/service-state.js +66 -0
- package/dist/share/service-state.js.map +1 -0
- package/dist/skill/access.d.ts +2 -2
- package/dist/skill/access.js +4 -2
- package/dist/skill/access.js.map +1 -1
- package/dist/skill/cloud-item.d.ts +2 -2
- package/dist/skill/cloud-item.js.map +1 -1
- package/dist/skill/entry.d.ts +1 -1
- package/dist/skill/entry.js +1 -1
- package/dist/skill/remote-mcp.d.ts +3 -0
- package/dist/skill/remote-mcp.js +7 -1
- package/dist/skill/remote-mcp.js.map +1 -1
- package/dist/skill/router.d.ts +6 -2
- package/dist/skill/router.js +4 -4
- package/dist/skill/router.js.map +1 -1
- package/dist/skill/sealed-run.js +5 -3
- package/dist/skill/sealed-run.js.map +1 -1
- package/dist/uninstall.d.ts +4 -0
- package/dist/uninstall.js +14 -0
- package/dist/uninstall.js.map +1 -1
- package/package.json +3 -2
- package/skills/frely-cli/SKILL.md +8 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Where an Agent's code comes from: a Frely Agent page (`username/name`) or a public GitHub repository. */
|
|
2
|
+
export type AgentSource = {
|
|
3
|
+
kind: "frely";
|
|
4
|
+
user: string;
|
|
5
|
+
name: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "github";
|
|
8
|
+
owner: string;
|
|
9
|
+
repo: string;
|
|
10
|
+
};
|
|
11
|
+
export declare class SourceError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
export declare function parseSource(target: string): AgentSource;
|
|
15
|
+
export declare const githubUrl: (source: {
|
|
16
|
+
owner: string;
|
|
17
|
+
repo: string;
|
|
18
|
+
}) => string;
|
|
19
|
+
/** The public record a Frely Agent page keeps for its repository. */
|
|
20
|
+
export interface RegisteredRepo {
|
|
21
|
+
repoUrl: string;
|
|
22
|
+
commit: string | undefined;
|
|
23
|
+
name: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** Reads the repository the Agent's author registered on Frely. The commit is the one the author listed. */
|
|
26
|
+
export declare function resolveRegisteredRepo(user: string, name: string, relayUrl: string, fetchFn?: typeof fetch): Promise<RegisteredRepo>;
|
|
27
|
+
/** Downloads `repoUrl` into the empty-or-missing `dir`, at `commit` when one is given, else at the default branch. Returns the commit that is checked out. */
|
|
28
|
+
export declare function download(repoUrl: string, dir: string, commit: string | undefined): Promise<string>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
const run = promisify(execFile);
|
|
6
|
+
export class SourceError extends Error {
|
|
7
|
+
constructor(message) { super(message); this.name = "SourceError"; }
|
|
8
|
+
}
|
|
9
|
+
const FRELY_PART = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
|
|
10
|
+
const GITHUB_URL = /^https:\/\/github\.com\/([A-Za-z0-9][A-Za-z0-9-]{0,38})\/([A-Za-z0-9._-]{1,100}?)(?:\.git)?\/?$/u;
|
|
11
|
+
const COMMIT = /^[0-9a-f]{40}$/u;
|
|
12
|
+
export function parseSource(target) {
|
|
13
|
+
const github = GITHUB_URL.exec(target);
|
|
14
|
+
if (github)
|
|
15
|
+
return { kind: "github", owner: github[1], repo: github[2] };
|
|
16
|
+
const [user, name, extra] = target.replace(/^@/u, "").split("/");
|
|
17
|
+
if (user !== undefined && name !== undefined && extra === undefined && FRELY_PART.test(user) && FRELY_PART.test(name))
|
|
18
|
+
return { kind: "frely", user, name };
|
|
19
|
+
throw new SourceError("Use a Frely Agent name such as username/name, or a public GitHub address such as https://github.com/owner/repo.");
|
|
20
|
+
}
|
|
21
|
+
export const githubUrl = (source) => `https://github.com/${source.owner}/${source.repo}`;
|
|
22
|
+
/** Reads the repository the Agent's author registered on Frely. The commit is the one the author listed. */
|
|
23
|
+
export async function resolveRegisteredRepo(user, name, relayUrl, fetchFn = fetch) {
|
|
24
|
+
const response = await fetchFn(`${relayUrl}/api/public/agent-repos/${encodeURIComponent(user)}/${encodeURIComponent(name)}`, { headers: { accept: "application/json" }, redirect: "error", signal: AbortSignal.timeout(15_000) });
|
|
25
|
+
if (response.status === 404)
|
|
26
|
+
throw new SourceError(`${user}/${name} is not a Frely Agent with a repository.`);
|
|
27
|
+
if (!response.ok)
|
|
28
|
+
throw new SourceError(`Frely could not look up ${user}/${name} (HTTP ${response.status}).`);
|
|
29
|
+
const body = await response.json().catch(() => null);
|
|
30
|
+
if (!body || typeof body.repoUrl !== "string" || !GITHUB_URL.test(body.repoUrl))
|
|
31
|
+
throw new SourceError(`Frely returned no usable repository for ${user}/${name}.`);
|
|
32
|
+
const commit = typeof body.commit === "string" && COMMIT.test(body.commit) ? body.commit : undefined;
|
|
33
|
+
return { repoUrl: body.repoUrl.replace(/\.git$/u, "").replace(/\/$/u, ""), commit, name: typeof body.name === "string" ? body.name : undefined };
|
|
34
|
+
}
|
|
35
|
+
/** git with no prompts, no hooks, no submodules and https only: the repository is untrusted. */
|
|
36
|
+
async function git(args, cwd) {
|
|
37
|
+
const safe = ["-c", "protocol.allow=never", "-c", "protocol.https.allow=always", "-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false", "-c", "submodule.recurse=false"];
|
|
38
|
+
try {
|
|
39
|
+
const { stdout } = await run("git", [...safe, ...args], { cwd, env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_CONFIG_NOSYSTEM: "1" }, timeout: 5 * 60_000, maxBuffer: 4 * 1024 * 1024 });
|
|
40
|
+
return stdout.trim();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const stderr = error.stderr?.trim().split("\n").slice(-3).join(" ");
|
|
44
|
+
throw new SourceError(`git ${args[0]} failed${stderr ? `: ${stderr}` : "."}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Downloads `repoUrl` into the empty-or-missing `dir`, at `commit` when one is given, else at the default branch. Returns the commit that is checked out. */
|
|
48
|
+
export async function download(repoUrl, dir, commit) {
|
|
49
|
+
await mkdir(dirname(dir), { recursive: true });
|
|
50
|
+
if (commit) {
|
|
51
|
+
await mkdir(dir, { recursive: true });
|
|
52
|
+
await git(["init", "--quiet"], dir);
|
|
53
|
+
await git(["fetch", "--quiet", "--depth", "1", "--no-tags", "--no-recurse-submodules", repoUrl, commit], dir);
|
|
54
|
+
await git(["checkout", "--quiet", "FETCH_HEAD"], dir);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await git(["clone", "--quiet", "--depth", "1", "--no-tags", "--single-branch", "--no-recurse-submodules", repoUrl, dir], undefined);
|
|
58
|
+
}
|
|
59
|
+
const head = await git(["rev-parse", "HEAD"], dir);
|
|
60
|
+
if (!COMMIT.test(head))
|
|
61
|
+
throw new SourceError("git did not report a commit.");
|
|
62
|
+
return head;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../../src/agent/local/source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is known about one Agent running on this computer. It lives with Frely's own files, not in the Agent's folder: the sandbox
|
|
3
|
+
* cannot read or write there, so the program it runs cannot change which sites it was approved for.
|
|
4
|
+
*/
|
|
5
|
+
export interface LocalAgentRecord {
|
|
6
|
+
version: 1;
|
|
7
|
+
slug: string;
|
|
8
|
+
/** What the person typed: `username/name` or a GitHub address. */
|
|
9
|
+
source: string;
|
|
10
|
+
repoUrl: string;
|
|
11
|
+
commit: string;
|
|
12
|
+
name: string;
|
|
13
|
+
workspace: string;
|
|
14
|
+
setup: string | undefined;
|
|
15
|
+
run: string;
|
|
16
|
+
/** Sites from frely.yaml, asked for when the Agent is added and started. */
|
|
17
|
+
network: string[];
|
|
18
|
+
addedAt: string;
|
|
19
|
+
setupDone: boolean;
|
|
20
|
+
/** Approved site -> when the approval ends (ISO time). */
|
|
21
|
+
approvals: Record<string, string>;
|
|
22
|
+
pid: number | undefined;
|
|
23
|
+
startedAt: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
export declare const SLUG: RegExp;
|
|
26
|
+
/** Records, logs and sockets: `~/.config/frely/agent-local`. */
|
|
27
|
+
export declare const stateDir: () => string;
|
|
28
|
+
/** One folder per Agent, the only place its program can write besides the system temp folder. */
|
|
29
|
+
export declare const agentsRoot: () => string;
|
|
30
|
+
export declare function assertSlug(slug: string): void;
|
|
31
|
+
export declare const workspaceOf: (slug: string) => string;
|
|
32
|
+
export declare const recordPath: (slug: string) => string;
|
|
33
|
+
export declare const logPath: (slug: string) => string;
|
|
34
|
+
/** Short enough for the ~100 character limit of a Unix socket path. */
|
|
35
|
+
export declare const socketPath: (slug: string) => string;
|
|
36
|
+
/** Whether `path` is inside the Agents folder (and not the folder itself), so a removal can never reach anything else. */
|
|
37
|
+
export declare function insideAgentsRoot(path: string): boolean;
|
|
38
|
+
export declare function readRecord(slug: string): Promise<LocalAgentRecord | undefined>;
|
|
39
|
+
export declare function writeRecord(record: LocalAgentRecord): Promise<void>;
|
|
40
|
+
export declare function listRecords(): Promise<LocalAgentRecord[]>;
|
|
41
|
+
export declare function removeRecordFiles(slug: string): Promise<void>;
|
|
42
|
+
/** Whether the process the record names is still running. */
|
|
43
|
+
export declare function isRunning(record: Pick<LocalAgentRecord, "pid">): boolean;
|
|
44
|
+
/** Approvals that have not ended yet, as a site list. */
|
|
45
|
+
export declare function approvedHosts(record: Pick<LocalAgentRecord, "approvals" | "network">, now?: number): string[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { chmod, mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join, resolve, sep } from "node:path";
|
|
5
|
+
export const SLUG = /^[a-z0-9][a-z0-9-]{0,62}$/u;
|
|
6
|
+
const configRoot = () => process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
7
|
+
/** Records, logs and sockets: `~/.config/frely/agent-local`. */
|
|
8
|
+
export const stateDir = () => join(configRoot(), "frely", "agent-local");
|
|
9
|
+
/** One folder per Agent, the only place its program can write besides the system temp folder. */
|
|
10
|
+
export const agentsRoot = () => resolve(process.env.FRELY_AGENTS_DIR || join(homedir(), "frely-agents"));
|
|
11
|
+
export function assertSlug(slug) {
|
|
12
|
+
if (!SLUG.test(slug))
|
|
13
|
+
throw new Error("The Agent name must be lower-case letters, digits and dashes.");
|
|
14
|
+
}
|
|
15
|
+
export const workspaceOf = (slug) => join(agentsRoot(), slug);
|
|
16
|
+
export const recordPath = (slug) => join(stateDir(), `${slug}.json`);
|
|
17
|
+
export const logPath = (slug) => join(stateDir(), `${slug}.log`);
|
|
18
|
+
/** Short enough for the ~100 character limit of a Unix socket path. */
|
|
19
|
+
export const socketPath = (slug) => join(process.env.XDG_RUNTIME_DIR || stateDir(), `m-${createHash("sha256").update(slug).digest("hex").slice(0, 10)}.sock`);
|
|
20
|
+
/** Whether `path` is inside the Agents folder (and not the folder itself), so a removal can never reach anything else. */
|
|
21
|
+
export function insideAgentsRoot(path) {
|
|
22
|
+
const root = agentsRoot();
|
|
23
|
+
const target = resolve(path);
|
|
24
|
+
return target !== root && target.startsWith(root.endsWith(sep) ? root : root + sep);
|
|
25
|
+
}
|
|
26
|
+
export async function readRecord(slug) {
|
|
27
|
+
assertSlug(slug);
|
|
28
|
+
const raw = await readFile(recordPath(slug), "utf8").catch(() => undefined);
|
|
29
|
+
if (raw === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
try {
|
|
32
|
+
const value = JSON.parse(raw);
|
|
33
|
+
return value.version === 1 && value.slug === slug && typeof value.run === "string" ? value : undefined;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function writeRecord(record) {
|
|
40
|
+
await mkdir(stateDir(), { recursive: true, mode: 0o700 });
|
|
41
|
+
const target = recordPath(record.slug);
|
|
42
|
+
const temp = `${target}.${process.pid}.tmp`;
|
|
43
|
+
await writeFile(temp, JSON.stringify(record, null, 2) + "\n", { mode: 0o600 });
|
|
44
|
+
await rename(temp, target);
|
|
45
|
+
await chmod(target, 0o600).catch(() => undefined);
|
|
46
|
+
}
|
|
47
|
+
export async function listRecords() {
|
|
48
|
+
const names = await readdir(stateDir()).catch(() => []);
|
|
49
|
+
const records = [];
|
|
50
|
+
for (const name of names.filter((file) => file.endsWith(".json")).sort()) {
|
|
51
|
+
const record = await readRecord(name.slice(0, -5)).catch(() => undefined);
|
|
52
|
+
if (record)
|
|
53
|
+
records.push(record);
|
|
54
|
+
}
|
|
55
|
+
return records;
|
|
56
|
+
}
|
|
57
|
+
export async function removeRecordFiles(slug) {
|
|
58
|
+
await rm(recordPath(slug), { force: true });
|
|
59
|
+
await rm(logPath(slug), { force: true });
|
|
60
|
+
await rm(socketPath(slug), { force: true });
|
|
61
|
+
}
|
|
62
|
+
/** Whether the process the record names is still running. */
|
|
63
|
+
export function isRunning(record) {
|
|
64
|
+
if (record.pid === undefined)
|
|
65
|
+
return false;
|
|
66
|
+
try {
|
|
67
|
+
process.kill(record.pid, 0);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return error.code === "EPERM";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Approvals that have not ended yet, as a site list. */
|
|
75
|
+
export function approvedHosts(record, now = Date.now()) {
|
|
76
|
+
return record.network.filter((host) => { const end = record.approvals[host]; return end !== undefined && Date.parse(end) > now; });
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/agent/local/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class SupervisorError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Runs one Agent until it exits or this process is told to stop: the model proxy on a Unix socket, then the Agent's `local.run`
|
|
6
|
+
* inside the sandbox with only Frely's gateway, the proxy name and the approved sites reachable. Everything the program prints goes to
|
|
7
|
+
* this process's output, which `frely agent local start` points at the Agent's log file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function superviseAgent(slug: string): Promise<number>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { requireLogin } from "../../auth.js";
|
|
2
|
+
import { terminateProcessTree } from "../../runtime/process-tree.js";
|
|
3
|
+
import { restrictSandboxNetwork, shutdownSandbox } from "../../runtime/sandbox.js";
|
|
4
|
+
import { agentEnv, gatewayOrigin, readApiKey, spawnConfined } from "./confine.js";
|
|
5
|
+
import { MODEL_HOST, startModelProxy } from "./model-proxy.js";
|
|
6
|
+
import { approvedHosts, readRecord, socketPath, writeRecord } from "./store.js";
|
|
7
|
+
export class SupervisorError extends Error {
|
|
8
|
+
constructor(message) { super(message); this.name = "SupervisorError"; }
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Runs one Agent until it exits or this process is told to stop: the model proxy on a Unix socket, then the Agent's `local.run`
|
|
12
|
+
* inside the sandbox with only Frely's gateway, the proxy name and the approved sites reachable. Everything the program prints goes to
|
|
13
|
+
* this process's output, which `frely agent local start` points at the Agent's log file.
|
|
14
|
+
*/
|
|
15
|
+
export async function superviseAgent(slug) {
|
|
16
|
+
const record = await readRecord(slug);
|
|
17
|
+
if (!record)
|
|
18
|
+
throw new SupervisorError(`No local Agent named ${slug}. Add it with frely agent local add.`);
|
|
19
|
+
if (!record.setupDone)
|
|
20
|
+
throw new SupervisorError(`${slug} was not set up yet. Run frely agent local add again to finish.`);
|
|
21
|
+
const login = await requireLogin().catch(() => { throw new SupervisorError("Frely login is required. Run `frely login`."); });
|
|
22
|
+
const origin = gatewayOrigin(login.config.relayUrl);
|
|
23
|
+
const apiKey = await readApiKey(origin);
|
|
24
|
+
if (!apiKey)
|
|
25
|
+
throw new SupervisorError(`${slug} needs a Frely API key for its model calls. Create one at ${login.config.relayUrl}/user/keys, then run: frely agent local key --api-key-stdin`);
|
|
26
|
+
const sites = approvedHosts(record);
|
|
27
|
+
const skipped = record.network.filter((host) => !sites.includes(host));
|
|
28
|
+
if (skipped.length > 0)
|
|
29
|
+
process.stderr.write(`Not approved, so blocked: ${skipped.join(", ")}. Run frely agent local start ${slug} again to ask.\n`);
|
|
30
|
+
const socket = socketPath(slug);
|
|
31
|
+
restrictSandboxNetwork({ allowedDomains: [new URL(origin).hostname, MODEL_HOST, ...sites], mitmProxy: { socketPath: socket, domains: [MODEL_HOST] } });
|
|
32
|
+
const proxy = await startModelProxy({ socketPath: socket, upstream: origin, authorization: async () => `Bearer ${apiKey}` });
|
|
33
|
+
let confined;
|
|
34
|
+
try {
|
|
35
|
+
confined = await spawnConfined(record.run, record.workspace, agentEnv(record.workspace, { model: true }));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
await proxy.close();
|
|
39
|
+
await shutdownSandbox();
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
const { child } = confined;
|
|
43
|
+
child.stdout?.pipe(process.stdout, { end: false });
|
|
44
|
+
child.stderr?.pipe(process.stderr, { end: false });
|
|
45
|
+
await writeRecord({ ...record, pid: process.pid, startedAt: new Date().toISOString() });
|
|
46
|
+
process.stderr.write(`[frely] ${slug} started${sites.length ? `; sites: ${sites.join(", ")}` : ""}\n`);
|
|
47
|
+
const stop = () => { void terminateProcessTree(child); };
|
|
48
|
+
process.once("SIGTERM", stop);
|
|
49
|
+
process.once("SIGINT", stop);
|
|
50
|
+
const code = await new Promise((done) => { child.once("error", () => done(1)); child.once("close", (exit) => done(exit ?? 1)); });
|
|
51
|
+
const blocked = confined.violations();
|
|
52
|
+
if (blocked.length > 0)
|
|
53
|
+
process.stderr.write(`[frely] The sandbox blocked:\n${[...new Set(blocked)].slice(0, 10).join("\n")}\n`);
|
|
54
|
+
await proxy.close();
|
|
55
|
+
await shutdownSandbox();
|
|
56
|
+
const latest = await readRecord(slug);
|
|
57
|
+
if (latest)
|
|
58
|
+
await writeRecord({ ...latest, pid: undefined, startedAt: undefined });
|
|
59
|
+
process.stderr.write(`[frely] ${slug} stopped (exit ${code}).\n`);
|
|
60
|
+
return code;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../src/agent/local/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC,CAAC,CAAC;CAChF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,wBAAwB,IAAI,sCAAsC,CAAC,CAAC;IAC3G,IAAI,CAAC,MAAM,CAAC,SAAS;QAAE,MAAM,IAAI,eAAe,CAAC,GAAG,IAAI,iEAAiE,CAAC,CAAC;IAC3H,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,eAAe,CAAC,6CAA6C,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9H,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,eAAe,CAAC,GAAG,IAAI,6DAA6D,KAAK,CAAC,MAAM,CAAC,QAAQ,6DAA6D,CAAC,CAAC;IAE/L,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,IAAI,kBAAkB,CAAC,CAAC;IACrJ,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,sBAAsB,CAAC,EAAE,cAAc,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACvJ,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7H,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5G,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;QACpB,MAAM,eAAe,EAAE,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;IAC3B,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,MAAM,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACxF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,WAAW,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAEvG,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1I,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjI,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACpB,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM;QAAE,MAAM,WAAW,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;IACnF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,kBAAkB,IAAI,MAAM,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC"}
|