agenttwin 0.3.4 → 0.3.6

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 (51) hide show
  1. package/README.md +8 -0
  2. package/dist/api.js +96 -56
  3. package/dist/cli.js +210 -180
  4. package/dist/dashboard/assets/dashboard/agent-home.css +33 -10
  5. package/dist/dashboard/assets/dashboard/bay-morning.png +0 -0
  6. package/dist/dashboard/assets/dashboard/golden-gate-afternoon.png +0 -0
  7. package/dist/dashboard/assets/dashboard/inventory.json +1 -1
  8. package/dist/dashboard/assets/dashboard/runs.json +1 -1
  9. package/dist/dashboard/assets/next/static/HZwGKKvvx_oO6caYggjFh/_buildManifest.js +1 -0
  10. package/dist/dashboard/assets/next/static/HZwGKKvvx_oO6caYggjFh/_ssgManifest.js +1 -0
  11. package/dist/dashboard/assets/next/static/chunks/255-09fb0d129bb12f51.js +1 -0
  12. package/dist/dashboard/assets/next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  13. package/dist/dashboard/assets/next/static/chunks/772-85561381eedc95da.js +67 -0
  14. package/dist/dashboard/assets/next/static/chunks/app/_not-found/page-5dc6a60918e8652d.js +1 -0
  15. package/dist/dashboard/assets/next/static/chunks/app/dashboard/layout-74603c2c8eaf0760.js +1 -0
  16. package/dist/dashboard/assets/next/static/chunks/app/dashboard/page-b79ed135f6bac5f7.js +1 -0
  17. package/dist/dashboard/assets/next/static/chunks/app/demo/page-760a47a5e4dee43f.js +1 -0
  18. package/dist/dashboard/assets/next/static/chunks/app/docs/[[...slug]]/page-80a0c2c82d5b4efd.js +1 -0
  19. package/dist/dashboard/assets/next/static/chunks/app/layout-1a40c59e535513d4.js +1 -0
  20. package/dist/dashboard/assets/next/static/chunks/app/page-de4735052adab906.js +1 -0
  21. package/dist/dashboard/assets/next/static/chunks/app/pricing/page-7703fc31d6dff0f7.js +1 -0
  22. package/dist/dashboard/assets/next/static/chunks/app/sitemap.xml/route-ef5a216a578eb7a8.js +1 -0
  23. package/dist/dashboard/assets/next/static/chunks/framework-292291387d6b2e39.js +1 -0
  24. package/dist/dashboard/assets/next/static/chunks/main-aea6e71289384293.js +1 -0
  25. package/dist/dashboard/assets/next/static/chunks/main-app-99295a8cc37e8a47.js +1 -0
  26. package/dist/dashboard/assets/next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  27. package/dist/dashboard/assets/next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  28. package/dist/dashboard/assets/next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  29. package/dist/dashboard/assets/next/static/chunks/webpack-f3b6dd27998e84ce.js +1 -0
  30. package/dist/dashboard/assets/next/static/css/1323d7da89b3fa5e.css +1 -0
  31. package/dist/dashboard/assets/next/static/css/45513ebc8c6ae800.css +1 -0
  32. package/dist/dashboard/assets/next/static/css/61ec74d503f353d4.css +1 -0
  33. package/dist/dashboard/assets/next/static/css/9282330a2fd1ab73.css +1 -0
  34. package/dist/dashboard/assets/next/static/css/96e4f356a1159071.css +1 -0
  35. package/dist/dashboard/assets/next/static/css/c5ac36ef5726e746.css +1 -0
  36. package/dist/dashboard/assets/next/static/media/bay-morning.1a9f358c.png +0 -0
  37. package/dist/dashboard/assets/next/static/media/golden-gate-afternoon.3e7cea58.png +0 -0
  38. package/dist/dashboard/assets/next/static/media/inter-var.e4af272c.woff2 +0 -0
  39. package/dist/dashboard/assets/next/static/media/moonlit-coast.bbe901a1.png +0 -0
  40. package/dist/dashboard/assets/next/static/media/plexmono-400.d3ebbfd6.woff2 +0 -0
  41. package/dist/dashboard/index.html +1 -140
  42. package/dist/gateway.js +96 -56
  43. package/package.json +1 -1
  44. package/dist/dashboard/assets/dashboard/agent-home.js +0 -298
  45. package/dist/dashboard/assets/dashboard/dashboard.js +0 -462
  46. package/dist/dashboard/assets/dashboard/hosted.js +0 -89
  47. package/dist/dashboard/assets/dashboard/workflows.js +0 -39
  48. package/dist/dashboard/assets/vendor/dompurify.LICENSE +0 -202
  49. package/dist/dashboard/assets/vendor/marked.LICENSE +0 -44
  50. package/dist/dashboard/assets/vendor/marked.js +0 -82
  51. package/dist/dashboard/assets/vendor/purify.min.js +0 -7
package/README.md CHANGED
@@ -15,6 +15,14 @@ npx agenttwin example --out ./agenttwin-example
15
15
 
16
16
  `init` writes the inventory, workflow candidates, `agenttwin.config.json`, `ENVIRONMENT.md`, `REPLICATION.md`, and an offline browser report. Discovery is evidence, not an automatically executable environment. It never uploads source. `init --json --dry-run` writes nothing.
17
17
 
18
+ Installed packages and source references are clues, not proof that an integration is active. Credentials, environment keys and deployment configuration are kept separately. Unmatched `.env` entries do not require setup and are never turned into services by an interactive prompt.
19
+
20
+ Exclude unused integrations by name; your choices are remembered for this repository:
21
+
22
+ ```sh
23
+ npx agenttwin init --exclude "Ollama,ClickHouse,AWS,Google Cloud"
24
+ ```
25
+
18
26
  ## Test through the CLI
19
27
 
20
28
  ```sh
package/dist/api.js CHANGED
@@ -782,11 +782,50 @@ var init_catalog = __esm({
782
782
  }
783
783
  });
784
784
 
785
+ // src/inventory/store.ts
786
+ import { mkdir, readFile as readFile5, writeFile } from "fs/promises";
787
+ import { join as join5 } from "path";
788
+ function storeDir(cwd) {
789
+ return join5(cwd, STORE_DIR);
790
+ }
791
+ function storePath(cwd, name) {
792
+ return join5(storeDir(cwd), name);
793
+ }
794
+ async function readJson(path) {
795
+ try {
796
+ return JSON.parse(await readFile5(path, "utf8"));
797
+ } catch {
798
+ return void 0;
799
+ }
800
+ }
801
+ var STORE_DIR, STORE_GITIGNORE, readDecisions;
802
+ var init_store = __esm({
803
+ "src/inventory/store.ts"() {
804
+ "use strict";
805
+ STORE_DIR = ".agenttwin";
806
+ STORE_GITIGNORE = [
807
+ "inventory.json",
808
+ "plan.json",
809
+ "permissions.local.json",
810
+ "report.html",
811
+ "demo/",
812
+ "trial/",
813
+ "feedback.json",
814
+ "cache/",
815
+ "logs/",
816
+ "connections/",
817
+ ""
818
+ ].join("\n");
819
+ readDecisions = (cwd) => readJson(storePath(cwd, "decisions.json"));
820
+ }
821
+ });
822
+
785
823
  // src/inventory/project-products.ts
786
824
  async function projectProducts(cwd, data, base) {
787
825
  const current = new Set(base.tools.map((t) => t.id));
788
826
  const known = new Set(PROVIDERS.map((p) => p.title));
789
- const tools = data.tools.filter((t) => current.has(t.id) || !known.has(t.title) && t.category !== "access" && t.category !== "tooling");
827
+ const excluded = new Set(((await readDecisions(cwd))?.items ?? []).filter((d) => d.kind === "exclude_tool").map((d) => d.target));
828
+ const tools = data.tools.filter((t) => !excluded.has(t.id) && (current.has(t.id) || !known.has(t.title) && t.category !== "access" && t.category !== "tooling"));
790
829
  const ids = new Set(tools.map((t) => t.id));
791
830
  const workflows = data.workflows.map((w) => ({ ...w, tools: w.tools.filter((id) => ids.has(id)), steps: w.steps.filter((s) => ids.has(s.tool)) }));
792
831
  const google = tools.find((t) => /Google \(Gmail/.test(t.title));
@@ -840,6 +879,7 @@ var init_project_products = __esm({
840
879
  init_entrypoints();
841
880
  init_catalog();
842
881
  init_dashboard_transfer();
882
+ init_store();
843
883
  }
844
884
  });
845
885
 
@@ -861,8 +901,8 @@ var init_sanitize = __esm({
861
901
  });
862
902
 
863
903
  // src/commands/dashboard.ts
864
- import { cp, mkdir, readFile as readFile5, writeFile } from "fs/promises";
865
- import { basename, join as join5 } from "path";
904
+ import { cp, mkdir as mkdir2, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
905
+ import { basename, join as join6 } from "path";
866
906
  import { fileURLToPath } from "url";
867
907
  function dashboardInventory(cwd, inventory) {
868
908
  return JSON.parse(sanitizeOutput(JSON.stringify({
@@ -898,8 +938,8 @@ __export(session_exports, {
898
938
  writeSessionTask: () => writeSessionTask
899
939
  });
900
940
  import { spawn as spawn2, spawnSync } from "child_process";
901
- import { writeFile as writeFile2, readFile as readFile6 } from "fs/promises";
902
- import { join as join6 } from "path";
941
+ import { writeFile as writeFile3, readFile as readFile7 } from "fs/promises";
942
+ import { join as join7 } from "path";
903
943
  function sessionTask() {
904
944
  return `# Prepare this repository for AgentTwin
905
945
 
@@ -924,8 +964,8 @@ function installedOpenCode() {
924
964
  return spawnSync("opencode", ["--version"], { stdio: "ignore", timeout: 5e3 }).status === 0;
925
965
  }
926
966
  async function writeSessionTask(cwd) {
927
- const path = join6(cwd, ".agenttwin/AGENT-TASK.md");
928
- await writeFile2(path, sessionTask(), "utf8");
967
+ const path = join7(cwd, ".agenttwin/AGENT-TASK.md");
968
+ await writeFile3(path, sessionTask(), "utf8");
929
969
  return path;
930
970
  }
931
971
  async function launchSession(cwd) {
@@ -940,14 +980,14 @@ async function launchSession(cwd) {
940
980
  async function loadDashboardDiscovery(cwd, inventory) {
941
981
  let previousHead;
942
982
  try {
943
- previousHead = JSON.parse(await readFile6(join6(cwd, ".agenttwin/git.json"), "utf8")).head;
983
+ previousHead = JSON.parse(await readFile7(join7(cwd, ".agenttwin/git.json"), "utf8")).head;
944
984
  } catch {
945
985
  }
946
986
  const git = await captureGit(cwd, previousHead);
947
987
  const base = discoveryTransfer({ ...dashboardInventory(cwd, inventory), ...git ? { git } : {} });
948
988
  let raw;
949
989
  try {
950
- raw = await readFile6(join6(cwd, ".agenttwin/agent-discovery.json"), "utf8");
990
+ raw = await readFile7(join7(cwd, ".agenttwin/agent-discovery.json"), "utf8");
951
991
  } catch (error) {
952
992
  if (error.code === "ENOENT") return projectProducts(cwd, base, base);
953
993
  throw error;
@@ -977,8 +1017,8 @@ var init_session = __esm({
977
1017
  init_dashboard_transfer();
978
1018
  import { createServer as createServer2 } from "http";
979
1019
  import { createHash as createHash2, randomBytes as randomBytes3, randomUUID as randomUUID2, timingSafeEqual } from "crypto";
980
- import { mkdir as mkdir3, readFile as readFile8, writeFile as writeFile4, rename, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
981
- import { resolve as resolve2, join as join8, dirname as dirname2, extname } from "path";
1020
+ import { mkdir as mkdir4, readFile as readFile9, writeFile as writeFile5, rename, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
1021
+ import { resolve as resolve2, join as join9, dirname as dirname2, extname } from "path";
982
1022
  import { tmpdir as tmpdir2 } from "os";
983
1023
 
984
1024
  // src/runtime/transcription.ts
@@ -1111,9 +1151,9 @@ function portableLocalReceipt(value) {
1111
1151
  }
1112
1152
 
1113
1153
  // src/commands/run.ts
1114
- import { mkdtemp, mkdir as mkdir2, readFile as readFile7, writeFile as writeFile3, realpath, lstat, rm, copyFile } from "fs/promises";
1154
+ import { mkdtemp, mkdir as mkdir3, readFile as readFile8, writeFile as writeFile4, realpath, lstat, rm, copyFile } from "fs/promises";
1115
1155
  import { tmpdir } from "os";
1116
- import { basename as basename2, dirname, isAbsolute, join as join7, relative as relative2, resolve, sep as sep2 } from "path";
1156
+ import { basename as basename2, dirname, isAbsolute, join as join8, relative as relative2, resolve, sep as sep2 } from "path";
1117
1157
  import { fileURLToPath as fileURLToPath2 } from "url";
1118
1158
  import { createHash, randomUUID } from "crypto";
1119
1159
 
@@ -1525,12 +1565,12 @@ async function stageApplication(root, files, destination) {
1525
1565
  const source = await realpath(resolve(canonicalRoot, file));
1526
1566
  const rel = relative2(canonicalRoot, source);
1527
1567
  if (rel.startsWith(`..${sep2}`) || rel === ".." || isAbsolute(rel) || source !== resolve(canonicalRoot, file) || !(await lstat(source)).isFile()) throw new CliError(`Files must be regular files within the project, without symlinks: ${file}`, { code: EXIT.USAGE });
1528
- const contents = await readFile7(source);
1568
+ const contents = await readFile8(source);
1529
1569
  bytes += contents.length;
1530
1570
  if (bytes > 20 * 1024 * 1024) throw new CliError("Application files exceed 20 MiB; supply a smaller built bundle", { code: EXIT.USAGE });
1531
- const target = join7(destination, file);
1532
- await mkdir2(dirname(target), { recursive: true });
1533
- await writeFile3(target, contents, { mode: 420 });
1571
+ const target = join8(destination, file);
1572
+ await mkdir3(dirname(target), { recursive: true });
1573
+ await writeFile4(target, contents, { mode: 420 });
1534
1574
  digests[file] = createHash("sha256").update(contents).digest("hex");
1535
1575
  }
1536
1576
  return digests;
@@ -1539,14 +1579,14 @@ async function runWorld(cwd, opts) {
1539
1579
  const file = resolve(cwd, opts.file ?? "agenttwin.world.json");
1540
1580
  let spec;
1541
1581
  try {
1542
- spec = parseWorld(JSON.parse(await readFile7(file, "utf8")));
1582
+ spec = parseWorld(JSON.parse(await readFile8(file, "utf8")));
1543
1583
  } catch (error) {
1544
1584
  throw new CliError(String(error), { code: EXIT.USAGE, action: "Create agenttwin.world.json; run agenttwin example --out ./agenttwin-example for a working example." });
1545
1585
  }
1546
1586
  if (spec.workflowId) {
1547
1587
  let inventory;
1548
1588
  try {
1549
- inventory = JSON.parse(await readFile7(join7(cwd, ".agenttwin/inventory.json"), "utf8"));
1589
+ inventory = JSON.parse(await readFile8(join8(cwd, ".agenttwin/inventory.json"), "utf8"));
1550
1590
  } catch {
1551
1591
  throw new CliError("Linked workflow needs discovery inventory; run init first", { code: EXIT.BLOCKED });
1552
1592
  }
@@ -1559,26 +1599,26 @@ async function runWorld(cwd, opts) {
1559
1599
  const runtime = opts.runtime ?? "local";
1560
1600
  if (!["local", "e2b", "hosted"].includes(runtime)) throw new CliError("runtime must be local, hosted or e2b", { code: EXIT.USAGE });
1561
1601
  if (runtime === "e2b" && !process.env.E2B_API_KEY) throw new CliError("E2B_API_KEY is not configured", { code: EXIT.BLOCKED, action: "Configure your E2B key in the shell; it will not be uploaded." });
1562
- const stage = await mkdtemp(join7(tmpdir(), "agenttwin-world-"));
1602
+ const stage = await mkdtemp(join8(tmpdir(), "agenttwin-world-"));
1563
1603
  try {
1564
- const sourceDigests = await stageApplication(dirname(file), spec.files, join7(stage, "app"));
1565
- await writeFile3(join7(stage, "world.json"), JSON.stringify(spec), { mode: 420 });
1604
+ const sourceDigests = await stageApplication(dirname(file), spec.files, join8(stage, "app"));
1605
+ await writeFile4(join8(stage, "world.json"), JSON.stringify(spec), { mode: 420 });
1566
1606
  const git = await captureGit(cwd);
1567
1607
  let project;
1568
1608
  try {
1569
- project = JSON.parse(await readFile7(join7(cwd, ".agenttwin/inventory.json"), "utf8")).name ?? basename2(cwd);
1609
+ project = JSON.parse(await readFile8(join8(cwd, ".agenttwin/inventory.json"), "utf8")).name ?? basename2(cwd);
1570
1610
  } catch {
1571
1611
  }
1572
1612
  if (runtime === "local") {
1573
1613
  opts.log("Testing through the CLI with in-process service twins. No cloud VM or containers.");
1574
- const report2 = await executeLocal(join7(stage, "app"), spec, opts.signal);
1614
+ const report2 = await executeLocal(join8(stage, "app"), spec, opts.signal);
1575
1615
  const runId2 = randomUUID();
1576
1616
  const receipt2 = { ...report2, runId: runId2, runtime, project, git, createdAt: (/* @__PURE__ */ new Date()).toISOString(), sourceDigests, specDigest: createHash("sha256").update(JSON.stringify(spec)).digest("hex"), provenance: "CLI-reported execution" };
1577
1617
  const out2 = resolve(cwd, opts.out ?? `.agenttwin/runs/${runId2}`);
1578
- await mkdir2(out2, { recursive: true });
1579
- const evidencePath = join7(out2, "run.json"), reportPath = join7(out2, "report.md");
1580
- await writeFile3(evidencePath, JSON.stringify(receipt2, null, 2) + "\n", { mode: 384 });
1581
- await writeFile3(reportPath, `# ${spec.name}: ${receipt2.status}
1618
+ await mkdir3(out2, { recursive: true });
1619
+ const evidencePath = join8(out2, "run.json"), reportPath = join8(out2, "report.md");
1620
+ await writeFile4(evidencePath, JSON.stringify(receipt2, null, 2) + "\n", { mode: 384 });
1621
+ await writeFile4(reportPath, `# ${spec.name}: ${receipt2.status}
1582
1622
 
1583
1623
  Runner: CLI
1584
1624
  Git: ${git?.head ?? "unavailable"}
@@ -1586,8 +1626,8 @@ Git: ${git?.head ?? "unavailable"}
1586
1626
  ` + receipt2.assertions.map((a) => `- ${a.passed ? "PASS" : "FAIL"} ${a.service}${a.path}: expected ${a.count}, observed ${a.actual}`).join("\n") + "\n\nSee run.json for activities, fault and initial/final state.\n");
1587
1627
  return { ...receipt2, reportPath, evidencePath };
1588
1628
  }
1589
- const worker = join7(dirname(fileURLToPath2(import.meta.url)), "worker.js");
1590
- await copyFile(worker, join7(stage, "worker.js"));
1629
+ const worker = join8(dirname(fileURLToPath2(import.meta.url)), "worker.js");
1630
+ await copyFile(worker, join8(stage, "worker.js"));
1591
1631
  if (runtime === "hosted") {
1592
1632
  const receipt2 = await executeRemote(stage, spec, opts.log, { git, project });
1593
1633
  if (receipt2.schema !== "agenttwin/run-v1" || typeof receipt2.runId !== "string" || !/^[a-f0-9-]{36}$/.test(receipt2.runId) || !["passed", "failed", "error", "incomplete"].includes(String(receipt2.status))) throw new CliError("Invalid hosted receipt");
@@ -1595,11 +1635,11 @@ Git: ${git?.head ?? "unavailable"}
1595
1635
  const reportedSources = receipt2.sourceDigests;
1596
1636
  if (receipt2.specDigest !== expectedSpec || !reportedSources || Object.keys(reportedSources).length !== Object.keys(sourceDigests).length || Object.entries(sourceDigests).some(([path, digest]) => reportedSources[path] !== digest)) throw new CliError("Hosted receipt does not match the submitted source/specification");
1597
1637
  const out2 = resolve(cwd, opts.out ?? `.agenttwin/runs/${receipt2.runId}`);
1598
- await mkdir2(out2, { recursive: true });
1599
- const evidencePath = join7(out2, "run.json");
1600
- const reportPath = join7(out2, "report.md");
1601
- await writeFile3(evidencePath, JSON.stringify(receipt2, null, 2) + "\n", { mode: 384 });
1602
- await writeFile3(reportPath, `# ${spec.name}: ${receipt2.status}
1638
+ await mkdir3(out2, { recursive: true });
1639
+ const evidencePath = join8(out2, "run.json");
1640
+ const reportPath = join8(out2, "report.md");
1641
+ await writeFile4(evidencePath, JSON.stringify(receipt2, null, 2) + "\n", { mode: 384 });
1642
+ await writeFile4(reportPath, `# ${spec.name}: ${receipt2.status}
1603
1643
 
1604
1644
  Run: ${receipt2.runId}
1605
1645
 
@@ -1633,12 +1673,12 @@ See run.json for assertions, service state, application output and isolation met
1633
1673
  isolation
1634
1674
  };
1635
1675
  const out = resolve(cwd, opts.out ?? `.agenttwin/runs/${runId}`);
1636
- await mkdir2(out, { recursive: true });
1637
- await writeFile3(join7(out, "run.json"), JSON.stringify(receipt, null, 2) + "\n", { mode: 384 });
1638
- await writeFile3(join7(out, "world.json"), JSON.stringify(spec, null, 2) + "\n", { mode: 384 });
1676
+ await mkdir3(out, { recursive: true });
1677
+ await writeFile4(join8(out, "run.json"), JSON.stringify(receipt, null, 2) + "\n", { mode: 384 });
1678
+ await writeFile4(join8(out, "world.json"), JSON.stringify(spec, null, 2) + "\n", { mode: 384 });
1639
1679
  const summary = [`# ${spec.name}: ${report.status}`, "", `Run: ${runId}`, `Image: ${image}`, "", "## Assertions", "", ...report.assertions.map((a) => `- ${a.passed ? "PASS" : "FAIL"} ${a.service}${a.path}: expected ${a.count}, observed ${a.actual}`), "", "## Infrastructure assertions", "", ...(report.infrastructureAssertions ?? []).map((a) => `- ${a.passed ? "PASS" : "FAIL"} ${a.service}: ${JSON.stringify(a.actual)}`), "", "## Coverage", "", report.coverage, "", "External networking disabled. Only explicitly listed source files were uploaded. New state and tokens are created for each run.", "", "See run.json for application output, faults, events, and initial/final state.", ""].join("\n");
1640
- await writeFile3(join7(out, "report.md"), summary);
1641
- return { ...receipt, reportPath: join7(out, "report.md"), evidencePath: join7(out, "run.json") };
1680
+ await writeFile4(join8(out, "report.md"), summary);
1681
+ return { ...receipt, reportPath: join8(out, "report.md"), evidencePath: join8(out, "run.json") };
1642
1682
  } finally {
1643
1683
  await rm(stage, { recursive: true, force: true });
1644
1684
  }
@@ -1680,11 +1720,11 @@ async function startGateway(opts) {
1680
1720
  const chatControllers = /* @__PURE__ */ new Map();
1681
1721
  const voiceControllers = /* @__PURE__ */ new Map();
1682
1722
  const directory = resolve2(opts.directory);
1683
- await mkdir3(directory, { recursive: true, mode: 448 });
1684
- const storePath = join8(directory, "state.json");
1723
+ await mkdir4(directory, { recursive: true, mode: 448 });
1724
+ const storePath2 = join9(directory, "state.json");
1685
1725
  let store;
1686
1726
  try {
1687
- store = JSON.parse(await readFile8(storePath, "utf8"));
1727
+ store = JSON.parse(await readFile9(storePath2, "utf8"));
1688
1728
  if (store.schema !== "agenttwin/gateway-v1") throw new Error("Invalid store");
1689
1729
  } catch (error) {
1690
1730
  if (error.code !== "ENOENT") throw error;
@@ -1699,9 +1739,9 @@ async function startGateway(opts) {
1699
1739
  const save = () => {
1700
1740
  const snapshot = JSON.stringify(store);
1701
1741
  writes = writes.then(async () => {
1702
- const path = join8(directory, `state-${randomUUID2()}.tmp`);
1703
- await writeFile4(path, snapshot, { mode: 384 });
1704
- await rename(path, storePath);
1742
+ const path = join9(directory, `state-${randomUUID2()}.tmp`);
1743
+ await writeFile5(path, snapshot, { mode: 384 });
1744
+ await rename(path, storePath2);
1705
1745
  }).catch((error) => {
1706
1746
  storageHealthy = false;
1707
1747
  throw error;
@@ -1734,16 +1774,16 @@ async function startGateway(opts) {
1734
1774
  if (!store.accounts.some((a) => a.id === item.job.accountId && a.active)) throw new Error("Account revoked before execution");
1735
1775
  item.job.status = "running";
1736
1776
  await save();
1737
- workspace = await mkdtemp2(join8(tmpdir2(), "agenttwin-api-run-"));
1777
+ workspace = await mkdtemp2(join9(tmpdir2(), "agenttwin-api-run-"));
1738
1778
  for (const [file, encoded] of Object.entries(item.files)) {
1739
- const destination = join8(workspace, uploadPath(file));
1740
- await mkdir3(dirname2(destination), { recursive: true });
1741
- await writeFile4(destination, Buffer.from(encoded, "base64"), { mode: 384 });
1779
+ const destination = join9(workspace, uploadPath(file));
1780
+ await mkdir4(dirname2(destination), { recursive: true });
1781
+ await writeFile5(destination, Buffer.from(encoded, "base64"), { mode: 384 });
1742
1782
  }
1743
- await writeFile4(join8(workspace, "agenttwin.world.json"), JSON.stringify(item.spec));
1783
+ await writeFile5(join9(workspace, "agenttwin.world.json"), JSON.stringify(item.spec));
1744
1784
  if (item.spec.workflowId) {
1745
- await mkdir3(join8(workspace, ".agenttwin"));
1746
- await writeFile4(join8(workspace, ".agenttwin/inventory.json"), JSON.stringify({ workflows: [{ id: item.spec.workflowId }] }));
1785
+ await mkdir4(join9(workspace, ".agenttwin"));
1786
+ await writeFile5(join9(workspace, ".agenttwin/inventory.json"), JSON.stringify({ workflows: [{ id: item.spec.workflowId }] }));
1747
1787
  }
1748
1788
  const receipt = await runWorld(workspace, { runtime: "e2b", signal: controllers.get(item.job.id)?.signal, log: () => {
1749
1789
  } });
@@ -1788,7 +1828,7 @@ async function startGateway(opts) {
1788
1828
  return;
1789
1829
  }
1790
1830
  try {
1791
- const bytes = await readFile8(file);
1831
+ const bytes = await readFile9(file);
1792
1832
  const types = { ".html": "text/html; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".css": "text/css; charset=utf-8", ".json": "application/json", ".svg": "image/svg+xml", ".png": "image/png", ".jpg": "image/jpeg", ".ico": "image/x-icon", ".woff2": "font/woff2" };
1793
1833
  res.writeHead(200, { "content-type": types[extname(file)] ?? "application/octet-stream", "cache-control": "no-store", "x-content-type-options": "nosniff", "referrer-policy": "no-referrer" });
1794
1834
  res.end(bytes);
@@ -1930,7 +1970,7 @@ async function startGateway(opts) {
1930
1970
  return;
1931
1971
  }
1932
1972
  if (path === "/v1/runs" && req.method === "GET") {
1933
- send(res, 200, { jobs: store.jobs.filter((j) => j.accountId === account.id).sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt)).slice(0, 100).map(({ id, status, createdAt }) => ({ id, status, createdAt })) });
1973
+ send(res, 200, { jobs: store.jobs.filter((j) => j.accountId === account.id).sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt)).slice(0, 100).map((job) => ({ id: job.id, status: job.status, createdAt: job.createdAt, name: job.name ?? (typeof job.receipt?.name === "string" ? job.receipt.name : void 0), workflowId: job.workflowId ?? (typeof job.receipt?.workflowId === "string" ? job.receipt.workflowId : void 0), project: job.project ?? (typeof job.receipt?.project === "string" ? job.receipt.project : void 0) })) });
1934
1974
  return;
1935
1975
  }
1936
1976
  if (path === "/v1/runs" && req.method === "POST") {
@@ -1991,7 +2031,7 @@ async function startGateway(opts) {
1991
2031
  return;
1992
2032
  }
1993
2033
  store.jobs = store.jobs.filter((j) => Date.parse(j.createdAt) > Date.now() - 30 * 864e5);
1994
- const job = { id: randomUUID2(), accountId: account.id, status: "queued", createdAt: (/* @__PURE__ */ new Date()).toISOString() };
2034
+ const job = { id: randomUUID2(), accountId: account.id, status: "queued", createdAt: (/* @__PURE__ */ new Date()).toISOString(), name: spec.name, workflowId: spec.workflowId, project };
1995
2035
  account.runs++;
1996
2036
  store.jobs.push(job);
1997
2037
  await save();