@growthub/cli 0.13.1 → 0.13.4

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 (33) hide show
  1. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/refresh-sources/route.js +24 -2
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +14 -0
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/login/route.js +74 -0
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/logout/route.js +67 -0
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/status/route.js +77 -0
  6. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +48 -3
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +123 -27
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +136 -0
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +713 -92
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxAgentAuthPanel.jsx +224 -0
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxRunPanel.jsx +32 -1
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +514 -9
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +8 -1
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +10 -7
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/RunSetupPanel.jsx +261 -0
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +72 -7
  17. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +778 -140
  18. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +91 -14
  19. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/docs/sandbox-environment-primitive.md +35 -0
  20. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +15 -3
  21. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +384 -0
  22. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-inputs.js +323 -0
  23. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +32 -3
  24. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-eligibility.js +50 -0
  25. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-redaction.js +64 -0
  26. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +629 -0
  27. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-host-catalog.js +168 -0
  28. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-chart-values.js +542 -0
  29. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +164 -7
  30. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +11 -0
  31. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +111 -1
  32. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +9 -0
  33. package/package.json +1 -1
@@ -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,15 @@ 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
+ base.exports = {
396
+ available: ["download-json", "copy-output", "download-stdout", "download-stderr", "download-log-node"],
397
+ external: []
398
+ };
383
399
  return base;
384
400
  }
385
401
 
@@ -448,6 +464,29 @@ async function POST(request) {
448
464
  ? { ...row, orchestrationGraph: draftGraph, orchestrationConfig: draftGraph }
449
465
  : row;
450
466
 
467
+ const inputSchema = discoverRunInputSchema(rowForRun.orchestrationGraph || rowForRun.orchestrationConfig);
468
+ let normalizedRunInputs = null;
469
+ if (body?.runInputs != null) {
470
+ const validation = validateRunInputsEnvelope(body.runInputs, inputSchema);
471
+ if (validation.error) {
472
+ return NextResponse.json({ ok: false, error: validation.error }, { status: 400 });
473
+ }
474
+ if (inputSchema.requiresInput && validation.missing.length > 0) {
475
+ return NextResponse.json({
476
+ ok: false,
477
+ error: `Missing required run input fields: ${validation.missing.join(", ")}`,
478
+ missingFields: validation.missing
479
+ }, { status: 400 });
480
+ }
481
+ normalizedRunInputs = normalizeRunInputsEnvelope(body.runInputs, inputSchema);
482
+ } else if (inputSchema.requiresInput) {
483
+ return NextResponse.json({
484
+ ok: false,
485
+ error: "runInputs is required for this workflow",
486
+ missingFields: (inputSchema.fields || []).filter((f) => f.required).map((f) => f.id)
487
+ }, { status: 400 });
488
+ }
489
+
451
490
  const runLocality = normalizeRunLocality(rowForRun);
452
491
  const runtime = KNOWN_SANDBOX_RUNTIMES.includes(rowForRun.runtime) ? rowForRun.runtime : "node";
453
492
  let adapterId = (typeof rowForRun.adapter === "string" && rowForRun.adapter.trim()) ? rowForRun.adapter.trim() : DEFAULT_SANDBOX_ADAPTER;
@@ -515,7 +554,12 @@ async function POST(request) {
515
554
 
516
555
  const hasNativeGraph = Boolean(parseOrchestrationGraph(rowForRun.orchestrationGraph || rowForRun.orchestrationConfig));
517
556
  if (hasNativeGraph && runLocality !== "serverless") {
518
- const graphResult = await runOrchestrationGraphIfPresent({ workspaceConfig, row: rowForRun, timeoutMs });
557
+ const graphResult = await runOrchestrationGraphIfPresent({
558
+ workspaceConfig,
559
+ row: rowForRun,
560
+ timeoutMs,
561
+ runInputs: normalizedRunInputs
562
+ });
519
563
  if (graphResult !== null) {
520
564
  result = graphResult;
521
565
  effectiveAdapterId = "orchestration-graph";
@@ -613,7 +657,8 @@ async function POST(request) {
613
657
  allowList,
614
658
  result,
615
659
  timeoutMs,
616
- row: rowForRun
660
+ row: rowForRun,
661
+ runInputs: normalizedRunInputs
617
662
  });
618
663
 
619
664
  const sourceId = sandboxRunSourceId(objectId, row.Name || name);