@frumu/tandem-panel 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/setup.js +1 -0
- package/dist/assets/AutomationsPage-BGqpmilp.js +946 -0
- package/dist/assets/BugMonitorPage-BVzdj9y-.js +4 -0
- package/dist/assets/ChannelsPage-B-InJ4Yh.js +1 -0
- package/dist/assets/ChatInterfacePanel-BrMo4cXg.js +1 -0
- package/dist/assets/ChatPage-Bc-BfOG1.js +1 -0
- package/dist/assets/CodingWorkflowsPage-xgfwLRlt.js +8 -0
- package/dist/assets/ControlPanelDialogs-yFfCht3Y.js +1 -0
- package/dist/assets/DashboardPage-CrA1itFc.js +1 -0
- package/dist/assets/ExperimentsPage-Bkg1_6rw.js +84 -0
- package/dist/assets/FilesPage-DChyHlO_.js +1 -0
- package/dist/assets/IntentPlannerPage-Dti1h8Tm.js +5 -0
- package/dist/assets/LazyJson-vfWw7G9F.js +1 -0
- package/dist/assets/MarketplacePage-90fAVNGg.js +1 -0
- package/dist/assets/McpToolAllowlistEditor-BzQ64HrZ.js +1 -0
- package/dist/assets/MemoryImportDialog-DSpS1JF5.js +1 -0
- package/dist/assets/MemoryPage-DRRLgoc0.js +1 -0
- package/dist/assets/OrchestratorPage-CYU-ESPI.js +3 -0
- package/dist/assets/PacksPage-dRmjjdKD.js +3 -0
- package/dist/assets/PlannerDiagnosticsPanel-C1uIuRIx.js +1 -0
- package/dist/assets/ProviderModelSelector-BdtOpkJR.js +1 -0
- package/dist/assets/RunsPage-DEy8vbRT.js +1 -0
- package/dist/assets/SettingsPage-CwH_FzOs.js +5 -0
- package/dist/assets/TaskBoard-CCY_Qy5S.js +1 -0
- package/dist/assets/TeamsPage-Dn81V0EB.js +4472 -0
- package/dist/assets/TimezoneField-B5i---lF.js +1 -0
- package/dist/assets/WorkflowStudioPage-yFhlA4KV.js +1854 -0
- package/dist/assets/WorkflowsPage-vmaKHFox.js +2 -0
- package/dist/assets/chatPageHelpers-Dmb4waDk.js +1 -0
- package/dist/assets/explorerHandoff-BPKxMR82.js +1 -0
- package/dist/assets/format-DyX5imzJ.js +1 -0
- package/dist/assets/fullcalendar-Bn75j0xM.js +1 -0
- package/dist/assets/index-C8Bjo7hU.css +1 -0
- package/dist/assets/index-TvymvGva.js +3 -0
- package/dist/assets/messages-uD0aB_MZ.js +3 -0
- package/dist/assets/motion-B3ZE8SGR.js +9 -0
- package/dist/assets/plannerShared-Dx7-Sxpc.js +1 -0
- package/dist/assets/preact-vendor-DaCG_P2o.js +1 -0
- package/dist/assets/react-query-BIbNygEJ.js +1 -0
- package/dist/assets/sse-B4A2m-Nk.js +2 -0
- package/dist/assets/useEngineStream-Diqri33l.js +1 -0
- package/dist/assets/vendor-DSaYtO9f.js +156 -0
- package/dist/assets/workflowStability-C8USyGOY.js +2 -0
- package/dist/index.html +8 -7
- package/lib/automations/workflow-list.js +147 -0
- package/lib/setup/control-panel-preferences.js +4 -0
- package/package.json +3 -3
- package/server/routes/capabilities.js +1 -0
- package/server/routes/knowledgebase.js +7 -1
- package/dist/assets/index-BL-9rGEh.css +0 -1
- package/dist/assets/index-DhoScTZK.js +0 -7379
- package/dist/assets/motion-CBnf8hfk.js +0 -9
- package/dist/assets/preact-vendor-B239Onrg.js +0 -1
- package/dist/assets/react-query-_hsOQSt5.js +0 -1
- package/dist/assets/vendor-DZYPF2Pz.js +0 -156
- /package/dist/assets/{markdown-Dd89TVib.js → markdown-Dwwtq3bu.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-TvymvGva.js";import{g as h}from"./workflowStability-C8USyGOY.js";import{r as g,t as _}from"./McpToolAllowlistEditor-BzQ64HrZ.js";import{r as v}from"./plannerShared-Dx7-Sxpc.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};
|