@growthub/cli 0.13.7 → 0.13.9

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 (25) hide show
  1. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/codex-sites/route.js +13 -0
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/query/route.js +98 -34
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/swarm-condition/route.js +106 -0
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceActivationPanel.jsx +17 -0
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceContributionGraph.jsx +119 -0
  6. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceHelperSetupModal.jsx +357 -0
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceLensPanel.jsx +488 -0
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceLensWalkthrough.jsx +69 -0
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +105 -0
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +37 -2
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +382 -32
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/apps/codex-sites-data-model-card.jsx +81 -0
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/apps/page.jsx +31 -14
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/apps/settings-accordion-section.jsx +50 -0
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +192 -7
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-lens/page.jsx +76 -0
  17. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +140 -4
  18. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/codex-sites-local-state.js +139 -0
  19. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/codex-sites-workspace-adapter.js +156 -0
  20. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-activation.js +1025 -0
  21. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +2 -3
  22. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper-apply.js +24 -8
  23. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +5 -0
  24. package/dist/index.js +5224 -5225
  25. package/package.json +1 -1
@@ -95,6 +95,12 @@ import {
95
95
  pluralize,
96
96
  textColorForAccent,
97
97
  } from "./dm-shared.jsx";
98
+ import {
99
+ CODEX_SITES_OBJECT_ID,
100
+ codexSiteRecordToRow,
101
+ isCodexSiteUrl,
102
+ normalizeCodexSiteRecord,
103
+ } from "@/lib/codex-sites-workspace-adapter";
98
104
 
99
105
  // ─── Object type definitions for the type-picker step ────────────────────────
100
106
 
@@ -1015,6 +1021,95 @@ function SandboxRecordFields({
1015
1021
  );
1016
1022
  }
1017
1023
 
1024
+ function CodexSitesRecordFields({ draft, setDraft, table, saving, onSave, rowIndex }) {
1025
+ const [sites, setSites] = useState([]);
1026
+ const [loadingSites, setLoadingSites] = useState(false);
1027
+ const [sitesMessage, setSitesMessage] = useState("");
1028
+ const selectedUrl = String(draft?.url || "").trim();
1029
+
1030
+ useEffect(() => {
1031
+ let cancelled = false;
1032
+ setLoadingSites(true);
1033
+ setSitesMessage("");
1034
+ fetch("/api/workspace/codex-sites", { cache: "no-store" })
1035
+ .then((res) => res.json())
1036
+ .then((payload) => {
1037
+ if (cancelled) return;
1038
+ const nextSites = Array.isArray(payload.sites)
1039
+ ? payload.sites.map((site) => normalizeCodexSiteRecord(site)).filter((site) => isCodexSiteUrl(site.url))
1040
+ : [];
1041
+ setSites(nextSites);
1042
+ setSitesMessage(nextSites.length ? "" : "No Codex Sites are available from the workspace adapter.");
1043
+ })
1044
+ .catch((error) => {
1045
+ if (cancelled) return;
1046
+ setSites([]);
1047
+ setSitesMessage(error?.message || "Codex Sites adapter unavailable.");
1048
+ })
1049
+ .finally(() => {
1050
+ if (!cancelled) setLoadingSites(false);
1051
+ });
1052
+ return () => { cancelled = true; };
1053
+ }, []);
1054
+
1055
+ function patchFields(fields) {
1056
+ setDraft((current) => ({ ...current, ...fields }));
1057
+ onSave((config) => Object.entries(fields).reduce(
1058
+ (nextConfig, [column, value]) => updateTableCell(nextConfig, table, rowIndex, column, value),
1059
+ config
1060
+ ));
1061
+ }
1062
+
1063
+ function selectSite(url) {
1064
+ const site = sites.find((item) => item.url === url);
1065
+ if (!site) return;
1066
+ patchFields(codexSiteRecordToRow(site));
1067
+ }
1068
+
1069
+ return (
1070
+ <div className="dm-codex-sites-config">
1071
+ <DrawerSection title="Codex Site Binding" defaultOpen>
1072
+ <label className="dm-record-field">
1073
+ <span>Available site</span>
1074
+ <StaticSelect
1075
+ value={selectedUrl}
1076
+ disabled={!table.mutable || saving || loadingSites || sites.length === 0}
1077
+ placeholder={loadingSites ? "Loading Codex Sites..." : "Select Codex Site..."}
1078
+ options={sites.map((site) => ({
1079
+ value: site.url,
1080
+ label: site.Name,
1081
+ source: site.url,
1082
+ }))}
1083
+ onChange={selectSite}
1084
+ />
1085
+ {sitesMessage && <span className="dm-cell-empty">{sitesMessage}</span>}
1086
+ </label>
1087
+ {selectedUrl && (
1088
+ <a className="dm-btn-outline dm-codex-sites-open-link" href={selectedUrl} target="_blank" rel="noreferrer">
1089
+ <Link2 size={13} />Open selected site
1090
+ </a>
1091
+ )}
1092
+ </DrawerSection>
1093
+ <DrawerSection title="Bound Row" defaultOpen>
1094
+ {["Name", "app", "client", "url", "status", "accessMode", "dashboardId", "lastRecordedAt", "notes"].map((column) => (
1095
+ <RecordFieldEditor
1096
+ key={column}
1097
+ table={table}
1098
+ tables={[]}
1099
+ column={column}
1100
+ value={String(draft?.[column] ?? "")}
1101
+ saving={saving}
1102
+ editable={false}
1103
+ onDraft={() => {}}
1104
+ onCommit={() => {}}
1105
+ onExpandJson={() => {}}
1106
+ />
1107
+ ))}
1108
+ </DrawerSection>
1109
+ </div>
1110
+ );
1111
+ }
1112
+
1018
1113
  function DataModelRecordDrawer({
1019
1114
  table,
1020
1115
  tables,
@@ -1086,6 +1181,7 @@ function DataModelRecordDrawer({
1086
1181
 
1087
1182
  const isApiRegistry = table.objectType === "api-registry";
1088
1183
  const isSandbox = table.objectType === "sandbox-environment";
1184
+ const isCodexSitesObject = table.objectId === CODEX_SITES_OBJECT_ID;
1089
1185
  const isDirty = JSON.stringify(draft || {}) !== JSON.stringify(row || {}) || JSON.stringify(pendingColumns) !== JSON.stringify(table.columns || []) || JSON.stringify(pendingHidden) !== JSON.stringify(table.fieldSettings?.hidden || []);
1090
1186
 
1091
1187
  function updateField(column, value) {
@@ -1561,6 +1657,15 @@ function DataModelRecordDrawer({
1561
1657
  onOpenGraphSidecar={openWorkflowView}
1562
1658
  onOpenTraceSidecar={openTraceSidecar}
1563
1659
  />
1660
+ ) : isCodexSitesObject ? (
1661
+ <CodexSitesRecordFields
1662
+ draft={draft}
1663
+ setDraft={setDraft}
1664
+ table={table}
1665
+ saving={saving}
1666
+ onSave={onSave}
1667
+ rowIndex={rowIndex}
1668
+ />
1564
1669
  ) : groupRecordColumns(table.columns || []).map((section) => (
1565
1670
  <DrawerSection key={section.title} title={section.title}>
1566
1671
  {section.columns.map((column) => (
@@ -42,6 +42,11 @@ import {
42
42
  Wrench as RepairIcon,
43
43
  X,
44
44
  } from "lucide-react";
45
+ import {
46
+ HELPER_SANDBOX_OBJECT_ID,
47
+ isHelperConfigured,
48
+ WorkspaceHelperSetupModal,
49
+ } from "../../components/WorkspaceHelperSetupModal.jsx";
45
50
 
46
51
  // Generic "Tool Call Output" title matches the reference grammar — the
47
52
  // user already sees the prompt + assistant response in the chat above,
@@ -229,8 +234,10 @@ let persistedWidth = 420;
229
234
 
230
235
  function resolveSandboxEnvRow(workspaceConfig) {
231
236
  const objects = workspaceConfig?.dataModel?.objects || [];
237
+ const helper = objects.find((obj) => obj?.id === HELPER_SANDBOX_OBJECT_ID && obj?.objectType === "sandbox-environment");
238
+ if (Array.isArray(helper?.rows) && helper.rows.length > 0) return helper.rows[0];
232
239
  for (const obj of objects) {
233
- if (obj.objectType === "sandbox-environment" && Array.isArray(obj.rows) && obj.rows.length > 0) {
240
+ if (obj.id !== HELPER_SANDBOX_OBJECT_ID && obj.objectType === "sandbox-environment" && Array.isArray(obj.rows) && obj.rows.length > 0) {
234
241
  return obj.rows[0];
235
242
  }
236
243
  }
@@ -306,6 +313,7 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
306
313
  const [setupSaveError, setSetupSaveError] = useState("");
307
314
  const [setupSaveOk, setSetupSaveOk] = useState(false);
308
315
  const [copiedCommand, setCopiedCommand] = useState(false);
316
+ const [agentSetupOpen, setAgentSetupOpen] = useState(false);
309
317
 
310
318
  // Drag state
311
319
  const [panelWidth, setPanelWidth] = useState(persistedWidth);
@@ -611,6 +619,7 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
611
619
  }, [open, activeTab]);
612
620
 
613
621
  const sandboxRow = resolveSandboxEnvRow(workspaceConfig);
622
+ const helperAgentConfigured = isHelperConfigured(workspaceConfig);
614
623
  const liveModel = sandboxRow?.localModel || "";
615
624
  const liveEndpoint = sandboxRow?.localEndpoint || "";
616
625
  const liveAdapter = sandboxRow?.intelligenceAdapterMode || "ollama";
@@ -1193,9 +1202,26 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
1193
1202
  {activeTab === "setup" && (
1194
1203
  <div className="dm-sidecar-body dm-helper-setup-body">
1195
1204
  <p className="dm-helper-setup-intro">
1196
- The helper sends your prompt to a local model. Credentials are never stored in the workspace.
1205
+ Connect the helper to Codex, Claude, or another local agent. Advanced local model setup stays below.
1197
1206
  </p>
1198
1207
 
1208
+ <div className={`dm-helper-setup-status state-${helperAgentConfigured ? "connected" : "unconfigured"}`}>
1209
+ <div className="dm-helper-setup-status-row">
1210
+ <span className={`dm-connection-dot dm-connection-${helperAgentConfigured ? "ok" : "amber"}`} />
1211
+ <span className="dm-helper-setup-status-label">
1212
+ {helperAgentConfigured ? `Agent connected: ${sandboxRow?.agentHost}` : "No helper agent configured yet"}
1213
+ </span>
1214
+ <button type="button" className="dm-helper-setup-recheck" onClick={() => setAgentSetupOpen(true)}>
1215
+ {helperAgentConfigured ? "Change agent" : "Set up agent"}
1216
+ </button>
1217
+ </div>
1218
+ <span className="dm-helper-setup-status-meta">
1219
+ Uses workspace-helper-sandbox for the same helper widget.
1220
+ </span>
1221
+ </div>
1222
+
1223
+ <p className="dm-helper-setup-intro">Advanced local model fallback.</p>
1224
+
1199
1225
  <div
1200
1226
  className={`dm-helper-setup-status state-${setupStatusState}`}
1201
1227
  data-connection-status=""
@@ -1321,6 +1347,15 @@ export function HelperSidecar({ open, onClose, workspaceConfig, initialIntent, i
1321
1347
  {copiedCommand ? "Copied" : "Copy command"}
1322
1348
  </button>
1323
1349
  </div>
1350
+ <WorkspaceHelperSetupModal
1351
+ workspaceConfig={workspaceConfig}
1352
+ open={agentSetupOpen}
1353
+ onClose={() => setAgentSetupOpen(false)}
1354
+ onSaved={(nextConfig) => {
1355
+ setAgentSetupOpen(false);
1356
+ if (onApplied) onApplied(nextConfig);
1357
+ }}
1358
+ />
1324
1359
  </div>
1325
1360
  )}
1326
1361
  </aside>