@hmj-ai/cflow 1.2.0 → 1.3.2
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/public/assets/index-DzsWw3GO.js +16 -0
- package/dist/public/assets/index-oZC2r1XL.css +1 -0
- package/dist/public/cflow-lockup.svg +35 -0
- package/dist/public/cflow-mark.svg +23 -0
- package/dist/public/index.html +4 -4
- package/dist/src/compiler.js +30 -0
- package/dist/src/flow-agent.js +2 -2
- package/dist/src/server.js +75 -11
- package/dist/src/workspace-files.js +82 -0
- package/package.json +1 -1
- package/dist/public/assets/index-C1_cd_s8.css +0 -1
- package/dist/public/assets/index-DsBDM4p-.js +0 -15
|
@@ -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-text{fill:var(--xy-edge-label-color,var(--xy-edge-label-color-default))}:root{color:#1d2126;font-synthesis:none;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;--paper:#f6f7f9;--paper-deep:#eef0f4;--surface:#fff;--white:#fff;--panel:#fbfbfc;--inset:#f2f4f7;--text:#1d2126;--muted:#5b636d;--faint:#8a919b;--border:#e5e8ec;--border-strong:#d2d7de;--accent:#35569e;--accent-deep:#2b4681;--accent-soft:#eef1f8;--green:#16794e;--green-soft:#e8f3ed;--red:#b0392d;--red-soft:#fbecea;--amber:#8f6314;--amber-soft:#fbf2df;--blue:#35569e;--orange:var(--accent);--orange-deep:var(--accent-deep);--ink:#f0f2f5;--ink-soft:#e9ecf1;--ink-line:#e5e8ec;--topbar-height:52px;--detail-width:300px;--agent-width:340px;--rail-width:50px;--drawer-height:min(38vh, 320px);--radius:9px;--shadow-pop:0 8px 24px #18202e1a;background:#f6f7f9;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans CJK SC,Source Han Sans SC,PingFang SC,Microsoft YaHei,system-ui,sans-serif}*{box-sizing:border-box}html,body,#root{width:100%;height:100%;margin:0}body{min-width:1280px;overflow:hidden}button,input,select,textarea{font:inherit}button{color:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}button:disabled{cursor:not-allowed;opacity:.46}code,pre{font-family:SFMono-Regular,Consolas,Liberation Mono,monospace}.app-frame{grid-template-rows:var(--topbar-height) auto minmax(0, 1fr);width:100%;min-width:1280px;height:100%;display:grid;position:relative;overflow:hidden}.notice-stack{display:grid}.workbench{grid-template-columns:var(--detail-width) minmax(560px, 1fr) var(--agent-width);min-height:0;transition:grid-template-columns .18s cubic-bezier(.22,1,.36,1);display:grid;overflow:hidden}.workbench.left-collapsed{grid-template-columns:var(--rail-width) minmax(560px, 1fr) var(--agent-width)}.workbench.right-collapsed{grid-template-columns:var(--detail-width) minmax(560px, 1fr) var(--rail-width)}.workbench.left-collapsed.right-collapsed{grid-template-columns:var(--rail-width) minmax(560px, 1fr) var(--rail-width)}.workbench.is-empty{grid-template-columns:minmax(0,1fr)}.brand-mark{-webkit-user-select:none;user-select:none;border-radius:8px;flex:none;width:34px;height:34px;display:block}.new-flow-button{height:36px;color:var(--accent);background:var(--surface);border:1px solid var(--border-strong);cursor:pointer;border-radius:8px;justify-content:center;align-items:center;gap:8px;font-size:12px;font-weight:600;display:flex}.new-flow-button:hover{background:var(--accent-soft);border-color:var(--accent)}.search-field{height:34px;color:var(--muted);background:var(--inset);border:1px solid var(--border);border-radius:7px;align-items:center;gap:7px;padding:0 9px;display:flex}.search-field input{width:100%;min-width:0;color:var(--text);background:0 0;border:0;outline:0;font-size:12px}.search-field input::placeholder{color:var(--faint)}.flow-list-item{width:100%;color:var(--muted);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;grid-template-columns:10px minmax(0,1fr);gap:9px;padding:9px;display:grid;position:relative}.flow-list-item.has-action{cursor:default;grid-template-columns:minmax(0,1fr) 30px;gap:2px;padding:0}.flow-list-main{min-width:0;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;grid-template-columns:10px minmax(0,1fr);gap:9px;padding:9px 0 9px 9px;display:grid}.flow-list-delete{width:28px;height:28px;color:var(--faint);cursor:pointer;background:0 0;border:0;border-radius:7px;align-self:center;place-items:center;display:grid}.flow-list-item:hover{color:var(--text);background:var(--inset)}.flow-list-delete:hover:not(:disabled){color:var(--red);background:var(--red-soft)}.flow-list-item.is-current{color:var(--text);background:var(--accent-soft)}.flow-list-item.is-current:before{content:"";background:var(--orange);border-radius:0 2px 2px 0;width:3px;position:absolute;top:8px;bottom:8px;left:-9px}.flow-list-item>span:last-child,.flow-list-main>span:last-child{min-width:0}.flow-list-item strong,.flow-list-item small{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.flow-list-item strong{font-size:12px;font-weight:550}.flow-list-item small{color:var(--faint);margin-top:3px;font-size:10px}.route-lamp{background:var(--amber);border:1px solid var(--amber);border-radius:50%;width:8px;height:8px;margin-top:4px}.route-lamp.is-published{background:var(--green);border-color:var(--green)}.service-health{min-width:0;color:var(--faint);font-size:10px}.icon-button{width:34px;height:34px;color:var(--muted);background:var(--surface);border:1px solid var(--border);cursor:pointer;border-radius:8px;flex:none;place-items:center;padding:0;display:inline-grid}.icon-button:hover{color:var(--text);background:var(--white);border-color:var(--border-strong)}.icon-button.on-dark{color:var(--muted);background:0 0;border-color:#0000}.icon-button.on-dark:hover{color:var(--text);background:var(--inset);border-color:var(--border)}.route-state{background:var(--amber);border:2px solid var(--surface);width:11px;height:11px;box-shadow:0 0 0 1px var(--amber);border-radius:50%;flex:none}.route-state.is-running{background:var(--orange);box-shadow:0 0 0 1px var(--orange-deep)}.route-state.is-passed,.route-state.is-published{background:var(--green);box-shadow:0 0 0 1px #245c43}.route-state.is-failed{background:var(--red);box-shadow:0 0 0 1px #813326}.route-state.is-cancelled{background:var(--amber);box-shadow:0 0 0 1px var(--amber)}.button{min-height:34px;color:var(--text);background:var(--surface);border:1px solid var(--border-strong);cursor:pointer;white-space:nowrap;border-radius:7px;flex:none;justify-content:center;align-items:center;gap:7px;padding:0 11px;font-size:11px;font-weight:600;transition:background .15s,border-color .15s,transform .15s;display:inline-flex}.button:hover:not(:disabled){background:var(--white);border-color:var(--border-strong);transform:translateY(-1px)}.button.signal{color:#fff;background:var(--orange);border-color:var(--orange-deep)}.button.signal:hover:not(:disabled){background:var(--accent-deep)}.button.publish{color:var(--green);background:var(--surface);border-color:var(--border-strong)}.button.publish.signal{color:#fff;background:var(--green);border-color:var(--green)}.button.publish:hover:not(:disabled){border-color:var(--green)}.button.publish.signal:hover:not(:disabled){background:#12633f}.button.danger{color:var(--red);border-color:var(--red)}.button.full{width:100%}.button.is-active{color:var(--orange-deep);background:var(--accent-soft);border-color:var(--border-strong)}.count{background:var(--paper-deep);border-radius:9px;place-items:center;min-width:18px;height:18px;padding:0 5px;font-size:9px;display:grid}.save-state{color:var(--muted);align-items:center;gap:5px;font-size:10px;display:flex}.save-state.is-dirty{color:var(--amber)}.save-state.is-error{color:var(--red)}.operation-notice{color:#314037;background:var(--inset);border-bottom:1px solid var(--border);flex:none;grid-template-columns:10px minmax(0,1fr) 28px;align-items:center;gap:9px;min-height:44px;padding:6px 10px 6px 16px;display:grid}.operation-notice.error{color:var(--red);background:var(--red-soft);border-color:var(--border-strong)}.operation-notice.success{color:#24583f;background:var(--green-soft);border-color:var(--green)}.operation-notice strong,.operation-notice p{margin:0;display:block}.operation-notice strong{font-size:11px}.operation-notice p{margin-top:1px;font-size:10px}.operation-notice>button{color:currentColor;cursor:pointer;background:0 0;border:0;width:28px;height:28px;font-size:18px}.approval-notice{color:#63451e;background:var(--amber-soft);border-bottom:1px solid var(--amber);flex:none;grid-template-columns:10px minmax(0,1fr) auto;align-items:center;gap:10px;min-height:56px;padding:8px 12px 8px 16px;display:grid}.workspace-unavailable-notice{min-height:52px;color:var(--red);background:var(--red-soft);border-bottom:1px solid var(--border-strong);flex:none;grid-template-columns:10px minmax(0,1fr);align-items:center;gap:10px;padding:8px 16px;display:grid}.workspace-unavailable-notice .status-lamp{background:var(--red)}.workspace-unavailable-notice strong,.workspace-unavailable-notice p{margin:0}.workspace-unavailable-notice strong{font-size:11px}.workspace-unavailable-notice p{margin-top:2px;font-size:10px}.approval-notice>div:last-child{gap:7px;display:flex}.approval-notice strong,.approval-notice p{margin:0;display:block}.approval-notice strong{font-size:11px}.approval-notice p{margin-top:2px;font-size:10px}.signal-emblem{width:58px;height:58px;color:var(--accent);background:var(--accent-soft);border:1px solid var(--border);box-shadow:none;border-radius:14px;place-items:center;margin:0 auto 17px;display:grid}.view-kicker{color:var(--orange-deep);letter-spacing:.06em;font-size:10px;font-weight:600}.messages{gap:18px;max-width:760px;margin:0 auto;display:grid}.message{grid-template-columns:30px minmax(0,1fr);gap:11px;display:grid}.message-avatar{width:30px;height:30px;color:var(--inset);background:var(--ink);border-radius:7px;place-items:center;font-size:10px;font-weight:600;display:grid}.message-avatar img,.agent-message-avatar img{border-radius:inherit;width:100%;height:100%;display:block}.message.is-user .message-avatar{color:#fff;background:var(--orange)}.message strong{font-size:11px}.message p{white-space:pre-wrap;max-width:70ch;margin:4px 0 0;font-size:13px;line-height:1.55}.message small{color:var(--muted);margin-top:5px;font:10px SFMono-Regular,Consolas,monospace;display:block}.retry-button{color:var(--accent-deep);background:var(--accent-soft);border:1px solid var(--border-strong);cursor:pointer;border-radius:6px;align-items:center;gap:5px;margin-top:8px;padding:5px 8px;font-size:10px;font-weight:600;display:inline-flex}.retry-button:hover{color:var(--accent);border-color:var(--accent)}.thinking{color:var(--muted);align-items:center;gap:7px;display:flex}.goal-composer{background:var(--white);border:1px solid var(--border-strong);border-radius:12px;flex:none;width:min(790px,100% - 48px);margin:0 auto 18px;box-shadow:0 9px 26px #353a311c}.goal-composer:focus-within{border-color:var(--orange);box-shadow:0 0 0 2px #35569e26}.goal-composer textarea{resize:vertical;width:100%;min-height:74px;max-height:180px;color:var(--text);background:0 0;border:0;outline:0;padding:13px 14px 6px;font-size:14px;line-height:1.5;display:block}.goal-composer textarea::placeholder{color:var(--muted)}.visually-hidden{clip:rect(0, 0, 0, 0)!important;white-space:nowrap!important;border:0!important;width:1px!important;height:1px!important;margin:-1px!important;padding:0!important;position:absolute!important;overflow:hidden!important}.skill-attachments{background:var(--surface);border:1px solid var(--border);border-radius:8px;margin:2px 12px 8px;padding:9px 10px 10px}.attachment-summary{justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px;display:flex}.attachment-summary>div{align-items:baseline;gap:8px;min-width:0;display:flex}.attachment-summary strong{color:var(--text);font-size:11px}.attachment-summary span{color:var(--muted);font-size:10px}.attachment-clear{color:var(--muted);cursor:pointer;background:0 0;border:0;border-radius:4px;padding:2px 4px;font-size:10px}.attachment-clear:hover{color:var(--red)}.attachment-list{grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin:0;padding:0;list-style:none;display:grid}.skill-attachment{min-width:0;height:30px;color:var(--text);background:var(--white);border:1px solid var(--border);border-radius:6px;align-items:center;gap:6px;padding:0 5px 0 8px;font-size:10px;display:flex}.skill-attachment>svg{color:var(--orange-deep);flex:none}.skill-attachment>span{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.skill-attachment small{color:var(--muted);white-space:nowrap;flex:none}.skill-attachment button{width:24px;height:24px;color:var(--muted);cursor:pointer;background:0 0;border:0;border-radius:5px;flex:none;place-items:center;padding:0;display:grid}.skill-attachment button:hover{color:var(--red);background:var(--red-soft)}.attachment-overflow{color:var(--muted);margin:7px 0 0;font-size:10px}.attachment-button{border:1px solid var(--border);background:var(--surface);color:var(--text);cursor:pointer;border-radius:6px;align-items:center;gap:6px;height:30px;padding:0 8px;font-size:10px;display:inline-flex}.attachment-button:hover{border-color:var(--orange);color:var(--orange)}.attachment-button:disabled{cursor:not-allowed;opacity:.55}.composer-footer{align-items:center;gap:8px;min-height:44px;padding:4px 7px 7px 10px;display:flex}.composer-footer>span{color:var(--muted);flex:1;font-size:10px}.runtime-select{background:var(--surface);border:1px solid var(--border);border-radius:6px;align-items:center;gap:5px;height:30px;padding:0 7px;display:flex}.runtime-select select{background:0 0;border:0;outline:0;max-width:150px;font-size:11px}.send-button{color:#fff;background:var(--orange);border:1px solid var(--orange-deep);cursor:pointer;border-radius:8px;place-items:center;width:34px;height:34px;display:grid}.canvas-view{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;overflow:hidden}.canvas-workspace{flex-direction:row;flex:1;min-width:0;min-height:0;display:flex;overflow:hidden}.canvas-toolbar{background:var(--surface);border-bottom:1px solid var(--border);flex:none;align-items:center;gap:7px;min-height:48px;padding:7px 10px;display:flex;overflow-x:auto}.toolbar-divider{background:var(--border);flex:none;width:1px;height:22px}.library-tray{background:var(--paper-deep);border-right:1px solid var(--border);flex-direction:column;flex:0 0 268px;width:268px;min-width:268px;min-height:0;display:flex;overflow:hidden}.library-tray.is-collapsed{flex-basis:50px;width:50px;min-width:50px}.library-header{flex:none;align-items:center;gap:8px;min-height:46px;padding:8px 8px 6px 12px;display:flex}.library-header>div{flex:1;min-width:0}.library-header strong,.library-header span{display:block}.library-header strong{font-size:12px;font-weight:600}.library-header span{color:var(--muted);margin-top:2px;font-size:10px}.library-toggle{flex:none}.library-search{height:32px;color:var(--muted);background:var(--surface);border:1px solid var(--border);border-radius:7px;flex:none;align-items:center;gap:6px;margin:0 10px 8px;padding:0 8px;display:flex}.library-search input{width:100%;min-width:0;color:var(--text);background:0 0;border:0;outline:0;font-size:12px}.library-search input::placeholder{color:var(--muted)}.library-scroll{flex:1;min-height:0;padding:0 8px 14px;overflow-y:auto}.library-group+.library-group{margin-top:10px}.library-group-header{width:100%;min-height:28px;color:var(--text);background:0 0;border:0;align-items:center;gap:6px;padding:0 4px;font-size:11px;font-weight:600;display:flex}.library-group-header strong{color:var(--muted);margin-left:auto;font-size:10px;font-weight:600}.library-group-body{gap:8px;padding:6px 0 4px;display:grid}.library-card{background:var(--surface);border:1px solid var(--border);border-radius:8px;overflow:hidden}.library-card-row{display:block}.library-card-main{text-align:left;cursor:pointer;background:0 0;border:0;grid-template-columns:34px minmax(0,1fr) 16px;align-items:center;gap:8px;min-width:0;padding:8px 6px 8px 8px;display:grid}.library-card-main strong,.library-card-main small{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.library-card-main strong{font-size:11px}.library-card-main small{color:var(--muted);margin-top:3px;font-size:9px}.library-card-main:hover{color:var(--text);background:var(--white)}.library-empty{color:var(--muted);margin:4px 6px 8px;font-size:11px;line-height:1.5}.library-rail-button{width:100%;height:100%;color:var(--muted);cursor:pointer;writing-mode:vertical-rl;letter-spacing:.08em;background:0 0;border:0;align-items:center;gap:12px;padding:14px 0;font-size:10px;font-weight:600;display:flex}.library-rail-button:hover{color:var(--text);background:#fbfaf5b3}.capability-mark{color:#fff;background:var(--blue);border-radius:6px;place-items:center;width:32px;height:32px;font-size:9px;font-weight:600;display:grid}.capability-mark.candidate{color:#6e4719;background:var(--amber-soft)}.flow-canvas-shell{background:var(--paper);flex:1;min-height:0}.react-flow__viewport{cursor:grab}.react-flow__viewport:active{cursor:grabbing}.react-flow__node{cursor:grab}.react-flow__node.dragging{cursor:grabbing}.react-flow__edge-path{stroke:#68746b;stroke-width:2.5px}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path{stroke:var(--orange);stroke-width:3.5px}.react-flow__edge-text{fill:var(--text);font-size:10px}.react-flow__edge-textbg{fill:var(--surface)}.react-flow__controls{border:1px solid var(--border-strong);border-radius:8px;overflow:hidden;box-shadow:0 3px 8px #2e342d1a}.react-flow__controls-button{color:var(--text);background:var(--surface);border-bottom-color:var(--border)}.react-flow__controls-button:hover{background:var(--white)}.react-flow__minimap{border:1px solid var(--border-strong);box-shadow:none;border-radius:8px}.flow-card{width:190px;color:var(--text);background:var(--white);border:1px solid var(--border-strong);border-radius:11px;overflow:hidden;box-shadow:0 5px 14px #2e342d1c}.flow-card:hover,.flow-card.is-selected{border-color:var(--orange);box-shadow:0 0 0 2px #ce6f322e,0 7px 18px #2e342d26}.flow-card.is-running,.flow-card.is-pending,.flow-card.is-waiting-approval{border-color:#ce6f3273}.flow-card.is-completed,.flow-card.is-published{border-color:#2f7d5559}.flow-card.is-failed,.flow-card.is-blocked{border-color:#b5474759}.flow-card.is-inactive,.flow-card.is-draft{border-color:var(--border-strong)}.flow-card-head{color:var(--muted);justify-content:space-between;align-items:center;padding:8px 10px 6px;display:flex}.node-kind{color:var(--blue);text-transform:uppercase;font-size:9px;font-weight:600}.flow-card-branch .node-kind{color:var(--orange-deep)}.flow-card-join .node-kind{color:var(--green)}.flow-card-approval .node-kind{color:var(--amber)}.flow-card-output .node-kind{color:var(--ink)}.node-index{color:var(--faint);font:9px SFMono-Regular,Consolas,monospace}.flow-card>strong{-webkit-line-clamp:2;-webkit-box-orient:vertical;padding:0 10px;font-size:14px;line-height:1.35;display:-webkit-box;overflow:hidden}.flow-card>p{height:34px;color:var(--muted);margin:4px 0 8px;padding:0 10px;font-size:10px;line-height:1.45;overflow:hidden}.flow-card-bindings{min-height:28px;color:var(--muted);gap:3px;padding:0 10px 7px;font-size:9px;line-height:1.35;display:grid}.flow-card-bindings span{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.flow-card-bindings .is-bound{color:var(--green)}.flow-card-bindings .is-unbound{color:var(--faint)}.flow-card-config{color:var(--orange-deep);background:var(--accent-soft);border:1px solid var(--border-strong);text-overflow:ellipsis;white-space:nowrap;border-radius:5px;margin:0 10px 7px;padding:3px 5px;font-size:8px;overflow:hidden}.flow-card-foot{color:var(--muted);background:var(--paper);border-top:1px solid var(--border);align-items:center;gap:6px;padding:7px 10px;font-size:9px;display:flex}.flow-handle{background:var(--surface)!important;border:3px solid var(--orange)!important;width:11px!important;height:11px!important}.flow-handle:hover{transform:scale(1.25)}.entry-card{width:105px;height:40px;color:var(--accent);background:var(--surface);border:1px solid var(--accent);box-shadow:none;border-radius:20px;align-items:center;gap:8px;padding:0 12px;font-size:10px;font-weight:600;display:flex;position:relative}.entry-signal{background:var(--accent);border-radius:50%;width:7px;height:7px}.canvas-readout{color:var(--muted);border:1px solid var(--border);background:#fbfaf5f0;border-radius:7px;align-items:center;gap:8px;font-size:9px;display:flex;padding:6px 9px!important}.canvas-readout strong{color:var(--text);font:11px SFMono-Regular,Consolas,monospace}.agent-chat{flex-direction:column;gap:12px;min-height:100%;padding:14px;display:flex}.agent-context{background:var(--paper);border:1px solid var(--border);border-radius:8px;gap:10px;padding:11px;display:grid}.agent-context-heading{align-items:center;gap:8px;min-width:0;display:flex}.agent-context-heading>div{flex:1;gap:2px;min-width:0;display:grid}.agent-context-heading strong{font-size:12px}.agent-context-heading span:not(.agent-icon):not(.agent-live-mark){color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.agent-icon{width:26px;height:26px;color:var(--orange-deep);background:var(--inset);border-radius:7px;flex:none;place-items:center;display:grid}.agent-live-mark{background:var(--green);border:1px solid var(--green);border-radius:50%;flex:none;width:7px;height:7px}.agent-context-facts{flex-wrap:wrap;gap:5px;display:flex}.agent-context-facts span{color:var(--muted);background:var(--surface);border:1px solid var(--border);border-radius:5px;padding:3px 6px;font:9px SFMono-Regular,Consolas,monospace}.agent-fault-context{color:var(--red);background:var(--red-soft);border:1px solid var(--border-strong);border-radius:8px;align-items:flex-start;gap:8px;padding:10px 11px;display:flex}.agent-fault-context>svg{flex:none;margin-top:1px}.agent-fault-context strong,.agent-fault-context p{margin:0;display:block}.agent-fault-context strong{font-size:10px}.agent-fault-context p{overflow-wrap:anywhere;margin-top:3px;font:9px/1.45 SFMono-Regular,Consolas,monospace}.agent-messages{flex:1;align-content:start;gap:14px;display:grid}.agent-empty{justify-items:start;gap:5px;padding:8px 2px 4px;display:grid}.agent-empty-mark{width:28px;height:28px;color:var(--orange-deep);background:var(--inset);border-radius:7px;place-items:center;margin-bottom:2px;display:grid}.agent-empty>strong{font-size:12px}.agent-empty>p{color:var(--muted);margin:0;font-size:10px;line-height:1.5}.agent-starters{flex-wrap:wrap;gap:6px;margin-top:5px;display:flex}.agent-starters button{color:var(--orange-deep);background:var(--accent-soft);border:1px solid var(--border-strong);cursor:pointer;border-radius:6px;padding:5px 7px;font-size:9px;font-weight:600}.agent-starters button:hover{background:var(--accent-soft)}.agent-message{grid-template-columns:24px minmax(0,1fr);align-items:start;gap:8px;display:grid}.agent-message-avatar{width:24px;height:24px;color:var(--inset);background:var(--ink);border-radius:6px;place-items:center;font-size:9px;font-weight:600;display:grid}.agent-message.is-user .agent-message-avatar{color:#fff;background:var(--orange)}.agent-message-body{min-width:0}.agent-message-body>strong{font-size:10px}.agent-message-body>p{color:var(--text);white-space:pre-wrap;margin:4px 0 0;font-size:11px;line-height:1.55}.agent-message-body>small{color:var(--muted);margin-top:5px;font:8px SFMono-Regular,Consolas,monospace;display:block}.agent-actions{gap:5px;margin-top:8px;display:grid}.agent-action{color:var(--orange-deep);text-align:left;background:var(--accent-soft);border:1px solid var(--border-strong);cursor:pointer;border-radius:6px;align-items:flex-start;gap:7px;padding:8px;display:flex}.agent-action:hover{background:var(--accent-soft)}.agent-action>svg{flex:none;margin-top:1px}.agent-action>span{gap:2px;min-width:0;display:grid}.agent-action strong,.agent-action small{display:block}.agent-action strong{font-size:9px}.agent-action small{color:var(--muted);font-size:9px;line-height:1.4}.agent-composer{background:var(--white);border:1px solid var(--border-strong);border-radius:9px;flex:none}.agent-composer:focus-within{border-color:var(--orange);box-shadow:0 0 0 2px #35569e26}.agent-composer textarea{resize:vertical;width:100%;min-height:62px;max-height:140px;color:var(--text);background:0 0;border:0;outline:0;padding:10px 11px 4px;font-size:11px;line-height:1.5;display:block}.agent-composer textarea::placeholder{color:var(--muted)}.agent-composer-footer{align-items:center;gap:7px;min-height:38px;padding:3px 6px 6px 9px;display:flex}.agent-composer-footer>span{color:var(--muted);flex:1;font-size:9px}.inspector-section{gap:12px;padding:18px;display:grid}.inspector-section+.inspector-section{border-top:1px solid var(--border)}.inspector-section h3{margin:0;font-size:12px;font-weight:600}.section-title-row{justify-content:space-between;align-items:center;gap:10px;display:flex}.section-title-row>div{align-items:center;gap:7px;display:flex}.section-icon{width:26px;height:26px;color:var(--orange-deep);background:var(--inset);border-radius:6px;place-items:center;display:grid}.tag{color:var(--muted);background:var(--paper-deep);border-radius:10px;padding:3px 7px;font:9px SFMono-Regular,Consolas,monospace}.tag.is-running,.tag.is-waiting-approval{color:var(--amber);background:var(--amber-soft)}.tag.is-completed,.tag.is-published{color:#285f46;background:var(--green-soft)}.tag.is-failed,.tag.is-blocked,.tag.is-cancelled{color:var(--red);background:var(--red-soft)}.tag.is-inactive,.tag.is-draft{color:var(--muted)}.field{gap:5px;display:grid}.field>span{color:var(--muted);font-size:10px;font-weight:600}.field input,.field select,.field textarea{width:100%;min-width:0;height:34px;color:var(--text);background:var(--white);border:1px solid var(--border-strong);border-radius:7px;padding:0 9px;font-size:11px}.field textarea{resize:vertical;min-height:82px;padding:8px 9px;line-height:1.45}.field small{color:var(--muted);font-size:9px;line-height:1.5}.field input.workspace-path{font-family:SFMono-Regular,Consolas,monospace}.agent-disabled-note{color:var(--red);background:var(--red-soft);border-radius:7px;margin:0 0 8px;padding:8px 9px;font-size:10px;line-height:1.45}.field-auto-context{gap:6px}.auto-context-note{color:var(--muted);background:var(--paper-deep);border:1px solid var(--border);border-radius:7px;gap:3px;padding:10px 11px;font-size:11px;line-height:1.45;display:grid}.auto-context-note strong{color:var(--text);font-size:11px;font-weight:600}.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--orange);outline:0;box-shadow:0 0 0 2px #ce6f3221}.effects-field{gap:8px;padding-top:2px}.effects-field>span{margin-bottom:1px;display:block}.effect-warning{color:var(--amber);line-height:1.45}.file-references{border-top:1px solid var(--border);gap:8px;padding-top:4px;display:grid}.file-references.is-inactive .file-reference-list{opacity:.58}.file-reference-heading{justify-content:space-between;align-items:center;gap:8px;display:flex}.file-reference-heading>div{gap:2px;min-width:0;display:grid}.file-reference-heading strong{font-size:11px;font-weight:600}.file-reference-heading span{color:var(--muted);font-size:9px;line-height:1.4}.file-reference-trigger{flex:none;height:30px;padding:0 8px;font-size:10px}.file-reference-list{gap:3px;margin:0;padding:0;list-style:none;display:grid}.file-reference-list li{min-height:30px;color:var(--muted);border-bottom:1px solid var(--border);grid-template-columns:18px 14px minmax(0,1fr) 26px;align-items:center;gap:6px;font:9px SFMono-Regular,Consolas,monospace;display:grid}.file-reference-list li.is-missing{color:var(--amber)}.file-reference-list li>span:nth-of-type(2){text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.file-reference-order{color:var(--faint);text-align:center}.file-reference-list .icon-button{width:26px;height:26px}.file-reference-warnings{color:var(--amber);gap:3px;font-size:9px;line-height:1.45;display:grid}.file-mention-field{position:relative}.file-mention-suggestions{border:1px solid var(--border-strong);border-radius:7px;display:grid;overflow:hidden}.file-mention-suggestions button{min-width:0;color:var(--text);text-align:left;background:var(--surface);cursor:pointer;border:0;align-items:center;gap:7px;padding:7px 9px;font:9px SFMono-Regular,Consolas,monospace;display:flex}.file-mention-suggestions button+button{border-top:1px solid var(--border)}.file-mention-suggestions button:hover,.file-mention-suggestions button[aria-selected=true],.file-mention-suggestions button:focus-visible{background:var(--accent-soft)}.file-mention-suggestions span{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.checkbox-row{min-height:34px;color:var(--text);background:var(--white);border:1px solid var(--border);cursor:pointer;border-radius:7px;align-items:center;gap:9px;padding:7px 10px;font-size:11px;line-height:1.4;transition:border-color .16s,background-color .16s;display:flex}.file-picker-popover{z-index:12;background:var(--surface);width:364px;max-height:444px;box-shadow:var(--shadow-pop);border-radius:9px;grid-template-rows:auto auto minmax(120px,1fr) auto;display:grid;position:fixed;overflow:hidden}.file-picker-popover>header,.file-picker-popover>footer{align-items:center;gap:8px;padding:10px 12px;display:flex}.file-picker-popover>header{border-bottom:1px solid var(--border);justify-content:space-between}.file-picker-popover>header>div{gap:2px;display:grid}.file-picker-popover>header strong{font-size:12px}.file-picker-popover>header span,.file-picker-popover>footer>span{color:var(--muted);font-size:9px}.file-picker-search{color:var(--muted);background:var(--inset);border-radius:7px;grid-template-columns:16px minmax(0,1fr) 16px;align-items:center;gap:7px;margin:10px 12px 7px;padding:0 9px;display:grid}.file-picker-search input{min-width:0;height:34px;color:var(--text);background:0 0;border:0;outline:0;padding:0;font-size:11px}.file-picker-results{min-height:0;padding:0 7px 7px;overflow-y:auto}.file-picker-results label{cursor:pointer;border-radius:6px;grid-template-columns:16px 14px minmax(0,1fr);align-items:center;gap:7px;min-height:32px;padding:5px 7px;font:9px SFMono-Regular,Consolas,monospace;display:grid}.file-picker-results label:hover{background:var(--inset)}.file-picker-results input{width:15px;height:15px;accent-color:var(--accent)}.file-picker-results span{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.file-picker-results p{color:var(--muted);text-align:center;margin:24px 10px;font-size:10px}.file-picker-results p.is-error{color:var(--red)}.file-picker-popover>footer{border-top:1px solid var(--border)}.file-picker-popover>footer>span{flex:1;min-width:0}.file-picker-popover>footer .button{height:30px}.checkbox-row:hover{border-color:var(--border-strong);background:var(--surface)}.checkbox-row:focus-within{border-color:var(--orange);box-shadow:0 0 0 2px #ce6f3221}.field .checkbox-row input[type=checkbox]{width:16px;min-width:16px;height:16px;accent-color:var(--orange);flex:0 0 16px;margin:0;padding:0}.branch-conditions{background:var(--paper-deep);border:1px solid var(--border);border-radius:9px;gap:10px;padding:12px;display:grid}.branch-conditions-heading,.branch-condition-row{align-items:flex-start;gap:8px;display:flex}.branch-conditions-heading{justify-content:space-between;align-items:center}.branch-conditions-heading strong,.branch-conditions-heading span{display:block}.branch-conditions-heading strong{font-size:11px}.branch-conditions-heading span{color:var(--muted);margin-top:3px;font-size:9px}.branch-condition-row{border-top:1px solid var(--border);padding-top:10px}.branch-condition-index{width:24px;height:24px;color:var(--orange-deep);background:var(--orange-soft);border-radius:6px;flex:none;place-items:center;font:10px SFMono-Regular,Consolas,monospace;display:grid}.branch-condition-fields{flex:1;gap:8px;min-width:0;display:grid}.branch-condition-fields .field textarea{min-height:64px}.section-help{color:var(--muted);margin:0;font-size:10px;line-height:1.5}.property-list{border-top:1px solid var(--border)}.property-list>div{border-bottom:1px solid var(--border);justify-content:space-between;align-items:center;padding:8px 0;font-size:10px;display:flex}.property-list span{color:var(--muted)}.property-list strong{font:10px SFMono-Regular,Consolas,monospace}.compile-status{background:var(--paper);border:1px solid var(--border);border-radius:8px;align-items:flex-start;gap:9px;padding:10px;display:flex}.compile-status.ready{background:var(--green-soft);border-color:var(--green)}.compile-status.ready .status-lamp{background:var(--green)}.compile-status strong,.compile-status p{margin:0;display:block}.compile-status strong{font-size:10px}.compile-status p{color:var(--muted);margin-top:3px;font-size:9px;line-height:1.45}.activity-list{gap:2px;display:grid}.activity-list article,.activity-list-item{width:100%;color:inherit;text-align:left;border:0;border-bottom:1px solid var(--border);background:0 0;grid-template-columns:10px minmax(0,1fr);align-items:start;gap:8px;padding:9px 0;display:grid}.activity-list-item{cursor:pointer;appearance:none}.activity-list-item:hover,.activity-list-item.is-selected{background:var(--paper-deep)}.activity-list-item>div{min-width:0}.activity-list strong{font-size:10px}.activity-list p{overflow-wrap:anywhere;color:var(--muted);margin:2px 0 0;font:9px SFMono-Regular,Consolas,monospace}.activity-list small{color:var(--faint);margin-top:4px;font:8px SFMono-Regular,Consolas,monospace;display:block}.run-result{background:var(--paper);border:1px solid var(--border);border-radius:8px;align-items:flex-start;gap:8px;padding:10px 11px;display:flex}.run-result strong{font-size:11px;display:block}.run-result p{color:var(--muted);margin:2px 0 0;font-size:9px}.run-output{background:var(--paper);border:1px solid var(--border);border-radius:8px;gap:6px;padding:10px 11px;display:grid}.run-output>span{color:var(--muted);font-size:9px;font-weight:600}.run-output pre{color:var(--text);white-space:pre-wrap;word-break:break-word;margin:0;font:9px/1.5 SFMono-Regular,Consolas,monospace;overflow:auto}.empty-panel{color:var(--muted);text-align:center;background:var(--paper);border:1px solid var(--border);border-radius:8px;margin:18px;padding:20px 14px;font-size:10px;line-height:1.6}.empty-panel.compact{margin:0}.inline-alert{color:var(--red);background:var(--red-soft);border-bottom:1px solid var(--border-strong);flex:none;gap:10px;padding:11px 28px;font-size:11px;display:flex}.inline-alert strong{flex:none}.code-section{background:#101814;border:1px solid #26332b;border-radius:9px;margin-bottom:14px;overflow:hidden}.code-section>header{min-height:42px;color:var(--border);background:#1b2720;border-bottom:1px solid #344239;justify-content:space-between;align-items:center;gap:16px;padding:8px 12px;display:flex}.code-section>header>div{align-items:center;gap:7px;display:flex}.code-section h3{margin:0;font-size:11px}.code-section header code{max-width:70%;color:var(--faint);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.code-section pre{max-height:460px;color:var(--border);tab-size:2;margin:0;padding:14px;font-size:10px;line-height:1.6;overflow:auto}.settings-view{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.settings-layer{inset:var(--topbar-height) 0 0 0;z-index:8;background:var(--paper);box-shadow:var(--shadow-pop);display:flex;position:absolute}.settings-header{background:var(--surface);border-bottom:1px solid var(--border);flex:none;align-items:center;gap:12px;min-height:88px;padding:16px 24px;display:flex}.settings-header .button{margin-left:auto}.settings-emblem{width:40px;height:40px;color:var(--accent);background:var(--accent-soft);border-radius:9px;place-items:center;display:grid}.settings-header h2{margin:0;font-size:18px}.settings-header p{color:var(--muted);margin:3px 0 0;font-size:11px}.settings-scroll{flex:1;min-height:0;overflow-y:auto}.settings-section-main{width:min(820px,100% - 48px);margin:0 auto;padding:25px 0}.settings-section-main+.settings-section-main{border-top:1px solid var(--border-strong)}.settings-section-title{margin-bottom:16px}.settings-section-heading{justify-content:space-between;align-items:flex-start;gap:18px;margin-bottom:16px;display:flex}.settings-section-heading .settings-section-title{margin-bottom:0}.settings-section-heading .button{flex:none}.runtime-discovery-warning{color:var(--red);background:var(--red-soft);border:1px solid color-mix(in srgb, var(--red) 28%, var(--border));overflow-wrap:anywhere;border-radius:7px;align-items:flex-start;gap:8px;margin:0 0 12px;padding:9px 10px;font-size:10px;line-height:1.5;display:flex}.runtime-discovery-warning svg{flex:none;margin-top:1px}.settings-section-title h3{margin:0;font-size:14px}.settings-section-title p{color:var(--muted);margin:4px 0 0;font-size:10px}.settings-section-main form{gap:13px;display:grid}.settings-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;display:grid}.runtime-table{background:var(--surface);border-top:1px solid var(--border-strong)}.runtime-table article{border-bottom:1px solid var(--border);grid-template-columns:10px minmax(0,1fr) 88px 104px;align-items:start;gap:10px;padding:12px 10px;display:grid}.runtime-table article>.status-lamp,.runtime-table article>.runtime-health,.runtime-table article>.button{margin-top:4px}.runtime-info{min-width:0}.runtime-table strong{font-size:11px}.runtime-table p{color:var(--muted);margin:2px 0;font-size:10px}.runtime-table code,.runtime-table small{color:var(--faint);font-size:9px}.runtime-table .runtime-error-summary{color:var(--red);margin:7px 0 0;font-size:10px}.runtime-technical-details{color:var(--muted);margin-top:5px;font-size:9px}.runtime-technical-details summary{cursor:pointer;width:fit-content;font-weight:600}.runtime-technical-details dl{background:var(--inset);border-radius:7px;gap:5px;margin:7px 0 0;padding:8px;display:grid}.runtime-technical-details dl>div{grid-template-columns:58px minmax(0,1fr);gap:8px;display:grid}.runtime-technical-details dt{color:var(--muted);font-weight:600}.runtime-technical-details dd{min-width:0;color:var(--text);overflow-wrap:anywhere;margin:0;font-family:SFMono-Regular,Consolas,monospace}.runtime-health{color:var(--muted);font-size:10px}.status-lamp{background:var(--amber);border-radius:50%;flex:none;width:8px;height:8px;display:inline-block;box-shadow:inset 0 1px 1px #ffffffa6,0 1px 3px #1e28203d}.status-lamp.is-completed,.status-lamp.is-available{background:var(--green)}.status-lamp.is-running,.status-lamp.is-checking{background:var(--orange)}.status-lamp.is-failed,.status-lamp.is-unavailable,.status-lamp.is-cancelled{background:var(--red)}.status-lamp.is-disabled{background:var(--faint)}.spin{animation:.8s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.boot-screen{width:100%;height:100%;color:var(--muted);background:var(--paper);place-content:center;justify-items:center;gap:12px;display:grid}.boot-screen p{margin:0;font-size:11px}.boot-screen.error strong{color:var(--red)}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}.tech-disclosure{background:var(--surface);border:1px solid var(--border);border-radius:8px;margin:12px 0;padding:8px 10px 10px}.tech-disclosure>summary{cursor:pointer;color:var(--text);font-size:12px;font-weight:600}.tech-disclosure>summary+*{margin-top:10px}.inspector-callout{background:var(--paper-deep);border-radius:8px;gap:3px;margin-bottom:12px;padding:10px 11px;display:grid}.inspector-callout strong,.inspector-callout span{display:block}.inspector-callout strong{font-size:12px}.inspector-callout span{color:var(--muted);font-size:11px;line-height:1.5}.settings-form-actions{justify-content:flex-end;display:flex}.top-bar{background:var(--surface);border-bottom:1px solid var(--border-strong);align-items:center;gap:10px;min-width:0;padding:0 10px 0 12px;display:flex}.top-bar-meta{color:var(--muted);flex:none;align-items:center;gap:6px;font-size:11px;display:flex}.top-bar-dot{color:var(--faint)}.toolbar-spacer{flex:1;min-width:12px}.flow-switcher{flex:0 auto;min-width:0;position:relative}.flow-switcher-trigger{min-width:0;max-width:380px;height:34px;color:var(--text);background:var(--surface);border:1px solid var(--border-strong);cursor:pointer;border-radius:8px;align-items:center;gap:8px;padding:0 9px;font-size:13px;font-weight:600;display:flex}.flow-switcher-trigger:hover{background:var(--inset)}.flow-switcher-name{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.flow-switcher-menu{z-index:7;background:var(--surface);border:1px solid var(--border-strong);width:380px;max-height:min(60vh,440px);box-shadow:var(--shadow-pop);border-radius:9px;flex-direction:column;padding:8px;display:flex;position:absolute;top:calc(100% + 6px);left:0}.flow-switcher-list{flex:1;min-height:0;margin:8px 0 0;padding:0;list-style:none;overflow-y:auto}.flow-switcher-list .flow-list-item{grid-template-columns:minmax(0,1fr) auto 30px;align-items:center}.flow-switcher-empty{color:var(--muted);margin:14px 8px;font-size:11px}.flow-switcher-new{color:var(--accent);background:var(--surface);border:1px solid var(--border);cursor:pointer;border-radius:8px;flex:none;justify-content:center;align-items:center;gap:7px;margin-top:8px;padding:9px;font-size:12px;font-weight:600;display:flex}.flow-switcher-new:hover{background:var(--accent-soft);border-color:var(--accent)}.detail-panel,.agent-panel{background:var(--surface);flex-direction:column;min-width:0;min-height:0;display:flex;overflow:hidden}.detail-panel{border-right:1px solid var(--border)}.agent-panel{border-left:1px solid var(--border)}.center-column{background:var(--paper);flex-direction:column;min-width:0;min-height:0;display:flex;overflow:hidden}.panel-rail{width:100%;height:100%;color:var(--muted);cursor:pointer;letter-spacing:.08em;writing-mode:vertical-rl;background:0 0;border:0;justify-content:center;align-items:center;padding:15px 0;font-size:10px;font-weight:600;display:flex}.panel-rail:hover{color:var(--text);background:var(--inset)}.detail-layout{flex-direction:column;flex:1;min-height:0;display:flex}.detail-heading{border-bottom:1px solid var(--border);flex:none;padding:14px 16px 11px}.detail-heading h2{letter-spacing:-.008em;margin:0;font-size:15px;font-weight:600}.detail-heading p{color:var(--muted);margin:3px 0 0;font-size:11px}.detail-scroll{flex:1;min-height:0;overflow-y:auto}.agent-panel .agent-chat{height:100%;min-height:0;overflow:hidden}.agent-panel .agent-context,.agent-panel .agent-fault-context,.agent-panel .agent-composer{flex:none}.agent-panel .agent-messages{flex:1;min-height:0;overflow-y:auto}.agent-attachments{background:var(--inset);border:1px solid var(--border);border-radius:8px;gap:6px;padding:8px;display:grid}.agent-regenerate-note{color:var(--muted);margin:0;font-size:10px}.goal-view{flex-direction:column;flex:1;min-height:0;display:flex}.goal-scroll{flex:1;min-height:0;padding:38px max(26px,50% - 380px) 24px;overflow-y:auto}.goal-intro{text-align:center;max-width:650px;margin:6vh auto 34px}.bottom-drawer{height:var(--drawer-height);background:var(--surface);border-top:1px solid var(--border-strong);flex-direction:column;flex:none;min-height:0;display:flex}.drawer-resize-handle{cursor:ns-resize;touch-action:none;-webkit-user-select:none;user-select:none;flex:none;place-items:center;height:10px;display:grid}.drawer-resize-handle>span{background:var(--border-strong);border-radius:2px;width:34px;height:3px;transition:background .15s,width .15s}.drawer-resize-handle:hover>span,.drawer-resize-handle:focus-visible>span,.bottom-drawer.is-resizing .drawer-resize-handle>span{background:var(--accent);width:44px}.bottom-drawer.is-resizing,.bottom-drawer.is-resizing *{cursor:ns-resize!important}.drawer-tabs{border-bottom:1px solid var(--border);flex:none;align-items:center;gap:2px;height:36px;padding:0 8px 0 10px;display:flex}.drawer-tabs button[role=tab]{height:100%;color:var(--muted);cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0 11px;font-size:11px;font-weight:600;display:flex;position:relative}.drawer-tabs button[role=tab][aria-selected=true]{color:var(--text)}.drawer-tabs button[role=tab][aria-selected=true]:after{content:"";background:var(--accent);height:2px;position:absolute;bottom:-1px;left:6px;right:6px}.drawer-close{margin-left:auto}.drawer-body{flex:1;min-height:0;overflow-y:auto}.run-log{grid-template-columns:minmax(0,1fr) 232px;min-height:0;display:grid}.run-log-main{min-width:0;padding:12px 14px 18px}.run-log-runs{border-left:1px solid var(--border);min-width:0;padding:12px 14px 18px}.run-log-runs h3{color:var(--muted);letter-spacing:.08em;text-transform:uppercase;margin:0 0 8px;font-size:10px;font-weight:600}.run-log-summary{background:var(--inset);border-radius:8px;align-items:flex-start;gap:9px;margin-bottom:12px;padding:10px 11px;display:flex}.run-log-summary strong{font-size:12px;font-weight:600;display:block}.run-log-summary p{color:var(--muted);margin:2px 0 0;font-size:11px}.run-log-output{width:min(480px,55%);min-width:220px;color:var(--muted);margin:0 0 0 auto;font-size:10px}.run-log-output summary{cursor:pointer;grid-template-columns:13px minmax(0,1fr);align-items:start;gap:2px;min-width:0;list-style:none;display:grid}.run-log-output summary::-webkit-details-marker{display:none}.run-log-output summary svg{margin-top:2px;transition:transform .16s cubic-bezier(.22,1,.36,1)}.run-log-output[open] summary svg{transform:rotate(90deg)}.run-log-output-label{min-width:0}.run-log-output-label strong{color:var(--text);font-weight:600;display:block}.run-log-output-label code{min-width:0;color:var(--muted);text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.run-log-output summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}.run-log-output[open]{width:min(560px,65%)}.run-log-output pre{max-height:180px;color:var(--text);background:var(--surface);border:1px solid var(--border);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:7px;margin:8px 0 0;padding:9px 10px;font-size:10px;line-height:1.5;overflow:auto}.run-log-group+.run-log-group{margin-top:10px}.run-log-group{border:1px solid var(--border);border-radius:9px;overflow:hidden}.run-log-head{width:100%;color:inherit;text-align:left;background:var(--inset);border:0;border-bottom:1px solid var(--border);cursor:pointer;align-items:center;gap:10px;padding:9px 11px;display:flex}.run-log-head.is-static{cursor:default}.run-log-head:not(.is-static):hover{background:var(--accent-soft)}.run-log-order{color:var(--faint);font:10px SFMono-Regular,Consolas,monospace}.run-log-title{flex:1;min-width:0}.run-log-title strong{overflow-wrap:anywhere;font-size:12px;font-weight:600;line-height:1.45;display:block}.run-log-title small{color:var(--muted);margin-top:2px;font-size:10px;display:block}.run-log-state{color:var(--muted);flex:none;align-items:center;gap:5px;font-size:10px;display:flex}.run-log-time{color:var(--faint);flex:none;font-size:10px}.run-log-group .activity-list{padding:4px 6px 6px}.run-log-group .tech-disclosure{margin:0 8px 8px}.check-panel{flex-direction:column;min-height:0;display:flex}.check-bar{border-bottom:1px solid var(--border);flex:none;align-items:center;gap:9px;padding:10px 14px;display:flex}.check-runtime{color:var(--muted);align-items:center;gap:7px;font-size:11px;display:flex}.check-runtime select{min-width:160px;height:30px;color:var(--text);background:var(--surface);border:1px solid var(--border-strong);border-radius:7px;padding:0 8px}.check-counts{color:var(--muted);font-size:11px}.check-body{flex:1;min-height:0;padding:12px 14px 18px}.check-steps{gap:4px;margin:0;padding:0;list-style:none;display:grid}.check-steps li{background:var(--inset);border-radius:7px;align-items:center;gap:9px;padding:7px 10px;font-size:12px;display:flex}.check-step-kind{min-width:34px;color:var(--accent);font-size:9px;font-weight:600}.button.is-icon{width:34px;padding:0}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 80" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">CFlow</title>
|
|
3
|
+
<desc id="desc">CFlow logo: a continuous workflow path forming the letter C, paired with the CFlow wordmark.</desc>
|
|
4
|
+
<rect width="300" height="80" rx="12" fill="#171A1F"/>
|
|
5
|
+
<g transform="translate(12 8)">
|
|
6
|
+
<rect width="64" height="64" rx="14" fill="#23272E"/>
|
|
7
|
+
<g transform="rotate(-90 32 32)">
|
|
8
|
+
<path
|
|
9
|
+
d="M47 17H31C21.61 17 14 24.61 14 34s7.61 17 17 17h15"
|
|
10
|
+
fill="none"
|
|
11
|
+
stroke="#F8FAFC"
|
|
12
|
+
stroke-width="4.5"
|
|
13
|
+
stroke-linecap="round"
|
|
14
|
+
/>
|
|
15
|
+
<circle cx="47" cy="17" r="3.4" fill="#F8FAFC"/>
|
|
16
|
+
<path
|
|
17
|
+
d="m40.5 44.5 6.5 6.5-6.5 6.5"
|
|
18
|
+
fill="none"
|
|
19
|
+
stroke="#F8FAFC"
|
|
20
|
+
stroke-width="4.5"
|
|
21
|
+
stroke-linecap="round"
|
|
22
|
+
stroke-linejoin="round"
|
|
23
|
+
/>
|
|
24
|
+
</g>
|
|
25
|
+
</g>
|
|
26
|
+
<text
|
|
27
|
+
x="94"
|
|
28
|
+
y="51"
|
|
29
|
+
fill="#F8FAFC"
|
|
30
|
+
font-family="Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
|
|
31
|
+
font-size="34"
|
|
32
|
+
font-weight="600"
|
|
33
|
+
letter-spacing="0"
|
|
34
|
+
>CFlow</text>
|
|
35
|
+
</svg>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">CFlow</title>
|
|
3
|
+
<desc id="desc">A continuous white workflow path forming the letter C on a charcoal background.</desc>
|
|
4
|
+
<rect width="64" height="64" rx="14" fill="#171A1F"/>
|
|
5
|
+
<g transform="rotate(-90 32 32)">
|
|
6
|
+
<path
|
|
7
|
+
d="M47 17H31C21.61 17 14 24.61 14 34s7.61 17 17 17h15"
|
|
8
|
+
fill="none"
|
|
9
|
+
stroke="#F8FAFC"
|
|
10
|
+
stroke-width="4.5"
|
|
11
|
+
stroke-linecap="round"
|
|
12
|
+
/>
|
|
13
|
+
<circle cx="47" cy="17" r="3.4" fill="#F8FAFC"/>
|
|
14
|
+
<path
|
|
15
|
+
d="m40.5 44.5 6.5 6.5-6.5 6.5"
|
|
16
|
+
fill="none"
|
|
17
|
+
stroke="#F8FAFC"
|
|
18
|
+
stroke-width="4.5"
|
|
19
|
+
stroke-linecap="round"
|
|
20
|
+
stroke-linejoin="round"
|
|
21
|
+
/>
|
|
22
|
+
</g>
|
|
23
|
+
</svg>
|
package/dist/public/index.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="color-scheme" content="light" />
|
|
7
|
-
<link rel="icon" href="
|
|
8
|
-
<title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/cflow-mark.svg" />
|
|
8
|
+
<title>CFlow</title>
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-DzsWw3GO.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/index-oZC2r1XL.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="root"></div>
|
package/dist/src/compiler.js
CHANGED
|
@@ -4,6 +4,20 @@ function assert(condition, message) {
|
|
|
4
4
|
if (!condition)
|
|
5
5
|
throw new Error(message);
|
|
6
6
|
}
|
|
7
|
+
export function assertFileReferences(fileReferences) {
|
|
8
|
+
if (!fileReferences)
|
|
9
|
+
return;
|
|
10
|
+
assert(fileReferences.length <= 100, 'CF_FILE_REFERENCES_LIMIT');
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
for (const path of fileReferences) {
|
|
13
|
+
assert(typeof path === 'string' && path.length > 0 && path.length <= 1024, 'CF_FILE_PATH_INVALID');
|
|
14
|
+
assert(!path.startsWith('/') && !path.startsWith('\\') && !/^[A-Za-z]:/.test(path), 'CF_FILE_PATH_INVALID');
|
|
15
|
+
const parts = path.split('/');
|
|
16
|
+
assert(parts.every((part) => part.length > 0 && part !== '.' && part !== '..'), 'CF_FILE_PATH_INVALID');
|
|
17
|
+
assert(!path.includes('\\') && !seen.has(path), 'CF_FILE_PATH_INVALID');
|
|
18
|
+
seen.add(path);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
7
21
|
function checkGraph(nodes, edges, entries) {
|
|
8
22
|
const adj = new Map();
|
|
9
23
|
for (const i of nodes)
|
|
@@ -27,6 +41,7 @@ function checkGraph(nodes, edges, entries) {
|
|
|
27
41
|
assert(seen.size === nodes.length, 'UNREACHABLE_NODE: all nodes must be reachable');
|
|
28
42
|
}
|
|
29
43
|
export function compileCF(draft) {
|
|
44
|
+
assertFileReferences(draft.fileReferences);
|
|
30
45
|
if (draft.effects) {
|
|
31
46
|
const validTypes = new Set(['file-read', 'file-write', 'command']);
|
|
32
47
|
for (const effect of draft.effects) {
|
|
@@ -40,8 +55,23 @@ export function compileCF(draft) {
|
|
|
40
55
|
assertContractSchema(inputContract, 'CF_INPUT');
|
|
41
56
|
assertContractSchema(outputContract, 'CF_OUTPUT');
|
|
42
57
|
assert(draft.does.trim().length > 0, 'CF_DOES_REQUIRED');
|
|
58
|
+
const hasFileAccess = (draft.effects ?? []).some((effect) => effect.type === 'file-read' || effect.type === 'file-write');
|
|
59
|
+
const fileReferenceGuidance = hasFileAccess && draft.fileReferences?.length
|
|
60
|
+
? [
|
|
61
|
+
'Indexed workspace files (priority order):',
|
|
62
|
+
...draft.fileReferences.map((path, index) => `${index + 1}. ${path}`),
|
|
63
|
+
'',
|
|
64
|
+
'File resolution rules:',
|
|
65
|
+
'- Resolve an explicit @{relative/path} against the indexed paths first.',
|
|
66
|
+
'- Resolve a mentioned relative path, filename, or basename against the indexed paths before searching elsewhere.',
|
|
67
|
+
'- When more than one indexed file matches, use the first matching indexed path in the order above.',
|
|
68
|
+
'- If no indexed path matches, search the workspace for the mentioned file.',
|
|
69
|
+
'- Use only files required by the task. These paths are location hints; no file contents are embedded here.',
|
|
70
|
+
].join('\n')
|
|
71
|
+
: undefined;
|
|
43
72
|
const task = [
|
|
44
73
|
draft.does.trim(),
|
|
74
|
+
fileReferenceGuidance,
|
|
45
75
|
draft.input?.trim() ? `Input guidance: ${draft.input.trim()}` : undefined,
|
|
46
76
|
draft.output?.trim() ? `Output guidance: ${draft.output.trim()}` : undefined,
|
|
47
77
|
draft.process?.trim() ? `Process constraints: ${draft.process.trim()}` : undefined,
|
package/dist/src/flow-agent.js
CHANGED
|
@@ -128,13 +128,13 @@ export function flowAgentFallback(body, catalog = []) {
|
|
|
128
128
|
};
|
|
129
129
|
if (looksLikeRevision(body.message))
|
|
130
130
|
return {
|
|
131
|
-
message: `我已经加载「${draft.name}
|
|
131
|
+
message: `我已经加载「${draft.name}」当前草稿,但当前没有可用的流程助手,不能直接改图。请在设置里选一个可用 Runtime 后再说一次要改的地方。`,
|
|
132
132
|
intent: 'answer',
|
|
133
133
|
stages: [],
|
|
134
134
|
};
|
|
135
135
|
const stepCount = draft.nodes.filter((node) => node.kind === 'cf-call').length;
|
|
136
136
|
return {
|
|
137
|
-
message: `我已经加载「${draft.name}
|
|
137
|
+
message: `我已经加载「${draft.name}」当前草稿,当前有 ${stepCount} 个能力步骤。你可以问某一步在做什么,或在助手可用时直接说要怎么改。`,
|
|
138
138
|
intent: 'answer',
|
|
139
139
|
stages: [],
|
|
140
140
|
};
|
package/dist/src/server.js
CHANGED
|
@@ -7,11 +7,12 @@ import { existsSync, realpathSync } from 'node:fs';
|
|
|
7
7
|
import { cp, mkdir, rm } from 'node:fs/promises';
|
|
8
8
|
import { dirname, join, sep } from 'node:path';
|
|
9
9
|
import { Store } from './db.js';
|
|
10
|
-
import { compileCF, compileFlow } from './compiler.js';
|
|
10
|
+
import { assertFileReferences, compileCF, compileFlow } from './compiler.js';
|
|
11
11
|
import { Engine, builtins, newRunId } from './engine.js';
|
|
12
12
|
import { RuntimeManager } from './runtime.js';
|
|
13
13
|
import { sha256 } from './hash.js';
|
|
14
14
|
import { initializeWorkspace, validateWorkspaceRoot } from './workspace.js';
|
|
15
|
+
import { missingWorkspaceFiles, searchWorkspaceFiles } from './workspace-files.js';
|
|
15
16
|
import { collectGroundingFailures, groundingError, assertAttachmentGrounding, applyFlowRevision, buildProposalGraph, flowProposalOutputSchema, flowProposalPrompt, matchPublishedCapabilities, prepareSkillAttachments, } from './proposal.js';
|
|
16
17
|
import { flowAgentContext, flowAgentFallback, flowAgentOutputSchema, flowAgentPrompt, normalizeAgentResponse, } from './flow-agent.js';
|
|
17
18
|
export function createApp(store = new Store(), requestedWorkspaceRoot = process.cwd()) {
|
|
@@ -75,15 +76,18 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
75
76
|
nodes: draft.nodes.map((node) => node.kind === 'cf-call' && !node.executor ? { ...node, executor: selected } : node),
|
|
76
77
|
};
|
|
77
78
|
};
|
|
78
|
-
const saveCompilationSnapshot = (mode, flowDraft, plan, programs, runId) => {
|
|
79
|
+
const saveCompilationSnapshot = (mode, flowDraft, plan, programs, runId, warnings) => {
|
|
79
80
|
const snapshot = {
|
|
80
|
-
id:
|
|
81
|
+
id: mode === 'test' && runId
|
|
82
|
+
? `test:${runId}`
|
|
83
|
+
: `${flowDraft.flowId}@${flowDraft.revision}:${mode}`,
|
|
81
84
|
flowId: flowDraft.flowId,
|
|
82
85
|
flowRevision: flowDraft.revision,
|
|
83
86
|
mode,
|
|
84
87
|
flowDraft,
|
|
85
88
|
plan,
|
|
86
89
|
programs,
|
|
90
|
+
...(warnings?.length ? { warnings } : {}),
|
|
87
91
|
runId,
|
|
88
92
|
createdAt: new Date().toISOString(),
|
|
89
93
|
};
|
|
@@ -145,7 +149,11 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
145
149
|
await rm(attachments.root, { recursive: true, force: true });
|
|
146
150
|
}
|
|
147
151
|
}
|
|
148
|
-
store.
|
|
152
|
+
store.db.transaction(() => {
|
|
153
|
+
store.save('flow_drafts', draft.flowId, draft);
|
|
154
|
+
for (const cfDraft of proposal.cfDrafts ?? [])
|
|
155
|
+
store.save('cf_drafts', cfDraft.cfId, cfDraft);
|
|
156
|
+
})();
|
|
149
157
|
return {
|
|
150
158
|
...proposal,
|
|
151
159
|
flowDraft: draft,
|
|
@@ -157,6 +165,7 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
157
165
|
app.register(fastifyStatic, { root: runtimePublicRoot });
|
|
158
166
|
app.get('/', async (_, reply) => reply.sendFile('index.html'));
|
|
159
167
|
app.get('/api/workspace', async () => ({ root: workspaceRoot }));
|
|
168
|
+
app.post('/api/workspace/files/search', async (req) => searchWorkspaceFiles(workspaceRoot, req.body ?? {}));
|
|
160
169
|
app.get('/api/settings', async () => runtimes.settings());
|
|
161
170
|
app.put('/api/settings', async (req) => runtimes.updateSettings(req.body ?? {}));
|
|
162
171
|
const runtimeCatalog = () => Promise.all(runtimes.profiles().map(async (profile) => ({
|
|
@@ -209,13 +218,32 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
209
218
|
app.get('/api/flows', async () => store.list('flow_versions'));
|
|
210
219
|
app.get('/api/flow-drafts', async () => store.list('flow_drafts'));
|
|
211
220
|
app.put('/api/flow-drafts/:id', async (req) => {
|
|
212
|
-
|
|
221
|
+
const { flowDraft, cfDrafts } = req.body ?? {};
|
|
222
|
+
if (req.params.id !== flowDraft?.flowId)
|
|
213
223
|
throw new Error('FLOW_DRAFT_ID_MISMATCH');
|
|
214
|
-
if (!
|
|
224
|
+
if (!flowDraft.flowId?.trim() || !flowDraft.name?.trim() || !flowDraft.objective?.trim())
|
|
215
225
|
throw new Error('FLOW_DRAFT_INVALID');
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
if (!Array.isArray(cfDrafts))
|
|
227
|
+
throw new Error('CF_DRAFTS_REQUIRED');
|
|
228
|
+
const ids = new Set();
|
|
229
|
+
for (const cfDraft of cfDrafts) {
|
|
230
|
+
if (!cfDraft.cfId?.trim() || !Number.isInteger(cfDraft.revision) || cfDraft.revision < 1)
|
|
231
|
+
throw new Error('CF_DRAFT_INVALID');
|
|
232
|
+
if (ids.has(cfDraft.cfId))
|
|
233
|
+
throw new Error('CF_DRAFT_DUPLICATE');
|
|
234
|
+
ids.add(cfDraft.cfId);
|
|
235
|
+
assertFileReferences(cfDraft.fileReferences);
|
|
236
|
+
}
|
|
237
|
+
const draft = scopeFlowDraft(flowDraft);
|
|
238
|
+
const stored = store.get('flow_drafts', draft.flowId);
|
|
239
|
+
if (stored && stored.revision > draft.revision)
|
|
240
|
+
throw new Error('FLOW_DRAFT_STALE');
|
|
241
|
+
store.db.transaction(() => {
|
|
242
|
+
store.save('flow_drafts', draft.flowId, draft);
|
|
243
|
+
for (const cfDraft of cfDrafts)
|
|
244
|
+
store.save('cf_drafts', cfDraft.cfId, cfDraft);
|
|
245
|
+
})();
|
|
246
|
+
return { flowDraft: draft, cfDrafts };
|
|
219
247
|
});
|
|
220
248
|
app.delete('/api/flow-drafts/:id', async (req, reply) => {
|
|
221
249
|
const result = store.db.prepare('DELETE FROM flow_drafts WHERE id=?').run(req.params.id);
|
|
@@ -244,15 +272,47 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
244
272
|
const plan = req.body.runtimeId
|
|
245
273
|
? await pinRuntimeProfiles(compiled, [...versions(), ...candidates])
|
|
246
274
|
: compiled;
|
|
275
|
+
const warnings = [];
|
|
276
|
+
for (const node of selectedDraft.nodes) {
|
|
277
|
+
if (node.kind !== 'cf-call')
|
|
278
|
+
continue;
|
|
279
|
+
const version = catalog.get(`${node.cfRef.cfId}@${node.cfRef.version}`);
|
|
280
|
+
const hasFileAccess = (version?.draft.effects ?? []).some((effect) => effect.type === 'file-read' || effect.type === 'file-write');
|
|
281
|
+
if (!hasFileAccess || !version)
|
|
282
|
+
continue;
|
|
283
|
+
const fileReferences = version.draft.fileReferences ?? [];
|
|
284
|
+
for (const path of await missingWorkspaceFiles(workspaceRoot, fileReferences)) {
|
|
285
|
+
warnings.push({
|
|
286
|
+
code: 'INDEXED_FILE_MISSING',
|
|
287
|
+
cfId: version.cfId,
|
|
288
|
+
nodeId: node.id,
|
|
289
|
+
path,
|
|
290
|
+
message: `引用文件不存在:${path}`,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const indexed = new Set(fileReferences);
|
|
294
|
+
for (const match of version.draft.does.matchAll(/@\{([^}]+)\}/g)) {
|
|
295
|
+
const path = match[1];
|
|
296
|
+
if (!indexed.has(path))
|
|
297
|
+
warnings.push({
|
|
298
|
+
code: 'FILE_MENTION_NOT_INDEXED',
|
|
299
|
+
cfId: version.cfId,
|
|
300
|
+
nodeId: node.id,
|
|
301
|
+
path,
|
|
302
|
+
message: `任务中的文件没有加入引用列表:${path}`,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
247
306
|
saveCompilationSnapshot('preview', selectedDraft, plan, [...versions(), ...candidates].filter((version) => selectedDraft.nodes.some((node) => node.kind === 'cf-call' &&
|
|
248
307
|
node.cfRef.cfId === version.cfId &&
|
|
249
|
-
node.cfRef.version === version.version)));
|
|
308
|
+
node.cfRef.version === version.version)), undefined, warnings);
|
|
250
309
|
const referenced = new Set(selectedDraft.nodes
|
|
251
310
|
.filter((node) => node.kind === 'cf-call')
|
|
252
311
|
.map((node) => `${node.cfRef.cfId}@${node.cfRef.version}`));
|
|
253
312
|
return {
|
|
254
313
|
plan,
|
|
255
314
|
programs: [...catalog.values()].filter((version) => referenced.has(`${version.cfId}@${version.version}`)),
|
|
315
|
+
warnings,
|
|
256
316
|
};
|
|
257
317
|
});
|
|
258
318
|
app.post('/api/flow-proposals', async (req) => {
|
|
@@ -458,7 +518,11 @@ export function createApp(store = new Store(), requestedWorkspaceRoot = process.
|
|
|
458
518
|
version,
|
|
459
519
|
]));
|
|
460
520
|
const selectedDraft = applyCompileRuntime(scopedDraft, req.body.runtimeId);
|
|
461
|
-
store.
|
|
521
|
+
store.db.transaction(() => {
|
|
522
|
+
store.save('flow_drafts', scopedDraft.flowId, scopedDraft);
|
|
523
|
+
for (const cfDraft of req.body.cfDrafts ?? [])
|
|
524
|
+
store.save('cf_drafts', cfDraft.cfId, cfDraft);
|
|
525
|
+
})();
|
|
462
526
|
const compiled = compileFlow(selectedDraft, catalog);
|
|
463
527
|
const plan = await pinRuntimeProfiles(compiled, [...versions(), ...candidateVersions]);
|
|
464
528
|
const programs = [...versions(), ...candidateVersions].filter((version) => selectedDraft.nodes.some((node) => node.kind === 'cf-call' &&
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { lstat, readdir, realpath } from 'node:fs/promises';
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
const EXCLUDED_DIRECTORIES = new Set([
|
|
4
|
+
'.git',
|
|
5
|
+
'.cflow',
|
|
6
|
+
'node_modules',
|
|
7
|
+
'dist',
|
|
8
|
+
'build',
|
|
9
|
+
'coverage',
|
|
10
|
+
]);
|
|
11
|
+
const RESULT_LIMIT = 200;
|
|
12
|
+
function normalizedRelativePath(value) {
|
|
13
|
+
const path = value.trim().replaceAll('\\', '/');
|
|
14
|
+
if (!path || path.startsWith('/') || /^[A-Za-z]:/.test(path))
|
|
15
|
+
return null;
|
|
16
|
+
const parts = path.split('/');
|
|
17
|
+
if (parts.some((part) => !part || part === '.' || part === '..'))
|
|
18
|
+
return null;
|
|
19
|
+
if (parts.some((part) => EXCLUDED_DIRECTORIES.has(part)))
|
|
20
|
+
return null;
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
async function isWorkspaceFile(root, path) {
|
|
24
|
+
const normalized = normalizedRelativePath(path);
|
|
25
|
+
if (!normalized)
|
|
26
|
+
return false;
|
|
27
|
+
const target = resolve(root, ...normalized.split('/'));
|
|
28
|
+
try {
|
|
29
|
+
const [stat, resolvedTarget] = await Promise.all([lstat(target), realpath(target)]);
|
|
30
|
+
const scope = relative(root, resolvedTarget);
|
|
31
|
+
return (stat.isFile() && scope !== '..' && !scope.startsWith(`..${sep}`) && !scope.startsWith(sep));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function indexedFiles(root) {
|
|
38
|
+
const files = [];
|
|
39
|
+
const walk = async (directory, prefix) => {
|
|
40
|
+
const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
if (entry.isSymbolicLink())
|
|
43
|
+
continue;
|
|
44
|
+
const path = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
if (!EXCLUDED_DIRECTORIES.has(entry.name))
|
|
47
|
+
await walk(resolve(directory, entry.name), path);
|
|
48
|
+
}
|
|
49
|
+
else if (entry.isFile()) {
|
|
50
|
+
files.push(path);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
await walk(root, '');
|
|
55
|
+
return files.sort((left, right) => left.localeCompare(right));
|
|
56
|
+
}
|
|
57
|
+
export async function searchWorkspaceFiles(root, input) {
|
|
58
|
+
const query = String(input.query ?? '')
|
|
59
|
+
.trim()
|
|
60
|
+
.toLocaleLowerCase();
|
|
61
|
+
const safeSelected = [
|
|
62
|
+
...new Set((input.selected ?? []).map(normalizedRelativePath).filter(Boolean)),
|
|
63
|
+
];
|
|
64
|
+
const files = await indexedFiles(root);
|
|
65
|
+
const filtered = query ? files.filter((path) => path.toLocaleLowerCase().includes(query)) : files;
|
|
66
|
+
const missing = [];
|
|
67
|
+
for (const path of safeSelected)
|
|
68
|
+
if (!(await isWorkspaceFile(root, path)))
|
|
69
|
+
missing.push(path);
|
|
70
|
+
return {
|
|
71
|
+
matches: filtered.slice(0, RESULT_LIMIT),
|
|
72
|
+
missing,
|
|
73
|
+
truncated: filtered.length > RESULT_LIMIT,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export async function missingWorkspaceFiles(root, paths) {
|
|
77
|
+
const missing = [];
|
|
78
|
+
for (const path of paths)
|
|
79
|
+
if (!(await isWorkspaceFile(root, path)))
|
|
80
|
+
missing.push(path);
|
|
81
|
+
return missing;
|
|
82
|
+
}
|