@groundfloorcloud/mcp 0.1.12 → 0.1.14
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/README.md +3 -2
- package/dist/index.js +215 -49
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,8 +84,9 @@ then `npm run release` and `gf apps publish --path release.zip`. Do not invent
|
|
|
84
84
|
`App.tsx` / `vite.config`, zip `dist/`, or upload only `remoteEntry.js`.
|
|
85
85
|
Own CSS framework: `docs_get` id `css-and-styling` (`FederatedStyleRoot`).
|
|
86
86
|
|
|
87
|
-
**Databases:** `docs_get` id `databases`. Dataplane is not a database.
|
|
88
|
-
is ready through Dataplane;
|
|
87
|
+
**Databases:** `docs_get` id `databases`. Dataplane is not a database. Shared
|
|
88
|
+
PostgreSQL is ready through Dataplane; a dedicated PostgreSQL is what you can
|
|
89
|
+
deploy today. No other engines are offered.
|
|
89
90
|
|
|
90
91
|
**Coderunner how-to** is embedded: `docs_get` id `coderunner` (also
|
|
91
92
|
`coderunner-overview`). That page covers:
|
package/dist/index.js
CHANGED
|
@@ -327,6 +327,12 @@ function listSecrets(apiUrl, workspaceId, environmentId) {
|
|
|
327
327
|
})}`
|
|
328
328
|
);
|
|
329
329
|
}
|
|
330
|
+
function listFlags(apiUrl, workspaceId, environmentId) {
|
|
331
|
+
return cpGet(
|
|
332
|
+
apiUrl,
|
|
333
|
+
`${wsPath(workspaceId, "/flags")}${queryString({ environment_id: environmentId })}`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
330
336
|
function listFiles(apiUrl, workspaceId) {
|
|
331
337
|
return cpGet(apiUrl, wsPath(workspaceId, "/files"));
|
|
332
338
|
}
|
|
@@ -685,11 +691,11 @@ When the handler looks right locally, \`gf deploy\` the same tree.
|
|
|
685
691
|
Do not pass credential-shaped keys as \`--env KEY=VALUE\` (\`*_SECRET\`,
|
|
686
692
|
\`*_API_KEY\`, \`DATABASE_URL\`, \u2026). Control Plane returns **422**.
|
|
687
693
|
\`gf secrets set KEY\` then \`gf deploy --secret KEY\` (inject by reference).
|
|
688
|
-
This requires \`CODERUNNER_INJECT_ENV_SECRETS
|
|
689
|
-
**off by default
|
|
690
|
-
|
|
691
|
-
\`secrets:read\` instead (below) rather
|
|
692
|
-
\`--env\`.
|
|
694
|
+
This requires \`CODERUNNER_INJECT_ENV_SECRETS\`, a platform-wide Control Plane
|
|
695
|
+
setting \u2014 **off by default** and currently off. It cannot be enabled per
|
|
696
|
+
workspace, so there is nothing to request. If \`--secret\` 422s naming that
|
|
697
|
+
setting, read the secret live via M2M \`secrets:read\` instead (below) rather
|
|
698
|
+
than falling back to plaintext \`--env\`.
|
|
693
699
|
|
|
694
700
|
## M2M tokens (Vault, Files, and Secrets)
|
|
695
701
|
|
|
@@ -776,43 +782,40 @@ Dataplane is not a database. It is how Groundfloor talks to databases.
|
|
|
776
782
|
When the user starts any data or database work, say this first. Do not mention
|
|
777
783
|
infrastructure internals (cluster operators, installers, and the like):
|
|
778
784
|
|
|
779
|
-
You have
|
|
780
|
-
cluster, already there, no deploy step. If you want a
|
|
781
|
-
database that is entirely your own (own scaling, own
|
|
782
|
-
|
|
785
|
+
You have PostgreSQL ready to use through Dataplane \u2014 a shared,
|
|
786
|
+
platform-managed cluster, already there, no deploy step. If you want a
|
|
787
|
+
database that is entirely your own (own scaling, own backup schedule), you can
|
|
788
|
+
deploy a dedicated PostgreSQL first.
|
|
783
789
|
|
|
784
790
|
## Options
|
|
785
791
|
|
|
786
|
-
-
|
|
792
|
+
- PostgreSQL (shared) \u2014 platform-managed, already there. Default for app data
|
|
787
793
|
and Vault. No deploy step. This is NOT a workspace-owned resource: it does
|
|
788
794
|
not appear on the customer Databases page, and there is nothing to scale,
|
|
789
795
|
back up, or delete yourself \u2014 it's offered, not provisioned. Query via
|
|
790
796
|
Control Plane vault: POST /v1/workspaces/{id}/vault/collections/{name}/query
|
|
791
|
-
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
POST /v1/workspaces/{id}/managed-databases. Heavier than the shared
|
|
796
|
-
default: you own its scaling, backups, and lifecycle. Use this when you
|
|
797
|
-
need a tier/engine the shared default doesn't offer (Redis, ClickHouse,
|
|
798
|
-
Qdrant) or want a database isolated to this workspace.
|
|
797
|
+
- Dedicated PostgreSQL you deploy and own \u2014 portal Data \u2192 Databases, or
|
|
798
|
+
POST /v1/workspaces/{id}/managed-databases with engine postgres. Heavier
|
|
799
|
+
than the shared default: you own its scaling, backups, and lifecycle. Use it
|
|
800
|
+
when you want a database isolated to this workspace.
|
|
799
801
|
- A database they already run \u2014 through Dataplane if they wire it, or direct.
|
|
800
802
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
+
PostgreSQL is the only engine offered today, shared or dedicated. Do not offer
|
|
804
|
+
other engines (ArangoDB, MongoDB, Redis, ClickHouse, Qdrant, \u2026) as available,
|
|
805
|
+
even if you see them mentioned elsewhere. Do not call Dataplane hosts from apps
|
|
806
|
+
or embed service keys.
|
|
803
807
|
|
|
804
808
|
## Creating a collection / table
|
|
805
809
|
|
|
806
810
|
Pass the engine explicitly \u2014 do not rely on Dataplane's default connector
|
|
807
811
|
resolution. POST /v1/workspaces/{id}/vault/collections with
|
|
808
|
-
\`"schema": {"engine": "postgresql", ...}
|
|
809
|
-
\`"engine": "arangodb"\` to use ArangoDB instead.
|
|
812
|
+
\`"schema": {"engine": "postgresql", ...}\`.
|
|
810
813
|
|
|
811
814
|
## Paths
|
|
812
815
|
|
|
813
816
|
- Browse / edit rows \u2192 Data Vault (portal or vault APIs)
|
|
814
|
-
- Deploy your own
|
|
815
|
-
POST /v1/workspaces/{id}/managed-databases with engine postgres
|
|
817
|
+
- Deploy your own PostgreSQL \u2192 Customer Portal Databases page, or
|
|
818
|
+
POST /v1/workspaces/{id}/managed-databases with engine postgres
|
|
816
819
|
- Shell 403 / empty vault \u2192 collection Access for the site role
|
|
817
820
|
|
|
818
821
|
docs_get id databases. Human docs: /docs/customer-portal/databases and /docs/customer-portal/data-vault
|
|
@@ -865,6 +868,112 @@ stay in Shadow DOM. Render modals inside that root, not document.body.
|
|
|
865
868
|
Full steps: docs_get id css-and-styling.
|
|
866
869
|
`;
|
|
867
870
|
|
|
871
|
+
// src/flags-guide.ts
|
|
872
|
+
var FLAGS_GUIDE = `
|
|
873
|
+
# Feature Flags
|
|
874
|
+
|
|
875
|
+
Groundfloor has built-in feature flags: per-environment key \u2192 value toggles
|
|
876
|
+
(boolean, string, number or JSON) stored in Control Plane. **Use them instead
|
|
877
|
+
of building a flags table in a Vault collection or reading \`.env\`.** Each
|
|
878
|
+
environment (dev / staging / prod) has its own values; \`promote\` copies
|
|
879
|
+
between them.
|
|
880
|
+
|
|
881
|
+
## Manage (builder)
|
|
882
|
+
|
|
883
|
+
\`\`\`bash
|
|
884
|
+
gf flags ls -e dev # -e takes an environment id or name
|
|
885
|
+
gf flags set new-checkout true -e dev # type inferred; --type json for objects
|
|
886
|
+
gf flags compare dev prod
|
|
887
|
+
gf flags promote dev prod --dry-run
|
|
888
|
+
gf flags rm new-checkout -e dev
|
|
889
|
+
\`\`\`
|
|
890
|
+
|
|
891
|
+
Or the Portal: Workspace \u2192 Feature Flags. API (builder \`gf token\`):
|
|
892
|
+
\`GET|PUT|DELETE /v1/workspaces/{id}/flags[/{key}]?environment_id=\`,
|
|
893
|
+
\`GET \u2026/flags/compare\`, \`POST \u2026/flags/promote\` \u2014 docs_get id \`flags-api\`.
|
|
894
|
+
|
|
895
|
+
- **Keys**: trimmed + lowercased, then \`^[a-z][a-z0-9_.-]{0,62}$\` (\`new-checkout\`,
|
|
896
|
+
\`ui.dark_mode\`). \`compare\`, \`promote\`, \`runtime\` are reserved.
|
|
897
|
+
- **Values**: \`value_type\` defaults to \`boolean\`; a mismatched value is 422.
|
|
898
|
+
- **Default environment**: omit \`environment_id\` \u2192 the active env named
|
|
899
|
+
\`dev\` (or the only active env). The response echoes the resolved
|
|
900
|
+
\`environment_id\`. Pass it explicitly for anything prod-facing.
|
|
901
|
+
|
|
902
|
+
## Read at runtime (apps)
|
|
903
|
+
|
|
904
|
+
One endpoint for every runtime:
|
|
905
|
+
|
|
906
|
+
\`GET /v1/workspaces/{workspace_id}/flags/runtime?environment_id=<env>\`
|
|
907
|
+
\u2192 \`{ "workspace_id", "environment_id", "flags": { "new-checkout": true, \u2026 } }\`
|
|
908
|
+
|
|
909
|
+
Weak \`ETag\` + \`Cache-Control: private, no-cache\`. Send \`If-None-Match\` \u2192 304.
|
|
910
|
+
Poll no faster than every 30s (the kit uses 60s). No push channel yet.
|
|
911
|
+
Flag values are not secrets \u2014 every signed-in end user can read them.
|
|
912
|
+
|
|
913
|
+
### Shell federated app (browser)
|
|
914
|
+
|
|
915
|
+
- **Token**: the Shell end-user JWT, \`await window.__GF_GET_ACCESS_TOKEN__()\`.
|
|
916
|
+
- **Permission**: workspace \`read\`. Site users get it from a recognised site
|
|
917
|
+
role (member/admin); self-registered users with no role get 403 (same rule
|
|
918
|
+
as Vault). No per-flag Access grant exists or is needed.
|
|
919
|
+
- **Environment**: \`window.__GF_ENVIRONMENT_ID__\` \u2014 the environment the app is
|
|
920
|
+
bound to, published by the Shell before your remote mounts. Unset in local
|
|
921
|
+
Dev Shell \u2192 server default (dev); \`VITE_GF_ENVIRONMENT_ID\` pins one.
|
|
922
|
+
- **Code**: the starter kit ships \`src/lib/flags.ts\`. Do not hand-roll it.
|
|
923
|
+
|
|
924
|
+
\`\`\`tsx
|
|
925
|
+
import { useFlag, useFlags } from './lib/flags';
|
|
926
|
+
|
|
927
|
+
export function Checkout() {
|
|
928
|
+
const newCheckout = useFlag('new-checkout', false);
|
|
929
|
+
const maxItems = useFlag('max-items', 10);
|
|
930
|
+
return newCheckout ? <NewCheckout max={maxItems} /> : <LegacyCheckout />;
|
|
931
|
+
}
|
|
932
|
+
// Many flags: const { flags, loading, error } = useFlags();
|
|
933
|
+
\`\`\`
|
|
934
|
+
|
|
935
|
+
### Coderunner (server)
|
|
936
|
+
|
|
937
|
+
- **Token**: M2M \u2014 \`gf m2m token\` locally, or exchange
|
|
938
|
+
\`GROUNDFLOOR_M2M_CLIENT_ID\`/\`_SECRET\` at \`POST \u2026/m2m/token\` in code. M2M is
|
|
939
|
+
**read-only** on flags (PUT/DELETE/promote \u2192 403). Workload-identity Vault
|
|
940
|
+
JWTs cannot read flags (403).
|
|
941
|
+
- **Environment**: \`GROUNDFLOOR_ENVIRONMENT_ID\` is injected on deploy (the
|
|
942
|
+
Coderunner's bound environment). \`GROUNDFLOOR_WORKSPACE_ID\`,
|
|
943
|
+
\`CONTROLPLANE_URL\` and the M2M client id/secret are injected when an M2M
|
|
944
|
+
client is attached. Redeploy once to pick up the variable on older deploys.
|
|
945
|
+
|
|
946
|
+
\`\`\`js
|
|
947
|
+
const CP = process.env.CONTROLPLANE_URL;
|
|
948
|
+
const WS = process.env.GROUNDFLOOR_WORKSPACE_ID;
|
|
949
|
+
const ENV = process.env.GROUNDFLOOR_ENVIRONMENT_ID;
|
|
950
|
+
let cache = { etag: null, flags: {} };
|
|
951
|
+
|
|
952
|
+
export async function getFlags(token) {
|
|
953
|
+
const qs = ENV ? \`?environment_id=\${encodeURIComponent(ENV)}\` : '';
|
|
954
|
+
const res = await fetch(\`\${CP}/v1/workspaces/\${WS}/flags/runtime\${qs}\`, {
|
|
955
|
+
headers: {
|
|
956
|
+
Authorization: \`Bearer \${token}\`,
|
|
957
|
+
...(cache.etag ? { 'If-None-Match': cache.etag } : {}),
|
|
958
|
+
},
|
|
959
|
+
});
|
|
960
|
+
if (res.status === 304) return cache.flags;
|
|
961
|
+
if (!res.ok) throw new Error(\`flags \${res.status}: \${await res.text()}\`);
|
|
962
|
+
const body = await res.json();
|
|
963
|
+
cache = { etag: res.headers.get('etag'), flags: body.flags };
|
|
964
|
+
return cache.flags;
|
|
965
|
+
}
|
|
966
|
+
// Call per request with a cached M2M token; refresh at most every 30\u201360s.
|
|
967
|
+
\`\`\`
|
|
968
|
+
|
|
969
|
+
## Errors
|
|
970
|
+
|
|
971
|
+
401 bad/missing token \xB7 403 no workspace read, M2M write, or workload identity \xB7
|
|
972
|
+
404 unknown workspace/environment/flag \xB7 409 environment not active, or no
|
|
973
|
+
active environments \xB7 400 bad or reserved key \xB7 422 value/value_type mismatch \xB7
|
|
974
|
+
423 workspace frozen (writes).
|
|
975
|
+
`.trim();
|
|
976
|
+
|
|
868
977
|
// src/shell-guide.ts
|
|
869
978
|
var SHELL_APP_GUIDE = `
|
|
870
979
|
# Shell federated apps
|
|
@@ -899,10 +1008,9 @@ remoteEntry.js. Header logos: manifest \`theme.logoUrl\` (absolute https).
|
|
|
899
1008
|
UI look: \`docs_get\` id \`design-standard\`. CSS: Tailwind by default;
|
|
900
1009
|
own framework uses FederatedStyleRoot (Shadow DOM) \u2014 \`docs_get\` id
|
|
901
1010
|
\`css-and-styling\`. Data: Dataplane is not a database. Say first: you have
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
(\`docs_get\` id \`databases\`). Local UI without live vault:
|
|
1011
|
+
PostgreSQL (shared, platform-managed, no deploy step) ready through Dataplane.
|
|
1012
|
+
Deploy a dedicated PostgreSQL only if you want workspace-owned isolation.
|
|
1013
|
+
No other engines are offered (\`docs_get\` id \`databases\`). Local UI without live vault:
|
|
906
1014
|
\`npm run dev:fixtures\`.
|
|
907
1015
|
|
|
908
1016
|
Detail routes (e.g. \`records/:id\`): once the record loads, call
|
|
@@ -934,12 +1042,14 @@ POST \`/v1/workspaces/{id}/vault/collections\` with a **JSON Schema** object
|
|
|
934
1042
|
**400** with a field error \u2014 not a 500.
|
|
935
1043
|
|
|
936
1044
|
Pass \`engine\` explicitly \u2014 don't rely on Dataplane's default connector.
|
|
937
|
-
\`"postgresql"\` is the platform default (shared, no deploy step)
|
|
938
|
-
\`
|
|
1045
|
+
\`"postgresql"\` is the platform default (shared, no deploy step) and the only
|
|
1046
|
+
engine offered today. \`?connection=\` must be \`postgresql\` or the name of a dedicated
|
|
1047
|
+
PostgreSQL in this workspace \u2014 another engine or an unknown name is **400**.
|
|
939
1048
|
|
|
940
|
-
\`id\` and \`
|
|
941
|
-
|
|
942
|
-
|
|
1049
|
+
\`id\`, \`tenant_id\`, and \`gf_extra\` are reserved field names \u2014 Dataplane adds
|
|
1050
|
+
them automatically as system columns on every Postgres table. Declaring any of
|
|
1051
|
+
them as a property is a **400**, not a 500. Undeclared record fields are kept in \`gf_extra\` and
|
|
1052
|
+
merged back on read, so extra keys are not lost.
|
|
943
1053
|
|
|
944
1054
|
Example:
|
|
945
1055
|
|
|
@@ -1028,7 +1138,7 @@ var DOC_CATALOG = [
|
|
|
1028
1138
|
id: "developers",
|
|
1029
1139
|
title: "Developers (gf CLI)",
|
|
1030
1140
|
path: "/docs/customer-portal/developers",
|
|
1031
|
-
summary: "gf login, workspaces, deploy, secrets, files, apps, gf m2m token. Coderunner types: function, job, schedule, service (also called Deployment). App authentication optional."
|
|
1141
|
+
summary: "gf login, workspaces, deploy, secrets, feature flags (gf flags), files, apps, gf m2m token. Coderunner types: function, job, schedule, service (also called Deployment). App authentication optional."
|
|
1032
1142
|
},
|
|
1033
1143
|
{
|
|
1034
1144
|
id: "coderunner",
|
|
@@ -1036,7 +1146,7 @@ var DOC_CATALOG = [
|
|
|
1036
1146
|
path: "/docs/customer-portal/coderunner",
|
|
1037
1147
|
summary: "Workload types (function, job, schedule, service/Deployment), runtime contract (scripts.start, 0.0.0.0:8080), Dockerfile for services, Coderunner identities for Vault, App authentication optional, local live data, gf deploy.",
|
|
1038
1148
|
embedded: CODERUNNER_GUIDE,
|
|
1039
|
-
lastUpdated: "2026-09-
|
|
1149
|
+
lastUpdated: "2026-09-25"
|
|
1040
1150
|
},
|
|
1041
1151
|
{
|
|
1042
1152
|
id: "coderunner-runtime",
|
|
@@ -1052,7 +1162,7 @@ var DOC_CATALOG = [
|
|
|
1052
1162
|
path: "/docs/integrations/coderunner/overview",
|
|
1053
1163
|
summary: "Architecture and lifecycle. Prefer docs_get id coderunner for type usage, Dockerfile, and create prerequisites.",
|
|
1054
1164
|
embedded: CODERUNNER_GUIDE,
|
|
1055
|
-
lastUpdated: "2026-09-
|
|
1165
|
+
lastUpdated: "2026-09-25"
|
|
1056
1166
|
},
|
|
1057
1167
|
{
|
|
1058
1168
|
id: "authentication",
|
|
@@ -1084,7 +1194,7 @@ var DOC_CATALOG = [
|
|
|
1084
1194
|
path: "/docs/integrations/shell",
|
|
1085
1195
|
summary: "Product Apps vs Coderunner. Always gf apps init --slug <portal-slug>, then npm run release and gf apps publish --path release.zip. Never zip dist/ or upload only remoteEntry.js.",
|
|
1086
1196
|
embedded: SHELL_APP_GUIDE,
|
|
1087
|
-
lastUpdated: "2026-09-
|
|
1197
|
+
lastUpdated: "2026-09-26"
|
|
1088
1198
|
},
|
|
1089
1199
|
{
|
|
1090
1200
|
id: "design-standard",
|
|
@@ -1106,9 +1216,9 @@ var DOC_CATALOG = [
|
|
|
1106
1216
|
id: "databases",
|
|
1107
1217
|
title: "Databases",
|
|
1108
1218
|
path: "/docs/customer-portal/databases",
|
|
1109
|
-
summary: "Dataplane is not a database.
|
|
1219
|
+
summary: "Dataplane is not a database. PostgreSQL (shared, platform-managed) is ready through Dataplane with no deploy step. A dedicated PostgreSQL you deploy and own is a separate, heavier path. PostgreSQL is the only engine offered.",
|
|
1110
1220
|
embedded: DATABASES_GUIDE,
|
|
1111
|
-
lastUpdated: "2026-09-
|
|
1221
|
+
lastUpdated: "2026-09-26"
|
|
1112
1222
|
},
|
|
1113
1223
|
{
|
|
1114
1224
|
id: "vault",
|
|
@@ -1116,7 +1226,23 @@ var DOC_CATALOG = [
|
|
|
1116
1226
|
path: "/docs/api/vault",
|
|
1117
1227
|
summary: "Create collections with JSON Schema, query totals vs limit, ACLs, implicit tables, nested filters, identities vs M2M.",
|
|
1118
1228
|
embedded: VAULT_GUIDE,
|
|
1119
|
-
lastUpdated: "2026-09-
|
|
1229
|
+
lastUpdated: "2026-09-26"
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
id: "feature-flags",
|
|
1233
|
+
title: "Feature Flags",
|
|
1234
|
+
path: "/docs/customer-portal/feature-flags",
|
|
1235
|
+
summary: "Built-in per-environment feature flags (toggles / config values) \u2014 use these, not a Vault collection. gf flags ls|set|compare|promote. Apps read GET \u2026/flags/runtime: Shell apps with the end-user JWT + window.__GF_ENVIRONMENT_ID__ (starter-kit useFlag), Coderunners with gf m2m token + GROUNDFLOOR_ENVIRONMENT_ID. Default environment is dev.",
|
|
1236
|
+
embedded: FLAGS_GUIDE,
|
|
1237
|
+
lastUpdated: "2026-09-26"
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
id: "flags-api",
|
|
1241
|
+
title: "Feature flags API",
|
|
1242
|
+
path: "/docs/api/flags",
|
|
1243
|
+
summary: "REST reference for flags: list/get/put/delete per environment_id (omitted \u2192 workspace default, dev), compare, promote, runtime read. Key format, value_type validation, auth per method (M2M read-only), error codes.",
|
|
1244
|
+
embedded: FLAGS_GUIDE,
|
|
1245
|
+
lastUpdated: "2026-09-26"
|
|
1120
1246
|
},
|
|
1121
1247
|
{
|
|
1122
1248
|
id: "scheduled-jobs",
|
|
@@ -1124,7 +1250,7 @@ var DOC_CATALOG = [
|
|
|
1124
1250
|
path: "/docs/customer-portal/scheduled-jobs",
|
|
1125
1251
|
summary: "workload_type=schedule plus cron. gf coderunner status shows type/schedule/last_job. Use Process Log, not a public URL.",
|
|
1126
1252
|
embedded: CODERUNNER_GUIDE,
|
|
1127
|
-
lastUpdated: "2026-09-
|
|
1253
|
+
lastUpdated: "2026-09-25"
|
|
1128
1254
|
}
|
|
1129
1255
|
];
|
|
1130
1256
|
function docUrl(entry) {
|
|
@@ -1252,6 +1378,12 @@ function suggestCli(intent, args) {
|
|
|
1252
1378
|
why: "Mutations: gf secrets set|get|rm. MCP only lists keys.",
|
|
1253
1379
|
docs: "https://docs.groundfloor.cloud/docs/customer-portal/developers"
|
|
1254
1380
|
};
|
|
1381
|
+
case "flags":
|
|
1382
|
+
return {
|
|
1383
|
+
command: `gf flags ls${ws}`,
|
|
1384
|
+
why: "Feature flags per environment. Mutations: gf flags set|rm|compare|promote (-e <id|name>). Apps read GET \u2026/flags/runtime (docs_get id feature-flags). Do not build flags in a Vault collection.",
|
|
1385
|
+
docs: "https://docs.groundfloor.cloud/docs/customer-portal/feature-flags"
|
|
1386
|
+
};
|
|
1255
1387
|
case "dataplane":
|
|
1256
1388
|
return {
|
|
1257
1389
|
command: `gf dataplane status${ws} # provision: gf dataplane provision`,
|
|
@@ -1268,7 +1400,7 @@ function suggestCli(intent, args) {
|
|
|
1268
1400
|
default:
|
|
1269
1401
|
return {
|
|
1270
1402
|
command: "gf --help",
|
|
1271
|
-
why: `Unknown intent "${intent}". Use login | switch_workspace | deploy | run | status | logs | environments | cancel_deployment | init_app | publish_app | secrets | dataplane | vault_token.`,
|
|
1403
|
+
why: `Unknown intent "${intent}". Use login | switch_workspace | deploy | run | status | logs | environments | cancel_deployment | init_app | publish_app | secrets | flags | dataplane | vault_token.`,
|
|
1272
1404
|
docs: "https://docs.groundfloor.cloud/docs/customer-portal/developers"
|
|
1273
1405
|
};
|
|
1274
1406
|
}
|
|
@@ -1339,16 +1471,18 @@ server.tool(
|
|
|
1339
1471
|
);
|
|
1340
1472
|
server.tool(
|
|
1341
1473
|
"workspace_context",
|
|
1342
|
-
"Live context for the selected workspace: session, coderunners, apps, dataplane (access layer, not a database), databases_howto, suggested gf commands. Use docs_get id coderunner before deploying; id databases for data work; id css-and-styling for own CSS framework.",
|
|
1474
|
+
"Live context for the selected workspace: session, coderunners, apps, environments (with the default one), feature flags, dataplane (access layer, not a database), databases_howto, suggested gf commands. Use docs_get id coderunner before deploying; id databases for data work; id feature-flags for toggles/config; id css-and-styling for own CSS framework.",
|
|
1343
1475
|
{ workspace_id: wsId },
|
|
1344
1476
|
async ({ workspace_id }) => {
|
|
1345
1477
|
try {
|
|
1346
1478
|
const c = await cfg(workspace_id);
|
|
1347
1479
|
const claims = decodeJwt(c.token) ?? {};
|
|
1348
|
-
const [coderunners, apps, dataplane] = await Promise.all([
|
|
1480
|
+
const [coderunners, apps, dataplane, environments, flags] = await Promise.all([
|
|
1349
1481
|
listCoderunners(c.apiUrl, c.workspaceId),
|
|
1350
1482
|
listApps(c.apiUrl, c.workspaceId).catch(() => ({ apps: [] })),
|
|
1351
|
-
getDataplaneStatus(c.apiUrl, c.workspaceId).catch(() => null)
|
|
1483
|
+
getDataplaneStatus(c.apiUrl, c.workspaceId).catch(() => null),
|
|
1484
|
+
listWorkspaceEnvironments(c.apiUrl, c.workspaceId).catch(() => []),
|
|
1485
|
+
listFlags(c.apiUrl, c.workspaceId).catch(() => null)
|
|
1352
1486
|
]);
|
|
1353
1487
|
return text({
|
|
1354
1488
|
session: {
|
|
@@ -1370,6 +1504,21 @@ server.tool(
|
|
|
1370
1504
|
status: app.status
|
|
1371
1505
|
})),
|
|
1372
1506
|
dataplane,
|
|
1507
|
+
environments: environments.map((env) => ({
|
|
1508
|
+
id: env.id,
|
|
1509
|
+
name: env.name,
|
|
1510
|
+
status: env.status,
|
|
1511
|
+
default: flags ? env.id === flags.environment_id : void 0
|
|
1512
|
+
})),
|
|
1513
|
+
feature_flags_howto: {
|
|
1514
|
+
docs_get: "feature-flags",
|
|
1515
|
+
rule: "Groundfloor has built-in per-environment feature flags. Use them; never build a flags collection in Vault or read toggles from .env.",
|
|
1516
|
+
default_environment_id: flags?.environment_id ?? null,
|
|
1517
|
+
default_environment_flags: flags ? flags.flags.map((f) => ({ key: f.key, value_type: f.value_type, value: f.value })) : null,
|
|
1518
|
+
manage: "gf flags ls|get|set|rm|compare|promote -e <env id or name>. Omitting -e uses the default environment (dev).",
|
|
1519
|
+
shell_app: "Starter-kit src/lib/flags.ts: useFlag('key', fallback). Calls GET /v1/workspaces/{id}/flags/runtime?environment_id=window.__GF_ENVIRONMENT_ID__ with the Shell end-user JWT (needs a site role \u2192 workspace read).",
|
|
1520
|
+
coderunner: "GET \u2026/flags/runtime?environment_id=$GROUNDFLOOR_ENVIRONMENT_ID with an M2M token (gf m2m token). M2M is read-only on flags; workload-identity tokens are rejected."
|
|
1521
|
+
},
|
|
1373
1522
|
coderunner_howto: {
|
|
1374
1523
|
docs_get: "coderunner",
|
|
1375
1524
|
runtime_contract: "coderunner-runtime",
|
|
@@ -1393,10 +1542,10 @@ server.tool(
|
|
|
1393
1542
|
databases_howto: {
|
|
1394
1543
|
docs_get: "databases",
|
|
1395
1544
|
dataplane: "Dataplane is not a database. It is how Groundfloor talks to databases.",
|
|
1396
|
-
say_first: "You have
|
|
1545
|
+
say_first: "You have PostgreSQL ready to use through Dataplane \u2014 shared, platform-managed, already there, no deploy step. If you want your own dedicated database instead, deploy a dedicated PostgreSQL first.",
|
|
1397
1546
|
shared_postgres: 'Default for app data and Vault. Platform-managed, not workspace-owned \u2014 nothing to scale/backup/delete yourself. Pass engine "postgresql" explicitly when creating a collection.',
|
|
1398
|
-
|
|
1399
|
-
|
|
1547
|
+
deploy: "A dedicated PostgreSQL you own is what you can deploy today (portal Data \u2192 Databases).",
|
|
1548
|
+
engines: "PostgreSQL only, shared or dedicated. Do not offer ArangoDB, MongoDB, Redis, ClickHouse, Qdrant or other engines."
|
|
1400
1549
|
},
|
|
1401
1550
|
actions: {
|
|
1402
1551
|
deploy: suggestCli("deploy"),
|
|
@@ -1404,6 +1553,7 @@ server.tool(
|
|
|
1404
1553
|
run: suggestCli("run"),
|
|
1405
1554
|
logs: suggestCli("logs"),
|
|
1406
1555
|
environments: suggestCli("environments"),
|
|
1556
|
+
flags: suggestCli("flags"),
|
|
1407
1557
|
cancel_deployment: suggestCli("cancel_deployment"),
|
|
1408
1558
|
vault_token: suggestCli("m2m_token"),
|
|
1409
1559
|
init_app: suggestCli("init_app"),
|
|
@@ -1641,6 +1791,21 @@ server.tool(
|
|
|
1641
1791
|
}
|
|
1642
1792
|
}
|
|
1643
1793
|
);
|
|
1794
|
+
server.tool(
|
|
1795
|
+
"flags_list",
|
|
1796
|
+
"List feature flags and values in one environment (omit environment_id \u2192 workspace default, dev; response echoes the resolved id). To set/delete/promote, use `gf flags`. docs_get id feature-flags for runtime use.",
|
|
1797
|
+
{ workspace_id: wsId, environment_id: z.string().optional() },
|
|
1798
|
+
async (args) => {
|
|
1799
|
+
try {
|
|
1800
|
+
const c = await cfg(args.workspace_id);
|
|
1801
|
+
return text(
|
|
1802
|
+
await listFlags(c.apiUrl, c.workspaceId, args.environment_id)
|
|
1803
|
+
);
|
|
1804
|
+
} catch (e) {
|
|
1805
|
+
return errText(e);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1644
1809
|
server.tool(
|
|
1645
1810
|
"files_list",
|
|
1646
1811
|
"List workspace files (read-only). Upload/download with `gf files`.",
|
|
@@ -1674,7 +1839,7 @@ server.tool(
|
|
|
1674
1839
|
);
|
|
1675
1840
|
server.tool(
|
|
1676
1841
|
"dataplane_status",
|
|
1677
|
-
"Dataplane setup status (Dataplane is how Groundfloor talks to databases, not a database itself).
|
|
1842
|
+
"Dataplane setup status (Dataplane is how Groundfloor talks to databases, not a database itself). PostgreSQL (shared, platform-managed) is ready through it by default. Provision with `gf dataplane provision`.",
|
|
1678
1843
|
{ workspace_id: wsId },
|
|
1679
1844
|
async ({ workspace_id }) => {
|
|
1680
1845
|
try {
|
|
@@ -1744,6 +1909,7 @@ server.tool(
|
|
|
1744
1909
|
"init_app",
|
|
1745
1910
|
"publish_app",
|
|
1746
1911
|
"secrets",
|
|
1912
|
+
"flags",
|
|
1747
1913
|
"dataplane",
|
|
1748
1914
|
"vault_token",
|
|
1749
1915
|
"m2m_token"
|