@exaudeus/workrail 3.24.4 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/index.d.ts +6 -0
- package/dist/cli/commands/index.js +14 -1
- package/dist/cli/commands/version.d.ts +6 -0
- package/dist/cli/commands/version.js +14 -0
- package/dist/cli/commands/worktrain-await.d.ts +35 -0
- package/dist/cli/commands/worktrain-await.js +207 -0
- package/dist/cli/commands/worktrain-inbox.d.ts +23 -0
- package/dist/cli/commands/worktrain-inbox.js +82 -0
- package/dist/cli/commands/worktrain-init.d.ts +23 -0
- package/dist/cli/commands/worktrain-init.js +338 -0
- package/dist/cli/commands/worktrain-spawn.d.ts +28 -0
- package/dist/cli/commands/worktrain-spawn.js +106 -0
- package/dist/cli/commands/worktrain-tell.d.ts +25 -0
- package/dist/cli/commands/worktrain-tell.js +32 -0
- package/dist/cli-worktrain.d.ts +2 -0
- package/dist/cli-worktrain.js +169 -0
- package/dist/cli.js +100 -0
- package/dist/config/config-file.d.ts +2 -0
- package/dist/config/config-file.js +55 -0
- package/dist/console/assets/index-8dh0Psu-.css +1 -0
- package/dist/console/assets/{index-TMfptYpQ.js → index-HhtarvD5.js} +10 -10
- package/dist/console/index.html +2 -2
- package/dist/daemon/agent-loop.d.ts +90 -0
- package/dist/daemon/agent-loop.js +214 -0
- package/dist/daemon/pi-mono-loader.d.ts +0 -0
- package/dist/daemon/pi-mono-loader.js +1 -0
- package/dist/daemon/soul-template.d.ts +2 -0
- package/dist/daemon/soul-template.js +22 -0
- package/dist/daemon/workflow-runner.d.ts +63 -0
- package/dist/daemon/workflow-runner.js +689 -0
- package/dist/infrastructure/session/HttpServer.js +2 -2
- package/dist/manifest.json +226 -50
- package/dist/mcp/handlers/v2-execution/start.d.ts +2 -1
- package/dist/mcp/handlers/v2-execution/start.js +4 -3
- package/dist/mcp/output-schemas.d.ts +154 -154
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/transports/bridge-entry.js +20 -2
- package/dist/mcp/transports/bridge-events.d.ts +34 -0
- package/dist/mcp/transports/bridge-events.js +24 -0
- package/dist/mcp/transports/fatal-exit.d.ts +5 -0
- package/dist/mcp/transports/fatal-exit.js +82 -0
- package/dist/mcp/transports/http-entry.js +3 -0
- package/dist/mcp/transports/stdio-entry.js +3 -7
- package/dist/mcp/v2/tools.d.ts +7 -7
- package/dist/trigger/delivery-action.d.ts +37 -0
- package/dist/trigger/delivery-action.js +204 -0
- package/dist/trigger/delivery-client.d.ts +11 -0
- package/dist/trigger/delivery-client.js +27 -0
- package/dist/trigger/index.d.ts +5 -0
- package/dist/trigger/index.js +8 -0
- package/dist/trigger/trigger-listener.d.ts +32 -0
- package/dist/trigger/trigger-listener.js +176 -0
- package/dist/trigger/trigger-router.d.ts +38 -0
- package/dist/trigger/trigger-router.js +343 -0
- package/dist/trigger/trigger-store.d.ts +39 -0
- package/dist/trigger/trigger-store.js +698 -0
- package/dist/trigger/types.d.ts +70 -0
- package/dist/trigger/types.js +10 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +22 -22
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +114 -114
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +454 -454
- package/dist/v2/durable-core/schemas/session/blockers.d.ts +14 -14
- package/dist/v2/durable-core/schemas/session/events.d.ts +93 -93
- package/dist/v2/durable-core/schemas/session/gaps.d.ts +2 -2
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +4 -4
- package/dist/v2/infra/in-memory/daemon-registry/index.d.ts +14 -0
- package/dist/v2/infra/in-memory/daemon-registry/index.js +32 -0
- package/dist/v2/infra/in-memory/keyed-async-queue/index.d.ts +5 -0
- package/dist/v2/infra/in-memory/keyed-async-queue/index.js +32 -0
- package/dist/v2/usecases/console-routes.d.ts +3 -1
- package/dist/v2/usecases/console-routes.js +132 -1
- package/dist/v2/usecases/console-service.d.ts +2 -0
- package/dist/v2/usecases/console-service.js +18 -2
- package/dist/v2/usecases/console-types.d.ts +2 -0
- package/package.json +6 -2
- package/spec/workflow-tags.json +1 -0
- package/workflows/classify-task-workflow.json +68 -0
- package/workflows/coding-task-workflow-agentic.lean.v2.json +43 -13
- package/workflows/workflow-for-workflows.json +4 -2
- package/workflows/workflow-for-workflows.v2.json +4 -2
- package/dist/console/assets/index-BXRk3te_.css +0 -1
- package/workflows/rich-object-contribution.json +0 -258
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
{
|
|
23
23
|
"id": "design_soundness",
|
|
24
24
|
"purpose": "Design decision is made, tradeoffs are recorded, and there is no remaining ambiguity about the chosen approach.",
|
|
25
|
-
"levels": [
|
|
25
|
+
"levels": [
|
|
26
|
+
"low",
|
|
27
|
+
"high"
|
|
28
|
+
]
|
|
26
29
|
}
|
|
27
30
|
]
|
|
28
31
|
},
|
|
@@ -33,7 +36,10 @@
|
|
|
33
36
|
{
|
|
34
37
|
"id": "design_gaps",
|
|
35
38
|
"purpose": "Active scan completed: either no material gaps were found, or any found were addressed or explicitly filed.",
|
|
36
|
-
"levels": [
|
|
39
|
+
"levels": [
|
|
40
|
+
"low",
|
|
41
|
+
"high"
|
|
42
|
+
]
|
|
37
43
|
}
|
|
38
44
|
]
|
|
39
45
|
},
|
|
@@ -44,7 +50,10 @@
|
|
|
44
50
|
{
|
|
45
51
|
"id": "plan_completeness",
|
|
46
52
|
"purpose": "Slices have clear boundaries and acceptance criteria. The agent knows what done looks like for each.",
|
|
47
|
-
"levels": [
|
|
53
|
+
"levels": [
|
|
54
|
+
"low",
|
|
55
|
+
"high"
|
|
56
|
+
]
|
|
48
57
|
}
|
|
49
58
|
]
|
|
50
59
|
},
|
|
@@ -55,7 +64,10 @@
|
|
|
55
64
|
{
|
|
56
65
|
"id": "invariant_clarity",
|
|
57
66
|
"purpose": "Named invariants are checkable in the implementation. Non-goals are stated and will prevent scope creep.",
|
|
58
|
-
"levels": [
|
|
67
|
+
"levels": [
|
|
68
|
+
"low",
|
|
69
|
+
"high"
|
|
70
|
+
]
|
|
59
71
|
}
|
|
60
72
|
]
|
|
61
73
|
},
|
|
@@ -66,7 +78,10 @@
|
|
|
66
78
|
{
|
|
67
79
|
"id": "plan_gaps",
|
|
68
80
|
"purpose": "Active scan completed: either no material gaps were found, or any found were addressed or explicitly filed.",
|
|
69
|
-
"levels": [
|
|
81
|
+
"levels": [
|
|
82
|
+
"low",
|
|
83
|
+
"high"
|
|
84
|
+
]
|
|
70
85
|
}
|
|
71
86
|
]
|
|
72
87
|
},
|
|
@@ -77,7 +92,10 @@
|
|
|
77
92
|
{
|
|
78
93
|
"id": "build_correctness",
|
|
79
94
|
"purpose": "Build succeeds and tests pass. No compilation errors or failing assertions.",
|
|
80
|
-
"levels": [
|
|
95
|
+
"levels": [
|
|
96
|
+
"low",
|
|
97
|
+
"high"
|
|
98
|
+
]
|
|
81
99
|
}
|
|
82
100
|
]
|
|
83
101
|
},
|
|
@@ -88,7 +106,10 @@
|
|
|
88
106
|
{
|
|
89
107
|
"id": "invariant_preservation",
|
|
90
108
|
"purpose": "Each named invariant from the plan has been verified in the implementation.",
|
|
91
|
-
"levels": [
|
|
109
|
+
"levels": [
|
|
110
|
+
"low",
|
|
111
|
+
"high"
|
|
112
|
+
]
|
|
92
113
|
}
|
|
93
114
|
]
|
|
94
115
|
},
|
|
@@ -99,7 +120,10 @@
|
|
|
99
120
|
{
|
|
100
121
|
"id": "implementation_gaps",
|
|
101
122
|
"purpose": "Active scan completed: gaps found are either fixed inline, filed as follow-up tickets, or explicitly deferred with rationale.",
|
|
102
|
-
"levels": [
|
|
123
|
+
"levels": [
|
|
124
|
+
"low",
|
|
125
|
+
"high"
|
|
126
|
+
]
|
|
103
127
|
}
|
|
104
128
|
]
|
|
105
129
|
}
|
|
@@ -260,7 +284,9 @@
|
|
|
260
284
|
],
|
|
261
285
|
"assessmentConsequences": [
|
|
262
286
|
{
|
|
263
|
-
"when": {
|
|
287
|
+
"when": {
|
|
288
|
+
"anyEqualsLevel": "low"
|
|
289
|
+
},
|
|
264
290
|
"effect": {
|
|
265
291
|
"kind": "require_followup",
|
|
266
292
|
"guidance": "Address whichever gate scored low: design_soundness low -- the design decision is still ambiguous; commit to an approach and record the rationale before proceeding. design_gaps low -- the gap scan was not completed or found unaddressed gaps; either resolve them or explicitly file them before proceeding."
|
|
@@ -361,7 +387,9 @@
|
|
|
361
387
|
],
|
|
362
388
|
"assessmentConsequences": [
|
|
363
389
|
{
|
|
364
|
-
"when": {
|
|
390
|
+
"when": {
|
|
391
|
+
"anyEqualsLevel": "low"
|
|
392
|
+
},
|
|
365
393
|
"effect": {
|
|
366
394
|
"kind": "require_followup",
|
|
367
395
|
"guidance": "Address whichever gate scored low: plan_completeness low -- one or more slices lack clear boundaries or verifiable acceptance criteria; sharpen them before implementation begins. invariant_clarity low -- invariants or non-goals are too vague to verify against; make them concrete. plan_gaps low -- the gap scan was not completed or found unaddressed gaps; resolve or file them before proceeding."
|
|
@@ -472,7 +500,7 @@
|
|
|
472
500
|
"var": "taskComplexity",
|
|
473
501
|
"equals": "Small"
|
|
474
502
|
},
|
|
475
|
-
"prompt": "For Small tasks:\n-
|
|
503
|
+
"prompt": "For Small tasks, fast does not mean shallow. Every item below is required.\n\n**1. Confirm all wiring points with tools.**\nDon't assume a file you create is reachable. Check every public entry point:\n- Does the new symbol need to be exported from an index file?\n- Does it need to be imported and registered somewhere (CLI command map, router, DI container, plugin registry)?\n- Is there a test file that needs to reference it?\nTrace the full call path from the public interface down to your new code before writing anything.\n\n**2. Implement the smallest correct change.**\nChange exactly what needs changing. No drive-by refactors, no extra abstractions.\n\n**3. Verify end-to-end.**\n- Run build and tests. Both must pass.\n- Manually trace the new behavior through the public entry point (e.g. run the CLI command, check the export resolves, hit the endpoint). If you can't do this deterministically with tools, say why.\n- Apply the user's coding philosophy as the review lens. Flag any violation by principle name.\n\n**4. Produce a handoff note.**\nOutput a notes artifact containing a JSON fenced block with the following fields.\nThe daemon reads this block to run `git commit` and `gh pr create` -- write it exactly as shown:\n\n```json\n{\n \"commitType\": \"feat\",\n \"commitScope\": \"mcp\",\n \"commitSubject\": \"imperative mood, max 72 chars total with type(scope): prefix, no period\",\n \"prTitle\": \"same as full commit first line\",\n \"prBody\": \"markdown with ## Summary (bullets) and ## Test plan (checklist)\",\n \"followUpTickets\": [],\n \"filesChanged\": [\"src/path/to/file.ts\", \"tests/unit/file.test.ts\"]\n}\n```\n\nFields:\n- `commitType`: feat / fix / chore / refactor / docs / test / perf (pick one)\n- `commitScope`: product area only (console / mcp / workflows / engine / schema / docs)\n- `commitSubject`: imperative mood, max 72 chars total with type(scope): prefix, no period\n- `prTitle`: same as full commit first line\n- `prBody`: markdown with ## Summary (bullets) and ## Test plan (checklist)\n- `followUpTickets`: list of deferred items, or empty array\n- `filesChanged`: list of every file you created or modified (required -- do not omit)\n\nThe daemon will use this artifact to run git commit and open the PR. Do not commit or push yourself.\n\nDo not create heavyweight planning artifacts unless risk unexpectedly grows.",
|
|
476
504
|
"requireConfirmation": false
|
|
477
505
|
},
|
|
478
506
|
{
|
|
@@ -594,7 +622,9 @@
|
|
|
594
622
|
],
|
|
595
623
|
"assessmentConsequences": [
|
|
596
624
|
{
|
|
597
|
-
"when": {
|
|
625
|
+
"when": {
|
|
626
|
+
"anyEqualsLevel": "low"
|
|
627
|
+
},
|
|
598
628
|
"effect": {
|
|
599
629
|
"kind": "require_followup",
|
|
600
630
|
"guidance": "Address whichever gate scored low: build_correctness low -- the build or tests are still failing; fix them before this step can complete. invariant_preservation low -- one or more invariants from the plan are violated; fix the implementation. implementation_gaps low -- the gap scan was not completed or found unaddressed gaps; fix them inline, file as follow-up tickets, or explicitly defer with rationale."
|
|
@@ -606,7 +636,7 @@
|
|
|
606
636
|
{
|
|
607
637
|
"id": "phase-7c-loop-decision",
|
|
608
638
|
"title": "Final Verification Loop Decision",
|
|
609
|
-
"prompt": "Decide whether final verification needs another pass or whether we're done.\n\nThis loop gets up to two verify/fix passes.\n- If verification found real issues and you fixed them, keep going so the fixes get re-verified.\n- If the issues are clean or resolved, stop.\n- If you've hit the limit, stop and record what remains.\n\nWhen you stop, include:\n- acceptance criteria status\n- invariant status\n- test/build summary\n- a
|
|
639
|
+
"prompt": "Decide whether final verification needs another pass or whether we're done.\n\nThis loop gets up to two verify/fix passes.\n- If verification found real issues and you fixed them, keep going so the fixes get re-verified.\n- If the issues are clean or resolved, stop.\n- If you've hit the limit, stop and record what remains.\n\nWhen you stop, include:\n- acceptance criteria status\n- invariant status\n- test/build summary\n- follow-up tickets\n- any philosophy tensions you accepted on purpose\n\n**Handoff block (required for daemon auto-commit):**\nInclude a JSON fenced block in your notes. The daemon reads this to run `git commit` and `gh pr create`:\n\n```json\n{\n \"commitType\": \"feat\",\n \"commitScope\": \"mcp\",\n \"commitSubject\": \"imperative mood, max 72 chars total with type(scope): prefix, no period\",\n \"prTitle\": \"same as full commit first line\",\n \"prBody\": \"markdown with ## Summary (bullets) and ## Test plan (checklist)\",\n \"followUpTickets\": [],\n \"filesChanged\": [\"src/path/to/file.ts\", \"tests/unit/file.test.ts\"]\n}\n```\n\nFields: `commitType` (feat/fix/chore/refactor/docs/test/perf), `commitScope` (product area only: console/mcp/workflows/engine/schema/docs), `commitSubject` (imperative, <=72 chars including prefix, no period), `prTitle` (same as commit first line), `prBody` (markdown), `followUpTickets` (array), `filesChanged` (required -- every file created or modified).\n\nThen emit the required loop-control artifact in this shape (`decision` must be `continue` or `stop`):\n```json\n{\n \"artifacts\": [{\n \"kind\": \"wr.loop_control\",\n \"decision\": \"continue\"\n }]\n}\n```",
|
|
610
640
|
"requireConfirmation": true,
|
|
611
641
|
"outputContract": {
|
|
612
642
|
"contractRef": "wr.contracts.loop_control"
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"preconditions": [
|
|
21
21
|
"User has a recurring task or problem a workflow should solve, or an existing workflow that should be modernized.",
|
|
22
22
|
"Agent has access to file creation, editing, and terminal tools.",
|
|
23
|
-
"Agent can run workflow validators such as `npm run validate:registry` or equivalent."
|
|
23
|
+
"Agent can run workflow validators such as `npm run validate:registry` or equivalent.",
|
|
24
|
+
"Write output workflow JSON to ~/.workrail/workflows/<name>.json by default. Only write to a repo's workflows/ dir when the user explicitly asks to contribute a bundled workflow."
|
|
24
25
|
],
|
|
25
26
|
"metaGuidance": [
|
|
26
27
|
"REFERENCE HIERARCHY: treat workflow-schema as legal truth for structure. Treat authoring-spec as canonical current guidance for what makes a workflow good. Treat authoring-provenance as optional maintainer context only.",
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
"ANTI-PATTERNS TO AVOID IN AUTHORED WORKFLOWS: no pseudo-function metaGuidance, no learning-path branching, no satisfaction-score loops, no heavy clarification batteries, no regex-as-primary-validation, no celebration phases.",
|
|
38
39
|
"MODERNIZATION DISTINCTION: remove format problems (pseudo-DSL, regex, A/B phases). Preserve or equivalently replace behavioral mechanisms (forcing functions, hard gates, domain knowledge). Never silently drop a mechanism that prevents a real failure mode.",
|
|
39
40
|
"EQUIVALENT REPLACEMENT: a replacement only qualifies if it prevents the same failure mode with similar enforcement strength. A rubric suggestion is not equivalent to a hard gate. Document the tradeoff explicitly when the replacement is weaker.",
|
|
40
|
-
"NEVER COMMIT MARKDOWN FILES UNLESS USER EXPLICITLY ASKS."
|
|
41
|
+
"NEVER COMMIT MARKDOWN FILES UNLESS USER EXPLICITLY ASKS.",
|
|
42
|
+
"OUTPUT LOCATION: write workflow JSON to ~/.workrail/workflows/<name>.json unless user asks to contribute a bundled workflow. Never write to a repo's workflows/ dir by default -- it may be public."
|
|
41
43
|
],
|
|
42
44
|
"references": [
|
|
43
45
|
{
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"preconditions": [
|
|
21
21
|
"User has a recurring task or problem a workflow should solve, or an existing workflow that should be modernized.",
|
|
22
22
|
"Agent has access to file creation, editing, and terminal tools.",
|
|
23
|
-
"Agent can run workflow validators such as `npm run validate:registry` or equivalent."
|
|
23
|
+
"Agent can run workflow validators such as `npm run validate:registry` or equivalent.",
|
|
24
|
+
"Write output workflow JSON to ~/.workrail/workflows/<name>.json by default. Only write to a repo's workflows/ dir when the user explicitly asks to contribute a bundled workflow."
|
|
24
25
|
],
|
|
25
26
|
"metaGuidance": [
|
|
26
27
|
"REFERENCE HIERARCHY: treat workflow-schema as legal truth for structure. Treat authoring-spec as canonical current guidance for what makes a workflow good. Treat authoring-provenance as optional maintainer context only.",
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
"ANTI-PATTERNS TO AVOID IN AUTHORED WORKFLOWS: no pseudo-function metaGuidance, no learning-path branching, no satisfaction-score loops, no heavy clarification batteries, no regex-as-primary-validation, no celebration phases.",
|
|
38
39
|
"MODERNIZATION DISTINCTION: remove format problems (pseudo-DSL, regex, A/B phases). Preserve or equivalently replace behavioral mechanisms (forcing functions, hard gates, domain knowledge). Never silently drop a mechanism that prevents a real failure mode.",
|
|
39
40
|
"EQUIVALENT REPLACEMENT: a replacement only qualifies if it prevents the same failure mode with similar enforcement strength. A rubric suggestion is not equivalent to a hard gate. Document the tradeoff explicitly when the replacement is weaker.",
|
|
40
|
-
"NEVER COMMIT MARKDOWN FILES UNLESS USER EXPLICITLY ASKS."
|
|
41
|
+
"NEVER COMMIT MARKDOWN FILES UNLESS USER EXPLICITLY ASKS.",
|
|
42
|
+
"OUTPUT LOCATION: write workflow JSON to ~/.workrail/workflows/<name>.json unless user asks to contribute a bundled workflow. Never write to a repo's workflows/ dir by default -- it may be public."
|
|
41
43
|
],
|
|
42
44
|
"references": [
|
|
43
45
|
{
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.react-flow{--xy-edge-stroke-default:#b1b1b7;--xy-edge-stroke-width-default:1;--xy-edge-stroke-selected-default:#555;--xy-connectionline-stroke-default:#b1b1b7;--xy-connectionline-stroke-width-default:1;--xy-attribution-background-color-default:#ffffff80;--xy-minimap-background-color-default:#fff;--xy-minimap-mask-background-color-default:#f0f0f099;--xy-minimap-mask-stroke-color-default:transparent;--xy-minimap-mask-stroke-width-default:1;--xy-minimap-node-background-color-default:#e2e2e2;--xy-minimap-node-stroke-color-default:transparent;--xy-minimap-node-stroke-width-default:2;--xy-background-color-default:transparent;--xy-background-pattern-dots-color-default:#91919a;--xy-background-pattern-lines-color-default:#eee;--xy-background-pattern-cross-color-default:#e2e2e2;background-color:var(--xy-background-color,var(--xy-background-color-default));--xy-node-color-default:inherit;--xy-node-border-default:1px solid #1a192b;--xy-node-background-color-default:#fff;--xy-node-group-background-color-default:#f0f0f040;--xy-node-boxshadow-hover-default:0 1px 4px 1px #00000014;--xy-node-boxshadow-selected-default:0 0 0 .5px #1a192b;--xy-node-border-radius-default:3px;--xy-handle-background-color-default:#1a192b;--xy-handle-border-color-default:#fff;--xy-selection-background-color-default:#0059dc14;--xy-selection-border-default:1px dotted #0059dccc;--xy-controls-button-background-color-default:#fefefe;--xy-controls-button-background-color-hover-default:#f4f4f4;--xy-controls-button-color-default:inherit;--xy-controls-button-color-hover-default:inherit;--xy-controls-button-border-color-default:#eee;--xy-controls-box-shadow-default:0 0 2px 1px #00000014;--xy-edge-label-background-color-default:#fff;--xy-edge-label-color-default:inherit;--xy-resize-background-color-default:#3367d9;direction:ltr}.react-flow.dark{--xy-edge-stroke-default:#3e3e3e;--xy-edge-stroke-width-default:1;--xy-edge-stroke-selected-default:#727272;--xy-connectionline-stroke-default:#b1b1b7;--xy-connectionline-stroke-width-default:1;--xy-attribution-background-color-default:#96969640;--xy-minimap-background-color-default:#141414;--xy-minimap-mask-background-color-default:#3c3c3c99;--xy-minimap-mask-stroke-color-default:transparent;--xy-minimap-mask-stroke-width-default:1;--xy-minimap-node-background-color-default:#2b2b2b;--xy-minimap-node-stroke-color-default:transparent;--xy-minimap-node-stroke-width-default:2;--xy-background-color-default:#141414;--xy-background-pattern-dots-color-default:#777;--xy-background-pattern-lines-color-default:#777;--xy-background-pattern-cross-color-default:#777;--xy-node-color-default:#f8f8f8;--xy-node-border-default:1px solid #3c3c3c;--xy-node-background-color-default:#1e1e1e;--xy-node-group-background-color-default:#f0f0f040;--xy-node-boxshadow-hover-default:0 1px 4px 1px #ffffff14;--xy-node-boxshadow-selected-default:0 0 0 .5px #999;--xy-handle-background-color-default:#bebebe;--xy-handle-border-color-default:#1e1e1e;--xy-selection-background-color-default:#c8c8dc14;--xy-selection-border-default:1px dotted #c8c8dccc;--xy-controls-button-background-color-default:#2b2b2b;--xy-controls-button-background-color-hover-default:#3e3e3e;--xy-controls-button-color-default:#f8f8f8;--xy-controls-button-color-hover-default:#fff;--xy-controls-button-border-color-default:#5b5b5b;--xy-controls-box-shadow-default:0 0 2px 1px #00000014;--xy-edge-label-background-color-default:#141414;--xy-edge-label-color-default:#f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props,var(--xy-background-color,var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke,var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width,var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke,var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width,var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{pointer-events:none;position:absolute;overflow:visible}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:.5s linear infinite dashdraw}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected,var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke,var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke,var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:.5s linear infinite dashdraw}svg.react-flow__connectionline{z-index:1001;position:absolute;overflow:visible}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{-webkit-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default;position:absolute}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:0 0;pointer-events:none}.react-flow__nodesselection-rect{pointer-events:all;cursor:grab;position:absolute}.react-flow__handle{pointer-events:none;background-color:var(--xy-handle-background-color,var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color,var(--xy-handle-border-color-default));border-radius:100%;width:6px;min-width:5px;height:6px;min-height:5px;position:absolute}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;bottom:0;left:50%;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{z-index:5;margin:15px;position:absolute}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px)translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px)translateY(-50%)}.react-flow__attribution{background:var(--xy-attribution-background-color,var(--xy-attribution-background-color-default));margin:0;padding:2px 3px;font-size:10px}.react-flow__attribution a{color:#999;text-decoration:none}@keyframes dashdraw{0%{stroke-dashoffset:10px}}.react-flow__edgelabel-renderer{pointer-events:none;-webkit-user-select:none;user-select:none;width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__viewport-portal{-webkit-user-select:none;user-select:none;width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__minimap{background:var(--xy-minimap-background-color-props,var(--xy-minimap-background-color,var(--xy-minimap-background-color-default)))}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var(--xy-minimap-mask-background-color-props,var(--xy-minimap-mask-background-color,var(--xy-minimap-mask-background-color-default)));stroke:var(--xy-minimap-mask-stroke-color-props,var(--xy-minimap-mask-stroke-color,var(--xy-minimap-mask-stroke-color-default)));stroke-width:var(--xy-minimap-mask-stroke-width-props,var(--xy-minimap-mask-stroke-width,var(--xy-minimap-mask-stroke-width-default)))}.react-flow__minimap-node{fill:var(--xy-minimap-node-background-color-props,var(--xy-minimap-node-background-color,var(--xy-minimap-node-background-color-default)));stroke:var(--xy-minimap-node-stroke-color-props,var(--xy-minimap-node-stroke-color,var(--xy-minimap-node-stroke-color-default)));stroke-width:var(--xy-minimap-node-stroke-width-props,var(--xy-minimap-node-stroke-width,var(--xy-minimap-node-stroke-width-default)))}.react-flow__background-pattern.dots{fill:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-dots-color-default)))}.react-flow__background-pattern.lines{stroke:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-lines-color-default)))}.react-flow__background-pattern.cross{stroke:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-cross-color-default)))}.react-flow__controls{box-shadow:var(--xy-controls-box-shadow,var(--xy-controls-box-shadow-default));flex-direction:column;display:flex}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{background:var(--xy-controls-button-background-color,var(--xy-controls-button-background-color-default));border:none;border-bottom:1px solid var(--xy-controls-button-border-color-props,var(--xy-controls-button-border-color,var(--xy-controls-button-border-color-default)));width:26px;height:26px;color:var(--xy-controls-button-color-props,var(--xy-controls-button-color,var(--xy-controls-button-color-default)));cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;padding:4px;display:flex}.react-flow__controls-button svg{fill:currentColor;width:100%;max-width:12px;max-height:12px}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{border-radius:var(--xy-node-border-radius,var(--xy-node-border-radius-default));width:150px;color:var(--xy-node-color,var(--xy-node-color-default));text-align:center;border:var(--xy-node-border,var(--xy-node-border-default));background-color:var(--xy-node-background-color,var(--xy-node-background-color-default));padding:10px;font-size:12px}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover,var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected,var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color,var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color,var(--xy-selection-background-color-default));border:var(--xy-selection-border,var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var(--xy-controls-button-background-color-hover-props,var(--xy-controls-button-background-color-hover,var(--xy-controls-button-background-color-hover-default)));color:var(--xy-controls-button-color-hover-props,var(--xy-controls-button-color-hover,var(--xy-controls-button-color-hover-default)))}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var(--xy-controls-button-border-color-props,var(--xy-controls-button-border-color,var(--xy-controls-button-border-color-default)))}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{background-color:var(--xy-resize-background-color,var(--xy-resize-background-color-default));border:1px solid #fff;border-radius:1px;width:5px;height:5px;translate:-50% -50%}.react-flow__resize-control.handle.left{top:50%;left:0}.react-flow__resize-control.handle.right{top:50%;left:100%}.react-flow__resize-control.handle.top{top:0;left:50%}.react-flow__resize-control.handle.bottom{top:100%;left:50%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color,var(--xy-resize-background-color-default));border-style:solid;border-width:0}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;height:100%;top:0;transform:translate(-50%)}.react-flow__resize-control.line.left{border-left-width:1px;left:0}.react-flow__resize-control.line.right{border-right-width:1px;left:100%}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{width:100%;height:1px;left:0;transform:translateY(-50%)}.react-flow__resize-control.line.top{border-top-width:1px;top:0}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color,var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color,var(--xy-edge-label-color-default))}@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-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-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-outline-style:solid;--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-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;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-lg:32rem;--container-3xl:48rem;--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:calc(1.5 / 1);--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-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--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)}}@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%;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;-webkit-text-decoration:inherit;-webkit-text-decoration: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]){appearance:button}::file-selector-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{.branch-tree-line{margin-left:4px;padding-left:14px;position:relative}.branch-tree-line:before{content:"";pointer-events:none;clip-path:polygon(0 0,100% 0,100% calc(100% - 14px),0 100%);background:linear-gradient(#f4c4302e,#f4c4302e) 0 0/1px 100% no-repeat,linear-gradient(#f4c43073,#f4c43073) 5px 0/3px 100% no-repeat;width:10px;position:absolute;top:0;bottom:0;left:0}.tab-btn{position:relative;overflow:visible}.tab-corner{opacity:0;pointer-events:none;width:8px;height:8px;transition:opacity .15s,transform .15s;position:absolute;transform:scale(.5)}.tab-corner--tl{border-top:1px solid var(--accent);border-left:1px solid var(--accent);top:2px;left:2px}.tab-corner--tr{border-top:1px solid var(--accent);border-right:1px solid var(--accent);top:2px;right:2px}.tab-corner--bl{border-bottom:1px solid var(--accent);border-left:1px solid var(--accent);bottom:2px;left:2px}.tab-corner--br{border-bottom:1px solid var(--accent);border-right:1px solid var(--accent);bottom:2px;right:2px}.tab-btn--active .tab-corner{opacity:1;transform:scale(1)}}@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.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}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-1\/2{top:50%}.top-3{top:calc(var(--spacing) * 3)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-1\/2{left:50%}.z-50{z-index:50}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.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-\[3px\]{margin-top:3px}.mt-auto{margin-top:auto}.mt-px{margin-top:1px}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.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)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-4{margin-left:calc(var(--spacing) * 4)}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.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{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-3{height:calc(var(--spacing) * 3)}.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-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-14{height:calc(var(--spacing) * 14)}.h-\[3px\]{height:3px}.h-\[100px\]{height:100px}.h-\[506px\]{height:506px}.h-full{height:100%}.h-px{height:1px}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-48{max-height:calc(var(--spacing) * 48)}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[44px\]{min-height:44px}.min-h-\[160px\]{min-height:160px}.min-h-screen{min-height:100vh}.w-0\.5{width:calc(var(--spacing) * .5)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-1\/2{width:50%}.w-3{width:calc(var(--spacing) * 3)}.w-3\/4{width:75%}.w-4\/6{width:66.6667%}.w-5\/6{width:83.3333%}.w-6{width:calc(var(--spacing) * 6)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-64{width:calc(var(--spacing) * 64)}.w-\[560px\]{width:560px}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-\[80px\]{max-width:80px}.max-w-\[200px\]{max-width:200px}.max-w-\[360px\]{max-width:360px}.max-w-\[calc\(92vw-12px\)\]{max-width:calc(92vw - 12px)}.max-w-lg{max-width:var(--container-lg)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[44px\]{min-width:44px}.min-w-\[120px\]{min-width:120px}.min-w-\[200px\]{min-width:200px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-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-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.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)}.gap-8{gap:calc(var(--spacing) * 8)}:where(.space-y-0>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)))}: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(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * 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-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-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)))}:where(.space-y-px>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(1px * var(--tw-space-y-reverse));margin-block-end:calc(1px * calc(1 - var(--tw-space-y-reverse)))}.gap-x-8{column-gap:calc(var(--spacing) * 8)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.self-center{align-self:center}.self-stretch{align-self:stretch}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.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-\[rgba\(255\,255\,255\,0\.06\)\]{border-color:#ffffff0f}.border-\[var\(--accent\)\]{border-color:var(--accent)}.border-\[var\(--border\)\]{border-color:var(--border)}.border-blue-500\/20{border-color:#3080ff33}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/20{border-color:color-mix(in oklab, var(--color-blue-500) 20%, transparent)}}.border-green-500\/20{border-color:#00c75833}@supports (color:color-mix(in lab, red, red)){.border-green-500\/20{border-color:color-mix(in oklab, var(--color-green-500) 20%, transparent)}}.border-orange-500\/20{border-color:#fe6e0033}@supports (color:color-mix(in lab, red, red)){.border-orange-500\/20{border-color:color-mix(in oklab, var(--color-orange-500) 20%, transparent)}}.border-transparent{border-color:#0000}.bg-\[rgba\(0\,0\,0\,0\.18\)\]{background-color:#0000002e}.bg-\[rgba\(0\,240\,255\,0\.03\)\]{background-color:#00f0ff08}.bg-\[rgba\(10\,10\,10\,0\.38\)\]{background-color:#0a0a0a61}.bg-\[rgba\(255\,255\,255\,0\.02\)\]{background-color:#ffffff05}.bg-\[var\(--accent\)\]{background-color:var(--accent)}.bg-\[var\(--bg-card\)\]{background-color:var(--bg-card)}.bg-\[var\(--bg-primary\)\]{background-color:var(--bg-primary)}.bg-\[var\(--bg-secondary\)\]{background-color:var(--bg-secondary)}.bg-\[var\(--bg-tertiary\)\]{background-color:var(--bg-tertiary)}.bg-\[var\(--border\)\]{background-color:var(--border)}.bg-blue-500\/10{background-color:#3080ff1a}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/10{background-color:color-mix(in oklab, var(--color-blue-500) 10%, transparent)}}.bg-green-500\/10{background-color:#00c7581a}@supports (color:color-mix(in lab, red, red)){.bg-green-500\/10{background-color:color-mix(in oklab, var(--color-green-500) 10%, transparent)}}.bg-orange-500\/10{background-color:#fe6e001a}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/10{background-color:color-mix(in oklab, var(--color-orange-500) 10%, transparent)}}.bg-transparent{background-color:#0000}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.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-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-20{padding-block:calc(var(--spacing) * 20)}.py-32{padding-block:calc(var(--spacing) * 32)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-\[calc\(theme\(spacing\.2\)\+theme\(spacing\.3\)\+4ch\)\]{padding-left:calc(1.25rem + 4ch)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.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-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.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-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-\[0\.16em\]{--tw-tracking:.16em;letter-spacing:.16em}.tracking-\[0\.20em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.22em\]{--tw-tracking:.22em;letter-spacing:.22em}.tracking-\[0\.25em\]{--tw-tracking:.25em;letter-spacing:.25em}.tracking-\[0\.30em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-\[0\.35em\]{--tw-tracking:.35em;letter-spacing:.35em}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.text-ellipsis{text-overflow:ellipsis}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[var\(--accent\)\]{color:var(--accent)}.text-\[var\(--error\)\]{color:var(--error)}.text-\[var\(--text-muted\)\]{color:var(--text-muted)}.text-\[var\(--text-primary\)\]{color:var(--text-primary)}.text-\[var\(--text-secondary\)\]{color:var(--text-secondary)}.text-\[var\(--warning\)\]{color:var(--warning)}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-orange-400{color:var(--color-orange-400)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.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,)}.placeholder-\[var\(--text-muted\)\]::placeholder{color:var(--text-muted)}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--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)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + 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)}.ring-\[var\(--accent\)\]{--tw-ring-color:var(--accent)}.ring-blue-500\/40{--tw-ring-color:#3080ff66}@supports (color:color-mix(in lab, red, red)){.ring-blue-500\/40{--tw-ring-color:color-mix(in oklab, var(--color-blue-500) 40%, transparent)}}.ring-orange-500\/40{--tw-ring-color:#fe6e0066}@supports (color:color-mix(in lab, red, red)){.ring-orange-500\/40{--tw-ring-color:color-mix(in oklab, var(--color-orange-500) 40%, transparent)}}.ring-offset-1{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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,)}.drop-shadow{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#0000001a)) drop-shadow(0 1px 1px var(--tw-drop-shadow-color,#0000000f));--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f);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,)}.backdrop-filter{-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,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.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))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-600{--tw-duration:.6s;transition-duration:.6s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}@media (hover:hover){.group-hover\:text-\[var\(--accent\)\]:is(:where(.group):hover *){color:var(--accent)}.group-hover\:text-\[var\(--text-primary\)\]:is(:where(.group):hover *){color:var(--text-primary)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media (hover:hover){.hover\:border-\[var\(--accent\)\]:hover{border-color:var(--accent)}.hover\:border-\[var\(--accent-strong\)\]:hover{border-color:var(--accent-strong)}.hover\:bg-\[var\(--bg-card\)\]:hover{background-color:var(--bg-card)}.hover\:bg-\[var\(--bg-tertiary\)\]:hover{background-color:var(--bg-tertiary)}.hover\:bg-blue-500\/20:hover{background-color:#3080ff33}@supports (color:color-mix(in lab, red, red)){.hover\:bg-blue-500\/20:hover{background-color:color-mix(in oklab, var(--color-blue-500) 20%, transparent)}}.hover\:bg-orange-500\/20:hover{background-color:#fe6e0033}@supports (color:color-mix(in lab, red, red)){.hover\:bg-orange-500\/20:hover{background-color:color-mix(in oklab, var(--color-orange-500) 20%, transparent)}}.hover\:text-\[var\(--accent\)\]:hover{color:var(--accent)}.hover\:text-\[var\(--accent-hover\)\]:hover{color:var(--accent-hover)}.hover\:text-\[var\(--text-primary\)\]:hover{color:var(--text-primary)}.hover\:text-\[var\(--text-secondary\)\]:hover{color:var(--text-secondary)}}.focus\:border-\[var\(--accent\)\]:focus{border-color:var(--accent)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + 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)}.focus-visible\:ring-\[var\(--accent\)\]:focus-visible{--tw-ring-color:var(--accent)}.focus-visible\:ring-offset-1:focus-visible{--tw-ring-offset-width:1px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}@media (prefers-reduced-motion:no-preference){.motion-safe\:animate-pulse{animation:var(--animate-pulse)}}@media (width>=40rem){.sm\:block{display:block}.sm\:flex{display:flex}}@media (width>=48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=80rem){.xl\:grid-cols-\[minmax\(0\,1\.15fr\)_minmax\(0\,0\.85fr\)\]{grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr)}}}:root{--bg-primary:#0f131f;--bg-secondary:#171b28b3;--bg-card:#1b1f2c99;--bg-tertiary:#262937bf;--border:#3a3a2e;--text-primary:#e8dfc8;--text-secondary:#a89f8c;--text-muted:#5e5a4e;--accent:#f4c430;--accent-hover:#d4a80e;--accent-strong:#00afc0;--success:#00e1a9;--warning:#f97316;--error:#ff6b6b;--blocked:#f44}body{background-color:var(--bg-primary);color:var(--text-primary);background-image:radial-gradient(80% 50% at 50% -5%,#f4c4302e 0%,#0000 70%),radial-gradient(60% 50% at 100% 110%,#00dbe91f 0%,#0000 60%);background-attachment:fixed;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.glass-panel{-webkit-backdrop-filter:blur(16px);background:#1b1f2ca6!important}body:after{content:"";pointer-events:none;z-index:9999;background:repeating-linear-gradient(0deg,#00000005 0 1px,#0000 1px 4px);position:fixed;inset:0}.workrail-minimap-node{opacity:1}*{box-sizing:border-box}.console-blueprint-grid{background-image:linear-gradient(#84949514 1px,#0000 1px),linear-gradient(90deg,#84949514 1px,#0000 1px);background-size:20px 20px}.lineage-scroll-surface{background:var(--bg-primary)}.lineage-scroll-surface .react-flow,.lineage-scroll-surface .react-flow__renderer,.lineage-scroll-surface .react-flow__viewport,.lineage-scroll-surface .react-flow__pane{background:0 0!important}.workrail-current-lineage-node{isolation:isolate;animation:3.2s ease-in-out infinite workrail-current-node-pulse;position:relative;box-shadow:inset 0 0 0 1px #f4c43059,inset 0 0 28px #f4c4301a,0 0 16px #f4c43026}.workrail-current-lineage-node:after{content:"";pointer-events:none;border:1px solid #f4c43059;animation:3.2s ease-in-out infinite workrail-current-node-outline;position:absolute;inset:-1px}.workrail-current-lineage-edge .react-flow__edge-path{stroke-dasharray:7 9;animation:1.35s linear infinite workrail-current-edge-flow}.workrail-selected-lineage-node{isolation:isolate;position:relative;box-shadow:inset 0 0 0 1px #f4b34161,0 0 0 1px #f4b34147,0 0 18px #f4b3411a}@keyframes workrail-current-node-pulse{0%,to{filter:brightness();transform:translateZ(0)}50%{filter:brightness(1.1);transform:translateZ(0)}}@keyframes workrail-current-node-outline{0%,to{opacity:.34;box-shadow:0 0 #f4c43000,inset 0 0 #f4c43000}50%{opacity:1;box-shadow:0 0 32px #f4c4304d,inset 0 0 24px #f4c4301f}}@keyframes workrail-current-edge-flow{to{stroke-dashoffset:-32px}}.energy-glow{box-shadow:0 0 20px #f4c4304d,0 0 8px #f4c43033}.energy-live{animation:2.4s ease-in-out infinite energy-live-pulse;box-shadow:0 0 16px #00dbe94d,0 0 4px #00dbe933}@keyframes energy-live-pulse{0%,to{box-shadow:0 0 10px #00dbe933,0 0 3px #00dbe926}50%{box-shadow:0 0 22px #00dbe973,0 0 8px #00dbe94d}}.energy-card{transition:border-color .15s,box-shadow .15s}.energy-card:hover{border-color:#f4c43080;box-shadow:0 0 0 1px #f4c4301f,0 4px 24px #0006}.text-glow-amber{text-shadow:0 0 12px #f4c43080,0 0 4px #f4c4304d}.text-glow-cyan{text-shadow:0 0 12px #00dbe980,0 0 4px #00dbe94d}.badge-live{color:var(--accent-strong);animation:2.4s ease-in-out infinite badge-live-text-pulse}@keyframes badge-live-text-pulse{0%,to{text-shadow:0 0 6px #00dbe980}50%{text-shadow:0 0 16px #00dbe9e6,0 0 4px #00dbe999}}.markdown-view{color:var(--text-secondary);word-break:break-word;font-size:.8125rem;line-height:1.6}.markdown-view h1,.markdown-view h2,.markdown-view h3,.markdown-view h4,.markdown-view h5,.markdown-view h6{color:var(--text-primary);margin:1em 0 .4em;font-weight:600;line-height:1.3}.markdown-view h1{font-size:1.1em}.markdown-view h2{font-size:1em}.markdown-view h3{font-size:.95em}.markdown-view h4,.markdown-view h5,.markdown-view h6{font-size:.9em}.markdown-view>:first-child{margin-top:0}.markdown-view p{margin:.5em 0}.markdown-view em{font-style:italic}.markdown-view a{color:var(--accent);text-underline-offset:2px;text-decoration:underline}.markdown-view ul{margin:.4em 0;padding-left:1.4em;list-style-type:disc}.markdown-view ol{margin:.4em 0;padding-left:1.4em;list-style-type:decimal}.markdown-view li{color:var(--text-secondary);margin:.15em 0}.markdown-view li::marker{color:var(--text-muted)}.markdown-view li>ul,.markdown-view li>ol{margin:.1em 0}.markdown-view li>ul{list-style-type:circle}.markdown-view code{background:var(--bg-primary);color:var(--text-primary);border-radius:3px;padding:.15em .35em;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.88em}.markdown-view pre{background:var(--bg-primary);border-radius:6px;margin:.5em 0;padding:.75em;overflow-x:auto}.markdown-view pre code{background:0 0;padding:0;font-size:.85em;line-height:1.5}.markdown-view blockquote{border-left:3px solid var(--border);color:var(--text-muted);margin:.5em 0;padding:.25em .75em}.markdown-view hr{border:none;border-top:1px solid var(--border);margin:.75em 0}.markdown-view table{border-collapse:collapse;width:100%;margin:.5em 0;font-size:.9em}.markdown-view th,.markdown-view td{border:1px solid var(--border);text-align:left;padding:.35em .6em}.markdown-view th{background:var(--bg-primary);color:var(--text-primary);font-weight:600}.markdown-view img{border-radius:4px;max-width:100%}.markdown-view h1,.markdown-view h2,.markdown-view h3,.markdown-view h4{color:var(--accent);letter-spacing:.08em}.markdown-view strong{color:var(--accent);font-weight:700}.markdown-view code{color:var(--accent-strong);background:#00dbe914;border:1px solid #00dbe933;border-radius:0}.markdown-view pre{border:1px solid #00dbe933;border-left:2px solid var(--accent-strong);background:#0006;border-radius:0}.markdown-view pre code{color:var(--accent-strong);background:0 0;border:none}.markdown-view blockquote{border-left:2px solid var(--accent);color:var(--text-secondary);background:#f4c4300a;padding:.5em .75em}.markdown-view ul li:before{content:"// ";color:var(--accent);font-family:monospace;font-weight:700}.markdown-view ul{padding-left:1.2em;list-style:none}.markdown-view a{color:var(--accent-strong)}.corner-brackets{background-image:linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent)), linear-gradient(var(--accent), var(--accent));background-position:0 0,0 0,right 0 top 0,right 0 top 0,left 0 bottom 0,left 0 bottom 0,right 0 bottom 0,right 0 bottom 0;background-repeat:no-repeat;background-size:1px 12px,12px 1px,1px 12px,12px 1px,1px 12px,12px 1px,1px 12px,12px 1px;position:relative}@keyframes tab-activate-flicker{0%{opacity:1;filter:brightness()}10%{opacity:.2;filter:brightness(.5)}20%{opacity:1;filter:brightness(3)hue-rotate(180deg)}35%{opacity:.5;filter:brightness(1.5)}50%{opacity:1;filter:brightness(2.5)}70%{opacity:.8;filter:brightness(1.8)}85%{opacity:1;filter:brightness(1.3)}to{opacity:1;filter:brightness()}}.tab-activating{animation:.28s ease-out forwards tab-activate-flicker}@media (prefers-reduced-motion:reduce){.badge-live,.energy-live,.workrail-current-lineage-node,.workrail-current-lineage-node:after,.workrail-current-lineage-edge .react-flow__edge-path,.tab-activating{animation:none!important}.tab-corner{transition:none}}@keyframes modal-exit-to-top{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-14px)}}@keyframes modal-exit-to-bottom{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(14px)}}@keyframes modal-enter-from-below{0%{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}@keyframes modal-enter-from-above{0%{opacity:0;transform:translateY(-14px)}to{opacity:1;transform:translateY(0)}}@keyframes modal-exit-to-left{0%{opacity:1;transform:translate(0)}to{opacity:0;transform:translate(-20px)}}@keyframes modal-exit-to-right{0%{opacity:1;transform:translate(0)}to{opacity:0;transform:translate(20px)}}@keyframes modal-enter-from-right{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}@keyframes modal-enter-from-left{0%{opacity:0;transform:translate(-20px)}to{opacity:1;transform:translate(0)}}@keyframes modal-border-flash{0%{filter:brightness()}15%{filter:brightness(1.8)}50%{filter:brightness(1.3)}to{filter:brightness()}}@keyframes modal-crt-fade{0%{opacity:0}20%{opacity:.65}70%{opacity:.65}to{opacity:0}}.modal-content--exit-v-next{animation:80ms ease-in forwards modal-exit-to-top}.modal-content--exit-v-prev{animation:80ms ease-in forwards modal-exit-to-bottom}.modal-content--enter-v-next{animation:.16s ease-out forwards modal-enter-from-below}.modal-content--enter-v-prev{animation:.16s ease-out forwards modal-enter-from-above}.modal-content--exit-h-next{animation:80ms ease-in forwards modal-exit-to-left}.modal-content--exit-h-prev{animation:80ms ease-in forwards modal-exit-to-right}.modal-content--enter-h-next{animation:.16s ease-out forwards modal-enter-from-right}.modal-content--enter-h-prev{animation:.16s ease-out forwards modal-enter-from-left}.modal-border-flashing{animation:.2s ease-out forwards modal-border-flash}.modal-scanline{pointer-events:none;z-index:10;background:linear-gradient(to bottom, transparent calc(var(--glitch-y,38%) - 1px), #b4d2ff59 calc(var(--glitch-y,38%) - 1px), #b4d2ff59 calc(var(--glitch-y,38%) + var(--glitch-w,3px)), transparent calc(var(--glitch-y,38%) + var(--glitch-w,3px))), linear-gradient(to bottom, transparent calc(var(--glitch-y2,62%) - 1px), #f4c4304d calc(var(--glitch-y2,62%) - 1px), #f4c4304d calc(var(--glitch-y2,62%) + var(--glitch-w2,2px)), transparent calc(var(--glitch-y2,62%) + var(--glitch-w2,2px))), repeating-linear-gradient(to bottom, transparent 0px, transparent 2px, #0000008c 2px, #0000008c 3px), repeating-linear-gradient(to bottom, transparent 0px, transparent 5px, #00000038 5px, #00000042 7px), repeating-linear-gradient(to bottom, transparent 0px, transparent 3px, #0000001f 3px, #0000001f 5px);background-position-y:0, 0, var(--crt-offset,0px), calc(var(--crt-offset,0px) + 2px), calc(var(--crt-offset,0px) + 4px);opacity:0;animation:.22s linear forwards modal-crt-fade;position:absolute;inset:0}.modal-scanline--hidden{display:none}@media (prefers-reduced-motion:reduce){.modal-content--exit-v-next,.modal-content--exit-v-prev,.modal-content--enter-v-next,.modal-content--enter-v-prev,.modal-content--exit-h-next,.modal-content--exit-h-prev,.modal-content--enter-h-next,.modal-content--enter-h-prev{opacity:1!important;animation:none!important;transform:none!important}.modal-scanline{display:none}.modal-border-flashing{filter:none!important;animation:none!important}}@keyframes hero-card-glow-breathe{0%,to{filter:drop-shadow(0 0 12px #00afc033)}50%{filter:drop-shadow(0 0 28px #00afc08c)}}.hero-card-breathing{animation:3s ease-in-out infinite hero-card-glow-breathe}@media (prefers-reduced-motion:reduce){.hero-card-breathing{animation:none}}@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-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-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-outline-style{syntax:"*";inherits:false;initial-value:solid}@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-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}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "rich-object-contribution",
|
|
3
|
-
"name": "Rich Object Contribution Workflow",
|
|
4
|
-
"version": "1.0.0",
|
|
5
|
-
"description": "Technical Consultant for ZIM Rich Object contributions. Interviews the team, triages whether and what type of custom RO is needed, reads the codebase for current patterns, and guides a complete contribution on iOS or Android.",
|
|
6
|
-
"about": "## Rich Object Contribution Workflow\n\nThis workflow acts as a Technical Consultant for teams contributing a new Rich Object (RO) type to the ZIM messaging platform.\n\n### What it does\n\n1. **Interview** — gathers requirements and classifies the RO type (display_only, fetch_based, interactive)\n2. **Triage** — evaluates whether the built-in Card RO already covers the use case\n3. **Context gathering** — reads the Tour Rich Object implementation to understand current platform contracts\n4. **Design** — confirms contribution pattern, file locations, class naming, system message handling\n5. **Implement** — builds all required artifacts following the patterns found in the codebase\n6. **Pitfall verification** — checks for the known failure modes that caused rework in past contributions; the engine enforces all applicable checks are explicitly addressed before the step can complete\n\n### Why it exists\n\nPast contributions (Tour RO, Copilot ROs) required multiple rounds of Mercury review to fix the same recurring mistakes. This workflow bakes those checks in so teams can self-serve.\n\n### How to get good results\n\nThe workflow reads the codebase for platform contracts rather than hardcoding them, so it works correctly across both v1 and v2 of the contribution model. No external docs needed.",
|
|
7
|
-
"examples": [
|
|
8
|
-
"Contribute a Tour Itinerary Rich Object for tour confirmation messages in ZIM",
|
|
9
|
-
"Add a Pre-Approval Status RO with a refresh button to Home Loans conversations",
|
|
10
|
-
"Determine whether a Closing Milestone Update needs a custom RO or can use Card RO",
|
|
11
|
-
"Contribute a Rate Lock Notification RO for ZIM conversations on Android"
|
|
12
|
-
],
|
|
13
|
-
"validatedAgainstSpecVersion": 3,
|
|
14
|
-
"recommendedPreferences": {
|
|
15
|
-
"recommendedAutonomy": "guided",
|
|
16
|
-
"recommendedRiskPolicy": "conservative"
|
|
17
|
-
},
|
|
18
|
-
"metaGuidance": [
|
|
19
|
-
"ROLE: Technical Consultant for ZIM Rich Object contributions. Guide the team to a correct, complete contribution on their platform without requiring Mercury team review.",
|
|
20
|
-
"TRIAGE FIRST: Card RO is sufficient when all data is in the message payload, UI is title+body+image+link only, single tap to navigate, no live updates. Build custom only when Card cannot cut it.",
|
|
21
|
-
"RO TYPES after triage: display_only (payload data, custom layout, no fetch), fetch_based (API fetch on impression, no model mutations), interactive (API fetch + user-triggered model mutations).",
|
|
22
|
-
"INTERACTIVE vs FETCH: interactive means the user can trigger mutations that update the cached model (refresh, save/unsave). Tap-to-navigate alone is NOT interactive — it is fetch_based at most.",
|
|
23
|
-
"CODEBASE IS THE CONTRACT: do not guess at platform interfaces or DI patterns. Read the Tour Rich Object implementation first. The patterns there are authoritative for the current contribution model.",
|
|
24
|
-
"ANALYTICS AT RENDER TIME: analytics context must come from the render-time wrapper, not the cached model. Same cached model can appear in multiple messages — reading from it misattributes events.",
|
|
25
|
-
"PITFALLS: converter/registry entry present; provider correctly registered in DI; fallback on fetch failure; fallback on flag off; analytics context on every model."
|
|
26
|
-
],
|
|
27
|
-
"steps": [
|
|
28
|
-
{
|
|
29
|
-
"id": "phase-0-requirements",
|
|
30
|
-
"title": "Phase 0: Requirements Interview",
|
|
31
|
-
"prompt": "Interview the contributing team to understand what they need. These requirements cannot be found in the codebase — the RO does not exist yet. Keep questions focused; you need enough to make an accurate triage and classification.\n\nCover all of the following:\n\n1. **Platform** — iOS or Android?\n2. **What it is** — what product concept does this RO represent? What does the user see in the conversation?\n3. **Data source** — is all display data available in the message at send time, or must the RO fetch additional data from an API when the user views it?\n4. **Domain identifier** — if fetching, which field in the message payload is the lookup key? What is its type?\n5. **GraphQL typename** — what will the backend send as `__typename`? (e.g., `ZIMPreApprovalRichObject`)\n6. **UI content** — what fields does the RO display? List them with types.\n7. **Interactions** — what can the user do beyond viewing and tapping the card to navigate? Specifically: are there controls that fetch fresh data or mutate the displayed state (refresh button, save/unsave toggle)? Or only tap-to-navigate?\n8. **Navigation** — what happens when the user taps? Which navigation interface does the team own?\n9. **Analytics** — beyond impression and click, any domain-specific events?\n10. **Feature flag** — is there a feature flag controlling this RO? If yes, what is its name?\n11. **Fallback** — what should the user see if the fetch fails or the feature is disabled?\n12. **Module ownership** — which module (Gradle module on Android, Swift package on iOS) does the contributing team own?\n\nCapture:\n- `platform` (ios or android)\n- `roDisplayName`\n- `roTypeName`\n- `domainIdentifierField`\n- `domainIdentifierType`\n- `dataSource` (message_payload or api_fetch)\n- `uiDescription`\n- `interactions`\n- `navigationTarget`\n- `analyticsEvents`\n- `hasFeatureFlag` (true or false)\n- `featureFlagName` (only if hasFeatureFlag is true)\n- `fallbackBehavior`\n- `ownerModule`",
|
|
32
|
-
"requireConfirmation": false
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"id": "phase-1-triage",
|
|
36
|
-
"title": "Phase 1: Triage and Classify",
|
|
37
|
-
"prompt": "Based on the requirements, make two decisions: whether a custom RO is needed, and if so, which type.\n\n**Decision 1: Card RO or Custom RO?**\n\nCard RO is sufficient when ALL of the following hold:\n- All data is in the message payload at send time\n- UI is title + body/subheading + optional image + single tap-to-link\n- No interactions beyond tap-to-navigate\n- Content does not need to update after initial load\n\nCustom RO is needed if ANY of the following hold:\n- Data must be fetched from an API using a message identifier\n- UI requires domain-specific layout the Card cannot provide\n- There are user interactions beyond single tap-to-navigate\n- Content must reflect live state when the user returns\n\nFor borderline cases, lean toward Card RO. A custom RO is weeks of work; Card RO is a backend change.\n\n**Decision 2: What type of custom RO? (only if needsCustomRO is true)**\n\n- `display_only` — data is in the message payload but needs custom layout the Card RO cannot provide. No API fetch. No stateful mutations.\n- `fetch_based` — an API call is needed on impression to hydrate the view. User interactions are view-only or tap-to-navigate. No controls that update the displayed model.\n- `interactive` — fetch_based PLUS the user can trigger mutations that update the cached model: a refresh button that re-fetches and updates displayed data, a save/unsave toggle, or similar. Tap-to-navigate alone does NOT qualify as interactive.\n\nPresent both decisions with clear reasoning. For Card RO: show how each requirement maps to a Card field. For custom RO: name the criteria that drove the type classification.\n\nCapture:\n- `needsCustomRO` (true or false)\n- `roType` (display_only / fetch_based / interactive — only if needsCustomRO is true)\n- `triageRationale`",
|
|
38
|
-
"requireConfirmation": true
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"id": "phase-2a-card-ro-guidance",
|
|
42
|
-
"title": "Phase 2a: Card RO Configuration",
|
|
43
|
-
"runCondition": {
|
|
44
|
-
"var": "needsCustomRO",
|
|
45
|
-
"equals": false
|
|
46
|
-
},
|
|
47
|
-
"prompt": "Walk the team through configuring the Card RO for their use case.\n\nThe Card RO requires no client-side code — it is driven entirely by what the backend sends in the `fallback` block of the RO entry in the GraphQL response.\n\n**Field mapping** — map each requirement to a Card field:\n- `title`: primary label\n- `body`: secondary detail\n- `subheading`: tertiary label or status\n- `imageUrl`: thumbnail image URL (optional)\n- `url`: deep link for tap-to-navigate\n\n**Tags (Android)** — Android's Card RO supports tag pills for status indicators. If the team needs a colored status badge, explain how to send tags in the fallback block.\n\n**Typename** — the backend should send `CardRichObject` as the typename, or any unrecognized typename (which falls through to card parsing).\n\n**What they do not need to build** — no provider, no models, no converter entry, no DI wiring. The platform handles all of it.\n\nShow the expected GraphQL response shape using their actual field values.",
|
|
48
|
-
"requireConfirmation": false
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"id": "phase-2b-context-gathering",
|
|
52
|
-
"title": "Phase 2b: Context Gathering",
|
|
53
|
-
"runCondition": {
|
|
54
|
-
"var": "needsCustomRO",
|
|
55
|
-
"equals": true
|
|
56
|
-
},
|
|
57
|
-
"prompt": "Find and read the Tour Rich Object implementation. It is the canonical cross-module contribution example and your authoritative reference for current platform contracts — interfaces, registration patterns, model structure, DI wiring, and analytics flow.\n\nFor each reference you read, identify:\n- The provider contract: which interface does it implement, what are the method signatures, what do they return?\n- The model structure: how does the initial model relate to the full model? What fields does each carry?\n- Registration: how is the provider discovered by the framework at startup?\n- Converter/registry entry: how does a typename string get routed to an initial model constructor?\n- Fallback: how does the provider return fallback on failure and on feature-flag-off?\n- Analytics: how is analytics context attached at parse time, and how does it flow to render time?\n\nThe patterns you find are authoritative. They reflect the current contribution model — v1 or v2 — as it actually exists in the codebase.\n\nCapture:\n- `referenceImplementation` (which files you read)\n- `patternSummary` (provider interface, model shape, registration mechanism, analytics flow)",
|
|
58
|
-
"promptFragments": [
|
|
59
|
-
{
|
|
60
|
-
"id": "context-platform-ios",
|
|
61
|
-
"when": {
|
|
62
|
-
"var": "platform",
|
|
63
|
-
"equals": "ios"
|
|
64
|
-
},
|
|
65
|
-
"text": "On iOS: the Tour Rich Object lives in the Tour Swift package. Pay attention to (1) the protocol methods and their exact signatures, (2) how the provider is registered via the Container DI system, (3) `AnyMessagingRichObjectProvider` type erasure if present, and (4) how the message model initializers in `ZIMStandardMessage`, `ZIMSystemMessage`, and `ZIMSystemBannerMessage` each route the typename to an initial model — all three files have their own switch chain."
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"id": "context-platform-android",
|
|
69
|
-
"when": {
|
|
70
|
-
"var": "platform",
|
|
71
|
-
"equals": "android"
|
|
72
|
-
},
|
|
73
|
-
"text": "On Android: find the Tour Rich Object provider and `RichObjectConverters.kt`. Pay attention to (1) the `@ContributesMultibinding` annotation on the provider, (2) the `recoverCatching` fallback pattern in `fetchRenderable`, (3) how `RichObjectTypeName.fromString(__typename)` routes typenames in the converter, and (4) the `MessagingRichObjectContent` wrapper — note specifically why analytics come from it rather than from the cached model."
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"id": "context-type-display-only",
|
|
77
|
-
"when": {
|
|
78
|
-
"var": "roType",
|
|
79
|
-
"equals": "display_only"
|
|
80
|
-
},
|
|
81
|
-
"text": "Also find the Card/Fallback provider. It is the closest reference for a display_only RO — its fetch method is a no-op, returning the base model unchanged, which is exactly what display_only providers do."
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"id": "context-type-interactive",
|
|
85
|
-
"when": {
|
|
86
|
-
"var": "roType",
|
|
87
|
-
"equals": "interactive"
|
|
88
|
-
},
|
|
89
|
-
"text": "Also find the Property Rich Object implementation. It has the save/unsave mutation pattern — look specifically at how the onUpdate callback (Android) or RichObjectUpdater (iOS) is used to update the cached model and trigger a re-render without a full re-fetch."
|
|
90
|
-
}
|
|
91
|
-
],
|
|
92
|
-
"requireConfirmation": false
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"id": "phase-3-design",
|
|
96
|
-
"title": "Phase 3: Contribution Design",
|
|
97
|
-
"runCondition": {
|
|
98
|
-
"var": "needsCustomRO",
|
|
99
|
-
"equals": true
|
|
100
|
-
},
|
|
101
|
-
"prompt": "Confirm the contribution design before writing any code.\n\n**Contribution pattern** — recommend cross-module unless the team owns the messaging module:\n- Cross-module (recommended default): provider, models, views, and data layer live in the owning team's module. The messaging module only needs the initial model and the converter entry.\n- In-module: provider lives in the messaging module. Only appropriate when the team owns that module.\n\n**File locations** — based on `ownerModule` and `contributionPattern`, identify where each artifact goes. Use your context-gathering findings as the reference for exact module paths.\n\n**Class naming** — derive from `roDisplayName`:\n- Initial model: `<Name>RichObjectModel` (or equivalent per platform convention)\n- Full model: `Full<Name>RichObjectModel` (fetch_based and interactive only)\n- Provider: `<Name>RichObjectProvider`\n\n**Typename** — verify `roTypeName` exactly matches what the backend will send. A single character difference means the converter never matches and the RO silently never triggers.\n\n**System messages** — decide whether this RO should appear in system/confirmation/banner messages, or only in standard messages. Default is standard messages only. Document the decision — it affects which converter paths you add.\n\nPresent the design as a concrete summary: pattern, file paths, class names, typename, system message decision. This is what you will implement.\n\nCapture:\n- `contributionPattern`\n- `fileLocations`\n- `classNames`\n- `appearsInSystemMessages`",
|
|
102
|
-
"promptFragments": [
|
|
103
|
-
{
|
|
104
|
-
"id": "design-platform-ios",
|
|
105
|
-
"when": {
|
|
106
|
-
"var": "platform",
|
|
107
|
-
"equals": "ios"
|
|
108
|
-
},
|
|
109
|
-
"text": "On iOS: DI registration uses the Container scope system. The provider is exposed through a scope factory in the owning module and registered at app startup. `AnyMessagingRichObjectProvider` type erasure wraps the concrete provider at registration time — confirm whether the existing registration pattern requires this."
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"id": "design-platform-android",
|
|
113
|
-
"when": {
|
|
114
|
-
"var": "platform",
|
|
115
|
-
"equals": "android"
|
|
116
|
-
},
|
|
117
|
-
"text": "On Android: Anvil `@ContributesMultibinding(AppScope::class)` on the provider class handles automatic registration — no manual wiring needed. If the provider is in a module not yet wired into the app component graph, identify what needs to be added."
|
|
118
|
-
}
|
|
119
|
-
],
|
|
120
|
-
"requireConfirmation": true
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"id": "phase-4-implement",
|
|
124
|
-
"title": "Phase 4: Implement",
|
|
125
|
-
"runCondition": {
|
|
126
|
-
"var": "needsCustomRO",
|
|
127
|
-
"equals": true
|
|
128
|
-
},
|
|
129
|
-
"prompt": "Implement the contribution.\n\nBefore writing any code, declare your scope: list every file you will create or modify. Confirm the list covers all required artifacts and nothing outside them. If you discover during implementation that you need to touch something outside your declared scope, stop and update the declaration first.\n\nFollow the patterns from your context-gathering step. If the codebase shows a pattern that differs from your expectations, the codebase is right. Do not invent interfaces, annotations, or registration mechanisms.\n\nBuild and verify incrementally: after each new file, confirm it compiles. Run the relevant tests when implementation is complete.",
|
|
130
|
-
"promptFragments": [
|
|
131
|
-
{
|
|
132
|
-
"id": "impl-type-display-only",
|
|
133
|
-
"when": {
|
|
134
|
-
"var": "roType",
|
|
135
|
-
"equals": "display_only"
|
|
136
|
-
},
|
|
137
|
-
"text": "Your provider's fetch method is a no-op — return the base model unchanged. You do not need a separate full model; the initial model is the renderable model. Keep the provider minimal: canHandle, a no-op fetch, and a render that produces the view directly from the initial model's fields."
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
"id": "impl-type-fetch-or-interactive",
|
|
141
|
-
"when": {
|
|
142
|
-
"var": "roType",
|
|
143
|
-
"in": ["fetch_based", "interactive"]
|
|
144
|
-
},
|
|
145
|
-
"text": "Your provider needs two model types: a thin initial model (parsed from the message payload — domain identifier, fallback, and analytics context only) and a full model (hydrated from the API — all domain fields, plus fallback and analytics context explicitly copied from the initial model). The analytics context is not in the API response; it must be carried over from the initial model."
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
"id": "impl-type-interactive",
|
|
149
|
-
"when": {
|
|
150
|
-
"var": "roType",
|
|
151
|
-
"equals": "interactive"
|
|
152
|
-
},
|
|
153
|
-
"text": "Additionally: implement the mutation pattern (onUpdate callback or platform equivalent) for user-triggered interactions. Keep two failure modes separate — initial fetch failure means the RO has never loaded, so show the fallback card; interaction failure (e.g., refresh failed) means the RO is already displayed, so preserve the last loaded state and show an inline error indicator. Do not fall back to the card on interaction failure."
|
|
154
|
-
}
|
|
155
|
-
],
|
|
156
|
-
"requireConfirmation": false
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
"id": "phase-5-pitfall-check",
|
|
160
|
-
"title": "Phase 5: Pitfall Check",
|
|
161
|
-
"runCondition": {
|
|
162
|
-
"var": "needsCustomRO",
|
|
163
|
-
"equals": true
|
|
164
|
-
},
|
|
165
|
-
"prompt": "Run through the known RO contribution pitfalls. Check each one explicitly against what you built. For any FAIL, fix it inline and re-state the check as PASS before completing.\n\n**Check 1: Converter/registry entry present**\nIs there an entry that routes `roTypeName` to the initial model constructor? This is the most commonly missed step. Without it the framework never creates the initial model and the RO silently never triggers — no error, no crash, nothing.\n\n**Check 2: Provider correctly registered in DI**\nIs the provider registered in the framework's provider registry using the correct registration type? Wrong type (e.g., single binding instead of multibinding) means the provider is never discovered.\n\n**Check 3: Fallback on fetch failure** (fetch_based and interactive only)\nDoes the provider return the fallback when the API call throws? A provider that propagates the exception leaves the framework with nothing to show.\n\n**Check 4: Fallback on feature flag off** (only if hasFeatureFlag)\nIs the feature flag checked before any network call? Does a disabled flag return the fallback immediately?\n\n**Check 5: Analytics context on every model**\nIs analytics context (at minimum: messageId) present on every model the provider can return? Without it, events fire with no message attribution and break funnel analysis.\n\nFor each applicable check, state PASS or FAIL.",
|
|
166
|
-
"promptFragments": [
|
|
167
|
-
{
|
|
168
|
-
"id": "pitfall-platform-ios",
|
|
169
|
-
"when": {
|
|
170
|
-
"var": "platform",
|
|
171
|
-
"equals": "ios"
|
|
172
|
-
},
|
|
173
|
-
"text": "Check 1 (iOS): the converter entry lives in message model initializers. `ZIMStandardMessage` always needs it. If `appearsInSystemMessages` is true, `ZIMSystemMessage` and `ZIMSystemBannerMessage` also need it — each has its own switch chain. Updating only one file is the common mistake.\nCheck 2 (iOS): verify the provider is exposed through the correct Container scope factory and the factory is invoked at app startup."
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
"id": "pitfall-platform-android",
|
|
177
|
-
"when": {
|
|
178
|
-
"var": "platform",
|
|
179
|
-
"equals": "android"
|
|
180
|
-
},
|
|
181
|
-
"text": "Check 1 (Android): two things must be present — a new value in the `RichObjectTypeName` enum matching `roTypeName`, and a corresponding branch in the `convert()` when block. Missing either one is silent.\nCheck 2 (Android): the annotation must be `@ContributesMultibinding(AppScope::class)`, not `@ContributesBinding`. The provider compiles and runs with the wrong annotation — it just never appears in the registry."
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"id": "pitfall-analytics-fetch",
|
|
185
|
-
"when": {
|
|
186
|
-
"var": "roType",
|
|
187
|
-
"in": ["fetch_based", "interactive"]
|
|
188
|
-
},
|
|
189
|
-
"text": "Check 5 (fetch_based/interactive — two sub-checks): first, verify analytics context is explicitly copied from the initial model to the full model — it is not in the API response. Second, verify that at render time analytics are read from the render-time wrapper passed into the render method, not from the cached full model. The same cached model can be rendered for multiple messages; reading analytics from it causes all those messages to report the same messageId."
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"id": "pitfall-analytics-display-only",
|
|
193
|
-
"when": {
|
|
194
|
-
"var": "roType",
|
|
195
|
-
"equals": "display_only"
|
|
196
|
-
},
|
|
197
|
-
"text": "Check 5 (display_only): verify that analytics context is populated on the initial model at parse time. Since there is no full model, the initial model carries analytics context all the way to render time."
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
"id": "pitfall-interactive-extra",
|
|
201
|
-
"when": {
|
|
202
|
-
"var": "roType",
|
|
203
|
-
"equals": "interactive"
|
|
204
|
-
},
|
|
205
|
-
"text": "Check 6: mutations use the onUpdate callback (or platform equivalent) to update the cached model — they do not trigger a full re-fetch.\nCheck 7: interaction failure and initial fetch failure are handled differently. Initial fetch failure → show the fallback card. Interaction failure (refresh, save) → preserve last loaded state and show an inline error. Do not fall back to the card on interaction failure."
|
|
206
|
-
}
|
|
207
|
-
],
|
|
208
|
-
"hasValidation": true,
|
|
209
|
-
"validationCriteria": [
|
|
210
|
-
{
|
|
211
|
-
"type": "contains",
|
|
212
|
-
"value": "Check 1",
|
|
213
|
-
"message": "Response must address the converter/registry entry check (Check 1)"
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"type": "contains",
|
|
217
|
-
"value": "Check 2",
|
|
218
|
-
"message": "Response must address the DI registration check (Check 2)"
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
"type": "contains",
|
|
222
|
-
"value": "Check 3",
|
|
223
|
-
"condition": {
|
|
224
|
-
"or": [
|
|
225
|
-
{ "var": "roType", "equals": "fetch_based" },
|
|
226
|
-
{ "var": "roType", "equals": "interactive" }
|
|
227
|
-
]
|
|
228
|
-
},
|
|
229
|
-
"message": "Fetch/interactive ROs must address the fallback-on-failure check (Check 3)"
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
"type": "contains",
|
|
233
|
-
"value": "Check 4",
|
|
234
|
-
"condition": { "var": "hasFeatureFlag", "equals": true },
|
|
235
|
-
"message": "Feature-flagged ROs must address the flag-off fallback check (Check 4)"
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
"type": "contains",
|
|
239
|
-
"value": "Check 5",
|
|
240
|
-
"message": "Response must address the analytics context check (Check 5)"
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
"type": "contains",
|
|
244
|
-
"value": "Check 6",
|
|
245
|
-
"condition": { "var": "roType", "equals": "interactive" },
|
|
246
|
-
"message": "Interactive ROs must address the onUpdate mutation check (Check 6)"
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
"type": "contains",
|
|
250
|
-
"value": "Check 7",
|
|
251
|
-
"condition": { "var": "roType", "equals": "interactive" },
|
|
252
|
-
"message": "Interactive ROs must address the interaction failure semantics check (Check 7)"
|
|
253
|
-
}
|
|
254
|
-
],
|
|
255
|
-
"requireConfirmation": false
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
}
|