dsh-plugin-agentflow 0.3.1 → 0.4.1

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.
@@ -11,6 +11,11 @@
11
11
  // GET/PUT/DELETE /api/boards/:id/draft → 草稿(手动保存前的未落定修改)
12
12
  // GET/PUT /api/board → 旧接口过渡:读写 flow-agentflow
13
13
  //
14
+ // 斜杠命令(落盘 <DATA_DIR>/commands/<name>.json,生成即生效):
15
+ // POST /api/export/command?board=<id> → 把画布挂成命令(body {name?})
16
+ // GET /api/commands → 命令列表(带画布名 / 画布是否还在)
17
+ // DELETE /api/commands/:name → 删命令
18
+ //
14
19
  // 其余路由:
15
20
  // GET / → index.html
16
21
  // POST /api/nodes → 新建节点(带 from 时自动建边)
@@ -40,7 +45,6 @@ import {
40
45
  renameBoard,
41
46
  deleteBoard,
42
47
  resolveBoard,
43
- markPresetSynced,
44
48
  getBoard,
45
49
  mutateBoardById,
46
50
  ensureDefaultBoard,
@@ -48,7 +52,11 @@ import {
48
52
  getDraft,
49
53
  deleteDraft,
50
54
  httpError,
55
+ readIndex,
56
+ boardFile,
51
57
  } from './boards.mjs';
58
+ import { assertRootHasNoUpstream } from './orchestrator.mjs';
59
+ import { deleteCommand, isValidCommandName, listCommands, writeCommand } from './commands.mjs';
52
60
  import { normalizeConfig, makeCaller } from './llm.mjs';
53
61
  import { listSkills, defaultSkillDirs } from './skills.mjs';
54
62
  import { askJev, selfVerify } from './verify.mjs';
@@ -227,28 +235,6 @@ async function ensureMcpPool() {
227
235
  }
228
236
 
229
237
  /** 给 /api/mcp 用的快照:配置了哪些 server、连没连上、有哪些工具 */
230
- /** 当前可用的全部技能名与全部 MCP 工具名(根节点默认全选) */
231
- async function allSkillsAndTools() {
232
- let skills = [];
233
- try {
234
- const dirs = (await buildCfg()).skillDirs?.length ? (await buildCfg()).skillDirs : defaultSkillDirs();
235
- const listed = await listSkills(dirs);
236
- skills = (Array.isArray(listed) ? listed : []).map((x) => x.name);
237
- } catch {
238
- skills = [];
239
- }
240
- let tools = [];
241
- try {
242
- const snap = await mcpSnapshot();
243
- for (const server of snap.servers || []) {
244
- for (const tool of server.tools || []) tools.push(`${server.name}.${tool.name}`);
245
- }
246
- } catch {
247
- tools = [];
248
- }
249
- return { skills, tools };
250
- }
251
-
252
238
  async function mcpSnapshot() {
253
239
  const cfg = await buildCfg();
254
240
  const specs = cfg.mcpServers || {};
@@ -300,18 +286,10 @@ const nowId = () => 'n' + Math.random().toString(36).slice(2, 8);
300
286
  // PUT /api/board 只允许改这些字段:拖动不该把物料冲掉
301
287
  const LAYOUT_FIELDS = ['x', 'y', 'label', 'task', 'criteria', 'model', 'provider', 'reasoningEffort', 'fallback', 'fallbackEfforts', 'type', 'skills', 'tools', 'verify', 'tool', 'args'];
302
288
 
303
- // ---------- 导出 DSH 预设 ----------
304
-
305
- // 懒加载:preset-gen.mjs 由另一个任务并行写,文件暂时不存在时不能把服务带崩
306
- let presetGen = null;
307
- async function getPresetGen() {
308
- if (presetGen) return presetGen;
309
- presetGen = await import('./preset-gen.mjs');
310
- return presetGen;
311
- }
312
-
313
- /** 给用户照着敲的安装命令。不自动改 profile —— 改 profile 的风险太大,踩过坑。 */
314
- // ---------- 把生成的预设装进 profile ----------
289
+ // ---------- 遗留预设:自定义预设装在哪个 profile ----------
290
+ //
291
+ // 预设生成已下线(画布现在导出的是斜杠命令),这里只剩历史兼容:
292
+ // /api/presets(列出/复制/删除旧预设)与 /api/boards/import-preset 还在用。
315
293
 
316
294
  // 预设写到哪个 profile:默认 DSH 桌面版的 desktop,允许用 AGENTFLOW_PROFILE 覆盖
317
295
  const PRESET_PROFILE = () =>
@@ -530,7 +508,7 @@ const server = http.createServer(async (req, res) => {
530
508
  const method = req.method;
531
509
 
532
510
  // DSH 的客户端插件在 dsh-app:// 里跑,来调本机 API 属于跨源调用。
533
- // 只放行本机壳与本机页面,不放 *:导出预设会改写 profile,不能让任意网页触发。
511
+ // 只放行本机壳与本机页面,不放 *:生成命令会写 DATA_DIR,不能让任意网页触发。
534
512
  const origin = String(req.headers.origin || '');
535
513
  const originOk = !origin
536
514
  || origin.startsWith('dsh-app://')
@@ -759,8 +737,7 @@ const server = http.createServer(async (req, res) => {
759
737
  }
760
738
  }
761
739
  try {
762
- const gen = await import('./preset-gen.mjs');
763
- gen.assertRootHasNoUpstream(incoming);
740
+ assertRootHasNoUpstream(incoming);
764
741
  } catch (err) {
765
742
  if (err && err.status) return json(res, 400, { error: String(err.message) });
766
743
  }
@@ -933,73 +910,67 @@ const server = http.createServer(async (req, res) => {
933
910
  }
934
911
  }
935
912
 
936
- // --- 导出 DSH 预设:直接写进插件包,不再生成独立包 ---
937
- if (p === '/api/export/preset' && method === 'POST') {
913
+ // --- 生成斜杠命令:把画布挂成 DSH 的命令,落盘 <DATA_DIR>/commands/<name>.json ---
914
+ if (p === '/api/export/command' && method === 'POST') {
938
915
  const ctx = await resolveBoardCtx(url.searchParams.get('board'));
939
- const profileDir = PRESET_PROFILE();
940
- const profileOk = await fs
941
- .stat(profileDir)
942
- .then((st) => st.isDirectory())
943
- .catch(() => false);
944
- if (!profileOk) {
916
+ const body = await readBody(req).catch(() => ({}));
917
+ const wantedName = body && typeof body.name === 'string' ? body.name.trim() : '';
918
+ if (wantedName && !isValidCommandName(wantedName)) {
945
919
  return json(res, 400, {
946
- error: `找不到 profile:${profileDir}(可用 AGENTFLOW_PROFILE 指定 profile 名)`,
920
+ error: `命令名不合法:${wantedName}(只允许 ^[a-z][a-z0-9_-]*$,不超过 48 个字符)`,
947
921
  });
948
922
  }
949
- const board = ctx.board;
950
- const body = await readBody(req).catch(() => ({}));
951
- // 自定义预设显示名(可选):只影响预设名,presetId 仍由画布决定
952
- const presetName = body && typeof body.name === 'string' ? body.name.trim() : '';
953
- if (!board.nodes || board.nodes.length === 0) {
923
+ if (!Array.isArray(ctx.board.nodes) || ctx.board.nodes.length === 0) {
954
924
  return json(res, 400, { error: '画布是空的,先摆几个节点' });
955
925
  }
956
- let gen;
957
- try {
958
- gen = await getPresetGen();
959
- } catch {
960
- return json(res, 500, { error: '预设生成器还没就绪(preset-gen.mjs 缺失)' });
961
- }
926
+ // name 缺省时按画布 id 生成(agentflow-<slug>,重名自动加 -2/-3)
927
+ const out = await writeCommand({ board: ctx.id, name: wantedName || undefined });
928
+ return json(res, 200, {
929
+ ok: true,
930
+ name: out.name,
931
+ board: ctx.id,
932
+ boardName: ctx.board.name || ctx.id,
933
+ file: out.file,
934
+ replaced: out.replaced,
935
+ });
936
+ }
962
937
 
963
- // 调度根节点 = 对话入口 = persona 来源。导出前先补齐:
964
- // 多节点无调度卡时自动补一张并写回画布;已有只允许一张,多了直接拒绝。
965
- let ensured;
966
- try {
967
- const { skills, tools } = await allSkillsAndTools();
968
- ensured = gen.ensureOrchestrator(board, { skills, tools });
969
- gen.assertRootHasNoUpstream(ensured.board);
970
- } catch (err) {
971
- return json(res, 400, { error: String((err && err.message) || err) });
972
- }
973
- const exportBoard = ensured.board;
974
- const addedOrchestrator = ensured.added
975
- ? { id: ensured.added.id, label: ensured.added.label }
976
- : null;
977
- const personaSource = gen.personaSource(board);
978
- if (addedOrchestrator || ensured.refreshed) {
979
- // 先写回画布再生成:根节点的人格/技能是固定模板,刷新后页面能看到最新内容
980
- await saveBoard(ctx.id, exportBoard);
938
+ // --- 命令列表:带上画布名与画布是否还在(画布删了命令不会自动消失)---
939
+ if (p === '/api/commands' && method === 'GET') {
940
+ const index = await readIndex();
941
+ const commands = [];
942
+ for (const rec of await listCommands()) {
943
+ const meta = index.boards[rec.board];
944
+ const boardExists =
945
+ Boolean(meta)
946
+ || (await fs
947
+ .stat(boardFile(rec.board))
948
+ .then((st) => st.isFile())
949
+ .catch(() => false));
950
+ let boardName = meta?.name || null;
951
+ if (!boardName && boardExists) {
952
+ boardName = (await getBoard(rec.board).catch(() => null))?.name || rec.board;
953
+ }
954
+ commands.push({
955
+ name: rec.name,
956
+ board: rec.board,
957
+ boardName,
958
+ boardExists,
959
+ createdAt: rec.createdAt,
960
+ file: rec.file,
961
+ });
981
962
  }
963
+ return json(res, 200, { commands });
964
+ }
982
965
 
983
- try {
984
- const out = await gen.installPresetIntoProfile(exportBoard, {
985
- patchFile: path.join(PRESET_PROFILE(), 'cordis.patch.yml'),
986
- ...(presetName ? { name: presetName } : {}),
987
- });
988
- await markPresetSynced(ctx.id).catch(() => {});
989
- return json(res, 200, {
990
- ok: true,
991
- profileDir: PRESET_PROFILE(),
992
- file: out.file,
993
- presetId: out.presetId,
994
- presetName: out.name,
995
- replaced: out.replaced,
996
- personaPreview: gen.renderPersona(exportBoard),
997
- addedOrchestrator,
998
- personaSource,
999
- needRestart: true,
1000
- });
1001
- } catch (err) {
1002
- return json(res, 400, { error: String((err && err.message) || err) });
966
+ // --- 删命令:DSH 侧下次扫描就没了 ---
967
+ {
968
+ const commandMatch = /^\/api\/commands\/([a-z][a-z0-9_-]{0,47})$/.exec(p);
969
+ if (commandMatch && method === 'DELETE') {
970
+ const name = commandMatch[1];
971
+ const removed = await deleteCommand(name);
972
+ if (!removed) return json(res, 404, { error: `命令不存在:${name}` });
973
+ return json(res, 200, { ok: true, name });
1003
974
  }
1004
975
  }
1005
976
 
@@ -0,0 +1 @@
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:#555;--xy-background-pattern-lines-color-default:#333;--xy-background-pattern-cross-color-default:#333;--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;touch-action:none}.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-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--color-white:#fff;--spacing:.25rem;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--leading-relaxed:1.625;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--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)}}@layer base{.af-canvas,.af-canvas *,.af-canvas :before,.af-canvas :after{box-sizing:border-box;border:0 solid;margin:0;padding:0}.af-canvas :where(h1,h2,h3,h4,h5,h6){font-size:inherit;font-weight:inherit}.af-canvas :where(ol,ul,menu){list-style:none}.af-canvas :where(a){color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}.af-canvas :where(b,strong){font-weight:bolder}.af-canvas :where(code,kbd,samp,pre){font-family:var(--mono);font-size:1em}.af-canvas :where(img,svg,video,canvas,audio,iframe,embed,object){vertical-align:middle;display:block}.af-canvas :where(img,video){max-width:100%;height:auto}.af-canvas :where(button,input,select,optgroup,textarea){font:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}.af-canvas :where(textarea){resize:vertical}.af-canvas ::placeholder{opacity:1}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-y-0{inset-block:0}.top-0{top:0}.top-14{top:calc(var(--spacing) * 14)}.top-\[12px\]{top:12px}.right-0{right:0}.bottom-0{bottom:0}.bottom-6{bottom:calc(var(--spacing) * 6)}.left-0{left:0}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-30{z-index:30}.z-50{z-index:50}.\!m-4{margin:calc(var(--spacing) * 4)!important}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-\[5px\]{margin-top:5px}.mt-auto{margin-top:auto}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-2\.5{margin-bottom:calc(var(--spacing) * 2.5)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.ml-auto{margin-left:auto}.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}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-\[2px\]{height:2px}.h-\[3px\]{height:3px}.h-\[5px\]{height:5px}.h-\[6px\]{height:6px}.h-full{height:100%}.max-h-\[180px\]{max-height:180px}.max-h-\[200px\]{max-height:200px}.max-h-\[240px\]{max-height:240px}.min-h-0{min-height:0}.min-h-\[32px\]{min-height:32px}.min-h-\[150px\]{min-height:150px}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-1\/2{width:50%}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-\[3px\]{width:3px}.w-\[5px\]{width:5px}.w-\[6px\]{width:6px}.w-\[340px\]{width:340px}.w-\[420px\]{width:420px}.w-full{width:100%}.w-px{width:1px}.max-w-\[280px\]{max-width:280px}.max-w-\[340px\]{max-width:340px}.max-w-\[1080px\]{max-width:1080px}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-6{--tw-translate-y:calc(var(--spacing) * -6);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)}.animate-spin{animation:var(--animate-spin)}.cursor-grab{cursor:grab}.resize-none{resize:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.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}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-\[2px\]{gap:2px}: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)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[3px\]{border-radius:3px}.rounded-\[4px\]{border-radius:4px}.rounded-\[6px\]{border-radius:6px}.rounded-\[7px\]{border-radius:7px}.rounded-\[8px\]{border-radius:8px}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-\[4px\]{border-top-left-radius:4px;border-top-right-radius:4px}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.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-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[\#E1E2DD\]{border-color:#e1e2dd}.border-\[\#E2E4E0\]{border-color:#e2e4e0}.border-\[\#E3E4DF\]{border-color:#e3e4df}.border-\[\#E6E7E2\]{border-color:#e6e7e2}.border-\[\#E9D9B8\]{border-color:#e9d9b8}.border-\[\#EDEEE9\]{border-color:#edeee9}.border-\[\#eef0ec\]{border-color:#eef0ec}.bg-\[\#1C1C1A\]{background-color:#1c1c1a}.bg-\[\#3fa76b\]{background-color:#3fa76b}.bg-\[\#8b8b85\]{background-color:#8b8b85}.bg-\[\#24543F\]{background-color:#24543f}.bg-\[\#B4451F\]{background-color:#b4451f}.bg-\[\#E3E4DF\]{background-color:#e3e4df}.bg-\[\#EEF3EF\]{background-color:#eef3ef}.bg-\[\#EFEFEA\]{background-color:#efefea}.bg-\[\#F4F5F2\]{background-color:#f4f5f2}.bg-\[\#F9F9F6\]{background-color:#f9f9f6}.bg-\[\#FAEFE6\]{background-color:#faefe6}.bg-\[\#FAFAF7\]{background-color:#fafaf7}.bg-\[\#FBEFEA\]{background-color:#fbefea}.bg-\[\#FBF4E6\]{background-color:#fbf4e6}.bg-\[\#FCFCFA\]{background-color:#fcfcfa}.bg-\[\#FCFCFA\]\/90{background-color:oklab(99.0514% -.000745505 .00252551/.9)}.bg-\[\#a8a8a0\]{background-color:#a8a8a0}.bg-\[\#b0b7c3\]{background-color:#b0b7c3}.bg-\[\#b6becb\]{background-color:#b6becb}.bg-\[\#c2410c\]{background-color:#c2410c}.bg-\[\#e05252\]{background-color:#e05252}.bg-\[\#eef3fe\]{background-color:#eef3fe}.bg-\[\#f0a020\]{background-color:#f0a020}.bg-\[\#f1eefe\]{background-color:#f1eefe}.bg-\[\#f2f4f7\]{background-color:#f2f4f7}.bg-\[\#fbeee8\]{background-color:#fbeee8}.bg-\[\#fcfcfd\]{background-color:#fcfcfd}.bg-\[\#ffebee\]{background-color:#ffebee}.bg-current{background-color:currentColor}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-0{padding:0}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-\[3px\]{padding:3px}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.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:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-7{padding-block:calc(var(--spacing) * 7)}.py-14{padding-block:calc(var(--spacing) * 14)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-\[5px\]{padding-block:5px}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[20px\]{font-size:20px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.3\]{--tw-leading:1.3;line-height:1.3}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.6\]{--tw-leading:1.6;line-height:1.6}.leading-\[1\.65\]{--tw-leading:1.65;line-height:1.65}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.01em\]{--tw-tracking:.01em;letter-spacing:.01em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.text-\[\#1B1B18\]{color:#1b1b18}.text-\[\#1C1C1A\]{color:#1c1c1a}.text-\[\#5F5F59\]{color:#5f5f59}.text-\[\#5b6472\]{color:#5b6472}.text-\[\#6b6b66\]{color:#6b6b66}.text-\[\#7C7C75\]{color:#7c7c75}.text-\[\#7c6cf0\]{color:#7c6cf0}.text-\[\#8a93a3\]{color:#8a93a3}.text-\[\#8a6220\]{color:#8a6220}.text-\[\#8b8b85\]{color:#8b8b85}.text-\[\#98a1b0\]{color:#98a1b0}.text-\[\#24543F\]{color:#24543f}.text-\[\#333330\]{color:#333330}.text-\[\#B4451F\]{color:#b4451f}.text-\[\#a8542f\]{color:#a8542f}.text-\[\#aeb6c3\]{color:#aeb6c3}.text-\[\#c62828\]{color:#c62828}.text-white{color:var(--color-white)}.italic{font-style:italic}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.shadow-\[0_1px_2px_rgba\(0\,0\,0\,0\.06\)\]{--tw-shadow:0 1px 2px var(--tw-shadow-color,#0000000f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_3px_rgba\(20\,24\,20\,0\.06\)\,0_10px_28px_-18px_rgba\(20\,24\,20\,0\.22\)\]{--tw-shadow:0 1px 3px var(--tw-shadow-color,#1418140f), 0 10px 28px -18px var(--tw-shadow-color,#14181438);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_4px_16px_rgba\(16\,24\,40\,0\.06\)\]{--tw-shadow:0 4px 16px var(--tw-shadow-color,#1018280f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_6px_20px_rgba\(16\,24\,40\,0\.07\)\]{--tw-shadow:0 6px 20px var(--tw-shadow-color,#10182812);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_6px_20px_rgba\(16\,24\,40\,0\.08\)\]{--tw-shadow:0 6px 20px var(--tw-shadow-color,#10182814);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_10px_30px_-12px_rgba\(36\,84\,63\,0\.35\)\]{--tw-shadow:0 10px 30px -12px var(--tw-shadow-color,#24543f59);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px 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{--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-\[\#24543F\]{--tw-ring-color:#24543f}.ring-offset-2{--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)}.ring-offset-\[\#F4F5F2\]{--tw-ring-offset-color:#f4f5f2}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{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-shadow{transition-property:box-shadow;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}.outline-none{--tw-outline-style:none;outline-style:none}.placeholder\:text-\[\#9a9a92\]::placeholder{color:#9a9a92}.placeholder\:text-\[\#a8a8a0\]::placeholder{color:#a8a8a0}.first\:mt-1:first-child{margin-top:var(--spacing)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:bg-\[\#1D4634\]:hover{background-color:#1d4634}.hover\:bg-\[\#EFEFEA\]:hover{background-color:#efefea}.hover\:bg-\[\#FBEFEA\]:hover{background-color:#fbefea}.hover\:bg-\[\#eafaef\]:hover{background-color:#eafaef}.hover\:bg-\[\#eef3fe\]:hover{background-color:#eef3fe}.hover\:bg-white\/60:hover{background-color:#fff9}@supports (color:color-mix(in lab, red, red)){.hover\:bg-white\/60:hover{background-color:color-mix(in oklab, var(--color-white) 60%, transparent)}}.hover\:text-\[\#1B1B18\]:hover{color:#1b1b18}.hover\:text-\[\#2e7d32\]:hover{color:#2e7d32}.hover\:text-\[\#24543F\]:hover{color:#24543f}.hover\:text-\[\#B4451F\]:hover{color:#b4451f}.hover\:opacity-70:hover{opacity:.7}.hover\:shadow-\[0_2px_6px_rgba\(20\,24\,20\,0\.08\)\,0_16px_36px_-20px_rgba\(20\,24\,20\,0\.3\)\]:hover{--tw-shadow:0 2px 6px var(--tw-shadow-color,#14181414), 0 16px 36px -20px var(--tw-shadow-color,#1418144d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.focus\:border-\[\#24543F\]:focus{border-color:#24543f}.focus\:bg-white:focus{background-color:var(--color-white)}.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-\[\#24543F\]\/30:focus-visible{--tw-ring-color:oklab(40.5771% -.0609612 .0189529/.3)}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-transparent:disabled{background-color:#0000}.disabled\:opacity-35:disabled{opacity:.35}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media (hover:hover){.disabled\:hover\:bg-transparent:disabled:hover{background-color:#0000}}@media (width>=48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.dark\:border-\[\#2A2C31\]:where(.dark,.dark *){border-color:#2a2c31}.dark\:border-\[\#2E3037\]:where(.dark,.dark *){border-color:#2e3037}.dark\:border-\[\#4a3a1c\]:where(.dark,.dark *){border-color:#4a3a1c}.dark\:border-\[\#262b36\]:where(.dark,.dark *){border-color:#262b36}.dark\:border-\[\#33353B\]:where(.dark,.dark *){border-color:#33353b}.dark\:border-\[\#232421\]:where(.dark,.dark *){border-color:#232421}.dark\:border-\[\#262724\]:where(.dark,.dark *){border-color:#262724}.dark\:bg-\[\#0f1116\]:where(.dark,.dark *){background-color:#0f1116}.dark\:bg-\[\#1B1C20\]:where(.dark,.dark *){background-color:#1b1c20}.dark\:bg-\[\#1B2A22\]:where(.dark,.dark *){background-color:#1b2a22}.dark\:bg-\[\#1E1F24\]:where(.dark,.dark *){background-color:#1e1f24}.dark\:bg-\[\#1a1d25\]:where(.dark,.dark *){background-color:#1a1d25}.dark\:bg-\[\#1b2a44\]:where(.dark,.dark *){background-color:#1b2a44}.dark\:bg-\[\#2A1C17\]:where(.dark,.dark *){background-color:#2a1c17}.dark\:bg-\[\#2a2314\]:where(.dark,.dark *){background-color:#2a2314}.dark\:bg-\[\#2a2440\]:where(.dark,.dark *){background-color:#2a2440}.dark\:bg-\[\#2c2d29\]:where(.dark,.dark *){background-color:#2c2d29}.dark\:bg-\[\#3A3B35\]:where(.dark,.dark *){background-color:#3a3b35}.dark\:bg-\[\#3F7A5F\]:where(.dark,.dark *){background-color:#3f7a5f}.dark\:bg-\[\#3a1b1f\]:where(.dark,.dark *){background-color:#3a1b1f}.dark\:bg-\[\#6aa583\]:where(.dark,.dark *){background-color:#6aa583}.dark\:bg-\[\#6b7385\]:where(.dark,.dark *){background-color:#6b7385}.dark\:bg-\[\#6ee7a0\]:where(.dark,.dark *){background-color:#6ee7a0}.dark\:bg-\[\#6f6f68\]:where(.dark,.dark *){background-color:#6f6f68}.dark\:bg-\[\#8b8b85\]:where(.dark,.dark *){background-color:#8b8b85}.dark\:bg-\[\#181b23\]:where(.dark,.dark *){background-color:#181b23}.dark\:bg-\[\#17181B\]:where(.dark,.dark *),.dark\:bg-\[\#17181b\]:where(.dark,.dark *){background-color:#17181b}.dark\:bg-\[\#17181b\]\/90:where(.dark,.dark *){background-color:oklab(20.9238% .000118949 -.00610654/.9)}.dark\:bg-\[\#39231a\]:where(.dark,.dark *){background-color:#39231a}.dark\:bg-\[\#111214\]:where(.dark,.dark *){background-color:#111214}.dark\:bg-\[\#121312\]\/90:where(.dark,.dark *){background-color:oklab(18.5187% -.0021049 .00144818/.9)}.dark\:bg-\[\#151617\]:where(.dark,.dark *){background-color:#151617}.dark\:bg-\[\#232421\]:where(.dark,.dark *){background-color:#232421}.dark\:bg-\[\#232733\]:where(.dark,.dark *){background-color:#232733}.dark\:bg-\[\#e7e9ee\]:where(.dark,.dark *){background-color:#e7e9ee}.dark\:bg-\[\#e08a6a\]:where(.dark,.dark *){background-color:#e08a6a}.dark\:bg-\[\#f4b95f\]:where(.dark,.dark *){background-color:#f4b95f}.dark\:bg-\[\#f28b8b\]:where(.dark,.dark *){background-color:#f28b8b}.dark\:bg-\[\#fb923c\]:where(.dark,.dark *){background-color:#fb923c}.dark\:text-\[\#0f1116\]:where(.dark,.dark *){color:#0f1116}.dark\:text-\[\#6d7586\]:where(.dark,.dark *){color:#6d7586}.dark\:text-\[\#8E8E86\]:where(.dark,.dark *){color:#8e8e86}.dark\:text-\[\#8FC3A7\]:where(.dark,.dark *){color:#8fc3a7}.dark\:text-\[\#8b8b85\]:where(.dark,.dark *){color:#8b8b85}.dark\:text-\[\#8b93a5\]:where(.dark,.dark *){color:#8b93a5}.dark\:text-\[\#8fb3f2\]:where(.dark,.dark *){color:#8fb3f2}.dark\:text-\[\#A8A8A0\]:where(.dark,.dark *){color:#a8a8a0}.dark\:text-\[\#E08A6A\]:where(.dark,.dark *){color:#e08a6a}.dark\:text-\[\#EDEDE8\]:where(.dark,.dark *){color:#edede8}.dark\:text-\[\#a3a39b\]:where(.dark,.dark *){color:#a3a39b}.dark\:text-\[\#a7aebb\]:where(.dark,.dark *){color:#a7aebb}.dark\:text-\[\#b3a6fa\]:where(.dark,.dark *){color:#b3a6fa}.dark\:text-\[\#c9cdc7\]:where(.dark,.dark *){color:#c9cdc7}.dark\:text-\[\#e0b866\]:where(.dark,.dark *){color:#e0b866}.dark\:text-\[\#e7e9ee\]:where(.dark,.dark *){color:#e7e9ee}.dark\:text-\[\#e08a6a\]:where(.dark,.dark *){color:#e08a6a}.dark\:text-\[\#e8e8e4\]:where(.dark,.dark *){color:#e8e8e4}.dark\:text-\[\#e9a484\]:where(.dark,.dark *){color:#e9a484}.dark\:text-\[\#ff9a9a\]:where(.dark,.dark *){color:#ff9a9a}.dark\:shadow-\[0_1px_3px_rgba\(0\,0\,0\,0\.5\)\,0_10px_28px_-18px_rgba\(0\,0\,0\,0\.7\)\]:where(.dark,.dark *){--tw-shadow:0 1px 3px var(--tw-shadow-color,#00000080), 0 10px 28px -18px var(--tw-shadow-color,#000000b3);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.dark\:shadow-\[0_4px_16px_rgba\(0\,0\,0\,0\.4\)\]:where(.dark,.dark *){--tw-shadow:0 4px 16px var(--tw-shadow-color,#0006);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.dark\:shadow-\[0_6px_20px_rgba\(0\,0\,0\,0\.5\)\]:where(.dark,.dark *){--tw-shadow:0 6px 20px var(--tw-shadow-color,#00000080);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.dark\:shadow-\[0_10px_30px_-12px_rgba\(0\,0\,0\,0\.65\)\]:where(.dark,.dark *){--tw-shadow:0 10px 30px -12px var(--tw-shadow-color,#000000a6);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.dark\:ring-\[\#6aa583\]:where(.dark,.dark *){--tw-ring-color:#6aa583}.dark\:ring-offset-\[\#121312\]:where(.dark,.dark *){--tw-ring-offset-color:#121312}.dark\:placeholder\:text-\[\#6f6f68\]:where(.dark,.dark *)::placeholder{color:#6f6f68}@media (hover:hover){.dark\:hover\:bg-\[\#1b2a44\]:where(.dark,.dark *):hover{background-color:#1b2a44}.dark\:hover\:bg-\[\#1b3327\]:where(.dark,.dark *):hover{background-color:#1b3327}.dark\:hover\:bg-\[\#2A1C17\]:where(.dark,.dark *):hover{background-color:#2a1c17}.dark\:hover\:bg-\[\#4B8B6D\]:where(.dark,.dark *):hover{background-color:#4b8b6d}.dark\:hover\:bg-\[\#232421\]:where(.dark,.dark *):hover{background-color:#232421}.dark\:hover\:text-\[\#6ee7a0\]:where(.dark,.dark *):hover{color:#6ee7a0}.dark\:hover\:text-\[\#8fb3f2\]:where(.dark,.dark *):hover{color:#8fb3f2}.dark\:hover\:text-\[\#e08a6a\]:where(.dark,.dark *):hover{color:#e08a6a}.dark\:hover\:text-\[\#e8e8e4\]:where(.dark,.dark *):hover{color:#e8e8e4}.dark\:hover\:shadow-\[0_2px_6px_rgba\(0\,0\,0\,0\.55\)\,0_16px_36px_-20px_rgba\(0\,0\,0\,0\.8\)\]:where(.dark,.dark *):hover{--tw-shadow:0 2px 6px var(--tw-shadow-color,#0000008c), 0 16px 36px -20px var(--tw-shadow-color,#000c);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.dark\:focus\:border-\[\#6aa583\]:where(.dark,.dark *):focus{border-color:#6aa583}.dark\:focus\:bg-\[\#1B1C20\]:where(.dark,.dark *):focus{background-color:#1b1c20}.dark\:focus-visible\:ring-\[\#6aa583\]\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:oklab(67.1614% -.0742714 .0298978/.4)}.\[\&_button\]\:h-7 button{height:calc(var(--spacing) * 7)}.\[\&_button\]\:w-7 button{width:calc(var(--spacing) * 7)}.\[\&_button\]\:border-b button{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_button\]\:border-\[\#eef1f5\] button{border-color:#eef1f5}.\[\&_button\]\:bg-white button{background-color:var(--color-white)}.\[\&_button\]\:text-\[\#5b6472\] button{color:#5b6472}.\[\&_button\:hover\]\:bg-\[\#f5f7fa\] button:hover{background-color:#f5f7fa}}.af-canvas{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--bg:#f4f5f2;--fg:#1c1c1a;--line:#e2e4e0;--accent:#c2410c;--ink:#24543f;--muted:#6b6b66;--mono:ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;height:100%;color:var(--fg);background:var(--bg);-webkit-font-smoothing:antialiased;margin:0;font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Hiragino Sans GB,Microsoft YaHei,ui-sans-serif,sans-serif;font-size:15px;line-height:1.65;transition:background .2s,color .2s;position:relative}.af-canvas.dark{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--bg:#121312;--fg:#e8e8e4;--line:#262724;--accent:#f97316;--ink:#6aa583;--muted:#8b8b85}.af-canvas .mono{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.01em}.af-canvas .react-flow__node{font-family:inherit}.af-canvas .react-flow__handle{background:#b9bcb4;border:2px solid #fff;width:9px;height:9px;transition:background .15s,transform .15s}.af-canvas.dark .react-flow__handle{background:#4a4d47;border-color:#1a1b19}.af-canvas .react-flow__handle:hover{background:var(--ink);transform:scale(1.25)}.af-canvas .react-flow__controls{border:1px solid var(--line);border-radius:8px;overflow:hidden;box-shadow:0 1px 3px #0000000f}.af-canvas .react-flow__controls-button{border-color:var(--line);color:#3f3f3a;fill:#3f3f3a;background:#fff}.af-canvas .react-flow__controls-button:hover{background:#f0f1ed}.af-canvas.dark .react-flow__controls{border-color:var(--line);background:#1a1b19}.af-canvas.dark .react-flow__controls-button{border-color:var(--line);color:#c9cec7;fill:#c9cec7;background:#1a1b19}.af-canvas.dark .react-flow__controls-button:hover{background:#232421}.af-canvas .react-flow__minimap{border:1px solid var(--line);border-radius:8px;overflow:hidden}.af-canvas.dark .react-flow__minimap{border-color:var(--line);background:#151614}.af-canvas .react-flow__node:focus-visible{outline:2px solid var(--ink);outline-offset:3px}@keyframes af-bar-scan{0%{transform:translate(-120%)}to{transform:translate(240%)}}.af-canvas .af-bar-scan{background:linear-gradient(90deg,#fff0 0%,#fffffff2 50%,#fff0 100%);animation:1.2s linear infinite af-bar-scan}@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-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}