@gxp-dev/tools 2.0.77 → 2.0.79

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.
@@ -1009,7 +1009,7 @@ function buildInteractiveInitialPrompt(projectName, description, provider) {
1009
1009
  "- What real-world data it reads/writes — identify the concrete platform operationIds via the MCP, never invent them",
1010
1010
  "- Which real-time events matter (use `api_find_events_for_operation` for each planned operationId)",
1011
1011
  "- Every piece of admin-editable content: strings, assets, colors/thresholds/settings, feature toggles",
1012
- '- Whether this is a **form app** (quiz, survey, questionnaire, signup flow). If yes, set `formTemplate: true` in `app-manifest.json` and populate `configuration.json`\'s `formTemplate` root array with starter question cards (`config_add_card` with `parent_path: "/formTemplate"` — auto-initializes). See the instructions file for the full pattern. Keep end-user questions in `formTemplate` and admin config in `additionalTabs` do not mix the two.',
1012
+ '- Whether the plugin uses the platform\'s **form/quiz/survey API** at all. The rule has two independent parts — do not collapse them. (a) **Capability flag.** Any time the plugin calls form/quiz operationIds (creating a form, reading questions, submitting responses, listing form data), set `"formTemplate": true` in `app-manifest.json`. The platform uses this to auto-provision a `ProjectForm` for the install. Required regardless of whether you ship starter questions. (b) **Prepopulated questions.** If you want the admin to install with a starter question set instead of an empty form, also populate `configuration.json`\'s `formTemplate` root array (`config_add_card` with `parent_path: "/formTemplate"` — auto-initializes). Optional payload; the platform seeds the auto-provisioned form from it. At runtime the plugin still declares its form dependencies in `app-manifest.json` (e.g. a `quiz_form` identifier bound to `ProjectForm`) and calls `store.callApi("forms.show", "quiz_form")` / `store.callApi("form_responses.store", "quiz_form", {...})`. End-user questions go in `formTemplate`; admin plugin config stays in `additionalTabs`. Never mix.',
1013
1013
  "",
1014
1014
  "Then propose a plan — screens/components, data flow, admin configuration form, and the exact keys you'll add to `app-manifest.json` — and get my confirmation before implementing.",
1015
1015
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gxp-dev/tools",
3
- "version": "2.0.77",
3
+ "version": "2.0.79",
4
4
  "description": "Dev tools to create platform plugins",
5
5
  "type": "commonjs",
6
6
  "publishConfig": {
@@ -313,6 +313,19 @@ export default defineConfig(async (ctx) => {
313
313
  vue(),
314
314
  // GxP Inspector plugin for browser extension integration
315
315
  ...(useInspector ? [gxpInspectorPlugin()] : []),
316
+ // `externalGlobals` rewrites `import ... from "vue"` → references to
317
+ // the `Vue` global that the GxP platform exposes on `window`, and
318
+ // `@/stores/gxpPortalConfigStore` imports → `window.useGxpStore`.
319
+ //
320
+ // We want this to run in BOTH dev and build so user source code keeps
321
+ // the same external-store indirection regardless of mode. The only
322
+ // exception is the toolkit's own runtime code (`@gxp-dev/tools/runtime/
323
+ // *.js` and the workspace equivalent) — that code bootstraps its own
324
+ // local Vue + Pinia via main.js (createApp + app.use) and would crash
325
+ // with "getActivePinia() was called" if its `from "pinia"` were
326
+ // rewritten to a non-existent `window.Pinia`.
327
+ //
328
+ // So: exclude the toolkit's runtime from the transform.
316
329
  externalGlobals(
317
330
  {
318
331
  vue: "Vue",
@@ -320,11 +333,14 @@ export default defineConfig(async (ctx) => {
320
333
  "@/stores/gxpPortalConfigStore":
321
334
  "(window.useGxpStore || (() => { console.warn('useGxpStore not found on window, using fallback'); return {}; }))",
322
335
  },
323
- // No `include` filter — rewrite `from "vue"` / `from "pinia"`
324
- // in every module of the final bundle, including transitive deps
325
- // from node_modules (component libraries, etc.). Without this,
326
- // deps' internal `import { h } from "vue"` leak through as bare
327
- // specifiers and crash at runtime on the platform.
336
+ {
337
+ exclude: [
338
+ // Consumer install (published toolkit from npm)
339
+ "**/node_modules/@gxp-dev/tools/**",
340
+ // Workspace / `npm link` / self-dev: the runtime source itself
341
+ `${runtimeDir.replace(/\\/g, "/")}/**`,
342
+ ],
343
+ },
328
344
  ),
329
345
  // Custom request logging and CORS plugin
330
346
  {
@@ -524,12 +524,38 @@ Every mutation is linter-guarded against `bin/lib/lint/schemas/`. If a write is
524
524
 
525
525
  ## Form / Quiz / Survey Apps — `formTemplate`
526
526
 
527
- Some plugins _are_ a form: a quiz, a survey, a signup flow. For those, ship a starter question set an admin can customize on install. Two keys, kept consistent:
527
+ `formTemplate` appears in **two** files and the two meanings are **independent**. Don't collapse them treat the manifest flag and the configuration array as separate decisions.
528
528
 
529
- 1. **`app-manifest.json` `"formTemplate": true`** — flags the plugin as a form app so the platform opts into form-specific UI (question editor, response viewer).
530
- 2. **`configuration.json` → `"formTemplate": [ ...cards ]`** — array of cards defining the starter form sections, same shape as `additionalTabs`. Typically `fields_list` cards whose `fieldsList` items are the end-user questions.
529
+ ### The two keys
531
530
 
532
- ### Minimal example
531
+ **1. `app-manifest.json` → `"formTemplate": true` — capability flag.**
532
+
533
+ Set this **any time** the plugin calls the platform's form/quiz/survey API: creating a form, reading questions, submitting responses, listing form data. It tells the platform "this plugin uses a form resource" and opts the install into form-specific behavior — auto-provisioning a `ProjectForm` for the install, enabling the question editor and response viewer in the admin UI, etc. **Required whenever form/quiz operationIds are in play, regardless of whether you ship starter questions.**
534
+
535
+ **2. `configuration.json` → `"formTemplate": [ ...cards ]` — prepopulated starter questions.**
536
+
537
+ An array of cards (same shape as `additionalTabs`, typically `fields_list`) that the platform seeds into the auto-provisioned `ProjectForm` at install time. **Optional** — omit it if you want the admin to build the form from scratch.
538
+
539
+ ### The rule — three scenarios
540
+
541
+ | Scenario | Manifest `formTemplate` | Configuration `formTemplate` |
542
+ | ----------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------- |
543
+ | Uses form/quiz API, no starter questions | **`true`** (required) | omit |
544
+ | Uses form/quiz API, with starter questions | **`true`** (required) | `[ ...cards ]` |
545
+ | Doesn't touch the form/quiz API | omit / `false` | must not be set |
546
+ | You have starter questions but the manifest flag is missing | — wrong: the array is dead content until the flag is `true` | — |
547
+
548
+ In one line: **uses form API → flag is true.** **Wants to prepopulate questions → array is populated.** These are independent decisions.
549
+
550
+ ### How it lands at runtime
551
+
552
+ 1. Install-time: platform sees `formTemplate: true` in the manifest → auto-provisions a `ProjectForm` for this plugin install.
553
+ 2. If `configuration.json` has a `formTemplate` array → platform seeds that new form with those cards/questions. If absent → the form is empty and the admin fills it in.
554
+ 3. The plugin still declares its form dependencies in `app-manifest.json` (e.g. `{ "identifier": "quiz_form", "model": "ProjectForm" }`) and the admin binds that identifier to the auto-provisioned form. Plugin code then calls `store.callApi("forms.show", "quiz_form")`, `store.callApi("form_responses.store", "quiz_form", {...})`, etc.
555
+ 4. Discover the right operationIds via MCP: `api_list_tags`, then `api_list_operation_ids --tag Forms` (or `search_api_endpoints quiz`). Never invent them.
556
+ 5. After install the admin owns the form — they can add/remove/reorder questions. Your `formTemplate` is a starting point, not a lock.
557
+
558
+ ### Minimal example — form app with starter questions and a dependency
533
559
 
534
560
  ```json
535
561
  // app-manifest.json
@@ -540,8 +566,13 @@ Some plugins _are_ a form: a quiz, a survey, a signup flow. For those, ship a st
540
566
  "settings": {},
541
567
  "strings": { "default": { "title": "Welcome Quiz" } },
542
568
  "assets": {},
543
- "dependencies": [],
544
- "permissions": []
569
+ "dependencies": [{ "identifier": "quiz_form", "model": "ProjectForm" }],
570
+ "permissions": [
571
+ {
572
+ "identifier": "quiz_form",
573
+ "description": "Read questions and submit responses"
574
+ }
575
+ ]
545
576
  }
546
577
  ```
547
578
 
@@ -323,14 +323,42 @@ If a mutation is refused, read the validation error and fix the input — do not
323
323
 
324
324
  ## Form / Quiz / Survey Apps — `formTemplate`
325
325
 
326
- Some plugins _are_ a form a quiz, a survey, a signup questionnaire, a check-in flow. For those, the configuration file ships a second root-level card array, `formTemplate`, that holds the starter questions an admin customizes on install.
326
+ `formTemplate` appears in **two** places and they mean **two different things**. Read this section carefully treat the manifest flag and the configuration array as independent decisions.
327
327
 
328
- **Two keys tie this together. You must set both consistently.**
328
+ ### The two keys
329
329
 
330
- 1. **`app-manifest.json` → `"formTemplate": true`**declares the plugin as a form app. Platforms use this to opt the install into form-specific UI (question editor, response viewer, etc.).
331
- 2. **`configuration.json` → `"formTemplate": [ ...cards ]`** — the starter question set, structured identically to `additionalTabs`: an array of cards, typically `fields_list` sections, each with a `fieldsList` of question fields.
330
+ **1. `app-manifest.json` → `"formTemplate": true` — the capability flag.**
332
331
 
333
- ### Minimal example
332
+ Set this any time the plugin calls the platform's form/quiz/survey API — creating a form, reading responses, submitting answers, listing questions. It tells the platform "this plugin owns or consumes a form resource" and opts the install into form-specific behavior (question editor in the admin UI, response viewer, auto-provisioned `ProjectForm`, etc.). **Required** whenever you're using form/quiz operationIds, regardless of whether you ship prepopulated questions.
333
+
334
+ **2. `configuration.json` → `"formTemplate": [ ...cards ]` — the prepopulated questions.**
335
+
336
+ A starter question set the platform seeds into the auto-provisioned form at install time, so the admin doesn't start from an empty form. Structured identically to `additionalTabs`: an array of cards (usually `fields_list`) whose `fieldsList` items are the questions. **Optional** — only set it when you actually want to ship starter content. If omitted, the platform provisions an empty form and the admin builds it from scratch.
337
+
338
+ ### The rule
339
+
340
+ | Scenario | Manifest `formTemplate` | Configuration `formTemplate` |
341
+ | ----------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------- |
342
+ | Plugin calls form/quiz API, ships no starter questions | **`true`** (required) | omit / leave empty |
343
+ | Plugin calls form/quiz API, ships starter questions | **`true`** (required) | `[ ...cards ]` |
344
+ | Plugin does **not** touch the form/quiz API | omit / `false` | must not be set |
345
+ | You want starter questions but didn't set the manifest flag | — fix this — the array is dead content unless the flag is true | — |
346
+
347
+ Short version:
348
+
349
+ - **Uses form/quiz API → manifest `formTemplate: true`.** Non-negotiable.
350
+ - **Wants to prepopulate questions → configuration `formTemplate: [...]`.** Optional payload.
351
+
352
+ ### How the pieces connect at runtime
353
+
354
+ 1. At install time the platform sees `formTemplate: true` in the manifest and auto-provisions a `ProjectForm` for this plugin install.
355
+ 2. If `configuration.json` includes a `formTemplate` array, the platform seeds the new `ProjectForm` with those questions. If not, it creates an empty form.
356
+ 3. The plugin code still declares whichever form/quiz dependencies it needs in `app-manifest.json` (e.g. `quiz_form`, `response_stream`) and calls `store.callApi("forms.show", "quiz_form")` / `store.callApi("form_responses.store", "quiz_form", {...})` etc. Discover the right operationIds via the MCP (`search_api_endpoints quiz`, `api_list_operation_ids --tag Forms`).
357
+ 4. The admin can edit, add, or remove questions on the auto-provisioned form after install. Your `formTemplate` array is a starting point, not a lock — the admin owns the form once it's provisioned.
358
+
359
+ So: the manifest flag wires up the form backing store; the configuration array pre-seeds its contents; the dependency bindings scope which form the plugin talks to at runtime. Three independent concerns, all of which you need for a proper form app.
360
+
361
+ ### Minimal example — form app with starter questions
334
362
 
335
363
  ```json
336
364
  // app-manifest.json
@@ -341,8 +369,13 @@ Some plugins _are_ a form — a quiz, a survey, a signup questionnaire, a check-
341
369
  "settings": {},
342
370
  "strings": { "default": { "title": "Welcome Quiz" } },
343
371
  "assets": {},
344
- "dependencies": [],
345
- "permissions": []
372
+ "dependencies": [{ "identifier": "quiz_form", "model": "ProjectForm" }],
373
+ "permissions": [
374
+ {
375
+ "identifier": "quiz_form",
376
+ "description": "The quiz form — read questions and submit responses"
377
+ }
378
+ ]
346
379
  }
347
380
  ```
348
381
 
@@ -384,12 +417,12 @@ Use the same `config_*` tools you'd use for `additionalTabs`, pointed at the `/f
384
417
 
385
418
  Use the same field types as any other form (`text`, `textarea`, `number`, `radio`, `checkbox`, `select`, `asyncSelect`, `selectAsset`, etc.). Question names live under `fieldsList[].name` — these become the response keys the platform stores.
386
419
 
387
- ### When to use `formTemplate` vs `additionalTabs`
420
+ ### Don't confuse `formTemplate` with `additionalTabs`
388
421
 
389
422
  - `additionalTabs` — **admin** configuration form (every plugin has this). The person installing the plugin fills this in once.
390
423
  - `formTemplate` — **end-user** form questions (only form apps). Admins may tweak these before publishing; end users (attendees, staff) answer them at runtime.
391
424
 
392
- Don't confuse them. Strings, assets, dependencies, colors → `additionalTabs`. Quiz/survey questions that end users will answer → `formTemplate`.
425
+ Strings, assets, dependencies, colors → `additionalTabs`. Quiz/survey questions that end users will answer → `formTemplate`.
393
426
 
394
427
  Finish with `gxdev lint --all`. The linter validates both roots against the same card/field schema, so malformed questions fail in the same way malformed admin fields do.
395
428
 
@@ -233,18 +233,36 @@ Tools: `config_list_card_types`, `config_list_field_types`, `config_get_field_sc
233
233
 
234
234
  ## Form / Quiz / Survey Apps — `formTemplate`
235
235
 
236
- If the plugin _is_ a form (quiz, survey, questionnaire), ship a starter question set the admin can customize on install. Two keys, both required, must be kept consistent:
236
+ `formTemplate` lives in two files and the two meanings are independent don't treat them as a single toggle.
237
237
 
238
- 1. `app-manifest.json` `"formTemplate": true` — marks the plugin as a form app.
239
- 2. `configuration.json` → `"formTemplate": [ ...cards ]` — array of cards (same shape as `additionalTabs`), typically `fields_list` sections whose `fieldsList` items are the questions.
238
+ ### The two keys
240
239
 
241
- Build it with the same MCP tools, pointed at `/formTemplate`:
240
+ - **`app-manifest.json` `"formTemplate": true` — capability flag.** Set **any time** the plugin uses the platform's form/quiz/survey API (creating a form, reading questions, submitting responses, etc.). Tells the platform to auto-provision a `ProjectForm` for this install and opt into form-specific admin UI. Required whenever form/quiz operationIds are in play, regardless of whether you ship starter questions.
241
+
242
+ - **`configuration.json` → `"formTemplate": [ ...cards ]` — prepopulated questions.** Starter question set the platform seeds into the auto-provisioned form at install time. Structured identically to `additionalTabs`. Optional — omit to let the admin build the form from scratch.
243
+
244
+ ### The rule
245
+
246
+ - Uses form/quiz API → manifest `formTemplate: true`. Non-negotiable.
247
+ - Wants to ship starter questions → configuration `formTemplate: [...]`. Optional payload.
248
+ - Doesn't touch the form/quiz API → neither key.
249
+
250
+ ### Runtime flow
251
+
252
+ 1. `formTemplate: true` in the manifest → platform auto-provisions a `ProjectForm` on install.
253
+ 2. `formTemplate` array in configuration.json (if present) → seeds the new form with those starter questions.
254
+ 3. Plugin code still declares form dependencies (e.g. `quiz_form`) in `app-manifest.json` and calls `store.callApi("forms.show", "quiz_form")` / `store.callApi("form_responses.store", "quiz_form", {...})` — discover operationIds via the MCP (`search_api_endpoints quiz` / `api_list_operation_ids --tag Forms`).
255
+ 4. The admin owns the form after install; your array is a starting point, not a lock.
256
+
257
+ ### Building `formTemplate` with the MCP
242
258
 
243
259
  - `config_add_card` with `parent_path: "/formTemplate"` (the array is auto-initialized on first add).
244
260
  - `config_add_field` with `card_path: "/formTemplate/0"` to add questions to a section.
245
261
  - `config_list_cards` surfaces both `/additionalTabs` and `/formTemplate` cards.
246
262
 
247
- Mental model: `additionalTabs` = **admin** config (every plugin). `formTemplate` = **end-user** questions (only form apps). Admin strings, assets, colors, dependency bindings → `additionalTabs`. Questions an attendee/user will answer → `formTemplate`.
263
+ ### Don't confuse with `additionalTabs`
264
+
265
+ `additionalTabs` = **admin** config (every plugin). `formTemplate` = **end-user** questions (only form apps). Admin strings, assets, colors, dependency bindings → `additionalTabs`. Questions an attendee/user will answer → `formTemplate`.
248
266
 
249
267
  ## Component Kit
250
268