@growthub/cli 0.13.2 → 0.13.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/metadata-graph/route.js +184 -0
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/refresh-sources/route.js +24 -2
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +14 -0
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/login/route.js +74 -0
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/logout/route.js +67 -0
  6. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/status/route.js +77 -0
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +72 -4
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/AgentSwarmPanel.jsx +326 -0
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +123 -27
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphEmptyCanvas.jsx +6 -0
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +224 -1
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +754 -92
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxAgentAuthPanel.jsx +224 -0
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxRunPanel.jsx +32 -1
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/WorkspaceGraphInspectorPanel.jsx +226 -0
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +530 -9
  17. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +8 -1
  18. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +10 -7
  19. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/RunSetupPanel.jsx +261 -0
  20. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +119 -9
  21. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +779 -138
  22. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +91 -14
  23. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/docs/sandbox-environment-primitive.md +35 -0
  24. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-agent-swarm.js +923 -0
  25. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +28 -3
  26. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +216 -5
  27. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +412 -0
  28. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-inputs.js +366 -0
  29. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +34 -3
  30. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-eligibility.js +50 -0
  31. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-redaction.js +64 -0
  32. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +665 -0
  33. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-host-catalog.js +168 -0
  34. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-chart-values.js +595 -0
  35. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +164 -7
  36. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +11 -0
  37. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-graph.js +646 -0
  38. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-selectors.js +249 -0
  39. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +1186 -0
  40. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +111 -1
  41. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +14 -0
  42. package/package.json +1 -1
@@ -0,0 +1,184 @@
1
+ /**
2
+ * GET /api/workspace/metadata-graph
3
+ *
4
+ * Growthub Workspace Metadata Graph V1 — read-only projection.
5
+ *
6
+ * Combines the governed workspace config and the live source-record sidecar
7
+ * into a typed metadata store and a node/edge graph. Consumers (the UI
8
+ * inspector, the workspace helper agent, and external operators) use this
9
+ * envelope to ask dependency questions without re-deriving widget/workflow
10
+ * contracts inside every component.
11
+ *
12
+ * Optional query parameters:
13
+ * - staleKind: "object" | "field" | "sourceRecord" | "workflow" | "agentHost" | "widget"
14
+ * - staleId: the corresponding metadata id (for `field`, use
15
+ * "<objectId>::<fieldId>")
16
+ *
17
+ * When both are provided the response `stale.groups` and `stale.reasons`
18
+ * reflect `selectStaleMetadataGroups({ kind, id })`. When omitted the
19
+ * stale section returns the empty baseline.
20
+ *
21
+ * Authority invariants:
22
+ * - GET only. PATCH / POST / PUT / DELETE are not exposed. Writes still
23
+ * flow through the existing governed routes
24
+ * (`PATCH /api/workspace`, `POST /api/workspace/refresh-sources`,
25
+ * `POST /api/workspace/sandbox-run`).
26
+ * - growthub.config.json remains the authoritative artifact.
27
+ * - No secrets are returned. Field metadata derived from secret-shaped
28
+ * column names is marked `isSecret: true` but no value is echoed.
29
+ * - Failures during read OR projection fall back to an empty store with
30
+ * warnings — this route never throws.
31
+ */
32
+
33
+ import { NextResponse } from "next/server";
34
+ import { readWorkspaceConfig, readWorkspaceSourceRecords } from "@/lib/workspace-config";
35
+ import { buildWorkspaceMetadataStore } from "@/lib/workspace-metadata-store";
36
+ import { buildWorkspaceMetadataGraph } from "@/lib/workspace-metadata-graph";
37
+ import { selectStaleMetadataGroups } from "@/lib/workspace-metadata-selectors";
38
+
39
+ const ENVELOPE_KIND = "growthub-workspace-metadata-graph-v1";
40
+ const ENVELOPE_VERSION = 1;
41
+
42
+ function emptyMetadataStore() {
43
+ return {
44
+ kind: "growthub-workspace-metadata-store-v1",
45
+ version: 1,
46
+ objects: [],
47
+ fields: [],
48
+ views: [],
49
+ filters: [],
50
+ sorts: [],
51
+ widgets: [],
52
+ dashboards: [],
53
+ workflows: [],
54
+ workflowNodes: [],
55
+ workflowActions: [],
56
+ runInputs: [],
57
+ agentHosts: [],
58
+ sandboxes: [],
59
+ integrations: [],
60
+ integrationEntities: [],
61
+ sourceRecords: [],
62
+ runs: [],
63
+ outputArtifacts: [],
64
+ workerKits: [],
65
+ pipelineHealth: [],
66
+ warnings: []
67
+ };
68
+ }
69
+
70
+ async function GET(request) {
71
+ const warnings = [];
72
+
73
+ let workspaceConfig = null;
74
+ try {
75
+ workspaceConfig = await readWorkspaceConfig();
76
+ } catch (error) {
77
+ warnings.push(`Failed to read workspace config: ${error?.message || "unknown error"}`);
78
+ }
79
+
80
+ let workspaceSourceRecords = {};
81
+ try {
82
+ workspaceSourceRecords = (await readWorkspaceSourceRecords()) || {};
83
+ } catch (error) {
84
+ warnings.push(`Failed to read source records sidecar: ${error?.message || "unknown error"}`);
85
+ }
86
+
87
+ // Defensive: helpers are designed to never throw on partial/unknown input,
88
+ // but the route must remain HTTP-200 even if an unexpected exception bubbles
89
+ // up (so the UI inspector and agents always get a typed envelope).
90
+ let metadataStore;
91
+ try {
92
+ metadataStore = buildWorkspaceMetadataStore({
93
+ workspaceConfig: workspaceConfig || {},
94
+ workspaceSourceRecords
95
+ });
96
+ warnings.push(...metadataStore.warnings);
97
+ } catch (error) {
98
+ warnings.push(`Failed to build metadata store: ${error?.message || "unknown error"}`);
99
+ metadataStore = emptyMetadataStore();
100
+ }
101
+
102
+ let graph;
103
+ try {
104
+ graph = buildWorkspaceMetadataGraph(metadataStore);
105
+ warnings.push(...graph.warnings);
106
+ } catch (error) {
107
+ warnings.push(`Failed to build metadata graph: ${error?.message || "unknown error"}`);
108
+ graph = { kind: "growthub-workspace-metadata-graph-v1", version: 1, nodes: [], edges: [], warnings: [] };
109
+ }
110
+
111
+ // Optional stale-group selector via query params.
112
+ let staleGroups = [];
113
+ let staleReasons = [];
114
+ try {
115
+ const url = request && request.url ? new URL(request.url) : null;
116
+ const staleKind = url ? (url.searchParams.get("staleKind") || "").trim() : "";
117
+ const staleId = url ? (url.searchParams.get("staleId") || "").trim() : "";
118
+ if (staleKind && staleId) {
119
+ const result = selectStaleMetadataGroups(metadataStore, { kind: staleKind, id: staleId });
120
+ staleGroups = Array.isArray(result?.groups) ? result.groups : [];
121
+ staleReasons = Array.isArray(result?.reasons) ? result.reasons : [];
122
+ }
123
+ } catch (error) {
124
+ warnings.push(`Failed to compute stale groups: ${error?.message || "unknown error"}`);
125
+ }
126
+
127
+ return NextResponse.json({
128
+ kind: ENVELOPE_KIND,
129
+ version: ENVELOPE_VERSION,
130
+ authority: {
131
+ config: "growthub.config.json",
132
+ sourceRecords: "growthub.source-records.json",
133
+ readOnlyProjection: true
134
+ },
135
+ metadata: {
136
+ objects: metadataStore.objects,
137
+ fields: metadataStore.fields,
138
+ views: metadataStore.views,
139
+ filters: metadataStore.filters,
140
+ sorts: metadataStore.sorts,
141
+ widgets: metadataStore.widgets,
142
+ dashboards: metadataStore.dashboards,
143
+ workflows: metadataStore.workflows,
144
+ workflowNodes: metadataStore.workflowNodes,
145
+ workflowActions: metadataStore.workflowActions,
146
+ runInputs: metadataStore.runInputs,
147
+ agentHosts: metadataStore.agentHosts,
148
+ sandboxes: metadataStore.sandboxes,
149
+ integrations: metadataStore.integrations,
150
+ integrationEntities: metadataStore.integrationEntities,
151
+ sourceRecords: metadataStore.sourceRecords,
152
+ runs: metadataStore.runs,
153
+ outputArtifacts: metadataStore.outputArtifacts,
154
+ workerKits: metadataStore.workerKits,
155
+ pipelineHealth: metadataStore.pipelineHealth
156
+ },
157
+ graph: {
158
+ nodes: graph.nodes,
159
+ edges: graph.edges
160
+ },
161
+ stale: {
162
+ groups: staleGroups,
163
+ reasons: staleReasons
164
+ },
165
+ warnings,
166
+ selectors: {
167
+ // Manifest of selectors the route honours. Only `selectStaleMetadataGroups`
168
+ // is wired through HTTP (via `?staleKind=&staleId=`). The remaining
169
+ // selectors are exposed as importable helpers for server-side consumers
170
+ // and the read-only inspector; they are NOT toggled through query
171
+ // params in V1.
172
+ httpEnabled: ["selectStaleMetadataGroups"],
173
+ helperOnly: [
174
+ "selectWidgetRequiredFields",
175
+ "selectWorkflowNodeInputSchema",
176
+ "selectObjectFilterableFields",
177
+ "selectObjectSortableFields",
178
+ "selectRunLineage"
179
+ ]
180
+ }
181
+ });
182
+ }
183
+
184
+ export { GET };
@@ -119,8 +119,30 @@ async function POST(request) {
119
119
  ) || null;
120
120
  const records = await resolver.fetchRecords(adapterConfig, connection, binding);
121
121
  const fetchedAt = new Date().toISOString();
122
- await writeWorkspaceSourceRecords(sourceId, records, { integrationId, fetchedAt });
123
- refreshed.push({ sourceId, integrationId, recordCount: records.length, fetchedAt });
122
+ // Persist the records under the object's `id` (canonical sidecar key).
123
+ // We also include `objectId`, `objectSourceId`, and `bindingSourceId`
124
+ // metadata so reader-side hydration in `lib/workspace-data-model.js`
125
+ // can fall back across the three places that may legitimately store
126
+ // the same key (object.id, object.sourceId, object.binding.sourceId)
127
+ // without having to re-parse the object.
128
+ const objectSourceId = typeof obj.sourceId === "string" && obj.sourceId.trim() ? obj.sourceId.trim() : null;
129
+ const bindingSourceId = typeof binding.sourceId === "string" && binding.sourceId.trim() ? binding.sourceId.trim() : null;
130
+ await writeWorkspaceSourceRecords(sourceId, records, {
131
+ integrationId,
132
+ fetchedAt,
133
+ objectId: sourceId,
134
+ objectSourceId,
135
+ bindingSourceId
136
+ });
137
+ refreshed.push({
138
+ sourceId,
139
+ integrationId,
140
+ recordCount: records.length,
141
+ fetchedAt,
142
+ objectId: sourceId,
143
+ objectSourceId,
144
+ bindingSourceId
145
+ });
124
146
  } catch (err) {
125
147
  skipped.push(sourceId);
126
148
  skippedDetail.push({
@@ -9,9 +9,14 @@ import { buildPortalWorkspace, portalCapabilities } from "@/lib/domain/portal";
9
9
  import {
10
10
  describePersistenceMode,
11
11
  readWorkspaceConfig,
12
+ readWorkspaceSourceRecords,
12
13
  writeWorkspaceConfig
13
14
  } from "@/lib/workspace-config";
14
15
 
16
+ // Workspace Config Contract V1 — PATCH is permanently restricted to these
17
+ // four fields. Sidecar source records (`workspaceSourceRecords`) are exposed
18
+ // on GET for runtime hydration only; they are deliberately NOT in this set.
19
+ // Sidecar writes flow through POST /api/workspace/refresh-sources.
15
20
  const ALLOWED_PATCH_FIELDS = new Set(["dashboards", "widgetTypes", "canvas", "dataModel"]);
16
21
 
17
22
  async function GET() {
@@ -27,6 +32,14 @@ async function GET() {
27
32
  integrations: groupIntegrationsByLane(integrations)
28
33
  };
29
34
  const workspaceConfig = await readWorkspaceConfig();
35
+ // Source records hydrate live-backed Data Model objects at runtime.
36
+ // Missing or unreadable sidecar returns `{}` — never throws.
37
+ let workspaceSourceRecords = {};
38
+ try {
39
+ workspaceSourceRecords = (await readWorkspaceSourceRecords()) || {};
40
+ } catch {
41
+ workspaceSourceRecords = {};
42
+ }
30
43
  const persistence = describePersistenceMode();
31
44
  return NextResponse.json({
32
45
  config,
@@ -35,6 +48,7 @@ async function GET() {
35
48
  settings,
36
49
  workspace: buildPortalWorkspace({ config, adapters, integrations: settings.integrations }),
37
50
  workspaceConfig,
51
+ workspaceSourceRecords,
38
52
  workspaceConfigPersistence: persistence
39
53
  });
40
54
  }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * POST /api/workspace/sandbox-agent-auth/login
3
+ *
4
+ * Spawns the catalog-declared login subcommand for a sandbox row whose
5
+ * adapter is `local-agent-host`. The actual subcommand (e.g.
6
+ * `claude auth login`) is read from `lib/sandbox-agent-host-catalog.js` —
7
+ * this route is host-agnostic.
8
+ *
9
+ * Hosts without a documented login subcommand return 400 with
10
+ * `code: "SANDBOX_AGENT_AUTH_LOGIN_UNSUPPORTED"` so the UI can render the
11
+ * host's `notes` string ("sign in via the host CLI directly").
12
+ *
13
+ * Captures stdout, stderr, login URL (if printed), exit code. Token-shaped
14
+ * output is redacted before crossing the response boundary. Raw tokens are
15
+ * NEVER written to `growthub.config.json`.
16
+ *
17
+ * Request body:
18
+ * { objectId: string, name: string }
19
+ *
20
+ * Response:
21
+ * {
22
+ * ok: boolean,
23
+ * status: "active" | "reachable" | "stale" | "missing" | "unknown",
24
+ * provider: string,
25
+ * label: string,
26
+ * binary: string,
27
+ * cwd: string,
28
+ * exitCode: number | null,
29
+ * timedOut: boolean,
30
+ * durationMs: number,
31
+ * stdout: string,
32
+ * stderr: string,
33
+ * loginUrl: string | null,
34
+ * message: string,
35
+ * checkedAt: string
36
+ * }
37
+ */
38
+
39
+ import { NextResponse } from "next/server";
40
+ import { runAgentLogin } from "@/lib/sandbox-agent-auth";
41
+
42
+ async function POST(request) {
43
+ let body;
44
+ try {
45
+ body = await request.json();
46
+ } catch {
47
+ return NextResponse.json({ ok: false, error: "invalid JSON body" }, { status: 400 });
48
+ }
49
+
50
+ const objectId = typeof body?.objectId === "string" ? body.objectId.trim() : "";
51
+ const name = typeof body?.name === "string" ? body.name.trim() : "";
52
+ if (!objectId || !name) {
53
+ return NextResponse.json(
54
+ { ok: false, error: "objectId and name are required" },
55
+ { status: 400 }
56
+ );
57
+ }
58
+
59
+ try {
60
+ const result = await runAgentLogin({ objectId, name });
61
+ return NextResponse.json(result);
62
+ } catch (error) {
63
+ return NextResponse.json(
64
+ {
65
+ ok: false,
66
+ error: error?.message || "Agent login failed",
67
+ code: error?.code || null
68
+ },
69
+ { status: error?.code === "SANDBOX_AGENT_AUTH_NOT_FOUND" ? 404 : 400 }
70
+ );
71
+ }
72
+ }
73
+
74
+ export { POST };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * POST /api/workspace/sandbox-agent-auth/logout
3
+ *
4
+ * Spawns the catalog-declared logout subcommand for a sandbox row whose
5
+ * adapter is `local-agent-host`. Host-agnostic; the actual subcommand is
6
+ * read from `lib/sandbox-agent-host-catalog.js`.
7
+ *
8
+ * Hosts without a documented logout subcommand return 400 with
9
+ * `code: "SANDBOX_AGENT_AUTH_LOGOUT_UNSUPPORTED"` so the UI can render the
10
+ * host's `notes` string.
11
+ *
12
+ * Request body:
13
+ * { objectId: string, name: string }
14
+ *
15
+ * Response:
16
+ * {
17
+ * ok: boolean,
18
+ * status: "stale" | "missing" | "unknown",
19
+ * provider: string,
20
+ * label: string,
21
+ * binary: string,
22
+ * cwd: string,
23
+ * exitCode: number | null,
24
+ * durationMs: number,
25
+ * stdout: string,
26
+ * stderr: string,
27
+ * message: string,
28
+ * checkedAt: string
29
+ * }
30
+ */
31
+
32
+ import { NextResponse } from "next/server";
33
+ import { runAgentLogout } from "@/lib/sandbox-agent-auth";
34
+
35
+ async function POST(request) {
36
+ let body;
37
+ try {
38
+ body = await request.json();
39
+ } catch {
40
+ return NextResponse.json({ ok: false, error: "invalid JSON body" }, { status: 400 });
41
+ }
42
+
43
+ const objectId = typeof body?.objectId === "string" ? body.objectId.trim() : "";
44
+ const name = typeof body?.name === "string" ? body.name.trim() : "";
45
+ if (!objectId || !name) {
46
+ return NextResponse.json(
47
+ { ok: false, error: "objectId and name are required" },
48
+ { status: 400 }
49
+ );
50
+ }
51
+
52
+ try {
53
+ const result = await runAgentLogout({ objectId, name });
54
+ return NextResponse.json(result);
55
+ } catch (error) {
56
+ return NextResponse.json(
57
+ {
58
+ ok: false,
59
+ error: error?.message || "Agent logout failed",
60
+ code: error?.code || null
61
+ },
62
+ { status: error?.code === "SANDBOX_AGENT_AUTH_NOT_FOUND" ? 404 : 400 }
63
+ );
64
+ }
65
+ }
66
+
67
+ export { POST };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * POST /api/workspace/sandbox-agent-auth/status
3
+ *
4
+ * Probes the local agent CLI for a sandbox row whose adapter is
5
+ * `local-agent-host`. The probe is host-agnostic — each host's reachability
6
+ * + auth-status subcommand lives in `lib/sandbox-agent-host-catalog.js`.
7
+ *
8
+ * Status semantics (uniform across every host):
9
+ * - "active" a real auth probe confirmed authentication
10
+ * - "reachable" CLI is callable but auth NOT yet confirmed
11
+ * - "stale" CLI reachable but auth-shaped failure detected
12
+ * - "missing" binary not on PATH
13
+ * - "unknown" indeterminate
14
+ *
15
+ * A `--version` (or equivalent) probe NEVER promotes to "active" — the
16
+ * next sandbox-run is the source of truth for session readiness.
17
+ *
18
+ * Side effect: stamps `agentAuthStatus` + sibling fields onto the row so
19
+ * the Data Model record drawer surfaces the result without a follow-up
20
+ * load.
21
+ *
22
+ * Request body:
23
+ * { objectId: string, name: string }
24
+ *
25
+ * Response (success):
26
+ * {
27
+ * ok: boolean,
28
+ * status: "active" | "reachable" | "stale" | "missing" | "unknown",
29
+ * provider: string,
30
+ * label: string,
31
+ * binary: string,
32
+ * cwd: string,
33
+ * exitCode: number | null,
34
+ * probe: "auth-status" | "version",
35
+ * stdout: string,
36
+ * stderr: string,
37
+ * message: string,
38
+ * checkedAt: string
39
+ * }
40
+ */
41
+
42
+ import { NextResponse } from "next/server";
43
+ import { checkAgentStatus } from "@/lib/sandbox-agent-auth";
44
+
45
+ async function POST(request) {
46
+ let body;
47
+ try {
48
+ body = await request.json();
49
+ } catch {
50
+ return NextResponse.json({ ok: false, error: "invalid JSON body" }, { status: 400 });
51
+ }
52
+
53
+ const objectId = typeof body?.objectId === "string" ? body.objectId.trim() : "";
54
+ const name = typeof body?.name === "string" ? body.name.trim() : "";
55
+ if (!objectId || !name) {
56
+ return NextResponse.json(
57
+ { ok: false, error: "objectId and name are required" },
58
+ { status: 400 }
59
+ );
60
+ }
61
+
62
+ try {
63
+ const result = await checkAgentStatus({ objectId, name });
64
+ return NextResponse.json(result);
65
+ } catch (error) {
66
+ return NextResponse.json(
67
+ {
68
+ ok: false,
69
+ error: error?.message || "Agent auth status check failed",
70
+ code: error?.code || null
71
+ },
72
+ { status: error?.code === "SANDBOX_AGENT_AUTH_NOT_FOUND" ? 404 : 400 }
73
+ );
74
+ }
75
+ }
76
+
77
+ export { POST };
@@ -77,6 +77,12 @@ import {
77
77
  } from "@/lib/adapters/sandboxes";
78
78
  import { runOrchestrationGraphIfPresent } from "@/lib/orchestration-graph-runner";
79
79
  import { parseOrchestrationGraph } from "@/lib/orchestration-graph";
80
+ import {
81
+ discoverRunInputSchema,
82
+ normalizeRunInputsEnvelope,
83
+ validateRunInputsEnvelope,
84
+ summarizeRunInputs
85
+ } from "@/lib/orchestration-run-inputs";
80
86
 
81
87
  function envKeyCandidates(ref) {
82
88
  const token = String(ref || "")
@@ -347,7 +353,8 @@ function buildRunResponse({
347
353
  allowList,
348
354
  result,
349
355
  timeoutMs,
350
- row
356
+ row,
357
+ runInputs
351
358
  }) {
352
359
  const base = {
353
360
  runId,
@@ -380,6 +387,21 @@ function buildRunResponse({
380
387
  executionLane: row.executionLane ? String(row.executionLane) : null
381
388
  };
382
389
  }
390
+ if (runInputs && typeof runInputs === "object") {
391
+ base.input = runInputs;
392
+ base.runInputs = runInputs;
393
+ base.inputSummary = summarizeRunInputs(runInputs);
394
+ }
395
+ if (result && typeof result === "object" && result.swarm && typeof result.swarm === "object") {
396
+ base.swarm = result.swarm;
397
+ }
398
+ if (result && typeof result === "object" && Array.isArray(result.logTree)) {
399
+ base.logTree = result.logTree;
400
+ }
401
+ base.exports = {
402
+ available: ["download-json", "copy-output", "download-stdout", "download-stderr", "download-log-node"],
403
+ external: []
404
+ };
383
405
  return base;
384
406
  }
385
407
 
@@ -448,6 +470,29 @@ async function POST(request) {
448
470
  ? { ...row, orchestrationGraph: draftGraph, orchestrationConfig: draftGraph }
449
471
  : row;
450
472
 
473
+ const inputSchema = discoverRunInputSchema(rowForRun.orchestrationGraph || rowForRun.orchestrationConfig);
474
+ let normalizedRunInputs = null;
475
+ if (body?.runInputs != null) {
476
+ const validation = validateRunInputsEnvelope(body.runInputs, inputSchema);
477
+ if (validation.error) {
478
+ return NextResponse.json({ ok: false, error: validation.error }, { status: 400 });
479
+ }
480
+ if (inputSchema.requiresInput && validation.missing.length > 0) {
481
+ return NextResponse.json({
482
+ ok: false,
483
+ error: `Missing required run input fields: ${validation.missing.join(", ")}`,
484
+ missingFields: validation.missing
485
+ }, { status: 400 });
486
+ }
487
+ normalizedRunInputs = normalizeRunInputsEnvelope(body.runInputs, inputSchema);
488
+ } else if (inputSchema.requiresInput) {
489
+ return NextResponse.json({
490
+ ok: false,
491
+ error: "runInputs is required for this workflow",
492
+ missingFields: (inputSchema.fields || []).filter((f) => f.required).map((f) => f.id)
493
+ }, { status: 400 });
494
+ }
495
+
451
496
  const runLocality = normalizeRunLocality(rowForRun);
452
497
  const runtime = KNOWN_SANDBOX_RUNTIMES.includes(rowForRun.runtime) ? rowForRun.runtime : "node";
453
498
  let adapterId = (typeof rowForRun.adapter === "string" && rowForRun.adapter.trim()) ? rowForRun.adapter.trim() : DEFAULT_SANDBOX_ADAPTER;
@@ -515,10 +560,32 @@ async function POST(request) {
515
560
 
516
561
  const hasNativeGraph = Boolean(parseOrchestrationGraph(rowForRun.orchestrationGraph || rowForRun.orchestrationConfig));
517
562
  if (hasNativeGraph && runLocality !== "serverless") {
518
- const graphResult = await runOrchestrationGraphIfPresent({ workspaceConfig, row: rowForRun, timeoutMs });
563
+ const graphResult = await runOrchestrationGraphIfPresent({
564
+ workspaceConfig,
565
+ row: rowForRun,
566
+ timeoutMs,
567
+ runInputs: normalizedRunInputs,
568
+ executionContext: {
569
+ runId,
570
+ ranAt,
571
+ runtime,
572
+ agentHost,
573
+ adapterId,
574
+ env,
575
+ envRefSlugs,
576
+ envRefsMissing,
577
+ envRefsResolved,
578
+ networkAllow,
579
+ allowList,
580
+ instructions,
581
+ command,
582
+ timeoutMs,
583
+ sandboxName: rowForRun.Name || name
584
+ }
585
+ });
519
586
  if (graphResult !== null) {
520
587
  result = graphResult;
521
- effectiveAdapterId = "orchestration-graph";
588
+ effectiveAdapterId = String(graphResult?.adapterMeta?.adapter || "").trim() || "orchestration-graph";
522
589
  }
523
590
  }
524
591
 
@@ -613,7 +680,8 @@ async function POST(request) {
613
680
  allowList,
614
681
  result,
615
682
  timeoutMs,
616
- row: rowForRun
683
+ row: rowForRun,
684
+ runInputs: normalizedRunInputs
617
685
  });
618
686
 
619
687
  const sourceId = sandboxRunSourceId(objectId, row.Name || name);