agent-dealer 1.2.5 → 1.2.7

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 (75) hide show
  1. package/bundle/server/dist/adapters/agent-deck-bind.js +33 -3
  2. package/bundle/server/dist/adapters/agent-deck-bind.test.js +60 -2
  3. package/bundle/server/dist/adapters/agent-health.js +3 -4
  4. package/bundle/server/dist/adapters/agent-health.test.js +11 -9
  5. package/bundle/server/dist/adapters/git-worktree.js +187 -18
  6. package/bundle/server/dist/adapters/git-worktree.test.js +293 -0
  7. package/bundle/server/dist/adapters/muse-capability.js +51 -25
  8. package/bundle/server/dist/adapters/muse-capability.test.js +138 -52
  9. package/bundle/server/dist/capacity/claude-local-cache.js +59 -27
  10. package/bundle/server/dist/capacity/claude-local-cache.test.js +163 -9
  11. package/bundle/server/dist/capacity/muse-host.js +34 -32
  12. package/bundle/server/dist/capacity/muse-host.test.js +5 -3
  13. package/bundle/server/dist/coordinator/args.js +4 -3
  14. package/bundle/server/dist/coordinator/checkpoint.js +5 -3
  15. package/bundle/server/dist/coordinator/checkpoint.test.js +23 -0
  16. package/bundle/server/dist/coordinator/commands.js +66 -5
  17. package/bundle/server/dist/coordinator/developer-effect.js +88 -10
  18. package/bundle/server/dist/coordinator/developer-effect.test.js +170 -0
  19. package/bundle/server/dist/coordinator/human-resolution.js +2 -0
  20. package/bundle/server/dist/coordinator/muse-developer.integration.test.js +291 -55
  21. package/bundle/server/dist/coordinator/muse-spawn.js +72 -174
  22. package/bundle/server/dist/coordinator/projection.js +1 -0
  23. package/bundle/server/dist/coordinator/prompts.js +10 -6
  24. package/bundle/server/dist/coordinator/prompts.test.js +16 -8
  25. package/bundle/server/dist/coordinator/routing.js +1 -0
  26. package/bundle/server/dist/coordinator/routing.test.js +20 -0
  27. package/bundle/server/dist/coordinator/spawn.js +2 -1
  28. package/bundle/server/dist/coordinator/worktree-owner-liveness.js +6 -1
  29. package/bundle/server/dist/coordinator/worktree-owner-liveness.test.js +2 -1
  30. package/bundle/server/dist/repository/human-actions.js +13 -0
  31. package/bundle/server/dist/routes/index.js +11 -8
  32. package/bundle/server/dist/routes/version.js +30 -0
  33. package/bundle/server/dist/routes/version.test.js +21 -0
  34. package/bundle/server/dist/runners/muse-config-core.js +63 -16
  35. package/bundle/server/dist/runners/muse-config.js +1 -1
  36. package/bundle/server/dist/runners/muse-config.test.js +135 -29
  37. package/bundle/server/dist/runners/spawn-cli.js +17 -3
  38. package/bundle/server/dist/runners/spawn-cli.test.js +59 -0
  39. package/bundle/server/package.json +2 -2
  40. package/bundle/server/static-ui/assets/index-DyAJNyfV.css +1 -0
  41. package/bundle/server/static-ui/assets/index-yLyxRd-7.js +64 -0
  42. package/bundle/server/static-ui/index.html +2 -2
  43. package/bundle/shared/dist/action-presentation.d.ts +51 -0
  44. package/bundle/shared/dist/action-presentation.js +280 -0
  45. package/bundle/shared/dist/action-presentation.test.d.ts +1 -0
  46. package/bundle/shared/dist/action-presentation.test.js +180 -0
  47. package/bundle/shared/dist/attempt-waste.d.ts +2 -2
  48. package/bundle/shared/dist/execution-report.d.ts +2 -2
  49. package/bundle/shared/dist/human-actions.d.ts +12 -12
  50. package/bundle/shared/dist/index.d.ts +41 -40
  51. package/bundle/shared/dist/index.js +1 -0
  52. package/bundle/shared/dist/issues.d.ts +12 -12
  53. package/bundle/shared/dist/outbound-draft.d.ts +6 -6
  54. package/bundle/shared/dist/profile-snapshot.d.ts +2 -2
  55. package/bundle/shared/dist/usage-events.d.ts +2 -2
  56. package/bundle/shared/dist/worker-sessions.d.ts +6 -6
  57. package/bundle/shared/dist/workflow.d.ts +2 -2
  58. package/bundle/shared/package.json +1 -1
  59. package/dist/doctor.js +4 -1
  60. package/dist/managed/index.d.ts +1 -1
  61. package/dist/managed/index.js +1 -1
  62. package/dist/managed/updater.d.ts +16 -6
  63. package/dist/managed/updater.js +28 -11
  64. package/dist/managed-update-restart.test.d.ts +1 -0
  65. package/dist/managed-update-restart.test.js +227 -0
  66. package/dist/ports.d.ts +6 -0
  67. package/dist/ports.js +10 -0
  68. package/dist/runtime-state.d.ts +10 -0
  69. package/dist/runtime-state.js +26 -0
  70. package/dist/start.js +67 -2
  71. package/dist/status.js +30 -2
  72. package/dist/update-check.js +3 -6
  73. package/package.json +1 -1
  74. package/bundle/server/static-ui/assets/index-BII-LgB8.css +0 -1
  75. package/bundle/server/static-ui/assets/index-Bq8wWpZm.js +0 -60
@@ -13,7 +13,11 @@ export const NOT_177_EVIDENCE = Object.freeze({
13
13
  });
14
14
  export const MUSE_MODEL = "muse-spark-1.3-contributor";
15
15
  export const AGENT_DECK_SERVER = "agent-deck";
16
- /** Deck reads a worker needs. `call_service_tool` (outbound mutation) is never in this list. */
16
+ /**
17
+ * NOT-278: the read-only allowlist is a reviewer requirement, not a developer requirement.
18
+ * Developers receive the selected deck's full surface, including `call_service_tool`. These
19
+ * lists only ever materialize for a reviewer build that proves allowlist enforcement.
20
+ */
17
21
  export const AGENT_DECK_READ_TOOLS = [
18
22
  "get_bound_deck",
19
23
  "get_playbook",
@@ -46,6 +50,10 @@ const FORBIDDEN_FLAGS = [
46
50
  ];
47
51
  /** Which ambient env vars reach Muse. Everything else (META_API_KEY, MUSE_*, CODEX_HOME, ...) is dropped. */
48
52
  const ENV_ALLOWLIST = ["PATH", "HOME", "USER", "LOGNAME", "SHELL", "LANG", "TERM", "TMPDIR"];
53
+ /** Test-only harness vars for the fake `muse` fixture (fixtures/fake-muse.mjs), which can only be
54
+ * selected via the operator/test `MUSE_CLI` override — and passed through only when that
55
+ * override is set, so production runs of the default binary never carry them. */
56
+ const FAKE_HARNESS_PREFIX = "FAKE_MUSE_";
49
57
  const ATTEMPT_PREFIX = "muse-attempt-";
50
58
  const SENTINEL = ".dealer-muse-attempt";
51
59
  /** Messages name fields and paths, never values that could be credentials. */
@@ -59,10 +67,17 @@ export class MuseIsolationError extends Error {
59
67
  this.name = "MuseIsolationError";
60
68
  }
61
69
  }
62
- /** Capabilities a role needs that the evidence does not prove. Both roles need both today. */
63
- export function unenforceableRestrictions(_role, evidence = NOT_177_EVIDENCE) {
70
+ /**
71
+ * NOT-278: capabilities a role needs that the evidence does not prove. Developers receive the
72
+ * selected deck's full surface (including `call_service_tool`), so no allowlist enforcement is
73
+ * required; `cron_*` stays prohibited by the developer prompt and is detected post-run
74
+ * (`muse_cron_used`), not mechanically disabled. Reviewers still need both controls proven.
75
+ */
76
+ export function unenforceableRestrictions(role, evidence = NOT_177_EVIDENCE) {
77
+ if (role === "developer")
78
+ return [];
64
79
  const missing = [];
65
- // Outbound mutation (`call_service_tool`) must stay denied for every role, and Muse only
80
+ // Outbound mutation (`call_service_tool`) must stay denied for reviewers, and Muse only
66
81
  // stores enabled_tools/disabled_tools unless this is proven.
67
82
  if (!evidence.mcp_tool_allowlist_enforcement)
68
83
  missing.push("mcp_tool_allowlist_enforcement");
@@ -71,15 +86,37 @@ export function unenforceableRestrictions(_role, evidence = NOT_177_EVIDENCE) {
71
86
  missing.push("cron_tool_disable");
72
87
  return missing;
73
88
  }
74
- export function buildMuseSettings(agentDeck, evidence = NOT_177_EVIDENCE) {
89
+ /**
90
+ * NOT-278: the deckless worker posture shared by every Muse settings.json — workflows and
91
+ * subagents off, reminder child runs off, plus `cron_*` only when proven mechanically
92
+ * disableable. The capacity serve host (which is shared across decks and never runs a
93
+ * session) uses this directly; per-attempt sessions add the required `agent-deck` server
94
+ * below. Exported only for that host — it is not a session attempt and `assertMuseSettings`
95
+ * rejects it (exactly one required `agent-deck` server is mandatory for a launch).
96
+ */
97
+ export function buildMuseBaseSettings(role = "developer", evidence = NOT_177_EVIDENCE) {
75
98
  const runtime_capabilities = {};
76
99
  for (const name of REMINDERS) {
77
100
  runtime_capabilities[`plugin:tbh-reminders:reminder:${name}`] = { enabled: false };
78
101
  }
79
- if (evidence.cron_tool_disable) {
102
+ // NOT-278: `cron_*` can only be claimed disabled for reviewers on a build that proves it.
103
+ // Developers are prohibited by prompt and detected post-run; their settings never claim it.
104
+ if (role === "reviewer" && evidence.cron_tool_disable) {
80
105
  for (const tool of CRON_TOOLS)
81
106
  runtime_capabilities[`tool:${tool}`] = { enabled: false };
82
107
  }
108
+ return {
109
+ schema_version: 1,
110
+ run: { workflow_trigger_mode: "off", subagent_delegation_mode: "off" },
111
+ runtime_capabilities,
112
+ };
113
+ }
114
+ /**
115
+ * NOT-278: developers always receive the selected deck's full surface unfiltered — their
116
+ * settings never carry `enabled_tools`/`disabled_tools` claims. The read-only allowlist only
117
+ * materializes for reviewers on a build that proves enforcement.
118
+ */
119
+ export function buildMuseSettings(agentDeck, role = "developer", evidence = NOT_177_EVIDENCE) {
83
120
  const server = {
84
121
  type: "streamable-http",
85
122
  url: agentDeck.url,
@@ -90,20 +127,18 @@ export function buildMuseSettings(agentDeck, evidence = NOT_177_EVIDENCE) {
90
127
  // `mode`, not `required`: writing both drops the whole MCP block. Never "optional".
91
128
  mode: "required",
92
129
  };
93
- if (evidence.mcp_tool_allowlist_enforcement) {
130
+ if (role === "reviewer" && evidence.mcp_tool_allowlist_enforcement) {
94
131
  server.enabled_tools = [...AGENT_DECK_READ_TOOLS];
95
132
  server.disabled_tools = [...AGENT_DECK_DENIED_TOOLS];
96
133
  }
97
134
  return {
98
- schema_version: 1,
99
- run: { workflow_trigger_mode: "off", subagent_delegation_mode: "off" },
100
- runtime_capabilities,
135
+ ...buildMuseBaseSettings(role, evidence),
101
136
  mcpServers: { [AGENT_DECK_SERVER]: server },
102
137
  };
103
138
  }
104
139
  /** Whitelist check on a settings object (generated or re-read from disk). */
105
- export function assertMuseSettings(settings, agentDeck, evidence = NOT_177_EVIDENCE) {
106
- const expected = buildMuseSettings(agentDeck, evidence);
140
+ export function assertMuseSettings(settings, agentDeck, role = "developer", evidence = NOT_177_EVIDENCE) {
141
+ const expected = buildMuseSettings(agentDeck, role, evidence);
107
142
  if (JSON.stringify(sortKeys(settings)) !== JSON.stringify(sortKeys(expected))) {
108
143
  throw new MuseIsolationError("invalid_settings", "Muse settings differ from the approved role settings (extra, missing, or altered keys)");
109
144
  }
@@ -194,6 +229,17 @@ export function buildMuseEnv(root, ambient = process.env) {
194
229
  if (key.startsWith("LC_") && value !== undefined)
195
230
  env[key] = value;
196
231
  }
232
+ // Test-only seam: the fake fixture is driven by FAKE_MUSE_* (scenario, record path, version
233
+ // pins) and the exec lane is exact, so without this the fixture cannot be driven at all.
234
+ // These vars join attempt.env only when the operator/test MUSE_CLI override selects the
235
+ // binary — i.e. only the fixture can ever receive them, never the default real binary —
236
+ // and the pre-spawn verify() snapshot covers them exactly like every other approved var.
237
+ if (ambient.MUSE_CLI?.trim()) {
238
+ for (const [key, value] of Object.entries(ambient)) {
239
+ if (key.startsWith(FAKE_HARNESS_PREFIX) && value !== undefined)
240
+ env[key] = value;
241
+ }
242
+ }
197
243
  env.MUSE_NO_AUTO_UPDATE = "1";
198
244
  env.XDG_CONFIG_HOME = path.join(root, "config");
199
245
  env.XDG_DATA_HOME = path.join(root, "data");
@@ -337,7 +383,8 @@ function sameJson(a, b) {
337
383
  * Validates, refuses unenforceable restrictions, then writes the per-attempt dir (0700) with
338
384
  * settings.json (0600) and an auth link. Throws before spawn; leaves nothing behind on failure.
339
385
  *
340
- * Always uses the pinned `NOT_177_EVIDENCE`, under which both roles are currently refused. There is
386
+ * Always uses the pinned `NOT_177_EVIDENCE`, under which developers are admitted unfiltered
387
+ * (NOT-278: the full deck surface, no allowlist claims) and reviewers are still refused. There is
341
388
  * deliberately no runtime seam that accepts other evidence: the enforced-path tests load a
342
389
  * source-rewritten copy of this file instead (see muse-config.test.ts).
343
390
  */
@@ -355,8 +402,8 @@ function prepareWithEvidence(rawInput, evidence) {
355
402
  const { worktree, baseDir } = validateInput(input);
356
403
  const agentDeck = input.agentDeck;
357
404
  const credentialKind = input.credential.kind;
358
- const settings = deepFreeze(buildMuseSettings(agentDeck, evidence));
359
- assertMuseSettings(settings, agentDeck, evidence);
405
+ const settings = deepFreeze(buildMuseSettings(agentDeck, input.role, evidence));
406
+ assertMuseSettings(settings, agentDeck, input.role, evidence);
360
407
  const apiKey = input.credential.kind === "api-key" ? input.credential.apiKey : undefined;
361
408
  const argv = buildMuseArgv({
362
409
  role: input.role,
@@ -445,7 +492,7 @@ function prepareWithEvidence(rawInput, evidence) {
445
492
  throw err;
446
493
  throw new MuseIsolationError("invalid_settings", "Muse settings.json is missing or unreadable");
447
494
  }
448
- assertMuseSettings(onDisk, agentDeck, evidence);
495
+ assertMuseSettings(onDisk, agentDeck, input.role, evidence);
449
496
  const entries = fs.readdirSync(path.dirname(settingsPath)).sort();
450
497
  const allowed = credentialKind === "auth-file" ? ["auth.json", "settings.json"] : ["settings.json"];
451
498
  if (entries.join() !== allowed.join()) {
@@ -2,4 +2,4 @@
2
2
  //
3
3
  // The implementation lives in muse-config-core.ts, which pins `prepareMuseAttempt` to
4
4
  // `NOT_177_EVIDENCE`. No module in the build exports a preparer that accepts caller-supplied evidence.
5
- export { AGENT_DECK_DENIED_TOOLS, AGENT_DECK_READ_TOOLS, AGENT_DECK_SERVER, MUSE_MODEL, MuseIsolationError, NOT_177_EVIDENCE, assertMuseArgv, assertMuseSettings, buildMuseArgv, buildMuseEnv, buildMuseSettings, createRedactor, defaultOperatorAuthPath, prepareMuseAttempt, unenforceableRestrictions, } from "./muse-config-core.js";
5
+ export { AGENT_DECK_DENIED_TOOLS, AGENT_DECK_READ_TOOLS, AGENT_DECK_SERVER, MUSE_MODEL, MuseIsolationError, NOT_177_EVIDENCE, assertMuseArgv, assertMuseSettings, buildMuseArgv, buildMuseBaseSettings, buildMuseEnv, buildMuseSettings, createRedactor, defaultOperatorAuthPath, prepareMuseAttempt, unenforceableRestrictions, } from "./muse-config-core.js";
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
3
3
  import fs from "node:fs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
- import { assertMuseArgv, buildMuseArgv, prepareMuseAttempt as prepareMuseAttemptPinned, unenforceableRestrictions, } from "./muse-config.js";
6
+ import { assertMuseArgv, buildMuseArgv, NOT_177_EVIDENCE, prepareMuseAttempt as prepareMuseAttemptPinned, unenforceableRestrictions, } from "./muse-config.js";
7
7
  import { pathToFileURL } from "node:url";
8
8
  // The Muse sandbox leaves temp dirs writable, so the module refuses them: fixtures live under $HOME.
9
9
  const SCRATCH = fs.mkdtempSync(path.join(os.homedir(), ".dealer-muse-config-test-"));
@@ -68,26 +68,54 @@ function walk(dir) {
68
68
  return e.isDirectory() ? walk(p) : [p];
69
69
  });
70
70
  }
71
- test("with NOT-177 evidence both roles fail before anything is written", () => {
72
- for (const role of ["developer", "reviewer"]) {
73
- const fx = fixture();
74
- let thrown;
75
- try {
76
- prepareMuseAttemptPinned(input(fx, role));
77
- }
78
- catch (err) {
79
- thrown = err;
71
+ // NOT-278: developers get the selected deck's full surface unfiltered, so the pinned evidence
72
+ // admits them; reviewers still need both controls proven and fail before anything is written.
73
+ test("with NOT-177 evidence the developer is admitted unfiltered and the reviewer still fails closed", () => {
74
+ const fx = fixture();
75
+ const attempt = prepareMuseAttemptPinned(input(fx, "developer"));
76
+ try {
77
+ const onDisk = JSON.parse(fs.readFileSync(attempt.settingsPath, "utf8"));
78
+ assert.deepEqual(Object.keys(onDisk.mcpServers), ["agent-deck"]);
79
+ assert.equal(onDisk.mcpServers["agent-deck"].mode, "required");
80
+ assert.deepEqual(onDisk.mcpServers["agent-deck"].headers, {
81
+ "x-agent-deck-deck-id": "deck-123",
82
+ "x-agent-deck-workspace": fs.realpathSync(fx.worktree),
83
+ });
84
+ assert.equal("enabled_tools" in onDisk.mcpServers["agent-deck"], false);
85
+ assert.equal("disabled_tools" in onDisk.mcpServers["agent-deck"], false);
86
+ for (const tool of ["cron_create", "cron_list", "cron_delete"]) {
87
+ assert.equal(`tool:${tool}` in onDisk.runtime_capabilities, false, tool);
80
88
  }
81
- assert.equal(thrown?.code, "unenforceable_restriction", role);
82
- assert.deepEqual([...thrown.capabilities], ["mcp_tool_allowlist_enforcement", "cron_tool_disable"]);
83
- assert.deepEqual(fs.readdirSync(fx.baseDir), []);
89
+ assert.doesNotThrow(() => attempt.verify());
90
+ }
91
+ finally {
92
+ attempt.cleanup();
93
+ }
94
+ const fxReviewer = fixture();
95
+ let thrown;
96
+ try {
97
+ prepareMuseAttemptPinned(input(fxReviewer, "reviewer"));
84
98
  }
99
+ catch (err) {
100
+ thrown = err;
101
+ }
102
+ assert.equal(thrown?.code, "unenforceable_restriction");
103
+ assert.deepEqual([...thrown.capabilities], ["mcp_tool_allowlist_enforcement", "cron_tool_disable"]);
104
+ assert.deepEqual(fs.readdirSync(fxReviewer.baseDir), []);
105
+ assert.deepEqual(unenforceableRestrictions("developer", NOT_177_EVIDENCE), []);
106
+ assert.deepEqual(unenforceableRestrictions("reviewer", NOT_177_EVIDENCE), [
107
+ "mcp_tool_allowlist_enforcement",
108
+ "cron_tool_disable",
109
+ ]);
85
110
  assert.deepEqual(unenforceableRestrictions("developer", ENFORCED), []);
111
+ assert.deepEqual(unenforceableRestrictions("reviewer", ENFORCED), []);
86
112
  assert.deepEqual(unenforceableRestrictions("reviewer", { ...ENFORCED, cron_tool_disable: false }), [
87
113
  "cron_tool_disable",
88
114
  ]);
89
115
  });
90
- test("developer: only the assigned Agent Deck surface, sandbox on, no unrestricted flags", () => {
116
+ // NOT-278: the developer's deck surface is the full one — exactly one required server, no
117
+ // allowlist claims even when enforcement is proven (the enforced-core copy below proves it).
118
+ test("developer: the full assigned Agent Deck surface, sandbox on, no unrestricted flags", () => {
91
119
  const fx = fixture();
92
120
  const attempt = prepareMuseAttempt(input(fx, "developer"));
93
121
  try {
@@ -102,11 +130,11 @@ test("developer: only the assigned Agent Deck surface, sandbox on, no unrestrict
102
130
  "x-agent-deck-deck-id": "deck-123",
103
131
  "x-agent-deck-workspace": fs.realpathSync(fx.worktree),
104
132
  });
105
- assert.deepEqual(server.enabled_tools, ["get_bound_deck", "get_playbook", "list_service_tools", "bind_workspace"]);
106
- assert.deepEqual(server.disabled_tools, ["call_service_tool"]);
133
+ assert.equal("enabled_tools" in server, false, "developers are unfiltered: no allowlist claim");
134
+ assert.equal("disabled_tools" in server, false, "developers are unfiltered: no denylist claim");
107
135
  assert.deepEqual(onDisk.run, { workflow_trigger_mode: "off", subagent_delegation_mode: "off" });
108
136
  for (const tool of ["cron_create", "cron_list", "cron_delete"]) {
109
- assert.deepEqual(onDisk.runtime_capabilities[`tool:${tool}`], { enabled: false });
137
+ assert.equal(`tool:${tool}` in onDisk.runtime_capabilities, false, tool);
110
138
  }
111
139
  const flag = (f) => attempt.argv[attempt.argv.indexOf(f) + 1];
112
140
  assert.equal(attempt.argv[0], "exec");
@@ -130,16 +158,21 @@ test("developer: only the assigned Agent Deck surface, sandbox on, no unrestrict
130
158
  attempt.cleanup();
131
159
  }
132
160
  });
133
- test("reviewer: read-only flags and the same deck reads, mutation denied", () => {
161
+ test("reviewer: read-only flags and the allowlisted deck reads, mutation denied", () => {
134
162
  const fx = fixture();
135
163
  const attempt = prepareMuseAttempt(input(fx, "reviewer"));
136
164
  try {
137
165
  assert.ok(attempt.argv.includes("--disable-write"));
138
166
  assert.ok(attempt.argv.includes("--disable-shell"));
139
167
  const server = attempt.settings.mcpServers["agent-deck"];
168
+ assert.deepEqual(server.enabled_tools, ["get_bound_deck", "get_playbook", "list_service_tools", "bind_workspace"]);
140
169
  assert.equal(server.enabled_tools?.includes("call_service_tool"), false);
141
170
  assert.deepEqual(server.disabled_tools, ["call_service_tool"]);
142
171
  assert.deepEqual(Object.keys(attempt.settings.mcpServers), ["agent-deck"]);
172
+ for (const tool of ["cron_create", "cron_list", "cron_delete"]) {
173
+ assert.deepEqual(attempt.settings.runtime_capabilities[`tool:${tool}`], { enabled: false }, tool);
174
+ }
175
+ assert.doesNotThrow(() => attempt.verify());
143
176
  }
144
177
  finally {
145
178
  attempt.cleanup();
@@ -219,6 +252,53 @@ test("ambient Muse config, env, and workspace files cannot expand the attempt",
219
252
  }
220
253
  assert.equal(fs.readFileSync(ambientSettings, "utf8"), ambientBody);
221
254
  });
255
+ test("test-only FAKE_MUSE_* harness vars reach the child; credentials and unrelated vars do not", () => {
256
+ const fx = fixture();
257
+ const attempt = prepareMuseAttempt(input(fx, "developer", {
258
+ env: {
259
+ PATH: "/usr/bin",
260
+ HOME: os.homedir(),
261
+ MUSE_CLI: "/operator/fake-muse.mjs",
262
+ META_API_KEY: API_KEY,
263
+ MUSE_SENTINEL: "must-not-reach-child",
264
+ CODEX_HOME: "/operator/codex",
265
+ DEALER_MUSE_SENTINEL: "must-not-reach-child",
266
+ FAKE_MUSE_SCENARIO: "success",
267
+ FAKE_MUSE_RECORD: "/tmp/record.json",
268
+ },
269
+ }));
270
+ try {
271
+ // The fake fixture (selected via MUSE_CLI) is driven by FAKE_MUSE_*; they join
272
+ // attempt.env only under that override, so the pre-spawn verify() snapshot covers them.
273
+ assert.equal(attempt.env.FAKE_MUSE_SCENARIO, "success");
274
+ assert.equal(attempt.env.FAKE_MUSE_RECORD, "/tmp/record.json");
275
+ assert.doesNotThrow(() => attempt.verify({ cwd: attempt.cwd, argv: [...attempt.argv], env: { ...attempt.env }, stdin: attempt.stdin }));
276
+ for (const dropped of ["META_API_KEY", "MUSE_SENTINEL", "CODEX_HOME", "DEALER_MUSE_SENTINEL"]) {
277
+ assert.equal(dropped in attempt.env, false, dropped);
278
+ }
279
+ }
280
+ finally {
281
+ attempt.cleanup();
282
+ }
283
+ });
284
+ test("FAKE_MUSE_* harness vars never reach the default real binary (no MUSE_CLI override)", () => {
285
+ const fx = fixture();
286
+ const attempt = prepareMuseAttempt(input(fx, "developer", {
287
+ env: {
288
+ PATH: "/usr/bin",
289
+ HOME: os.homedir(),
290
+ FAKE_MUSE_SCENARIO: "success",
291
+ FAKE_MUSE_RECORD: "/tmp/record.json",
292
+ },
293
+ }));
294
+ try {
295
+ assert.equal("FAKE_MUSE_SCENARIO" in attempt.env, false);
296
+ assert.equal("FAKE_MUSE_RECORD" in attempt.env, false);
297
+ }
298
+ finally {
299
+ attempt.cleanup();
300
+ }
301
+ });
222
302
  test("required Agent Deck server: optional mode, bad url, and missing identity fail before spawn", () => {
223
303
  const fx = fixture();
224
304
  const attempt = prepareMuseAttempt(input(fx, "developer"));
@@ -400,11 +480,23 @@ test("api key never reaches argv, env, disk, or error text; redact scrubs it", (
400
480
  finally {
401
481
  attempt.cleanup();
402
482
  }
403
- for (const over of [{ sessionId: "bad" }, { prompt: "-x" }, {}]) {
483
+ for (const over of [{ sessionId: "bad" }, { prompt: "-x" }]) {
484
+ try {
485
+ prepareMuseAttempt(input(fx, "developer", { credential: { kind: "api-key", apiKey: API_KEY }, ...over }));
486
+ assert.fail("expected refusal");
487
+ }
488
+ catch (err) {
489
+ assert.ok(err instanceof Error && err.name === "MuseIsolationError");
490
+ assert.ok(!err.message.includes(API_KEY));
491
+ assert.ok(!String(err.stack).includes(API_KEY));
492
+ }
493
+ }
494
+ // The pinned entry point admits developers too: a valid api-key input succeeds there as well,
495
+ // and its errors never carry the key either.
496
+ {
497
+ let created;
404
498
  try {
405
- // The `{}` case goes through the pinned entry point, which refuses on NOT-177 evidence.
406
- const prepare = Object.keys(over).length === 0 ? prepareMuseAttemptPinned : prepareMuseAttempt;
407
- prepare(input(fx, "developer", { credential: { kind: "api-key", apiKey: API_KEY }, ...over }));
499
+ created = prepareMuseAttemptPinned(input(fx, "developer", { credential: { kind: "api-key", apiKey: API_KEY }, sessionId: "bad" }));
408
500
  assert.fail("expected refusal");
409
501
  }
410
502
  catch (err) {
@@ -412,16 +504,30 @@ test("api key never reaches argv, env, disk, or error text; redact scrubs it", (
412
504
  assert.ok(!err.message.includes(API_KEY));
413
505
  assert.ok(!String(err.stack).includes(API_KEY));
414
506
  }
507
+ finally {
508
+ created?.cleanup();
509
+ }
415
510
  }
416
511
  assert.deepEqual(fs.readdirSync(fx.baseDir), []);
417
512
  });
418
513
  test("callers cannot supply enforcement evidence: an injected evidence field is ignored", () => {
419
- for (const role of ["developer", "reviewer"]) {
420
- const fx = fixture();
421
- const forged = { ...input(fx, role), evidence: ENFORCED };
422
- assert.equal(code(() => prepareMuseAttemptPinned(forged)), "unenforceable_restriction", role);
423
- assert.deepEqual(fs.readdirSync(fx.baseDir), []);
514
+ // The pinned entry point ignores the forged field: the developer is still admitted unfiltered.
515
+ const fx = fixture();
516
+ const forged = { ...input(fx, "developer"), evidence: ENFORCED };
517
+ const attempt = prepareMuseAttemptPinned(forged);
518
+ try {
519
+ assert.equal("enabled_tools" in attempt.settings.mcpServers["agent-deck"], false);
520
+ assert.equal("disabled_tools" in attempt.settings.mcpServers["agent-deck"], false);
521
+ assert.doesNotThrow(() => attempt.verify());
522
+ }
523
+ finally {
524
+ attempt.cleanup();
424
525
  }
526
+ // ... and the reviewer is still refused.
527
+ const fxReviewer = fixture();
528
+ const forgedReviewer = { ...input(fxReviewer, "reviewer"), evidence: ENFORCED };
529
+ assert.equal(code(() => prepareMuseAttemptPinned(forgedReviewer)), "unenforceable_restriction");
530
+ assert.deepEqual(fs.readdirSync(fxReviewer.baseDir), []);
425
531
  });
426
532
  test("launch contract: cwd is the real worktree and argv/env/cwd/stdin must match exactly", () => {
427
533
  const fx = fixture();
@@ -501,10 +607,10 @@ test("no runtime export can produce a launchable attempt from caller-supplied ev
501
607
  assert.equal(value.length, 1, `${mod}#${name}`);
502
608
  }
503
609
  }
504
- // The pinned core cannot be talked into success with a forged evidence argument or field.
610
+ // The pinned core cannot be talked into reviewer success with a forged evidence argument or field.
505
611
  const core = (await import("./muse-config-core.js"));
506
612
  const fx = fixture();
507
- const forged = () => core.prepareMuseAttempt(input(fx, "developer"), ENFORCED);
613
+ const forged = () => core.prepareMuseAttempt(input(fx, "reviewer"), ENFORCED);
508
614
  assert.equal(code(forged), "unenforceable_restriction");
509
615
  assert.deepEqual(fs.readdirSync(fx.baseDir), []);
510
616
  });
@@ -71,10 +71,24 @@ export async function spawnCli(runId, cmd, args, cwd, opts) {
71
71
  cwd,
72
72
  // Extra vars (e.g. codex's bearer-token env var for its per-attempt CODEX_HOME
73
73
  // MCP config, agent-deck-bind.ts) are added on top of, never in place of, the
74
- // process env the CLI itself needs to run.
75
- env: { ...process.env, ...opts.env },
76
- stdio: ["ignore", "pipe", "pipe"],
74
+ // process env the CLI itself needs to run — unless the caller asked for the exact
75
+ // environment (NOT-278: the Muse exec lane's approved attempt.env, stdin key).
76
+ env: opts.exactEnv ? { ...opts.env } : { ...process.env, ...opts.env },
77
+ stdio: opts.stdin === undefined ? ["ignore", "pipe", "pipe"] : ["pipe", "pipe", "pipe"],
77
78
  });
79
+ // NOT-278: the stdin payload (Muse API key) is written once and closed right after
80
+ // spawn. It never reaches the log stream, the transcript, or any error below.
81
+ if (opts.stdin !== undefined) {
82
+ const payload = opts.stdin;
83
+ const stdin = child.stdin;
84
+ if (stdin) {
85
+ stdin.on("error", () => {
86
+ // The child exited before reading (e.g. instant spawn error) — the 'error'/'close'
87
+ // handlers below still settle the promise; a broken pipe must not throw here.
88
+ });
89
+ stdin.end(payload);
90
+ }
91
+ }
78
92
  registerChild(runId, child, opts.logPath);
79
93
  // Best-effort bookkeeping: a throwing callback must never take down the spawn.
80
94
  if (child.pid !== undefined) {
@@ -157,3 +157,62 @@ test("spawnCli runs normally when an un-aborted signal is supplied", { timeout:
157
157
  assert.equal(result.timedOut, false);
158
158
  assert.match(result.transcript, /untouched/);
159
159
  });
160
+ // NOT-278: the Muse exec lane passes the approved attempt.env exactly — ambient
161
+ // META_API_KEY, MUSE_*, CODEX_HOME, and unrelated variables must not reach the child.
162
+ test("spawnCli exactEnv delivers only the supplied environment", async () => {
163
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "dealer-spawn-cli-"));
164
+ const logPath = path.join(dir, "out.ndjson");
165
+ process.env.DEALER_SPAWN_CLI_AMBIENT_PROBE = "ambient-leaks";
166
+ process.env.MUSE_PROBE_SHOULD_NOT_ARRIVE = "1";
167
+ try {
168
+ const result = await spawnCli("test-run-exact-env", process.execPath, ["-e", "console.log(JSON.stringify(process.env))"], process.cwd(), { logPath, timeoutMs: 5000, env: { EXACT_ONLY: "yes" }, exactEnv: true });
169
+ assert.equal(result.exitCode, 0);
170
+ const childEnv = JSON.parse(result.transcript);
171
+ assert.equal(childEnv.EXACT_ONLY, "yes");
172
+ assert.equal("DEALER_SPAWN_CLI_AMBIENT_PROBE" in childEnv, false);
173
+ assert.equal("MUSE_PROBE_SHOULD_NOT_ARRIVE" in childEnv, false);
174
+ assert.equal("META_API_KEY" in childEnv, false);
175
+ for (const key of Object.keys(childEnv)) {
176
+ assert.equal(key.startsWith("MUSE_"), false, key);
177
+ assert.equal(key.startsWith("CODEX_"), false, key);
178
+ }
179
+ }
180
+ finally {
181
+ delete process.env.DEALER_SPAWN_CLI_AMBIENT_PROBE;
182
+ delete process.env.MUSE_PROBE_SHOULD_NOT_ARRIVE;
183
+ }
184
+ });
185
+ test("spawnCli merges process.env by default (existing callers unchanged)", async () => {
186
+ const logPath = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "dealer-spawn-cli-")), "out.ndjson");
187
+ process.env.DEALER_SPAWN_CLI_AMBIENT_PROBE = "ambient-present";
188
+ try {
189
+ const result = await spawnCli("test-run-merged-env", process.execPath, ["-e", "console.log(`${process.env.DEALER_SPAWN_CLI_AMBIENT_PROBE}|${process.env.MERGED_ONLY}`)"], process.cwd(), { logPath, timeoutMs: 5000, env: { MERGED_ONLY: "yes" } });
190
+ assert.equal(result.exitCode, 0);
191
+ assert.match(result.transcript, /ambient-present\|yes/);
192
+ }
193
+ finally {
194
+ delete process.env.DEALER_SPAWN_CLI_AMBIENT_PROBE;
195
+ }
196
+ });
197
+ // NOT-278: the Muse API key travels on stdin only — written once, closed, never logged.
198
+ test("spawnCli stdin payload is delivered on stdin and never logged", async () => {
199
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "dealer-spawn-cli-"));
200
+ const logPath = path.join(dir, "out.ndjson");
201
+ const secret = `mk-test-secret-${Date.now()}`;
202
+ const result = await spawnCli("test-run-stdin", process.execPath, ["-e", "let b='';process.stdin.on('data',c=>b+=c).on('end',()=>console.log('got:'+b.length))"], process.cwd(), { logPath, timeoutMs: 5000, stdin: `${secret}\n` });
203
+ assert.equal(result.exitCode, 0);
204
+ assert.match(result.transcript, new RegExp(`got:${secret.length + 1}`));
205
+ const logged = fs.readFileSync(logPath, "utf8");
206
+ assert.equal(logged.includes(secret), false);
207
+ assert.equal(result.transcript.includes(secret), false);
208
+ });
209
+ test("spawnCli stdin close on an instantly-exiting child still settles", async () => {
210
+ const logPath = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "dealer-spawn-cli-")), "out.ndjson");
211
+ const result = await spawnCli("test-run-stdin-early-exit", process.execPath, ["-e", "process.exit(3)"], process.cwd(), {
212
+ logPath,
213
+ timeoutMs: 5000,
214
+ stdin: "payload-that-nobody-reads\n",
215
+ });
216
+ assert.equal(result.exitCode, 3);
217
+ assert.equal(result.timedOut, false);
218
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-dealer/server",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -22,7 +22,7 @@
22
22
  "typecheck": "tsc --noEmit"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-dealer/shared": "1.2.5",
25
+ "@agent-dealer/shared": "1.2.7",
26
26
  "@fastify/cors": "^11.0.1",
27
27
  "@fastify/static": "^8.2.0",
28
28
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;400;600;700;800&display=swap";/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:Monaco, "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:Monaco, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-950:oklch(25.8% .092 26.042);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-emerald-400:oklch(76.5% .177 163.223);--color-teal-200:oklch(91% .096 180.426);--color-cyan-500:oklch(71.5% .143 215.221);--color-blue-500:oklch(62.3% .214 259.815);--color-pink-500:oklch(65.6% .241 354.308);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-3xl:48rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--radius-lg:.5rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--font-ui-display:"Avenir Next", Avenir, "Helvetica Neue", system-ui, sans-serif;--color-cyber-gold:#c4b643;--color-cyber-teal:#92e4dd;--color-cyber-violet:#a78bfa;--color-cyber-violet-light:#d4bcff;--color-panel-elevated:#161612;--glass-blur:14px;--glass-bg:#ffffff07;--glass-border:#ffffff13;--glass-highlight:#ffffff0a}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{top:0;right:0;bottom:0;left:0}.top-1\/2{top:50%}.top-16{top:calc(var(--spacing) * 16)}.right-12{right:calc(var(--spacing) * 12)}.bottom-20{bottom:calc(var(--spacing) * 20)}.left-1\/2{left:50%}.left-12{left:calc(var(--spacing) * 12)}.z-0{z-index:0}.z-10{z-index:10}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-\[22rem\]{height:22rem}.h-\[26rem\]{height:26rem}.h-\[70\%\]{height:70%}.max-h-64{max-height:calc(var(--spacing) * 64)}.min-h-0{min-height:0}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-40{width:calc(var(--spacing) * 40)}.w-\[22rem\]{width:22rem}.w-\[26rem\]{width:26rem}.w-\[70\%\]{width:70%}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[10rem\]{max-width:10rem}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:0}.min-w-\[560px\]{min-width:560px}.min-w-\[1440px\]{min-width:1440px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-1\.5{column-gap:calc(var(--spacing) * 1.5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-white\/5>:not(:last-child)){border-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){:where(.divide-white\/5>:not(:last-child)){border-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.self-center{align-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-\[\#92E4DD\]\/25{border-color:#92e4dd40}.border-\[\#C4B643\]\/40{border-color:#c4b64366}.border-\[\#C4B643\]\/50{border-color:#c4b64380}.border-amber-300\/30{border-color:#ffd2364d}@supports (color:color-mix(in lab,red,red)){.border-amber-300\/30{border-color:color-mix(in oklab,var(--color-amber-300) 30%,transparent)}}.border-amber-400\/30{border-color:#fcbb004d}@supports (color:color-mix(in lab,red,red)){.border-amber-400\/30{border-color:color-mix(in oklab,var(--color-amber-400) 30%,transparent)}}.border-amber-400\/40{border-color:#fcbb0066}@supports (color:color-mix(in lab,red,red)){.border-amber-400\/40{border-color:color-mix(in oklab,var(--color-amber-400) 40%,transparent)}}.border-cyber-gold\/40{border-color:#c4b64366}@supports (color:color-mix(in lab,red,red)){.border-cyber-gold\/40{border-color:color-mix(in oklab,var(--color-cyber-gold) 40%,transparent)}}.border-cyber-teal\/20{border-color:#92e4dd33}@supports (color:color-mix(in lab,red,red)){.border-cyber-teal\/20{border-color:color-mix(in oklab,var(--color-cyber-teal) 20%,transparent)}}.border-cyber-teal\/25{border-color:#92e4dd40}@supports (color:color-mix(in lab,red,red)){.border-cyber-teal\/25{border-color:color-mix(in oklab,var(--color-cyber-teal) 25%,transparent)}}.border-cyber-teal\/30{border-color:#92e4dd4d}@supports (color:color-mix(in lab,red,red)){.border-cyber-teal\/30{border-color:color-mix(in oklab,var(--color-cyber-teal) 30%,transparent)}}.border-cyber-teal\/35{border-color:#92e4dd59}@supports (color:color-mix(in lab,red,red)){.border-cyber-teal\/35{border-color:color-mix(in oklab,var(--color-cyber-teal) 35%,transparent)}}.border-cyber-teal\/40{border-color:#92e4dd66}@supports (color:color-mix(in lab,red,red)){.border-cyber-teal\/40{border-color:color-mix(in oklab,var(--color-cyber-teal) 40%,transparent)}}.border-cyber-violet\/40{border-color:#a78bfa66}@supports (color:color-mix(in lab,red,red)){.border-cyber-violet\/40{border-color:color-mix(in oklab,var(--color-cyber-violet) 40%,transparent)}}.border-cyber-violet\/50{border-color:#a78bfa80}@supports (color:color-mix(in lab,red,red)){.border-cyber-violet\/50{border-color:color-mix(in oklab,var(--color-cyber-violet) 50%,transparent)}}.border-red-300\/40{border-color:#ffa3a366}@supports (color:color-mix(in lab,red,red)){.border-red-300\/40{border-color:color-mix(in oklab,var(--color-red-300) 40%,transparent)}}.border-red-400\/20{border-color:#ff656833}@supports (color:color-mix(in lab,red,red)){.border-red-400\/20{border-color:color-mix(in oklab,var(--color-red-400) 20%,transparent)}}.border-red-400\/30{border-color:#ff65684d}@supports (color:color-mix(in lab,red,red)){.border-red-400\/30{border-color:color-mix(in oklab,var(--color-red-400) 30%,transparent)}}.border-red-400\/40{border-color:#ff656866}@supports (color:color-mix(in lab,red,red)){.border-red-400\/40{border-color:color-mix(in oklab,var(--color-red-400) 40%,transparent)}}.border-red-400\/50{border-color:#ff656880}@supports (color:color-mix(in lab,red,red)){.border-red-400\/50{border-color:color-mix(in oklab,var(--color-red-400) 50%,transparent)}}.border-white\/5{border-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.border-white\/5{border-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.border-white\/10{border-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.border-white\/10{border-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.border-white\/15{border-color:#ffffff26}@supports (color:color-mix(in lab,red,red)){.border-white\/15{border-color:color-mix(in oklab,var(--color-white) 15%,transparent)}}.border-white\/20{border-color:#fff3}@supports (color:color-mix(in lab,red,red)){.border-white\/20{border-color:color-mix(in oklab,var(--color-white) 20%,transparent)}}.bg-\[\#92E4DD\]\/10{background-color:#92e4dd1a}.bg-\[\#C4B643\]\/5{background-color:#c4b6430d}.bg-\[\#C4B643\]\/25{background-color:#c4b64340}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-400\/5{background-color:#fcbb000d}@supports (color:color-mix(in lab,red,red)){.bg-amber-400\/5{background-color:color-mix(in oklab,var(--color-amber-400) 5%,transparent)}}.bg-amber-400\/10{background-color:#fcbb001a}@supports (color:color-mix(in lab,red,red)){.bg-amber-400\/10{background-color:color-mix(in oklab,var(--color-amber-400) 10%,transparent)}}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/10{background-color:color-mix(in oklab,var(--color-amber-500) 10%,transparent)}}.bg-amber-500\/20{background-color:#f99c0033}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/20{background-color:color-mix(in oklab,var(--color-amber-500) 20%,transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab,red,red)){.bg-black\/20{background-color:color-mix(in oklab,var(--color-black) 20%,transparent)}}.bg-black\/30{background-color:#0000004d}@supports (color:color-mix(in lab,red,red)){.bg-black\/30{background-color:color-mix(in oklab,var(--color-black) 30%,transparent)}}.bg-blue-500\/\[0\.07\]{background-color:#3080ff12}@supports (color:color-mix(in lab,red,red)){.bg-blue-500\/\[0\.07\]{background-color:color-mix(in oklab,var(--color-blue-500) 7%,transparent)}}.bg-cyan-500\/10{background-color:#00b7d71a}@supports (color:color-mix(in lab,red,red)){.bg-cyan-500\/10{background-color:color-mix(in oklab,var(--color-cyan-500) 10%,transparent)}}.bg-cyber-gold\/20{background-color:#c4b64333}@supports (color:color-mix(in lab,red,red)){.bg-cyber-gold\/20{background-color:color-mix(in oklab,var(--color-cyber-gold) 20%,transparent)}}.bg-cyber-teal{background-color:var(--color-cyber-teal)}.bg-cyber-teal\/5{background-color:#92e4dd0d}@supports (color:color-mix(in lab,red,red)){.bg-cyber-teal\/5{background-color:color-mix(in oklab,var(--color-cyber-teal) 5%,transparent)}}.bg-cyber-teal\/10{background-color:#92e4dd1a}@supports (color:color-mix(in lab,red,red)){.bg-cyber-teal\/10{background-color:color-mix(in oklab,var(--color-cyber-teal) 10%,transparent)}}.bg-cyber-teal\/15{background-color:#92e4dd26}@supports (color:color-mix(in lab,red,red)){.bg-cyber-teal\/15{background-color:color-mix(in oklab,var(--color-cyber-teal) 15%,transparent)}}.bg-cyber-teal\/20{background-color:#92e4dd33}@supports (color:color-mix(in lab,red,red)){.bg-cyber-teal\/20{background-color:color-mix(in oklab,var(--color-cyber-teal) 20%,transparent)}}.bg-cyber-violet\/10{background-color:#a78bfa1a}@supports (color:color-mix(in lab,red,red)){.bg-cyber-violet\/10{background-color:color-mix(in oklab,var(--color-cyber-violet) 10%,transparent)}}.bg-cyber-violet\/20{background-color:#a78bfa33}@supports (color:color-mix(in lab,red,red)){.bg-cyber-violet\/20{background-color:color-mix(in oklab,var(--color-cyber-violet) 20%,transparent)}}.bg-cyber-violet\/25{background-color:#a78bfa40}@supports (color:color-mix(in lab,red,red)){.bg-cyber-violet\/25{background-color:color-mix(in oklab,var(--color-cyber-violet) 25%,transparent)}}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-panel-elevated\/40{background-color:#16161266}@supports (color:color-mix(in lab,red,red)){.bg-panel-elevated\/40{background-color:color-mix(in oklab,var(--color-panel-elevated) 40%,transparent)}}.bg-panel-elevated\/60{background-color:#16161299}@supports (color:color-mix(in lab,red,red)){.bg-panel-elevated\/60{background-color:color-mix(in oklab,var(--color-panel-elevated) 60%,transparent)}}.bg-pink-500\/10{background-color:#f6339a1a}@supports (color:color-mix(in lab,red,red)){.bg-pink-500\/10{background-color:color-mix(in oklab,var(--color-pink-500) 10%,transparent)}}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/10{background-color:color-mix(in oklab,var(--color-red-500) 10%,transparent)}}.bg-red-500\/15{background-color:#fb2c3626}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/15{background-color:color-mix(in oklab,var(--color-red-500) 15%,transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.bg-red-500\/20{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.bg-transparent{background-color:#0000}.bg-white\/5{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.bg-white\/5{background-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.bg-white\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.bg-white\/10{background-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.bg-white\/\[0\.02\]{background-color:#ffffff05}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.02\]{background-color:color-mix(in oklab,var(--color-white) 2%,transparent)}}.bg-white\/\[0\.03\]{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.03\]{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.bg-white\/\[0\.04\]{background-color:#ffffff0a}@supports (color:color-mix(in lab,red,red)){.bg-white\/\[0\.04\]{background-color:color-mix(in oklab,var(--color-white) 4%,transparent)}}.object-contain{object-fit:contain}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-12{padding-left:calc(var(--spacing) * 12)}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-ui-display{font-family:var(--font-ui-display)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#92E4DD\]{color:#92e4dd}.text-\[\#92E4DD\]\/80{color:#92e4ddcc}.text-\[\#A8C4C0\]{color:#a8c4c0}.text-\[\#C4B643\]{color:#c4b643}.text-\[\#E8DC7A\]{color:#e8dc7a}.text-\[\#E8F6F4\]{color:#e8f6f4}.text-amber-100{color:var(--color-amber-100)}.text-amber-100\/80{color:#fef3c6cc}@supports (color:color-mix(in lab,red,red)){.text-amber-100\/80{color:color-mix(in oklab,var(--color-amber-100) 80%,transparent)}}.text-amber-200\/80{color:#fee685cc}@supports (color:color-mix(in lab,red,red)){.text-amber-200\/80{color:color-mix(in oklab,var(--color-amber-200) 80%,transparent)}}.text-amber-200\/90{color:#fee685e6}@supports (color:color-mix(in lab,red,red)){.text-amber-200\/90{color:color-mix(in oklab,var(--color-amber-200) 90%,transparent)}}.text-amber-300{color:var(--color-amber-300)}.text-amber-300\/80{color:#ffd236cc}@supports (color:color-mix(in lab,red,red)){.text-amber-300\/80{color:color-mix(in oklab,var(--color-amber-300) 80%,transparent)}}.text-amber-300\/90{color:#ffd236e6}@supports (color:color-mix(in lab,red,red)){.text-amber-300\/90{color:color-mix(in oklab,var(--color-amber-300) 90%,transparent)}}.text-cyber-teal{color:var(--color-cyber-teal)}.text-cyber-violet-light{color:var(--color-cyber-violet-light)}.text-red-100{color:var(--color-red-100)}.text-red-200{color:var(--color-red-200)}.text-red-300{color:var(--color-red-300)}.text-red-300\/80{color:#ffa3a3cc}@supports (color:color-mix(in lab,red,red)){.text-red-300\/80{color:color-mix(in oklab,var(--color-red-300) 80%,transparent)}}.text-red-300\/90{color:#ffa3a3e6}@supports (color:color-mix(in lab,red,red)){.text-red-300\/90{color:color-mix(in oklab,var(--color-red-300) 90%,transparent)}}.text-red-400{color:var(--color-red-400)}.text-teal-200\/80{color:#96f7e4cc}@supports (color:color-mix(in lab,red,red)){.text-teal-200\/80{color:color-mix(in oklab,var(--color-teal-200) 80%,transparent)}}.text-white{color:var(--color-white)}.text-white\/25{color:#ffffff40}@supports (color:color-mix(in lab,red,red)){.text-white\/25{color:color-mix(in oklab,var(--color-white) 25%,transparent)}}.text-white\/30{color:#ffffff4d}@supports (color:color-mix(in lab,red,red)){.text-white\/30{color:color-mix(in oklab,var(--color-white) 30%,transparent)}}.text-white\/35{color:#ffffff59}@supports (color:color-mix(in lab,red,red)){.text-white\/35{color:color-mix(in oklab,var(--color-white) 35%,transparent)}}.text-white\/40{color:#fff6}@supports (color:color-mix(in lab,red,red)){.text-white\/40{color:color-mix(in oklab,var(--color-white) 40%,transparent)}}.text-white\/45{color:#ffffff73}@supports (color:color-mix(in lab,red,red)){.text-white\/45{color:color-mix(in oklab,var(--color-white) 45%,transparent)}}.text-white\/50{color:#ffffff80}@supports (color:color-mix(in lab,red,red)){.text-white\/50{color:color-mix(in oklab,var(--color-white) 50%,transparent)}}.text-white\/55{color:#ffffff8c}@supports (color:color-mix(in lab,red,red)){.text-white\/55{color:color-mix(in oklab,var(--color-white) 55%,transparent)}}.text-white\/60{color:#fff9}@supports (color:color-mix(in lab,red,red)){.text-white\/60{color:color-mix(in oklab,var(--color-white) 60%,transparent)}}.text-white\/70{color:#ffffffb3}@supports (color:color-mix(in lab,red,red)){.text-white\/70{color:color-mix(in oklab,var(--color-white) 70%,transparent)}}.text-white\/75{color:#ffffffbf}@supports (color:color-mix(in lab,red,red)){.text-white\/75{color:color-mix(in oklab,var(--color-white) 75%,transparent)}}.text-white\/80{color:#fffc}@supports (color:color-mix(in lab,red,red)){.text-white\/80{color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.text-white\/85{color:#ffffffd9}@supports (color:color-mix(in lab,red,red)){.text-white\/85{color:color-mix(in oklab,var(--color-white) 85%,transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab,red,red)){.text-white\/90{color:color-mix(in oklab,var(--color-white) 90%,transparent)}}.text-yellow-300{color:var(--color-yellow-300)}.text-yellow-400{color:var(--color-yellow-400)}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.accent-\[\#C4B643\]{accent-color:#c4b643}.opacity-80{opacity:.8}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.placeholder\:text-white\/30::placeholder{color:#ffffff4d}@supports (color:color-mix(in lab,red,red)){.placeholder\:text-white\/30::placeholder{color:color-mix(in oklab,var(--color-white) 30%,transparent)}}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media(hover:hover){.hover\:border-cyber-teal\/50:hover{border-color:#92e4dd80}@supports (color:color-mix(in lab,red,red)){.hover\:border-cyber-teal\/50:hover{border-color:color-mix(in oklab,var(--color-cyber-teal) 50%,transparent)}}.hover\:bg-cyber-teal\/10:hover{background-color:#92e4dd1a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-cyber-teal\/10:hover{background-color:color-mix(in oklab,var(--color-cyber-teal) 10%,transparent)}}.hover\:bg-panel-elevated\/70:hover{background-color:#161612b3}@supports (color:color-mix(in lab,red,red)){.hover\:bg-panel-elevated\/70:hover{background-color:color-mix(in oklab,var(--color-panel-elevated) 70%,transparent)}}.hover\:bg-red-500\/20:hover{background-color:#fb2c3633}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-500\/20:hover{background-color:color-mix(in oklab,var(--color-red-500) 20%,transparent)}}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}.hover\:text-cyber-teal:hover{color:var(--color-cyber-teal)}.hover\:text-red-300:hover{color:var(--color-red-300)}.hover\:text-white:hover{color:var(--color-white)}.hover\:text-white\/70:hover{color:#ffffffb3}@supports (color:color-mix(in lab,red,red)){.hover\:text-white\/70:hover{color:color-mix(in oklab,var(--color-white) 70%,transparent)}}.hover\:text-white\/80:hover{color:#fffc}@supports (color:color-mix(in lab,red,red)){.hover\:text-white\/80:hover{color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-cyber-teal\/45:focus-visible{outline-color:#92e4dd73}@supports (color:color-mix(in lab,red,red)){.focus-visible\:outline-cyber-teal\/45:focus-visible{outline-color:color-mix(in oklab,var(--color-cyber-teal) 45%,transparent)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media(min-width:40rem){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:justify-between{justify-content:space-between}.sm\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.sm\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media(min-width:64rem){.lg\:col-span-4{grid-column:span 4/span 4}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:80rem){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}}@font-face{font-family:Monaco;font-style:normal;font-weight:400;font-display:block;src:url(/fonts/Monaco.ttf)format("truetype")}html{font-size:17px}html,body{font-family:var(--font-sans)}body{color:#92e4dd;-webkit-font-smoothing:antialiased;background-color:#0a0a07;min-height:100vh;margin:0;font-size:1rem;line-height:1.5}@keyframes ambient-drift-a{0%,to{opacity:1;transform:translate(0)scale(1)}50%{opacity:.72;transform:translate(28px,-22px)scale(1.06)}}@keyframes ambient-drift-b{0%,to{opacity:1;transform:translate(0)scale(1)}50%{opacity:.75;transform:translate(-24px,18px)scale(1.05)}}@keyframes ambient-drift-c{0%,to{opacity:1;transform:translate(0)scale(1)}50%{opacity:.68;transform:translate(16px,20px)scale(.96)}}.ambient-orb{will-change:transform,opacity}.ambient-orb-a{animation:14s ease-in-out infinite ambient-drift-a}.ambient-orb-b{animation:17s ease-in-out -6s infinite ambient-drift-b}.ambient-orb-c{animation:20s ease-in-out -11s infinite ambient-drift-c}.glass-header{-webkit-backdrop-filter:blur(12px);background:#0a0a07b8}.field{border-style:var(--tw-border-style);border-width:1px;border-color:#ffffff1a;border-radius:.25rem;width:100%}@supports (color:color-mix(in lab,red,red)){.field{border-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.field{background-color:#ffffff08}@supports (color:color-mix(in lab,red,red)){.field{background-color:color-mix(in oklab,var(--color-white) 3%,transparent)}}.field{padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:#e8f6f4;--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);font-family:var(--font-mono)}input,select,textarea{font-family:var(--font-mono)}button{font-family:var(--font-ui-display)}.panel{border-radius:var(--radius-2xl);padding:calc(var(--spacing) * 4);background:var(--glass-bg);-webkit-backdrop-filter:blur(var(--glass-blur));border:1px solid var(--glass-border);box-shadow:inset 0 1px 0 var(--glass-highlight)}.btn-gold{padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:#0a0a07;font-family:var(--font-ui-display);background:#c4b643;border-radius:.25rem}.btn-gold:hover{background:#d4c760}.btn-ghost{border-style:var(--tw-border-style);border-width:1px;border-color:#fff3;border-radius:.25rem}@supports (color:color-mix(in lab,red,red)){.btn-ghost{border-color:color-mix(in oklab,var(--color-white) 20%,transparent)}}.btn-ghost{padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));color:#e8f6f4;font-family:var(--font-ui-display)}.btn-ghost-danger{border-style:var(--tw-border-style);border-width:1px;border-color:#fb2c36bf;border-radius:.25rem}@supports (color:color-mix(in lab,red,red)){.btn-ghost-danger{border-color:color-mix(in oklab,var(--color-red-500) 75%,transparent)}}.btn-ghost-danger{background-color:#46080933}@supports (color:color-mix(in lab,red,red)){.btn-ghost-danger{background-color:color-mix(in oklab,var(--color-red-950) 20%,transparent)}}.btn-ghost-danger{padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-red-400);font-family:var(--font-ui-display)}.btn-ghost-danger:hover:not(:disabled){border-color:var(--color-red-400);background-color:#46080966}@supports (color:color-mix(in lab,red,red)){.btn-ghost-danger:hover:not(:disabled){background-color:color-mix(in oklab,var(--color-red-950) 40%,transparent)}}.btn-ghost-danger:hover:not(:disabled){color:var(--color-red-300)}.heading-page{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:#c4b643;font-family:var(--font-ui-display)}.heading-panel{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:#92e4dd;font-family:var(--font-ui-display)}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:#ffffff1a;border-radius:10px}::-webkit-scrollbar-thumb{background:#ffffff4d;border-radius:10px}::-webkit-scrollbar-thumb:hover{background:#ffffff80}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}