@growthub/cli 0.13.4 → 0.13.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.
Files changed (52) hide show
  1. package/assets/worker-kits/growthub-custom-workspace-starter-v1/QUICKSTART.md +19 -0
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/.env.example +8 -0
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/README.md +4 -0
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/action/execute/route.js +60 -0
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/actions/route.js +50 -0
  6. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/connect-session/route.js +68 -0
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/connection-status/route.js +56 -0
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/proxy/route.js +67 -0
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/integrations/nango/status/route.js +50 -0
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/metadata-graph/route.js +184 -0
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +25 -2
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/AgentSwarmPanel.jsx +326 -0
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +161 -50
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/NangoConnectionPanel.jsx +496 -0
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphEmptyCanvas.jsx +6 -0
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +88 -1
  17. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +41 -0
  18. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/WorkspaceGraphInspectorPanel.jsx +226 -0
  19. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +120 -17
  20. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/nango/page.jsx +167 -0
  21. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +1 -0
  22. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +67 -11
  23. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +31 -10
  24. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +16 -14
  25. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/env.js +7 -0
  26. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/nango/index.js +38 -0
  27. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/nango/nango-adapter.js +552 -0
  28. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/nango/nango-config-loader.js +202 -0
  29. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/nango/nango-schema.js +303 -0
  30. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/resolver-loader.js +49 -10
  31. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/source-resolver-registry.js +1 -1
  32. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/templates/nango.js +49 -0
  33. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/templates/template-registry.js +4 -2
  34. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-agent-swarm.js +923 -0
  35. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +14 -1
  36. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +218 -7
  37. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +28 -0
  38. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-inputs.js +43 -0
  39. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +3 -1
  40. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +36 -0
  41. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-chart-values.js +53 -0
  42. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +2 -1
  43. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-graph.js +646 -0
  44. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-selectors.js +249 -0
  45. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +1186 -0
  46. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +102 -3
  47. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +1 -0
  48. package/assets/worker-kits/growthub-custom-workspace-starter-v1/bundles/growthub-custom-workspace-starter-v1.json +1 -0
  49. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +7 -0
  50. package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/seeded-configs/project-management.config.json +276 -0
  51. package/dist/index.js +127 -44
  52. package/package.json +1 -1
@@ -0,0 +1,326 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import { Plus, Trash2 } from "lucide-react";
5
+ import { HOST_AUTH_CATALOG } from "@/lib/sandbox-agent-host-catalog";
6
+
7
+ function getHostOptions() {
8
+ return Object.entries(HOST_AUTH_CATALOG || {}).map(([slug, host]) => ({
9
+ value: slug,
10
+ label: host?.label || slug
11
+ }));
12
+ }
13
+
14
+ function patchOrchestrator(graph, patch) {
15
+ const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
16
+ return {
17
+ ...graph,
18
+ nodes: nodes.map((node) =>
19
+ node?.type === "thinAdapter"
20
+ ? { ...node, config: { ...(node.config || {}), ...patch } }
21
+ : node
22
+ )
23
+ };
24
+ }
25
+
26
+ function patchSynthesis(graph, patch) {
27
+ const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
28
+ return {
29
+ ...graph,
30
+ nodes: nodes.map((node) =>
31
+ node?.type === "tool-result"
32
+ ? { ...node, config: { ...(node.config || {}), ...patch } }
33
+ : node
34
+ )
35
+ };
36
+ }
37
+
38
+ function patchSubagent(graph, nodeId, patch) {
39
+ const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
40
+ return {
41
+ ...graph,
42
+ nodes: nodes.map((node) =>
43
+ node?.type === "ai-agent" && String(node.id) === String(nodeId)
44
+ ? {
45
+ ...node,
46
+ label: patch.role != null ? String(patch.role) : node.label,
47
+ config: { ...(node.config || {}), ...patch }
48
+ }
49
+ : node
50
+ )
51
+ };
52
+ }
53
+
54
+ function addSubagent(graph, defaults = {}) {
55
+ const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
56
+ const edges = Array.isArray(graph?.edges) ? graph.edges : [];
57
+ const existing = new Set(nodes.map((n) => String(n?.id || "")));
58
+ let id = `subagent-${nodes.filter((n) => n?.type === "ai-agent").length + 1}`;
59
+ let index = 2;
60
+ while (existing.has(id)) {
61
+ id = `subagent-${index}`;
62
+ index += 1;
63
+ }
64
+ const node = {
65
+ id,
66
+ type: "ai-agent",
67
+ label: defaults.role || "Subagent",
68
+ subtitle: "Swarm subagent",
69
+ config: {
70
+ role: defaults.role || "Subagent",
71
+ description: defaults.description || "",
72
+ taskPrompt: defaults.taskPrompt || "",
73
+ tools: Array.isArray(defaults.tools) ? defaults.tools : [],
74
+ agentHost: defaults.agentHost || "",
75
+ required: true,
76
+ canReadWorkspace: true,
77
+ canWriteDraft: false,
78
+ networkAccess: false,
79
+ maxTokens: 0,
80
+ timeoutMs: 0
81
+ }
82
+ };
83
+ const nextEdges = [...edges];
84
+ if (nodes.some((n) => n?.type === "thinAdapter")) {
85
+ nextEdges.push({ from: "orchestrator", to: id, passes: "subtask-assignment" });
86
+ }
87
+ if (nodes.some((n) => n?.type === "tool-result")) {
88
+ const synth = nodes.find((n) => n?.type === "tool-result");
89
+ nextEdges.push({ from: id, to: synth.id, passes: "subtask-result" });
90
+ }
91
+ return { ...graph, nodes: [...nodes, node], edges: nextEdges };
92
+ }
93
+
94
+ function removeSubagent(graph, nodeId) {
95
+ const id = String(nodeId);
96
+ return {
97
+ ...graph,
98
+ nodes: (Array.isArray(graph?.nodes) ? graph.nodes : []).filter((n) => String(n.id) !== id),
99
+ edges: (Array.isArray(graph?.edges) ? graph.edges : []).filter(
100
+ (edge) => String(edge.from) !== id && String(edge.to) !== id
101
+ )
102
+ };
103
+ }
104
+
105
+ function patchSwarmConfig(graph, patch) {
106
+ const base = graph?.swarm && typeof graph.swarm === "object" ? graph.swarm : {};
107
+ return { ...graph, swarm: { ...base, ...patch } };
108
+ }
109
+
110
+ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
111
+ const hostOptions = useMemo(getHostOptions, []);
112
+ if (!graph || typeof graph !== "object") return null;
113
+
114
+ const orchestrator = (Array.isArray(graph.nodes) ? graph.nodes : []).find((n) => n?.type === "thinAdapter") || null;
115
+ const subagents = (Array.isArray(graph.nodes) ? graph.nodes : []).filter((n) => n?.type === "ai-agent");
116
+ const synthesis = (Array.isArray(graph.nodes) ? graph.nodes : []).find((n) => n?.type === "tool-result") || null;
117
+ const swarmCfg = graph.swarm && typeof graph.swarm === "object" ? graph.swarm : {};
118
+ const weights = swarmCfg.rewardWeights || { parallel: 0.25, finish: 0.35, outcome: 0.4 };
119
+
120
+ function patchGraph(updater) {
121
+ if (typeof updater !== "function") return;
122
+ onGraphChange?.(updater);
123
+ }
124
+
125
+ return (
126
+ <div className="dm-orchestration-config dm-agent-swarm-panel">
127
+ <div className="dm-orchestration-config__pane">
128
+ <div className="dm-orchestration-config__section">
129
+ <span>Orchestrator</span>
130
+ <label className="dm-orchestration-config__field">
131
+ <span>Prompt</span>
132
+ <textarea
133
+ rows={3}
134
+ value={orchestrator?.config?.prompt || ""}
135
+ disabled={disabled || !orchestrator}
136
+ onChange={(e) => patchGraph((g) => patchOrchestrator(g, { prompt: e.target.value }))}
137
+ />
138
+ </label>
139
+ </div>
140
+
141
+ <div className="dm-orchestration-config__section">
142
+ <div className="dm-agent-swarm-panel__row">
143
+ <span>Subagents · {subagents.length}</span>
144
+ <button
145
+ type="button"
146
+ className="dm-btn-outline"
147
+ disabled={disabled}
148
+ onClick={() => patchGraph((g) => addSubagent(g))}
149
+ >
150
+ <Plus size={12} aria-hidden="true" /> Add
151
+ </button>
152
+ </div>
153
+ {subagents.length === 0 && (
154
+ <p className="dm-orchestration-config__hint">Add at least one subagent.</p>
155
+ )}
156
+ {subagents.map((node) => {
157
+ const cfg = node.config || {};
158
+ return (
159
+ <div key={node.id} className="dm-agent-swarm-panel__subagent">
160
+ <div className="dm-agent-swarm-panel__row">
161
+ <input
162
+ className="dm-agent-swarm-panel__role"
163
+ placeholder="Role"
164
+ value={cfg.role || node.label || ""}
165
+ disabled={disabled}
166
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { role: e.target.value }))}
167
+ />
168
+ <button
169
+ type="button"
170
+ className="dm-btn-ghost"
171
+ disabled={disabled}
172
+ onClick={() => patchGraph((g) => removeSubagent(g, node.id))}
173
+ aria-label={`Remove ${cfg.role || node.id}`}
174
+ >
175
+ <Trash2 size={12} aria-hidden="true" />
176
+ </button>
177
+ </div>
178
+ <label className="dm-orchestration-config__field">
179
+ <span>Description</span>
180
+ <input
181
+ placeholder="One-sentence charter"
182
+ value={cfg.description || ""}
183
+ disabled={disabled}
184
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { description: e.target.value }))}
185
+ />
186
+ </label>
187
+ <label className="dm-orchestration-config__field">
188
+ <span>Task</span>
189
+ <textarea
190
+ rows={2}
191
+ value={cfg.taskPrompt || ""}
192
+ disabled={disabled}
193
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { taskPrompt: e.target.value }))}
194
+ />
195
+ </label>
196
+ <label className="dm-orchestration-config__field">
197
+ <span>Tools</span>
198
+ <input
199
+ placeholder="read, summarize"
200
+ value={Array.isArray(cfg.tools) ? cfg.tools.join(", ") : ""}
201
+ disabled={disabled}
202
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, {
203
+ tools: e.target.value.split(",").map((t) => t.trim()).filter(Boolean)
204
+ }))}
205
+ />
206
+ </label>
207
+ <label className="dm-orchestration-config__field">
208
+ <span>Max tokens</span>
209
+ <input
210
+ type="number"
211
+ min="0"
212
+ placeholder="0 = inherit"
213
+ value={cfg.maxTokens || 0}
214
+ disabled={disabled}
215
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { maxTokens: Math.max(0, Number(e.target.value) || 0) }))}
216
+ />
217
+ </label>
218
+ <label className="dm-orchestration-config__field">
219
+ <span>Agent host</span>
220
+ <select
221
+ value={cfg.agentHost || ""}
222
+ disabled={disabled}
223
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { agentHost: e.target.value }))}
224
+ >
225
+ <option value="">Inherit</option>
226
+ {hostOptions.map((opt) => (
227
+ <option key={opt.value} value={opt.value}>{opt.label}</option>
228
+ ))}
229
+ </select>
230
+ </label>
231
+ <label className="dm-orchestration-config__field dm-orchestration-config__field-inline">
232
+ <input
233
+ type="checkbox"
234
+ checked={cfg.required !== false}
235
+ disabled={disabled}
236
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { required: e.target.checked }))}
237
+ />
238
+ <span>Required</span>
239
+ </label>
240
+ <label
241
+ className="dm-orchestration-config__field dm-orchestration-config__field-inline"
242
+ title="Network is granted only when both this and the row's networkAllow are on."
243
+ >
244
+ <input
245
+ type="checkbox"
246
+ checked={cfg.networkAccess === true}
247
+ disabled={disabled}
248
+ onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { networkAccess: e.target.checked }))}
249
+ />
250
+ <span>Network</span>
251
+ </label>
252
+ </div>
253
+ );
254
+ })}
255
+ </div>
256
+
257
+ <div className="dm-orchestration-config__section">
258
+ <span>Concurrency & reward</span>
259
+ <label className="dm-orchestration-config__field">
260
+ <span>Max concurrency</span>
261
+ <input
262
+ type="number"
263
+ min="1"
264
+ value={swarmCfg.maxConcurrency ?? subagents.length}
265
+ disabled={disabled}
266
+ onChange={(e) => patchGraph((g) => patchSwarmConfig(g, { maxConcurrency: Math.max(1, Number(e.target.value) || 1) }))}
267
+ />
268
+ </label>
269
+ <div className="dm-agent-swarm-panel__weights">
270
+ {[
271
+ ["parallel", "Parallel"],
272
+ ["finish", "Finish"],
273
+ ["outcome", "Outcome"]
274
+ ].map(([key, label]) => (
275
+ <label key={key} className="dm-orchestration-config__field">
276
+ <span>{label}</span>
277
+ <input
278
+ type="number"
279
+ step="0.05"
280
+ min="0"
281
+ max="1"
282
+ value={weights[key] ?? 0}
283
+ disabled={disabled}
284
+ onChange={(e) =>
285
+ patchGraph((g) =>
286
+ patchSwarmConfig(g, {
287
+ rewardWeights: { ...weights, [key]: Number(e.target.value) || 0 }
288
+ })
289
+ )
290
+ }
291
+ />
292
+ </label>
293
+ ))}
294
+ </div>
295
+ <label className="dm-orchestration-config__field">
296
+ <span>Outcome criteria</span>
297
+ <textarea
298
+ rows={2}
299
+ value={swarmCfg.outcomeCriteria || ""}
300
+ disabled={disabled}
301
+ onChange={(e) => patchGraph((g) => patchSwarmConfig(g, { outcomeCriteria: e.target.value }))}
302
+ />
303
+ </label>
304
+ <p className="dm-orchestration-config__hint">
305
+ Outcome is parsed from the synthesizer's last <code>OUTCOME_SCORE: 0–1</code>; otherwise falls back to required-completion.
306
+ </p>
307
+ </div>
308
+
309
+ {synthesis && (
310
+ <div className="dm-orchestration-config__section">
311
+ <span>Synthesizer</span>
312
+ <label className="dm-orchestration-config__field">
313
+ <span>Prompt</span>
314
+ <textarea
315
+ rows={2}
316
+ value={synthesis?.config?.outcomePrompt || ""}
317
+ disabled={disabled}
318
+ onChange={(e) => patchGraph((g) => patchSynthesis(g, { outcomePrompt: e.target.value }))}
319
+ />
320
+ </label>
321
+ </div>
322
+ )}
323
+ </div>
324
+ </div>
325
+ );
326
+ }