@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.
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/metadata-graph/route.js +184 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/refresh-sources/route.js +24 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +14 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/login/route.js +74 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/logout/route.js +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/status/route.js +77 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +72 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/AgentSwarmPanel.jsx +326 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +123 -27
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphEmptyCanvas.jsx +6 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +224 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationRunTracePanel.jsx +754 -92
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxAgentAuthPanel.jsx +224 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxRunPanel.jsx +32 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/WorkspaceGraphInspectorPanel.jsx +226 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +530 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +8 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +10 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/RunSetupPanel.jsx +261 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +119 -9
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +779 -138
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +91 -14
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/docs/sandbox-environment-primitive.md +35 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-agent-swarm.js +923 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +28 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +216 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +412 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-inputs.js +366 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-trace.js +34 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-eligibility.js +50 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth-redaction.js +64 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +665 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-host-catalog.js +168 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-chart-values.js +595 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +164 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +11 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-graph.js +646 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-selectors.js +249 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +1186 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +111 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +14 -0
- package/package.json +1 -1
|
@@ -232,6 +232,50 @@ function filterNavFolderRows(rows, query, typeFilter) {
|
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Derive which nav-folder item is "active" for the current route. The
|
|
237
|
+
* destination URLs here mirror `openDashboardItem`/`openViewItem`/
|
|
238
|
+
* `openWorkflowItem` below — so a freshly mounted rail can recover the
|
|
239
|
+
* active item (and therefore its parent folder) purely from
|
|
240
|
+
* pathname + searchParams, without depending on transient client state.
|
|
241
|
+
*/
|
|
242
|
+
function isNavItemActive(item, pathname, searchParams) {
|
|
243
|
+
if (!item || !pathname) return false;
|
|
244
|
+
const get = (key) => (searchParams && typeof searchParams.get === "function"
|
|
245
|
+
? searchParams.get(key)
|
|
246
|
+
: null);
|
|
247
|
+
if (item.type === "dashboard") {
|
|
248
|
+
return pathname === "/" && get("dashboard") === String(item.refId || "");
|
|
249
|
+
}
|
|
250
|
+
if (item.type === "view") {
|
|
251
|
+
return pathname.startsWith("/data-model")
|
|
252
|
+
&& get("object") === String(item.objectId || "");
|
|
253
|
+
}
|
|
254
|
+
if (item.type === "workflow") {
|
|
255
|
+
return pathname.startsWith("/workflows")
|
|
256
|
+
&& get("object") === String(item.objectId || "")
|
|
257
|
+
&& get("row") === String(item.rowId || "");
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Walk the persisted nav-folder rows and return the folder id whose item
|
|
264
|
+
* matches the active route, or null if none do. This is the anchor the
|
|
265
|
+
* rail uses to keep the parent folder open while the user navigates
|
|
266
|
+
* between its dashboards / views / workflows.
|
|
267
|
+
*/
|
|
268
|
+
function deriveActiveNavFolderId(rows, pathname, searchParams) {
|
|
269
|
+
if (!Array.isArray(rows) || !rows.length) return null;
|
|
270
|
+
for (const folder of rows) {
|
|
271
|
+
const items = Array.isArray(folder?.items) ? folder.items : [];
|
|
272
|
+
for (const item of items) {
|
|
273
|
+
if (isNavItemActive(item, pathname, searchParams)) return folder.id;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
235
279
|
function hexToTintBg(hex, alpha = 0.1) {
|
|
236
280
|
const h = String(hex || "").replace("#", "");
|
|
237
281
|
if (!/^[0-9a-f]{6}$/i.test(h)) return "#f5f5f5";
|
|
@@ -415,6 +459,19 @@ function NavFoldersSection({
|
|
|
415
459
|
const dashboards = useMemo(() => listAvailableDashboards(workspaceConfig), [workspaceConfig]);
|
|
416
460
|
const viewableObjects = useMemo(() => listAvailableObjectsForViews(workspaceConfig), [workspaceConfig]);
|
|
417
461
|
const workflows = useMemo(() => listAvailableWorkflows(workspaceConfig), [workspaceConfig]);
|
|
462
|
+
const activeFolderId = useMemo(
|
|
463
|
+
() => deriveActiveNavFolderId(rows, pathname, searchParams),
|
|
464
|
+
[rows, pathname, searchParams],
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
// When the user lands on a route owned by a folder item (deep-link,
|
|
468
|
+
// reload, cross-page navigation), expand the Folders section so the
|
|
469
|
+
// active folder/item is visible without an extra click. Manual
|
|
470
|
+
// collapse still wins — the effect only fires when activeFolderId
|
|
471
|
+
// changes, not on every render.
|
|
472
|
+
useEffect(() => {
|
|
473
|
+
if (activeFolderId) setSectionCollapsed(false);
|
|
474
|
+
}, [activeFolderId]);
|
|
418
475
|
const filteredEntries = useMemo(
|
|
419
476
|
() => filterNavFolderRows(rows, filterQuery, filterType),
|
|
420
477
|
[rows, filterQuery, filterType],
|
|
@@ -875,7 +932,10 @@ function NavFoldersSection({
|
|
|
875
932
|
type="button"
|
|
876
933
|
role="menuitem"
|
|
877
934
|
className="workspace-rail-thread-menu-item"
|
|
878
|
-
onClick={() =>
|
|
935
|
+
onClick={(e) => {
|
|
936
|
+
e.stopPropagation();
|
|
937
|
+
startCustomizeItem(folder, item);
|
|
938
|
+
}}
|
|
879
939
|
>
|
|
880
940
|
<Pencil size={13} aria-hidden="true" /> Customize
|
|
881
941
|
</button>
|
|
@@ -883,7 +943,10 @@ function NavFoldersSection({
|
|
|
883
943
|
type="button"
|
|
884
944
|
role="menuitem"
|
|
885
945
|
className="workspace-rail-thread-menu-item is-destructive"
|
|
886
|
-
onClick={() =>
|
|
946
|
+
onClick={(e) => {
|
|
947
|
+
e.stopPropagation();
|
|
948
|
+
deleteItem(folder.id, item.id);
|
|
949
|
+
}}
|
|
887
950
|
>
|
|
888
951
|
<Trash2 size={13} aria-hidden="true" /> Remove
|
|
889
952
|
</button>
|
|
@@ -896,11 +959,7 @@ function NavFoldersSection({
|
|
|
896
959
|
const renderItemRow = (folder, item) => {
|
|
897
960
|
const composedId = `${folder.id}::${item.id}`;
|
|
898
961
|
const isMenuOpen = openMenuId === composedId;
|
|
899
|
-
const isActive = item
|
|
900
|
-
|| (item.type === "workflow"
|
|
901
|
-
&& pathname.startsWith("/workflows")
|
|
902
|
-
&& searchParams.get("object") === item.objectId
|
|
903
|
-
&& searchParams.get("row") === item.rowId);
|
|
962
|
+
const isActive = isNavItemActive(item, pathname, searchParams);
|
|
904
963
|
const style = navItemStyle(item);
|
|
905
964
|
const typeHint = item.type === "dashboard" ? "Dashboard" : item.type === "workflow" ? "Workflow" : "View";
|
|
906
965
|
return (
|
|
@@ -918,7 +977,11 @@ function NavFoldersSection({
|
|
|
918
977
|
<button
|
|
919
978
|
type="button"
|
|
920
979
|
className="workspace-rail-nav-row-main"
|
|
921
|
-
onClick={() => {
|
|
980
|
+
onClick={(e) => {
|
|
981
|
+
// Child clicks must never reach the folder toggle — keep
|
|
982
|
+
// navigation independent from accordion state so the parent
|
|
983
|
+
// folder stays open while the user moves between its items.
|
|
984
|
+
e.stopPropagation();
|
|
922
985
|
if (item.type === "dashboard") openDashboardItem(item);
|
|
923
986
|
else if (item.type === "workflow") openWorkflowItem(item);
|
|
924
987
|
else openViewItem(item);
|
|
@@ -996,7 +1059,10 @@ function NavFoldersSection({
|
|
|
996
1059
|
type="button"
|
|
997
1060
|
role="menuitem"
|
|
998
1061
|
className="workspace-rail-thread-menu-item"
|
|
999
|
-
onClick={() =>
|
|
1062
|
+
onClick={(e) => {
|
|
1063
|
+
e.stopPropagation();
|
|
1064
|
+
startCustomizeFolder(folder);
|
|
1065
|
+
}}
|
|
1000
1066
|
>
|
|
1001
1067
|
<Pencil size={13} aria-hidden="true" /> Customize
|
|
1002
1068
|
</button>
|
|
@@ -1005,7 +1071,8 @@ function NavFoldersSection({
|
|
|
1005
1071
|
role="menuitem"
|
|
1006
1072
|
className="workspace-rail-thread-menu-item"
|
|
1007
1073
|
disabled={dashboards.length === 0}
|
|
1008
|
-
onClick={() => {
|
|
1074
|
+
onClick={(e) => {
|
|
1075
|
+
e.stopPropagation();
|
|
1009
1076
|
setOpenMenuId(null);
|
|
1010
1077
|
setMenuAnchor(null);
|
|
1011
1078
|
setAddPickerFor({ folderId: folder.id, kind: "dashboard" });
|
|
@@ -1018,7 +1085,8 @@ function NavFoldersSection({
|
|
|
1018
1085
|
role="menuitem"
|
|
1019
1086
|
className="workspace-rail-thread-menu-item"
|
|
1020
1087
|
disabled={viewableObjects.length === 0}
|
|
1021
|
-
onClick={() => {
|
|
1088
|
+
onClick={(e) => {
|
|
1089
|
+
e.stopPropagation();
|
|
1022
1090
|
setOpenMenuId(null);
|
|
1023
1091
|
setMenuAnchor(null);
|
|
1024
1092
|
setAddPickerFor({ folderId: folder.id, kind: "view" });
|
|
@@ -1031,7 +1099,8 @@ function NavFoldersSection({
|
|
|
1031
1099
|
role="menuitem"
|
|
1032
1100
|
className="workspace-rail-thread-menu-item"
|
|
1033
1101
|
disabled={workflows.length === 0}
|
|
1034
|
-
onClick={() => {
|
|
1102
|
+
onClick={(e) => {
|
|
1103
|
+
e.stopPropagation();
|
|
1035
1104
|
setOpenMenuId(null);
|
|
1036
1105
|
setMenuAnchor(null);
|
|
1037
1106
|
setAddPickerFor({ folderId: folder.id, kind: "workflow" });
|
|
@@ -1043,7 +1112,10 @@ function NavFoldersSection({
|
|
|
1043
1112
|
type="button"
|
|
1044
1113
|
role="menuitem"
|
|
1045
1114
|
className="workspace-rail-thread-menu-item is-destructive"
|
|
1046
|
-
onClick={() =>
|
|
1115
|
+
onClick={(e) => {
|
|
1116
|
+
e.stopPropagation();
|
|
1117
|
+
deleteFolder(folder.id);
|
|
1118
|
+
}}
|
|
1047
1119
|
>
|
|
1048
1120
|
<Trash2 size={13} aria-hidden="true" /> Delete
|
|
1049
1121
|
</button>
|
|
@@ -1057,7 +1129,12 @@ function NavFoldersSection({
|
|
|
1057
1129
|
const { folder, items, expand: forceExpand } = entry;
|
|
1058
1130
|
const isMenuOpen = openMenuId === folder.id;
|
|
1059
1131
|
const isCustomizing = customizeTarget?.scope === "folder" && customizeTarget.folderId === folder.id;
|
|
1060
|
-
|
|
1132
|
+
// Active-folder preservation: if a child item matches the current
|
|
1133
|
+
// route, the parent folder stays open regardless of its persisted
|
|
1134
|
+
// `collapsed` flag — so navigating between sibling items inside a
|
|
1135
|
+
// folder never collapses the folder underneath the user.
|
|
1136
|
+
const isActiveFolder = activeFolderId === folder.id;
|
|
1137
|
+
const collapsed = !isActiveFolder && Boolean(folder.collapsed) && !forceExpand;
|
|
1061
1138
|
const isExpanded = !collapsed;
|
|
1062
1139
|
const style = navFolderStyle(folder);
|
|
1063
1140
|
const visibleItems = items;
|
|
@@ -30,3 +30,38 @@ Workspace Builder excludes **`sandbox-environment`** from View widget bindings (
|
|
|
30
30
|
## Extension points
|
|
31
31
|
|
|
32
32
|
- Custom adapters: `apps/workspace/lib/adapters/sandboxes/adapters/` (see `README.md` there).
|
|
33
|
+
|
|
34
|
+
## Local agent auth onboarding
|
|
35
|
+
|
|
36
|
+
Sandbox rows whose **`adapter` is `local-agent-host`** route execution through whichever local agent CLI is registered for `agentHost` (Claude Code, Codex, Cursor, Gemini, OpenCode, Pi, Qwen, Hermes, OpenClaw Gateway). The record sidecar exposes a **uniform** auth onboarding panel beside the existing **Run sandbox** bar — the mental model is identical for every host:
|
|
37
|
+
|
|
38
|
+
1. **Check status** — probes the host CLI for reachability and (where the catalog declares one) a real auth-status subcommand.
|
|
39
|
+
2. **Run login** — only shown when the host catalog declares a documented `loginCommand`. Spawns it server-side and surfaces stdout / stderr / login URL.
|
|
40
|
+
3. **Log out** — only shown when the host catalog declares a documented `logoutCommand`.
|
|
41
|
+
4. **Run sandbox** — existing button (unchanged execution path).
|
|
42
|
+
|
|
43
|
+
Per-host capabilities (binary path, install hint, login/logout subcommands, notes for hosts without a documented login flow) are declared in **`apps/workspace/lib/sandbox-agent-host-catalog.js`**. Adding a new host means adding one entry there — never extending the auth helper or the panel component. The catalog is the single source of truth for "what does this host's onboarding look like?".
|
|
44
|
+
|
|
45
|
+
Wired through `POST /api/workspace/sandbox-agent-auth/{status,login,logout}` and the helper at `apps/workspace/lib/sandbox-agent-auth.js`. The Claude flow mirrors the upstream Paperclip server route in `server/src/routes/agents.ts` (`claude auth login` / `claude auth logout`) so behaviour matches the hosted agents surface.
|
|
46
|
+
|
|
47
|
+
### Status semantics — uniform across every host
|
|
48
|
+
|
|
49
|
+
| Status | Meaning |
|
|
50
|
+
| ----------- | -------------------------------------------------------------------------------- |
|
|
51
|
+
| `active` | A real auth probe confirmed authentication (login exit 0, or `auth status` exit 0). |
|
|
52
|
+
| `reachable` | The CLI is callable (`--version` exit 0) — but authentication is **not** yet confirmed. |
|
|
53
|
+
| `stale` | The CLI is reachable but printed auth-shaped failure output. |
|
|
54
|
+
| `missing` | The binary is not on PATH. |
|
|
55
|
+
| `checking` | Transient UI state during a probe. |
|
|
56
|
+
| `unknown` | Indeterminate. |
|
|
57
|
+
|
|
58
|
+
A `--version` (or equivalent reachability) probe **never** promotes to `active`. The next sandbox-run is the source of truth for session readiness.
|
|
59
|
+
|
|
60
|
+
### Authority invariants
|
|
61
|
+
|
|
62
|
+
- Auth setup is **separate** from the `local-agent-host` execution adapter — the adapter at `lib/adapters/sandboxes/default-local-agent-host.js` stays execution-only and does not mutate any host config file.
|
|
63
|
+
- Raw host tokens **never** enter `growthub.config.json`. Each CLI manages its own on-disk auth state. The sandbox row stores only safe metadata: `agentAuthStatus`, `agentAuthProvider`, `agentAuthLastChecked`, `agentAuthLastExitCode`, `agentAuthLastMessage`, `agentAuthLastLoginUrl`.
|
|
64
|
+
- Token-shaped output (`sk-ant-…`, `sk-…`, JWT, `Bearer …`, prefix patterns like `access_token=`, `api_key=`) is redacted server-side before crossing the response boundary.
|
|
65
|
+
- The schema rejects out-of-band PATCHes that try to stash a secret field (`token`, `apiKey`, `accessToken`, `refreshToken`, `bearer`, `password`, `secret`, `sessionKey`) on a sandbox row.
|
|
66
|
+
- The panel is hidden when `runLocality === "serverless"` (the local CLI is irrelevant in that case), when `adapter !== "local-agent-host"`, or when `agentHost` is not registered in the host auth catalog.
|
|
67
|
+
- Hosts without a documented login subcommand show only the **Check status** button plus the catalog's `notes` line directing the operator to sign in via the host CLI directly. No invented subcommands.
|