@finchip.ai/foga 0.6.1 → 0.6.2

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.
@@ -62,6 +62,17 @@ export async function waitForRpc(rpc, timeoutMs, giveUp) {
62
62
  throw new Error(`RPC at ${rpc} did not come up within ${timeoutMs} ms`);
63
63
  }
64
64
  /** Why a port cannot be used for a new anvil: another RPC already answers there, or something else holds it. */
65
+ /**
66
+ * The first port from `from` (inclusive) that nothing on 127.0.0.1 accepts connections on, trying `tries` ports in a
67
+ * row; null when all are taken. For the defaults a quickstart falls back on when its usual port is busy — the next
68
+ * one up rather than an ephemeral one, so the URL it prints is still one a person can remember.
69
+ */
70
+ export async function nextFreePort(from, tries = 20) {
71
+ for (let p = from; p < from + tries; p++)
72
+ if (!(await portInUse(p)))
73
+ return p;
74
+ return null;
75
+ }
65
76
  export async function portProblem(port) {
66
77
  if (!(await portInUse(port)))
67
78
  return null;
@@ -12,7 +12,7 @@ import { defaultCatalog, OPERATOR_CALLER } from "../tools/index.js";
12
12
  import { ensureWallet, ensuredKey, walletDir } from "../node/wallet.js";
13
13
  import { repoRoot } from "../util/fs.js";
14
14
  import { deployWorld } from "../world/deploy.js";
15
- import { ANVIL_INSTALL_HINT, anvilBinary, anvilVersion, launchAnvil, portInUse, portProblem, stopChild } from "./anvil.js";
15
+ import { ANVIL_INSTALL_HINT, anvilBinary, anvilVersion, launchAnvil, nextFreePort, portInUse, portProblem, stopChild } from "./anvil.js";
16
16
  import { birthCell } from "./birth.js";
17
17
  import { mintCases } from "./demander.js";
18
18
  import { cleanEnv, ownCli, waitForHttp } from "./loop-d.js";
@@ -49,29 +49,48 @@ export async function runQuickstart(o = {}) {
49
49
  const out = o.out ?? ((text) => console.log(text));
50
50
  const root = repoRoot();
51
51
  const dir = resolve(o.dir ?? defaultQuickstartDir());
52
- const port = o.port ?? 8545;
53
- const listen = o.listen === undefined ? "127.0.0.1:8787" : o.listen;
54
52
  const name = o.name ?? "quick";
55
- const rpc = `http://127.0.0.1:${port}`;
56
53
  const walletPath = resolve(o.wallet ?? walletDir());
57
- const nodeUrlPlanned = listen ? (() => {
58
- const i = listen.lastIndexOf(":");
59
- const host = listen.slice(0, i) || "127.0.0.1";
60
- return `http://${host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host}:${listen.slice(i + 1)}`;
61
- })() : null;
62
54
  // --- say what is wrong before touching anything
63
55
  const anvilBin = anvilBinary();
64
56
  const version = anvilVersion(anvilBin.path);
65
57
  if (!version)
66
58
  throw new Error(ANVIL_INSTALL_HINT);
67
- const problem = await portProblem(port);
68
- if (problem)
69
- throw new Error(problem);
59
+ // The default ports give way when something else holds them — a served cell on 8787 (the reference cell's own box,
60
+ // or a node of yours), another chain on 8545 — so the bare command works on any machine; the next free port up is
61
+ // taken and said so. A port asked for by name (--port, --listen) is not moved: that one is refused as before.
62
+ let port = o.port ?? 8545;
63
+ if (o.port === undefined && (await portInUse(port))) {
64
+ const next = await nextFreePort(port + 1);
65
+ if (next === null)
66
+ throw new Error(`ports ${port}-${port + 20} are all in use; pass --port <n> for the chain`);
67
+ log(`quickstart: port ${port} is in use (another chain or node); anvil takes ${next} instead`);
68
+ port = next;
69
+ }
70
+ else {
71
+ const problem = await portProblem(port);
72
+ if (problem)
73
+ throw new Error(problem);
74
+ }
75
+ let listen = o.listen === undefined ? "127.0.0.1:8787" : o.listen;
70
76
  if (listen) {
71
77
  const lp = Number(listen.slice(listen.lastIndexOf(":") + 1));
72
- if (await portInUse(lp))
73
- throw new Error(`port ${lp} is in use; pass --listen <host:port> for the node (or --no-serve to run no node)`);
78
+ if (await portInUse(lp)) {
79
+ if (o.listen !== undefined)
80
+ throw new Error(`port ${lp} is in use; pass --listen <host:port> for the node (or --no-serve to run no node)`);
81
+ const next = await nextFreePort(lp + 1);
82
+ if (next === null)
83
+ throw new Error(`ports ${lp}-${lp + 20} are all in use; pass --listen <host:port> for the node (or --no-serve)`);
84
+ log(`quickstart: port ${lp} is in use (a served cell, perhaps); the node listens on ${next} instead`);
85
+ listen = `127.0.0.1:${next}`;
86
+ }
74
87
  }
88
+ const rpc = `http://127.0.0.1:${port}`;
89
+ const nodeUrlPlanned = listen ? (() => {
90
+ const i = listen.lastIndexOf(":");
91
+ const host = listen.slice(0, i) || "127.0.0.1";
92
+ return `http://${host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host}:${listen.slice(i + 1)}`;
93
+ })() : null;
75
94
  if (walletPath === dir || walletPath.startsWith(dir + sep))
76
95
  throw new Error(`the wallet (${walletPath}) must live outside the quickstart directory (${dir}), which is cleared on every run`);
77
96
  if (existsSync(dir)) {
@@ -8,6 +8,8 @@ npx -y @finchip.ai/foga quickstart
8
8
 
9
9
  `npx -y @finchtech.ai/foga quickstart` is the same command: `@finchtech.ai/foga` is an alias package (`alias/finchtech.ai`) whose only content is a launcher for `@finchip.ai/foga` at the same version.
10
10
 
11
+ When its default ports are taken — 8787 by a served cell on the same machine (the reference cell's own box, a node of yours), 8545 by another chain — the quickstart takes the next free port up for each and says so; the URLs it prints are the ones it used. A port asked for by name (`--port`, `--listen`) is not moved: it is refused when busy, as before.
12
+
11
13
  Run it from any directory except a checkout of this repository itself: inside one, `npx` takes the checkout for the package already present (same name, same version) and looks for the `foga` command among its installed binaries, where a project's own binaries never are — `'foga' is not recognized` on Windows, `foga: not found` elsewhere. From a checkout the command is `node bin/foga.js quickstart` after `npm run build`.
12
14
 
13
15
  What it does, in order (about twenty-five seconds on a laptop): makes the default wallet — one key, the agent's identity, under `~/.foga/wallet` — when there is none, and reuses it when there is (docs/wallet.md: the wallet is the first step, and never a reason to stop; a disk that refuses the write gets keys made in memory for the run); starts `anvil` on port 8545; deploys the local world — the ten reference implementations and the FOGA contracts, 47 contracts (`worlds/local.json`); births a cell (`quick`) with the wallet's keys, funded by anvil's first account, which also registers the attested standing scheme and attests the cell's level-2 standing; mints the cell's two skills (`foga-probe`, `finch-extract-verify`) and offers them; builds the cell's documents and commits them on chain (the registration, the AID document, the ARD descriptor, the AUF unit; docs/documents.md); mints two tenders for the cell to find (a probe of the cell itself, an extraction over the fixture); serves the node — the watchers, the HTTP API, MCP over Streamable HTTP, A2A and the documents on `127.0.0.1:8787` — on the operator key alone, read from the wallet's file; checks that the entrances answer (health, a public read, the agent key's pre-check of the first tender, the MCP handshake and the 37-tool list over HTTP, the agent card naming `/a2a` and an A2A quote; the stdio server's handshake and its 44 tools with the operator key); and prints the summary below, with every path filled in. Then it waits: the chain lives as long as the process, and Ctrl-C ends both.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finchip.ai/foga",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/garyyang-finchip/foga.git"
package/server.json CHANGED
@@ -8,13 +8,13 @@
8
8
  "source": "github"
9
9
  },
10
10
  "websiteUrl": "https://foga.finchip.ai",
11
- "version": "0.6.1",
11
+ "version": "0.6.2",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "@finchip.ai/foga",
17
- "version": "0.6.1",
17
+ "version": "0.6.2",
18
18
  "runtimeHint": "npx",
19
19
  "transport": {
20
20
  "type": "stdio"