@growthub/cli 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +50 -25
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryActionCard.jsx +141 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryReviewModal.jsx +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +522 -35
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +242 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphEmptyCanvas.jsx +52 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +1203 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +163 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxOrchestrationEditorPanel.jsx +190 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxToolConfirmModal.jsx +64 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxToolDraftPanel.jsx +376 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/page.jsx +6 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +1062 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +10 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +906 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/page.jsx +12 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +492 -28
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +114 -30
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/data-model/field-contracts.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/nav-workflows.js +54 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +322 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +734 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +73 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-sidecar-routing.js +24 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +2 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +21 -1
- package/package.json +1 -1
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* Data Sources downstream can normalize either locality.
|
|
24
24
|
*
|
|
25
25
|
* Request body:
|
|
26
|
-
* { objectId: string, name: string }
|
|
26
|
+
* { objectId: string, name: string, useDraft?: boolean, draftGraph?: string | object }
|
|
27
27
|
*
|
|
28
28
|
* Response (success):
|
|
29
29
|
* {
|
|
@@ -75,6 +75,8 @@ import {
|
|
|
75
75
|
ensureSandboxAdaptersLoaded,
|
|
76
76
|
getSandboxAdapter
|
|
77
77
|
} from "@/lib/adapters/sandboxes";
|
|
78
|
+
import { runOrchestrationGraphIfPresent } from "@/lib/orchestration-graph-runner";
|
|
79
|
+
import { parseOrchestrationGraph } from "@/lib/orchestration-graph";
|
|
78
80
|
|
|
79
81
|
function envKeyCandidates(ref) {
|
|
80
82
|
const token = String(ref || "")
|
|
@@ -425,6 +427,7 @@ async function POST(request) {
|
|
|
425
427
|
|
|
426
428
|
const objectId = typeof body?.objectId === "string" ? body.objectId.trim() : "";
|
|
427
429
|
const name = typeof body?.name === "string" ? body.name.trim() : "";
|
|
430
|
+
const useDraft = body?.useDraft === true;
|
|
428
431
|
if (!objectId || !name) {
|
|
429
432
|
return NextResponse.json({ ok: false, error: "objectId and name are required" }, { status: 400 });
|
|
430
433
|
}
|
|
@@ -438,16 +441,23 @@ async function POST(request) {
|
|
|
438
441
|
return NextResponse.json({ ok: false, error: `no sandbox row named ${name} in object ${objectId}` }, { status: 404 });
|
|
439
442
|
}
|
|
440
443
|
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const
|
|
449
|
-
const
|
|
450
|
-
|
|
444
|
+
const draftGraph = useDraft
|
|
445
|
+
? parseOrchestrationGraph(body?.draftGraph || row.orchestrationDraftConfig || row.orchestrationDraftGraph)
|
|
446
|
+
: null;
|
|
447
|
+
const rowForRun = draftGraph
|
|
448
|
+
? { ...row, orchestrationGraph: draftGraph, orchestrationConfig: draftGraph }
|
|
449
|
+
: row;
|
|
450
|
+
|
|
451
|
+
const runLocality = normalizeRunLocality(rowForRun);
|
|
452
|
+
const runtime = KNOWN_SANDBOX_RUNTIMES.includes(rowForRun.runtime) ? rowForRun.runtime : "node";
|
|
453
|
+
let adapterId = (typeof rowForRun.adapter === "string" && rowForRun.adapter.trim()) ? rowForRun.adapter.trim() : DEFAULT_SANDBOX_ADAPTER;
|
|
454
|
+
const agentHost = typeof rowForRun.agentHost === "string" ? rowForRun.agentHost.trim() : "";
|
|
455
|
+
const schedulerRegistryId = typeof rowForRun.schedulerRegistryId === "string" ? rowForRun.schedulerRegistryId.trim() : "";
|
|
456
|
+
const networkAllow = coerceBoolean(rowForRun.networkAllow);
|
|
457
|
+
const allowList = parseSandboxAllowList(rowForRun.allowList);
|
|
458
|
+
const envRefSlugs = parseSandboxEnvRefs(rowForRun.envRefs);
|
|
459
|
+
const command = typeof rowForRun.command === "string" ? rowForRun.command : "";
|
|
460
|
+
const instructions = typeof rowForRun.instructions === "string" ? rowForRun.instructions.trim() : "";
|
|
451
461
|
const agentCommand = instructions
|
|
452
462
|
? `Instructions:\n${instructions}\n\nPrompt:\n${command}`
|
|
453
463
|
: command;
|
|
@@ -455,17 +465,17 @@ async function POST(request) {
|
|
|
455
465
|
adapterId === "local-intelligence"
|
|
456
466
|
? {
|
|
457
467
|
userIntent: agentCommand,
|
|
458
|
-
localModel: typeof
|
|
459
|
-
localEndpoint: typeof
|
|
468
|
+
localModel: typeof rowForRun.localModel === "string" ? rowForRun.localModel.trim() : "",
|
|
469
|
+
localEndpoint: typeof rowForRun.localEndpoint === "string" ? rowForRun.localEndpoint.trim() : "",
|
|
460
470
|
intelligenceAdapterMode:
|
|
461
|
-
typeof
|
|
462
|
-
?
|
|
471
|
+
typeof rowForRun.intelligenceAdapterMode === "string"
|
|
472
|
+
? rowForRun.intelligenceAdapterMode.trim().toLowerCase()
|
|
463
473
|
: "ollama",
|
|
464
474
|
}
|
|
465
475
|
: undefined;
|
|
466
|
-
const lifecycleStatus = String(
|
|
467
|
-
const version =
|
|
468
|
-
const requestedTimeout = Number(
|
|
476
|
+
const lifecycleStatus = String(rowForRun.lifecycleStatus || "draft").trim().toLowerCase() === "live" ? "live" : "draft";
|
|
477
|
+
const version = rowForRun.version ?? "";
|
|
478
|
+
const requestedTimeout = Number(rowForRun.timeoutMs);
|
|
469
479
|
const timeoutMs = Number.isFinite(requestedTimeout) && requestedTimeout > 0
|
|
470
480
|
? Math.min(requestedTimeout, SANDBOX_MAX_TIMEOUT_MS)
|
|
471
481
|
: SANDBOX_DEFAULT_TIMEOUT_MS;
|
|
@@ -503,16 +513,25 @@ async function POST(request) {
|
|
|
503
513
|
let result;
|
|
504
514
|
let effectiveAdapterId = adapterId;
|
|
505
515
|
|
|
506
|
-
|
|
516
|
+
const hasNativeGraph = Boolean(parseOrchestrationGraph(rowForRun.orchestrationGraph || rowForRun.orchestrationConfig));
|
|
517
|
+
if (hasNativeGraph && runLocality !== "serverless") {
|
|
518
|
+
const graphResult = await runOrchestrationGraphIfPresent({ workspaceConfig, row: rowForRun, timeoutMs });
|
|
519
|
+
if (graphResult !== null) {
|
|
520
|
+
result = graphResult;
|
|
521
|
+
effectiveAdapterId = "orchestration-graph";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (!result && runLocality === "serverless") {
|
|
507
526
|
effectiveAdapterId = "serverless";
|
|
508
527
|
result = await runServerlessScheduler({
|
|
509
528
|
workspaceConfig,
|
|
510
|
-
row,
|
|
529
|
+
row: rowForRun,
|
|
511
530
|
runId,
|
|
512
531
|
ranAt,
|
|
513
532
|
workspaceId: workspaceConfig?.id ?? null,
|
|
514
533
|
objectId,
|
|
515
|
-
sandboxName:
|
|
534
|
+
sandboxName: rowForRun.Name || name,
|
|
516
535
|
runtime,
|
|
517
536
|
adapterId,
|
|
518
537
|
agentHost,
|
|
@@ -525,7 +544,7 @@ async function POST(request) {
|
|
|
525
544
|
envRefsResolved,
|
|
526
545
|
envRefsMissing
|
|
527
546
|
});
|
|
528
|
-
} else {
|
|
547
|
+
} else if (!result) {
|
|
529
548
|
await ensureSandboxAdaptersLoaded();
|
|
530
549
|
const adapter = getSandboxAdapter(adapterId);
|
|
531
550
|
if (!adapter) {
|
|
@@ -547,7 +566,7 @@ async function POST(request) {
|
|
|
547
566
|
try {
|
|
548
567
|
result = await adapter.run({
|
|
549
568
|
runId,
|
|
550
|
-
name:
|
|
569
|
+
name: rowForRun.Name || name,
|
|
551
570
|
runtime,
|
|
552
571
|
agentHost,
|
|
553
572
|
command: adapterId === "local-agent-host" || adapterId === "local-intelligence" ? agentCommand : command,
|
|
@@ -594,7 +613,7 @@ async function POST(request) {
|
|
|
594
613
|
allowList,
|
|
595
614
|
result,
|
|
596
615
|
timeoutMs,
|
|
597
|
-
row
|
|
616
|
+
row: rowForRun
|
|
598
617
|
});
|
|
599
618
|
|
|
600
619
|
const sourceId = sandboxRunSourceId(objectId, row.Name || name);
|
|
@@ -633,7 +652,13 @@ async function POST(request) {
|
|
|
633
652
|
lastTested: ranAt,
|
|
634
653
|
lastRunId: runId,
|
|
635
654
|
lastSourceId: sourceIdValue,
|
|
636
|
-
lastResponse: compactResponse
|
|
655
|
+
lastResponse: compactResponse,
|
|
656
|
+
...(useDraft ? {
|
|
657
|
+
orchestrationDraftLastTested: ranAt,
|
|
658
|
+
orchestrationDraftLastRunId: runId,
|
|
659
|
+
orchestrationDraftLastStatus: status,
|
|
660
|
+
orchestrationDraftLastResponse: compactResponse
|
|
661
|
+
} : {})
|
|
637
662
|
};
|
|
638
663
|
});
|
|
639
664
|
return { ...entry, rows: nextRows };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Check, ExternalLink, Play, Terminal, X } from "lucide-react";
|
|
4
|
+
import { getApiRegistrySandboxToolState } from "@/lib/orchestration-graph";
|
|
5
|
+
|
|
6
|
+
export function ApiRegistryActionCard({
|
|
7
|
+
registryRow,
|
|
8
|
+
workspaceConfig,
|
|
9
|
+
disabled,
|
|
10
|
+
onCreateSandboxTool,
|
|
11
|
+
onOpenSandboxTool,
|
|
12
|
+
onRunSandboxTool,
|
|
13
|
+
onTestConnection,
|
|
14
|
+
testing,
|
|
15
|
+
sandboxRunning
|
|
16
|
+
}) {
|
|
17
|
+
const state = getApiRegistrySandboxToolState(registryRow, workspaceConfig);
|
|
18
|
+
|
|
19
|
+
if (state.kind === "incomplete") {
|
|
20
|
+
const checklist = state.checklist || [];
|
|
21
|
+
return (
|
|
22
|
+
<section className="dm-api-action-card dm-api-action-card-muted" aria-label="Complete API setup">
|
|
23
|
+
<div className="dm-api-action-card-body">
|
|
24
|
+
<p className="dm-api-action-card-eyebrow">API Registry</p>
|
|
25
|
+
<h3>Complete API setup</h3>
|
|
26
|
+
<p>
|
|
27
|
+
This API needs a registry ID, base URL, endpoint, method, and auth reference before it can become a sandbox tool.
|
|
28
|
+
</p>
|
|
29
|
+
<ul className="dm-api-action-checklist">
|
|
30
|
+
{checklist.map((item) => (
|
|
31
|
+
<li key={item.field} className={item.ok ? "is-done" : "is-pending"}>
|
|
32
|
+
{item.ok ? <Check size={14} aria-hidden="true" /> : <X size={14} aria-hidden="true" />}
|
|
33
|
+
<span>{item.field}</span>
|
|
34
|
+
</li>
|
|
35
|
+
))}
|
|
36
|
+
</ul>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (state.kind === "untested") {
|
|
43
|
+
return (
|
|
44
|
+
<section className="dm-api-action-card dm-api-action-card-muted" aria-label="Test API first">
|
|
45
|
+
<div className="dm-api-action-card-body">
|
|
46
|
+
<p className="dm-api-action-card-eyebrow">Sandbox tool</p>
|
|
47
|
+
<h3>Test this API first</h3>
|
|
48
|
+
<p>{state.message}</p>
|
|
49
|
+
</div>
|
|
50
|
+
<button
|
|
51
|
+
type="button"
|
|
52
|
+
className="dm-btn-primary-sm dm-api-action-card-cta"
|
|
53
|
+
disabled={disabled || testing}
|
|
54
|
+
onClick={onTestConnection}
|
|
55
|
+
>
|
|
56
|
+
{testing ? "Testing…" : "Test connection"}
|
|
57
|
+
</button>
|
|
58
|
+
</section>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (state.kind === "failed") {
|
|
63
|
+
return (
|
|
64
|
+
<section className="dm-api-action-card dm-api-action-card-muted" aria-label="API test failed">
|
|
65
|
+
<div className="dm-api-action-card-body">
|
|
66
|
+
<p className="dm-api-action-card-eyebrow">Connection</p>
|
|
67
|
+
<h3>API test failed</h3>
|
|
68
|
+
<p>{state.message}</p>
|
|
69
|
+
</div>
|
|
70
|
+
<button
|
|
71
|
+
type="button"
|
|
72
|
+
className="dm-btn-outline dm-api-action-card-cta"
|
|
73
|
+
disabled={disabled || testing}
|
|
74
|
+
onClick={onTestConnection}
|
|
75
|
+
>
|
|
76
|
+
{testing ? "Testing…" : "Retest"}
|
|
77
|
+
</button>
|
|
78
|
+
</section>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (state.kind === "existing") {
|
|
83
|
+
const toolName = String(state.row?.Name || "").trim();
|
|
84
|
+
return (
|
|
85
|
+
<section className="dm-api-action-card" aria-label="Sandbox tool ready">
|
|
86
|
+
<div className="dm-api-action-card-icon" aria-hidden="true">
|
|
87
|
+
<Terminal size={18} />
|
|
88
|
+
</div>
|
|
89
|
+
<div className="dm-api-action-card-body">
|
|
90
|
+
<p className="dm-api-action-card-eyebrow">Sandbox tool</p>
|
|
91
|
+
<h3>Sandbox tool ready</h3>
|
|
92
|
+
<p>{toolName} — governed row linked to this API Registry entry.</p>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="dm-api-action-card-actions">
|
|
95
|
+
<button
|
|
96
|
+
type="button"
|
|
97
|
+
className="dm-btn-outline dm-api-action-card-cta"
|
|
98
|
+
disabled={disabled || !toolName}
|
|
99
|
+
onClick={() => onOpenSandboxTool?.({ name: toolName })}
|
|
100
|
+
>
|
|
101
|
+
<ExternalLink size={14} aria-hidden="true" />
|
|
102
|
+
Open sandbox tool
|
|
103
|
+
</button>
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
className="dm-btn-primary-sm dm-api-action-card-cta"
|
|
107
|
+
disabled={disabled || sandboxRunning || !toolName}
|
|
108
|
+
onClick={() => onRunSandboxTool?.({ name: toolName })}
|
|
109
|
+
>
|
|
110
|
+
<Play size={14} aria-hidden="true" />
|
|
111
|
+
{sandboxRunning ? "Running…" : "Run sandbox"}
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</section>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<section className="dm-api-action-card" aria-label="Create sandbox tool">
|
|
120
|
+
<div className="dm-api-action-card-icon" aria-hidden="true">
|
|
121
|
+
<Terminal size={18} />
|
|
122
|
+
</div>
|
|
123
|
+
<div className="dm-api-action-card-body">
|
|
124
|
+
<p className="dm-api-action-card-eyebrow">API connected</p>
|
|
125
|
+
<h3>Create sandbox tool</h3>
|
|
126
|
+
<p>
|
|
127
|
+
This API is connected. Turn it into a sandbox tool that agents can run safely from this workspace.
|
|
128
|
+
</p>
|
|
129
|
+
<p className="dm-api-action-card-note">No secrets are stored. Nothing runs until you test the sandbox.</p>
|
|
130
|
+
</div>
|
|
131
|
+
<button
|
|
132
|
+
type="button"
|
|
133
|
+
className="dm-btn-primary-sm dm-api-action-card-cta"
|
|
134
|
+
disabled={disabled}
|
|
135
|
+
onClick={onCreateSandboxTool}
|
|
136
|
+
>
|
|
137
|
+
Create sandbox tool
|
|
138
|
+
</button>
|
|
139
|
+
</section>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { CheckCircle2, X } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Read-only summary of a successfully tested API Registry row.
|
|
7
|
+
* Shown at the top of the sandbox-tool draft flow (not a blocking modal).
|
|
8
|
+
*/
|
|
9
|
+
export function ApiRegistryReviewModal({ registryRow, onClose = null }) {
|
|
10
|
+
if (!registryRow) return null;
|
|
11
|
+
const integrationId = String(registryRow.integrationId || "").trim();
|
|
12
|
+
const endpoint = String(registryRow.endpoint || "").trim();
|
|
13
|
+
const method = String(registryRow.method || "GET").trim().toUpperCase();
|
|
14
|
+
const baseUrl = String(registryRow.baseUrl || "").trim();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<section className="dm-api-review-banner" aria-label="Connected API summary">
|
|
18
|
+
<div className="dm-api-review-banner-icon" aria-hidden="true">
|
|
19
|
+
<CheckCircle2 size={18} />
|
|
20
|
+
</div>
|
|
21
|
+
<div className="dm-api-review-banner-body">
|
|
22
|
+
<p className="dm-api-review-banner-eyebrow">Connected API</p>
|
|
23
|
+
<h3>{registryRow.Name || integrationId}</h3>
|
|
24
|
+
<p>
|
|
25
|
+
This endpoint returned a valid response. You can now turn it into a sandbox tool.
|
|
26
|
+
</p>
|
|
27
|
+
<code className="dm-api-review-banner-route">
|
|
28
|
+
{method} {baseUrl && endpoint ? `${baseUrl.replace(/\/+$/, "")}/${endpoint.replace(/^\/+/, "")}` : endpoint || baseUrl}
|
|
29
|
+
</code>
|
|
30
|
+
</div>
|
|
31
|
+
{onClose && (
|
|
32
|
+
<button type="button" className="dm-sidebar-close" onClick={onClose} aria-label="Dismiss summary">
|
|
33
|
+
<X size={16} />
|
|
34
|
+
</button>
|
|
35
|
+
)}
|
|
36
|
+
</section>
|
|
37
|
+
);
|
|
38
|
+
}
|