ai-fly 0.3.0-alpha.2 → 0.3.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/dist/ai-fly.js CHANGED
@@ -29,7 +29,8 @@ Provider:
29
29
  Consumer:
30
30
  ai-fly join <dweb1-token> [--data <dir>] [--proxy …] admit this device (fabric layer)
31
31
  ai-fly import <aifly1-link> [--run] [--preview] [--proxy …] bundle link: join + keyring
32
- ai-fly run [--data <dir>] [--strict-ports] [--proxy …] run the local gateway
32
+ ai-fly run [--data <dir>] [--strict-ports] [--proxy …] [--detach] run the local gateway
33
+ ai-fly run stop|info|restart|log [--force] [--lines <n>] gateway lifecycle (mirrors daemon)
33
34
  ai-fly ports [--data <dir>] [<serviceId> --port <n>] view/override mapped ports
34
35
  ai-fly test [--data <dir>] [--service <name>] [--form …] [--content <text>]
35
36
  single AI request through the local gateway
@@ -60,7 +61,7 @@ async function dispatch(command, rest) {
60
61
  const lazy = (load) => {
61
62
  return (argv, ctx) => load().then((m) => m.run([...argv], ctx));
62
63
  };
63
- return match(command).with("serve", () => lazy(() => import("./serve-DSBlodTF.mjs"))(rest)).with("daemon", () => lazy(() => import("./daemon-DklsEniO.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-C73CAMZ6.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-SA37VND5.mjs"))(rest)).with("settings", async () => (await import("./settings-DU0YqNDt.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-DU0YqNDt.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-Bc0OKBAi.mjs"))(rest)).with("service", () => lazy(() => import("./service-B5uORhl3.mjs"))(rest)).with("group", () => lazy(() => import("./group-B96IKEDF.mjs"))(rest)).with("share", () => lazy(() => import("./share-Cug0944N.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-CkpvK33Q.mjs"))(rest)).with("join", () => lazy(() => import("./join-DsKUAibH.mjs"))(rest)).with("import", () => lazy(() => import("./import-tilxdbTH.mjs"))(rest)).with("run", () => lazy(() => import("./run-DbPXAm6h.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-rRppuBgo.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-B17zGwj4.mjs"))(rest)).with("key", () => {
64
+ return match(command).with("serve", () => lazy(() => import("./serve-DSBlodTF.mjs"))(rest)).with("daemon", () => lazy(() => import("./daemon-ZWUSWAgM.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-C73CAMZ6.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-SA37VND5.mjs"))(rest)).with("settings", async () => (await import("./settings-DU0YqNDt.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-DU0YqNDt.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-Bc0OKBAi.mjs"))(rest)).with("service", () => lazy(() => import("./service-B5uORhl3.mjs"))(rest)).with("group", () => lazy(() => import("./group-B96IKEDF.mjs"))(rest)).with("share", () => lazy(() => import("./share-Cug0944N.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-CkpvK33Q.mjs"))(rest)).with("join", () => lazy(() => import("./join-DsKUAibH.mjs"))(rest)).with("import", () => lazy(() => import("./import-tilxdbTH.mjs"))(rest)).with("run", () => lazy(() => import("./run-bbDjqVLr.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-rRppuBgo.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-B17zGwj4.mjs"))(rest)).with("key", () => {
64
65
  if (rest[0] === "add") return lazy(() => import("./key-CNufbB__.mjs"))(rest);
65
66
  return lazy(() => import("./key-BiEp995L.mjs"))(rest);
66
67
  }).with("status", async () => {
@@ -1,91 +1,13 @@
1
1
  import { n as UsageError, r as reportCliError, t as CliError } from "./errors-BGtxPkM7.mjs";
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { r as settingsPath, t as loadSettings } from "./settings-C1Hb4zwd.mjs";
4
+ import { a as killHard, c as terminateGracefully, i as isAlive, l as writeLastStart, n as daemonDir, o as readLastStart, r as ensureDaemonDir, s as readPid, t as clearPid, u as writePid } from "./daemon-state-CYkiW3SA.mjs";
4
5
  import { r as openStore } from "./common-CqxqIg6D.mjs";
5
- import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { openSync, readFileSync } from "node:fs";
6
7
  import { homedir } from "node:os";
7
- import { isAbsolute, join, resolve } from "node:path";
8
- import { execFileSync, spawn } from "node:child_process";
8
+ import { isAbsolute, resolve } from "node:path";
9
+ import { spawn } from "node:child_process";
9
10
  import process from "node:process";
10
- //#region src/cli/daemon-state.ts
11
- function daemonDir(base = homedir()) {
12
- const root = join(base, ".aifly", "daemon");
13
- return {
14
- root,
15
- pidFile: join(root, "pid"),
16
- lastStartFile: join(root, "last-start.json"),
17
- logFile: join(root, "daemon.log")
18
- };
19
- }
20
- function ensureDaemonDir(base = homedir()) {
21
- const dir = daemonDir(base);
22
- mkdirSync(dir.root, { recursive: true });
23
- return dir;
24
- }
25
- function writePid(pid, base = homedir()) {
26
- const dir = ensureDaemonDir(base);
27
- writeFileSync(dir.pidFile, `${pid}\n`);
28
- }
29
- function readPid(base = homedir()) {
30
- try {
31
- const raw = readFileSync(daemonDir(base).pidFile, "utf8").trim();
32
- const pid = Number.parseInt(raw, 10);
33
- return Number.isInteger(pid) && pid > 0 ? pid : null;
34
- } catch {
35
- return null;
36
- }
37
- }
38
- function clearPid(base = homedir()) {
39
- const { pidFile } = daemonDir(base);
40
- if (existsSync(pidFile)) writeFileSync(pidFile, "");
41
- }
42
- function writeLastStart(last, base = homedir()) {
43
- const dir = ensureDaemonDir(base);
44
- writeFileSync(dir.lastStartFile, `${JSON.stringify(last, null, 2)}\n`);
45
- }
46
- function readLastStart(base = homedir()) {
47
- try {
48
- const raw = JSON.parse(readFileSync(daemonDir(base).lastStartFile, "utf8"));
49
- if (typeof raw.entry === "string" && Array.isArray(raw.args)) return {
50
- entry: raw.entry,
51
- args: raw.args,
52
- startedAt: Number(raw.startedAt) || Date.now()
53
- };
54
- return null;
55
- } catch {
56
- return null;
57
- }
58
- }
59
- /** 进程活性(ESRCH = 不存在)。 */
60
- function isAlive(pid) {
61
- try {
62
- process.kill(pid, 0);
63
- return true;
64
- } catch (error) {
65
- return error.code === "EPERM";
66
- }
67
- }
68
- /** 优雅终止:SIGTERM → 轮询 ≤timeoutMs → 仍未退返回 false(调用方决定硬杀)。 */
69
- async function terminateGracefully(pid, timeoutMs = 1e4) {
70
- process.kill(pid, "SIGTERM");
71
- const deadline = Date.now() + timeoutMs;
72
- while (Date.now() < deadline) {
73
- if (!isAlive(pid)) return true;
74
- await new Promise((resolve) => setTimeout(resolve, 200));
75
- }
76
- return false;
77
- }
78
- /** 硬杀:posix SIGKILL;win32 taskkill(无优雅信号语义,USAGE 明示)。 */
79
- function killHard(pid) {
80
- if (process.platform === "win32") execFileSync("taskkill", [
81
- "/PID",
82
- String(pid),
83
- "/F",
84
- "/T"
85
- ], { stdio: "ignore" });
86
- else process.kill(pid, "SIGKILL");
87
- }
88
- //#endregion
89
11
  //#region src/cli/commands/provider/daemon.ts
90
12
  const SPEC = {
91
13
  detach: { type: "boolean" },
@@ -0,0 +1,85 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { execFileSync } from "node:child_process";
5
+ import process from "node:process";
6
+ //#region src/cli/daemon-state.ts
7
+ function daemonDir(base = homedir(), kind = "daemon") {
8
+ const root = join(base, ".aifly", kind);
9
+ return {
10
+ root,
11
+ pidFile: join(root, "pid"),
12
+ lastStartFile: join(root, "last-start.json"),
13
+ logFile: join(root, `${kind}.log`)
14
+ };
15
+ }
16
+ function ensureDaemonDir(base = homedir(), kind = "daemon") {
17
+ const dir = daemonDir(base, kind);
18
+ mkdirSync(dir.root, { recursive: true });
19
+ return dir;
20
+ }
21
+ function writePid(pid, base = homedir(), kind = "daemon") {
22
+ const dir = ensureDaemonDir(base, kind);
23
+ writeFileSync(dir.pidFile, `${pid}\n`);
24
+ }
25
+ function readPid(base = homedir(), kind = "daemon") {
26
+ try {
27
+ const raw = readFileSync(daemonDir(base, kind).pidFile, "utf8").trim();
28
+ const pid = Number.parseInt(raw, 10);
29
+ return Number.isInteger(pid) && pid > 0 ? pid : null;
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ function clearPid(base = homedir(), kind = "daemon") {
35
+ const { pidFile } = daemonDir(base, kind);
36
+ if (existsSync(pidFile)) writeFileSync(pidFile, "");
37
+ }
38
+ function writeLastStart(last, base = homedir(), kind = "daemon") {
39
+ const dir = ensureDaemonDir(base, kind);
40
+ writeFileSync(dir.lastStartFile, `${JSON.stringify(last, null, 2)}\n`);
41
+ }
42
+ function readLastStart(base = homedir(), kind = "daemon") {
43
+ try {
44
+ const raw = JSON.parse(readFileSync(daemonDir(base, kind).lastStartFile, "utf8"));
45
+ if (typeof raw.entry === "string" && Array.isArray(raw.args)) return {
46
+ entry: raw.entry,
47
+ args: raw.args,
48
+ startedAt: Number(raw.startedAt) || Date.now()
49
+ };
50
+ return null;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+ /** 进程活性(ESRCH = 不存在)。 */
56
+ function isAlive(pid) {
57
+ try {
58
+ process.kill(pid, 0);
59
+ return true;
60
+ } catch (error) {
61
+ return error.code === "EPERM";
62
+ }
63
+ }
64
+ /** 优雅终止:SIGTERM → 轮询 ≤timeoutMs → 仍未退返回 false(调用方决定硬杀)。 */
65
+ async function terminateGracefully(pid, timeoutMs = 1e4) {
66
+ process.kill(pid, "SIGTERM");
67
+ const deadline = Date.now() + timeoutMs;
68
+ while (Date.now() < deadline) {
69
+ if (!isAlive(pid)) return true;
70
+ await new Promise((resolve) => setTimeout(resolve, 200));
71
+ }
72
+ return false;
73
+ }
74
+ /** 硬杀:posix SIGKILL;win32 taskkill(无优雅信号语义,USAGE 明示)。 */
75
+ function killHard(pid) {
76
+ if (process.platform === "win32") execFileSync("taskkill", [
77
+ "/PID",
78
+ String(pid),
79
+ "/F",
80
+ "/T"
81
+ ], { stdio: "ignore" });
82
+ else process.kill(pid, "SIGKILL");
83
+ }
84
+ //#endregion
85
+ export { killHard as a, terminateGracefully as c, isAlive as i, writeLastStart as l, daemonDir as n, readLastStart as o, ensureDaemonDir as r, readPid as s, clearPid as t, writePid as u };
@@ -0,0 +1,215 @@
1
+ import { n as UsageError, r as reportCliError, t as CliError } from "./errors-BGtxPkM7.mjs";
2
+ import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
+ import { n as consumersRoot, s as listKeyrings } from "./store-BiTS2FTl.mjs";
4
+ import { a as ringsForRun, i as printListeners, n as ctxHomedir, o as waitForSignals, r as ctxOut, t as createSdkFabricFactory } from "./common-CgxCXeTt.mjs";
5
+ import { n as createFabricProviderTransport, t as startEngine } from "./runtime-D_nxUEjd.mjs";
6
+ import { a as killHard, c as terminateGracefully, i as isAlive, l as writeLastStart, n as daemonDir, o as readLastStart, r as ensureDaemonDir, s as readPid, t as clearPid, u as writePid } from "./daemon-state-CYkiW3SA.mjs";
7
+ import { openSync, readFileSync } from "node:fs";
8
+ import { resolve } from "node:path";
9
+ import { spawn } from "node:child_process";
10
+ //#region src/cli/commands/consumer/run.ts
11
+ const KIND = "gateway";
12
+ const SPEC = {
13
+ detach: { type: "boolean" },
14
+ force: { type: "boolean" },
15
+ data: {
16
+ type: "string",
17
+ tilde: true
18
+ },
19
+ "strict-ports": { type: "boolean" },
20
+ relay: { type: "multi" },
21
+ proxy: { type: "string" },
22
+ lines: { type: "string" }
23
+ };
24
+ const USAGE = `usage:
25
+ ai-fly run [--data <dir>] [--strict-ports] [--relay <url>]... [--proxy <url|env|none>] [--detach]
26
+ ai-fly run stop [--force]
27
+ ai-fly run info
28
+ ai-fly run restart [--detach] [同 start 参数]
29
+ ai-fly run log [--lines <n>]`;
30
+ async function run(argv, ctx = {}) {
31
+ const home = ctxHomedir(ctx);
32
+ const sub = argv[0];
33
+ try {
34
+ switch (sub) {
35
+ case "stop": return await stop(argv.slice(1), home);
36
+ case "info": return info(argv.slice(1), home);
37
+ case "restart": return await restart(argv.slice(1), home, ctx);
38
+ case "log": return log(argv.slice(1), home);
39
+ default: return await start(argv, home, ctx);
40
+ }
41
+ } catch (err) {
42
+ return reportCliError(err);
43
+ }
44
+ }
45
+ /** last-start 记忆(args 含 "run" token,restart 原样回放前剥除)。 */
46
+ function lastStartOf(runArgv) {
47
+ if (process.argv[1] === void 0) throw new CliError("error: cannot resolve the CLI entry for gateway respawn");
48
+ return {
49
+ entry: resolve(process.argv[1]),
50
+ args: ["run", ...runArgv],
51
+ startedAt: Date.now()
52
+ };
53
+ }
54
+ async function start(runArgv, home, ctx) {
55
+ const { options, positionals } = parseArgv([...runArgv], SPEC, { homedir: home });
56
+ if (positionals.length > 0) throw new UsageError(`error: unexpected argument '${positionals[0]}' (known subcommands: stop, info, restart, log)\n${USAGE}`);
57
+ const running = currentPid(home);
58
+ if (running !== null && running !== process.pid) throw new CliError(`error: gateway already running (pid ${running}); try 'ai-fly run restart'`);
59
+ const out = ctxOut(ctx);
60
+ const root = consumersRoot(options.data, home);
61
+ const { rings, warnings } = listKeyrings(root);
62
+ for (const w of warnings) out(`warning: ${w}`);
63
+ const engineRings = ringsForRun(rings);
64
+ if (engineRings.length === 0) throw new CliError("error: no imported providers - run 'ai-fly import <aifly1-link>' or 'ai-fly join <token>' first");
65
+ if (options.detach === true) {
66
+ const dir = ensureDaemonDir(home, KIND);
67
+ const respawnArgs = ["run", ...runArgv.filter((a) => a !== "--detach")];
68
+ const logFd = openSync(dir.logFile, "a");
69
+ const child = spawn(process.execPath, [
70
+ ...process.execArgv,
71
+ process.argv[1],
72
+ ...respawnArgs
73
+ ], {
74
+ detached: true,
75
+ stdio: [
76
+ "ignore",
77
+ logFd,
78
+ logFd
79
+ ],
80
+ env: process.env,
81
+ cwd: process.cwd()
82
+ });
83
+ child.unref();
84
+ await new Promise((resolve) => setTimeout(resolve, 400));
85
+ if (child.exitCode !== null) throw new CliError(`error: gateway exited immediately - see ${dir.logFile}`);
86
+ writePid(child.pid, home, KIND);
87
+ writeLastStart(lastStartOf(respawnArgs.slice(1)), home, KIND);
88
+ process.stdout.write(`gateway started in background (pid ${child.pid}) - log: ${dir.logFile}\n`);
89
+ return 0;
90
+ }
91
+ writePid(process.pid, home, KIND);
92
+ writeLastStart(lastStartOf(runArgv), home, KIND);
93
+ process.on("exit", () => {
94
+ clearPid(home, KIND);
95
+ });
96
+ const factory = await createSdkFabricFactory(options.relay, ctx, void 0, options.proxy);
97
+ out(`gateway starting - booting fabric for ${engineRings.length} provider ring(s) (unreachable relays can stall this ~30s; Ctrl+C to abort)...`);
98
+ const engine = await startEngine({
99
+ rings: engineRings,
100
+ consumersRoot: root,
101
+ sessionFactoryFor: (ring) => createFabricProviderTransport(factory, {
102
+ dataDir: `${root}/${ring.endpointId.slice(0, 8)}/fabric`,
103
+ providerEndpointId: ring.endpointId,
104
+ ...ring.relayUrls.length > 0 ? { relayUrls: ring.relayUrls } : {}
105
+ }),
106
+ strictPorts: options["strict-ports"] === true,
107
+ onNotice: out
108
+ });
109
+ printListeners(out, engine.gateway.listenerInfo());
110
+ out("gateway running - press Ctrl-C to stop");
111
+ await waitForSignals();
112
+ await engine.stop();
113
+ out("gateway stopped");
114
+ return 0;
115
+ }
116
+ /** 后台 pid(活性核验;陈旧 pidfile 就地清理返回 null)。 */
117
+ function currentPid(home) {
118
+ const pid = readPid(home, KIND);
119
+ if (pid === null) return null;
120
+ if (!isAlive(pid)) {
121
+ clearPid(home, KIND);
122
+ return null;
123
+ }
124
+ return pid;
125
+ }
126
+ async function stop(stopArgv, home) {
127
+ const { options, positionals } = parseArgv([...stopArgv], SPEC, { homedir: home });
128
+ if (positionals.length > 0) throw new UsageError(`error: unexpected argument '${positionals[0]}'`);
129
+ const pid = currentPid(home);
130
+ if (pid === null) {
131
+ process.stdout.write("gateway is not running\n");
132
+ return 0;
133
+ }
134
+ if (process.platform === "win32") {
135
+ killHard(pid);
136
+ clearPid(home, KIND);
137
+ process.stdout.write(`gateway stopped (pid ${pid}, forced - windows has no cross-process graceful signal)\n`);
138
+ return 0;
139
+ }
140
+ const graceful = await terminateGracefully(pid);
141
+ if (!graceful && options.force !== true) throw new CliError(`error: gateway (pid ${pid}) did not exit in time - retry with --force`);
142
+ if (!graceful) killHard(pid);
143
+ clearPid(home, KIND);
144
+ process.stdout.write(`gateway stopped (pid ${pid}${graceful ? "" : ", forced"})\n`);
145
+ return 0;
146
+ }
147
+ function info(infoArgv, home) {
148
+ const { positionals } = parseArgv([...infoArgv], SPEC, { homedir: home });
149
+ if (positionals.length > 0) throw new UsageError(`error: unexpected argument '${positionals[0]}'`);
150
+ const pid = currentPid(home);
151
+ const last = readLastStart(home, KIND);
152
+ const out = (line) => {
153
+ process.stdout.write(`${line}\n`);
154
+ };
155
+ out(pid !== null ? `running : yes (pid ${pid})` : "running : no");
156
+ if (pid !== null && last !== null) {
157
+ const up = Math.max(0, Math.round((Date.now() - last.startedAt) / 1e3));
158
+ out(`uptime : ${Math.floor(up / 60)}m ${up % 60}s`);
159
+ }
160
+ if (last !== null) {
161
+ out(`entry : ${last.entry}`);
162
+ out(`arguments : ${last.args.join(" ")}`);
163
+ }
164
+ out(`state dir : ${daemonDir(home, KIND).root}`);
165
+ out(`log file : ${daemonDir(home, KIND).logFile}`);
166
+ const dataArg = last?.args.includes("--data") ? last.args[last.args.indexOf("--data") + 1] : void 0;
167
+ const root = consumersRoot(dataArg, home);
168
+ try {
169
+ const { rings } = listKeyrings(root);
170
+ const services = rings.reduce((n, r) => n + r.services.length, 0);
171
+ const keys = rings.reduce((n, r) => n + r.keys.length, 0);
172
+ out(`data dir : ${root}`);
173
+ out(`rings : ${rings.length} (services: ${services}, keys: ${keys})`);
174
+ } catch {
175
+ out(`data dir : ${root} (store not readable)`);
176
+ }
177
+ return 0;
178
+ }
179
+ async function restart(restartArgv, home, ctx) {
180
+ parseArgv([...restartArgv], SPEC, { homedir: home });
181
+ const pid = currentPid(home);
182
+ if (pid !== null) {
183
+ const graceful = process.platform === "win32" ? false : await terminateGracefully(pid);
184
+ if (!graceful) killHard(pid);
185
+ clearPid(home, KIND);
186
+ process.stdout.write(`gateway stopped (pid ${pid}${graceful ? "" : ", forced"})\n`);
187
+ } else process.stdout.write("gateway was not running\n");
188
+ if (restartArgv.some((a) => !a.startsWith("--detach"))) return await start(restartArgv, home, ctx);
189
+ const last = readLastStart(home, KIND);
190
+ const detachWanted = restartArgv.includes("--detach");
191
+ if (last === null) return await start(detachWanted ? ["--detach"] : [], home, ctx);
192
+ const replay = last.args.filter((a) => a !== "run" && a !== "--detach");
193
+ return await start(detachWanted ? [...replay, "--detach"] : replay, home, ctx);
194
+ }
195
+ function log(logArgv, home) {
196
+ const { options, positionals } = parseArgv([...logArgv], SPEC, { homedir: home });
197
+ if (positionals.length > 0) throw new UsageError(`error: unexpected argument '${positionals[0]}'`);
198
+ const lines = Math.max(1, Number.parseInt(String(options.lines ?? "50"), 10) || 50);
199
+ const { logFile } = daemonDir(home, KIND);
200
+ try {
201
+ const content = readFileSync(logFile, "utf8").trimEnd();
202
+ if (content === "") {
203
+ process.stdout.write("(gateway.log is empty)\n");
204
+ return 0;
205
+ }
206
+ const tail = content.split("\n").slice(-lines).join("\n");
207
+ process.stdout.write(`${tail}\n`);
208
+ return 0;
209
+ } catch {
210
+ process.stdout.write(`no gateway log yet (${logFile})\n`);
211
+ return 0;
212
+ }
213
+ }
214
+ //#endregion
215
+ export { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-fly",
3
- "version": "0.3.0-alpha.2",
3
+ "version": "0.3.0",
4
4
  "description": "ai-fly — peer-to-peer HTTP/WebSocket bridge with AI-ready presets, over OpenDWeb fabric",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
@@ -1,45 +0,0 @@
1
- import { t as CliError } from "./errors-BGtxPkM7.mjs";
2
- import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
- import { n as consumersRoot, s as listKeyrings } from "./store-BiTS2FTl.mjs";
4
- import { a as ringsForRun, i as printListeners, n as ctxHomedir, o as waitForSignals, r as ctxOut, t as createSdkFabricFactory } from "./common-CgxCXeTt.mjs";
5
- import { n as createFabricProviderTransport, t as startEngine } from "./runtime-D_nxUEjd.mjs";
6
- import { homedir } from "node:os";
7
- //#region src/cli/commands/consumer/run.ts
8
- async function run(argv, ctx = {}) {
9
- const { options } = parseArgv(argv, {
10
- data: {
11
- type: "string",
12
- tilde: true
13
- },
14
- "strict-ports": { type: "boolean" },
15
- relay: { type: "multi" },
16
- proxy: { type: "string" }
17
- }, { homedir: ctx.homedir ?? homedir() });
18
- const out = ctxOut(ctx);
19
- const root = consumersRoot(options.data, ctxHomedir(ctx));
20
- const { rings, warnings } = listKeyrings(root);
21
- for (const w of warnings) out(`warning: ${w}`);
22
- const engineRings = ringsForRun(rings);
23
- if (engineRings.length === 0) throw new CliError("error: no imported providers - run 'ai-fly import <aifly1-link>' or 'ai-fly join <token>' first");
24
- const factory = await createSdkFabricFactory(options.relay, ctx, void 0, options.proxy);
25
- out(`gateway starting - booting fabric for ${engineRings.length} provider ring(s) (unreachable relays can stall this ~30s; Ctrl+C to abort)...`);
26
- const engine = await startEngine({
27
- rings: engineRings,
28
- consumersRoot: root,
29
- sessionFactoryFor: (ring) => createFabricProviderTransport(factory, {
30
- dataDir: `${root}/${ring.endpointId.slice(0, 8)}/fabric`,
31
- providerEndpointId: ring.endpointId,
32
- ...ring.relayUrls.length > 0 ? { relayUrls: ring.relayUrls } : {}
33
- }),
34
- strictPorts: options["strict-ports"] === true,
35
- onNotice: out
36
- });
37
- printListeners(out, engine.gateway.listenerInfo());
38
- out("gateway running - press Ctrl-C to stop");
39
- await waitForSignals();
40
- await engine.stop();
41
- out("gateway stopped");
42
- return 0;
43
- }
44
- //#endregion
45
- export { run };