@synergenius/flow-weaver-pack-weaver 0.9.134 → 0.9.136

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/bot/ai-client.d.ts +9 -0
  2. package/dist/bot/ai-client.d.ts.map +1 -1
  3. package/dist/bot/ai-client.js +59 -0
  4. package/dist/bot/ai-client.js.map +1 -1
  5. package/dist/bot/behavior-defaults.d.ts +4 -0
  6. package/dist/bot/behavior-defaults.d.ts.map +1 -1
  7. package/dist/bot/behavior-defaults.js +17 -0
  8. package/dist/bot/behavior-defaults.js.map +1 -1
  9. package/dist/bot/capability-registry.d.ts +20 -0
  10. package/dist/bot/capability-registry.d.ts.map +1 -0
  11. package/dist/bot/capability-registry.js +205 -0
  12. package/dist/bot/capability-registry.js.map +1 -0
  13. package/dist/bot/capability-types.d.ts +23 -0
  14. package/dist/bot/capability-types.d.ts.map +1 -0
  15. package/dist/bot/capability-types.js +9 -0
  16. package/dist/bot/capability-types.js.map +1 -0
  17. package/dist/bot/estimate-tokens.d.ts +12 -0
  18. package/dist/bot/estimate-tokens.d.ts.map +1 -0
  19. package/dist/bot/estimate-tokens.js +18 -0
  20. package/dist/bot/estimate-tokens.js.map +1 -0
  21. package/dist/bot/profile-types.d.ts +4 -0
  22. package/dist/bot/profile-types.d.ts.map +1 -1
  23. package/dist/bot/system-prompt.d.ts +11 -0
  24. package/dist/bot/system-prompt.d.ts.map +1 -1
  25. package/dist/bot/system-prompt.js +31 -0
  26. package/dist/bot/system-prompt.js.map +1 -1
  27. package/dist/bot/types.d.ts +1 -0
  28. package/dist/bot/types.d.ts.map +1 -1
  29. package/dist/node-types/plan-task.d.ts.map +1 -1
  30. package/dist/node-types/plan-task.js +49 -45
  31. package/dist/node-types/plan-task.js.map +1 -1
  32. package/dist/ui/capability-editor.js +657 -0
  33. package/dist/ui/profile-card.js +25 -0
  34. package/dist/ui/profile-editor.js +615 -316
  35. package/dist/ui/swarm-dashboard.js +643 -319
  36. package/flowweaver.manifest.json +1 -1
  37. package/package.json +2 -2
  38. package/src/bot/ai-client.ts +75 -0
  39. package/src/bot/behavior-defaults.ts +20 -0
  40. package/src/bot/capability-registry.ts +230 -0
  41. package/src/bot/capability-types.ts +23 -0
  42. package/src/bot/estimate-tokens.ts +16 -0
  43. package/src/bot/profile-types.ts +4 -0
  44. package/src/bot/system-prompt.ts +33 -0
  45. package/src/bot/types.ts +1 -0
  46. package/src/node-types/plan-task.ts +51 -44
  47. package/src/ui/capability-editor.tsx +420 -0
  48. package/src/ui/profile-card.tsx +20 -0
  49. package/src/ui/profile-editor.tsx +100 -6
@@ -0,0 +1,657 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/ui/capability-editor.tsx
21
+ var capability_editor_exports = {};
22
+ __export(capability_editor_exports, {
23
+ CapabilityEditor: () => CapabilityEditor,
24
+ default: () => capability_editor_default
25
+ });
26
+ module.exports = __toCommonJS(capability_editor_exports);
27
+
28
+ // src/bot/operations.ts
29
+ var OP_WRITE_FILE = "write_file";
30
+ var OP_READ_FILE = "read_file";
31
+ var OP_PATCH_FILE = "patch_file";
32
+ var OP_LIST_FILES = "list_files";
33
+ var OP_RUN_SHELL = "run_shell";
34
+ var OP_VALIDATE = "validate";
35
+ var OP_TSC_CHECK = "tsc_check";
36
+ var OP_RUN_TESTS = "run_tests";
37
+ var OP_TASK_CREATE = "task_create";
38
+ var OP_RESPOND = "respond";
39
+ var PLAN_OPERATIONS = [
40
+ OP_WRITE_FILE,
41
+ OP_READ_FILE,
42
+ OP_PATCH_FILE,
43
+ OP_LIST_FILES,
44
+ OP_RUN_SHELL,
45
+ OP_VALIDATE,
46
+ OP_TASK_CREATE,
47
+ OP_RESPOND
48
+ ];
49
+
50
+ // src/bot/capability-registry.ts
51
+ var CAP_CORE = {
52
+ name: "core",
53
+ description: "Bot identity, structured plan output format, and safety rules. Always loaded.",
54
+ prompt: `You are Weaver, an expert AI companion for Flow Weaver workflows.
55
+
56
+ ## Plan Format
57
+ Your plans MUST be structured JSON with concrete steps.
58
+ Each step has: operation (tool name), description (what it does), args (complete arguments).
59
+ Do NOT describe what you would do \u2014 actually do it by calling tools.
60
+
61
+ ## Safety Rules
62
+ - Writes that shrink a file by >50% or write empty content are automatically BLOCKED.
63
+ - Blocked shell commands: rm -rf, git push, npm publish, sudo, curl|sh.
64
+ - Always validate BEFORE and AFTER patching.
65
+ - Always read a file before patching it (you need exact strings for find/replace).
66
+ - Use patch_file for modifications, write_file only for new files.
67
+ - Be concise \u2014 let tool results speak.`
68
+ };
69
+ var CAP_FILE_OPS = {
70
+ name: "file-ops",
71
+ description: "File read/write/patch operations and best practices for file manipulation.",
72
+ tools: [OP_READ_FILE, OP_WRITE_FILE, OP_PATCH_FILE, OP_LIST_FILES],
73
+ prompt: `## File Operations
74
+ - read_file: Read a file and return its content. args: { file }
75
+ - write_file: Write a file. args: { file, content }. Content must be the COMPLETE file.
76
+ - patch_file: Surgical find-and-replace edits. args: { file, patches: [{ find: "old text", replace: "new text" }] }. PREFERRED for modifying existing files.
77
+ - list_files: List files in a directory. args: { directory, pattern? } (pattern is regex)
78
+
79
+ ## Best Practices
80
+ PREFER patch_file over write_file for modifying existing files (surgical edits, no truncation risk).
81
+ Use read_file to understand a file before modifying it.
82
+ Use list_files to discover project structure.
83
+ Writes that shrink a file by >50% or write empty content are automatically BLOCKED.`
84
+ };
85
+ var CAP_SHELL = {
86
+ name: "shell",
87
+ description: "Shell command execution for running tests, builds, and inspecting output.",
88
+ tools: [OP_RUN_SHELL, OP_VALIDATE, OP_TSC_CHECK, OP_RUN_TESTS],
89
+ prompt: `## Shell Commands
90
+ - run_shell: Execute a shell command and return output. args: { command }
91
+ Use for: npx vitest, git status, grep, find, etc.
92
+ Examples: { "command": "npx vitest run --reporter verbose" }, { "command": "npx flow-weaver validate src/workflow.ts --json" }
93
+ Blocked: rm -rf, git push, npm publish, sudo, curl|sh (safety policy).
94
+ Use run_shell for running tests (npx vitest), validation (flow-weaver validate), and inspecting output.`
95
+ };
96
+ var CAP_TASK_MGMT = {
97
+ name: "task-mgmt",
98
+ description: "Create and manage swarm subtasks for parallel execution.",
99
+ tools: [OP_TASK_CREATE],
100
+ prompt: `## Task Management
101
+ - task_create: Create swarm subtasks for parallel execution. args: { title, description, complexity, subtasks[] }
102
+ - task_list, task_get, task_update: Query and update existing tasks
103
+
104
+ Use task_create to decompose complex work into smaller, independent subtasks that other bots can execute in parallel.`
105
+ };
106
+ var CAP_FW_GRAMMAR = {
107
+ name: "fw-grammar",
108
+ description: "Flow Weaver annotation syntax, node types, workflows, patterns, and data flow.",
109
+ prompt: `## Core Mental Model
110
+
111
+ The code IS the workflow. Flow Weaver workflows are plain TypeScript files with JSDoc annotations above functions. The compiler reads annotations and generates deterministic execution code between @flow-weaver-body-start/end markers. Compiled code is standalone with no runtime dependency on flow-weaver.
112
+
113
+ Three block types:
114
+ - @flowWeaver nodeType: A reusable function (node) with typed inputs/outputs
115
+ - @flowWeaver workflow: A DAG orchestration that wires node instances together
116
+ - @flowWeaver pattern: A reusable fragment with boundary ports (IN/OUT instead of Start/Exit)
117
+
118
+ ## Node Execution Model
119
+
120
+ Expression nodes (@expression):
121
+ - No execute/onSuccess/onFailure params. Just inputs and return value.
122
+ - throw = failure path, return = success path
123
+ - Synchronous. Use execSync for shell commands.
124
+ - Preferred for deterministic operations.
125
+
126
+ Standard nodes:
127
+ - execute: boolean param gates execution
128
+ - Return { onSuccess: boolean, onFailure: boolean, ...outputs }
129
+ - Can be async for I/O operations
130
+
131
+ Async agent nodes:
132
+ - Use (globalThis as any).__fw_agent_channel__ to pause workflow
133
+ - Call channel.request({ agentId, context, prompt }) which returns a Promise
134
+ - Workflow suspends until agent responds
135
+ - NOT @expression (must be async)
136
+
137
+ Pass-through pattern:
138
+ - FW auto-connects ports by matching names on adjacent nodes
139
+ - To forward data through intermediate nodes, declare it as both @input and @output with the same name
140
+ - For non-adjacent wiring, use @connect sourceNode.port -> targetNode.port
141
+
142
+ Data flow:
143
+ - @path A -> B -> C: Linear execution path (sugar for multiple @connect)
144
+ - @autoConnect: Auto-wire all nodes in declaration order
145
+ - @connect: Explicit port-to-port wiring
146
+ - Merge strategies for fan-in: FIRST, LAST, COLLECT, MERGE, CONCAT`
147
+ };
148
+ var CAP_FW_VALIDATE = {
149
+ name: "fw-validate",
150
+ description: "Flow Weaver validation error codes and common fix patterns.",
151
+ prompt: `## Validation Errors
152
+
153
+ When you encounter validation errors, suggest the specific fix. Common resolutions:
154
+ - UNKNOWN_NODE_TYPE: Ensure the referenced function has @flowWeaver nodeType annotation
155
+ - MISSING_REQUIRED_INPUT: Add a @connect from a source port or make the input optional with [brackets]
156
+ - UNKNOWN_SOURCE_PORT / UNKNOWN_TARGET_PORT: Check port name spelling in @connect
157
+ - CYCLE_DETECTED: Break the cycle; use scoped iteration (@scope, @map) instead of circular dependencies`
158
+ };
159
+ var CAP_FW_GENESIS = {
160
+ name: "fw-genesis",
161
+ description: "Flow Weaver genesis protocol for self-evolving workflows.",
162
+ prompt: `## Genesis Protocol
163
+
164
+ Genesis is a 17-step self-evolving workflow engine:
165
+ 1. Load config 2. Observe project 3. Load task workflow 4. Diff fingerprint
166
+ 5. Check stabilize mode 6. Wait for agent 7. Propose evolution 8. Validate proposal
167
+ 9. Snapshot for rollback 10. Apply changes 11. Compile and validate
168
+ 12. Diff workflow 13. Check approval threshold 14. Wait for approval
169
+ 15. Commit or rollback 16. Update history 17. Report summary
170
+
171
+ When stabilize mode is active, only fix-up operations are allowed.`
172
+ };
173
+ var CAP_FW_CLI = {
174
+ name: "fw-cli",
175
+ description: "Flow Weaver CLI command reference for compile, validate, diagram, and other operations.",
176
+ prompt: `## CLI Commands
177
+
178
+ Note: compile, validate, modify, diff, diagram, and describe operations are available as direct plan steps (no CLI needed).`
179
+ };
180
+ var CAP_CODE_REVIEW = {
181
+ name: "code-review",
182
+ description: "Code review guidelines, quality checklist, and security review patterns.",
183
+ prompt: `## Code Review
184
+
185
+ When reviewing code, check for:
186
+ 1. Correctness: Does the code do what the task asked?
187
+ 2. Security: No hardcoded secrets, no injection vulnerabilities, no exposed APIs
188
+ 3. Style: Consistent with project conventions, proper naming, no dead code
189
+ 4. Testing: Are there tests? Do they cover edge cases?
190
+ 5. Performance: No unnecessary loops, no blocking calls in async code
191
+
192
+ Report concerns with specific file:line references and suggested fixes.`
193
+ };
194
+ var CAP_WEB = {
195
+ name: "web",
196
+ description: "Web fetch capability for fetching URLs and external resources.",
197
+ tools: ["web_fetch"],
198
+ prompt: `## Web
199
+ - web_fetch(url): Fetch a URL and return its content. Use for API docs, examples, etc.`
200
+ };
201
+ var CAP_CONTEXT = {
202
+ name: "context",
203
+ description: "Project file listings, directory structure, and workspace context.",
204
+ prompt: `## Project Context
205
+
206
+ Use list_files to understand the project structure before making changes.
207
+ The context bundle (when available) provides a snapshot of the workspace.`
208
+ };
209
+ var BUILT_IN_CAPABILITIES = [
210
+ CAP_CORE,
211
+ CAP_FILE_OPS,
212
+ CAP_SHELL,
213
+ CAP_TASK_MGMT,
214
+ CAP_FW_GRAMMAR,
215
+ CAP_FW_VALIDATE,
216
+ CAP_FW_GENESIS,
217
+ CAP_FW_CLI,
218
+ CAP_CODE_REVIEW,
219
+ CAP_WEB,
220
+ CAP_CONTEXT
221
+ ];
222
+ var capabilityMap = new Map(
223
+ BUILT_IN_CAPABILITIES.map((c) => [c.name, c])
224
+ );
225
+
226
+ // src/bot/estimate-tokens.ts
227
+ function estimateTokens(text) {
228
+ if (!text) return 0;
229
+ const byChars = text.length / 3.5;
230
+ const byWords = text.split(/\s+/).filter(Boolean).length * 1.33;
231
+ return Math.ceil((byChars + byWords) / 2);
232
+ }
233
+
234
+ // src/ui/capability-editor.tsx
235
+ var React = require("react");
236
+ var { useState, useCallback } = React;
237
+ var {
238
+ Flex,
239
+ Typography,
240
+ Input,
241
+ Button,
242
+ IconButton,
243
+ Icon,
244
+ Field,
245
+ Chip,
246
+ Checkbox,
247
+ Table,
248
+ CodeBlock,
249
+ ScrollArea,
250
+ toast,
251
+ usePackWorkspace
252
+ } = require("@fw/plugin-ui-kit");
253
+ var AVAILABLE_TOOLS = [...PLAN_OPERATIONS];
254
+ function CapabilityDetail({
255
+ cap,
256
+ mode,
257
+ allNames,
258
+ onBack,
259
+ onSubmit
260
+ }) {
261
+ const [name, setName] = useState(cap?.name ?? "");
262
+ const [description, setDescription] = useState(cap?.description ?? "");
263
+ const [prompt, setPrompt] = useState(cap?.prompt ?? "");
264
+ const [tools, setTools] = useState(cap?.tools ?? []);
265
+ const readOnly = mode === "view";
266
+ const isCreate = mode === "create";
267
+ const handleToggleTool = useCallback((tool) => {
268
+ setTools(
269
+ (prev) => prev.includes(tool) ? prev.filter((t) => t !== tool) : [...prev, tool]
270
+ );
271
+ }, []);
272
+ const handleSubmit = useCallback(() => {
273
+ const trimName = name.trim().toLowerCase().replace(/\s+/g, "-");
274
+ if (!trimName || !description.trim()) {
275
+ toast("Name and description are required", { type: "error" });
276
+ return;
277
+ }
278
+ if (isCreate && allNames.includes(trimName)) {
279
+ toast(`Capability "${trimName}" already exists`, { type: "error" });
280
+ return;
281
+ }
282
+ onSubmit({
283
+ name: isCreate ? trimName : cap?.name ?? trimName,
284
+ description: description.trim(),
285
+ prompt: prompt.trim() || `## ${description.trim()}`,
286
+ tools: tools.length > 0 ? tools : void 0
287
+ });
288
+ }, [name, description, prompt, tools, isCreate, allNames, cap, onSubmit]);
289
+ const title = isCreate ? "New Capability" : readOnly ? cap?.name ?? "" : `Edit: ${cap?.name ?? ""}`;
290
+ return React.createElement(
291
+ Flex,
292
+ {
293
+ variant: "column-stretch-start-nowrap-0",
294
+ style: { width: "100%", height: "100%", overflow: "hidden" }
295
+ },
296
+ // Header
297
+ React.createElement(
298
+ Flex,
299
+ {
300
+ variant: "row-center-space-between-nowrap-8",
301
+ style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" }
302
+ },
303
+ React.createElement(
304
+ Flex,
305
+ { variant: "row-center-start-nowrap-8" },
306
+ React.createElement(IconButton, {
307
+ icon: "back",
308
+ size: "xs",
309
+ variant: "clear",
310
+ onClick: onBack,
311
+ title: "Back to list"
312
+ }),
313
+ React.createElement(Typography, { variant: "caption-thick", color: "color-text-high" }, title),
314
+ readOnly && React.createElement(Chip, {
315
+ label: "built-in",
316
+ size: "small",
317
+ color: "color-status-info"
318
+ })
319
+ )
320
+ ),
321
+ // Scrollable form
322
+ React.createElement(
323
+ ScrollArea,
324
+ { style: { flex: 1, minHeight: 0 } },
325
+ React.createElement(
326
+ Flex,
327
+ {
328
+ variant: "column-stretch-start-nowrap-10",
329
+ style: { padding: "12px 16px" }
330
+ },
331
+ // Name
332
+ React.createElement(
333
+ Field,
334
+ { label: "Name" },
335
+ readOnly ? React.createElement(Typography, {
336
+ variant: "smallCaption-thick",
337
+ color: "color-text-high",
338
+ style: { padding: "4px 0" }
339
+ }, cap?.name) : React.createElement(Input, {
340
+ type: "text",
341
+ size: "small",
342
+ placeholder: "e.g. api-design",
343
+ value: name,
344
+ onChange: (v) => setName(v),
345
+ disabled: !isCreate,
346
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
347
+ inputBoxStyle: { maxWidth: "none" }
348
+ })
349
+ ),
350
+ // Description
351
+ React.createElement(
352
+ Field,
353
+ { label: "Description" },
354
+ readOnly ? React.createElement(Typography, {
355
+ variant: "smallCaption-regular",
356
+ color: "color-text-medium",
357
+ style: { padding: "4px 0" }
358
+ }, cap?.description) : React.createElement(Input, {
359
+ type: "text",
360
+ size: "small",
361
+ placeholder: "What this capability provides",
362
+ value: description,
363
+ onChange: (v) => setDescription(v),
364
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
365
+ inputBoxStyle: { maxWidth: "none" }
366
+ })
367
+ ),
368
+ // Prompt
369
+ React.createElement(
370
+ Field,
371
+ { label: "Prompt", align: "start" },
372
+ readOnly ? React.createElement(Typography, {
373
+ variant: "smallCaption-regular",
374
+ color: "color-text-medium",
375
+ style: { whiteSpace: "pre-wrap", lineHeight: 1.5 }
376
+ }, cap?.prompt) : React.createElement(Input, {
377
+ type: "text",
378
+ size: "small",
379
+ multiline: true,
380
+ placeholder: "Knowledge content (markdown) injected into the system prompt",
381
+ value: prompt,
382
+ onChange: (v) => setPrompt(v),
383
+ defaultBoxStyle: { flex: 1, minWidth: 0 },
384
+ inputBoxStyle: { maxWidth: "none", minHeight: 160 }
385
+ })
386
+ ),
387
+ // Tools
388
+ React.createElement(
389
+ Field,
390
+ { label: "Tools", align: "start" },
391
+ React.createElement(Table, {
392
+ size: "compact",
393
+ showHeader: false,
394
+ data: AVAILABLE_TOOLS.map((t) => ({
395
+ tool: t,
396
+ active: (readOnly ? cap?.tools ?? [] : tools).includes(t)
397
+ })),
398
+ getRowKey: (row) => row.tool,
399
+ columns: [
400
+ {
401
+ key: "check",
402
+ header: "",
403
+ width: "28px",
404
+ render: (_v, row) => React.createElement(
405
+ "div",
406
+ { style: { height: 20, display: "flex", alignItems: "center" } },
407
+ React.createElement(Checkbox, {
408
+ checked: row.active,
409
+ disabled: readOnly,
410
+ onChange: readOnly ? void 0 : () => handleToggleTool(row.tool),
411
+ size: "sm"
412
+ })
413
+ )
414
+ },
415
+ {
416
+ key: "tool",
417
+ header: "Tool",
418
+ render: (_v, row) => React.createElement(
419
+ "div",
420
+ { style: { height: 20, display: "flex", alignItems: "center" } },
421
+ React.createElement(Typography, {
422
+ variant: "smallCaption-regular",
423
+ color: row.active ? "color-text-high" : "color-text-subtle"
424
+ }, row.tool)
425
+ )
426
+ }
427
+ ]
428
+ })
429
+ ),
430
+ // Token estimate
431
+ React.createElement(
432
+ Field,
433
+ { label: "Est. tokens" },
434
+ React.createElement(Typography, {
435
+ variant: "smallCaption-regular",
436
+ color: "color-text-subtle"
437
+ }, `~${estimateTokens(readOnly ? cap?.prompt ?? "" : prompt)} tokens (approx.)`)
438
+ ),
439
+ // Submit button (not for view mode)
440
+ !readOnly && React.createElement(
441
+ Flex,
442
+ {
443
+ variant: "row-center-end-nowrap-8",
444
+ style: { paddingTop: 4 }
445
+ },
446
+ React.createElement(Button, {
447
+ size: "xs",
448
+ variant: "clear",
449
+ color: "secondary",
450
+ onClick: onBack
451
+ }, "Cancel"),
452
+ React.createElement(Button, {
453
+ size: "xs",
454
+ variant: "fill",
455
+ color: "primary",
456
+ onClick: handleSubmit,
457
+ disabled: readOnly || !isCreate && !description.trim() || isCreate && (!name.trim() || !description.trim())
458
+ }, isCreate ? "Create" : "Save")
459
+ )
460
+ )
461
+ )
462
+ );
463
+ }
464
+ function CapabilityList({
465
+ allCaps,
466
+ onOpen,
467
+ onDelete,
468
+ onCreate,
469
+ onSaveAll,
470
+ onClose,
471
+ hasCustom
472
+ }) {
473
+ return React.createElement(
474
+ Flex,
475
+ {
476
+ variant: "column-stretch-start-nowrap-0",
477
+ style: { width: "100%", height: "100%", overflow: "hidden" }
478
+ },
479
+ // Header
480
+ React.createElement(
481
+ Flex,
482
+ {
483
+ variant: "row-center-space-between-nowrap-8",
484
+ style: { padding: "8px 16px", flexShrink: 0, borderBottom: "1px solid var(--color-border-default)" }
485
+ },
486
+ React.createElement(
487
+ Flex,
488
+ { variant: "row-center-start-nowrap-8" },
489
+ onClose && React.createElement(IconButton, {
490
+ icon: "back",
491
+ size: "xs",
492
+ variant: "clear",
493
+ onClick: onClose,
494
+ title: "Back"
495
+ }),
496
+ React.createElement(Typography, { variant: "caption-thick", color: "color-text-high" }, "Capabilities"),
497
+ React.createElement(Chip, {
498
+ label: `${allCaps.length}`,
499
+ size: "small",
500
+ color: "color-brand-main"
501
+ })
502
+ ),
503
+ React.createElement(
504
+ Flex,
505
+ { variant: "row-center-end-nowrap-6" },
506
+ onSaveAll && hasCustom && React.createElement(Button, {
507
+ size: "xs",
508
+ variant: "outlined",
509
+ color: "primary",
510
+ onClick: onSaveAll
511
+ }, "Save"),
512
+ React.createElement(Button, {
513
+ size: "xs",
514
+ variant: "fill",
515
+ color: "primary",
516
+ onClick: onCreate
517
+ }, "New")
518
+ )
519
+ ),
520
+ // Scrollable list
521
+ React.createElement(
522
+ ScrollArea,
523
+ { style: { flex: 1, minHeight: 0 } },
524
+ React.createElement(
525
+ Flex,
526
+ {
527
+ variant: "column-stretch-start-nowrap-2",
528
+ style: { padding: "8px 16px" }
529
+ },
530
+ ...allCaps.map(
531
+ (cap) => React.createElement(
532
+ Flex,
533
+ {
534
+ key: cap.name,
535
+ variant: "row-center-space-between-nowrap-8",
536
+ style: {
537
+ padding: "7px 10px",
538
+ borderRadius: 6,
539
+ cursor: "pointer",
540
+ border: "1px solid var(--color-border-default)",
541
+ transition: "background-color 0.1s"
542
+ },
543
+ onClick: () => onOpen(cap.name),
544
+ onMouseEnter: (e) => {
545
+ e.currentTarget.style.backgroundColor = "var(--color-surface-hover)";
546
+ },
547
+ onMouseLeave: (e) => {
548
+ e.currentTarget.style.backgroundColor = "transparent";
549
+ }
550
+ },
551
+ // Left: icon + name + description
552
+ React.createElement(
553
+ Flex,
554
+ { variant: "row-center-start-nowrap-8", style: { flex: 1, minWidth: 0 } },
555
+ React.createElement(Icon, {
556
+ name: cap.builtIn ? "lock" : "edit",
557
+ size: 13,
558
+ color: cap.builtIn ? "color-text-subtle" : "color-brand-main"
559
+ }),
560
+ React.createElement(Typography, {
561
+ variant: "smallCaption-thick",
562
+ color: "color-text-high",
563
+ style: { minWidth: 80, flexShrink: 0 }
564
+ }, cap.name),
565
+ React.createElement(Typography, {
566
+ variant: "smallCaption-regular",
567
+ color: "color-text-subtle",
568
+ style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }
569
+ }, cap.description)
570
+ ),
571
+ // Right: chips + actions
572
+ React.createElement(
573
+ Flex,
574
+ { variant: "row-center-end-nowrap-4", style: { flexShrink: 0 } },
575
+ cap.tools && cap.tools.length > 0 && React.createElement(Chip, {
576
+ label: `${cap.tools.length} tools`,
577
+ size: "small",
578
+ color: "color-status-positive"
579
+ }),
580
+ !cap.builtIn && React.createElement(IconButton, {
581
+ icon: "outlinedDelete",
582
+ size: "xs",
583
+ variant: "clear",
584
+ color: "danger",
585
+ onClick: (e) => {
586
+ e.stopPropagation();
587
+ onDelete(cap.name);
588
+ },
589
+ title: "Delete capability"
590
+ }),
591
+ React.createElement(Icon, {
592
+ name: "chevronRight",
593
+ size: 12,
594
+ color: "color-text-subtle"
595
+ })
596
+ )
597
+ )
598
+ )
599
+ )
600
+ )
601
+ );
602
+ }
603
+ function CapabilityEditor({ customCapabilities = [], onSave, onClose }) {
604
+ const [customs, setCustoms] = useState(customCapabilities);
605
+ const [screen, setScreen] = useState("list");
606
+ const allCaps = [
607
+ ...BUILT_IN_CAPABILITIES.map((c) => ({ ...c, builtIn: true })),
608
+ ...customs.map((c) => ({ ...c, builtIn: false }))
609
+ ];
610
+ const allNames = allCaps.map((c) => c.name);
611
+ const handleOpen = useCallback((name) => {
612
+ const cap = allCaps.find((c) => c.name === name);
613
+ if (!cap) return;
614
+ setScreen({ mode: cap.builtIn ? "view" : "edit", name });
615
+ }, [allCaps]);
616
+ const handleDelete = useCallback((name) => {
617
+ setCustoms((prev) => prev.filter((c) => c.name !== name));
618
+ toast(`Capability "${name}" deleted`, { type: "success" });
619
+ }, []);
620
+ const handleSubmit = useCallback((cap) => {
621
+ if (typeof screen === "object" && screen.mode === "edit") {
622
+ setCustoms(
623
+ (prev) => prev.map((c) => c.name === cap.name ? cap : c)
624
+ );
625
+ toast(`Capability "${cap.name}" updated`, { type: "success" });
626
+ } else {
627
+ setCustoms((prev) => [...prev, cap]);
628
+ toast(`Capability "${cap.name}" created`, { type: "success" });
629
+ }
630
+ setScreen("list");
631
+ }, [screen]);
632
+ const handleSaveAll = useCallback(() => {
633
+ onSave?.(customs);
634
+ toast("Capabilities saved", { type: "success" });
635
+ }, [customs, onSave]);
636
+ if (typeof screen === "object") {
637
+ const cap = screen.name ? allCaps.find((c) => c.name === screen.name) : void 0;
638
+ return React.createElement(CapabilityDetail, {
639
+ cap,
640
+ mode: screen.mode,
641
+ allNames,
642
+ onBack: () => setScreen("list"),
643
+ onSubmit: handleSubmit
644
+ });
645
+ }
646
+ return React.createElement(CapabilityList, {
647
+ allCaps,
648
+ onOpen: handleOpen,
649
+ onDelete: handleDelete,
650
+ onCreate: () => setScreen({ mode: "create" }),
651
+ onSaveAll: onSave ? handleSaveAll : void 0,
652
+ onClose,
653
+ hasCustom: customs.length > 0
654
+ });
655
+ }
656
+ var capability_editor_default = CapabilityEditor;
657
+ module.exports = CapabilityEditor;
@@ -138,6 +138,31 @@ function ProfileCard({ profile, activeInstances, onEdit, onDelete }) {
138
138
  )
139
139
  )
140
140
  ),
141
+ // Knowledge capabilities (from behavior)
142
+ behavior?.capabilities && behavior.capabilities.length > 0 && React.createElement(
143
+ Field,
144
+ { label: "Knowledge", labelWidth: 90, align: "start" },
145
+ React.createElement(
146
+ Flex,
147
+ { variant: "row-center-start-wrap-4" },
148
+ ...behavior.capabilities.map(
149
+ (capName) => React.createElement(
150
+ "span",
151
+ { key: capName },
152
+ React.createElement(Chip, { label: capName, size: "small", color: "color-status-info" })
153
+ )
154
+ )
155
+ )
156
+ ),
157
+ // Budget (from behavior)
158
+ behavior?.budget && React.createElement(
159
+ Field,
160
+ { label: "Budget", labelWidth: 90, align: "center" },
161
+ React.createElement(Typography, {
162
+ variant: "smallCaption-regular",
163
+ color: "color-text-high"
164
+ }, `$${behavior.budget.toFixed(2)}/task`)
165
+ ),
141
166
  // Strategy
142
167
  React.createElement(
143
168
  Field,