@finchip.ai/foga 0.0.0-stage → 0.6.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +21 -0
- package/README.md +216 -2
- package/artifacts/bundle.json +74250 -0
- package/artifacts/bundle.sha256 +1 -0
- package/bin/foga.js +14 -0
- package/build/known-interface-ids.json +18 -0
- package/build/profiles.json +120 -0
- package/dist/build/bundle.js +417 -0
- package/dist/build/vendor.js +74 -0
- package/dist/bundle/load.js +24 -0
- package/dist/bundle/types.js +1 -0
- package/dist/cli-cell.js +395 -0
- package/dist/cli.js +505 -0
- package/dist/core/acdf.js +162 -0
- package/dist/core/adrf.js +273 -0
- package/dist/core/aid.js +83 -0
- package/dist/core/ard.js +146 -0
- package/dist/core/asf.js +157 -0
- package/dist/core/canonical.js +79 -0
- package/dist/core/erc8004.js +52 -0
- package/dist/core/kya.js +225 -0
- package/dist/core/measure.js +96 -0
- package/dist/core/pack/cbor.js +130 -0
- package/dist/core/pack/skillpack.js +142 -0
- package/dist/core/skills.js +40 -0
- package/dist/core/swarm.js +206 -0
- package/dist/core/tenders.js +121 -0
- package/dist/core/units.js +122 -0
- package/dist/core/world.js +104 -0
- package/dist/demo/demander.js +76 -0
- package/dist/demo/evidence.js +1 -0
- package/dist/demo/loop-d.js +449 -0
- package/dist/doctor/checks.js +51 -0
- package/dist/doctor/doctor.js +385 -0
- package/dist/doctor/loop-d.js +103 -0
- package/dist/doctor/probe.js +97 -0
- package/dist/doctor/semantic.js +83 -0
- package/dist/genesis/extract.js +64 -0
- package/dist/genesis/funding.js +126 -0
- package/dist/genesis/operator-scope.js +90 -0
- package/dist/genesis/preflight.js +54 -0
- package/dist/genesis/probe.js +164 -0
- package/dist/genesis/roles.js +96 -0
- package/dist/genesis/run.js +71 -0
- package/dist/genesis/scenario.js +765 -0
- package/dist/genesis/skill-runner.js +103 -0
- package/dist/genesis/skill-worker.js +41 -0
- package/dist/genesis/t1-zk.js +62 -0
- package/dist/genesis/t3-zk.js +105 -0
- package/dist/genesis/t4.js +259 -0
- package/dist/genesis/t5.js +168 -0
- package/dist/genesis/t6.js +222 -0
- package/dist/genesis/t7.js +198 -0
- package/dist/genesis/t8.js +189 -0
- package/dist/genesis/t9.js +188 -0
- package/dist/genesis/zk.js +128 -0
- package/dist/http/server.js +276 -0
- package/dist/kernel/cell.js +104 -0
- package/dist/kernel/errors.js +78 -0
- package/dist/kernel/kernel.js +251 -0
- package/dist/kernel/provider.js +125 -0
- package/dist/kernel/store.js +470 -0
- package/dist/kernel/tx.js +385 -0
- package/dist/mcp/server.js +170 -0
- package/dist/node/config.js +195 -0
- package/dist/node/init.js +200 -0
- package/dist/node/keys.js +95 -0
- package/dist/node/migrate.js +173 -0
- package/dist/node/model/anthropic.js +97 -0
- package/dist/node/model/stub.js +129 -0
- package/dist/node/model/types.js +9 -0
- package/dist/node/node.js +198 -0
- package/dist/node/policy.js +95 -0
- package/dist/node/runner.js +256 -0
- package/dist/node/watchers.js +88 -0
- package/dist/tools/admin.js +184 -0
- package/dist/tools/catalog.js +261 -0
- package/dist/tools/common.js +143 -0
- package/dist/tools/identity.js +107 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/read.js +471 -0
- package/dist/tools/tenders.js +400 -0
- package/dist/tools/types.js +4 -0
- package/dist/util/bytecode.js +123 -0
- package/dist/util/fs.js +58 -0
- package/dist/util/hash.js +4 -0
- package/dist/util/log.js +11 -0
- package/dist/util/version.js +12 -0
- package/dist/world/deploy.js +277 -0
- package/dist/world/plan.js +93 -0
- package/dist/world/types.js +1 -0
- package/docs/build.md +45 -0
- package/docs/cell-account.md +58 -0
- package/docs/compatibility-matrix.md +38 -0
- package/docs/design-memo.md +113 -0
- package/docs/doctor.md +53 -0
- package/docs/examples/README.md +11 -0
- package/docs/examples/claude-code-mcp.json +13 -0
- package/docs/examples/claude_desktop_config.json +12 -0
- package/docs/examples/cursor-mcp.json +11 -0
- package/docs/genesis.md +312 -0
- package/docs/kernel.md +101 -0
- package/docs/loop-d.md +90 -0
- package/docs/mcp.md +105 -0
- package/docs/node.md +66 -0
- package/docs/version-lock.md +67 -0
- package/docs/world.md +50 -0
- package/docs/zk.md +48 -0
- package/package.json +82 -4
- package/prover/README.md +26 -0
- package/prover/build-predicate.mjs +77 -0
- package/prover/package-lock.json +1837 -0
- package/prover/package.json +15 -0
- package/prover/run.cjs +199 -0
- package/scenarios/fixtures/sample-filing.txt +16 -0
- package/scenarios/skills/finch-extract-verify/LICENSE +2 -0
- package/scenarios/skills/finch-extract-verify/SKILL.md +34 -0
- package/scenarios/skills/finch-extract-verify/fields.json +56 -0
- package/scenarios/skills/finch-extract-verify/manifest.json +16 -0
- package/scenarios/skills/foga-probe/LICENSE +2 -0
- package/scenarios/skills/foga-probe/SKILL.md +35 -0
- package/scenarios/skills/foga-probe/manifest.json +16 -0
- package/scenarios/skills/foga-probe/probe.schema.json +40 -0
- package/server.json +79 -0
- package/vendor/LOCK.json +107 -0
- package/vendor/README.md +13 -0
- package/worlds/local.json +34 -0
- package/worlds/sepolia.json +314 -0
- package/zk/build/verification_key.json +174 -0
- package/zk/circuits/kya_predicate_count_v1.circom +231 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { HDNodeWallet, Mnemonic, Wallet, randomBytes } from "ethers";
|
|
3
|
+
/**
|
|
4
|
+
* The accounts of the genesis scenario (design memo, section 3.1). Keys are signer names in the kernel.
|
|
5
|
+
*
|
|
6
|
+
* W world operator: deploys / attaches the world, registers schemes and specifications, issues
|
|
7
|
+
* the attested standing assertions, funds the other roles and the cells
|
|
8
|
+
* G guardian: the intervener named in every cell's safety binding
|
|
9
|
+
* owner.<X> cold principal of cell X (deploys the account, administers it)
|
|
10
|
+
* operator.<X> hot signer of cell X (acts through the account's execute)
|
|
11
|
+
* E evaluator (ERC-8454 measurement receipts, Phase 2b)
|
|
12
|
+
* J1..J3 judges of the FOGA-Council policy (Phase 2a-2)
|
|
13
|
+
*
|
|
14
|
+
* Every key is derived from one BIP-39 phrase at the standard Ethereum path, role i at m/44'/60'/0'/0/i in the
|
|
15
|
+
* order below. On anvil the phrase is anvil's well-known one, so every local run uses the same addresses. On any
|
|
16
|
+
* other chain the phrase comes from FOGA_MNEMONIC (the words) or FOGA_MNEMONIC_FILE (a file holding them), and
|
|
17
|
+
* FOGA_KEY_<ROLE> ("." as "_", upper case) overrides the key of one role — W = the key that already holds the
|
|
18
|
+
* chain's gas token, for instance. `foga keys new` writes a fresh phrase; `foga keys show` lists the addresses.
|
|
19
|
+
*/
|
|
20
|
+
export const CELLS = ["A", "B", "C"];
|
|
21
|
+
export const ROLE_ORDER = ["W", "G", "owner.A", "owner.B", "owner.C", "operator.A", "operator.B", "operator.C", "E", "J1", "J2", "J3"];
|
|
22
|
+
export const ANVIL_MNEMONIC = "test test test test test test test test test test test junk";
|
|
23
|
+
/** Roles that must be funded by W on a local chain because anvil only pre-funds its first ten accounts. */
|
|
24
|
+
export const DERIVED_BEYOND_ANVIL_DEFAULTS = ["J1", "J2", "J3"];
|
|
25
|
+
export function rolePath(index) {
|
|
26
|
+
return `m/44'/60'/0'/0/${index}`;
|
|
27
|
+
}
|
|
28
|
+
export function envNameOf(role) {
|
|
29
|
+
return `FOGA_KEY_${role.replace(".", "_").toUpperCase()}`;
|
|
30
|
+
}
|
|
31
|
+
/** Every role's key from one phrase, role i at the i-th standard Ethereum path. */
|
|
32
|
+
export function mnemonicKeys(phrase) {
|
|
33
|
+
const m = Mnemonic.fromPhrase(phrase.trim().split(/\s+/).join(" "));
|
|
34
|
+
const out = {};
|
|
35
|
+
ROLE_ORDER.forEach((role, i) => {
|
|
36
|
+
out[role] = HDNodeWallet.fromMnemonic(m, rolePath(i)).privateKey;
|
|
37
|
+
});
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
export function anvilKeys() {
|
|
41
|
+
return mnemonicKeys(ANVIL_MNEMONIC);
|
|
42
|
+
}
|
|
43
|
+
/** A new 12-word phrase from 128 bits of the platform's randomness. */
|
|
44
|
+
export function newMnemonic() {
|
|
45
|
+
return Mnemonic.fromEntropy(randomBytes(16)).phrase;
|
|
46
|
+
}
|
|
47
|
+
/** The phrase the environment names, if any: FOGA_MNEMONIC (the words) or FOGA_MNEMONIC_FILE (a file holding them). */
|
|
48
|
+
export function envMnemonic() {
|
|
49
|
+
const inline = process.env.FOGA_MNEMONIC?.trim();
|
|
50
|
+
if (inline)
|
|
51
|
+
return inline;
|
|
52
|
+
const file = process.env.FOGA_MNEMONIC_FILE;
|
|
53
|
+
if (file)
|
|
54
|
+
return readFileSync(file, "utf8").trim();
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The keys of a non-anvil chain: the phrase's derivation, each role overridable by FOGA_KEY_<ROLE>. Without a
|
|
59
|
+
* phrase every required role needs its own variable.
|
|
60
|
+
*/
|
|
61
|
+
export function envKeys(required) {
|
|
62
|
+
const phrase = envMnemonic();
|
|
63
|
+
const derived = phrase ? mnemonicKeys(phrase) : null;
|
|
64
|
+
const out = {};
|
|
65
|
+
const missing = [];
|
|
66
|
+
for (const role of required) {
|
|
67
|
+
const override = process.env[envNameOf(role)];
|
|
68
|
+
if (override)
|
|
69
|
+
out[role] = override;
|
|
70
|
+
else if (derived)
|
|
71
|
+
out[role] = derived[role];
|
|
72
|
+
else
|
|
73
|
+
missing.push(envNameOf(role));
|
|
74
|
+
}
|
|
75
|
+
if (missing.length)
|
|
76
|
+
throw new Error(`missing keys for this world: set FOGA_MNEMONIC (or FOGA_MNEMONIC_FILE) for all roles, or ${missing.join(", ")}`);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/** The keys a genesis run needs for a world: anvil's derived set, or the environment on other chains. */
|
|
80
|
+
export function roleKeys(world, required = ROLE_ORDER) {
|
|
81
|
+
if (world.network === "anvil") {
|
|
82
|
+
const all = anvilKeys();
|
|
83
|
+
return Object.fromEntries(required.map((r) => [r, all[r]]));
|
|
84
|
+
}
|
|
85
|
+
return envKeys(required);
|
|
86
|
+
}
|
|
87
|
+
/** The address of every role for a key set. */
|
|
88
|
+
export function roleAddresses(keys) {
|
|
89
|
+
return Object.fromEntries(Object.entries(keys).map(([role, pk]) => [role, new Wallet(pk).address]));
|
|
90
|
+
}
|
|
91
|
+
export function ownerRole(cell) {
|
|
92
|
+
return `owner.${cell}`;
|
|
93
|
+
}
|
|
94
|
+
export function operatorRole(cell) {
|
|
95
|
+
return `operator.${cell}`;
|
|
96
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
2
|
+
import { readJson, repoRoot, writeJson } from "../util/fs.js";
|
|
3
|
+
import { log } from "../util/log.js";
|
|
4
|
+
import { Genesis, STEPS } from "./scenario.js";
|
|
5
|
+
/** `foga genesis run`: open the kernel on a deployed world, run T0..until, write the evidence file. */
|
|
6
|
+
export async function runGenesis(opts) {
|
|
7
|
+
const root = repoRoot();
|
|
8
|
+
const worldPath = resolve(opts.worldPath);
|
|
9
|
+
const world = readJson(worldPath);
|
|
10
|
+
if (world.schema !== "foga.world/1")
|
|
11
|
+
throw new Error(`${worldPath} is not a deployed world file (run foga world deploy first)`);
|
|
12
|
+
const name = basename(worldPath).replace(/\.json$/, "");
|
|
13
|
+
const rpc = opts.rpc ?? process.env.FOGA_RPC_URL ?? (world.network === "anvil" ? "http://127.0.0.1:8545" : undefined);
|
|
14
|
+
if (!rpc)
|
|
15
|
+
throw new Error("no RPC: pass --rpc or set FOGA_RPC_URL");
|
|
16
|
+
const storePath = resolve(opts.storePath ?? join(root, "deployments", `${name}.genesis.sqlite`));
|
|
17
|
+
const evidencePath = resolve(opts.evidencePath ?? join(root, "deployments", `${name}.genesis.json`));
|
|
18
|
+
const skillsDir = resolve(opts.skillsDir ?? join(root, "scenarios", "skills"));
|
|
19
|
+
const fixturesDir = resolve(opts.fixturesDir ?? join(root, "scenarios", "fixtures"));
|
|
20
|
+
const until = opts.until ?? "T9";
|
|
21
|
+
if (!STEPS.includes(until))
|
|
22
|
+
throw new Error(`--until must be one of ${STEPS.join(", ")}`);
|
|
23
|
+
const say = opts.quiet ? () => { } : (line) => log.step(line);
|
|
24
|
+
const g = await Genesis.open({ worldPath, rpc, bundlePath: opts.bundlePath, storePath, skillsDir, fixturesDir, zk: opts.zk ?? "auto", crashBeforeBroadcast: opts.crashBeforeBroadcast, crashAfterBroadcast: opts.crashAfterBroadcast, log: say });
|
|
25
|
+
log.info(`genesis on world ${world.worldId} (chain ${world.chainId}) via ${rpc}; store ${storePath}`);
|
|
26
|
+
const before = g.kernel.store.summary();
|
|
27
|
+
if (before.ops.confirmed + before.ops.sent + before.ops.failed > 0)
|
|
28
|
+
log.info(`resuming: store holds ${before.ops.confirmed} confirmed, ${before.ops.sent} sent, ${before.ops.failed} failed operations`);
|
|
29
|
+
const startSeq = g.kernel.store.journalEntries().at(-1)?.seq ?? 0;
|
|
30
|
+
let runError = null;
|
|
31
|
+
try {
|
|
32
|
+
await g.run(until);
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
runError = e;
|
|
36
|
+
}
|
|
37
|
+
const journal = g.kernel.store.journalEntries();
|
|
38
|
+
const thisRun = journal.filter((j) => j.seq > startSeq);
|
|
39
|
+
const ops = g.kernel.store.summary().ops;
|
|
40
|
+
const failed = g.checks.filter((c) => !c.pass).length;
|
|
41
|
+
const evidence = {
|
|
42
|
+
schema: "foga.genesis-evidence/1",
|
|
43
|
+
worldId: world.worldId,
|
|
44
|
+
chainId: world.chainId,
|
|
45
|
+
world: relative(root, worldPath),
|
|
46
|
+
store: relative(root, storePath),
|
|
47
|
+
ranAt: new Date().toISOString(),
|
|
48
|
+
until,
|
|
49
|
+
checks: g.checks,
|
|
50
|
+
summary: {
|
|
51
|
+
checks: g.checks.length,
|
|
52
|
+
passed: g.checks.length - failed,
|
|
53
|
+
failed,
|
|
54
|
+
operations: ops,
|
|
55
|
+
sent: thisRun.filter((j) => j.event === "sent").length,
|
|
56
|
+
replayed: thisRun.filter((j) => j.event === "replayed").length,
|
|
57
|
+
recovered: thisRun.filter((j) => j.event === "recovered-receipt" || j.event === "recovered-pending").length,
|
|
58
|
+
resent: thisRun.filter((j) => j.event === "resend").length,
|
|
59
|
+
replaced: thisRun.filter((j) => j.event === "replaced").length,
|
|
60
|
+
},
|
|
61
|
+
facts: g.kernel.store.facts(),
|
|
62
|
+
evidence: g.kernel.evidenceRecords(),
|
|
63
|
+
journal,
|
|
64
|
+
};
|
|
65
|
+
writeJson(evidencePath, evidence);
|
|
66
|
+
g.close();
|
|
67
|
+
if (runError)
|
|
68
|
+
throw runError;
|
|
69
|
+
log.info(`genesis ${until}: ${evidence.summary.passed}/${evidence.summary.checks} checks passed; ${ops.confirmed} operations confirmed in the store; this run: ${evidence.summary.sent} sent, ${evidence.summary.replayed} replayed, ${evidence.summary.recovered} recovered, ${evidence.summary.resent} re-sent, ${evidence.summary.replaced} fee-replaced -> ${evidencePath}`);
|
|
70
|
+
return { evidence, failed };
|
|
71
|
+
}
|