frely-cli 0.23.9 → 0.23.11
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 +49 -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/run-store.d.ts +80 -0
- package/dist/agent/run-store.js +154 -0
- package/dist/agent/run-store.js.map +1 -0
- package/dist/agent/run.d.ts +41 -0
- package/dist/agent/run.js +233 -0
- package/dist/agent/run.js.map +1 -0
- package/dist/agent/workspace-read.d.ts +78 -0
- package/dist/agent/workspace-read.js +292 -0
- package/dist/agent/workspace-read.js.map +1 -0
- package/dist/agent-help.d.ts +158 -14
- package/dist/agent-help.js +33 -8
- package/dist/agent-help.js.map +1 -1
- package/dist/cloud.d.ts +2 -42
- package/dist/cloud.js +8 -260
- package/dist/cloud.js.map +1 -1
- package/dist/controller/client.d.ts +6 -3
- package/dist/controller/client.js +7 -8
- package/dist/controller/client.js.map +1 -1
- package/dist/controller/session.d.ts +7 -2
- package/dist/controller/session.js +79 -22
- package/dist/controller/session.js.map +1 -1
- package/dist/index.js +114 -9
- 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 +2 -0
- package/dist/share/control.js +14 -10
- package/dist/share/control.js.map +1 -1
- 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 +25 -6
- package/dist/skill/access.js +59 -9
- 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 +57 -2
- package/dist/skill/router.js +76 -40
- package/dist/skill/router.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/dist/share/control.d.ts
CHANGED
|
@@ -14,3 +14,5 @@ export interface ShareControl {
|
|
|
14
14
|
}
|
|
15
15
|
/** Calls Frely's share route as the signed-in user; the device is this computer's enrolled device. */
|
|
16
16
|
export declare function accountShareControl(): Promise<ShareControl>;
|
|
17
|
+
/** A POST helper for one of Frely's device-relay routes, signed in as the user. */
|
|
18
|
+
export declare function accountRelayCaller(path: string): Promise<(body: Record<string, unknown>) => Promise<unknown>>;
|
package/dist/share/control.js
CHANGED
|
@@ -5,15 +5,8 @@ const TIMEOUT_MS = 20_000;
|
|
|
5
5
|
const SHARES_PATH = "/api/user/device-relay/shares";
|
|
6
6
|
/** Calls Frely's share route as the signed-in user; the device is this computer's enrolled device. */
|
|
7
7
|
export async function accountShareControl() {
|
|
8
|
-
const auth = await requireLogin();
|
|
9
8
|
const device = await ensureDevice();
|
|
10
|
-
const call =
|
|
11
|
-
const response = await relayFetch(auth.config.relayUrl, auth.credential, { method: "POST", body: JSON.stringify(body) });
|
|
12
|
-
const payload = await response.json().catch(() => null);
|
|
13
|
-
if (!response.ok)
|
|
14
|
-
throw new Error(publicError(payload, response.status));
|
|
15
|
-
return payload;
|
|
16
|
-
};
|
|
9
|
+
const call = await accountRelayCaller(SHARES_PATH);
|
|
17
10
|
return {
|
|
18
11
|
async create(input) { return parseShareGrant(await call({ action: "create", deviceId: device.deviceId, ...(input.ttlSeconds !== undefined ? { ttlSeconds: input.ttlSeconds } : {}) })); },
|
|
19
12
|
async heartbeat(sessionId) {
|
|
@@ -25,12 +18,23 @@ export async function accountShareControl() {
|
|
|
25
18
|
async revoke(sessionId) { await call({ action: "revoke", sessionId }); },
|
|
26
19
|
};
|
|
27
20
|
}
|
|
28
|
-
|
|
21
|
+
/** A POST helper for one of Frely's device-relay routes, signed in as the user. */
|
|
22
|
+
export async function accountRelayCaller(path) {
|
|
23
|
+
const auth = await requireLogin();
|
|
24
|
+
return async (body) => {
|
|
25
|
+
const response = await relayFetch(auth.config.relayUrl, auth.credential, path, { method: "POST", body: JSON.stringify(body) });
|
|
26
|
+
const payload = await response.json().catch(() => null);
|
|
27
|
+
if (!response.ok)
|
|
28
|
+
throw new Error(publicError(payload, response.status));
|
|
29
|
+
return payload;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function relayFetch(relayUrl, credential, path, init) {
|
|
29
33
|
const controller = new AbortController();
|
|
30
34
|
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
31
35
|
timer.unref?.();
|
|
32
36
|
try {
|
|
33
|
-
return await fetch(`${relayUrl}${
|
|
37
|
+
return await fetch(`${relayUrl}${path}`, { ...init, signal: controller.signal, redirect: "error", headers: { accept: "application/json", origin: relayUrl, "content-type": "application/json", ...(credential.scheme === "bearer" ? { authorization: `Bearer ${credential.value}` } : { cookie: credential.value }) } });
|
|
34
38
|
}
|
|
35
39
|
catch (error) {
|
|
36
40
|
if (controller.signal.aborted)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/share/control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAmB,MAAM,kBAAkB,CAAC;AAEpE,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,MAAM,WAAW,GAAG,+BAA+B,CAAC;AAUpD,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/share/control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** What the relay returns for a service session (`POST /api/user/device-relay/services`, action session). */
|
|
2
|
+
export interface ServiceGrant {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly serviceShareId: string;
|
|
5
|
+
readonly expiresAt: string;
|
|
6
|
+
readonly node: string;
|
|
7
|
+
readonly bandwidthBytesPerSecond: number;
|
|
8
|
+
readonly remainingBytes: number;
|
|
9
|
+
readonly frpc: {
|
|
10
|
+
readonly serverAddr: string;
|
|
11
|
+
readonly serverPort: number;
|
|
12
|
+
readonly user: string;
|
|
13
|
+
readonly token: string;
|
|
14
|
+
readonly proxyName: "svc";
|
|
15
|
+
readonly proxyType: "stcp";
|
|
16
|
+
readonly secretKey: string;
|
|
17
|
+
readonly allowUsers: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export type ServiceType = "mcp" | "a2a";
|
|
21
|
+
/** A registered service as `register` and `list` return it. The local port is never part of it. */
|
|
22
|
+
export interface ServiceShareRecord {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly deviceId: string;
|
|
25
|
+
readonly type: ServiceType;
|
|
26
|
+
readonly label: string;
|
|
27
|
+
readonly createdAt: string;
|
|
28
|
+
}
|
|
29
|
+
export declare const SERVICE_SHARE_ID: RegExp;
|
|
30
|
+
/** Checks the grant's shape before anything of it reaches a process or a file; throws on anything unexpected. */
|
|
31
|
+
export declare function parseServiceGrant(value: unknown): ServiceGrant;
|
|
32
|
+
/** Checks a `register` / `list` row. */
|
|
33
|
+
export declare function parseServiceRecord(value: unknown): ServiceShareRecord;
|
|
34
|
+
/**
|
|
35
|
+
* The frpc config for a service: exactly one stcp proxy that points at a port on loopback. `localIP` is fixed here and the port comes
|
|
36
|
+
* from the author's own command line; the relay never supplies a target. No client plugin, no admin port and no other proxy type are written.
|
|
37
|
+
* The stcp key and `allowUsers` (Frely's visitor) come from the grant.
|
|
38
|
+
*/
|
|
39
|
+
export declare function serviceFrpcConfigToml(grant: ServiceGrant, localPort: number): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const HOST = /^(?:[A-Za-z0-9](?:[A-Za-z0-9.-]{0,251}[A-Za-z0-9])?|\[[0-9A-Fa-f:]{2,45}\])$/u;
|
|
2
|
+
const SECRET = /^[A-Za-z0-9_-]{20,128}$/u;
|
|
3
|
+
const VISITOR = /^[A-Za-z0-9_.-]{1,80}$/u;
|
|
4
|
+
export const SERVICE_SHARE_ID = /^svcs_[0-9a-f]{24}$/u;
|
|
5
|
+
/** Checks the grant's shape before anything of it reaches a process or a file; throws on anything unexpected. */
|
|
6
|
+
export function parseServiceGrant(value) {
|
|
7
|
+
const fail = () => { throw new Error("Frely returned an invalid service session."); };
|
|
8
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9
|
+
return fail();
|
|
10
|
+
const grant = value, frpc = grant.frpc;
|
|
11
|
+
if (typeof grant.id !== "string" || !/^frps_[0-9a-f]{24}$/u.test(grant.id))
|
|
12
|
+
return fail();
|
|
13
|
+
if (typeof grant.serviceShareId !== "string" || !SERVICE_SHARE_ID.test(grant.serviceShareId))
|
|
14
|
+
return fail();
|
|
15
|
+
if (typeof grant.expiresAt !== "string" || !Number.isFinite(Date.parse(grant.expiresAt)) || typeof grant.node !== "string" || grant.node.length < 1 || grant.node.length > 64)
|
|
16
|
+
return fail();
|
|
17
|
+
if (typeof grant.bandwidthBytesPerSecond !== "number" || !Number.isFinite(grant.bandwidthBytesPerSecond) || grant.bandwidthBytesPerSecond < 0)
|
|
18
|
+
return fail();
|
|
19
|
+
if (typeof grant.remainingBytes !== "number" || !Number.isFinite(grant.remainingBytes) || grant.remainingBytes < 0)
|
|
20
|
+
return fail();
|
|
21
|
+
if (!frpc || typeof frpc !== "object" || Array.isArray(frpc))
|
|
22
|
+
return fail();
|
|
23
|
+
const { serverAddr, serverPort, user, token, proxyName, proxyType, secretKey, allowUsers } = frpc;
|
|
24
|
+
if (typeof serverAddr !== "string" || !HOST.test(serverAddr))
|
|
25
|
+
return fail();
|
|
26
|
+
if (typeof serverPort !== "number" || !Number.isInteger(serverPort) || serverPort < 1 || serverPort > 65535)
|
|
27
|
+
return fail();
|
|
28
|
+
if (user !== grant.id || typeof token !== "string" || !/^frs_[A-Za-z0-9_-]{20,64}$/u.test(token))
|
|
29
|
+
return fail();
|
|
30
|
+
if (proxyName !== "svc" || proxyType !== "stcp")
|
|
31
|
+
return fail();
|
|
32
|
+
if (typeof secretKey !== "string" || !SECRET.test(secretKey))
|
|
33
|
+
return fail();
|
|
34
|
+
if (!Array.isArray(allowUsers) || allowUsers.length < 1 || allowUsers.length > 4 || allowUsers.some((entry) => typeof entry !== "string" || !VISITOR.test(entry) || entry === "*"))
|
|
35
|
+
return fail();
|
|
36
|
+
return {
|
|
37
|
+
id: grant.id, serviceShareId: grant.serviceShareId, expiresAt: grant.expiresAt, node: grant.node,
|
|
38
|
+
bandwidthBytesPerSecond: grant.bandwidthBytesPerSecond, remainingBytes: grant.remainingBytes,
|
|
39
|
+
frpc: { serverAddr, serverPort, user, token, proxyName, proxyType, secretKey, allowUsers: [...allowUsers] },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Checks a `register` / `list` row. */
|
|
43
|
+
export function parseServiceRecord(value) {
|
|
44
|
+
const fail = () => { throw new Error("Frely returned an invalid service."); };
|
|
45
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
46
|
+
return fail();
|
|
47
|
+
const row = value;
|
|
48
|
+
if (typeof row.id !== "string" || !SERVICE_SHARE_ID.test(row.id) || typeof row.deviceId !== "string" || row.deviceId.length > 64)
|
|
49
|
+
return fail();
|
|
50
|
+
if (row.type !== "mcp" && row.type !== "a2a")
|
|
51
|
+
return fail();
|
|
52
|
+
if (typeof row.label !== "string" || row.label.length < 1 || row.label.length > 60)
|
|
53
|
+
return fail();
|
|
54
|
+
return { id: row.id, deviceId: row.deviceId, type: row.type, label: row.label, createdAt: typeof row.createdAt === "string" ? row.createdAt : "" };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The frpc config for a service: exactly one stcp proxy that points at a port on loopback. `localIP` is fixed here and the port comes
|
|
58
|
+
* from the author's own command line; the relay never supplies a target. No client plugin, no admin port and no other proxy type are written.
|
|
59
|
+
* The stcp key and `allowUsers` (Frely's visitor) come from the grant.
|
|
60
|
+
*/
|
|
61
|
+
export function serviceFrpcConfigToml(grant, localPort) {
|
|
62
|
+
if (!Number.isInteger(localPort) || localPort < 1 || localPort > 65535)
|
|
63
|
+
throw new Error("Invalid local port.");
|
|
64
|
+
const q = (text) => JSON.stringify(text);
|
|
65
|
+
return [
|
|
66
|
+
`serverAddr = ${q(grant.frpc.serverAddr.replace(/^\[|\]$/gu, ""))}`,
|
|
67
|
+
`serverPort = ${grant.frpc.serverPort}`,
|
|
68
|
+
`user = ${q(grant.frpc.user)}`,
|
|
69
|
+
`loginFailExit = true`,
|
|
70
|
+
`metadatas.token = ${q(grant.frpc.token)}`,
|
|
71
|
+
`transport.tls.enable = true`,
|
|
72
|
+
`log.to = "console"`,
|
|
73
|
+
`log.level = "warn"`,
|
|
74
|
+
``,
|
|
75
|
+
`[[proxies]]`,
|
|
76
|
+
`name = "svc"`,
|
|
77
|
+
`type = "stcp"`,
|
|
78
|
+
`secretKey = ${q(grant.frpc.secretKey)}`,
|
|
79
|
+
`allowUsers = [${grant.frpc.allowUsers.map(q).join(", ")}]`,
|
|
80
|
+
`localIP = "127.0.0.1"`,
|
|
81
|
+
`localPort = ${localPort}`,
|
|
82
|
+
``,
|
|
83
|
+
].join("\n");
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=service-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-config.js","sourceRoot":"","sources":["../../src/share/service-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ShareHeartbeat } from "./control.js";
|
|
2
|
+
import { type ServiceGrant, type ServiceShareRecord, type ServiceType } from "./service-config.js";
|
|
3
|
+
export interface ServiceControl {
|
|
4
|
+
register(input: {
|
|
5
|
+
type: ServiceType;
|
|
6
|
+
label: string;
|
|
7
|
+
}): Promise<ServiceShareRecord>;
|
|
8
|
+
list(): Promise<ServiceShareRecord[]>;
|
|
9
|
+
remove(serviceShareId: string): Promise<void>;
|
|
10
|
+
session(serviceShareId: string): Promise<ServiceGrant>;
|
|
11
|
+
heartbeat(sessionId: string): Promise<ShareHeartbeat>;
|
|
12
|
+
revoke(sessionId: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/** Calls Frely's service route as the signed-in user. Only the type and label are registered; the local port never leaves this computer. */
|
|
15
|
+
export declare function accountServiceControl(): Promise<ServiceControl>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ensureDevice } from "../device/control.js";
|
|
2
|
+
import { accountRelayCaller } from "./control.js";
|
|
3
|
+
import { parseServiceGrant, parseServiceRecord } from "./service-config.js";
|
|
4
|
+
const SERVICES_PATH = "/api/user/device-relay/services";
|
|
5
|
+
/** Calls Frely's service route as the signed-in user. Only the type and label are registered; the local port never leaves this computer. */
|
|
6
|
+
export async function accountServiceControl() {
|
|
7
|
+
const call = await accountRelayCaller(SERVICES_PATH);
|
|
8
|
+
return {
|
|
9
|
+
async register(input) {
|
|
10
|
+
const device = await ensureDevice();
|
|
11
|
+
return parseServiceRecord(await call({ action: "register", deviceId: device.deviceId, type: input.type, label: input.label }));
|
|
12
|
+
},
|
|
13
|
+
async list() {
|
|
14
|
+
const value = await call({ action: "list" });
|
|
15
|
+
const items = value && typeof value === "object" ? value.items : undefined;
|
|
16
|
+
if (!Array.isArray(items))
|
|
17
|
+
throw new Error("Frely returned an invalid service list.");
|
|
18
|
+
return items.map(parseServiceRecord);
|
|
19
|
+
},
|
|
20
|
+
async remove(serviceShareId) { await call({ action: "remove", serviceShareId }); },
|
|
21
|
+
async session(serviceShareId) { return parseServiceGrant(await call({ action: "session", serviceShareId })); },
|
|
22
|
+
async heartbeat(sessionId) {
|
|
23
|
+
const value = await call({ action: "heartbeat", sessionId });
|
|
24
|
+
if (!value || typeof value !== "object" || typeof value.active !== "boolean")
|
|
25
|
+
throw new Error("Frely returned an invalid service status.");
|
|
26
|
+
return value;
|
|
27
|
+
},
|
|
28
|
+
async revoke(sessionId) { await call({ action: "revoke", sessionId }); },
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=service-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-control.js","sourceRoot":"","sources":["../../src/share/service-control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAuB,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAgE,MAAM,qBAAqB,CAAC;AAE1I,MAAM,aAAa,GAAG,iCAAiC,CAAC;AAWxD,4IAA4I;AAC5I,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACrD,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,KAAK;YAClB,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;YACpC,OAAO,kBAAkB,CAAC,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjI,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YACpG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACtF,OAAO,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;QAClF,KAAK,CAAC,OAAO,CAAC,cAAc,IAAI,OAAO,iBAAiB,CAAC,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9G,KAAK,CAAC,SAAS,CAAC,SAAS;YACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAQ,KAA8B,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;YACrK,OAAO,KAAuB,CAAC;QACjC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;KACzE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ServiceGrant, type ServiceType } from "./service-config.js";
|
|
2
|
+
import { type ServiceControl } from "./service-control.js";
|
|
3
|
+
import { type LocalService } from "./service-state.js";
|
|
4
|
+
import { ALLOWANCE_NOTE } from "./allowance.js";
|
|
5
|
+
import { type FrpcProcess } from "./run.js";
|
|
6
|
+
export { ALLOWANCE_NOTE };
|
|
7
|
+
export interface ServiceShareOptions {
|
|
8
|
+
readonly type: ServiceType;
|
|
9
|
+
readonly port: number;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly background: boolean;
|
|
12
|
+
readonly json: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function serviceUsage(): string;
|
|
15
|
+
export declare function parseServiceShareArguments(args: readonly string[]): ServiceShareOptions;
|
|
16
|
+
export interface ServiceSessionDeps {
|
|
17
|
+
readonly control: ServiceControl;
|
|
18
|
+
readonly ensureFrpc: () => Promise<string>;
|
|
19
|
+
readonly spawnFrpc: (binary: string, configPath: string) => FrpcProcess;
|
|
20
|
+
readonly write: (text: string) => void;
|
|
21
|
+
readonly signal: AbortSignal;
|
|
22
|
+
readonly heartbeatMs?: number;
|
|
23
|
+
readonly configLifetimeMs?: number;
|
|
24
|
+
/** Called once the session is up, with the grant (for the allowance line). */
|
|
25
|
+
readonly onGrant?: (grant: ServiceGrant) => void;
|
|
26
|
+
}
|
|
27
|
+
/** One session of one service: ask Frely for it, run frpc on it, heartbeat, and revoke when it ends. Returns why it ended. */
|
|
28
|
+
export declare function runServiceSession(service: Pick<LocalService, "serviceShareId" | "port">, deps: ServiceSessionDeps): Promise<{
|
|
29
|
+
reason: string;
|
|
30
|
+
stopped: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function allowanceLines(grant: ServiceGrant): string[];
|
|
33
|
+
/** Keeps one service connected until aborted: when a session ends for any reason but a stop, ask for a new one after a growing pause. */
|
|
34
|
+
export declare function keepServiceConnected(service: Pick<LocalService, "serviceShareId" | "port" | "label">, deps: ServiceSessionDeps, sleep?: (ms: number, signal: AbortSignal) => Promise<void>): Promise<void>;
|
|
35
|
+
/** Runs inside the device daemon: every service saved with `background` stays connected; a stop or removal in the state file ends it within seconds. */
|
|
36
|
+
export declare function superviseServices(options: {
|
|
37
|
+
signal: AbortSignal;
|
|
38
|
+
log: (text: string) => void;
|
|
39
|
+
pollMs?: number;
|
|
40
|
+
control?: () => Promise<ServiceControl>;
|
|
41
|
+
session?: Partial<ServiceSessionDeps>;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
export interface ServiceCommandIo {
|
|
44
|
+
readonly write: (text: string) => void;
|
|
45
|
+
}
|
|
46
|
+
export interface ServiceCommandDeps {
|
|
47
|
+
readonly control: () => Promise<ServiceControl>;
|
|
48
|
+
readonly probe: (port: number) => Promise<boolean>;
|
|
49
|
+
readonly ensureFrpc: () => Promise<string>;
|
|
50
|
+
readonly spawnFrpc: (binary: string, configPath: string) => FrpcProcess;
|
|
51
|
+
readonly signal: AbortSignal;
|
|
52
|
+
/** Installs / restarts the background service so it picks the service up. */
|
|
53
|
+
readonly installDaemon: () => Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
export declare function runServiceCommand(args: readonly string[], io: ServiceCommandIo, deps: ServiceCommandDeps): Promise<number>;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { serviceFrpcConfigToml, SERVICE_SHARE_ID } from "./service-config.js";
|
|
5
|
+
import { accountServiceControl } from "./service-control.js";
|
|
6
|
+
import { listLocalServices, removeLocalService, saveLocalService } from "./service-state.js";
|
|
7
|
+
import { ensureFrpc } from "./frpc.js";
|
|
8
|
+
import { ALLOWANCE_NOTE, remainingAllowanceLine } from "./allowance.js";
|
|
9
|
+
import { spawnFrpcProcess } from "./run.js";
|
|
10
|
+
const HEARTBEAT_MS = 30_000;
|
|
11
|
+
const HEARTBEAT_FAILURES = 3;
|
|
12
|
+
const POLL_MS = 10_000;
|
|
13
|
+
const RETRY_MIN_MS = 30_000;
|
|
14
|
+
const RETRY_MAX_MS = 10 * 60_000;
|
|
15
|
+
export { ALLOWANCE_NOTE };
|
|
16
|
+
export function serviceUsage() {
|
|
17
|
+
return [
|
|
18
|
+
"frely service share --type mcp|a2a --port <n> [--label <text>] [--background] [--json]",
|
|
19
|
+
"frely service list [--json]",
|
|
20
|
+
"frely service stop <id|label>",
|
|
21
|
+
"frely service remove <id|label>",
|
|
22
|
+
].join("\n");
|
|
23
|
+
}
|
|
24
|
+
export function parseServiceShareArguments(args) {
|
|
25
|
+
let type, port, label;
|
|
26
|
+
let background = false, json = false;
|
|
27
|
+
const value = (i, arg, name) => {
|
|
28
|
+
const inline = arg.startsWith(`${name}=`) ? arg.slice(name.length + 1) : args[i + 1];
|
|
29
|
+
if (inline === undefined || inline === "" || (!arg.includes("=") && inline.startsWith("-")))
|
|
30
|
+
throw new Error(`${name} needs a value.\n${serviceUsage()}`);
|
|
31
|
+
return inline;
|
|
32
|
+
};
|
|
33
|
+
for (let i = 0; i < args.length; i++) {
|
|
34
|
+
const arg = args[i];
|
|
35
|
+
const name = arg.split("=")[0];
|
|
36
|
+
if (name === "--type") {
|
|
37
|
+
type = value(i, arg, name);
|
|
38
|
+
if (!arg.includes("="))
|
|
39
|
+
i++;
|
|
40
|
+
}
|
|
41
|
+
else if (name === "--port") {
|
|
42
|
+
const text = value(i, arg, name);
|
|
43
|
+
if (!arg.includes("="))
|
|
44
|
+
i++;
|
|
45
|
+
port = Number(text);
|
|
46
|
+
if (!/^\d+$/u.test(text) || port < 1 || port > 65535)
|
|
47
|
+
throw new Error("--port must be a port number from 1 to 65535 on this computer (127.0.0.1).");
|
|
48
|
+
}
|
|
49
|
+
else if (name === "--label") {
|
|
50
|
+
label = value(i, arg, name);
|
|
51
|
+
if (!arg.includes("="))
|
|
52
|
+
i++;
|
|
53
|
+
}
|
|
54
|
+
else if (arg === "--background")
|
|
55
|
+
background = true;
|
|
56
|
+
else if (arg === "--json")
|
|
57
|
+
json = true;
|
|
58
|
+
else
|
|
59
|
+
throw new Error(`${arg.startsWith("-") ? "Unknown option" : "Unexpected argument"} ${arg}. A service is a port on this computer; no address is accepted.\n${serviceUsage()}`);
|
|
60
|
+
}
|
|
61
|
+
if (type !== "mcp" && type !== "a2a")
|
|
62
|
+
throw new Error(`--type must be mcp or a2a.\n${serviceUsage()}`);
|
|
63
|
+
if (port === undefined)
|
|
64
|
+
throw new Error(`--port is required.\n${serviceUsage()}`);
|
|
65
|
+
const text = (label ?? `local-${type}`).trim();
|
|
66
|
+
if (text.length < 1 || text.length > 60 || /[\u0000-\u001f\u007f]/u.test(text))
|
|
67
|
+
throw new Error("--label must be 1 to 60 characters.");
|
|
68
|
+
return { type, port, label: text, background, json };
|
|
69
|
+
}
|
|
70
|
+
/** One session of one service: ask Frely for it, run frpc on it, heartbeat, and revoke when it ends. Returns why it ended. */
|
|
71
|
+
export async function runServiceSession(service, deps) {
|
|
72
|
+
const binary = await deps.ensureFrpc();
|
|
73
|
+
const grant = await deps.control.session(service.serviceShareId);
|
|
74
|
+
let directory, frpc;
|
|
75
|
+
let heartbeat, expiry, configTimer;
|
|
76
|
+
try {
|
|
77
|
+
directory = await mkdtemp(join(tmpdir(), "frely-service-"));
|
|
78
|
+
await chmod(directory, 0o700).catch(() => undefined);
|
|
79
|
+
const configPath = join(directory, "frpc.toml");
|
|
80
|
+
await writeFile(configPath, serviceFrpcConfigToml(grant, service.port), { mode: 0o600 });
|
|
81
|
+
frpc = deps.spawnFrpc(binary, configPath);
|
|
82
|
+
configTimer = setTimeout(() => { void rm(configPath, { force: true }).catch(() => undefined); }, deps.configLifetimeMs ?? 3000);
|
|
83
|
+
deps.onGrant?.(grant);
|
|
84
|
+
let stoppedByUser = false;
|
|
85
|
+
const reason = await new Promise((resolve) => {
|
|
86
|
+
let failures = 0;
|
|
87
|
+
const stop = (text) => resolve(text);
|
|
88
|
+
if (deps.signal.aborted)
|
|
89
|
+
stop("Stopped.");
|
|
90
|
+
deps.signal.addEventListener("abort", () => { stoppedByUser = true; stop("Stopped."); }, { once: true });
|
|
91
|
+
void frpc.done.then(({ code, stderr }) => stop(`frpc exited${code === null ? "" : ` with code ${code}`}${stderr.trim() ? `: ${stderr.trim().split("\n").slice(-3).join(" | ")}` : "."}`));
|
|
92
|
+
expiry = setTimeout(() => stop("The session expired."), Math.max(0, Date.parse(grant.expiresAt) - Date.now()));
|
|
93
|
+
heartbeat = setInterval(() => {
|
|
94
|
+
void deps.control.heartbeat(grant.id).then((status) => {
|
|
95
|
+
failures = 0;
|
|
96
|
+
if (!status.active)
|
|
97
|
+
stop(describeEnd(status.reason));
|
|
98
|
+
}, () => { failures += 1; if (failures >= HEARTBEAT_FAILURES)
|
|
99
|
+
stop("Frely could not be reached."); });
|
|
100
|
+
}, deps.heartbeatMs ?? HEARTBEAT_MS);
|
|
101
|
+
});
|
|
102
|
+
return { reason, stopped: stoppedByUser };
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
if (heartbeat)
|
|
106
|
+
clearInterval(heartbeat);
|
|
107
|
+
if (expiry)
|
|
108
|
+
clearTimeout(expiry);
|
|
109
|
+
if (configTimer)
|
|
110
|
+
clearTimeout(configTimer);
|
|
111
|
+
frpc?.kill();
|
|
112
|
+
if (directory)
|
|
113
|
+
await rm(directory, { recursive: true, force: true }).catch(() => undefined);
|
|
114
|
+
await deps.control.revoke(grant.id).catch(() => undefined);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function describeEnd(reason) {
|
|
118
|
+
if (reason === "quota_exhausted")
|
|
119
|
+
return "This week's relay allowance is used up; it renews on Monday (UTC).";
|
|
120
|
+
if (reason === "expired")
|
|
121
|
+
return "The session expired.";
|
|
122
|
+
if (reason === "service_removed")
|
|
123
|
+
return "The service was removed.";
|
|
124
|
+
return `Frely ended this session (${reason ?? "revoked"}).`;
|
|
125
|
+
}
|
|
126
|
+
export function allowanceLines(grant) {
|
|
127
|
+
return [remainingAllowanceLine(grant.remainingBytes), ALLOWANCE_NOTE];
|
|
128
|
+
}
|
|
129
|
+
/** Keeps one service connected until aborted: when a session ends for any reason but a stop, ask for a new one after a growing pause. */
|
|
130
|
+
export async function keepServiceConnected(service, deps, sleep = abortableSleep) {
|
|
131
|
+
let pause = RETRY_MIN_MS;
|
|
132
|
+
while (!deps.signal.aborted) {
|
|
133
|
+
const started = Date.now();
|
|
134
|
+
try {
|
|
135
|
+
const { reason } = await runServiceSession(service, deps);
|
|
136
|
+
if (deps.signal.aborted)
|
|
137
|
+
return;
|
|
138
|
+
deps.write(`Service ${service.label}: ${reason}\n`);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (deps.signal.aborted)
|
|
142
|
+
return;
|
|
143
|
+
deps.write(`Service ${service.label}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
144
|
+
}
|
|
145
|
+
pause = Date.now() - started > 60_000 ? RETRY_MIN_MS : Math.min(pause * 2, RETRY_MAX_MS);
|
|
146
|
+
await sleep(pause, deps.signal);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function abortableSleep(ms, signal) {
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
if (signal.aborted)
|
|
152
|
+
return resolve();
|
|
153
|
+
const timer = setTimeout(done, ms);
|
|
154
|
+
function done() { clearTimeout(timer); signal.removeEventListener("abort", done); resolve(); }
|
|
155
|
+
signal.addEventListener("abort", done, { once: true });
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/** Runs inside the device daemon: every service saved with `background` stays connected; a stop or removal in the state file ends it within seconds. */
|
|
159
|
+
export async function superviseServices(options) {
|
|
160
|
+
const running = new Map();
|
|
161
|
+
let control;
|
|
162
|
+
const reconcile = async () => {
|
|
163
|
+
const wanted = (await listLocalServices().catch(() => [])).filter((service) => service.background);
|
|
164
|
+
for (const [id, entry] of running) {
|
|
165
|
+
const current = wanted.find((service) => service.serviceShareId === id);
|
|
166
|
+
if (!current || (current.port !== entry.port)) {
|
|
167
|
+
entry.abort.abort();
|
|
168
|
+
await entry.done;
|
|
169
|
+
running.delete(id);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
for (const service of wanted) {
|
|
173
|
+
if (running.has(service.serviceShareId))
|
|
174
|
+
continue;
|
|
175
|
+
try {
|
|
176
|
+
control ??= await (options.control ?? accountServiceControl)();
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
options.log(`Services: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const abort = new AbortController();
|
|
183
|
+
const onParent = () => abort.abort();
|
|
184
|
+
options.signal.addEventListener("abort", onParent, { once: true });
|
|
185
|
+
const done = keepServiceConnected(service, {
|
|
186
|
+
control, ensureFrpc: () => ensureFrpc({ log: () => undefined }), spawnFrpc: spawnFrpcProcess, write: (text) => options.log(text.trimEnd()), signal: abort.signal,
|
|
187
|
+
onGrant: (grant) => options.log(`Service ${service.label} connected. ${allowanceLines(grant).join(" ")}`), ...options.session,
|
|
188
|
+
}).finally(() => options.signal.removeEventListener("abort", onParent));
|
|
189
|
+
running.set(service.serviceShareId, Object.assign({ abort, done }, { port: service.port }));
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
while (!options.signal.aborted) {
|
|
193
|
+
await reconcile();
|
|
194
|
+
await abortableSleep(options.pollMs ?? POLL_MS, options.signal);
|
|
195
|
+
}
|
|
196
|
+
for (const entry of running.values())
|
|
197
|
+
entry.abort.abort();
|
|
198
|
+
await Promise.all([...running.values()].map((entry) => entry.done));
|
|
199
|
+
}
|
|
200
|
+
export async function runServiceCommand(args, io, deps) {
|
|
201
|
+
const [action, ...rest] = args;
|
|
202
|
+
if (action === undefined || action === "help" || action === "--help") {
|
|
203
|
+
io.write(`Usage:\n${serviceUsage().split("\n").map((line) => ` ${line}`).join("\n")}\n`);
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
if (action === "share")
|
|
207
|
+
return shareService(parseServiceShareArguments(rest), io, deps);
|
|
208
|
+
if (action === "list") {
|
|
209
|
+
if (rest.some((arg) => arg !== "--json"))
|
|
210
|
+
throw new Error(`Usage: frely service list [--json]`);
|
|
211
|
+
const control = await deps.control();
|
|
212
|
+
const [remote, local] = await Promise.all([control.list(), listLocalServices()]);
|
|
213
|
+
const rows = remote.map((item) => {
|
|
214
|
+
const mine = local.find((service) => service.serviceShareId === item.id);
|
|
215
|
+
return { id: item.id, type: item.type, label: item.label, onThisComputer: Boolean(mine), background: mine?.background ?? false };
|
|
216
|
+
});
|
|
217
|
+
if (rest.includes("--json"))
|
|
218
|
+
io.write(`${JSON.stringify({ services: rows }, null, 2)}\n`);
|
|
219
|
+
else if (rows.length === 0)
|
|
220
|
+
io.write("No services are registered.\n");
|
|
221
|
+
else
|
|
222
|
+
for (const row of rows)
|
|
223
|
+
io.write(`${row.id} ${row.type} ${row.label} ${row.onThisComputer ? (row.background ? "background" : "this computer") : "other device"}\n`);
|
|
224
|
+
return 0;
|
|
225
|
+
}
|
|
226
|
+
if (action === "stop" || action === "remove") {
|
|
227
|
+
if (rest.length !== 1 || rest[0].startsWith("-"))
|
|
228
|
+
throw new Error(`Usage: frely service ${action} <id|label>`);
|
|
229
|
+
const service = await findLocal(rest[0]);
|
|
230
|
+
if (action === "stop") {
|
|
231
|
+
await saveLocalService({ ...service, background: false });
|
|
232
|
+
io.write(`Stopped ${service.label}. The background service disconnects it within seconds; a foreground \`frely service share\` stops with Ctrl+C. The service stays registered.\n`);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
await (await deps.control()).remove(service.serviceShareId);
|
|
236
|
+
await removeLocalService(service.serviceShareId);
|
|
237
|
+
io.write(`Removed ${service.label}. Products that pointed at it answer as unreachable.\n`);
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
throw new Error(`Unknown service command ${action}.\n${serviceUsage()}`);
|
|
241
|
+
}
|
|
242
|
+
async function findLocal(selector) {
|
|
243
|
+
const services = await listLocalServices();
|
|
244
|
+
const matches = services.filter((service) => SERVICE_SHARE_ID.test(selector) ? service.serviceShareId === selector : service.label === selector);
|
|
245
|
+
if (matches.length !== 1)
|
|
246
|
+
throw new Error(matches.length === 0 ? `No service "${selector}" on this computer. Run frely service list.` : `More than one service is called "${selector}"; use its id.`);
|
|
247
|
+
return matches[0];
|
|
248
|
+
}
|
|
249
|
+
async function shareService(options, io, deps) {
|
|
250
|
+
const say = (text) => { if (!options.json)
|
|
251
|
+
io.write(text); };
|
|
252
|
+
if (!(await deps.probe(options.port)))
|
|
253
|
+
throw new Error(`Nothing is listening on 127.0.0.1:${options.port}. Start your ${options.type.toUpperCase()} service first.`);
|
|
254
|
+
const control = await deps.control();
|
|
255
|
+
const record = await control.register({ type: options.type, label: options.label });
|
|
256
|
+
const existing = (await listLocalServices()).find((service) => service.serviceShareId === record.id);
|
|
257
|
+
if (existing?.background && !options.background)
|
|
258
|
+
throw new Error(`${record.label} is already kept connected by the background service. Run \`frely service stop ${record.id}\` first, or share it again with --background.`);
|
|
259
|
+
const service = { serviceShareId: record.id, type: record.type, label: record.label, port: options.port, createdAt: existing?.createdAt || record.createdAt || new Date().toISOString(), background: options.background };
|
|
260
|
+
await saveLocalService(service);
|
|
261
|
+
if (options.background) {
|
|
262
|
+
await deps.installDaemon();
|
|
263
|
+
if (options.json)
|
|
264
|
+
io.write(`${JSON.stringify({ serviceShareId: record.id, type: record.type, label: record.label, background: true })}\n`);
|
|
265
|
+
else
|
|
266
|
+
io.write(`Service ${record.id} (${record.type}, ${record.label}) is kept connected by the background service. It is not a public link: only Frely can reach it. ${ALLOWANCE_NOTE}\n`);
|
|
267
|
+
return 0;
|
|
268
|
+
}
|
|
269
|
+
const outcome = await runServiceSession(service, {
|
|
270
|
+
control, ensureFrpc: deps.ensureFrpc, spawnFrpc: deps.spawnFrpc, write: io.write, signal: deps.signal,
|
|
271
|
+
onGrant: (grant) => {
|
|
272
|
+
if (options.json) {
|
|
273
|
+
io.write(`${JSON.stringify({ serviceShareId: record.id, type: record.type, label: record.label, sessionId: grant.id, expiresAt: grant.expiresAt, remainingBytes: grant.remainingBytes })}\n`);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
say(`Sharing ${record.type.toUpperCase()} service ${record.id} (${record.label}) from 127.0.0.1:${options.port}. There is no public link; only Frely can reach it.\n`);
|
|
277
|
+
for (const line of allowanceLines(grant))
|
|
278
|
+
say(`${line}\n`);
|
|
279
|
+
say(`Expires ${grant.expiresAt}; run again to renew, or use --background to keep it connected. Press Ctrl+C to stop.\n`);
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
say(`\n${outcome.reason}\n`);
|
|
283
|
+
return outcome.stopped ? 0 : 1;
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=service-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-run.js","sourceRoot":"","sources":["../../src/share/service-run.ts"],"names":[],"mappings":"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"}
|