orbit-agent-runtime 0.8.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.
Files changed (168) hide show
  1. package/CHANGELOG.md +750 -0
  2. package/LICENSE +201 -0
  3. package/README.md +492 -0
  4. package/README.zh-CN.md +389 -0
  5. package/benchmarks/README.md +24 -0
  6. package/benchmarks/gateway.mjs +68 -0
  7. package/benchmarks/pae.mjs +90 -0
  8. package/benchmarks/replay.mjs +51 -0
  9. package/benchmarks/run-all.mjs +24 -0
  10. package/benchmarks/wal.mjs +50 -0
  11. package/bin/orbit.mjs +523 -0
  12. package/dist/.tsbuildinfo +1 -0
  13. package/dist/demo-deepseek.d.ts +2 -0
  14. package/dist/demo-deepseek.d.ts.map +1 -0
  15. package/dist/demo-deepseek.js +66 -0
  16. package/dist/demo-deepseek.js.map +1 -0
  17. package/dist/demo-host.d.ts +2 -0
  18. package/dist/demo-host.d.ts.map +1 -0
  19. package/dist/demo-host.js +98 -0
  20. package/dist/demo-host.js.map +1 -0
  21. package/dist/demo-replay.d.ts +2 -0
  22. package/dist/demo-replay.d.ts.map +1 -0
  23. package/dist/demo-replay.js +68 -0
  24. package/dist/demo-replay.js.map +1 -0
  25. package/dist/src/core/orbitRuntimeHost.d.ts +349 -0
  26. package/dist/src/core/orbitRuntimeHost.d.ts.map +1 -0
  27. package/dist/src/core/orbitRuntimeHost.js +706 -0
  28. package/dist/src/core/orbitRuntimeHost.js.map +1 -0
  29. package/dist/src/index.d.ts +92 -0
  30. package/dist/src/index.d.ts.map +1 -0
  31. package/dist/src/index.js +226 -0
  32. package/dist/src/index.js.map +1 -0
  33. package/dist/test/audit_chain.test.d.ts +2 -0
  34. package/dist/test/audit_chain.test.d.ts.map +1 -0
  35. package/dist/test/audit_chain.test.js +283 -0
  36. package/dist/test/audit_chain.test.js.map +1 -0
  37. package/dist/test/channel_hub.test.d.ts +2 -0
  38. package/dist/test/channel_hub.test.d.ts.map +1 -0
  39. package/dist/test/channel_hub.test.js +66 -0
  40. package/dist/test/channel_hub.test.js.map +1 -0
  41. package/dist/test/cordis_adapter.test.d.ts +2 -0
  42. package/dist/test/cordis_adapter.test.d.ts.map +1 -0
  43. package/dist/test/cordis_adapter.test.js +280 -0
  44. package/dist/test/cordis_adapter.test.js.map +1 -0
  45. package/dist/test/cost_routing.test.d.ts +2 -0
  46. package/dist/test/cost_routing.test.d.ts.map +1 -0
  47. package/dist/test/cost_routing.test.js +31 -0
  48. package/dist/test/cost_routing.test.js.map +1 -0
  49. package/dist/test/domain_transaction.test.d.ts +2 -0
  50. package/dist/test/domain_transaction.test.d.ts.map +1 -0
  51. package/dist/test/domain_transaction.test.js +351 -0
  52. package/dist/test/domain_transaction.test.js.map +1 -0
  53. package/dist/test/file_channel.test.d.ts +2 -0
  54. package/dist/test/file_channel.test.d.ts.map +1 -0
  55. package/dist/test/file_channel.test.js +179 -0
  56. package/dist/test/file_channel.test.js.map +1 -0
  57. package/dist/test/gateway.test.d.ts +2 -0
  58. package/dist/test/gateway.test.d.ts.map +1 -0
  59. package/dist/test/gateway.test.js +548 -0
  60. package/dist/test/gateway.test.js.map +1 -0
  61. package/dist/test/governance_profile.test.d.ts +2 -0
  62. package/dist/test/governance_profile.test.d.ts.map +1 -0
  63. package/dist/test/governance_profile.test.js +214 -0
  64. package/dist/test/governance_profile.test.js.map +1 -0
  65. package/dist/test/governance_schema.test.d.ts +2 -0
  66. package/dist/test/governance_schema.test.d.ts.map +1 -0
  67. package/dist/test/governance_schema.test.js +200 -0
  68. package/dist/test/governance_schema.test.js.map +1 -0
  69. package/dist/test/host_integration.test.d.ts +2 -0
  70. package/dist/test/host_integration.test.d.ts.map +1 -0
  71. package/dist/test/host_integration.test.js +104 -0
  72. package/dist/test/host_integration.test.js.map +1 -0
  73. package/dist/test/host_journal_persistence.test.d.ts +2 -0
  74. package/dist/test/host_journal_persistence.test.d.ts.map +1 -0
  75. package/dist/test/host_journal_persistence.test.js +367 -0
  76. package/dist/test/host_journal_persistence.test.js.map +1 -0
  77. package/dist/test/impact_domain.test.d.ts +2 -0
  78. package/dist/test/impact_domain.test.d.ts.map +1 -0
  79. package/dist/test/impact_domain.test.js +48 -0
  80. package/dist/test/impact_domain.test.js.map +1 -0
  81. package/dist/test/injected_clock.test.d.ts +13 -0
  82. package/dist/test/injected_clock.test.d.ts.map +1 -0
  83. package/dist/test/injected_clock.test.js +200 -0
  84. package/dist/test/injected_clock.test.js.map +1 -0
  85. package/dist/test/isolation_domain.test.d.ts +2 -0
  86. package/dist/test/isolation_domain.test.d.ts.map +1 -0
  87. package/dist/test/isolation_domain.test.js +302 -0
  88. package/dist/test/isolation_domain.test.js.map +1 -0
  89. package/dist/test/journal_wal.test.d.ts +2 -0
  90. package/dist/test/journal_wal.test.d.ts.map +1 -0
  91. package/dist/test/journal_wal.test.js +622 -0
  92. package/dist/test/journal_wal.test.js.map +1 -0
  93. package/dist/test/mcp_adapter.test.d.ts +2 -0
  94. package/dist/test/mcp_adapter.test.d.ts.map +1 -0
  95. package/dist/test/mcp_adapter.test.js +440 -0
  96. package/dist/test/mcp_adapter.test.js.map +1 -0
  97. package/dist/test/openai_compat_channel.test.d.ts +2 -0
  98. package/dist/test/openai_compat_channel.test.d.ts.map +1 -0
  99. package/dist/test/openai_compat_channel.test.js +325 -0
  100. package/dist/test/openai_compat_channel.test.js.map +1 -0
  101. package/dist/test/openapi_adapter.test.d.ts +2 -0
  102. package/dist/test/openapi_adapter.test.d.ts.map +1 -0
  103. package/dist/test/openapi_adapter.test.js +270 -0
  104. package/dist/test/openapi_adapter.test.js.map +1 -0
  105. package/dist/test/orbit_cli.test.d.ts +2 -0
  106. package/dist/test/orbit_cli.test.d.ts.map +1 -0
  107. package/dist/test/orbit_cli.test.js +137 -0
  108. package/dist/test/orbit_cli.test.js.map +1 -0
  109. package/dist/test/pact_verifier.test.d.ts +2 -0
  110. package/dist/test/pact_verifier.test.d.ts.map +1 -0
  111. package/dist/test/pact_verifier.test.js +41 -0
  112. package/dist/test/pact_verifier.test.js.map +1 -0
  113. package/dist/test/pae_adapter.test.d.ts +2 -0
  114. package/dist/test/pae_adapter.test.d.ts.map +1 -0
  115. package/dist/test/pae_adapter.test.js +469 -0
  116. package/dist/test/pae_adapter.test.js.map +1 -0
  117. package/dist/test/plugin_sandbox_guard.test.d.ts +2 -0
  118. package/dist/test/plugin_sandbox_guard.test.d.ts.map +1 -0
  119. package/dist/test/plugin_sandbox_guard.test.js +57 -0
  120. package/dist/test/plugin_sandbox_guard.test.js.map +1 -0
  121. package/dist/test/rate_limit_behavior.test.d.ts +2 -0
  122. package/dist/test/rate_limit_behavior.test.d.ts.map +1 -0
  123. package/dist/test/rate_limit_behavior.test.js +85 -0
  124. package/dist/test/rate_limit_behavior.test.js.map +1 -0
  125. package/dist/test/replay_compat.test.d.ts +2 -0
  126. package/dist/test/replay_compat.test.d.ts.map +1 -0
  127. package/dist/test/replay_compat.test.js +1122 -0
  128. package/dist/test/replay_compat.test.js.map +1 -0
  129. package/dist/test/replay_engine.test.d.ts +2 -0
  130. package/dist/test/replay_engine.test.d.ts.map +1 -0
  131. package/dist/test/replay_engine.test.js +85 -0
  132. package/dist/test/replay_engine.test.js.map +1 -0
  133. package/dist/test/shell_channel.test.d.ts +2 -0
  134. package/dist/test/shell_channel.test.d.ts.map +1 -0
  135. package/dist/test/shell_channel.test.js +173 -0
  136. package/dist/test/shell_channel.test.js.map +1 -0
  137. package/dist/test/teardown_isolation.test.d.ts +10 -0
  138. package/dist/test/teardown_isolation.test.d.ts.map +1 -0
  139. package/dist/test/teardown_isolation.test.js +279 -0
  140. package/dist/test/teardown_isolation.test.js.map +1 -0
  141. package/dist/test/token_budget.test.d.ts +2 -0
  142. package/dist/test/token_budget.test.d.ts.map +1 -0
  143. package/dist/test/token_budget.test.js +113 -0
  144. package/dist/test/token_budget.test.js.map +1 -0
  145. package/dist/test/trace_journal.test.d.ts +2 -0
  146. package/dist/test/trace_journal.test.d.ts.map +1 -0
  147. package/dist/test/trace_journal.test.js +43 -0
  148. package/dist/test/trace_journal.test.js.map +1 -0
  149. package/dist/test/trace_journal_persistence.test.d.ts +2 -0
  150. package/dist/test/trace_journal_persistence.test.d.ts.map +1 -0
  151. package/dist/test/trace_journal_persistence.test.js +175 -0
  152. package/dist/test/trace_journal_persistence.test.js.map +1 -0
  153. package/dist/test/trace_persistence.test.d.ts +2 -0
  154. package/dist/test/trace_persistence.test.d.ts.map +1 -0
  155. package/dist/test/trace_persistence.test.js +216 -0
  156. package/dist/test/trace_persistence.test.js.map +1 -0
  157. package/dist/test/trip_protector.test.d.ts +2 -0
  158. package/dist/test/trip_protector.test.d.ts.map +1 -0
  159. package/dist/test/trip_protector.test.js +42 -0
  160. package/dist/test/trip_protector.test.js.map +1 -0
  161. package/examples/README.md +34 -0
  162. package/examples/cli-record-replay.mjs +74 -0
  163. package/examples/custom-channel.mjs +102 -0
  164. package/examples/js-pae-plugin.mjs +128 -0
  165. package/examples/mcp-adapter.mjs +102 -0
  166. package/package.json +60 -0
  167. package/src/core/orbitRuntimeHost.ts +853 -0
  168. package/src/index.ts +256 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Example 1 — a custom deterministic channel.
3
+ *
4
+ * Shows how a plugin-extendable capability channel is implemented and wired
5
+ * into the host, then how the record → replay loop proves it byte-identical.
6
+ *
7
+ * The channel uppercases text ("shout"). It is trivially deterministic: no
8
+ * random, no clock, no I/O — so a recorded call replays to exactly the same
9
+ * output, and the digest-chain reconciliation reports no drift.
10
+ *
11
+ * Run: node examples/custom-channel.mjs
12
+ *
13
+ * For npm consumers the imports below become
14
+ * import { OrbitRuntimeHost, ChannelKind, ... } from "orbit-agent-runtime";
15
+ * The relative paths are only for running inside this repository.
16
+ */
17
+ import { OrbitRuntimeHost, ChannelKind } from "../dist/src/index.js";
18
+ import { makeUniqueMark, DeterminismLevel, RecordJournal, ReplayEngine } from "../dist/src/index.js";
19
+
20
+ class ShoutChannel {
21
+ determinismMeta = {
22
+ determinism: DeterminismLevel.DETERMINISTIC,
23
+ replayPolicy: "inject"
24
+ };
25
+
26
+ async setup() {}
27
+ async teardown() {}
28
+
29
+ /** Uppercase the input. The only surface of the channel. */
30
+ async shout(text) {
31
+ return String(text).toUpperCase();
32
+ }
33
+ }
34
+
35
+ async function main() {
36
+ console.log("=== example 1 · custom deterministic channel ===");
37
+
38
+ const host = new OrbitRuntimeHost();
39
+ await host.bootHost();
40
+ console.log("[boot] host started");
41
+
42
+ // Register the channel as a plugin-extension of a real ChannelKind. Channel
43
+ // kinds are the fixed capability vocabulary; plugins provide providers.
44
+ host.channelHub.registerPluginExtChannel(ChannelKind.LLM_ACCESS, new ShoutChannel());
45
+ console.log("[channel] ShoutChannel registered on LLM_ACCESS");
46
+
47
+ // Every plugin must declare the capabilities it may use (capability gate).
48
+ host.registerPlugin({
49
+ id: "example.shout",
50
+ displayName: "Shout Example",
51
+ edition: "1.0.0",
52
+ requireHostMinEdition: "1.0.0",
53
+ allowCapabilities: ["channel:read"]
54
+ });
55
+
56
+ const ctx = { traceMarkId: makeUniqueMark(), pluginUnitId: "example.shout", maxWaitMs: 5000 };
57
+ const call = (mode, text) =>
58
+ host.capabilityInvoke({
59
+ kind: ChannelKind.LLM_ACCESS,
60
+ pluginId: "example.shout",
61
+ funcName: "shout",
62
+ args: [text],
63
+ mode,
64
+ ctx
65
+ });
66
+
67
+ const out = await call("live", "hello orbit");
68
+ console.log(`[live] shout("hello orbit") -> "${out}"`);
69
+
70
+ // record mode: real channel calls, journaled verbatim through the gateway.
71
+ const recordJournal = host.beginRecording();
72
+ await call("record", "first");
73
+ await call("record", "second");
74
+ await call("record", "third");
75
+ console.log(`[record] journal holds ${recordJournal.snapshot().length} call(s)`);
76
+
77
+ // replay mode: attach the recorded journal as the injection source, then
78
+ // re-run the SAME sequence. The gateway injects frozen outputs (zero channel
79
+ // calls) and every call is signature-checked against the recorded chain —
80
+ // a mismatch is a ReplayDriftError, so "no error" IS the byte-identical proof.
81
+ host.attachReplayEngine(new ReplayEngine(recordJournal));
82
+ const r1 = await call("replay", "first");
83
+ const r2 = await call("replay", "second");
84
+ const r3 = await call("replay", "third");
85
+ console.log(`[replay] first/second/third -> "${r1}" / "${r2}" / "${r3}" (injected)`);
86
+
87
+ // Drift detection: changing the input of the next call must be rejected.
88
+ try {
89
+ await call("replay", "tampered");
90
+ console.error("FAIL: a drifted call was not rejected");
91
+ process.exit(1);
92
+ } catch (err) {
93
+ console.log(`[drift] tampered input rejected: ${err.constructor.name}`);
94
+ }
95
+
96
+ console.log("OK — custom channel records and replays byte-identically");
97
+ }
98
+
99
+ main().catch((err) => {
100
+ console.error(err);
101
+ process.exit(1);
102
+ });
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Example 2 — a JS plugin adapter (PAE, L0).
3
+ *
4
+ * External plain-JavaScript functions are mapped onto the kernel capability
5
+ * contract through a JsPaeAdapter and published as tools on the single PAE
6
+ * channel. Every call through the adapter is a gateway transaction: recorded,
7
+ * replayed byte-identically, and the adapter surface is hashed into the run
8
+ * fingerprint for drift detection.
9
+ *
10
+ * Run: node examples/js-pae-plugin.mjs
11
+ *
12
+ * The "plugin" here is an in-process function bundle (a foreign runtime in
13
+ * embryo). See examples/mcp-adapter.mjs for a true out-of-process peer.
14
+ */
15
+ import { OrbitRuntimeHost, ChannelKind } from "../dist/src/index.js";
16
+ import { JsPaeAdapter, SeededRng, DeterminismLevel } from "../dist/src/index.js";
17
+ import { makeUniqueMark } from "../dist/src/index.js";
18
+
19
+ /** The foreign tool bundle — deterministic by contract: no Math.random,
20
+ * no Date.now; randomness arrives via the injected SeededRng. */
21
+ function makeToolBundle() {
22
+ const rng = new SeededRng(42);
23
+ return {
24
+ rollDie: () => {
25
+ // Deterministic "die roll" for the given seed — replay reproduces it.
26
+ const value = 1 + Math.floor(rng.next() * 6);
27
+ return { face: value, seeded: true };
28
+ },
29
+ greet: (ctx, name) => `Hello, ${String(name)}!`,
30
+ add: (ctx, a, b) => Number(a) + Number(b)
31
+ };
32
+ }
33
+
34
+ async function main() {
35
+ console.log("=== example 2 · JS plugin adapter (PAE L0) ===");
36
+
37
+ const host = new OrbitRuntimeHost();
38
+ await host.bootHost();
39
+ console.log("[boot] host started");
40
+
41
+ const bundle = makeToolBundle();
42
+ const adapter = new JsPaeAdapter({
43
+ adapterId: "example.dice",
44
+ sourceEdition: "1.0.0",
45
+ isolation: "L0",
46
+ tools: [
47
+ {
48
+ name: "rollDie",
49
+ capability: "channel:read",
50
+ determinism: DeterminismLevel.DETERMINISTIC,
51
+ fidelity: "full",
52
+ description: "Roll a deterministic die (seeded)",
53
+ handler: () => bundle.rollDie()
54
+ },
55
+ {
56
+ name: "greet",
57
+ capability: "channel:read",
58
+ determinism: DeterminismLevel.DETERMINISTIC,
59
+ fidelity: "full",
60
+ description: "Greet someone",
61
+ handler: (_ctx, name) => bundle.greet(_ctx, name)
62
+ }
63
+ ]
64
+ });
65
+
66
+ const pact = host.registerPaeToolAdapter(adapter);
67
+ console.log(`[adapter] registered "${adapter.meta.adapterId}" -> pact "${pact.id}"`);
68
+ console.log(`[adapter] tools: ${adapter.describe().map((t) => t.name).join(", ")}`);
69
+
70
+ // The adapter surface is now a capability channel: foreign calls travel the
71
+ // same gateway → hub path as any native channel call.
72
+ const ctx = { traceMarkId: makeUniqueMark(), pluginUnitId: pact.id, maxWaitMs: 5000 };
73
+ const roll = await host.capabilityInvoke({
74
+ kind: ChannelKind.PAE_TOOL,
75
+ pluginId: pact.id,
76
+ funcName: "rollDie",
77
+ args: [],
78
+ mode: "live",
79
+ ctx
80
+ });
81
+ console.log(`[live] rollDie() -> ${JSON.stringify(roll)}`);
82
+
83
+ // Record the same call, then replay it: the frozen output is injected and
84
+ // the signature check guarantees the recorded run reproduces verbatim.
85
+ const recordJournal = host.beginRecording();
86
+ await host.capabilityInvoke({
87
+ kind: ChannelKind.PAE_TOOL,
88
+ pluginId: pact.id,
89
+ funcName: "rollDie",
90
+ args: [],
91
+ mode: "record",
92
+ ctx
93
+ });
94
+ const first = recordJournal.get(0).outputSnapshot;
95
+ console.log(`[record] rollDie() journaled output -> ${JSON.stringify(first)}`);
96
+
97
+ host.attachReplayEngine(
98
+ new (await import("../dist/src/index.js")).ReplayEngine(recordJournal)
99
+ );
100
+ const replayed = await host.capabilityInvoke({
101
+ kind: ChannelKind.PAE_TOOL,
102
+ pluginId: pact.id,
103
+ funcName: "rollDie",
104
+ args: [],
105
+ mode: "replay",
106
+ ctx
107
+ });
108
+ console.log(`[replay] rollDie() injected output -> ${JSON.stringify(replayed)}`);
109
+ if (JSON.stringify(replayed) !== JSON.stringify(first)) {
110
+ console.error("FAIL: replayed output differs from the recorded one");
111
+ process.exit(1);
112
+ }
113
+
114
+ // Drift surface: registering a different tool bundle changes the surface
115
+ // hash, so a trace recorded under the old bundle no longer replays cleanly.
116
+ console.log("[drift] adapter surface is part of the run fingerprint");
117
+ const fp = host.runFingerprint();
118
+ console.log(`[drift] paeAdaptersHash = ${fp.paeAdaptersHash ? "present" : "absent"}`);
119
+
120
+ await host.shutdownHost();
121
+ console.log("[shutdown] clean teardown");
122
+ console.log("OK — foreign JS tools are governed, recorded and replayed verbatim");
123
+ }
124
+
125
+ main().catch((err) => {
126
+ console.error(err);
127
+ process.exit(1);
128
+ });
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Example 3 — an MCP adapter (PAE, L2, out-of-process).
3
+ *
4
+ * A real MCP server child process is spawned over stdio, passed through the
5
+ * `initialize` handshake and `tools/list` discovery, and only then registered —
6
+ * the console never advertises a tool the peer did not announce. Every call is
7
+ * an IO_BOUND gateway transaction: recorded and replayed byte-identically even
8
+ * after the peer is gone (replay injects the frozen output and never re-enters
9
+ * the child).
10
+ *
11
+ * The peer is a tiny MCP server bundled with the repo:
12
+ * web/test/fixtures/mcp-stdio-server.mjs (tools: greet, total)
13
+ *
14
+ * Run: node examples/mcp-adapter.mjs
15
+ */
16
+ import { fileURLToPath } from "node:url";
17
+ import { OrbitRuntimeHost, ChannelKind } from "../dist/src/index.js";
18
+ import { McpPaeAdapter, StdioMcpTransport, ReplayEngine } from "../dist/src/index.js";
19
+ import { makeUniqueMark } from "../dist/src/index.js";
20
+
21
+ const PEER = fileURLToPath(new URL("../web/test/fixtures/mcp-stdio-server.mjs", import.meta.url));
22
+
23
+ async function main() {
24
+ console.log("=== example 3 · MCP adapter (PAE L2) ===");
25
+ console.log(`[peer] spawning ${PEER}`);
26
+
27
+ const host = new OrbitRuntimeHost();
28
+ await host.bootHost();
29
+
30
+ const transport = new StdioMcpTransport({ command: process.execPath, args: [PEER] });
31
+ const adapter = new McpPaeAdapter({
32
+ adapterId: "example.mcp",
33
+ sourceEdition: "0.1.0",
34
+ transport
35
+ });
36
+
37
+ // connect = handshake first, then register the *discovered* surface.
38
+ const pact = await host.connectPaeToolAdapter(adapter, { maxWaitMs: 10_000 });
39
+ const tools = adapter.describe().map((t) => t.name);
40
+ console.log(`[adapter] connected; discovered tools: ${tools.join(", ")}`);
41
+ if (!tools.includes("greet") || !tools.includes("total")) {
42
+ console.error("FAIL: expected tools greet + total from the peer");
43
+ process.exit(1);
44
+ }
45
+
46
+ const ctx = { traceMarkId: makeUniqueMark(), pluginUnitId: pact.id, maxWaitMs: 10_000 };
47
+
48
+ // Live call: real child process, real JSON-RPC round trip.
49
+ const live = await host.capabilityInvoke({
50
+ kind: ChannelKind.PAE_TOOL,
51
+ pluginId: pact.id,
52
+ funcName: "greet",
53
+ args: [{ name: "Orbit" }],
54
+ mode: "live",
55
+ ctx
56
+ });
57
+ console.log(`[live] greet({name:"Orbit"}) -> ${JSON.stringify(live)}`);
58
+
59
+ // Record a call, then kill the peer: replay must still reproduce verbatim,
60
+ // because the frozen output is injected — the child is never re-entered.
61
+ const recordJournal = host.beginRecording();
62
+ await host.capabilityInvoke({
63
+ kind: ChannelKind.PAE_TOOL,
64
+ pluginId: pact.id,
65
+ funcName: "total",
66
+ args: [{ values: [1, 2, 3] }],
67
+ mode: "record",
68
+ ctx
69
+ });
70
+ const recorded = recordJournal.get(0).outputSnapshot;
71
+ console.log(`[record] total([1,2,3]) journaled -> ${JSON.stringify(recorded)}`);
72
+
73
+ // Kill the peer process but keep the registration: the surface stays part of
74
+ // the fingerprint, so the trace still replays — with the frozen output
75
+ // injected, the dead child is never re-entered.
76
+ await adapter.teardown();
77
+ console.log("[peer] child process closed; adapter surface retained");
78
+
79
+ host.attachReplayEngine(new ReplayEngine(recordJournal));
80
+ const replayed = await host.capabilityInvoke({
81
+ kind: ChannelKind.PAE_TOOL,
82
+ pluginId: pact.id,
83
+ funcName: "total",
84
+ args: [{ values: [1, 2, 3] }],
85
+ mode: "replay",
86
+ ctx
87
+ });
88
+ console.log(`[replay] total([1,2,3]) injected -> ${JSON.stringify(replayed)}`);
89
+ if (JSON.stringify(replayed) !== JSON.stringify(recorded)) {
90
+ console.error("FAIL: replay after peer death differs from the recording");
91
+ process.exit(1);
92
+ }
93
+
94
+ await host.shutdownHost();
95
+ console.log("[shutdown] clean teardown");
96
+ console.log("OK — MCP tools are governed, recorded and replayable after peer death");
97
+ }
98
+
99
+ main().catch((err) => {
100
+ console.error(err);
101
+ process.exit(1);
102
+ });
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "orbit-agent-runtime",
3
+ "version": "0.8.0",
4
+ "description": "Deterministic · Provable · Governable — a plugin-based agent runtime kernel with hot plugin registration, provable fault isolation, full-chain traceability and sandboxed execution.",
5
+ "keywords": [
6
+ "agent",
7
+ "runtime",
8
+ "plugin",
9
+ "sandbox",
10
+ "circuit-breaker",
11
+ "traceability",
12
+ "deterministic-replay"
13
+ ],
14
+ "license": "Apache-2.0",
15
+ "main": "dist/src/index.js",
16
+ "types": "dist/src/index.d.ts",
17
+ "bin": {
18
+ "orbit": "bin/orbit.mjs"
19
+ },
20
+ "files": [
21
+ "bin",
22
+ "dist",
23
+ "src",
24
+ "examples",
25
+ "benchmarks",
26
+ "README.md",
27
+ "README.zh-CN.md",
28
+ "LICENSE",
29
+ "CHANGELOG.md"
30
+ ],
31
+ "workspaces": [
32
+ "packages/*",
33
+ "web"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc -b tsconfig.json",
37
+ "build:packages": "tsc -b packages/infra-common packages/core-hub packages/sandbox-runtime packages/pae-engine",
38
+ "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && node -e \"for (const p of ['infra-common','core-hub','sandbox-runtime','pae-engine']) fs.rmSync('packages/'+p+'/dist',{recursive:true,force:true})\"",
39
+ "test": "npm run build && node --test \"dist/test/*.test.js\"",
40
+ "test:console": "node --test web/test/*.test.mjs",
41
+ "start:web": "node web/bridge-server.mjs",
42
+ "test:web": "node --test web/test/*.test.mjs",
43
+ "demo": "npm run build && node dist/demo-host.js",
44
+ "demo:replay": "npm run build && node dist/demo-replay.js",
45
+ "demo:deepseek": "npm run build && node dist/demo-deepseek.js",
46
+ "example:channel": "npm run build && node examples/custom-channel.mjs",
47
+ "example:pae": "npm run build && node examples/js-pae-plugin.mjs",
48
+ "example:mcp": "npm run build && node examples/mcp-adapter.mjs",
49
+ "example:cli": "npm run build && node examples/cli-record-replay.mjs",
50
+ "benchmark": "npm run build && node benchmarks/run-all.mjs",
51
+ "prepublishOnly": "npm run clean && npm run build && npm test && npm run test:console"
52
+ },
53
+ "engines": {
54
+ "node": ">=20"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^26.4.0",
58
+ "typescript": "^5.9.3"
59
+ }
60
+ }