@frumu/tandem-panel 0.5.3 → 0.5.5

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 (58) hide show
  1. package/bin/setup.js +21 -4
  2. package/dist/assets/AutomationsPage-6mRHsh9V.js +946 -0
  3. package/dist/assets/BugMonitorPage-B9mcxV8k.js +4 -0
  4. package/dist/assets/ChannelsPage-oJ5a717t.js +1 -0
  5. package/dist/assets/ChatInterfacePanel-3nvwn0cJ.js +1 -0
  6. package/dist/assets/ChatPage-CGKFC9ev.js +1 -0
  7. package/dist/assets/CodingWorkflowsPage-DosUtoeO.js +8 -0
  8. package/dist/assets/ControlPanelDialogs-BBIPHXnw.js +1 -0
  9. package/dist/assets/DashboardPage-Cv9_TUZQ.js +1 -0
  10. package/dist/assets/ExperimentsPage-DuYHzo7d.js +84 -0
  11. package/dist/assets/FilesPage-NAInb3WU.js +1 -0
  12. package/dist/assets/IntentPlannerPage-BwlF9wfW.js +5 -0
  13. package/dist/assets/LazyJson-DYncL_RR.js +1 -0
  14. package/dist/assets/MarketplacePage-Wo7biaBa.js +1 -0
  15. package/dist/assets/McpToolAllowlistEditor-B3qCkiFT.js +1 -0
  16. package/dist/assets/MemoryImportDialog-BWT93PW1.js +1 -0
  17. package/dist/assets/MemoryPage-gSBH1OKG.js +1 -0
  18. package/dist/assets/OrchestratorPage-HDyjjwF-.js +3 -0
  19. package/dist/assets/PacksPage-BWnL4dRB.js +3 -0
  20. package/dist/assets/PlannerDiagnosticsPanel-VyacxaCM.js +1 -0
  21. package/dist/assets/ProviderModelSelector-B_IE0-e7.js +1 -0
  22. package/dist/assets/RunsPage-B6ttNeUJ.js +1 -0
  23. package/dist/assets/SettingsPage-DhAKDQHw.js +5 -0
  24. package/dist/assets/TaskBoard-DSRrmiyQ.js +1 -0
  25. package/dist/assets/TeamsPage-CwMnVES9.js +4472 -0
  26. package/dist/assets/TimezoneField-DKINpKxU.js +1 -0
  27. package/dist/assets/WorkflowStudioPage-CyWDhEEE.js +1854 -0
  28. package/dist/assets/WorkflowsPage-BWGWH8uD.js +2 -0
  29. package/dist/assets/api-CpR5ozpc.js +1 -0
  30. package/dist/assets/chatPageHelpers-D-NhHk4M.js +1 -0
  31. package/dist/assets/explorerHandoff-KpFRPNQc.js +1 -0
  32. package/dist/assets/format-CimuGHiH.js +1 -0
  33. package/dist/assets/fullcalendar-Bn75j0xM.js +1 -0
  34. package/dist/assets/index-DAWzCKcg.css +1 -0
  35. package/dist/assets/index-picB46b5.js +3 -0
  36. package/dist/assets/messages-AWZpX-Rw.js +3 -0
  37. package/dist/assets/motion-B3ZE8SGR.js +9 -0
  38. package/dist/assets/plannerShared-1kHFyAp-.js +1 -0
  39. package/dist/assets/preact-vendor-DaCG_P2o.js +1 -0
  40. package/dist/assets/react-query-BIbNygEJ.js +1 -0
  41. package/dist/assets/sse-B1wvyjPI.js +2 -0
  42. package/dist/assets/ui-CV-Z6sqF.js +1 -0
  43. package/dist/assets/useEngineStream-ChEkuUVV.js +1 -0
  44. package/dist/assets/vendor-DSaYtO9f.js +156 -0
  45. package/dist/assets/workflowStability-Dsk2DR6F.js +2 -0
  46. package/dist/index.html +10 -7
  47. package/lib/automations/workflow-list.js +147 -0
  48. package/lib/setup/control-panel-preferences.js +4 -0
  49. package/package.json +3 -3
  50. package/server/routes/capabilities.js +1 -0
  51. package/server/routes/knowledgebase.js +7 -1
  52. package/dist/assets/index-D6sUkBw6.css +0 -1
  53. package/dist/assets/index-gUgdIB3_.js +0 -7379
  54. package/dist/assets/motion-CBnf8hfk.js +0 -9
  55. package/dist/assets/preact-vendor-B239Onrg.js +0 -1
  56. package/dist/assets/react-query-_hsOQSt5.js +0 -1
  57. package/dist/assets/vendor-DeUDWccs.js +0 -156
  58. /package/dist/assets/{markdown-Dd89TVib.js → markdown-DJurGVIJ.js} +0 -0
@@ -0,0 +1,1854 @@
1
+ import{C as e,E as t,g as n,v as r}from"./fullcalendar-Bn75j0xM.js";import{a as i,n as a,t as o}from"./react-query-BIbNygEJ.js";import{t as s}from"./vendor-DSaYtO9f.js";import{i as c,n as l,r as u}from"./motion-B3ZE8SGR.js";import{a as d,c as f,n as p,s as m}from"./index-picB46b5.js";import{g as h}from"./workflowStability-Dsk2DR6F.js";import{r as g,t as _}from"./McpToolAllowlistEditor-B3qCkiFT.js";import{r as v}from"./plannerShared-1kHFyAp-.js";var y=Object.assign({"./templates/competitor-research-pipeline.yaml":`id: competitor-research-pipeline
2
+ order: 2
3
+ name: Competitor Research Pipeline
4
+ icon: radar
5
+ summary: Track competitors, synthesize movements, and brief the team on strategic changes.
6
+ description: A recurring competitor workflow that scans rivals, synthesizes patterns, reviews implications, and prepares a distribution-ready summary.
7
+ suggestedOutputs:
8
+ - competitor-scan.md
9
+ - strategic-summary.md
10
+ agents:
11
+ - agentId: market-discover
12
+ displayName: Market Discover
13
+ role: watcher
14
+ avatarUrl: ""
15
+ templateId: ""
16
+ linkedTemplateId: ""
17
+ skills:
18
+ - analysis
19
+ prompt:
20
+ role: You are a market-source scout.
21
+ mission: Identify the local context, competitor list, and source corpus that should guide the competitor scan before evidence gathering begins.
22
+ inputs: Inspect any local competitor lists, prior scans, strategy docs, changelogs, and source bundles. Return a clear inventory of what should be read next.
23
+ outputContract: Return a structured handoff with \`workspace_inventory_summary\`, \`discovered_paths\`, \`priority_paths\`, and \`skipped_paths_initial\`.
24
+ guardrails: Do not jump to conclusions or write the final competitor scan in this stage.
25
+ modelProvider: ""
26
+ modelId: ""
27
+ toolAllowlist:
28
+ - glob
29
+ - read
30
+ toolDenylist: []
31
+ mcpAllowedServers: []
32
+ - agentId: market-local-sources
33
+ displayName: Market Local Sources
34
+ role: watcher
35
+ avatarUrl: ""
36
+ templateId: ""
37
+ linkedTemplateId: ""
38
+ skills:
39
+ - analysis
40
+ prompt:
41
+ role: You are a local-source analyst for competitor intelligence.
42
+ mission: Read the prioritized local sources and extract the competitor context, prior findings, and product framing that should shape the scan.
43
+ inputs: Use the upstream \`source_inventory\` handoff to choose concrete files to read and capture the facts that later scanning should compare against.
44
+ outputContract: Return a structured handoff with \`read_paths\`, \`reviewed_facts\`, \`files_reviewed\`, \`files_not_reviewed\`, and \`citations_local\`.
45
+ guardrails: Only cite local files that were actually read in this run.
46
+ modelProvider: ""
47
+ modelId: ""
48
+ toolAllowlist:
49
+ - glob
50
+ - read
51
+ toolDenylist: []
52
+ mcpAllowedServers: []
53
+ - agentId: market-external
54
+ displayName: Market External
55
+ role: watcher
56
+ avatarUrl: ""
57
+ templateId: ""
58
+ linkedTemplateId: ""
59
+ skills:
60
+ - websearch
61
+ - trend-analysis
62
+ prompt:
63
+ role: You are an external competitor-research analyst.
64
+ mission: Gather current web evidence about competitor launches, pricing moves, positioning shifts, and customer sentiment.
65
+ inputs: Use the upstream \`source_inventory\` and \`local_source_notes\` handoffs to focus the search and fetch specific sources when snippets are not enough.
66
+ outputContract: Return a structured handoff with \`external_research_mode\`, \`queries_attempted\`, \`sources_reviewed\`, \`citations_external\`, and \`research_limitations\`.
67
+ guardrails: If search is unavailable, record the limitation clearly instead of inventing web evidence.
68
+ modelProvider: ""
69
+ modelId: ""
70
+ toolAllowlist:
71
+ - read
72
+ - websearch
73
+ - webfetch
74
+ - glob
75
+ toolDenylist: []
76
+ mcpAllowedServers: []
77
+ - agentId: market-scan
78
+ displayName: Market Scan
79
+ role: watcher
80
+ avatarUrl: ""
81
+ templateId: ""
82
+ linkedTemplateId: ""
83
+ skills:
84
+ - trend-analysis
85
+ prompt:
86
+ role: You are a competitor intelligence analyst responsible for finding real market changes and separating signal from noise.
87
+ mission: Turn the upstream discovery, local source notes, and external market research into the final competitor scan.
88
+ inputs: Use the upstream \`source_inventory\`, \`local_source_notes\`, and \`external_research\` handoffs as the source of truth for the final scan.
89
+ outputContract: Produce a structured scan with what changed, why it matters, evidence links, confidence level, affected audience or buyer stage, and whether the signal is emerging, confirmed, or low-confidence.
90
+ guardrails: Ignore rumors and recycled noise. Separate evidence from inference, be honest about uncertainty, and do not redo web research in this stage.
91
+ modelProvider: ""
92
+ modelId: ""
93
+ toolAllowlist:
94
+ - read
95
+ - glob
96
+ toolDenylist: []
97
+ mcpAllowedServers: []
98
+ - agentId: synthesist
99
+ displayName: Synthesist
100
+ role: worker
101
+ avatarUrl: ""
102
+ templateId: ""
103
+ linkedTemplateId: ""
104
+ skills:
105
+ - synthesis
106
+ prompt:
107
+ role: You are a strategy synthesist who turns raw competitor monitoring into a useful decision brief.
108
+ mission: Convert the market scan into clear strategic implications, priority calls, and recommended responses for the team.
109
+ inputs: Use the competitor scan, prior strategy context, product positioning, and known customer objections or differentiators.
110
+ outputContract: Produce a summary with key themes, what changed, why it matters, threats, opportunities, confidence levels, and recommended actions ranked by urgency and impact.
111
+ guardrails: Do not overreact to a single data point. Distinguish hard facts from interpretation, and explain why each recommended response matters to the business.
112
+ modelProvider: ""
113
+ modelId: ""
114
+ toolAllowlist:
115
+ - read
116
+ - write
117
+ - glob
118
+ toolDenylist: []
119
+ mcpAllowedServers: []
120
+ - agentId: review
121
+ displayName: Review
122
+ role: reviewer
123
+ avatarUrl: ""
124
+ templateId: ""
125
+ linkedTemplateId: ""
126
+ skills:
127
+ - qa
128
+ prompt:
129
+ role: You are the review editor for competitor intelligence, responsible for evidence quality, honest framing, and practical usefulness.
130
+ mission: Review the strategic summary for unsupported conclusions, weak evidence, and recommendations that do not follow from the data.
131
+ inputs: Use the summary, the raw scan evidence, and any relevant positioning context or review criteria.
132
+ outputContract: Approve or request revisions with exact issues grouped by evidence, interpretation, recommendation quality, and missing context.
133
+ guardrails: Reject unsupported conclusions, misleading framing, and advice that skips over uncertainty. Preserve nuance instead of flattening every insight into a threat.
134
+ modelProvider: ""
135
+ modelId: ""
136
+ toolAllowlist:
137
+ - read
138
+ - write
139
+ - glob
140
+ toolDenylist: []
141
+ mcpAllowedServers: []
142
+ - agentId: briefing
143
+ displayName: Briefing
144
+ role: committer
145
+ avatarUrl: ""
146
+ templateId: ""
147
+ linkedTemplateId: ""
148
+ skills:
149
+ - reporting
150
+ prompt:
151
+ role: You are the internal briefing operator who packages approved competitor intelligence for busy stakeholders.
152
+ mission: Turn the approved summary into a concise update the team can skim quickly and act on.
153
+ inputs: Use the reviewed summary, destination channel guidance, and any audience-specific formatting requirements.
154
+ outputContract: Generate a concise update with headline, TL;DR, the top changes, recommended follow-ups, and any owners or deadlines if the brief implies action.
155
+ guardrails: Keep recommendations grounded in the approved evidence, and do not add new claims while packaging the brief.
156
+ modelProvider: ""
157
+ modelId: ""
158
+ toolAllowlist:
159
+ - read
160
+ - write
161
+ - glob
162
+ toolDenylist: []
163
+ mcpAllowedServers: []
164
+ nodes:
165
+ - nodeId: scan-market-discover
166
+ title: Discover Market Sources
167
+ agentId: market-discover
168
+ objective: Identify the local source corpus and file inventory that should guide the competitor scan.
169
+ dependsOn: []
170
+ inputRefs: []
171
+ stageKind: research_discover
172
+ outputKind: structured_json
173
+ outputPath: ""
174
+ taskKind: ""
175
+ projectBacklogTasks: false
176
+ backlogTaskId: ""
177
+ repoRoot: ""
178
+ writeScope: ""
179
+ acceptanceCriteria: ""
180
+ taskDependencies: ""
181
+ verificationState: ""
182
+ taskOwner: ""
183
+ verificationCommand: ""
184
+ - nodeId: scan-market-local-sources
185
+ title: Read Market Sources
186
+ agentId: market-local-sources
187
+ objective: Read the prioritized local competitor and strategy sources before external scanning.
188
+ dependsOn:
189
+ - scan-market-discover
190
+ inputRefs:
191
+ - fromStepId: scan-market-discover
192
+ alias: source_inventory
193
+ stageKind: research_local_sources
194
+ outputKind: structured_json
195
+ outputPath: ""
196
+ taskKind: ""
197
+ projectBacklogTasks: false
198
+ backlogTaskId: ""
199
+ repoRoot: ""
200
+ writeScope: ""
201
+ acceptanceCriteria: ""
202
+ taskDependencies: ""
203
+ verificationState: ""
204
+ taskOwner: ""
205
+ verificationCommand: ""
206
+ - nodeId: scan-market-external-research
207
+ title: Research Market
208
+ agentId: market-external
209
+ objective: Gather current external competitor evidence guided by the local market context.
210
+ dependsOn:
211
+ - scan-market-discover
212
+ - scan-market-local-sources
213
+ inputRefs:
214
+ - fromStepId: scan-market-discover
215
+ alias: source_inventory
216
+ - fromStepId: scan-market-local-sources
217
+ alias: local_source_notes
218
+ stageKind: research_external_sources
219
+ outputKind: structured_json
220
+ outputPath: ""
221
+ taskKind: ""
222
+ projectBacklogTasks: false
223
+ backlogTaskId: ""
224
+ repoRoot: ""
225
+ writeScope: ""
226
+ acceptanceCriteria: ""
227
+ taskDependencies: ""
228
+ verificationState: ""
229
+ taskOwner: ""
230
+ verificationCommand: ""
231
+ - nodeId: scan-market
232
+ title: Scan Market
233
+ agentId: market-scan
234
+ objective: Synthesize the discovered local and external evidence into the final competitor scan.
235
+ dependsOn:
236
+ - scan-market-discover
237
+ - scan-market-local-sources
238
+ - scan-market-external-research
239
+ inputRefs:
240
+ - fromStepId: scan-market-discover
241
+ alias: source_inventory
242
+ - fromStepId: scan-market-local-sources
243
+ alias: local_source_notes
244
+ - fromStepId: scan-market-external-research
245
+ alias: external_research
246
+ stageKind: research_finalize
247
+ outputKind: scan
248
+ outputPath: ""
249
+ taskKind: ""
250
+ projectBacklogTasks: false
251
+ backlogTaskId: ""
252
+ repoRoot: ""
253
+ writeScope: ""
254
+ acceptanceCriteria: ""
255
+ taskDependencies: ""
256
+ verificationState: ""
257
+ taskOwner: ""
258
+ verificationCommand: ""
259
+ - nodeId: synthesize-signals
260
+ title: Synthesize Signals
261
+ agentId: synthesist
262
+ objective: Turn the raw scan into a strategic competitor summary.
263
+ dependsOn:
264
+ - scan-market
265
+ inputRefs:
266
+ - fromStepId: scan-market
267
+ alias: scan
268
+ outputKind: summary
269
+ outputPath: ""
270
+ taskKind: ""
271
+ projectBacklogTasks: false
272
+ backlogTaskId: ""
273
+ repoRoot: ""
274
+ writeScope: ""
275
+ acceptanceCriteria: ""
276
+ taskDependencies: ""
277
+ verificationState: ""
278
+ taskOwner: ""
279
+ verificationCommand: ""
280
+ - nodeId: review-summary
281
+ title: Review Summary
282
+ agentId: review
283
+ objective: Review the summary for evidence quality and useful recommendations.
284
+ dependsOn:
285
+ - synthesize-signals
286
+ inputRefs:
287
+ - fromStepId: synthesize-signals
288
+ alias: summary
289
+ outputKind: review
290
+ outputPath: ""
291
+ taskKind: ""
292
+ projectBacklogTasks: false
293
+ backlogTaskId: ""
294
+ repoRoot: ""
295
+ writeScope: ""
296
+ acceptanceCriteria: ""
297
+ taskDependencies: ""
298
+ verificationState: ""
299
+ taskOwner: ""
300
+ verificationCommand: ""
301
+ - nodeId: publish-brief
302
+ title: Publish Brief
303
+ agentId: briefing
304
+ objective: Prepare the reviewed summary for internal distribution.
305
+ dependsOn:
306
+ - review-summary
307
+ inputRefs:
308
+ - fromStepId: review-summary
309
+ alias: approved_summary
310
+ outputKind: brief
311
+ outputPath: ""
312
+ taskKind: ""
313
+ projectBacklogTasks: false
314
+ backlogTaskId: ""
315
+ repoRoot: ""
316
+ writeScope: ""
317
+ acceptanceCriteria: ""
318
+ taskDependencies: ""
319
+ verificationState: ""
320
+ taskOwner: ""
321
+ verificationCommand: ""
322
+ `,"./templates/marketing-content-pipeline.yaml":`id: marketing-content-pipeline
323
+ order: 0
324
+ name: Marketing Content Pipeline
325
+ icon: megaphone
326
+ summary: Audit the workspace, create a marketing brief, draft copy, review it, and package it for publishing.
327
+ description: A reusable four-stage marketing workflow that starts by inspecting the workspace for product context, source material, and existing assets, then creates a fresh brief, drafts copy, reviews claims and tone, and prepares a publish-ready handoff.
328
+ suggestedOutputs:
329
+ - marketing-brief.md
330
+ - draft-post.md
331
+ - review-notes.md
332
+ - approved-post.md
333
+ - publish-checklist.md
334
+ agents:
335
+ - agentId: research-discover
336
+ displayName: Research Discover
337
+ role: watcher
338
+ avatarUrl: ""
339
+ templateId: ""
340
+ linkedTemplateId: ""
341
+ skills:
342
+ - analysis
343
+ prompt:
344
+ role: You are a workspace source scout for product marketing research.
345
+ mission: Enumerate the workspace, identify the product and marketing source corpus, and decide which files should be reviewed before synthesis begins.
346
+ inputs: Start at the workspace root. Enumerate the folders and concrete files that look relevant to product marketing, docs, customer-facing text, manifests, READMEs, or source bundles. If a curated source index such as \`SOURCES.md\` exists, read it first. Perform at least one concrete \`read\` before finishing, but read only enough to identify the source corpus and prioritize what must be reviewed next. Treat prior generated workflow artifacts as non-authoritative.
347
+ outputContract: Return a structured handoff that includes \`workspace_inventory_summary\`, \`discovered_paths\`, \`priority_paths\`, and \`skipped_paths_initial\` so the next stage can perform concrete file reads. Every path in \`discovered_paths\`, \`priority_paths\`, and \`skipped_paths_initial\` must be a concrete workspace-relative file path — never a glob pattern (e.g. \`*.yaml\`), directory placeholder (e.g. \`tandem-social/\`), or wildcard (e.g. \`tandem/components/*\`).
348
+ guardrails: Do not write the final brief in this stage. Do not invent file contents. Prefer broad source coverage and clear prioritization over early synthesis, and do not finish after \`glob\` alone. Never emit a glob pattern, wildcard, or directory path in any path field — only concrete individual file paths.
349
+ modelProvider: ""
350
+ modelId: ""
351
+ toolAllowlist:
352
+ - glob
353
+ - read
354
+ toolDenylist: []
355
+ mcpAllowedServers: []
356
+ - agentId: research-local-sources
357
+ displayName: Research Local Sources
358
+ role: watcher
359
+ avatarUrl: ""
360
+ templateId: ""
361
+ linkedTemplateId: ""
362
+ skills:
363
+ - analysis
364
+ prompt:
365
+ role: You are a local-source analyst preparing evidence-backed marketing notes from workspace files.
366
+ mission: Read the prioritized local files, extract usable facts and customer language, and account for all relevant sources before synthesis.
367
+ inputs: Use the upstream \`source_inventory\` handoff as the file plan. Perform concrete \`read\` calls on the prioritized local files and capture the product facts, audience clues, proof points, and messaging language supported by those reads.
368
+ outputContract: Return a structured handoff that includes \`read_paths\`, \`reviewed_facts\`, \`files_reviewed\`, \`files_not_reviewed\`, and \`citations_local\` so later stages can rely on concrete local evidence. Every path in \`read_paths\`, \`files_reviewed\`, and \`files_not_reviewed\` must be a concrete workspace-relative file path — never a glob pattern, wildcard, or directory placeholder.
369
+ guardrails: Do not invent facts from filenames alone. Every file listed in \`files_reviewed\` must have been actually read in this run. Any relevant discovered file you skip must appear in \`files_not_reviewed\` with a reason. Never use glob patterns, wildcards, or directory paths in any path field — only concrete individual file paths that exist in the workspace.
370
+ modelProvider: ""
371
+ modelId: ""
372
+ toolAllowlist:
373
+ - glob
374
+ - read
375
+ toolDenylist: []
376
+ mcpAllowedServers: []
377
+ - agentId: research-external
378
+ displayName: Research External
379
+ role: watcher
380
+ avatarUrl: ""
381
+ templateId: ""
382
+ linkedTemplateId: ""
383
+ skills:
384
+ - websearch
385
+ - analysis
386
+ prompt:
387
+ role: You are an external research analyst gathering current market context for the marketing brief.
388
+ mission: Use targeted web research to validate competitor context, market framing, and external proof points that complement the local source corpus.
389
+ inputs: Use the upstream \`source_inventory\` and \`local_source_notes\` handoffs to guide the external research. Perform targeted \`websearch\` queries and fetch result pages when needed before extracting evidence.
390
+ outputContract: Return a structured handoff that includes \`external_research_mode\`, \`queries_attempted\`, \`sources_reviewed\`, \`citations_external\`, and \`research_limitations\` so the final brief can disclose what web validation was or was not completed.
391
+ guardrails: If web research is unavailable, record that limitation clearly and continue without inventing external evidence. Do not write the final brief in this stage.
392
+ modelProvider: ""
393
+ modelId: ""
394
+ toolAllowlist:
395
+ - read
396
+ - websearch
397
+ - webfetch
398
+ - glob
399
+ toolDenylist: []
400
+ mcpAllowedServers: []
401
+ - agentId: research
402
+ displayName: Research
403
+ role: watcher
404
+ avatarUrl: ""
405
+ templateId: ""
406
+ linkedTemplateId: ""
407
+ skills:
408
+ - analysis
409
+ prompt:
410
+ role: You are a product marketing researcher focused on campaign positioning, audience insight, and competitive context.
411
+ mission: Turn the upstream discovery, local source evidence, and external research into the first complete marketing brief for the workflow.
412
+ inputs: Use the upstream \`source_inventory\`, \`local_source_notes\`, and \`external_research\` handoffs as the source of truth. Read \`marketing-brief.md\` from disk only as a fallback or verification step. Synthesize the brief from those handoffs instead of repeating discovery or fresh web research in this stage.
413
+ outputContract: "Use the write tool to create \`marketing-brief.md\` in the workspace even if it does not exist yet. The file must include: a workspace source audit, campaign goal, target audience, core pain points, customer-language phrases to mirror, positioning angle, competitor context, proof points with citations, likely objections, channel considerations, a recommended message hierarchy, a comprehensive \`Files reviewed\` section with exact local paths, a \`Files not reviewed\` section for any relevant sources skipped with reasons, and a \`Web sources reviewed\` section with the searches or pages used. Use only exact concrete workspace-relative file paths in \`Files reviewed\` and \`Files not reviewed\`; do not use directory names, wildcard paths, or glob patterns such as \`*.yaml\`. The brief should be usable even if no prior campaign brief existed."
414
+ guardrails: Do not invent metrics, testimonials, or competitor claims. Use the upstream evidence handoffs as the basis for the final brief, clearly note research limitations, and do not claim success unless the write tool actually created \`marketing-brief.md\`. Never list a path in the source audit unless it is a concrete workspace-relative file path that exists or a concrete URL that was actually reviewed.
415
+ modelProvider: ""
416
+ modelId: ""
417
+ toolAllowlist:
418
+ - read
419
+ - write
420
+ - glob
421
+ toolDenylist: []
422
+ mcpAllowedServers: []
423
+ - agentId: copywriter
424
+ displayName: Copywriter
425
+ role: worker
426
+ avatarUrl: ""
427
+ templateId: ""
428
+ linkedTemplateId: ""
429
+ skills:
430
+ - copywriting
431
+ - messaging
432
+ prompt:
433
+ role: You are a conversion-focused marketing copywriter who turns research into clear, persuasive, channel-native copy.
434
+ mission: Translate the newly created marketing brief into copy that is specific, audience-aware, and built around one clear promise and one clear call to action.
435
+ inputs: Use the upstream \`marketing_brief\` handoff from the previous stage as the primary source of truth. Only read \`marketing-brief.md\` from disk as a fallback or verification step. Use that brief, the workspace source audit, product marketing context, brand voice, channel constraints, and any proof points or customer-language phrases collected during research. Treat prior generated drafts, reviews, or checklists as workflow artifacts, not as source authority. Do not attempt to read directory placeholders, wildcard paths, or glob patterns from the brief source audit; only concrete workspace-relative file paths are eligible for \`read\`.
436
+ outputContract: "Use the write tool to create \`draft-post.md\` in the workspace. The file must include a strong hook, concise body, proof-backed claims, a clear CTA, and 2 optional hook or CTA variants for testing. Make the message progression obvious: problem, promise, proof, action."
437
+ guardrails: Choose clarity over cleverness, benefits over feature lists, and specificity over vague hype. Keep unsupported claims out, avoid filler words and jargon, and do not drift away from the approved audience or positioning. If the upstream \`marketing_brief\` handoff is missing or explicitly says the research is provisional or blocked, stop and write a blocked draft note instead of inventing source-backed messaging. Do not claim success unless the write tool actually created \`draft-post.md\`.
438
+ modelProvider: ""
439
+ modelId: ""
440
+ toolAllowlist:
441
+ - read
442
+ - write
443
+ - glob
444
+ toolDenylist: []
445
+ mcpAllowedServers: []
446
+ - agentId: reviewer
447
+ displayName: Reviewer
448
+ role: reviewer
449
+ avatarUrl: ""
450
+ templateId: ""
451
+ linkedTemplateId: ""
452
+ skills:
453
+ - fact-checking
454
+ - brand-review
455
+ prompt:
456
+ role: You are an editorial reviewer applying a claims check, brand check, and conversion copy edit before anything is approved.
457
+ mission: Pressure-test the draft for clarity, tone, specificity, proof, and actionability so only publishable marketing copy moves forward.
458
+ inputs: Use the upstream \`draft\` handoff as the primary draft input and the upstream \`marketing_brief\` context from the earlier stage when available. Read \`draft-post.md\` or \`marketing-brief.md\` from disk only as a fallback or verification step. Then use the workspace source audit, product marketing context, and any brand or compliance guidance to review claims, voice, benefit framing, proof, and CTA quality. Verify that the brief includes real files reviewed and, when expected, actual web research before approving copy.
459
+ outputContract: Always use the write tool for review output. If the draft is approved, write the approved version to \`approved-post.md\` and briefly note approval in \`review-notes.md\`. If the draft is not approved, write exact revision guidance to \`review-notes.md\` and clearly state that \`approved-post.md\` was not created yet.
460
+ guardrails: Do not approve unsupported or exaggerated claims. Preserve the core message when possible, prefer specific edits over vague criticism, and call out anything that fails the 'so what' or 'prove it' test. If the upstream \`draft\` handoff is missing, or if the research brief shows missing source evidence, missing file citations, or no current web research where web research was expected, reject the draft rather than approving generic messaging. Never claim approval unless the write tool actually created \`approved-post.md\`.
461
+ modelProvider: ""
462
+ modelId: ""
463
+ toolAllowlist:
464
+ - read
465
+ - write
466
+ - glob
467
+ toolDenylist: []
468
+ mcpAllowedServers: []
469
+ - agentId: poster
470
+ displayName: Poster
471
+ role: committer
472
+ avatarUrl: ""
473
+ templateId: ""
474
+ linkedTemplateId: ""
475
+ skills:
476
+ - publishing
477
+ prompt:
478
+ role: You are a publishing operator who adapts approved copy into a channel-ready final artifact without losing the approved message.
479
+ mission: Prepare the approved copy for handoff or posting on the intended channel, including formatting, metadata, and an operator-ready checklist.
480
+ inputs: Use the upstream \`approved_copy\` handoff as the primary source of truth for approved content. Read \`approved-post.md\` from disk only as a fallback or verification step. If approval did not happen, inspect upstream review feedback and \`review-notes.md\`, then record a blocked handoff instead of pretending the post is ready.
481
+ outputContract: Always use the write tool to create \`publish-checklist.md\`. If approved content exists, produce a final publish-ready artifact summary, channel formatting notes, required assets or links, and a short posting checklist that records destination, timing, and any manual follow-up. If approved content does not exist, write a blocked handoff note in \`publish-checklist.md\` explaining exactly what is missing.
482
+ guardrails: Never publish unapproved text. Preserve the approved message, only make channel-formatting changes that do not alter claims, and clearly flag anything that still requires human action. If the upstream \`approved_copy\` handoff is missing, treat that as blocked rather than success. Do not claim success unless the write tool actually created \`publish-checklist.md\`.
483
+ modelProvider: ""
484
+ modelId: ""
485
+ toolAllowlist:
486
+ - read
487
+ - write
488
+ - glob
489
+ toolDenylist: []
490
+ mcpAllowedServers: []
491
+ nodes:
492
+ - nodeId: research-discover-sources
493
+ title: Discover Sources
494
+ agentId: research-discover
495
+ objective: Enumerate the workspace, identify the relevant source corpus, and prioritize which local files must be read for the marketing brief.
496
+ dependsOn: []
497
+ inputRefs: []
498
+ stageKind: research_discover
499
+ outputKind: structured_json
500
+ outputPath: ""
501
+ taskKind: ""
502
+ projectBacklogTasks: false
503
+ backlogTaskId: ""
504
+ repoRoot: ""
505
+ writeScope: ""
506
+ acceptanceCriteria: ""
507
+ taskDependencies: ""
508
+ verificationState: ""
509
+ taskOwner: ""
510
+ verificationCommand: ""
511
+ - nodeId: research-local-sources
512
+ title: Read Local Sources
513
+ agentId: research-local-sources
514
+ objective: Read the prioritized local product and marketing files and produce source-backed notes for the brief.
515
+ dependsOn:
516
+ - research-discover-sources
517
+ inputRefs:
518
+ - fromStepId: research-discover-sources
519
+ alias: source_inventory
520
+ stageKind: research_local_sources
521
+ outputKind: structured_json
522
+ outputPath: ""
523
+ taskKind: ""
524
+ projectBacklogTasks: false
525
+ backlogTaskId: ""
526
+ repoRoot: ""
527
+ writeScope: ""
528
+ acceptanceCriteria: ""
529
+ taskDependencies: ""
530
+ verificationState: ""
531
+ taskOwner: ""
532
+ verificationCommand: ""
533
+ - nodeId: research-external-research
534
+ title: External Research
535
+ agentId: research-external
536
+ objective: Perform targeted external research that complements the local source notes and record what web evidence was gathered or unavailable.
537
+ dependsOn:
538
+ - research-discover-sources
539
+ - research-local-sources
540
+ inputRefs:
541
+ - fromStepId: research-discover-sources
542
+ alias: source_inventory
543
+ - fromStepId: research-local-sources
544
+ alias: local_source_notes
545
+ stageKind: research_external_sources
546
+ outputKind: structured_json
547
+ outputPath: ""
548
+ taskKind: ""
549
+ projectBacklogTasks: false
550
+ backlogTaskId: ""
551
+ repoRoot: ""
552
+ writeScope: ""
553
+ acceptanceCriteria: ""
554
+ taskDependencies: ""
555
+ verificationState: ""
556
+ taskOwner: ""
557
+ verificationCommand: ""
558
+ - nodeId: research-brief
559
+ title: Research Brief
560
+ agentId: research
561
+ objective: Write \`marketing-brief.md\` from the structured discovery, local source notes, and external research gathered earlier in the workflow.
562
+ dependsOn:
563
+ - research-discover-sources
564
+ - research-local-sources
565
+ - research-external-research
566
+ inputRefs:
567
+ - fromStepId: research-discover-sources
568
+ alias: source_inventory
569
+ - fromStepId: research-local-sources
570
+ alias: local_source_notes
571
+ - fromStepId: research-external-research
572
+ alias: external_research
573
+ stageKind: research_finalize
574
+ outputKind: brief
575
+ outputPath: marketing-brief.md
576
+ taskKind: ""
577
+ projectBacklogTasks: false
578
+ backlogTaskId: ""
579
+ repoRoot: ""
580
+ writeScope: ""
581
+ acceptanceCriteria: ""
582
+ taskDependencies: ""
583
+ verificationState: ""
584
+ taskOwner: ""
585
+ verificationCommand: ""
586
+ - nodeId: draft-copy
587
+ title: Draft Copy
588
+ agentId: copywriter
589
+ objective: Write \`draft-post.md\` from the newly created marketing brief and workspace context.
590
+ dependsOn:
591
+ - research-brief
592
+ inputRefs:
593
+ - fromStepId: research-brief
594
+ alias: marketing_brief
595
+ outputKind: draft
596
+ outputPath: draft-post.md
597
+ taskKind: ""
598
+ projectBacklogTasks: false
599
+ backlogTaskId: ""
600
+ repoRoot: ""
601
+ writeScope: ""
602
+ acceptanceCriteria: ""
603
+ taskDependencies: ""
604
+ verificationState: ""
605
+ taskOwner: ""
606
+ verificationCommand: ""
607
+ - nodeId: review-copy
608
+ title: Review Copy
609
+ agentId: reviewer
610
+ objective: Review \`draft-post.md\` against the marketing brief and source evidence, then write \`review-notes.md\` and, when approved, \`approved-post.md\`.
611
+ dependsOn:
612
+ - draft-copy
613
+ inputRefs:
614
+ - fromStepId: draft-copy
615
+ alias: draft
616
+ outputKind: review
617
+ outputPath: review-notes.md
618
+ taskKind: ""
619
+ projectBacklogTasks: false
620
+ backlogTaskId: ""
621
+ repoRoot: ""
622
+ writeScope: ""
623
+ acceptanceCriteria: ""
624
+ taskDependencies: ""
625
+ verificationState: ""
626
+ taskOwner: ""
627
+ verificationCommand: ""
628
+ - nodeId: publish-copy
629
+ title: Publish Copy
630
+ agentId: poster
631
+ objective: Prepare the approved post for the requested channel and always write \`publish-checklist.md\`, including a blocked handoff note if approval has not happened yet.
632
+ dependsOn:
633
+ - review-copy
634
+ inputRefs:
635
+ - fromStepId: review-copy
636
+ alias: approved_copy
637
+ outputKind: publish
638
+ outputPath: publish-checklist.md
639
+ taskKind: ""
640
+ projectBacklogTasks: false
641
+ backlogTaskId: ""
642
+ repoRoot: ""
643
+ writeScope: ""
644
+ acceptanceCriteria: ""
645
+ taskDependencies: ""
646
+ verificationState: ""
647
+ taskOwner: ""
648
+ verificationCommand: ""
649
+ `,"./templates/prd-to-launch-plan-team.yaml":`id: prd-to-launch-plan-team
650
+ order: 6
651
+ name: PRD to Launch Plan Team
652
+ icon: rocket
653
+ summary: Turn a product brief into an execution plan, review it, and prepare launch handoff.
654
+ description: A cross-functional planning workflow that reads a PRD, drafts an execution plan, reviews risks, and prepares a launch-ready brief.
655
+ suggestedOutputs:
656
+ - execution-plan.md
657
+ - risk-review.md
658
+ - launch-brief.md
659
+ agents:
660
+ - agentId: planner
661
+ displayName: Planner
662
+ role: delegator
663
+ avatarUrl: ""
664
+ templateId: ""
665
+ linkedTemplateId: ""
666
+ skills:
667
+ - planning
668
+ prompt:
669
+ role: You are the implementation planner.
670
+ mission: Convert the PRD into a realistic execution plan with milestones and owners.
671
+ inputs: Use the PRD, known constraints, and delivery context.
672
+ outputContract: Produce a step-by-step plan with dependencies and key open questions.
673
+ guardrails: Call out assumptions and missing information explicitly.
674
+ modelProvider: ""
675
+ modelId: ""
676
+ toolAllowlist:
677
+ - read
678
+ - write
679
+ - glob
680
+ toolDenylist: []
681
+ mcpAllowedServers: []
682
+ - agentId: go-to-market
683
+ displayName: Go To Market
684
+ role: worker
685
+ avatarUrl: ""
686
+ templateId: ""
687
+ linkedTemplateId: ""
688
+ skills:
689
+ - launch-planning
690
+ prompt:
691
+ role: You are the launch planning writer.
692
+ mission: Add launch, messaging, enablement, and rollout considerations to the plan.
693
+ inputs: Use the execution plan and product context.
694
+ outputContract: Produce the GTM and rollout sections required for launch readiness.
695
+ guardrails: Keep dependencies and owner requests concrete.
696
+ modelProvider: ""
697
+ modelId: ""
698
+ toolAllowlist:
699
+ - read
700
+ - write
701
+ - glob
702
+ toolDenylist: []
703
+ mcpAllowedServers: []
704
+ - agentId: risk-review
705
+ displayName: Risk Review
706
+ role: reviewer
707
+ avatarUrl: ""
708
+ templateId: ""
709
+ linkedTemplateId: ""
710
+ skills:
711
+ - risk-analysis
712
+ prompt:
713
+ role: You are the delivery risk reviewer.
714
+ mission: Review the plan for sequencing risks, unclear owners, and launch gaps.
715
+ inputs: Use the implementation plan and GTM additions.
716
+ outputContract: Approve or provide explicit risk and gap notes for revision.
717
+ guardrails: Prioritize real execution blockers over stylistic concerns.
718
+ modelProvider: ""
719
+ modelId: ""
720
+ toolAllowlist:
721
+ - read
722
+ - write
723
+ - glob
724
+ toolDenylist: []
725
+ mcpAllowedServers: []
726
+ - agentId: launch-ops
727
+ displayName: Launch Ops
728
+ role: committer
729
+ avatarUrl: ""
730
+ templateId: ""
731
+ linkedTemplateId: ""
732
+ skills:
733
+ - operations
734
+ - handoff
735
+ prompt:
736
+ role: You are the launch handoff operator.
737
+ mission: Prepare the reviewed plan for team handoff and launch tracking.
738
+ inputs: Use the approved plan and rollout notes.
739
+ outputContract: Produce a launch brief with owners, timeline, and readiness checklist.
740
+ guardrails: Do not hide unresolved risks; surface them clearly in the brief.
741
+ modelProvider: ""
742
+ modelId: ""
743
+ toolAllowlist:
744
+ - read
745
+ - write
746
+ - glob
747
+ toolDenylist: []
748
+ mcpAllowedServers: []
749
+ nodes:
750
+ - nodeId: draft-plan
751
+ title: Draft Plan
752
+ agentId: planner
753
+ objective: Draft the implementation plan from the PRD.
754
+ dependsOn: []
755
+ inputRefs: []
756
+ outputKind: plan
757
+ outputPath: ""
758
+ taskKind: ""
759
+ projectBacklogTasks: false
760
+ backlogTaskId: ""
761
+ repoRoot: ""
762
+ writeScope: ""
763
+ acceptanceCriteria: ""
764
+ taskDependencies: ""
765
+ verificationState: ""
766
+ taskOwner: ""
767
+ verificationCommand: ""
768
+ - nodeId: add-rollout
769
+ title: Add Rollout
770
+ agentId: go-to-market
771
+ objective: Add GTM and rollout planning details to the execution plan.
772
+ dependsOn:
773
+ - draft-plan
774
+ inputRefs:
775
+ - fromStepId: draft-plan
776
+ alias: implementation_plan
777
+ outputKind: rollout
778
+ outputPath: ""
779
+ taskKind: ""
780
+ projectBacklogTasks: false
781
+ backlogTaskId: ""
782
+ repoRoot: ""
783
+ writeScope: ""
784
+ acceptanceCriteria: ""
785
+ taskDependencies: ""
786
+ verificationState: ""
787
+ taskOwner: ""
788
+ verificationCommand: ""
789
+ - nodeId: review-risks
790
+ title: Review Risks
791
+ agentId: risk-review
792
+ objective: Review the plan for risk, sequencing, and readiness gaps.
793
+ dependsOn:
794
+ - add-rollout
795
+ inputRefs:
796
+ - fromStepId: add-rollout
797
+ alias: launch_plan
798
+ outputKind: review
799
+ outputPath: ""
800
+ taskKind: ""
801
+ projectBacklogTasks: false
802
+ backlogTaskId: ""
803
+ repoRoot: ""
804
+ writeScope: ""
805
+ acceptanceCriteria: ""
806
+ taskDependencies: ""
807
+ verificationState: ""
808
+ taskOwner: ""
809
+ verificationCommand: ""
810
+ - nodeId: prepare-launch-brief
811
+ title: Prepare Launch Brief
812
+ agentId: launch-ops
813
+ objective: Prepare the reviewed launch plan for cross-functional handoff.
814
+ dependsOn:
815
+ - review-risks
816
+ inputRefs:
817
+ - fromStepId: review-risks
818
+ alias: approved_plan
819
+ outputKind: launch_brief
820
+ outputPath: ""
821
+ taskKind: ""
822
+ projectBacklogTasks: false
823
+ backlogTaskId: ""
824
+ repoRoot: ""
825
+ writeScope: ""
826
+ acceptanceCriteria: ""
827
+ taskDependencies: ""
828
+ verificationState: ""
829
+ taskOwner: ""
830
+ verificationCommand: ""
831
+ `,"./templates/repo-coding-backlog.yaml":`id: repo-coding-backlog
832
+ order: 1
833
+ name: Repo Coding Backlog
834
+ icon: code-2
835
+ summary: Analyze a repository task backlog, implement scoped changes, verify them, and prepare a merge-ready handoff.
836
+ description: "A coding workflow for long-running repository work: understand the task and repo area, make scoped code changes, run verification, review the outcome, and prepare a handoff with changed files and next steps."
837
+ suggestedOutputs:
838
+ - coding-backlog-plan.md
839
+ - implementation-notes.md
840
+ - verification-report.md
841
+ - merge-handoff.md
842
+ agents:
843
+ - agentId: repo-planner
844
+ displayName: Repo Planner
845
+ role: delegator
846
+ avatarUrl: ""
847
+ templateId: ""
848
+ linkedTemplateId: ""
849
+ skills:
850
+ - planning
851
+ - codebase-analysis
852
+ prompt:
853
+ role: You are a repository task planner turning backlog items into a concrete implementation approach.
854
+ mission: Inspect the repository, understand the requested task, identify the likely write scope, and prepare an implementation brief that downstream coding stages can execute safely.
855
+ inputs: Treat the workspace as a real repository, not a single-file task. Enumerate the repo, read the task-relevant source files, docs, manifests, tests, and configuration, and identify the modules most likely to change. If issue text, backlog text, or acceptance criteria are present in the workspace, use them as source-of-truth inputs.
856
+ outputContract: Create \`coding-backlog-plan.md\` with the task summary, acceptance criteria, likely write scope, affected files/modules, key architectural constraints, verification commands to run later, and a concise implementation approach. Also include a fenced \`json\` block for projected backlog tasks so downstream systems can ingest multiple coding tasks from this plan.
857
+ guardrails: Do not invent repository structure or acceptance criteria. List uncertainties explicitly, distinguish observed facts from inferred approach, and do not treat prior generated workflow artifacts as authoritative task inputs.
858
+ modelProvider: ""
859
+ modelId: ""
860
+ toolAllowlist:
861
+ - glob
862
+ - read
863
+ - write
864
+ - bash
865
+ toolDenylist: []
866
+ mcpAllowedServers: []
867
+ - agentId: implementer
868
+ displayName: Implementer
869
+ role: worker
870
+ avatarUrl: ""
871
+ templateId: ""
872
+ linkedTemplateId: ""
873
+ skills:
874
+ - coding
875
+ - debugging
876
+ prompt:
877
+ role: You are a coding agent implementing repository changes inside a declared scope with minimal churn.
878
+ mission: Make the requested code or config changes, keep edits scoped, and leave clear implementation notes for verification and review.
879
+ inputs: Use the upstream \`repo_plan\` handoff as the implementation guide, then inspect the referenced source files directly before editing. Prefer repo-local evidence over assumptions. When available, keep changes inside the declared write scope and note any necessary scope expansion explicitly.
880
+ outputContract: Create \`implementation-notes.md\` summarizing what changed, files touched, unresolved risks, and which verification commands should be run next. Also make the actual repository edits required by the task.
881
+ guardrails: Prefer \`apply_patch\` or \`edit\` for existing source files, and use \`write\` only for new files or when patch/edit cannot express the change. Do not replace source files with placeholders, status notes, or preservation notes. Keep modifications inside the planned scope unless new evidence forces a change, and then explain why.
882
+ modelProvider: ""
883
+ modelId: ""
884
+ toolAllowlist:
885
+ - glob
886
+ - read
887
+ - edit
888
+ - apply_patch
889
+ - write
890
+ - bash
891
+ toolDenylist: []
892
+ mcpAllowedServers: []
893
+ - agentId: verifier
894
+ displayName: Verifier
895
+ role: tester
896
+ avatarUrl: ""
897
+ templateId: ""
898
+ linkedTemplateId: ""
899
+ skills:
900
+ - testing
901
+ - qa
902
+ prompt:
903
+ role: You are a verification engineer responsible for proving whether the repository changes satisfy the task.
904
+ mission: Run the most relevant build, test, lint, or task-specific verification commands, then summarize whether the implementation is ready to review or needs more work.
905
+ inputs: Use the upstream \`implementation\` handoff, the repository files, and the verification commands identified earlier. Read changed files and related tests before running commands so the report explains what was actually checked.
906
+ outputContract: "Create \`verification-report.md\` with commands run, pass/fail results, failing output excerpts when relevant, changed files reviewed, and a clear verdict: verified, verify_failed, or blocked."
907
+ guardrails: Do not claim verification without actually running the commands you report. If a command cannot run, record the exact blocker. Keep the report factual and concise.
908
+ modelProvider: ""
909
+ modelId: ""
910
+ toolAllowlist:
911
+ - glob
912
+ - read
913
+ - write
914
+ - bash
915
+ toolDenylist: []
916
+ mcpAllowedServers: []
917
+ - agentId: handoff
918
+ displayName: Handoff
919
+ role: reviewer
920
+ avatarUrl: ""
921
+ templateId: ""
922
+ linkedTemplateId: ""
923
+ skills:
924
+ - code-review
925
+ - handoff
926
+ prompt:
927
+ role: You are the final coding workflow reviewer and handoff operator.
928
+ mission: Review the implementation notes and verification report, then prepare a merge-ready handoff that clearly states readiness, changed scope, and any remaining follow-up work.
929
+ inputs: Use the upstream \`implementation\` and \`verification\` handoffs as primary inputs. Read the changed files from disk only as needed to confirm claims or summarize the scope of change.
930
+ outputContract: Create \`merge-handoff.md\` with the task summary, changed files, verification outcome, review findings, follow-up items, and a clear release/merge recommendation.
931
+ guardrails: Do not mark work ready if verification failed or critical blockers remain. Keep review comments specific, and do not overwrite prior artifacts with status placeholders.
932
+ modelProvider: ""
933
+ modelId: ""
934
+ toolAllowlist:
935
+ - glob
936
+ - read
937
+ - write
938
+ toolDenylist: []
939
+ mcpAllowedServers: []
940
+ nodes:
941
+ - nodeId: plan-backlog-task
942
+ title: Plan Backlog Task
943
+ agentId: repo-planner
944
+ objective: Inspect the repository and backlog context, then write \`coding-backlog-plan.md\` with task scope, affected areas, and verification approach.
945
+ dependsOn: []
946
+ inputRefs: []
947
+ outputKind: plan
948
+ outputPath: coding-backlog-plan.md
949
+ taskKind: repo_plan
950
+ projectBacklogTasks: true
951
+ backlogTaskId: backlog-task
952
+ repoRoot: .
953
+ writeScope: repository analysis, docs, manifests, and task-relevant source files
954
+ acceptanceCriteria: Identify the task scope, affected repo areas, constraints, and a concrete verification plan.
955
+ taskDependencies: ""
956
+ verificationState: planned
957
+ taskOwner: repo-planner
958
+ verificationCommand: ""
959
+ - nodeId: implement-change
960
+ title: Implement Change
961
+ agentId: implementer
962
+ objective: Implement the repository changes described in the plan, update the relevant source files, and write \`implementation-notes.md\`.
963
+ dependsOn:
964
+ - plan-backlog-task
965
+ inputRefs:
966
+ - fromStepId: plan-backlog-task
967
+ alias: repo_plan
968
+ outputKind: code_change
969
+ outputPath: implementation-notes.md
970
+ taskKind: code_change
971
+ backlogTaskId: backlog-task
972
+ repoRoot: .
973
+ writeScope: task-scoped source files, tests, configs, and new files required by the change
974
+ acceptanceCriteria: Implement the planned repo change inside scope and leave clear notes for verification.
975
+ taskDependencies: plan-backlog-task
976
+ verificationState: pending
977
+ taskOwner: implementer
978
+ verificationCommand: Run the repo-appropriate build/test/lint commands for the touched area.
979
+ projectBacklogTasks: false
980
+ - nodeId: verify-change
981
+ title: Verify Change
982
+ agentId: verifier
983
+ objective: Verify the implementation with the relevant build, test, or lint commands and write \`verification-report.md\`.
984
+ dependsOn:
985
+ - implement-change
986
+ inputRefs:
987
+ - fromStepId: implement-change
988
+ alias: implementation
989
+ outputKind: verification
990
+ outputPath: verification-report.md
991
+ taskKind: verification
992
+ backlogTaskId: backlog-task
993
+ repoRoot: .
994
+ writeScope: changed files plus directly relevant tests and config
995
+ acceptanceCriteria: Run the relevant repo-local verification commands and return a factual pass/fail verdict.
996
+ taskDependencies: implement-change
997
+ verificationState: required
998
+ taskOwner: verifier
999
+ verificationCommand: Use the best repo-local verification commands for the touched files and report exact results.
1000
+ projectBacklogTasks: false
1001
+ - nodeId: prepare-merge-handoff
1002
+ title: Prepare Merge Handoff
1003
+ agentId: handoff
1004
+ objective: Review the implementation and verification outputs, then write \`merge-handoff.md\` with merge readiness and follow-up notes.
1005
+ dependsOn:
1006
+ - verify-change
1007
+ inputRefs:
1008
+ - fromStepId: implement-change
1009
+ alias: implementation
1010
+ - fromStepId: verify-change
1011
+ alias: verification
1012
+ outputKind: review
1013
+ outputPath: merge-handoff.md
1014
+ taskKind: review
1015
+ backlogTaskId: backlog-task
1016
+ repoRoot: .
1017
+ writeScope: implementation notes, verification report, and changed files for spot checks
1018
+ acceptanceCriteria: Summarize change scope, verification outcome, and merge readiness for the backlog task.
1019
+ taskDependencies: implement-change, verify-change
1020
+ verificationState: reported
1021
+ taskOwner: handoff
1022
+ verificationCommand: ""
1023
+ projectBacklogTasks: false
1024
+ `,"./templates/sales-prospecting-team.yaml":`id: sales-prospecting-team
1025
+ order: 5
1026
+ name: Sales Prospecting Team
1027
+ icon: target
1028
+ summary: Research accounts, write outreach, review positioning, and prepare sending.
1029
+ description: A prospecting workflow that researches a target account, drafts outreach, reviews fit and claims, and prepares the outbound package.
1030
+ suggestedOutputs:
1031
+ - account-brief.md
1032
+ - outreach-draft.md
1033
+ - send-pack.md
1034
+ agents:
1035
+ - agentId: account-discover
1036
+ displayName: Account Discover
1037
+ role: watcher
1038
+ avatarUrl: ""
1039
+ templateId: ""
1040
+ linkedTemplateId: ""
1041
+ skills:
1042
+ - account-research
1043
+ prompt:
1044
+ role: You are a prospecting source scout.
1045
+ mission: Identify the local account context, CRM notes, and source corpus that should be reviewed before outreach research begins.
1046
+ inputs: Inspect the workspace for account lists, CRM notes, ICP context, and prior research files, then prioritize the concrete sources to read next.
1047
+ outputContract: Return a structured handoff with \`workspace_inventory_summary\`, \`discovered_paths\`, \`priority_paths\`, and \`skipped_paths_initial\`.
1048
+ guardrails: Do not write the final account brief in this stage.
1049
+ modelProvider: ""
1050
+ modelId: ""
1051
+ toolAllowlist:
1052
+ - read
1053
+ - glob
1054
+ toolDenylist: []
1055
+ mcpAllowedServers: []
1056
+ - agentId: account-local-sources
1057
+ displayName: Account Local Sources
1058
+ role: watcher
1059
+ avatarUrl: ""
1060
+ templateId: ""
1061
+ linkedTemplateId: ""
1062
+ skills:
1063
+ - account-research
1064
+ prompt:
1065
+ role: You are a local account-context analyst.
1066
+ mission: Read the prioritized local account and ICP files and extract the most reliable personalization inputs.
1067
+ inputs: Use the upstream \`source_inventory\` handoff to choose concrete files to read and capture the facts that will anchor the account brief.
1068
+ outputContract: Return a structured handoff with \`read_paths\`, \`reviewed_facts\`, \`files_reviewed\`, \`files_not_reviewed\`, and \`citations_local\`.
1069
+ guardrails: Only cite files that were actually read in this run.
1070
+ modelProvider: ""
1071
+ modelId: ""
1072
+ toolAllowlist:
1073
+ - read
1074
+ - glob
1075
+ toolDenylist: []
1076
+ mcpAllowedServers: []
1077
+ - agentId: account-external
1078
+ displayName: Account External
1079
+ role: watcher
1080
+ avatarUrl: ""
1081
+ templateId: ""
1082
+ linkedTemplateId: ""
1083
+ skills:
1084
+ - account-research
1085
+ prompt:
1086
+ role: You are an external account researcher focused on current buying context and public signals.
1087
+ mission: Gather current public context that can strengthen or disprove likely personalization hooks before outreach is drafted.
1088
+ inputs: Use the upstream \`source_inventory\` and \`local_source_notes\` handoffs to guide targeted external account research.
1089
+ outputContract: Return a structured handoff with \`external_research_mode\`, \`queries_attempted\`, \`sources_reviewed\`, \`citations_external\`, and \`research_limitations\`.
1090
+ guardrails: Do not invent buying signals. If search is unavailable, capture that limitation explicitly.
1091
+ modelProvider: ""
1092
+ modelId: ""
1093
+ toolAllowlist:
1094
+ - read
1095
+ - websearch
1096
+ - webfetch
1097
+ - glob
1098
+ toolDenylist: []
1099
+ mcpAllowedServers: []
1100
+ - agentId: account-research
1101
+ displayName: Account Research
1102
+ role: watcher
1103
+ avatarUrl: ""
1104
+ templateId: ""
1105
+ linkedTemplateId: ""
1106
+ skills:
1107
+ - account-research
1108
+ prompt:
1109
+ role: You are an account researcher focused on finding real buying context and usable personalization hooks.
1110
+ mission: Turn the upstream source discovery, local account evidence, and external account research into the final account brief.
1111
+ inputs: Use the upstream \`source_inventory\`, \`local_source_notes\`, and \`external_research\` handoffs as the source of truth.
1112
+ outputContract: Produce a concise account brief with company context, likely priorities, buying signals, possible pain points, messaging angles, and high-confidence personalization hooks labeled by confidence.
1113
+ guardrails: Do not invent buying signals or pretend certainty. Separate observed facts from hypotheses and avoid re-running discovery or fresh web research in this stage.
1114
+ modelProvider: ""
1115
+ modelId: ""
1116
+ toolAllowlist:
1117
+ - read
1118
+ - glob
1119
+ toolDenylist: []
1120
+ mcpAllowedServers: []
1121
+ - agentId: outreach-writer
1122
+ displayName: Outreach Writer
1123
+ role: worker
1124
+ avatarUrl: ""
1125
+ templateId: ""
1126
+ linkedTemplateId: ""
1127
+ skills:
1128
+ - sales-copy
1129
+ prompt:
1130
+ role: You are an outbound copywriter who writes concise outreach anchored in relevance, not generic personalization theater.
1131
+ mission: Write outreach that connects the account context to a clear value hypothesis and a low-friction next step.
1132
+ inputs: Use the account brief, ICP, offer positioning, proof points, and any approved email or messaging guidelines.
1133
+ outputContract: Produce first-touch outreach with subject line, opening line, body, CTA, and one optional variant that tests a different angle or proof point.
1134
+ guardrails: Keep it personal, specific, and easy to reply to. Avoid generic hype, fake familiarity, and unsupported claims.
1135
+ modelProvider: ""
1136
+ modelId: ""
1137
+ toolAllowlist:
1138
+ - read
1139
+ - write
1140
+ - glob
1141
+ toolDenylist: []
1142
+ mcpAllowedServers: []
1143
+ - agentId: positioning-review
1144
+ displayName: Positioning Review
1145
+ role: reviewer
1146
+ avatarUrl: ""
1147
+ templateId: ""
1148
+ linkedTemplateId: ""
1149
+ skills:
1150
+ - message-review
1151
+ prompt:
1152
+ role: You are the outreach reviewer applying a quality and credibility check before anything is sent.
1153
+ mission: Review personalization, claims, tone, and CTA quality so outbound messages feel credible and worth replying to.
1154
+ inputs: Use the account brief, outreach draft, proof points, and any team messaging rules.
1155
+ outputContract: Approve or return revision notes focused on personalization quality, claim support, clarity, and CTA friction.
1156
+ guardrails: Reject fluff, weak personalization, false urgency, and unsupported claims. Prefer direct revision guidance over general criticism.
1157
+ modelProvider: ""
1158
+ modelId: ""
1159
+ toolAllowlist:
1160
+ - read
1161
+ - write
1162
+ - glob
1163
+ toolDenylist: []
1164
+ mcpAllowedServers: []
1165
+ - agentId: send-prep
1166
+ displayName: Send Prep
1167
+ role: committer
1168
+ avatarUrl: ""
1169
+ templateId: ""
1170
+ linkedTemplateId: ""
1171
+ skills:
1172
+ - ops
1173
+ prompt:
1174
+ role: You are the send-prep operator.
1175
+ mission: Prepare approved outreach for the outbound system or rep handoff.
1176
+ inputs: Use the approved message, account info, and sequencing metadata.
1177
+ outputContract: Produce a send-ready package with follow-up notes.
1178
+ guardrails: Do not alter approved claims without review.
1179
+ modelProvider: ""
1180
+ modelId: ""
1181
+ toolAllowlist:
1182
+ - read
1183
+ - write
1184
+ - glob
1185
+ toolDenylist: []
1186
+ mcpAllowedServers: []
1187
+ nodes:
1188
+ - nodeId: research-account-discover
1189
+ title: Discover Account Sources
1190
+ agentId: account-discover
1191
+ objective: Identify the source corpus that should guide account research.
1192
+ dependsOn: []
1193
+ inputRefs: []
1194
+ stageKind: research_discover
1195
+ outputKind: structured_json
1196
+ outputPath: ""
1197
+ taskKind: ""
1198
+ projectBacklogTasks: false
1199
+ backlogTaskId: ""
1200
+ repoRoot: ""
1201
+ writeScope: ""
1202
+ acceptanceCriteria: ""
1203
+ taskDependencies: ""
1204
+ verificationState: ""
1205
+ taskOwner: ""
1206
+ verificationCommand: ""
1207
+ - nodeId: research-account-local-sources
1208
+ title: Read Account Sources
1209
+ agentId: account-local-sources
1210
+ objective: Read the prioritized local account and ICP files before drafting the account brief.
1211
+ dependsOn:
1212
+ - research-account-discover
1213
+ inputRefs:
1214
+ - fromStepId: research-account-discover
1215
+ alias: source_inventory
1216
+ stageKind: research_local_sources
1217
+ outputKind: structured_json
1218
+ outputPath: ""
1219
+ taskKind: ""
1220
+ projectBacklogTasks: false
1221
+ backlogTaskId: ""
1222
+ repoRoot: ""
1223
+ writeScope: ""
1224
+ acceptanceCriteria: ""
1225
+ taskDependencies: ""
1226
+ verificationState: ""
1227
+ taskOwner: ""
1228
+ verificationCommand: ""
1229
+ - nodeId: research-account-external-research
1230
+ title: Research Account Externally
1231
+ agentId: account-external
1232
+ objective: Gather targeted external account context and buying signals to support the brief.
1233
+ dependsOn:
1234
+ - research-account-discover
1235
+ - research-account-local-sources
1236
+ inputRefs:
1237
+ - fromStepId: research-account-discover
1238
+ alias: source_inventory
1239
+ - fromStepId: research-account-local-sources
1240
+ alias: local_source_notes
1241
+ stageKind: research_external_sources
1242
+ outputKind: structured_json
1243
+ outputPath: ""
1244
+ taskKind: ""
1245
+ projectBacklogTasks: false
1246
+ backlogTaskId: ""
1247
+ repoRoot: ""
1248
+ writeScope: ""
1249
+ acceptanceCriteria: ""
1250
+ taskDependencies: ""
1251
+ verificationState: ""
1252
+ taskOwner: ""
1253
+ verificationCommand: ""
1254
+ - nodeId: research-account
1255
+ title: Research Account
1256
+ agentId: account-research
1257
+ objective: Prepare the final account brief from the staged discovery, local evidence, and external research.
1258
+ dependsOn:
1259
+ - research-account-discover
1260
+ - research-account-local-sources
1261
+ - research-account-external-research
1262
+ inputRefs:
1263
+ - fromStepId: research-account-discover
1264
+ alias: source_inventory
1265
+ - fromStepId: research-account-local-sources
1266
+ alias: local_source_notes
1267
+ - fromStepId: research-account-external-research
1268
+ alias: external_research
1269
+ stageKind: research_finalize
1270
+ outputKind: brief
1271
+ outputPath: ""
1272
+ taskKind: ""
1273
+ projectBacklogTasks: false
1274
+ backlogTaskId: ""
1275
+ repoRoot: ""
1276
+ writeScope: ""
1277
+ acceptanceCriteria: ""
1278
+ taskDependencies: ""
1279
+ verificationState: ""
1280
+ taskOwner: ""
1281
+ verificationCommand: ""
1282
+ - nodeId: draft-outreach
1283
+ title: Draft Outreach
1284
+ agentId: outreach-writer
1285
+ objective: Draft outbound outreach from the account brief.
1286
+ dependsOn:
1287
+ - research-account
1288
+ inputRefs:
1289
+ - fromStepId: research-account
1290
+ alias: account_brief
1291
+ outputKind: draft
1292
+ outputPath: ""
1293
+ taskKind: ""
1294
+ projectBacklogTasks: false
1295
+ backlogTaskId: ""
1296
+ repoRoot: ""
1297
+ writeScope: ""
1298
+ acceptanceCriteria: ""
1299
+ taskDependencies: ""
1300
+ verificationState: ""
1301
+ taskOwner: ""
1302
+ verificationCommand: ""
1303
+ - nodeId: review-outreach
1304
+ title: Review Outreach
1305
+ agentId: positioning-review
1306
+ objective: Review the outreach for fit, personalization, and quality.
1307
+ dependsOn:
1308
+ - draft-outreach
1309
+ inputRefs:
1310
+ - fromStepId: draft-outreach
1311
+ alias: outreach_draft
1312
+ outputKind: review
1313
+ outputPath: ""
1314
+ taskKind: ""
1315
+ projectBacklogTasks: false
1316
+ backlogTaskId: ""
1317
+ repoRoot: ""
1318
+ writeScope: ""
1319
+ acceptanceCriteria: ""
1320
+ taskDependencies: ""
1321
+ verificationState: ""
1322
+ taskOwner: ""
1323
+ verificationCommand: ""
1324
+ - nodeId: prepare-send
1325
+ title: Prepare Send
1326
+ agentId: send-prep
1327
+ objective: Prepare the approved outreach for the sending workflow.
1328
+ dependsOn:
1329
+ - review-outreach
1330
+ inputRefs:
1331
+ - fromStepId: review-outreach
1332
+ alias: approved_outreach
1333
+ outputKind: send_pack
1334
+ outputPath: ""
1335
+ taskKind: ""
1336
+ projectBacklogTasks: false
1337
+ backlogTaskId: ""
1338
+ repoRoot: ""
1339
+ writeScope: ""
1340
+ acceptanceCriteria: ""
1341
+ taskDependencies: ""
1342
+ verificationState: ""
1343
+ taskOwner: ""
1344
+ verificationCommand: ""
1345
+ `,"./templates/support-triage-team.yaml":`id: support-triage-team
1346
+ order: 4
1347
+ name: Support Triage Team
1348
+ icon: life-buoy
1349
+ summary: Classify support work, draft responses, review quality, and route action items.
1350
+ description: A support workflow for intake, response drafting, quality review, and escalation or publishing.
1351
+ suggestedOutputs:
1352
+ - triage-report.md
1353
+ - response-draft.md
1354
+ - escalation-summary.md
1355
+ agents:
1356
+ - agentId: intake
1357
+ displayName: Intake
1358
+ role: watcher
1359
+ avatarUrl: ""
1360
+ templateId: ""
1361
+ linkedTemplateId: ""
1362
+ skills:
1363
+ - triage
1364
+ prompt:
1365
+ role: You are the support intake analyst.
1366
+ mission: Classify incoming issues by severity, category, and owner.
1367
+ inputs: Use the support thread, customer metadata, and routing rules.
1368
+ outputContract: Produce a triage summary with next-step recommendations.
1369
+ guardrails: Escalate safety, billing, and security risks immediately.
1370
+ modelProvider: ""
1371
+ modelId: ""
1372
+ toolAllowlist:
1373
+ - read
1374
+ - glob
1375
+ toolDenylist: []
1376
+ mcpAllowedServers: []
1377
+ - agentId: responder
1378
+ displayName: Responder
1379
+ role: worker
1380
+ avatarUrl: ""
1381
+ templateId: ""
1382
+ linkedTemplateId: ""
1383
+ skills:
1384
+ - customer-support
1385
+ prompt:
1386
+ role: You are the support response drafter.
1387
+ mission: Draft a helpful, accurate customer-facing response.
1388
+ inputs: Use the triage result, product knowledge, and approved response patterns.
1389
+ outputContract: Produce a response draft and any internal notes required.
1390
+ guardrails: Do not promise unavailable fixes or timelines.
1391
+ modelProvider: ""
1392
+ modelId: ""
1393
+ toolAllowlist:
1394
+ - read
1395
+ - write
1396
+ - glob
1397
+ toolDenylist: []
1398
+ mcpAllowedServers: []
1399
+ - agentId: qa
1400
+ displayName: QA
1401
+ role: reviewer
1402
+ avatarUrl: ""
1403
+ templateId: ""
1404
+ linkedTemplateId: ""
1405
+ skills:
1406
+ - quality-review
1407
+ prompt:
1408
+ role: You are the support QA reviewer.
1409
+ mission: Check the drafted response for clarity, policy fit, and tone.
1410
+ inputs: Use the triage summary and drafted response.
1411
+ outputContract: Approve or provide concrete revision guidance.
1412
+ guardrails: Catch risky language, policy errors, and missing action items.
1413
+ modelProvider: ""
1414
+ modelId: ""
1415
+ toolAllowlist:
1416
+ - read
1417
+ - write
1418
+ - glob
1419
+ toolDenylist: []
1420
+ mcpAllowedServers: []
1421
+ - agentId: dispatcher
1422
+ displayName: Dispatcher
1423
+ role: committer
1424
+ avatarUrl: ""
1425
+ templateId: ""
1426
+ linkedTemplateId: ""
1427
+ skills:
1428
+ - operations
1429
+ prompt:
1430
+ role: You are the support dispatcher.
1431
+ mission: Finalize the response or route the case to the proper team.
1432
+ inputs: Use the QA-reviewed response and routing rules.
1433
+ outputContract: Prepare the final reply or escalation summary with correct owner.
1434
+ guardrails: Do not close unresolved escalations.
1435
+ modelProvider: ""
1436
+ modelId: ""
1437
+ toolAllowlist:
1438
+ - read
1439
+ - write
1440
+ - glob
1441
+ toolDenylist: []
1442
+ mcpAllowedServers: []
1443
+ nodes:
1444
+ - nodeId: triage-ticket
1445
+ title: Triage Ticket
1446
+ agentId: intake
1447
+ objective: Classify the issue and identify the right handling path.
1448
+ dependsOn: []
1449
+ inputRefs: []
1450
+ outputKind: triage
1451
+ outputPath: ""
1452
+ taskKind: ""
1453
+ projectBacklogTasks: false
1454
+ backlogTaskId: ""
1455
+ repoRoot: ""
1456
+ writeScope: ""
1457
+ acceptanceCriteria: ""
1458
+ taskDependencies: ""
1459
+ verificationState: ""
1460
+ taskOwner: ""
1461
+ verificationCommand: ""
1462
+ - nodeId: draft-response
1463
+ title: Draft Response
1464
+ agentId: responder
1465
+ objective: Draft the customer-facing response from the triage summary.
1466
+ dependsOn:
1467
+ - triage-ticket
1468
+ inputRefs:
1469
+ - fromStepId: triage-ticket
1470
+ alias: triage
1471
+ outputKind: draft
1472
+ outputPath: ""
1473
+ taskKind: ""
1474
+ projectBacklogTasks: false
1475
+ backlogTaskId: ""
1476
+ repoRoot: ""
1477
+ writeScope: ""
1478
+ acceptanceCriteria: ""
1479
+ taskDependencies: ""
1480
+ verificationState: ""
1481
+ taskOwner: ""
1482
+ verificationCommand: ""
1483
+ - nodeId: review-response
1484
+ title: Review Response
1485
+ agentId: qa
1486
+ objective: Review the response for quality and policy fit.
1487
+ dependsOn:
1488
+ - draft-response
1489
+ inputRefs:
1490
+ - fromStepId: draft-response
1491
+ alias: response_draft
1492
+ outputKind: review
1493
+ outputPath: ""
1494
+ taskKind: ""
1495
+ projectBacklogTasks: false
1496
+ backlogTaskId: ""
1497
+ repoRoot: ""
1498
+ writeScope: ""
1499
+ acceptanceCriteria: ""
1500
+ taskDependencies: ""
1501
+ verificationState: ""
1502
+ taskOwner: ""
1503
+ verificationCommand: ""
1504
+ - nodeId: route-case
1505
+ title: Route Case
1506
+ agentId: dispatcher
1507
+ objective: Finalize the approved response or route the case to an owner.
1508
+ dependsOn:
1509
+ - review-response
1510
+ inputRefs:
1511
+ - fromStepId: review-response
1512
+ alias: approved_response
1513
+ outputKind: dispatch
1514
+ outputPath: ""
1515
+ taskKind: ""
1516
+ projectBacklogTasks: false
1517
+ backlogTaskId: ""
1518
+ repoRoot: ""
1519
+ writeScope: ""
1520
+ acceptanceCriteria: ""
1521
+ taskDependencies: ""
1522
+ verificationState: ""
1523
+ taskOwner: ""
1524
+ verificationCommand: ""
1525
+ `,"./templates/weekly-newsletter-builder.yaml":`id: weekly-newsletter-builder
1526
+ order: 3
1527
+ name: Weekly Newsletter Builder
1528
+ icon: mail
1529
+ summary: Assemble a weekly newsletter from source updates, editorial drafting, and review.
1530
+ description: A newsletter production workflow that curates source material, drafts the issue, reviews it, and prepares a send-ready package.
1531
+ suggestedOutputs:
1532
+ - newsletter-outline.md
1533
+ - newsletter-draft.md
1534
+ - newsletter-final.md
1535
+ agents:
1536
+ - agentId: curator-discover
1537
+ displayName: Curator Discover
1538
+ role: watcher
1539
+ avatarUrl: ""
1540
+ templateId: ""
1541
+ linkedTemplateId: ""
1542
+ skills:
1543
+ - research
1544
+ prompt:
1545
+ role: You are a newsletter source scout.
1546
+ mission: Identify the local source corpus and candidate story files that should be reviewed before curation begins.
1547
+ inputs: Inspect prior issues, internal updates, source bundles, and audience context files to decide what deserves concrete reading next.
1548
+ outputContract: Return a structured handoff with \`workspace_inventory_summary\`, \`discovered_paths\`, \`priority_paths\`, and \`skipped_paths_initial\`.
1549
+ guardrails: Do not curate the final issue in this stage.
1550
+ modelProvider: ""
1551
+ modelId: ""
1552
+ toolAllowlist:
1553
+ - read
1554
+ - glob
1555
+ toolDenylist: []
1556
+ mcpAllowedServers: []
1557
+ - agentId: curator-local-sources
1558
+ displayName: Curator Local Sources
1559
+ role: watcher
1560
+ avatarUrl: ""
1561
+ templateId: ""
1562
+ linkedTemplateId: ""
1563
+ skills:
1564
+ - research
1565
+ - curation
1566
+ prompt:
1567
+ role: You are a local-source curator for the newsletter workflow.
1568
+ mission: Read the prioritized local updates and capture the strongest story candidates and supporting facts.
1569
+ inputs: Use the upstream \`source_inventory\` handoff to decide what to read and extract the facts that make each item worth including.
1570
+ outputContract: Return a structured handoff with \`read_paths\`, \`reviewed_facts\`, \`files_reviewed\`, \`files_not_reviewed\`, and \`citations_local\`.
1571
+ guardrails: Only elevate items that are supported by actual file reads in this run.
1572
+ modelProvider: ""
1573
+ modelId: ""
1574
+ toolAllowlist:
1575
+ - read
1576
+ - glob
1577
+ toolDenylist: []
1578
+ mcpAllowedServers: []
1579
+ - agentId: curator-external
1580
+ displayName: Curator External
1581
+ role: watcher
1582
+ avatarUrl: ""
1583
+ templateId: ""
1584
+ linkedTemplateId: ""
1585
+ skills:
1586
+ - research
1587
+ - curation
1588
+ prompt:
1589
+ role: You are an external-news analyst for newsletter curation.
1590
+ mission: Gather timely external signals that complement the local updates and help determine what belongs in this week’s issue.
1591
+ inputs: Use the upstream \`source_inventory\` and \`local_source_notes\` handoffs to guide targeted external searches and page fetches.
1592
+ outputContract: Return a structured handoff with \`external_research_mode\`, \`queries_attempted\`, \`sources_reviewed\`, \`citations_external\`, and \`research_limitations\`.
1593
+ guardrails: If search is unavailable, capture that limitation and continue with the evidence already gathered.
1594
+ modelProvider: ""
1595
+ modelId: ""
1596
+ toolAllowlist:
1597
+ - read
1598
+ - websearch
1599
+ - webfetch
1600
+ - glob
1601
+ toolDenylist: []
1602
+ mcpAllowedServers: []
1603
+ - agentId: curator
1604
+ displayName: Curator
1605
+ role: watcher
1606
+ avatarUrl: ""
1607
+ templateId: ""
1608
+ linkedTemplateId: ""
1609
+ skills:
1610
+ - curation
1611
+ prompt:
1612
+ role: You are a newsletter curator selecting stories and updates that deserve the audience's limited attention.
1613
+ mission: Choose the strongest mix of timely updates, useful insights, and product-relevant stories from the upstream evidence bundle.
1614
+ inputs: Use the upstream \`source_inventory\`, \`local_source_notes\`, and \`external_research\` handoffs. Turn them into the final curated shortlist and section order for the issue.
1615
+ outputContract: Produce a shortlist with item summaries, why each matters now, the intended audience takeaway, and a recommended section order for the issue.
1616
+ guardrails: Prefer relevance, freshness, and distinctiveness over volume. Do not redo discovery or fresh web research in this stage.
1617
+ modelProvider: ""
1618
+ modelId: ""
1619
+ toolAllowlist:
1620
+ - read
1621
+ - glob
1622
+ toolDenylist: []
1623
+ mcpAllowedServers: []
1624
+ - agentId: editor
1625
+ displayName: Editor
1626
+ role: worker
1627
+ avatarUrl: ""
1628
+ templateId: ""
1629
+ linkedTemplateId: ""
1630
+ skills:
1631
+ - writing
1632
+ - editing
1633
+ prompt:
1634
+ role: You are the newsletter editor responsible for turning curated inputs into a cohesive, highly readable issue.
1635
+ mission: Write a newsletter that feels timely, useful, and easy to scan while preserving a consistent editorial voice.
1636
+ inputs: Use the curated shortlist, publication tone guidance, prior issue patterns, and any desired structure or CTA rules.
1637
+ outputContract: Produce a full issue draft with subject line options, preview text, section transitions, concise commentary for each item, and a final CTA or reply prompt.
1638
+ guardrails: Keep the issue skimmable, specific, and audience-first. Avoid generic roundup filler, and make every section earn its place.
1639
+ modelProvider: ""
1640
+ modelId: ""
1641
+ toolAllowlist:
1642
+ - read
1643
+ - write
1644
+ - glob
1645
+ toolDenylist: []
1646
+ mcpAllowedServers: []
1647
+ - agentId: copy-review
1648
+ displayName: Copy Review
1649
+ role: reviewer
1650
+ avatarUrl: ""
1651
+ templateId: ""
1652
+ linkedTemplateId: ""
1653
+ skills:
1654
+ - fact-checking
1655
+ - copy-editing
1656
+ prompt:
1657
+ role: You are the newsletter reviewer applying a copy-edit and fact-check pass before send.
1658
+ mission: Review the issue for claim accuracy, clarity, formatting, consistency, and whether each section answers 'why should I care?'
1659
+ inputs: Use the draft, curation notes, proof sources, and any editorial or compliance guidance.
1660
+ outputContract: Approve or return exact edits needed before send, grouped by claims, flow, clarity, formatting, and CTA quality.
1661
+ guardrails: Catch broken references, vague claims, weak transitions, and unsupported statements. Do not let filler or overlong sections through.
1662
+ modelProvider: ""
1663
+ modelId: ""
1664
+ toolAllowlist:
1665
+ - read
1666
+ - write
1667
+ - glob
1668
+ toolDenylist: []
1669
+ mcpAllowedServers: []
1670
+ - agentId: publisher
1671
+ displayName: Publisher
1672
+ role: committer
1673
+ avatarUrl: ""
1674
+ templateId: ""
1675
+ linkedTemplateId: ""
1676
+ skills:
1677
+ - publishing
1678
+ prompt:
1679
+ role: You are the newsletter publishing operator responsible for final packaging and send readiness.
1680
+ mission: Prepare the approved issue for the ESP or publishing workflow with all required metadata and preflight checks complete.
1681
+ inputs: Use the approved newsletter draft, publish metadata, audience segment details, and delivery platform requirements.
1682
+ outputContract: Produce the final issue package, send checklist, subject and preview confirmation, and any handoff notes needed for scheduling.
1683
+ guardrails: Do not send unrevised drafts, and flag anything missing that could break layout, tracking, or links.
1684
+ modelProvider: ""
1685
+ modelId: ""
1686
+ toolAllowlist:
1687
+ - read
1688
+ - write
1689
+ - glob
1690
+ toolDenylist: []
1691
+ mcpAllowedServers: []
1692
+ nodes:
1693
+ - nodeId: curate-issue-discover
1694
+ title: Discover Issue Sources
1695
+ agentId: curator-discover
1696
+ objective: Identify the local source corpus and candidate files that should feed this week's issue.
1697
+ dependsOn: []
1698
+ inputRefs: []
1699
+ stageKind: research_discover
1700
+ outputKind: structured_json
1701
+ outputPath: ""
1702
+ taskKind: ""
1703
+ projectBacklogTasks: false
1704
+ backlogTaskId: ""
1705
+ repoRoot: ""
1706
+ writeScope: ""
1707
+ acceptanceCriteria: ""
1708
+ taskDependencies: ""
1709
+ verificationState: ""
1710
+ taskOwner: ""
1711
+ verificationCommand: ""
1712
+ - nodeId: curate-issue-local-sources
1713
+ title: Read Issue Sources
1714
+ agentId: curator-local-sources
1715
+ objective: Read the prioritized local source files and extract the strongest issue candidates.
1716
+ dependsOn:
1717
+ - curate-issue-discover
1718
+ inputRefs:
1719
+ - fromStepId: curate-issue-discover
1720
+ alias: source_inventory
1721
+ stageKind: research_local_sources
1722
+ outputKind: structured_json
1723
+ outputPath: ""
1724
+ taskKind: ""
1725
+ projectBacklogTasks: false
1726
+ backlogTaskId: ""
1727
+ repoRoot: ""
1728
+ writeScope: ""
1729
+ acceptanceCriteria: ""
1730
+ taskDependencies: ""
1731
+ verificationState: ""
1732
+ taskOwner: ""
1733
+ verificationCommand: ""
1734
+ - nodeId: curate-issue-external-research
1735
+ title: Research Issue
1736
+ agentId: curator-external
1737
+ objective: Gather timely external signals that should influence this week's issue.
1738
+ dependsOn:
1739
+ - curate-issue-discover
1740
+ - curate-issue-local-sources
1741
+ inputRefs:
1742
+ - fromStepId: curate-issue-discover
1743
+ alias: source_inventory
1744
+ - fromStepId: curate-issue-local-sources
1745
+ alias: local_source_notes
1746
+ stageKind: research_external_sources
1747
+ outputKind: structured_json
1748
+ outputPath: ""
1749
+ taskKind: ""
1750
+ projectBacklogTasks: false
1751
+ backlogTaskId: ""
1752
+ repoRoot: ""
1753
+ writeScope: ""
1754
+ acceptanceCriteria: ""
1755
+ taskDependencies: ""
1756
+ verificationState: ""
1757
+ taskOwner: ""
1758
+ verificationCommand: ""
1759
+ - nodeId: curate-issue
1760
+ title: Curate Issue
1761
+ agentId: curator
1762
+ objective: Curate the best items for this week's issue from the staged research handoffs.
1763
+ dependsOn:
1764
+ - curate-issue-discover
1765
+ - curate-issue-local-sources
1766
+ - curate-issue-external-research
1767
+ inputRefs:
1768
+ - fromStepId: curate-issue-discover
1769
+ alias: source_inventory
1770
+ - fromStepId: curate-issue-local-sources
1771
+ alias: local_source_notes
1772
+ - fromStepId: curate-issue-external-research
1773
+ alias: external_research
1774
+ stageKind: research_finalize
1775
+ outputKind: outline
1776
+ outputPath: ""
1777
+ taskKind: ""
1778
+ projectBacklogTasks: false
1779
+ backlogTaskId: ""
1780
+ repoRoot: ""
1781
+ writeScope: ""
1782
+ acceptanceCriteria: ""
1783
+ taskDependencies: ""
1784
+ verificationState: ""
1785
+ taskOwner: ""
1786
+ verificationCommand: ""
1787
+ - nodeId: draft-issue
1788
+ title: Draft Issue
1789
+ agentId: editor
1790
+ objective: Draft the newsletter issue from the curated outline.
1791
+ dependsOn:
1792
+ - curate-issue
1793
+ inputRefs:
1794
+ - fromStepId: curate-issue
1795
+ alias: outline
1796
+ outputKind: draft
1797
+ outputPath: ""
1798
+ taskKind: ""
1799
+ projectBacklogTasks: false
1800
+ backlogTaskId: ""
1801
+ repoRoot: ""
1802
+ writeScope: ""
1803
+ acceptanceCriteria: ""
1804
+ taskDependencies: ""
1805
+ verificationState: ""
1806
+ taskOwner: ""
1807
+ verificationCommand: ""
1808
+ - nodeId: review-issue
1809
+ title: Review Issue
1810
+ agentId: copy-review
1811
+ objective: Review the newsletter draft before distribution.
1812
+ dependsOn:
1813
+ - draft-issue
1814
+ inputRefs:
1815
+ - fromStepId: draft-issue
1816
+ alias: draft
1817
+ outputKind: review
1818
+ outputPath: ""
1819
+ taskKind: ""
1820
+ projectBacklogTasks: false
1821
+ backlogTaskId: ""
1822
+ repoRoot: ""
1823
+ writeScope: ""
1824
+ acceptanceCriteria: ""
1825
+ taskDependencies: ""
1826
+ verificationState: ""
1827
+ taskOwner: ""
1828
+ verificationCommand: ""
1829
+ - nodeId: publish-issue
1830
+ title: Publish Issue
1831
+ agentId: publisher
1832
+ objective: Prepare the issue for the sending platform and final approval.
1833
+ dependsOn:
1834
+ - review-issue
1835
+ inputRefs:
1836
+ - fromStepId: review-issue
1837
+ alias: approved_issue
1838
+ outputKind: publish
1839
+ outputPath: ""
1840
+ taskKind: ""
1841
+ projectBacklogTasks: false
1842
+ backlogTaskId: ""
1843
+ repoRoot: ""
1844
+ writeScope: ""
1845
+ acceptanceCriteria: ""
1846
+ taskDependencies: ""
1847
+ verificationState: ""
1848
+ taskOwner: ""
1849
+ verificationCommand: ""
1850
+ `});function b(e,t){let n=s.parse(e);if(!n||typeof n!=`object`)throw Error(`Invalid studio template at `+t+`: expected a YAML object.`);let r=n,i=String(r.id||``).trim(),a=String(r.name||``).trim(),o=String(r.icon||``).trim(),c=String(r.summary||``).trim(),l=String(r.description||``).trim(),u=Number(r.order),d=r.suggestedOutputs,f=r.agents,p=r.nodes;if(!i)throw Error(`Invalid studio template at `+t+`: missing id.`);if(!a)throw Error(`Invalid studio template at `+t+`: missing name.`);if(!o)throw Error(`Invalid studio template at `+t+`: missing icon.`);if(!c)throw Error(`Invalid studio template at `+t+`: missing summary.`);if(!l)throw Error(`Invalid studio template at `+t+`: missing description.`);if(Number.isNaN(u))throw Error(`Invalid studio template at `+t+`: order must be a number.`);if(!Array.isArray(d))throw Error(`Invalid studio template at `+t+`: suggestedOutputs must be an array.`);if(!Array.isArray(f))throw Error(`Invalid studio template at `+t+`: agents must be an array.`);if(!Array.isArray(p))throw Error(`Invalid studio template at `+t+`: nodes must be an array.`);return{id:i,name:a,icon:o,summary:c,description:l,order:u,suggestedOutputs:d,agents:f,nodes:p}}var x=Object.entries(y).map(([e,t])=>b(t,e)).sort((e,t)=>{let n=Number.isFinite(e.order)?Number(e.order):2**53-1,r=Number.isFinite(t.order)?Number(t.order):2**53-1;return n===r?e.name.localeCompare(t.name,void 0,{sensitivity:`base`}):n-r});function S(e,t=``){return{automationId:``,starterTemplateId:e.id,name:e.name,description:e.description,summary:e.summary,icon:e.icon,workspaceRoot:t,status:`draft`,scheduleType:`manual`,cronExpression:``,intervalSeconds:`3600`,maxParallelAgents:`1`,useSharedModel:!1,sharedModelProvider:``,sharedModelId:``,outputTargets:[...e.suggestedOutputs],agents:e.agents.map(e=>({...e,skills:[...e.skills],toolAllowlist:[...e.toolAllowlist],toolDenylist:[...e.toolDenylist],mcpAllowedServers:[...e.mcpAllowedServers],mcpAllowedTools:Array.isArray(e.mcpAllowedTools)?[...e.mcpAllowedTools]:null,mcpOtherAllowedTools:Array.isArray(e.mcpOtherAllowedTools)?[...e.mcpOtherAllowedTools]:[],prompt:{...e.prompt}})),nodes:e.nodes.map(e=>({...e,dependsOn:[...e.dependsOn],inputRefs:e.inputRefs.map(e=>({...e}))}))}}function C(e={}){return{role:``,mission:``,inputs:``,outputContract:``,guardrails:``,...e}}function ee(e,t,n={}){return{agentId:e,displayName:t,role:`worker`,avatarUrl:``,templateId:``,linkedTemplateId:``,skills:[],prompt:C(),modelProvider:``,modelId:``,toolAllowlist:[`read`,`write`,`glob`],toolDenylist:[],mcpAllowedServers:[],mcpAllowedTools:null,mcpOtherAllowedTools:[],...n}}function te(e,t,n,r=[],i=[],a={}){return{nodeId:e,title:t,agentId:n,objective:``,dependsOn:[...r],inputRefs:i.map(e=>({...e})),inputFiles:[],outputKind:`artifact`,outputPath:``,outputFiles:[],taskKind:``,projectBacklogTasks:!1,backlogTaskId:``,repoRoot:``,writeScope:``,acceptanceCriteria:``,taskDependencies:``,verificationState:``,taskOwner:``,verificationCommand:``,toolAccessMode:`inherit`,toolAllowlist:[],toolDenylist:[],mcpAllowedServers:[],mcpAllowedTools:null,mcpOtherAllowedTools:[],...a}}var ne=[`worker`,`reviewer`,`tester`,`watcher`,`delegator`,`committer`,`orchestrator`],re=`tandem.automations.studioHandoff`,w=`tandem.studio.agentCatalogHandoff`;function ie(e,t){return Array.isArray(e)?e:Array.isArray(e?.[t])?e[t]:[]}function T(e){return String(e||``).trim()}function ae(e){let t=T(e);return ne.includes(t)?t:`worker`}function oe(e){return ee(e.agentId,e.displayName,{role:ae(e.role),prompt:C({role:`${e.displayName} (${e.categoryTitle})`,mission:e.instructions,inputs:[`Source path: ${e.sourcePath}`,`Category: ${e.categoryTitle}`,`Sandbox: ${e.sandboxMode}`,e.tags.length?`Tags: ${e.tags.join(`, `)}`:``,e.requires.length?`Requires: ${e.requires.join(`, `)}`:``].filter(Boolean).join(`
1851
+ `),outputContract:`Use this catalog specialization to complete the selected workflow stage clearly and concretely.`,guardrails:`Keep the stage scoped to the imported catalog instructions and preserve the workflow's existing conventions.`})})}function E(e){let t=T(e).toLowerCase(),n=t.includes(`.`)&&t.split(`.`).pop()||``;return[`rs`,`ts`,`tsx`,`js`,`jsx`,`py`,`go`,`java`,`kt`,`kts`,`c`,`cc`,`cpp`,`h`,`hpp`,`cs`,`rb`,`php`,`swift`,`scala`,`sh`,`bash`,`zsh`].includes(n)}function D(e){let t=T(e).toLowerCase();return t.includes(`.`)&&t.split(`.`).pop()||``}function O(e){let t=T(e).toLowerCase();return t===`code_change`||t===`repo_fix`||t===`implementation`}function k(e){return!!(e.projectBacklogTasks||T(e.repoRoot)||T(e.writeScope)||T(e.verificationCommand))}function se(e){let t=D(e.outputPath);return t===`md`||t===`markdown`?`report_markdown`:t===`json`?`structured_json`:t===`txt`?`text_summary`:`artifact`}function A(e){let t=O(e.taskKind||``)&&!E(e.outputPath)&&!k(e),n=T(e.outputKind).toLowerCase()===`code_patch`&&!E(e.outputPath)&&!k(e);return!t&&!n?e:{...e,taskKind:t?``:e.taskKind,outputKind:n?se(e):e.outputKind}}function ce(e){let t=A(e);return O(T(t.taskKind).toLowerCase())||T(t.outputKind).toLowerCase()===`code_patch`||E(t.outputPath)}function le(e){return!!e.projectBacklogTasks}function j(e){let t=e.map(e=>T(e)).filter(Boolean);return t.includes(`*`)?[`*`]:Array.from(new Set(t))}function ue(e,t){let n=j(e);if(n.includes(`*`))return[`*`];let r=t.some(e=>ce(e))?[`read`,`glob`,`edit`,`apply_patch`,`write`,`bash`]:[];return Array.from(new Set([...n,...r]))}function de(e){let t=T(e);return t?t.length<=18?t:`${t.slice(0,8)}...${t.slice(-6)}`:``}function fe(e){let t=Number(e||0);if(!t)return``;try{return new Intl.DateTimeFormat(void 0,{year:`numeric`,month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`}).format(new Date(t))}catch{return``}}function M(e){return String(e||``).split(`,`).map(e=>e.trim()).filter(Boolean)}function N(e){return Array.isArray(e)?e.join(`, `):``}var pe=[`{current_date}`,`{current_time}`,`{current_timestamp}`,`{current_timestamp_filename}`];function P(e=new Date){let t=e=>String(e).padStart(2,`0`),n=e.getFullYear(),r=t(e.getMonth()+1),i=t(e.getDate()),a=t(e.getHours()),o=t(e.getMinutes()),s=t(e.getSeconds());return{current_date:`${n}-${r}-${i}`,current_time:`${a}${o}`,current_timestamp:`${n}-${r}-${i} ${a}:${o}`,current_timestamp_filename:`${n}-${r}-${i}_${a}-${o}-${s}`}}function F(e){let t=T(e);if(!t)return``;let n=t;return[[`{{current_timestamp_filename}}`,`{current_timestamp_filename}`],[`{{current_date}}`,`{current_date}`],[`{{current_time}}`,`{current_time}`],[`{{current_timestamp}}`,`{current_timestamp}`],[`{{date}}`,`{current_date}`],[`{date}`,`{current_date}`],[`YYYY-MM-DD_HH-MM-SS`,`{current_timestamp_filename}`],[`YYYY-MM-DD-HH-MM-SS`,`{current_timestamp_filename}`],[`YYYY-MM-DD_HHMMSS`,`{current_timestamp_filename}`],[`YYYY-MM-DD-HHMMSS`,`{current_timestamp_filename}`],[`YYYY-MM-DD_HHMM`,`{current_date}_{current_time}`],[`YYYY-MM-DD-HHMM`,`{current_date}-{current_time}`],[`YYYY-MM-DD`,`{current_date}`]].forEach(([e,t])=>{n=n.split(e).join(t)}),n.includes(`HHMMSS`)||(n=n.split(`HHMM`).join(`{current_time}`)),n}function me(e,t=new Date){let n=F(e),r=P(t);return n.split(`{current_timestamp_filename}`).join(r.current_timestamp_filename).split(`{current_timestamp}`).join(r.current_timestamp).split(`{current_date}`).join(r.current_date).split(`{current_time}`).join(r.current_time)}function he(e){let t=F(e);if(!t)return``;let n=Array.from(new Set((t.match(/\{[^}]+\}/g)||[]).filter(e=>!pe.includes(e))));return n.length?`Unknown output token${n.length===1?``:`s`}: ${n.join(`, `)}`:/(YYYY|YYYYMMDD|HHMMSS|HH-MM-SS|HH-MM|HH:MM|\{\{date\}\}|\{date\})/.test(t)?`This path still contains legacy timestamp text Tandem cannot safely canonicalize on save.`:``}function I(e){return{...e,outputPath:F(e.outputPath),outputFiles:L(e.outputFiles).map(F)}}function ge(e){return{...e,outputTargets:L(e.outputTargets).map(F),nodes:e.nodes.map(I)}}function _e(e){let t=[];return e.outputTargets.forEach(e=>{let n=he(e);n&&t.push(`Workflow target ${T(e)}: ${n}`)}),e.nodes.forEach(e=>{let n=T(e.outputPath);if(!n)return;let r=he(n);r&&t.push(`${T(e.title)||T(e.nodeId)}: ${r}`)}),t}function L(e){return Array.isArray(e)?e.map(e=>T(e)).filter(Boolean).filter((e,t,n)=>n.indexOf(e)===t):[]}function ve(e){let t=L(e.outputFiles);if(t.length)return t;let n=T(e.outputPath);return n?[n]:[]}function ye(e,t){let n=L(e.inputFiles);if(n.length)return n;let r=new Map(t.map(e=>[T(e.nodeId),e]));return L(V(e.dependsOn,e.inputRefs).flatMap(e=>{let t=r.get(T(e.fromStepId));return t?ve(t):[]}))}function be(e){return String(e||``).trim().toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,64)}function R(e,t){return be(e)||t}function xe(e){let t=T(e);return t?t.startsWith(`/`)?``:`Workspace root must be an absolute path.`:`Workspace root is required.`}function Se(e){try{sessionStorage.setItem(re,JSON.stringify(e))}catch{}}function Ce(e){return[[`Role`,e.role],[`Mission`,e.mission],[`Inputs`,e.inputs],[`Output Contract`,e.outputContract],[`Guardrails`,e.guardrails]].filter(([,e])=>T(e)).map(([e,t])=>`${e}:\n${String(t).trim()}`).join(`
1852
+
1853
+ `)}function we(e){if(!(!T(e.modelProvider)||!T(e.modelId)))return{default_model:{provider_id:T(e.modelProvider),model_id:T(e.modelId)}}}function Te(e,t){let n=T(t?.default),r=e.find(e=>e.id===n)?.id||e[0]?.id||``;if(!r)return{provider:``,model:``};let i=e.find(e=>e.id===r)?.models||[];return{provider:r,model:T(t?.providers?.[r]?.default_model||i[0])}}function z(e,t){return e.find(e=>e.id===t)?.models||[]}function B(e,t){return!t.provider||!t.model?e:e.map(e=>T(e.modelProvider)&&T(e.modelId)?e:{...e,modelProvider:T(e.modelProvider)||t.provider,modelId:T(e.modelId)||t.model})}function Ee(e){let t=e.map(e=>({provider:T(e.modelProvider),model:T(e.modelId)})).filter(e=>e.provider&&e.model);if(!t.length)return{useSharedModel:!1,provider:``,model:``};let n=t[0],r=t.every(e=>e.provider===n.provider&&e.model===n.model);return{useSharedModel:r,provider:r?n.provider:``,model:r?n.model:``}}function De(e,t,n){let r=T(t),i=T(n);return!r||!i?e:e.map(e=>({...e,modelProvider:r,modelId:i}))}function Oe(e){let t={type:`run_once`};return e.scheduleType===`cron`&&T(e.cronExpression)?{type:`cron`,cron_expression:T(e.cronExpression),timezone:`UTC`,misfire_policy:t}:e.scheduleType===`interval`?{type:`interval`,interval_seconds:Math.max(60,Number.parseInt(String(e.intervalSeconds||`3600`),10)||3600),timezone:`UTC`,misfire_policy:t}:{type:`manual`,timezone:`UTC`,misfire_policy:t}}function ke(e){return Array.isArray(e?.servers)?e.servers.map(e=>T(e?.name)).filter(Boolean).sort((e,t)=>e.localeCompare(t)):Object.keys(e||{}).map(e=>T(e)).filter(Boolean).sort((e,t)=>e.localeCompare(t))}function Ae(e){let t=e?.default_model||e?.defaultModel||{},n=(Array.isArray(e?.skills)?e.skills:[]).map(e=>T(typeof e==`string`?e:e?.skill_id||e?.skillId||e?.id||e?.name)).filter(Boolean);return{templateId:T(e?.template_id||e?.templateID||e?.id),displayName:T(e?.display_name||e?.displayName||e?.name),avatarUrl:T(e?.avatar_url||e?.avatarUrl),role:T(e?.role||`worker`)||`worker`,systemPrompt:T(e?.system_prompt||e?.systemPrompt),modelProvider:T(t?.provider_id||t?.providerId),modelId:T(t?.model_id||t?.modelId),skills:n}}function je(e){return{role:``,mission:T(e),inputs:``,outputContract:``,guardrails:``}}function V(e,t){return e.map(e=>t.find(t=>t.fromStepId===e)||{fromStepId:e,alias:e.replace(/-/g,`_`)})}function Me(e){let t=new Map(e.map(e=>[e.nodeId,e])),n=new Map,r=(e,i=new Set)=>{if(n.has(e))return Number(n.get(e)||0);if(i.has(e))return 0;let a=t.get(e);if(!a||!a.dependsOn.length)return n.set(e,0),0;let o=new Set(i);o.add(e);let s=Math.max(...a.dependsOn.map(e=>r(e,o)))+1;return n.set(e,s),s};for(let t of e)r(t.nodeId);return n}function Ne(e){let t=Array.isArray(e?.mcpAllowedTools||e?.mcp_allowed_tools),n=Array.isArray(e?.mcpOtherAllowedTools||e?.mcp_other_allowed_tools),r=g(t?e.mcpAllowedTools||e.mcp_allowed_tools:Array.isArray(e?.mcp_policy?.allowed_tools)?e.mcp_policy.allowed_tools:Array.isArray(e?.mcpPolicy?.allowedTools)?e.mcpPolicy.allowedTools:[]),i=t?(e.mcpAllowedTools||e.mcp_allowed_tools).map(e=>T(e)).filter(Boolean):r.mcpTools,a=n?(e.mcpOtherAllowedTools||e.mcp_other_allowed_tools).map(e=>T(e)).filter(Boolean):r.otherTools;return{agentId:T(e?.agentId||e?.agent_id||e?.id),displayName:T(e?.displayName||e?.display_name||e?.name),role:T(e?.role||`worker`)||`worker`,avatarUrl:T(e?.avatarUrl||e?.avatar_url),templateId:T(e?.templateId||e?.template_id),linkedTemplateId:T(e?.linkedTemplateId||e?.linked_template_id||e?.templateId||e?.template_id),skills:Array.isArray(e?.skills)?e.skills.map(e=>T(e)).filter(Boolean):[],prompt:e?.prompt&&typeof e.prompt==`object`?{role:T(e.prompt.role),mission:T(e.prompt.mission),inputs:T(e.prompt.inputs),outputContract:T(e.prompt.outputContract||e.prompt.output_contract),guardrails:T(e.prompt.guardrails)}:je(T(e?.systemPrompt||e?.system_prompt)),modelProvider:T(e?.modelProvider||e?.model_provider),modelId:T(e?.modelId||e?.model_id),toolAllowlist:j(Array.isArray(e?.toolAllowlist||e?.tool_allowlist)?(e.toolAllowlist||e.tool_allowlist).map(e=>T(e)).filter(Boolean):Array.isArray(e?.tool_policy?.allowlist)?e.tool_policy.allowlist.map(e=>T(e)).filter(Boolean):[]),toolDenylist:Array.isArray(e?.toolDenylist||e?.tool_denylist)?(e.toolDenylist||e.tool_denylist).map(e=>T(e)).filter(Boolean):Array.isArray(e?.tool_policy?.denylist)?e.tool_policy.denylist.map(e=>T(e)).filter(Boolean):[],mcpAllowedServers:Array.isArray(e?.mcpAllowedServers||e?.mcp_allowed_servers)?(e.mcpAllowedServers||e.mcp_allowed_servers).map(e=>T(e)).filter(Boolean):Array.isArray(e?.mcp_policy?.allowed_servers)?e.mcp_policy.allowed_servers.map(e=>T(e)).filter(Boolean):[],mcpAllowedTools:t||i.length?i:null,mcpOtherAllowedTools:a}}function Pe(e){let t=Array.isArray(e?.dependsOn||e?.depends_on)?(e.dependsOn||e.depends_on).map(e=>T(e)).filter(Boolean):[],n=Array.isArray(e?.inputRefs||e?.input_refs)?e.inputRefs||e.input_refs:[],r=e?.metadata?.builder&&typeof e.metadata.builder==`object`?e.metadata.builder:{},i=e?.tool_policy&&typeof e.tool_policy==`object`?!0:!!(e?.toolPolicy&&typeof e.toolPolicy==`object`),a=e?.mcp_policy&&typeof e.mcp_policy==`object`?!0:!!(e?.mcpPolicy&&typeof e.mcpPolicy==`object`),o=Array.isArray(e?.metadata?.tool_allowlist)?e.metadata.tool_allowlist.map(e=>T(e)).filter(Boolean):[],s=j(i?Array.isArray(e?.tool_policy?.allowlist||e?.toolPolicy?.allowlist)?(e.tool_policy?.allowlist||e.toolPolicy?.allowlist).map(e=>T(e)).filter(Boolean):[]:o),c=i?j(Array.isArray(e?.tool_policy?.denylist||e?.toolPolicy?.denylist)?(e.tool_policy?.denylist||e.toolPolicy?.denylist).map(e=>T(e)).filter(Boolean):[]):[],l=a?j(Array.isArray(e?.mcp_policy?.allowed_servers||e?.mcpPolicy?.allowedServers)?(e.mcp_policy?.allowed_servers||e.mcpPolicy?.allowedServers).map(e=>T(e)).filter(Boolean):[]):[],u=a?e?.mcp_policy?.allowed_tools??e?.mcpPolicy?.allowedTools:s,d=g(Array.isArray(u)?u:[]);return A({nodeId:T(e?.nodeId||e?.node_id||e?.id),title:T(e?.title||e?.objective||e?.nodeId||e?.node_id),agentId:T(e?.agentId||e?.agent_id),objective:T(e?.objective),dependsOn:t,inputRefs:V(t,n.map(e=>({fromStepId:T(e?.fromStepId||e?.from_step_id),alias:T(e?.alias)}))),stageKind:T(e?.stageKind||e?.stage_kind||r?.research_stage||e?.metadata?.studio?.research_stage),inputFiles:L(e?.inputFiles||e?.input_files||r?.input_files||e?.metadata?.studio?.input_files),outputKind:T(e?.outputKind||e?.output_kind||e?.output_contract?.kind||`artifact`),outputPath:T(e?.outputPath||e?.output_path||r?.output_path||e?.metadata?.studio?.output_path),outputFiles:L(e?.outputFiles||e?.output_files||r?.output_files||e?.metadata?.studio?.output_files),taskKind:T(e?.taskKind||e?.task_kind||r?.task_kind),projectBacklogTasks:!!(e?.projectBacklogTasks||e?.project_backlog_tasks||r?.project_backlog_tasks),backlogTaskId:T(e?.backlogTaskId||e?.backlog_task_id||r?.task_id),repoRoot:T(e?.repoRoot||e?.repo_root||r?.repo_root),writeScope:T(e?.writeScope||e?.write_scope||r?.write_scope),acceptanceCriteria:T(e?.acceptanceCriteria||e?.acceptance_criteria||r?.acceptance_criteria),taskDependencies:T(e?.taskDependencies||e?.task_dependencies||r?.task_dependencies),verificationState:T(e?.verificationState||e?.verification_state||r?.verification_state),taskOwner:T(e?.taskOwner||e?.task_owner||r?.task_owner),verificationCommand:T(e?.verificationCommand||e?.verification_command||r?.verification_command),toolAccessMode:i||a||o.length?`custom`:`inherit`,toolAllowlist:s,toolDenylist:c,mcpAllowedServers:l,mcpAllowedTools:a&&u==null?null:d.mcpTools.length?d.mcpTools:a?[]:null,mcpOtherAllowedTools:d.otherTools})}function Fe(e,t){let n=ce(e),r=t.toolAllowlist.includes(`glob`),i=t.toolAllowlist.includes(`read`),a=t.toolAllowlist.includes(`edit`)||n,o=t.toolAllowlist.includes(`apply_patch`)||n,s=t.toolAllowlist.includes(`bash`);return[T(e.objective),T(t.prompt.mission),T(t.prompt.inputs),T(t.prompt.outputContract),T(t.prompt.guardrails),T(e.taskKind)?`Task kind: ${T(e.taskKind)}.`:``,le(e)?"Project backlog tasks for this run. Include a fenced `json` block containing either an array of tasks or an object with `backlog_tasks`, where each task includes `task_id`, `title`, `description`, `repo_root`, `write_scope`, `acceptance_criteria`, `task_dependencies`, `verification_state`, `task_owner`, and `verification_command` when known.":``,T(e.backlogTaskId)?`Backlog task id: ${T(e.backlogTaskId)}.`:``,T(e.repoRoot)?`Repository root for this task: ${T(e.repoRoot)}.`:``,T(e.writeScope)?`Declared write scope: ${T(e.writeScope)}.`:``,T(e.acceptanceCriteria)?`Acceptance criteria: ${T(e.acceptanceCriteria)}.`:``,T(e.taskDependencies)?`Backlog task dependencies: ${T(e.taskDependencies)}.`:``,T(e.verificationState)?`Expected verification state progression: ${T(e.verificationState)}.`:``,T(e.taskOwner)?`Preferred task owner or claimer: ${T(e.taskOwner)}.`:``,T(e.verificationCommand)?`Expected verification command or rule: ${T(e.verificationCommand)}.`:``,e.inputFiles.length?`Declared input files: ${N(e.inputFiles)}.`:``,e.outputFiles.length?`Declared output files: ${N(e.outputFiles)}.`:``,`Execution rules:`,r||i?`- Inspect the workspace before writing using ${[r?"`glob`":``,i?"`read`":``].filter(Boolean).join(` and `)}.`:``,r?"- Use `glob` to enumerate directories or discover candidate file paths.":``,i?"- Use `read` only for concrete file paths you have already identified.":``,"- Use workspace-relative paths like `README.md` or `subdir/file.md`. Do not use a `/workspace/...` prefix.",t.toolAllowlist.includes(`websearch`)?"- Use `websearch` to gather current external evidence before finalizing the file.":``,e.stageKind===`research_discover`?"- After `glob` discovery, perform at least one concrete `read` on a prioritized source index or representative workspace file before completing this stage.":``,e.stageKind&&!T(e.outputPath)?`- Do not write final workspace artifacts in this stage. Return a structured handoff in your final response instead.`:``,n&&o?"- Prefer `apply_patch` for multi-line source edits when a git-backed patch tool is available.":``,n&&a?"- Prefer `edit` for existing-file source changes; use `write` only for new files or when patch/edit cannot express the change.":T(e.outputPath)?`- Create or update \`${T(e.outputPath)}\` in the workspace with the \`write\` tool.`:"- If this stage creates a file, use the `write` tool rather than a prose-only response.",n&&s?"- Use `bash` for repo-appropriate build, test, or lint commands after editing, and report the exact commands run.":``,n?`- Do not replace an existing source file with a status note, placeholder, or preservation summary.`:``,e.stageKind&&!T(e.outputPath)?`- Do not claim success unless the required structured handoff was actually returned in the final response.`:T(e.outputPath)?`- Do not claim success unless \`${T(e.outputPath)}\` was actually written.`:`- Do not claim success unless the required artifact was actually created.`].filter(Boolean).join(`
1854
+ `)}function Ie(e,t,n){let r=x.find(t=>t.id===e);return r&&S(r,n||``).agents.find(e=>e.agentId===t)||null}function Le(e,t){let n=[],r=[],i=e.nodes.map(e=>e.agentId).filter((t,n,r)=>!!t&&r.indexOf(t)===n&&!e.agents.some(e=>e.agentId===t)),a=e.agents.map(i=>{let a=T(i.linkedTemplateId||i.templateId);if(!a||t.has(a))return i;let o=Ie(e.starterTemplateId,i.agentId,e.workspaceRoot);return n.push(i.agentId),r.push(a),{...i,templateId:``,linkedTemplateId:``,prompt:Ce(i.prompt)?i.prompt:o?.prompt||i.prompt,role:T(i.role)?i.role:o?.role||`worker`,skills:i.skills.length?i.skills:o?.skills||[],toolAllowlist:j(i.toolAllowlist.length?i.toolAllowlist:o?.toolAllowlist||[`read`,`write`,`glob`]),toolDenylist:i.toolDenylist.length?i.toolDenylist:o?.toolDenylist||[],mcpAllowedServers:i.mcpAllowedServers.length?i.mcpAllowedServers:o?.mcpAllowedServers||[],mcpAllowedTools:i.mcpAllowedTools!==null&&Array.isArray(i.mcpAllowedTools)?i.mcpAllowedTools:o?.mcpAllowedTools??null,mcpOtherAllowedTools:i.mcpOtherAllowedTools.length?i.mcpOtherAllowedTools:o?.mcpOtherAllowedTools||[],modelProvider:T(i.modelProvider)||o?.modelProvider||``,modelId:T(i.modelId)||o?.modelId||``,avatarUrl:T(i.avatarUrl)||o?.avatarUrl||``,displayName:T(i.displayName)||o?.displayName||i.agentId}});return!n.length&&!i.length?{draft:e,repairState:null}:{draft:{...e,agents:a},repairState:{repairedAgentIds:n,repairedTemplateIds:r,missingNodeAgentIds:i,reason:`load`,requiresSave:n.length>0}}}function Re(e,t){let n=(Array.isArray(e?.agents)?e.agents:[]).map(e=>({agentId:T(e?.agent_id||e?.agentId),templateId:T(e?.template_id||e?.templateId)})).filter(e=>e.templateId&&!t.has(e.templateId));return{missingTemplateLinks:n,isBroken:n.length>0}}function ze(e,t){let n=[],r=xe(e.workspaceRoot);r&&n.push(r),T(e.name)||n.push(`Workflow name is required.`),e.agents.length||n.push(`Add at least one agent.`),e.nodes.length||n.push(`Add at least one stage.`);let i=e.nodes.map(e=>e.agentId).filter((t,n,r)=>!!t&&r.indexOf(t)===n&&!e.agents.some(e=>e.agentId===t));return i.length&&n.push(`Stages reference missing agents: ${i.join(`, `)}.`),{errors:n,missingNodeAgentIds:i,brokenAgentLinks:e.agents.map(e=>({agentId:e.agentId,templateId:T(e.linkedTemplateId||e.templateId)})).filter(e=>e.templateId&&!t.has(e.templateId))}}function Be(e,t,n){let r=e?.metadata&&typeof e.metadata==`object`?e.metadata:{},i=r?.studio&&typeof r.studio==`object`?r.studio:{},a=i?.workflow&&typeof i.workflow==`object`?i.workflow:{},o=T(i?.template_id||i?.templateId),s=Array.isArray(i?.agent_drafts)?i.agent_drafts.map(Ne):[],c=Array.isArray(i?.node_drafts)?i.node_drafts.map(Pe):[],l=Array.isArray(e?.agents)?e.agents.map(i=>{let a=T(i?.template_id||i?.templateId),s=a?n.get(a):null,c=g(Array.isArray(i?.mcp_policy?.allowed_tools)?i.mcp_policy.allowed_tools:Array.isArray(i?.mcpPolicy?.allowedTools)?i.mcpPolicy.allowedTools:[]),l=!s&&o?Ie(o,T(i?.agent_id||i?.agentId),T(e?.workspace_root||e?.workspaceRoot||r?.workspace_root||t)):null;return Ne({agentId:i?.agent_id||i?.agentId,displayName:i?.display_name||i?.displayName||l?.displayName||i?.agent_id||i?.agentId,role:s?.role||l?.role||`worker`,templateId:a,linkedTemplateId:a,skills:Array.isArray(i?.skills)?i.skills:s?.skills||l?.skills||[],prompt:s?.systemPrompt?je(s.systemPrompt):l?.prompt,modelProvider:i?.model_policy?.default_model?.provider_id||i?.modelPolicy?.defaultModel?.providerId||l?.modelProvider||s?.modelProvider||``,modelId:i?.model_policy?.default_model?.model_id||i?.modelPolicy?.defaultModel?.modelId||l?.modelId||s?.modelId||``,toolAllowlist:i?.tool_policy?.allowlist||i?.toolPolicy?.allowlist||[],toolDenylist:i?.tool_policy?.denylist||i?.toolPolicy?.denylist||[],mcpAllowedServers:i?.mcp_policy?.allowed_servers||i?.mcpPolicy?.allowedServers||[],mcpAllowedTools:c.mcpTools.length?c.mcpTools:null,mcpOtherAllowedTools:c.otherTools})}):[],u=Array.isArray(e?.flow?.nodes)?e.flow.nodes.map(e=>Pe({nodeId:e?.node_id||e?.nodeId,title:e?.metadata?.builder?.title||e?.metadata?.studio?.title||e?.objective||e?.node_id||e?.nodeId,agentId:e?.agent_id||e?.agentId,objective:e?.objective,dependsOn:e?.depends_on||e?.dependsOn||[],inputRefs:e?.input_refs||e?.inputRefs||[],outputKind:e?.output_contract?.kind||e?.outputContract?.kind||`artifact`,metadata:e?.metadata})):[],d={automationId:T(e?.automation_id||e?.automationId||e?.id),starterTemplateId:o,name:T(e?.name||`Workflow`),description:T(e?.description),summary:T(i?.summary),icon:T(i?.icon),workspaceRoot:T(e?.workspace_root||e?.workspaceRoot||r?.workspace_root||t),status:T(e?.status||a?.status||`draft`)||`draft`,scheduleType:T(e?.schedule?.type||a?.schedule_type||`manual`)||`manual`,cronExpression:T(e?.schedule?.cron_expression||e?.schedule?.cronExpression||a?.cron_expression),intervalSeconds:String(e?.schedule?.interval_seconds||e?.schedule?.intervalSeconds||a?.interval_seconds||3600),maxParallelAgents:String(e?.execution?.max_parallel_agents||e?.execution?.maxParallelAgents||a?.max_parallel_agents||1),useSharedModel:!1,sharedModelProvider:``,sharedModelId:``,outputTargets:Array.isArray(e?.output_targets||e?.outputTargets)?(e.output_targets||e.outputTargets).map(e=>T(e)).filter(Boolean):Array.isArray(a?.output_targets)?a.output_targets.map(e=>T(e)).filter(Boolean):[],agents:s.length?s:l,nodes:c.length?c:u},f=Ee(d.agents);return d.useSharedModel=f.useSharedModel,d.sharedModelProvider=f.provider,d.sharedModelId=f.model,Le(d,n)}function Ve(e,t){let n={templateID:t,display_name:T(e.displayName)||t,avatar_url:T(e.avatarUrl)||void 0,role:T(e.role)||`worker`,system_prompt:Ce(e.prompt)||void 0,skills:e.skills.map(e=>({id:e,skill_id:e,name:e})),default_budget:{},capabilities:{}};return T(e.modelProvider)&&T(e.modelId)&&(n.default_model={provider_id:T(e.modelProvider),model_id:T(e.modelId)}),n}function He(e,t,n){let r=Me(t);return{version:2,template_id:T(e.starterTemplateId),workflow_structure_version:2,summary:T(e.summary),icon:T(e.icon),created_from:`studio`,last_saved_at_ms:Date.now(),workflow:{status:T(e.status)||`draft`,schedule_type:T(e.scheduleType)||`manual`,cron_expression:T(e.cronExpression),interval_seconds:Math.max(60,Number.parseInt(String(e.intervalSeconds||`3600`),10)||3600),output_targets:e.outputTargets,max_parallel_agents:Math.max(1,Number.parseInt(String(e.maxParallelAgents||`1`),10)||1)},repair_state:n?{status:n.repairedAgentIds.length||n.missingNodeAgentIds.length?`repaired`:`clean`,reason:n.reason,requires_save:n.requiresSave}:{status:`clean`,reason:``,requires_save:!1},repaired_missing_templates:n?.repairedTemplateIds||[],repaired_agent_ids:n?.repairedAgentIds||[],agent_drafts:e.agents,node_drafts:t,node_layout:Object.fromEntries(Array.from(r.entries()))}}function Ue(e){let t=new Map,n=new Set;for(let r of e){let e=R(r.nodeId||r.title,`stage`),i=e,a=2;for(;n.has(i);)i=`${e}-${a}`,a+=1;n.add(i),t.set(r.nodeId,i)}return e.map(e=>{let n=t.get(e.nodeId)||R(e.nodeId||e.title,`stage`),r=e.dependsOn.map(e=>t.get(e)||R(e,e)).filter(Boolean),i=V(r,e.inputRefs.map(e=>({fromStepId:t.get(e.fromStepId)||R(e.fromStepId,e.fromStepId),alias:e.alias})));return I(A({...e,nodeId:n,dependsOn:r,inputRefs:i}))})}async function We(e,t,n=4){for(let r=0;r<n;r+=1){if(!ie(await e.automationsV2.list().catch(()=>({automations:[]})),`automations`).some(e=>T(e?.automation_id||e?.automationId||e?.id)===t))return;await new Promise(e=>window.setTimeout(e,250*(r+1)))}throw Error(`Delete did not persist on the engine. The workflow is still present after verification.`)}function Ge(e){let t=String(e||``).toLowerCase();return t.includes(`send_email`)||t.includes(`sendemail`)||t.includes(`send_draft`)||t.includes(`senddraft`)}function H(e){let t=``,n=!1;for(let r of String(e||``).trim())/^[a-z0-9]$/i.test(r)?(t+=r.toLowerCase(),n=!1):n||=(t+=`_`,!0);return t.replace(/^_+|_+$/g,``)||`mcp`}function U(e){return Array.from(new Set(e.map(e=>String(e||``).trim()).filter(Boolean))).sort()}function W(e,t){let n=`mcp.${H(t)}.`;return String(e||``).startsWith(n)}function G(e,t){return U(t.filter(t=>e.some(e=>W(e,t.name))).map(e=>e.name))}function Ke(e,t){let n=new Set(t);return e.filter(e=>n.has(e.name)).flatMap(e=>e.toolCache||[])}function qe(e){let{draft:n,selectedNode:r,selectedNodeInputFiles:i,selectedNodeOutputFiles:a,selectedNodeOutputPathPreview:o,selectedAgent:s,selectedTemplateLoadId:l,templateRows:u,templateMap:d,repairState:p,providerOptions:h,mcpServers:g,mcpServerRows:v,removeSelectedNode:y,removeSelectedAgent:b,updateNode:x,updateAgent:S,setSelectedAgentId:C,setSelectedNodeId:ee,setSelectedTemplateLoadId:te,loadTemplateIntoSelectedAgent:re}=e,w=r?.toolAccessMode||`inherit`,ie=w===`custom`?r?.toolAllowlist||[]:s?.toolAllowlist||[],T=w===`custom`?r?.mcpAllowedTools===null?null:[...r?.mcpOtherAllowedTools||[],...r?.mcpAllowedTools||[]]:s?.mcpAllowedTools===null?null:[...s?.mcpOtherAllowedTools||[],...s?.mcpAllowedTools||[]],ae=(ie||[]).some(Ge)||(T||[]).some(Ge),oe=w===`custom`?r?.mcpAllowedTools===null?`MCP: all selected`:T?.length?`MCP: ${T.length} tools`:`MCP: none`:`inherits agent tools`,E=U([...r?.mcpOtherAllowedTools||[],...r?.mcpAllowedTools||[]]),D=U([...r?.mcpAllowedServers||[],...G(E,v)]);return c(t,{children:[c(f,{title:r?`Stage: ${r.title}`:`Stage`,subtitle:`Edit stage behavior, dependencies, and handoff aliases.`,actions:c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:y,disabled:!r,children:[c(`i`,{"data-lucide":`trash-2`}),`Remove Stage`]}),children:r?c(`div`,{className:`grid gap-3`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Title`}),c(`input`,{className:`tcp-input text-sm`,value:r.title,onInput:e=>{x(r.nodeId,{title:e.target.value})}})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Bound Agent`}),c(`select`,{className:`tcp-input text-sm`,value:r.agentId,onInput:e=>{let t=e.target.value;x(r.nodeId,{agentId:t}),C(t)},children:n.agents.map(e=>c(`option`,{value:e.agentId,children:e.displayName||e.agentId},e.agentId))})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Objective`}),c(`textarea`,{className:`tcp-input min-h-[110px] text-sm`,value:r.objective,onInput:e=>x(r.nodeId,{objective:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Output Kind`}),c(`input`,{className:`tcp-input text-sm`,value:r.outputKind,onInput:e=>x(r.nodeId,{outputKind:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Required Output File`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`marketing-brief.md`,value:r.outputPath,onInput:e=>x(r.nodeId,{outputPath:e.target.value})}),o?c(`div`,{className:`rounded-lg border border-slate-700/60 bg-slate-950/30 px-3 py-2 text-[11px] text-slate-300`,children:[c(`div`,{children:[`Saved as:`,` `,c(`code`,{children:o.canonical||o.raw})]}),c(`div`,{children:[`Next run preview: `,c(`code`,{children:o.resolved})]}),o.warning?c(`div`,{className:`text-amber-200`,children:o.warning}):null]}):c(`span`,{className:`text-[11px] text-slate-500`,children:`Use the same runtime tokens here as the workflow output targets.`})]}),c(`label`,{className:`grid gap-1 sm:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Input Files Contract`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,placeholder:`Comma-separated relative paths this stage should read`,value:N(r.inputFiles),onInput:e=>x(r.nodeId,{inputFiles:M(e.target.value)})}),c(`span`,{className:`text-[11px] text-slate-500`,children:[`Effective contract:`,` `,i.length?N(i):`No file inputs inferred from upstream stages.`]})]}),c(`label`,{className:`grid gap-1 sm:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Output Files Contract`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,placeholder:`Comma-separated relative paths this stage must create`,value:N(r.outputFiles),onInput:e=>x(r.nodeId,{outputFiles:M(e.target.value)})}),c(`span`,{className:`text-[11px] text-slate-500`,children:[`Effective contract:`,` `,a.length?N(a):`No file outputs declared for this stage.`]})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Task Kind`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`code_change`,value:r.taskKind||``,onInput:e=>x(r.nodeId,{taskKind:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Project Backlog Tasks`}),c(`input`,{type:`checkbox`,checked:!!r.projectBacklogTasks,onChange:e=>x(r.nodeId,{projectBacklogTasks:e.target.checked})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Backlog Task ID`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`BACKLOG-123`,value:r.backlogTaskId||``,onInput:e=>x(r.nodeId,{backlogTaskId:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Repo Root`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`.`,value:r.repoRoot||``,onInput:e=>x(r.nodeId,{repoRoot:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Write Scope`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`src/api, tests/api, Cargo.toml`,value:r.writeScope||``,onInput:e=>x(r.nodeId,{writeScope:e.target.value})})]}),c(`label`,{className:`grid gap-1 sm:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Acceptance Criteria`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`Describe what must be true for this coding task to count as done.`,value:r.acceptanceCriteria||``,onInput:e=>x(r.nodeId,{acceptanceCriteria:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Backlog Dependencies`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`BACKLOG-101, BACKLOG-102`,value:r.taskDependencies||``,onInput:e=>x(r.nodeId,{taskDependencies:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Verification State`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`pending`,value:r.verificationState||``,onInput:e=>x(r.nodeId,{verificationState:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Task Owner / Claimer`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`implementer`,value:r.taskOwner||``,onInput:e=>x(r.nodeId,{taskOwner:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Verification Command`}),c(`input`,{className:`tcp-input text-sm`,placeholder:`cargo test -p tandem-server`,value:r.verificationCommand||``,onInput:e=>x(r.nodeId,{verificationCommand:e.target.value})})]}),c(`div`,{className:`grid gap-2`,children:[c(`div`,{className:`text-xs text-slate-400`,children:`Dependencies`}),c(`div`,{className:`flex flex-wrap gap-2`,children:n.nodes.filter(e=>e.nodeId!==r.nodeId).map(e=>{let t=r.dependsOn.includes(e.nodeId);return c(`button`,{className:t?`tcp-btn-primary inline-flex h-7 items-center gap-2 px-2 text-xs`:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:()=>{let n=t?r.dependsOn.filter(t=>t!==e.nodeId):[...r.dependsOn,e.nodeId];x(r.nodeId,{dependsOn:n})},children:[c(`i`,{"data-lucide":t?`check`:`plus`}),e.title]},`${r.nodeId}-${e.nodeId}`)})})]}),r.inputRefs.length?c(`div`,{className:`grid gap-2`,children:[c(`div`,{className:`text-xs text-slate-400`,children:`Input Aliases`}),r.inputRefs.map(e=>c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-500`,children:e.fromStepId}),c(`input`,{className:`tcp-input text-sm`,value:e.alias,onInput:t=>x(r.nodeId,{inputRefs:r.inputRefs.map(n=>n.fromStepId===e.fromStepId?{...n,alias:t.target.value}:n)})})]},`${r.nodeId}-${e.fromStepId}`))]}):null,c(`details`,{className:`rounded-xl border border-slate-700/60 bg-slate-950/30 p-3`,children:[c(`summary`,{className:`flex cursor-pointer flex-wrap items-center justify-between gap-2 text-sm text-slate-100`,children:[c(`span`,{className:`inline-flex items-center gap-2 font-medium`,children:[c(`i`,{"data-lucide":`wrench`}),c(`span`,{children:`Task Tool Access`})]}),c(`span`,{className:`flex flex-wrap items-center gap-2 text-[11px]`,children:[c(`span`,{className:`rounded-full border border-slate-700 px-2 py-1 text-slate-300`,children:w===`custom`?`custom task tools`:`inherits agent tools`}),c(`span`,{className:`rounded-full border border-slate-700 px-2 py-1 text-slate-300`,children:oe}),ae?c(`span`,{className:`rounded-full border border-red-400/40 bg-red-500/10 px-2 py-1 text-red-200`,children:`send-capable`}):null,c(`span`,{className:`text-slate-500`,children:`Expand to change tools for this task only.`})]})]}),c(`div`,{className:`mt-3 grid gap-3`,children:[c(`div`,{className:`grid gap-2 md:grid-cols-2`,children:[c(`button`,{type:`button`,className:w===`inherit`?`tcp-btn-primary justify-start`:`tcp-btn justify-start`,onClick:()=>x(r.nodeId,{toolAccessMode:`inherit`,toolAllowlist:[],toolDenylist:[],mcpAllowedServers:[],mcpAllowedTools:null,mcpOtherAllowedTools:[]}),children:`Inherit agent tools`}),c(`button`,{type:`button`,className:w===`custom`?`tcp-btn-primary justify-start`:`tcp-btn justify-start`,onClick:()=>x(r.nodeId,{toolAccessMode:`custom`,toolAllowlist:r.toolAllowlist?.length?r.toolAllowlist:s?.toolAllowlist||[`read`],toolDenylist:r.toolDenylist||[],mcpAllowedServers:r.mcpAllowedServers?.length?r.mcpAllowedServers:s?.mcpAllowedServers||[],mcpAllowedTools:r.mcpAllowedTools===void 0?s?.mcpAllowedTools||null:r.mcpAllowedTools,mcpOtherAllowedTools:r.mcpOtherAllowedTools||s?.mcpOtherAllowedTools||[]}),children:`Customize this task`})]}),w===`custom`?c(t,{children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Task Tool Allowlist`}),c(`input`,{className:`tcp-input text-sm`,value:N(r.toolAllowlist||[]),onInput:e=>x(r.nodeId,{toolAllowlist:M(e.target.value)})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Task Tool Denylist`}),c(`input`,{className:`tcp-input text-sm`,value:N(r.toolDenylist||[]),onInput:e=>x(r.nodeId,{toolDenylist:M(e.target.value)})})]}),c(`div`,{className:`grid gap-2`,children:[c(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Task MCP Servers`}),c(`span`,{className:`text-[11px] text-slate-500`,children:`Select runtime servers to reveal all available task tools.`})]}),v.length?c(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>{let t=D.includes(e.name);return c(`button`,{type:`button`,className:t?`tcp-btn-primary h-7 px-2 text-xs`:`tcp-btn h-7 px-2 text-xs`,onClick:()=>{let n=U([...r.mcpAllowedServers||[],...G(E,v)]),i=t?n.filter(t=>t!==e.name):U([...n,e.name]),a=Array.isArray(r.mcpAllowedTools)?r.mcpAllowedTools.filter(n=>!t||!W(n,e.name)):r.mcpAllowedTools;x(r.nodeId,{mcpAllowedServers:i,mcpAllowedTools:a})},children:e.name},e.name)})}):c(`div`,{className:`text-xs text-slate-500`,children:`No MCP servers are currently visible to the runtime.`})]}),c(_,{title:`Task MCP tool access`,subtitle:`This list applies only to the selected task. Unchecked tools stay visible so they can be restored.`,discoveredTools:Ke(v,D),value:r.mcpAllowedTools??null,onChange:e=>x(r.nodeId,{mcpAllowedTools:e}),collapsible:!0,defaultCollapsed:!0})]}):null]})]})]}):c(m,{text:`Select a stage to edit it.`})}),c(f,{title:s?`Agent: ${s.displayName||s.agentId}`:`Agent`,subtitle:`Role prompt, policies, reusable template link, and model settings.`,actions:c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:b,disabled:!s,children:[c(`i`,{"data-lucide":`trash-2`}),`Remove Agent`]}),children:s?c(`div`,{className:`grid gap-3`,children:[c(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Display Name`}),c(`input`,{className:`tcp-input text-sm`,value:s.displayName,onInput:e=>S(s.agentId,{displayName:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Role`}),c(`select`,{className:`tcp-input text-sm`,value:s.role,onInput:e=>S(s.agentId,{role:e.target.value}),children:ne.map(e=>c(`option`,{value:e,children:e},e))})]}),c(`label`,{className:`grid gap-1 md:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Skills`}),c(`input`,{className:`tcp-input text-sm`,value:N(s.skills),onInput:e=>S(s.agentId,{skills:M(e.target.value)}),placeholder:`copywriting, websearch, qa`})]})]}),c(`div`,{className:`rounded-xl border border-slate-700/60 bg-slate-950/30 p-3`,children:[c(`div`,{className:`mb-2 flex items-center justify-between gap-2`,children:[c(`div`,{className:`text-xs uppercase tracking-wide text-slate-500`,children:`Template Link`}),s.linkedTemplateId?c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:()=>S(s.agentId,{linkedTemplateId:``,templateId:``}),children:[c(`i`,{"data-lucide":`unlink`}),`Detach`]}):null]}),c(`div`,{className:`grid gap-2 md:grid-cols-[minmax(0,1fr)_auto]`,children:[c(`select`,{className:`tcp-input text-sm`,value:l,onInput:e=>te(e.target.value),children:[c(`option`,{value:``,children:`Select an existing agent template...`}),u.map(e=>c(`option`,{value:e.templateId,children:e.displayName||e.templateId},e.templateId))]}),c(`button`,{className:`tcp-btn inline-flex h-10 items-center gap-2 px-3 text-sm`,disabled:!l,onClick:re,children:[c(`i`,{"data-lucide":`download`}),`Load Template`]})]}),c(`div`,{className:`mt-2 text-xs text-slate-400`,children:p?.repairedAgentIds.includes(s.agentId)?`This agent had a missing shared template link. Studio repaired it into a workflow-local prompt.`:s.linkedTemplateId?d.has(s.linkedTemplateId)?`Linked template: ${s.linkedTemplateId}`:`Missing template link repaired locally: ${s.linkedTemplateId}`:`This agent is currently workflow-local unless you save reusable templates.`}),c(`div`,{className:`mt-1 text-xs text-slate-500`,children:`Local means Studio stores the prompt in workflow metadata. Linked means runtime depends on a shared Agent Team template.`})]}),c(`div`,{className:`grid gap-3 md:grid-cols-2`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Model Provider`}),c(`select`,{className:`tcp-input text-sm`,value:s.modelProvider,disabled:n.useSharedModel,onInput:e=>S(s.agentId,(()=>{let t=e.target.value,n=z(h,t);return{modelProvider:t,modelId:n.includes(s.modelId)?s.modelId:n[0]||s.modelId}})()),children:[c(`option`,{value:``,children:`Select provider...`}),h.map(e=>c(`option`,{value:e.id,children:e.id},e.id))]})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Model ID`}),z(h,s.modelProvider).length?c(`select`,{className:`tcp-input text-sm`,value:s.modelId,disabled:n.useSharedModel,onInput:e=>S(s.agentId,{modelId:e.target.value}),children:z(h,s.modelProvider).map(e=>c(`option`,{value:e,children:e},e))}):c(`input`,{className:`tcp-input text-sm`,value:s.modelId,disabled:n.useSharedModel,onInput:e=>S(s.agentId,{modelId:e.target.value}),placeholder:`provider-specific model id`})]}),n.useSharedModel?c(`div`,{className:`text-xs text-amber-200 md:col-span-2`,children:`Per-agent model controls are locked because this workflow is using one shared model for all agents.`}):null,c(`label`,{className:`grid gap-1 md:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Tool Allowlist`}),c(`input`,{className:`tcp-input text-sm`,value:N(s.toolAllowlist),onInput:e=>S(s.agentId,{toolAllowlist:M(e.target.value)})})]}),c(`label`,{className:`grid gap-1 md:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Tool Denylist`}),c(`input`,{className:`tcp-input text-sm`,value:N(s.toolDenylist),onInput:e=>S(s.agentId,{toolDenylist:M(e.target.value)})})]}),c(`label`,{className:`grid gap-1 md:col-span-2`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Allowed MCP Servers`}),c(`input`,{className:`tcp-input text-sm`,value:N(s.mcpAllowedServers),onInput:e=>S(s.agentId,{mcpAllowedServers:M(e.target.value)}),placeholder:N(g)||`No MCP servers detected`})]}),s.mcpAllowedServers.length?c(`div`,{className:`md:col-span-2`,children:c(_,{title:`Agent MCP tool access`,subtitle:`Leave all discovered tools selected to inherit full access from the chosen MCP servers, or uncheck tools to save an exact MCP allowlist for this agent.`,discoveredTools:v.filter(e=>s.mcpAllowedServers.includes(e.name)).flatMap(e=>e.toolCache),value:s.mcpAllowedTools,onChange:e=>S(s.agentId,{mcpAllowedTools:e})})}):null]}),c(`div`,{className:`grid gap-3`,children:[c(`div`,{className:`text-xs uppercase tracking-wide text-slate-500`,children:`Role Prompt`}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Role`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,value:s.prompt.role,onInput:e=>S(s.agentId,{prompt:{...s.prompt,role:e.target.value}})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Mission`}),c(`textarea`,{className:`tcp-input min-h-[92px] text-sm`,value:s.prompt.mission,onInput:e=>S(s.agentId,{prompt:{...s.prompt,mission:e.target.value}})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Inputs`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,value:s.prompt.inputs,onInput:e=>S(s.agentId,{prompt:{...s.prompt,inputs:e.target.value}})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Output Contract`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,value:s.prompt.outputContract,onInput:e=>S(s.agentId,{prompt:{...s.prompt,outputContract:e.target.value}})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Guardrails`}),c(`textarea`,{className:`tcp-input min-h-[72px] text-sm`,value:s.prompt.guardrails,onInput:e=>S(s.agentId,{prompt:{...s.prompt,guardrails:e.target.value}})})]})]}),c(`div`,{className:`rounded-xl border border-slate-700/60 bg-slate-950/40 p-3`,children:[c(`div`,{className:`mb-2 text-xs uppercase tracking-wide text-slate-500`,children:`Composed System Prompt`}),c(`pre`,{className:`whitespace-pre-wrap break-words text-xs text-slate-200`,children:Ce(s.prompt)||`Prompt preview will appear here.`})]})]}):c(m,{text:`Select or add an agent to edit it.`})})]})}function K({client:s,api:g,toast:_,navigate:y}){let b=i(),C=p(!0),ne=a({queryKey:[`studio`,`automations`],queryFn:()=>s.automationsV2.list().catch(()=>({automations:[]})),refetchInterval:15e3}),re=a({queryKey:[`studio`,`templates`],queryFn:()=>s.agentTeams.listTemplates().catch(()=>({templates:[]})),refetchInterval:1e4}),E=a({queryKey:[`studio`,`providers`,`catalog`],queryFn:()=>s.providers.catalog().catch(()=>({all:[]})),refetchInterval:3e4}),D=a({queryKey:[`studio`,`providers`,`config`],queryFn:()=>s.providers.config().catch(()=>({})),refetchInterval:3e4}),O=a({queryKey:[`studio`,`mcp`],queryFn:()=>s.mcp.list().catch(()=>({})),refetchInterval:15e3}),k=T(C.data?.workspaceRoot||C.data?.workspace_root),se=n(()=>ie(re.data,`templates`).map(Ae).filter(e=>e.templateId),[re.data]),A=n(()=>new Map(se.map(e=>[e.templateId,e])),[se]),j=D.data,P=n(()=>v({providerCatalog:E.data,providerConfig:j,defaultProvider:String(j?.default||``).trim(),defaultModel:String(j?.providers?.[String(j?.default||``).trim()]?.default_model||j?.providers?.[String(j?.default||``).trim()]?.defaultModel||``).trim()}),[E.data,j]),I=n(()=>Te(P,D.data),[P,D.data]),L=n(()=>ie(ne.data,`automations`).filter(e=>{let t=e?.metadata?.studio;return!!t&&(Number(t?.version||0)>0||T(t?.created_from)===`studio`)}),[ne.data]),R=n(()=>L.map(e=>T(e?.automation_id||e?.automationId||e?.id)).filter(Boolean),[L]),Ne=a({queryKey:[`studio`,`workflow-runs`,R],enabled:!!s?.automationsV2?.listRuns&&R.length>0,queryFn:async()=>({runs:(await Promise.all(R.map(async e=>{let t=await s.automationsV2.listRuns(e,6).catch(()=>({runs:[]}));return Array.isArray(t?.runs)?t.runs:[]}))).flat()}),refetchInterval:12e3}),Pe=n(()=>{let e=ie(Ne.data,`runs`),t=new Map;return e.forEach(e=>{let n=T(e?.automation_id||e?.automationId);if(!n)return;let r=t.get(n),i=Number(r?.updated_at_ms||r?.updatedAtMs||r?.created_at_ms||r?.createdAtMs||0),a=Number(e?.updated_at_ms||e?.updatedAtMs||e?.created_at_ms||e?.createdAtMs||0);(!r||a>=i)&&t.set(n,e)}),t},[Ne.data]),Ie=n(()=>ke(O.data),[O.data]),Ge=n(()=>(Array.isArray(O.data?.servers)?O.data.servers:[]).map(e=>{let t=T(e?.name);return t?{name:t,toolCache:Array.isArray(e?.tool_cache||e?.toolCache)?(e.tool_cache||e.toolCache).map(e=>T(e?.namespaced_name||e?.namespacedName||e?.tool_name||e?.name)).filter(Boolean):[]}:null}).filter(e=>!!e).sort((e,t)=>e.name.localeCompare(t.name)),[O.data]),[H,U]=r(()=>S(x[0],``)),[W,G]=r(()=>x[0]?.nodes?.[0]?.nodeId||``),[Ke,K]=r(()=>x[0]?.agents?.[0]?.agentId||``),[Je,Ye]=r(``),[q,Xe]=r(!1),[Ze,Qe]=r(!1),[$e,et]=r(!0),[tt,nt]=r(!0),[rt,it]=r(!1),[at,ot]=r(``),[st,ct]=r(``),[lt,ut]=r(null),[J,dt]=r(null),[Y,ft]=r(null);e(()=>{k&&U(e=>T(e.workspaceRoot)?e:{...e,workspaceRoot:k})},[k]),e(()=>{let e=sessionStorage.getItem(w);if(e){sessionStorage.removeItem(w);try{let t=JSON.parse(e),n=T(t.agentId);if(!n)return;ft({agentId:n,displayName:T(t.displayName)||n,categoryId:T(t.categoryId),categoryTitle:T(t.categoryTitle),summary:T(t.summary),sourcePath:T(t.sourcePath),sandboxMode:T(t.sandboxMode),role:ae(t.role),tags:Array.isArray(t.tags)?t.tags.map(e=>T(e)).filter(Boolean):[],requires:Array.isArray(t.requires)?t.requires.map(e=>T(e)).filter(Boolean):[],instructions:T(t.instructions)})}catch(e){console.warn(`Failed to parse catalog agent handoff:`,e)}}},[]),e(()=>{!I.provider||!I.model||U(e=>{let t=B(e.agents,I);return t.some((t,n)=>t.modelProvider!==e.agents[n]?.modelProvider||t.modelId!==e.agents[n]?.modelId)?{...e,agents:t}:e})},[I]),e(()=>{H.useSharedModel&&(!T(H.sharedModelProvider)||!T(H.sharedModelId)||U(e=>{if(!e.useSharedModel)return e;let t=De(e.agents,e.sharedModelProvider,e.sharedModelId);return t.some((t,n)=>t.modelProvider!==e.agents[n]?.modelProvider||t.modelId!==e.agents[n]?.modelId)?{...e,agents:t}:e}))},[H.useSharedModel,H.sharedModelProvider,H.sharedModelId]),e(()=>{new Set(H.nodes.map(e=>e.nodeId)).has(W)||G(H.nodes[0]?.nodeId||``)},[H.nodes,W]),e(()=>{new Set(H.agents.map(e=>e.agentId)).has(Ke)||K(H.agents[0]?.agentId||``)},[H.agents,Ke]),e(()=>{if(!Y)return;let e=T(Y.agentId);if(!e){ft(null);return}let t=H.nodes.find(e=>e.nodeId===W)?.nodeId||H.nodes.find(t=>t.agentId===e)?.nodeId||H.nodes[0]?.nodeId||``;U(n=>{let r=n.agents.find(t=>t.agentId===e)?n.agents.map(t=>t.agentId===e?{...t,role:ae(Y.role)}:t):[...n.agents,oe(Y)],i=t?n.nodes.map(n=>n.nodeId===t?{...n,agentId:e}:n):n.nodes;return{...n,agents:r,nodes:i}}),t&&G(t),K(e),dt(null),_(`ok`,`Seeded ${Y.displayName} into Studio and bound it to a workflow stage.`),ft(null)},[Y,H.nodes,W,_]),e(()=>{try{d()}catch{}},[H,W,Je,$e,tt,L.length,se.length,rt,st]);let pt=a({queryKey:[`studio`,`workspace-browser`,at],enabled:rt&&!!at,queryFn:()=>g(`/api/orchestrator/workspaces/list?dir=${encodeURIComponent(at)}`,{method:`GET`}),refetchInterval:rt?15e3:!1}),X=H.nodes.find(e=>e.nodeId===W)||H.nodes[0]||null,mt=X?ye(X,H.nodes):[],ht=X?ve(X):[],gt=n(()=>ge(H),[H]),_t=n(()=>_e(H),[H]),vt=n(()=>{let e=new Date,t=[];return gt.outputTargets.forEach((n,r)=>{let i=T(H.outputTargets[r]||n);t.push({id:`target-${r}`,label:`Workflow target ${r+1}`,raw:i,canonical:n,resolved:me(n,e),warning:he(i)})}),gt.nodes.forEach((n,r)=>{let i=T(H.nodes[r]?.outputPath||n.outputPath);!T(n.outputPath)&&!i||t.push({id:`node-${n.nodeId}`,label:`${T(n.title)||T(n.nodeId)||`Stage ${r+1}`}`,raw:i||T(n.outputPath),canonical:T(n.outputPath),resolved:me(T(n.outputPath),e),warning:he(i||T(n.outputPath))})}),t.filter(e=>e.raw||e.canonical)},[gt,H]),yt=n(()=>{if(!X)return null;let e=T(X.outputPath),t=F(e);return!e&&!t?null:{raw:e,canonical:t,resolved:me(t||e),warning:he(e)}},[X]),Z=H.agents.find(e=>e.agentId===(Ke||X?.agentId))||H.agents.find(e=>e.agentId===X?.agentId)||H.agents[0]||null,bt=xe(H.workspaceRoot),xt=Array.isArray(pt.data?.directories)?pt.data.directories:[],St=T(pt.data?.parent),Ct=T(pt.data?.dir||at||``),wt=n(()=>{let e=T(st).toLowerCase();return e?xt.filter(t=>T(t?.name||t?.path).toLowerCase().includes(e)):xt},[st,xt]),Tt=n(()=>Me(H.nodes),[H.nodes]),Et=n(()=>{let e=new Map;for(let t of H.nodes){let n=Number(Tt.get(t.nodeId)||0);e.has(n)||e.set(n,[]),e.get(n)?.push(t)}return Array.from(e.entries()).sort((e,t)=>e[0]-t[0])},[H.nodes,Tt]),Dt=e=>{let t=S(x.find(t=>t.id===e)||x[0],H.workspaceRoot||k);U({...t,agents:B(t.agents,I)}),G(t.nodes[0]?.nodeId||``),K(t.agents[0]?.agentId||``),Xe(!1),dt(null)},Q=e=>U(t=>({...t,...e})),Ot=(e,t)=>U(n=>({...n,nodes:n.nodes.map(n=>n.nodeId===e?{...n,...t,inputRefs:t.dependsOn||t.inputRefs?V(t.dependsOn?[...t.dependsOn]:n.dependsOn,t.inputRefs?[...t.inputRefs]:n.inputRefs):n.inputRefs}:n)})),kt=(e,t)=>U(n=>({...n,agents:n.agents.map(n=>n.agentId===e?{...n,...t}:n)})),At=()=>{let e=`agent-${H.agents.length+1}`,t=H.agents.some(t=>t.agentId===e)?`agent-${Date.now().toString().slice(-5)}`:e;U(e=>({...e,agents:[...e.agents,B([ee(t,`Agent ${e.agents.length+1}`)],I)[0]]})),K(t)},jt=()=>{let e=H.nodes.length+1,t=`stage-${e}`,n=Z?.agentId||H.agents[0]?.agentId||``,r=te(t,`Stage ${e}`,n,X?[X.nodeId]:[],X?[{fromStepId:X.nodeId,alias:X.nodeId.replace(/-/g,`_`)}]:[],{objective:`Describe what this stage should produce.`});U(e=>({...e,nodes:[...e.nodes,r]})),G(t),n&&K(n)},Mt=()=>{X&&U(e=>({...e,nodes:e.nodes.filter(e=>e.nodeId!==X.nodeId).map(e=>{let t=e.dependsOn.filter(e=>e!==X.nodeId);return{...e,dependsOn:t,inputRefs:V(t,e.inputRefs.filter(e=>e.fromStepId!==X.nodeId))}})}))},Nt=()=>{if(Z){if(H.nodes.some(e=>e.agentId===Z.agentId)){_(`warn`,`Reassign or remove the stages using this agent first.`);return}U(e=>({...e,agents:e.agents.filter(e=>e.agentId!==Z.agentId)})),K(``)}},Pt=()=>{if(!Z||!Je)return;let e=A.get(Je);e&&(kt(Z.agentId,{displayName:e.displayName||Z.displayName,avatarUrl:e.avatarUrl||Z.avatarUrl,role:e.role||Z.role,linkedTemplateId:e.templateId,templateId:e.templateId,prompt:e.systemPrompt?je(e.systemPrompt):Z.prompt,modelProvider:e.modelProvider||Z.modelProvider,modelId:e.modelId||Z.modelId,skills:e.skills.length?e.skills:Z.skills}),dt(t=>t&&{...t,repairedAgentIds:t.repairedAgentIds.filter(e=>e!==Z.agentId),repairedTemplateIds:t.repairedTemplateIds.filter(t=>t!==e.templateId)}),_(`ok`,`Loaded template ${e.templateId}.`))},Ft=e=>{let t=Be(e,k,A),n={...t.draft,agents:B(t.draft.agents,I)};U(n),G(n.nodes[0]?.nodeId||``),K(n.agents[0]?.agentId||``),Xe(t.draft.agents.some(e=>!!T(e.linkedTemplateId||e.templateId))),dt(t.repairState?{...t.repairState,reason:`load`,requiresSave:!0}:null),t.repairState?.repairedAgentIds.length&&_(`warn`,`Repaired missing template links for: ${t.repairState.repairedAgentIds.join(`, `)}. Save the workflow before running it.`),y(`studio`)},It=async e=>{let t=T(e?.automation_id||e?.automationId||e?.id);if(Re(e,A).isBroken){Ft(e),_(`warn`,`This workflow references missing agent templates. It was repaired in Studio. Save it before running.`);return}let n=await s.automationsV2.runNow(t),r=T(n?.run?.run_id||n?.run?.runId);await Promise.all([b.invalidateQueries({queryKey:[`studio`,`automations`]}),b.invalidateQueries({queryKey:[`automations`]}),b.invalidateQueries({queryKey:[`automations`,`runs`]}),b.invalidateQueries({queryKey:[`automations`,`v2`,`runs`]})]),_(`ok`,r?`Workflow run started: ${r}. Opening Automations.`:`Workflow run started. Opening Automations.`),Se({tab:`running`,runId:r,automationId:t,openTaskInspector:!0}),y(`automations`)},$=o({mutationFn:async()=>{let e=q?H:Le(H,A).draft,t={...e,agents:B(e.agents,I)};t.useSharedModel&&T(t.sharedModelProvider)&&T(t.sharedModelId)&&(t={...t,agents:De(t.agents,t.sharedModelProvider,t.sharedModelId)});let n=xe(t.workspaceRoot);if(n)throw Error(n);if(!T(t.name))throw Error(`Workflow name is required.`);if(!t.agents.length)throw Error(`Add at least one agent.`);if(!t.nodes.length)throw Error(`Add at least one stage.`);let r=ze(t,A);if(r.errors.length)throw Error(r.errors[0]);let i=t.agents.filter(e=>!T(e.modelProvider)||!T(e.modelId)).map(e=>e.displayName||e.agentId);if(i.length)throw Error(`Model selection is required. Set a default provider/model in Settings or choose one for: ${i.join(`, `)}.`);let a=_e(t);a.length&&_(`warn`,`${a[0]} Use the output preview to confirm the saved path before you run this workflow.`),t=ge(t);let o=be(t.name)||`studio-workflow`,c=new Map;if(q)for(let e of t.agents){let t=T(e.linkedTemplateId)||T(e.templateId)||`${o}--${be(e.agentId)||`agent`}`;c.set(e.agentId,t),A.has(t)?await s.agentTeams.updateTemplate(t,{display_name:T(e.displayName)||t,avatar_url:T(e.avatarUrl)||void 0,role:T(e.role)||`worker`,system_prompt:Ce(e.prompt)||void 0,default_model:T(e.modelProvider)&&T(e.modelId)?{provider_id:T(e.modelProvider),model_id:T(e.modelId)}:void 0,skills:e.skills.map(e=>({id:e,skill_id:e,name:e}))}):await s.agentTeams.createTemplate({template:Ve(e,t)})}let l=Ue(t.nodes),u={name:T(t.name),description:T(t.description)||void 0,status:t.status,schedule:Oe(t),workspace_root:T(t.workspaceRoot),execution:{max_parallel_agents:Math.max(1,Number.parseInt(String(t.maxParallelAgents||`1`),10)||1)},output_targets:t.outputTargets.map(e=>T(e)).filter(Boolean),agents:t.agents.map(e=>({...(()=>{let t=Array.isArray(e.mcpAllowedTools)?[...e.mcpOtherAllowedTools,...e.mcpAllowedTools]:e.mcpOtherAllowedTools;return{agent_id:T(e.agentId),template_id:q&&(c.get(e.agentId)||T(e.linkedTemplateId))||void 0,display_name:T(e.displayName)||T(e.agentId),avatar_url:T(e.avatarUrl)||void 0,model_policy:we(e),skills:e.skills.map(e=>T(e)).filter(Boolean),tool_policy:{allowlist:ue(e.toolAllowlist,l.filter(t=>t.agentId===e.agentId)),denylist:e.toolDenylist.map(e=>T(e)).filter(Boolean)},mcp_policy:{allowed_servers:e.mcpAllowedServers.map(e=>T(e)).filter(Boolean),allowed_tools:e.mcpAllowedTools===null?null:t.filter(Boolean)}}})()})),flow:{nodes:l.map(e=>{let n=t.agents.find(t=>t.agentId===e.agentId),r=T(e.outputPath),i=ye(e,l),a=ve(e),o=ce(e),s=T(e.stageKind),c=s===`research_finalize`,u=!!s&&!r,d=e.inputRefs.some(e=>T(e.alias)===`external_research`),f=ue(e.toolAccessMode===`custom`?e.toolAllowlist||[]:n?.toolAllowlist||[],l.filter(t=>t.agentId===e.agentId)),p=!!n?.toolAllowlist?.includes(`websearch`)&&!c,m=T(e.outputKind)===`brief`,h=u&&s===`research_discover`,g=u&&(s===`research_discover`||s===`research_local_sources`),_=u&&s===`research_external_sources`&&p,v=r?[f.includes(`read`)&&!c?`read`:null,f.includes(`websearch`)&&!c?`websearch`:null].filter(e=>!!e).filter((e,t,n)=>n.indexOf(e)===t):u?[g?`read`:null,_?`websearch`:null].filter(e=>!!e):[],y=r?[!c&&(v.includes(`read`)||m)?`local_source_reads`:null,!c&&p?`external_sources`:null].filter(e=>!!e):u?[g?`local_source_reads`:null,_?`external_sources`:null].filter(e=>!!e):[],b=m?[`files_reviewed`,`files_not_reviewed`,`citations`,p||d?`web_sources_reviewed`:null].filter(e=>!!e):[],x=r?[c?null:`workspace_inspection`,!c&&(v.includes(`read`)||m)?`concrete_reads`:null,!c&&p?`successful_web_research`:null].filter(e=>!!e):u?[h?`workspace_inspection`:null,g?`concrete_reads`:null,_?`successful_web_research`:null].filter(e=>!!e):[],S=[...y,...b,...x],C=e.toolAccessMode===`custom`?Array.isArray(e.mcpAllowedTools)?[...e.mcpOtherAllowedTools||[],...e.mcpAllowedTools]:(e.mcpAllowedServers||[]).map(e=>`mcp.${normalizeMcpServerNamespace(e)}.*`):[];return{node_id:T(e.nodeId),agent_id:T(e.agentId),objective:T(e.objective)||T(e.title),tool_policy:e.toolAccessMode===`custom`?{allowlist:[...f,...C],denylist:(e.toolDenylist||[]).map(e=>T(e)).filter(Boolean)}:void 0,mcp_policy:e.toolAccessMode===`custom`?{allowed_servers:(e.mcpAllowedServers||[]).map(e=>T(e)).filter(Boolean),allowed_tools:e.mcpAllowedTools===null?null:C.filter(Boolean)}:void 0,depends_on:e.dependsOn.map(e=>T(e)).filter(Boolean),input_refs:V(e.dependsOn,e.inputRefs).map(e=>({from_step_id:T(e.fromStepId),alias:T(e.alias)||T(e.fromStepId).replace(/-/g,`_`)})),stage_kind:s?`workstream`:void 0,output_contract:{kind:T(e.outputKind)||`artifact`,enforcement:r?{required_tools:v,required_evidence:y,required_sections:b,prewrite_gates:x,retry_on_missing:S,terminal_on:S.length?[`tool_unavailable`,`repair_budget_exhausted`]:[],repair_budget:S.length?5:void 0,session_text_recovery:S.length||m?`require_prewrite_satisfied`:`allow`}:void 0,summary_guidance:r?o?`Apply the scoped repository changes, update \`${r}\` in the workspace, and use patch/edit/write tools before completing this stage.`:`Create or update \`${r}\` in the workspace and use the write tool before completing this stage.`:u?`Return a structured handoff in the final response instead of writing workspace files.`:void 0},metadata:{studio:{input_files:i.length?i:void 0,output_path:r||void 0,output_files:a.length?a:void 0,research_stage:s||void 0},builder:{title:T(e.title)||T(e.nodeId),role:T(n?.role)||`worker`,input_files:i.length?i:void 0,output_path:r||void 0,output_files:a.length?a:void 0,research_stage:s||void 0,write_required:!!r,required_tools:v,web_research_expected:p,task_kind:T(e.taskKind)||void 0,project_backlog_tasks:le(e)||void 0,task_id:T(e.backlogTaskId)||void 0,repo_root:T(e.repoRoot)||void 0,write_scope:T(e.writeScope)||void 0,acceptance_criteria:T(e.acceptanceCriteria)||void 0,task_dependencies:T(e.taskDependencies)||void 0,verification_state:T(e.verificationState)||void 0,task_owner:T(e.taskOwner)||void 0,verification_command:T(e.verificationCommand)||void 0,prompt:Fe(e,n||ee(T(e.agentId),T(e.agentId)))}}}})},metadata:{workspace_root:T(H.workspaceRoot),studio:He({...t,agents:t.agents.map(e=>({...e,templateId:q?c.get(e.agentId)||T(e.linkedTemplateId)||T(e.templateId):``,linkedTemplateId:q?c.get(e.agentId)||T(e.linkedTemplateId)||T(e.templateId):``}))},l,q?null:J||Le(t,A).repairState)}},d=H.automationId?await s.automationsV2.update(H.automationId,u):await s.automationsV2.create(u),f=T(d?.automation?.automation_id||d?.automation?.automationId),p=``;if(Ze&&f){let e=await s.automationsV2.runNow(f);p=T(e?.run?.run_id||e?.run?.runId)}return{response:d,automationId:f,linkedTemplateIds:c,workingDraft:t,startedRunId:p}},onSuccess:async({response:e,automationId:t,linkedTemplateIds:n,workingDraft:r,startedRunId:i})=>{_(`ok`,Ze?`Studio workflow saved and run started.`:`Studio workflow saved.`),await Promise.all([b.invalidateQueries({queryKey:[`studio`,`automations`]}),b.invalidateQueries({queryKey:[`automations`]}),b.invalidateQueries({queryKey:[`studio`,`templates`]}),b.invalidateQueries({queryKey:[`teams`]})]),U(i=>({...i,...r,automationId:t||T(e?.automation?.automation_id||e?.automation?.automationId),agents:r.agents.map(e=>({...e,templateId:q?n.get(e.agentId)||e.templateId:``,linkedTemplateId:q?n.get(e.agentId)||e.linkedTemplateId:``}))})),dt(e=>e?{...e,requiresSave:!1,reason:`save`}:null),Ze&&(Se({tab:`running`,runId:i,automationId:t||T(e?.automation?.automation_id||e?.automation?.automationId),openTaskInspector:!0}),y(`automations`))},onError:e=>_(`err`,e instanceof Error?e.message:String(e))}),Lt=o({mutationFn:async e=>(await s.automationsV2.delete(e),await We(s,e),e),onSuccess:async e=>{if(H.automationId===e){let e=S(x[0],k||``);U(e),G(e.nodes[0]?.nodeId||``),K(e.agents[0]?.agentId||``)}await Promise.all([b.invalidateQueries({queryKey:[`studio`,`automations`]}),b.invalidateQueries({queryKey:[`automations`]})]),_(`ok`,`Studio workflow deleted.`)},onError:e=>_(`err`,e instanceof Error?e.message:String(e))});return c(`div`,{className:`grid gap-4`,children:c(f,{title:`Studio`,subtitle:`Template-first multi-agent workflow builder with reusable role prompts.`,actions:c(`div`,{className:`flex flex-wrap items-center gap-2`,children:[c(`button`,{className:`tcp-btn inline-flex items-center gap-2`,onClick:()=>Dt(H.starterTemplateId||x[0].id),children:[c(`i`,{"data-lucide":`rotate-ccw`}),`Reset From Template`]}),c(`button`,{className:`tcp-btn inline-flex items-center gap-2`,onClick:At,children:[c(`i`,{"data-lucide":`user-plus`}),`Add Agent`]}),c(`button`,{className:`tcp-btn inline-flex items-center gap-2`,onClick:jt,children:[c(`i`,{"data-lucide":`plus`}),`Add Stage`]}),c(`button`,{className:`tcp-btn-primary inline-flex items-center gap-2`,disabled:$.isPending,onClick:()=>$.mutate(),children:[c(`i`,{"data-lucide":$.isPending?`loader-circle`:`save`}),$.isPending?`Saving...`:`Save Workflow`]})]}),children:c(`div`,{className:`grid gap-4 xl:grid-cols-[320px_minmax(0,1fr)_360px] xl:items-start`,children:[c(`div`,{className:`grid auto-rows-max content-start self-start gap-4`,children:c(f,{title:`Studio Library`,subtitle:`Templates and saved workflows in one place.`,children:c(`div`,{className:`grid gap-4`,children:[c(`section`,{className:`grid gap-2`,children:[c(`button`,{type:`button`,className:`flex w-full items-center gap-2 text-left`,"aria-expanded":$e,onClick:()=>et(e=>!e),children:[c(`i`,{"data-lucide":$e?`chevron-down`:`chevron-right`,className:`text-slate-400`}),c(`div`,{className:`min-w-0`,children:[c(`div`,{className:`text-sm font-semibold text-slate-100`,children:`Starter Templates`}),c(`div`,{className:`text-xs text-slate-400`,children:`Begin with a proven workflow shape.`})]})]}),c(u,{initial:!1,children:$e?c(l.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:`auto`},exit:{opacity:0,height:0},transition:{duration:.16,ease:`easeOut`},className:`grid gap-2 overflow-hidden pl-5`,children:x.map(e=>c(`button`,{className:`tcp-list-item text-left ${H.starterTemplateId===e.id?`border-emerald-400/60 bg-emerald-500/10`:``}`,onClick:()=>Dt(e.id),children:[c(`div`,{className:`flex items-center justify-between gap-2`,children:[c(`strong`,{children:e.name}),c(`span`,{className:`tcp-badge-info`,children:e.icon})]}),c(`div`,{className:`mt-1 text-sm text-slate-300`,children:e.summary})]},e.id))}):null})]}),c(`section`,{className:`grid gap-2 border-t border-slate-800/80 pt-3`,children:[c(`button`,{type:`button`,className:`flex w-full items-center gap-2 text-left`,"aria-expanded":tt,onClick:()=>nt(e=>!e),children:[c(`i`,{"data-lucide":tt?`chevron-down`:`chevron-right`,className:`text-slate-400`}),c(`div`,{className:`min-w-0`,children:[c(`div`,{className:`text-sm font-semibold text-slate-100`,children:`Saved Studio Workflows`}),c(`div`,{className:`text-xs text-slate-400`,children:`Reopen workflows created from Studio metadata.`})]})]}),c(u,{initial:!1,children:tt?c(l.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:`auto`},exit:{opacity:0,height:0},transition:{duration:.16,ease:`easeOut`},className:`grid gap-2 overflow-hidden pl-5`,children:L.length?[...L].sort((e,t)=>{let n=Number(e?.updated_at_ms||e?.updatedAtMs||e?.created_at_ms||e?.createdAtMs||0);return Number(t?.updated_at_ms||t?.updatedAtMs||t?.created_at_ms||t?.createdAtMs||0)-n}).slice(0,12).map(e=>{let t=T(e?.automation_id||e?.automationId||e?.id),n=Pe.get(t)||null,r=h(n),i=T(r.status),a=T(r.failureKind),o=T(r.phase),s=fe(n?.updated_at_ms||n?.updatedAtMs||n?.created_at_ms||n?.createdAtMs),l=e?.metadata?.studio||{},u=Re(e,A),d=T(l?.template_id||l?.templateId||l?.starter_template_id||l?.starterTemplateId),f=fe(e?.updated_at_ms||e?.updatedAtMs||e?.created_at_ms||e?.createdAtMs),p=Lt.isPending&&Lt.variables===t;return c(`div`,{className:`tcp-list-item`,children:[c(`div`,{className:`flex items-center justify-between gap-2`,children:[c(`strong`,{children:T(e?.name)||t}),c(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[u.isBroken?c(`span`,{className:`tcp-badge-warn`,children:`broken links`}):null,c(`span`,{className:`tcp-badge-info`,children:T(e?.status)||`draft`})]})]}),c(`div`,{className:`mt-1 text-xs text-slate-400`,children:T(l?.summary)||`Studio workflow`}),c(`div`,{className:`mt-2 flex flex-wrap gap-2 text-[11px] text-slate-500`,children:[d?c(`span`,{className:`tcp-badge-info`,children:[`template: `,d]}):null,c(`span`,{className:`tcp-badge-muted`,children:[`id: `,de(t)]}),f?c(`span`,{className:`tcp-badge-muted`,children:[`updated: `,f]}):null]}),n?c(`div`,{className:`mt-2 rounded-lg border border-slate-700/50 bg-slate-950/20 p-2`,children:[c(`div`,{className:`text-[11px] uppercase tracking-wide text-slate-500`,children:`Latest Run Stability`}),c(`div`,{className:`mt-2 flex flex-wrap gap-2 text-[11px]`,children:[c(`span`,{className:`tcp-badge-info`,children:[`status: `,i]}),o?c(`span`,{className:`tcp-badge-muted`,children:[`phase: `,o]}):null,a?c(`span`,{className:`tcp-badge-warn`,children:[`failure: `,a]}):null,s?c(`span`,{className:`tcp-badge-muted`,children:[`run: `,s]}):null]}),T(r.reason)?c(`div`,{className:`mt-2 text-xs text-slate-300`,children:T(r.reason)}):null]}):null,c(`div`,{className:`mt-2 flex flex-wrap gap-2`,children:[c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:()=>{Ft(e)},children:[c(`i`,{"data-lucide":`folder-open`}),`Open`]}),c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs`,onClick:async()=>{try{await It(e)}catch(e){_(`err`,e instanceof Error?e.message:String(e))}},children:[c(`i`,{"data-lucide":`play`}),u.isBroken?`Repair & Open`:`Run Now`]}),c(`button`,{className:`tcp-btn inline-flex h-7 items-center gap-2 px-2 text-xs text-rose-200`,disabled:p,onClick:()=>{ut({automationId:t,title:T(e?.name)||t})},children:[c(`i`,{"data-lucide":`trash-2`}),p?`Deleting...`:`Delete`]})]})]},t)}):c(m,{text:`No Studio-created workflows yet.`})}):null})]})]})})}),c(`div`,{className:`grid auto-rows-max content-start self-start gap-4`,children:[J?.requiresSave&&(J?.repairedAgentIds.length||J?.missingNodeAgentIds.length)?c(f,{title:`Repair Applied`,subtitle:`Studio repaired runtime dependencies so this workflow can be saved and run locally.`,actions:c(`button`,{className:`tcp-btn-primary inline-flex items-center gap-2`,onClick:()=>$.mutate(),disabled:$.isPending,children:[c(`i`,{"data-lucide":$.isPending?`loader-circle`:`save`}),$.isPending?`Saving...`:`Save Repaired Workflow`]}),children:c(`div`,{className:`grid gap-2 text-sm text-slate-300`,children:[J.repairedAgentIds.length?c(`div`,{children:[`Repaired missing template links for: `,J.repairedAgentIds.join(`, `)]}):null,J.missingNodeAgentIds.length?c(`div`,{children:[`Stages still reference missing agents:`,` `,J.missingNodeAgentIds.join(`, `)]}):null,c(`div`,{className:`text-xs text-slate-400`,children:`Save this workflow to persist the repaired local-first configuration.`})]})}):null,c(f,{title:`Workflow Settings`,subtitle:`Name, schedule, workspace, and save behavior.`,children:c(`div`,{className:`grid gap-4 xl:grid-cols-[minmax(0,1.3fr)_minmax(18rem,0.95fr)]`,children:[c(`div`,{className:`grid content-start gap-3`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Name`}),c(`input`,{className:`tcp-input text-sm`,value:H.name,onInput:e=>Q({name:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Description`}),c(`textarea`,{className:`tcp-input min-h-[88px] text-sm`,value:H.description,onInput:e=>Q({description:e.target.value})})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Workspace Root`}),c(`div`,{className:`grid gap-2 md:grid-cols-[auto_1fr_auto]`,children:[c(`button`,{className:`tcp-btn h-10 px-3`,type:`button`,onClick:()=>{ot(T(H.workspaceRoot||k||`/`)||`/`),ct(``),it(!0)},children:[c(`i`,{"data-lucide":`folder-open`}),`Browse`]}),c(`input`,{className:`tcp-input text-sm ${bt?`border-red-500/60 text-red-100`:``}`,value:H.workspaceRoot,readOnly:!0,placeholder:`No local directory selected. Use Browse.`}),c(`button`,{className:`tcp-btn h-10 px-3`,type:`button`,onClick:()=>Q({workspaceRoot:``}),disabled:!H.workspaceRoot,children:[c(`i`,{"data-lucide":`x`}),`Clear`]})]}),bt?c(`span`,{className:`text-xs text-red-300`,children:bt}):null]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Output Targets`}),c(`input`,{className:`tcp-input text-sm`,value:N(H.outputTargets),onInput:e=>Q({outputTargets:M(e.target.value)}),placeholder:`content-brief.md, approved-post.md`}),c(`span`,{className:`text-[11px] text-slate-500`,children:[`Supported runtime tokens: `,pe.join(`, `),`. Legacy patterns like `,c(`code`,{children:`YYYY-MM-DD_HH-MM-SS`}),` are normalized on save.`]}),_t.length?c(`div`,{className:`rounded-lg border border-amber-500/30 bg-amber-500/8 px-3 py-2 text-[11px] text-amber-100`,children:[c(`div`,{className:`font-medium uppercase tracking-wide text-amber-200/90`,children:`Output path warnings`}),_t.slice(0,3).map(e=>c(`div`,{className:`mt-1`,children:e},e))]}):null,vt.length?c(`div`,{className:`rounded-lg border border-slate-700/60 bg-slate-950/30 px-3 py-2 text-[11px] text-slate-300`,children:[c(`div`,{className:`font-medium uppercase tracking-wide text-slate-500`,children:`Output path preview`}),vt.slice(0,8).map(e=>c(`div`,{className:`mt-2 grid gap-1 border-t border-slate-800/70 pt-2 first:mt-1 first:border-t-0 first:pt-0`,children:[c(`div`,{className:`text-slate-400`,children:e.label}),c(`div`,{children:[`Draft: `,c(`code`,{children:e.raw||e.canonical})]}),c(`div`,{children:[`Saved: `,c(`code`,{children:e.canonical})]}),c(`div`,{children:[`Next run preview: `,c(`code`,{children:e.resolved})]}),e.warning?c(`div`,{className:`text-amber-200`,children:e.warning}):null]},e.id))]}):null]})]}),c(`div`,{className:`grid content-start gap-3`,children:[c(`div`,{className:`grid gap-3 md:grid-cols-2 xl:grid-cols-1 2xl:grid-cols-2`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Status`}),c(`select`,{className:`tcp-input text-sm`,value:H.status,onInput:e=>Q({status:e.target.value}),children:[c(`option`,{value:`draft`,children:`draft`}),c(`option`,{value:`active`,children:`active`}),c(`option`,{value:`paused`,children:`paused`})]})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Max Parallel Agents`}),c(`input`,{className:`tcp-input text-sm`,value:H.maxParallelAgents,onInput:e=>Q({maxParallelAgents:e.target.value})})]})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Schedule`}),c(`select`,{className:`tcp-input text-sm`,value:H.scheduleType,onInput:e=>Q({scheduleType:e.target.value}),children:[c(`option`,{value:`manual`,children:`manual`}),c(`option`,{value:`cron`,children:`cron`}),c(`option`,{value:`interval`,children:`interval`})]})]}),H.scheduleType===`cron`?c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Cron Expression`}),c(`input`,{className:`tcp-input text-sm`,value:H.cronExpression,onInput:e=>Q({cronExpression:e.target.value}),placeholder:`0 9 * * 1`})]}):null,H.scheduleType===`interval`?c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Interval Seconds`}),c(`input`,{className:`tcp-input text-sm`,value:H.intervalSeconds,onInput:e=>Q({intervalSeconds:e.target.value})})]}):null,c(`label`,{className:`flex items-center gap-2 text-sm text-slate-300`,children:[c(`input`,{type:`checkbox`,checked:q,onInput:e=>Xe(e.target.checked)}),`Save agent prompts as reusable templates`]}),c(`div`,{className:`text-xs text-slate-400`,children:`Off: this workflow runs from Studio-local prompts only. On: Studio also creates shared Agent Team templates and links the workflow to them at runtime.`}),c(`div`,{className:`text-xs text-slate-500`,children:[`Default model fallback:`,` `,I.provider&&I.model?`${I.provider}/${I.model}`:`No provider default configured in Settings.`]}),c(`label`,{className:`flex items-center gap-2 text-sm text-slate-300`,children:[c(`input`,{type:`checkbox`,checked:H.useSharedModel,onInput:e=>{let t=e.target.checked,n=Ee(H.agents);Q({useSharedModel:t,sharedModelProvider:t?T(H.sharedModelProvider)||n.provider||I.provider:H.sharedModelProvider,sharedModelId:t?T(H.sharedModelId)||n.model||I.model:H.sharedModelId})}}),`Use one model for all agents in this workflow`]}),H.useSharedModel?c(t,{children:[c(`div`,{className:`grid gap-3 md:grid-cols-2 xl:grid-cols-1 2xl:grid-cols-2`,children:[c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Shared Model Provider`}),c(`select`,{className:`tcp-input text-sm`,value:H.sharedModelProvider,onInput:e=>{let t=e.target.value,n=z(P,t);Q({sharedModelProvider:t,sharedModelId:n.includes(H.sharedModelId)?H.sharedModelId:n[0]||H.sharedModelId})},children:[c(`option`,{value:``,children:`Select provider...`}),P.map(e=>c(`option`,{value:e.id,children:e.id},e.id))]})]}),c(`label`,{className:`grid gap-1`,children:[c(`span`,{className:`text-xs text-slate-400`,children:`Shared Model`}),z(P,H.sharedModelProvider).length?c(`select`,{className:`tcp-input text-sm`,value:H.sharedModelId,onInput:e=>Q({sharedModelId:e.target.value}),children:z(P,H.sharedModelProvider).map(e=>c(`option`,{value:e,children:e},e))}):c(`input`,{className:`tcp-input text-sm`,value:H.sharedModelId,onInput:e=>Q({sharedModelId:e.target.value}),placeholder:`provider-specific model id`})]})]}),c(`div`,{className:`rounded-lg border border-amber-500/20 bg-amber-500/8 px-3 py-2 text-xs text-amber-100`,children:`Shared model mode applies the same provider/model to every agent on save and while editing.`})]}):null,c(`label`,{className:`flex items-center gap-2 text-sm text-slate-300`,children:[c(`input`,{type:`checkbox`,checked:Ze,onInput:e=>Qe(e.target.checked)}),`Run workflow immediately after save`]}),J&&!J.requiresSave&&J.repairedAgentIds.length?c(`div`,{className:`rounded-lg border border-emerald-500/30 bg-emerald-500/8 px-3 py-2 text-xs text-emerald-100`,children:`Repaired template links were saved successfully. This workflow is now using local Studio prompts and can run normally.`}):null]})]})}),rt?c(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,children:[c(`button`,{type:`button`,className:`tcp-confirm-backdrop`,"aria-label":`Close workspace directory dialog`,onClick:()=>{it(!1),ct(``)}}),c(`div`,{className:`tcp-confirm-dialog max-w-2xl`,children:[c(`h3`,{className:`tcp-confirm-title`,children:`Select Workspace Folder`}),c(`p`,{className:`tcp-confirm-message`,children:[`Current: `,Ct||at||`n/a`]}),c(`div`,{className:`mb-2 flex flex-wrap gap-2`,children:[c(`button`,{className:`tcp-btn`,type:`button`,onClick:()=>{St&&ot(St)},disabled:!St,children:[c(`i`,{"data-lucide":`arrow-left-to-line`}),`Up`]}),c(`button`,{className:`tcp-btn-primary`,type:`button`,onClick:()=>{Ct&&(Q({workspaceRoot:Ct}),it(!1),ct(``),_(`ok`,`Workspace selected: ${Ct}`))},disabled:!Ct,children:[c(`i`,{"data-lucide":`badge-check`}),`Select This Folder`]}),c(`button`,{className:`tcp-btn`,type:`button`,onClick:()=>{it(!1),ct(``)},children:[c(`i`,{"data-lucide":`x`}),`Close`]})]}),c(`div`,{className:`mb-2`,children:c(`input`,{className:`tcp-input`,placeholder:`Type to filter folders...`,value:st,onInput:e=>ct(e.target.value)})}),c(`div`,{className:`max-h-[360px] overflow-auto rounded-lg border border-slate-700/60 bg-slate-900/20 p-2`,children:wt.length?wt.map(e=>c(`button`,{className:`tcp-list-item mb-1 w-full text-left`,type:`button`,onClick:()=>ot(String(e?.path||``)),children:c(`span`,{className:`inline-flex items-center gap-2`,children:[c(`i`,{"data-lucide":`folder-open`}),c(`span`,{children:String(e?.name||e?.path||``)})]})},String(e?.path||e?.name))):c(m,{text:T(st)?`No folders match your search.`:`No subdirectories in this folder.`})})]})]}):null,lt?c(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,children:[c(`button`,{type:`button`,className:`tcp-confirm-backdrop`,"aria-label":`Close delete workflow dialog`,onClick:()=>ut(null)}),c(`div`,{className:`tcp-confirm-dialog w-[min(34rem,96vw)]`,children:[c(`h3`,{className:`tcp-confirm-title`,children:`Delete Studio workflow`}),c(`p`,{className:`tcp-confirm-message`,children:[`This will permanently remove `,c(`strong`,{children:lt.title}),`.`]}),c(`div`,{className:`tcp-confirm-actions mt-3`,children:[c(`button`,{className:`tcp-btn inline-flex items-center gap-2`,onClick:()=>ut(null),children:[c(`i`,{"data-lucide":`x`}),`Cancel`]}),c(`button`,{className:`tcp-btn-danger inline-flex items-center gap-2`,disabled:Lt.isPending,onClick:()=>Lt.mutate(lt.automationId,{onSettled:()=>ut(null)}),children:[c(`i`,{"data-lucide":`trash-2`}),Lt.isPending?`Deleting...`:`Delete workflow`]})]})]})]}):null,c(f,{title:`Workflow Map`,subtitle:`Select a stage to edit its objective, dependencies, and bound agent.`,children:Et.length?c(`div`,{className:`grid gap-3 xl:grid-cols-4 xl:items-start`,children:Et.map(([e,t])=>c(`div`,{className:`grid content-start gap-2`,children:[c(`div`,{className:`text-xs uppercase tracking-wide text-slate-500`,children:[`Column `,e+1]}),t.map(e=>{let t=H.agents.find(t=>t.agentId===e.agentId);return c(`button`,{className:`tcp-list-item flex flex-col text-left ${e.nodeId===W?`border-emerald-400/60 bg-emerald-500/10`:``}`,onClick:()=>{G(e.nodeId),K(e.agentId)},children:[c(`div`,{className:`flex items-center justify-between gap-2`,children:[c(`strong`,{children:e.title}),c(`span`,{className:`tcp-badge-info`,children:e.outputKind||`artifact`})]}),c(`div`,{className:`mt-1 text-xs text-slate-400`,children:t?.displayName||e.agentId||`Unassigned agent`}),c(`div`,{className:`mt-2 text-sm text-slate-300`,children:e.objective}),e.outputPath?c(`div`,{className:`mt-2 text-xs text-emerald-200`,children:[`output: `,e.outputPath]}):null,c(`div`,{className:`mt-auto flex flex-wrap gap-1 pt-3`,children:e.dependsOn.length?e.dependsOn.map(t=>c(`span`,{className:`tcp-badge-warn`,children:[`<-`,` `,t]},`${e.nodeId}-${t}`)):c(`span`,{className:`tcp-badge-info`,children:`start`})})]},e.nodeId)})]},e))}):c(m,{text:`No stages yet. Add one to start shaping the workflow.`})}),c(f,{title:`Agent Directory`,subtitle:`All agents currently participating in this workflow.`,children:c(`div`,{className:`grid gap-2 md:grid-cols-2`,children:H.agents.map(e=>c(`button`,{className:`tcp-list-item text-left ${Z?.agentId===e.agentId?`border-emerald-400/60 bg-emerald-500/10`:``}`,onClick:()=>{K(e.agentId);let t=H.nodes.find(t=>t.agentId===e.agentId);t&&G(t.nodeId)},children:[c(`div`,{className:`flex items-center justify-between gap-2`,children:[c(`strong`,{children:e.displayName||e.agentId}),c(`div`,{className:`flex flex-wrap items-center justify-end gap-2`,children:[c(`span`,{className:`tcp-badge-info`,children:e.role}),J?.repairedAgentIds.includes(e.agentId)?c(`span`,{className:`tcp-badge-warn`,children:`missing/repaired`}):T(e.linkedTemplateId||e.templateId)?A.has(T(e.linkedTemplateId||e.templateId))?c(`span`,{className:`tcp-badge-info`,children:`linked`}):c(`span`,{className:`tcp-badge-warn`,children:`missing/repaired`}):c(`span`,{className:`tcp-badge-muted`,children:`local`})]})]}),c(`div`,{className:`mt-1 text-xs text-slate-400`,children:e.agentId}),e.linkedTemplateId?c(`div`,{className:`mt-2 text-xs text-emerald-200`,children:[`linked template: `,e.linkedTemplateId]}):null]},e.agentId))})})]}),c(`div`,{className:`grid auto-rows-max content-start self-start gap-4`,children:c(qe,{draft:H,selectedNode:X,selectedNodeInputFiles:mt,selectedNodeOutputFiles:ht,selectedNodeOutputPathPreview:yt,selectedAgent:Z,selectedTemplateLoadId:Je,templateRows:se,templateMap:A,repairState:J,providerOptions:P,mcpServers:Ie,mcpServerRows:Ge,removeSelectedNode:Mt,removeSelectedAgent:Nt,updateNode:Ot,updateAgent:kt,setSelectedAgentId:K,setSelectedNodeId:G,setSelectedTemplateLoadId:Ye,loadTemplateIntoSelectedAgent:Pt})})]})})})}export{K as WorkflowStudioPage};