@mccaskie-labs/workbench-config 0.2.3 → 0.2.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/CHANGELOG.md +12 -0
- package/capabilities/ai.json +183 -3
- package/capabilities/analytics.json +47 -3
- package/capabilities/country.json +160 -3
- package/capabilities/image-search.json +154 -3
- package/capabilities/images.json +192 -3
- package/capabilities/ui.json +27 -2
- package/dist/capabilities.gen.d.ts +602 -7
- package/dist/capabilities.gen.js +759 -13
- package/dist/capability-schema.d.ts +1 -1
- package/dist/capability-schema.js +1 -1
- package/dist/skills.js +1 -1
- package/package.json +1 -1
package/dist/capabilities.gen.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by `npm run capabilities:build` from capabilities/*.json. Do not edit.
|
|
2
2
|
// check:capabilities fails in Checks when this file is stale.
|
|
3
|
-
export const MANIFEST_VERSION = "
|
|
3
|
+
export const MANIFEST_VERSION = "b74fc43c59b7";
|
|
4
4
|
export const capabilities = {
|
|
5
5
|
"ai": {
|
|
6
6
|
"$schema": "./schema.json",
|
|
@@ -294,10 +294,190 @@ export const capabilities = {
|
|
|
294
294
|
"cost_hint_usd": 0.008
|
|
295
295
|
}
|
|
296
296
|
],
|
|
297
|
+
"offer": {
|
|
298
|
+
"pattern": "feature_or_content",
|
|
299
|
+
"when": "The client wants the app to write, summarise, sort, answer questions or pull details out of text with AI, as a feature visitors use, or wants wording for the site written once.",
|
|
300
|
+
"say": "I'll do this with Workbench AI, which uses Claude through Workbench, so the app holds no AI key and spending has a monthly cap.",
|
|
301
|
+
"answers_file": "workbench/ai/<name>.json",
|
|
302
|
+
"per": "feature or piece of wording",
|
|
303
|
+
"answers_format": "For a feature: `{ \"format\": 1, \"route\": \"feature\", \"name\", \"about\" (the client's words), \"who\", \"cap_usd\", \"keep\", \"job\" }`, where `job` is the `X-Workbench-Job` the feature's calls send (`<name>` with dots, such as `quotes.estimate`), so its spending shows on its own line in Control. Write it, then build the feature with the package. For wording made once: `npx workbench-ai pick <name> <round>-<draft>` writes it from the draft the client picked, with the round's request ids and cost; never write one from nothing. Then put the wording into the strings catalogue (the workbench-strings skill), keyed for where it is shown. Drafts and their previews stay in `workbench/ai/drafts/`, which isn't committed.",
|
|
304
|
+
"questions": [
|
|
305
|
+
{
|
|
306
|
+
"id": "ai.route",
|
|
307
|
+
"sets": "route",
|
|
308
|
+
"ask": "Is this something visitors use on the site, or something made once for the site?",
|
|
309
|
+
"style": "cards",
|
|
310
|
+
"answers": [
|
|
311
|
+
{
|
|
312
|
+
"label": "Visitors use it",
|
|
313
|
+
"value": "feature",
|
|
314
|
+
"means": "A feature on the site that calls the AI each time someone uses it, such as a question box or a summary of what they paste in."
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"label": "Made once for the site",
|
|
318
|
+
"value": "content",
|
|
319
|
+
"means": "Wording for a page, written once and kept: an About page, a welcome, product descriptions."
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"must_ask": true,
|
|
323
|
+
"note": "Ask it even when the client's words seem to say, as a quick check: the two routes are built and paid for differently."
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"id": "ai.who",
|
|
327
|
+
"sets": "feature.who",
|
|
328
|
+
"ask": "Who may use it?",
|
|
329
|
+
"style": "cards",
|
|
330
|
+
"answers": [
|
|
331
|
+
{
|
|
332
|
+
"label": "People who are signed in",
|
|
333
|
+
"value": "signed_in",
|
|
334
|
+
"means": "Anyone with an account. Each use is tied to a person, so misuse can be traced and stopped."
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"label": "Admins only",
|
|
338
|
+
"value": "admins",
|
|
339
|
+
"means": "Only the business's own admins, for example a tool for writing their own posts."
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"label": "Anyone visiting",
|
|
343
|
+
"value": "anyone",
|
|
344
|
+
"means": "No sign-in. The page checks for bots (Turnstile) and limits how often one visitor can use it."
|
|
345
|
+
}
|
|
346
|
+
],
|
|
347
|
+
"when": {
|
|
348
|
+
"id": "ai.route",
|
|
349
|
+
"is": [
|
|
350
|
+
"feature"
|
|
351
|
+
]
|
|
352
|
+
},
|
|
353
|
+
"note": "Signed in means `requireUser` and admins means `app_admins`, as the workbench-sign-in skill says. For anyone, check Turnstile on every use and keep a per-visitor limit; say plainly that strangers can run up the cost. Pass `subject` on every call so the Gateway can tell people apart: `user:<id>` for a signed-in person, and for anyone a random id kept in a cookie (`visitor:<id>`), never an email address or name."
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"id": "ai.cap",
|
|
357
|
+
"sets": "feature.cap_usd",
|
|
358
|
+
"ask": "How much may it spend in a month, at most? When it's reached, the feature stops until next month.",
|
|
359
|
+
"style": "cards",
|
|
360
|
+
"answers": [
|
|
361
|
+
{
|
|
362
|
+
"label": "US$5 a month",
|
|
363
|
+
"value": 5,
|
|
364
|
+
"means": "A small trial, or light use."
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"label": "US$20 a month",
|
|
368
|
+
"value": 20,
|
|
369
|
+
"means": "Steady use by a small business's visitors."
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"label": "US$50 a month",
|
|
373
|
+
"value": 50,
|
|
374
|
+
"means": "Heavy use. It can be raised later."
|
|
375
|
+
}
|
|
376
|
+
],
|
|
377
|
+
"other": {
|
|
378
|
+
"kind": "money",
|
|
379
|
+
"min": 1,
|
|
380
|
+
"max": 1000,
|
|
381
|
+
"description": "US dollars a month, whole or with cents."
|
|
382
|
+
},
|
|
383
|
+
"must_ask": true,
|
|
384
|
+
"when": {
|
|
385
|
+
"id": "ai.route",
|
|
386
|
+
"is": [
|
|
387
|
+
"feature"
|
|
388
|
+
]
|
|
389
|
+
},
|
|
390
|
+
"note": "Say roughly what one use costs (usually a cent or two with claude-default) so the owner can judge. The cap is the project's production cap for the `ai` tool in the Gateway, shared by every feature that uses it: set it with Workbench Control's `gw_budget_set` (env production, tool ai, monthly_usd). Raising a cap waits for the owner's approval on Control's approval page. When it is reached, calls fail with `budget_exceeded`: the page says the feature is resting until next month, never an error."
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"id": "ai.sensitive",
|
|
394
|
+
"sets": "feature.keep",
|
|
395
|
+
"ask": "Will people type in sensitive personal details, such as their health, religion, money troubles or someone else's private information?",
|
|
396
|
+
"style": "cards",
|
|
397
|
+
"answers": [
|
|
398
|
+
{
|
|
399
|
+
"label": "No",
|
|
400
|
+
"value": "no",
|
|
401
|
+
"means": "Workbench keeps what each call sent and got back, so a problem can be traced."
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"label": "Yes",
|
|
405
|
+
"value": "yes",
|
|
406
|
+
"means": "This feature's calls are marked not to be kept: Workbench records only that each call happened and what it cost."
|
|
407
|
+
}
|
|
408
|
+
],
|
|
409
|
+
"must_ask": true,
|
|
410
|
+
"when": {
|
|
411
|
+
"id": "ai.route",
|
|
412
|
+
"is": [
|
|
413
|
+
"feature"
|
|
414
|
+
]
|
|
415
|
+
},
|
|
416
|
+
"note": "With yes, pass `keep: false` on this feature's calls. If most of the app handles such details, suggest switching keeping off for the whole project instead (Workbench Control's `gw_keep_set`, env production, on false). Record it as `keep` (true or false) in the answers file."
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"id": "ai.what",
|
|
420
|
+
"sets": [
|
|
421
|
+
"content.name",
|
|
422
|
+
"content.about"
|
|
423
|
+
],
|
|
424
|
+
"ask": "What wording do you need?",
|
|
425
|
+
"style": "cards",
|
|
426
|
+
"answers": [
|
|
427
|
+
{
|
|
428
|
+
"label": "A page's main text",
|
|
429
|
+
"value": "page_text",
|
|
430
|
+
"means": "Such as an About page or a services page."
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
"label": "A short blurb",
|
|
434
|
+
"value": "blurb",
|
|
435
|
+
"means": "A line or two for the top of a page or a card."
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"label": "Descriptions",
|
|
439
|
+
"value": "descriptions",
|
|
440
|
+
"means": "For products or services."
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
"other": {
|
|
444
|
+
"kind": "text",
|
|
445
|
+
"min": 3,
|
|
446
|
+
"max": 200,
|
|
447
|
+
"description": "What the wording is, in a few words."
|
|
448
|
+
},
|
|
449
|
+
"when": {
|
|
450
|
+
"id": "ai.route",
|
|
451
|
+
"is": [
|
|
452
|
+
"content"
|
|
453
|
+
]
|
|
454
|
+
},
|
|
455
|
+
"note": "Name the piece after where it goes (about_us, home_blurb): lower case and underscores. The client's own words, with any facts they give (when they started, where they are), go in --about, because the drafts never invent facts and leave [gaps] for the owner instead."
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"not_asked": [
|
|
459
|
+
{
|
|
460
|
+
"sets": "model",
|
|
461
|
+
"why": "Features use claude-default unless the work needs more (claude-best) or speed matters more than depth (claude-fast). Choose from what the feature does; the client can't judge models."
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
"sets": "voice",
|
|
465
|
+
"why": "The tone comes from the project's voice and spelling, set once for the whole site."
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
"drafts": {
|
|
469
|
+
"of": "wording",
|
|
470
|
+
"surface": "ai",
|
|
471
|
+
"alias": "claude-default",
|
|
472
|
+
"count": 3,
|
|
473
|
+
"max_rounds": 3,
|
|
474
|
+
"job": "ai.drafts",
|
|
475
|
+
"command": "npx workbench-ai drafts text <name> --about \"<what it is for, with the client's facts>\""
|
|
476
|
+
}
|
|
477
|
+
},
|
|
297
478
|
"delivery": {
|
|
298
479
|
"choice": "built_in",
|
|
299
|
-
"intro": "Writing, summarising and answering questions with Claude, with a monthly spending cap."
|
|
300
|
-
"when": "The client wants the app to write, summarise, sort, answer questions or pull details out of text with AI, as a feature visitors use or as something made once for the site."
|
|
480
|
+
"intro": "Writing, summarising and answering questions with Claude, with a monthly spending cap."
|
|
301
481
|
}
|
|
302
482
|
},
|
|
303
483
|
"analytics": {
|
|
@@ -397,10 +577,54 @@ export const capabilities = {
|
|
|
397
577
|
"note": "Create the site, drive page views, query them back (cf_analytics_query, later)"
|
|
398
578
|
}
|
|
399
579
|
],
|
|
580
|
+
"offer": {
|
|
581
|
+
"pattern": "switch_on",
|
|
582
|
+
"when": "The client wants to know how many people visit, which pages they open, or to count an action such as a sign-up or an order.",
|
|
583
|
+
"say": "The project already has Workbench visitor counts: page views counted by Cloudflare without cookies, and the actions you choose counted in the app's own database. I'll switch on what you want.",
|
|
584
|
+
"answers_file": "workbench/analytics.json",
|
|
585
|
+
"answers_format": "`{ \"format\": 1, \"page_views\": true, \"events\": [{ \"name\": \"order.placed\", \"when\": \"a customer sends an order\", \"details\": [\"items\", \"total_band\"] }] }`. For page views, create the Web Analytics site with Workbench Control (`cf_web_analytics_site_create`), write its beacon token onto staging and production (`cf_worker_secret_put source=web_analytics`), and put `beacon(env)` on every page customers see. For each event, call `eventsFor(db).track(name, details)` where the action happens.",
|
|
586
|
+
"questions": [
|
|
587
|
+
{
|
|
588
|
+
"id": "analytics.page-views",
|
|
589
|
+
"sets": "page_views",
|
|
590
|
+
"ask": "Should the site count its page views?",
|
|
591
|
+
"style": "cards",
|
|
592
|
+
"answers": [
|
|
593
|
+
{
|
|
594
|
+
"label": "Yes",
|
|
595
|
+
"value": true,
|
|
596
|
+
"means": "How many people visit and which pages they open, counted by Cloudflare. No cookies, and no personal details kept."
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
"label": "No",
|
|
600
|
+
"value": false,
|
|
601
|
+
"means": "Nothing is counted on the site's pages."
|
|
602
|
+
}
|
|
603
|
+
],
|
|
604
|
+
"note": "Only pages customers see; never the owner's or admins' pages."
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
"id": "analytics.actions",
|
|
608
|
+
"sets": "events",
|
|
609
|
+
"ask": "Which actions should be counted?",
|
|
610
|
+
"style": "table",
|
|
611
|
+
"note": "Propose the few actions that show whether the site is working for the business (a sign-up, an order, a booking, a form sent), each with a name (`thing.past_verb`, lower case: `order.placed`), when it happens in the client's words, and its details. Details are counts, choices and bands (`items`, `plan`, `total_band`), never an email address, a name, a phone number or free text someone typed. The client accepts, removes or adds; an empty list is fine."
|
|
612
|
+
}
|
|
613
|
+
],
|
|
614
|
+
"not_asked": [
|
|
615
|
+
{
|
|
616
|
+
"sets": "consent",
|
|
617
|
+
"why": "The page-view counter sets no cookies and keeps no personal details, and events hold none either, so they add nothing that a cookie notice would need to cover."
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"sets": "reports",
|
|
621
|
+
"why": "Page views are seen in Cloudflare's Web Analytics, and events are rows in the app's own `events` table; ask what the owner wants to see when they ask for a report."
|
|
622
|
+
}
|
|
623
|
+
]
|
|
624
|
+
},
|
|
400
625
|
"delivery": {
|
|
401
626
|
"choice": "optional",
|
|
402
|
-
"intro": "Counting page views and the things visitors do on the site."
|
|
403
|
-
"when": "The client wants to know how many people visit, which pages they open, or to count an action such as a sign-up or an order."
|
|
627
|
+
"intro": "Counting page views and the things visitors do on the site."
|
|
404
628
|
}
|
|
405
629
|
},
|
|
406
630
|
"config": {
|
|
@@ -616,10 +840,167 @@ export const capabilities = {
|
|
|
616
840
|
"note": "Every pack's spelling is one the Gateway accepts (en-PH, en-AU, en-GB, en-US), checked against the ai manifest's spellings; no Gateway call"
|
|
617
841
|
}
|
|
618
842
|
],
|
|
843
|
+
"offer": {
|
|
844
|
+
"pattern": "project",
|
|
845
|
+
"when": "The app shows a date, a time, a number, a phone number or an amount of money to its readers, or the client says where their readers are.",
|
|
846
|
+
"say": "I'll write dates, times and money with Workbench country formats, the way your readers expect them. That needs to know where they are, once for the whole site.",
|
|
847
|
+
"answers_file": "workbench/country.json",
|
|
848
|
+
"answers_format": "`{ \"format\": 1, \"country\": \"AU\", \"time_zone\": null, \"currency\": null }`: the country code (or `ZZ`, the package's WORLDWIDE, for readers everywhere), and an IANA time zone or `{ \"code\", \"symbol\" }` currency only when they differ from the country's own (the Australian and US time questions both fill `time_zone`). Then set `READERS` in `src/lib/country.ts` to match: `audiencePack({ country, timeZone, currency })`, leaving out what is null. Every page, email, PDF and form reads `READERS`, so nothing else changes.",
|
|
849
|
+
"questions": [
|
|
850
|
+
{
|
|
851
|
+
"id": "country.where",
|
|
852
|
+
"sets": "audience.country",
|
|
853
|
+
"ask": "Where are most of the site's readers?",
|
|
854
|
+
"style": "cards",
|
|
855
|
+
"answers": [
|
|
856
|
+
{
|
|
857
|
+
"label": "Australia",
|
|
858
|
+
"value": "AU",
|
|
859
|
+
"means": "26 September 2026, A$1,400, Sydney time, Australian spelling."
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"label": "The Philippines",
|
|
863
|
+
"value": "PH",
|
|
864
|
+
"means": "September 26, 2026, ₱1,400, Manila time."
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
"label": "The United Kingdom",
|
|
868
|
+
"value": "GB",
|
|
869
|
+
"means": "26 September 2026, £1,400, UK time, British spelling."
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
"label": "The United States",
|
|
873
|
+
"value": "US",
|
|
874
|
+
"means": "September 26, 2026, US$1,400, Eastern time, American spelling."
|
|
875
|
+
}
|
|
876
|
+
],
|
|
877
|
+
"other": {
|
|
878
|
+
"kind": "text",
|
|
879
|
+
"min": 2,
|
|
880
|
+
"max": 60,
|
|
881
|
+
"description": "Another country, or readers all over the world."
|
|
882
|
+
},
|
|
883
|
+
"note": "Recommend Australia unless the client's words say otherwise. A country with no pack yet, or readers everywhere, gets the neutral one (`ZZ`: 26 September 2026, 24-hour clock, UTC, US$): say so, and ask for the currency."
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
"id": "country.au-time",
|
|
887
|
+
"sets": "audience.time_zone.au",
|
|
888
|
+
"ask": "Which Australian time should the site show?",
|
|
889
|
+
"style": "cards",
|
|
890
|
+
"answers": [
|
|
891
|
+
{
|
|
892
|
+
"label": "Sydney, Melbourne, Canberra",
|
|
893
|
+
"value": null,
|
|
894
|
+
"means": "The pack's own (Australia/Sydney), with daylight saving."
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
"label": "Brisbane",
|
|
898
|
+
"value": "Australia/Brisbane",
|
|
899
|
+
"means": "Queensland, no daylight saving."
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
"label": "Adelaide",
|
|
903
|
+
"value": "Australia/Adelaide",
|
|
904
|
+
"means": "South Australia, half an hour behind Sydney."
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
"label": "Perth",
|
|
908
|
+
"value": "Australia/Perth",
|
|
909
|
+
"means": "Western Australia."
|
|
910
|
+
}
|
|
911
|
+
],
|
|
912
|
+
"other": {
|
|
913
|
+
"kind": "text",
|
|
914
|
+
"min": 5,
|
|
915
|
+
"max": 40,
|
|
916
|
+
"description": "Another Australian time zone, such as Australia/Darwin or Australia/Hobart."
|
|
917
|
+
},
|
|
918
|
+
"when": {
|
|
919
|
+
"id": "country.where",
|
|
920
|
+
"is": [
|
|
921
|
+
"AU"
|
|
922
|
+
]
|
|
923
|
+
},
|
|
924
|
+
"note": "The time zone of the business, where bookings and opening hours happen. Hobart follows Sydney; Darwin is Australia/Darwin."
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
"id": "country.us-time",
|
|
928
|
+
"sets": "audience.time_zone.us",
|
|
929
|
+
"ask": "Which US time should the site show?",
|
|
930
|
+
"style": "cards",
|
|
931
|
+
"answers": [
|
|
932
|
+
{
|
|
933
|
+
"label": "Eastern",
|
|
934
|
+
"value": null,
|
|
935
|
+
"means": "The pack's own (America/New_York)."
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"label": "Central",
|
|
939
|
+
"value": "America/Chicago"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
"label": "Mountain",
|
|
943
|
+
"value": "America/Denver"
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
"label": "Pacific",
|
|
947
|
+
"value": "America/Los_Angeles"
|
|
948
|
+
}
|
|
949
|
+
],
|
|
950
|
+
"other": {
|
|
951
|
+
"kind": "text",
|
|
952
|
+
"min": 5,
|
|
953
|
+
"max": 40,
|
|
954
|
+
"description": "Another US time zone, such as America/Phoenix or Pacific/Honolulu."
|
|
955
|
+
},
|
|
956
|
+
"when": {
|
|
957
|
+
"id": "country.where",
|
|
958
|
+
"is": [
|
|
959
|
+
"US"
|
|
960
|
+
]
|
|
961
|
+
},
|
|
962
|
+
"note": "The time zone of the business."
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
"id": "country.currency",
|
|
966
|
+
"sets": "audience.currency",
|
|
967
|
+
"ask": "Which money are prices in?",
|
|
968
|
+
"style": "cards",
|
|
969
|
+
"answers": [
|
|
970
|
+
{
|
|
971
|
+
"label": "The country's own",
|
|
972
|
+
"value": null,
|
|
973
|
+
"means": "A$ in Australia, ₱ in the Philippines, £ in the UK, US$ in the US."
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"label": "US dollars",
|
|
977
|
+
"value": "USD",
|
|
978
|
+
"means": "Shown as US$1,400."
|
|
979
|
+
}
|
|
980
|
+
],
|
|
981
|
+
"other": {
|
|
982
|
+
"kind": "text",
|
|
983
|
+
"min": 3,
|
|
984
|
+
"max": 3,
|
|
985
|
+
"description": "Another currency's three-letter code, such as NZD or EUR."
|
|
986
|
+
},
|
|
987
|
+
"note": "Write a currency other than the country's as `{ \"code\", \"symbol\" }` (NZD is NZ$). Ask it only when the client sells something; otherwise record null."
|
|
988
|
+
}
|
|
989
|
+
],
|
|
990
|
+
"not_asked": [
|
|
991
|
+
{
|
|
992
|
+
"sets": "audience.format",
|
|
993
|
+
"why": "Date order, the clock, number separators, spelling and phone number shapes all come from the country's pack, so they match what readers expect without asking."
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
"sets": "audience.owner_pages",
|
|
997
|
+
"why": "Pages only the owner sees use workbench-ui's own times and money, not the readers'."
|
|
998
|
+
}
|
|
999
|
+
]
|
|
1000
|
+
},
|
|
619
1001
|
"delivery": {
|
|
620
1002
|
"choice": "optional",
|
|
621
|
-
"intro": "Dates, times, numbers and money written the way readers in your country expect."
|
|
622
|
-
"when": "The app shows a date, a time, a number, a phone number or an amount of money to its readers, or the client says where their readers are."
|
|
1003
|
+
"intro": "Dates, times, numbers and money written the way readers in your country expect."
|
|
623
1004
|
}
|
|
624
1005
|
},
|
|
625
1006
|
"database": {
|
|
@@ -2218,10 +2599,161 @@ export const capabilities = {
|
|
|
2218
2599
|
"cost_hint_usd": 0.001
|
|
2219
2600
|
}
|
|
2220
2601
|
],
|
|
2602
|
+
"offer": {
|
|
2603
|
+
"pattern": "feature_or_content",
|
|
2604
|
+
"when": "The client wants to find existing pictures on the web, for the site itself or as a search visitors use.",
|
|
2605
|
+
"say": "I'll do this with Workbench picture search, which searches the web through Workbench, so the app holds no search key and spending has a monthly cap.",
|
|
2606
|
+
"answers_file": "workbench/image-search/<name>.json",
|
|
2607
|
+
"per": "feature or picture",
|
|
2608
|
+
"answers_format": "For a feature: `{ \"format\": 1, \"route\": \"feature\", \"name\", \"about\" (the client's words), \"who\", \"cap_usd\", \"job\" }`, where `job` is the `X-Workbench-Job` the feature's calls send (`<name>` with dots, such as `quotes.estimate`), so its spending shows on its own line in Control. Write it, then build the feature with the package. For a picture found once: `npx workbench-ai pick <name> <round>-<draft> --licence \"<the owner's words>\"` downloads it to `public/images/<name>.jpg` (or .png) and writes the answers file with where it came from and the licence; never write one from nothing, and never pick one without the licence answer. Show the credit the licence asks for beside the picture. Drafts and their previews stay in `workbench/image-search/drafts/`, which isn't committed.",
|
|
2609
|
+
"questions": [
|
|
2610
|
+
{
|
|
2611
|
+
"id": "image-search.route",
|
|
2612
|
+
"sets": "route",
|
|
2613
|
+
"ask": "Is this something visitors use on the site, or something made once for the site?",
|
|
2614
|
+
"style": "cards",
|
|
2615
|
+
"answers": [
|
|
2616
|
+
{
|
|
2617
|
+
"label": "Visitors use it",
|
|
2618
|
+
"value": "feature",
|
|
2619
|
+
"means": "A search on the site that finds pictures for whoever uses it."
|
|
2620
|
+
},
|
|
2621
|
+
{
|
|
2622
|
+
"label": "Made once for the site",
|
|
2623
|
+
"value": "content",
|
|
2624
|
+
"means": "A picture for the site, found once and kept."
|
|
2625
|
+
}
|
|
2626
|
+
],
|
|
2627
|
+
"must_ask": true,
|
|
2628
|
+
"note": "Ask it even when the client's words seem to say, as a quick check: the two routes are built and paid for differently."
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
"id": "image-search.who",
|
|
2632
|
+
"sets": "feature.who",
|
|
2633
|
+
"ask": "Who may use it?",
|
|
2634
|
+
"style": "cards",
|
|
2635
|
+
"answers": [
|
|
2636
|
+
{
|
|
2637
|
+
"label": "People who are signed in",
|
|
2638
|
+
"value": "signed_in",
|
|
2639
|
+
"means": "Anyone with an account. Each use is tied to a person, so misuse can be traced and stopped."
|
|
2640
|
+
},
|
|
2641
|
+
{
|
|
2642
|
+
"label": "Admins only",
|
|
2643
|
+
"value": "admins",
|
|
2644
|
+
"means": "Only the business's own admins, for example a tool for writing their own posts."
|
|
2645
|
+
},
|
|
2646
|
+
{
|
|
2647
|
+
"label": "Anyone visiting",
|
|
2648
|
+
"value": "anyone",
|
|
2649
|
+
"means": "No sign-in. The page checks for bots (Turnstile) and limits how often one visitor can use it."
|
|
2650
|
+
}
|
|
2651
|
+
],
|
|
2652
|
+
"when": {
|
|
2653
|
+
"id": "image-search.route",
|
|
2654
|
+
"is": [
|
|
2655
|
+
"feature"
|
|
2656
|
+
]
|
|
2657
|
+
},
|
|
2658
|
+
"note": "Signed in means `requireUser` and admins means `app_admins`, as the workbench-sign-in skill says. For anyone, check Turnstile on every use and keep a per-visitor limit; say plainly that strangers can run up the cost. Pass `subject` on every call so the Gateway can tell people apart: `user:<id>` for a signed-in person, and for anyone a random id kept in a cookie (`visitor:<id>`), never an email address or name."
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
"id": "image-search.cap",
|
|
2662
|
+
"sets": "feature.cap_usd",
|
|
2663
|
+
"ask": "How much may it spend in a month, at most? When it's reached, the feature stops until next month.",
|
|
2664
|
+
"style": "cards",
|
|
2665
|
+
"answers": [
|
|
2666
|
+
{
|
|
2667
|
+
"label": "US$5 a month",
|
|
2668
|
+
"value": 5,
|
|
2669
|
+
"means": "A small trial, or light use."
|
|
2670
|
+
},
|
|
2671
|
+
{
|
|
2672
|
+
"label": "US$20 a month",
|
|
2673
|
+
"value": 20,
|
|
2674
|
+
"means": "Steady use by a small business's visitors."
|
|
2675
|
+
},
|
|
2676
|
+
{
|
|
2677
|
+
"label": "US$50 a month",
|
|
2678
|
+
"value": 50,
|
|
2679
|
+
"means": "Heavy use. It can be raised later."
|
|
2680
|
+
}
|
|
2681
|
+
],
|
|
2682
|
+
"other": {
|
|
2683
|
+
"kind": "money",
|
|
2684
|
+
"min": 1,
|
|
2685
|
+
"max": 1000,
|
|
2686
|
+
"description": "US dollars a month, whole or with cents."
|
|
2687
|
+
},
|
|
2688
|
+
"must_ask": true,
|
|
2689
|
+
"when": {
|
|
2690
|
+
"id": "image-search.route",
|
|
2691
|
+
"is": [
|
|
2692
|
+
"feature"
|
|
2693
|
+
]
|
|
2694
|
+
},
|
|
2695
|
+
"note": "Say roughly what one use costs (about a tenth of a cent a search) so the owner can judge. The cap is the project's production cap for the `search` tool in the Gateway, shared by every feature that uses it: set it with Workbench Control's `gw_budget_set` (env production, tool search, monthly_usd). Raising a cap waits for the owner's approval on Control's approval page. When it is reached, calls fail with `budget_exceeded`: the page says the feature is resting until next month, never an error."
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
"id": "image-search.licence",
|
|
2699
|
+
"sets": "content.licence",
|
|
2700
|
+
"ask": "Does the site have the right to use this picture?",
|
|
2701
|
+
"style": "cards",
|
|
2702
|
+
"answers": [
|
|
2703
|
+
{
|
|
2704
|
+
"label": "Yes, it's ours",
|
|
2705
|
+
"value": "own",
|
|
2706
|
+
"means": "The business took it or owns it."
|
|
2707
|
+
},
|
|
2708
|
+
{
|
|
2709
|
+
"label": "Yes, it's free to use",
|
|
2710
|
+
"value": "free",
|
|
2711
|
+
"means": "Its page says so, with a licence such as CC BY. Say which."
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
"label": "No, find another",
|
|
2715
|
+
"value": "none",
|
|
2716
|
+
"means": "Pick another result, or make one with AI pictures instead."
|
|
2717
|
+
}
|
|
2718
|
+
],
|
|
2719
|
+
"other": {
|
|
2720
|
+
"kind": "text",
|
|
2721
|
+
"min": 3,
|
|
2722
|
+
"max": 200,
|
|
2723
|
+
"description": "What gives the site the right to use it."
|
|
2724
|
+
},
|
|
2725
|
+
"must_ask": true,
|
|
2726
|
+
"when": {
|
|
2727
|
+
"id": "image-search.route",
|
|
2728
|
+
"is": [
|
|
2729
|
+
"content"
|
|
2730
|
+
]
|
|
2731
|
+
},
|
|
2732
|
+
"note": "Ask after the client picks a result, showing its page link. A search result is a lead, not permission. Pass the client's words as --licence; with no, don't pick it."
|
|
2733
|
+
}
|
|
2734
|
+
],
|
|
2735
|
+
"not_asked": [
|
|
2736
|
+
{
|
|
2737
|
+
"sets": "query",
|
|
2738
|
+
"why": "The client's description is the search: pass it as --about, shortened to the words that matter."
|
|
2739
|
+
},
|
|
2740
|
+
{
|
|
2741
|
+
"sets": "filters",
|
|
2742
|
+
"why": "Results narrower than 600 pixels are dropped; anything finer (shape, site) is for a feature to do in its own code."
|
|
2743
|
+
}
|
|
2744
|
+
],
|
|
2745
|
+
"drafts": {
|
|
2746
|
+
"of": "found pictures",
|
|
2747
|
+
"surface": "image-search",
|
|
2748
|
+
"count": 4,
|
|
2749
|
+
"max_rounds": 3,
|
|
2750
|
+
"job": "image-search.drafts",
|
|
2751
|
+
"command": "npx workbench-ai drafts search <name> --about \"<what to search for>\""
|
|
2752
|
+
}
|
|
2753
|
+
},
|
|
2221
2754
|
"delivery": {
|
|
2222
2755
|
"choice": "built_in",
|
|
2223
|
-
"intro": "Finding existing pictures on the web."
|
|
2224
|
-
"when": "The client wants to find existing pictures on the web, for the site itself or as a search visitors use."
|
|
2756
|
+
"intro": "Finding existing pictures on the web."
|
|
2225
2757
|
}
|
|
2226
2758
|
},
|
|
2227
2759
|
"images": {
|
|
@@ -2431,10 +2963,199 @@ export const capabilities = {
|
|
|
2431
2963
|
"cost_hint_usd": 0
|
|
2432
2964
|
}
|
|
2433
2965
|
],
|
|
2966
|
+
"offer": {
|
|
2967
|
+
"pattern": "feature_or_content",
|
|
2968
|
+
"when": "The client wants a picture made by AI, such as an illustration, a hero image or a product mock-up, as a feature visitors use or once for the site.",
|
|
2969
|
+
"say": "I'll make this with Workbench pictures, made by AI through Workbench, so the app holds no image key and spending has a monthly cap.",
|
|
2970
|
+
"answers_file": "workbench/images/<name>.json",
|
|
2971
|
+
"per": "feature or picture",
|
|
2972
|
+
"answers_format": "For a feature: `{ \"format\": 1, \"route\": \"feature\", \"name\", \"about\" (the client's words), \"who\", \"cap_usd\", \"job\" }`, where `job` is the `X-Workbench-Job` the feature's calls send (`<name>` with dots, such as `quotes.estimate`), so its spending shows on its own line in Control. Write it, then build the feature with the package. For a picture made once: `npx workbench-ai pick <name> <round>-<draft>` copies the picked picture to `public/images/<name>.png` (or .jpg) and writes the answers file with its prompt, model, request id and cost; never write one from nothing. Show it on the page from `/images/<name>.png`, with alt text that says what it shows. Drafts and their previews stay in `workbench/images/drafts/`, which isn't committed.",
|
|
2973
|
+
"questions": [
|
|
2974
|
+
{
|
|
2975
|
+
"id": "images.route",
|
|
2976
|
+
"sets": "route",
|
|
2977
|
+
"ask": "Is this something visitors use on the site, or something made once for the site?",
|
|
2978
|
+
"style": "cards",
|
|
2979
|
+
"answers": [
|
|
2980
|
+
{
|
|
2981
|
+
"label": "Visitors use it",
|
|
2982
|
+
"value": "feature",
|
|
2983
|
+
"means": "A feature that makes a new picture each time someone uses it, such as a mock-up of their own design."
|
|
2984
|
+
},
|
|
2985
|
+
{
|
|
2986
|
+
"label": "Made once for the site",
|
|
2987
|
+
"value": "content",
|
|
2988
|
+
"means": "A picture for the site, made once and kept: a hero image, an illustration for a page."
|
|
2989
|
+
}
|
|
2990
|
+
],
|
|
2991
|
+
"must_ask": true,
|
|
2992
|
+
"note": "Ask it even when the client's words seem to say, as a quick check: the two routes are built and paid for differently."
|
|
2993
|
+
},
|
|
2994
|
+
{
|
|
2995
|
+
"id": "images.who",
|
|
2996
|
+
"sets": "feature.who",
|
|
2997
|
+
"ask": "Who may use it?",
|
|
2998
|
+
"style": "cards",
|
|
2999
|
+
"answers": [
|
|
3000
|
+
{
|
|
3001
|
+
"label": "People who are signed in",
|
|
3002
|
+
"value": "signed_in",
|
|
3003
|
+
"means": "Anyone with an account. Each use is tied to a person, so misuse can be traced and stopped."
|
|
3004
|
+
},
|
|
3005
|
+
{
|
|
3006
|
+
"label": "Admins only",
|
|
3007
|
+
"value": "admins",
|
|
3008
|
+
"means": "Only the business's own admins, for example a tool for writing their own posts."
|
|
3009
|
+
},
|
|
3010
|
+
{
|
|
3011
|
+
"label": "Anyone visiting",
|
|
3012
|
+
"value": "anyone",
|
|
3013
|
+
"means": "No sign-in. The page checks for bots (Turnstile) and limits how often one visitor can use it."
|
|
3014
|
+
}
|
|
3015
|
+
],
|
|
3016
|
+
"when": {
|
|
3017
|
+
"id": "images.route",
|
|
3018
|
+
"is": [
|
|
3019
|
+
"feature"
|
|
3020
|
+
]
|
|
3021
|
+
},
|
|
3022
|
+
"note": "Signed in means `requireUser` and admins means `app_admins`, as the workbench-sign-in skill says. For anyone, check Turnstile on every use and keep a per-visitor limit; say plainly that strangers can run up the cost. Pass `subject` on every call so the Gateway can tell people apart: `user:<id>` for a signed-in person, and for anyone a random id kept in a cookie (`visitor:<id>`), never an email address or name."
|
|
3023
|
+
},
|
|
3024
|
+
{
|
|
3025
|
+
"id": "images.cap",
|
|
3026
|
+
"sets": "feature.cap_usd",
|
|
3027
|
+
"ask": "How much may it spend in a month, at most? When it's reached, the feature stops until next month.",
|
|
3028
|
+
"style": "cards",
|
|
3029
|
+
"answers": [
|
|
3030
|
+
{
|
|
3031
|
+
"label": "US$5 a month",
|
|
3032
|
+
"value": 5,
|
|
3033
|
+
"means": "A small trial, or light use."
|
|
3034
|
+
},
|
|
3035
|
+
{
|
|
3036
|
+
"label": "US$20 a month",
|
|
3037
|
+
"value": 20,
|
|
3038
|
+
"means": "Steady use by a small business's visitors."
|
|
3039
|
+
},
|
|
3040
|
+
{
|
|
3041
|
+
"label": "US$50 a month",
|
|
3042
|
+
"value": 50,
|
|
3043
|
+
"means": "Heavy use. It can be raised later."
|
|
3044
|
+
}
|
|
3045
|
+
],
|
|
3046
|
+
"other": {
|
|
3047
|
+
"kind": "money",
|
|
3048
|
+
"min": 1,
|
|
3049
|
+
"max": 1000,
|
|
3050
|
+
"description": "US dollars a month, whole or with cents."
|
|
3051
|
+
},
|
|
3052
|
+
"must_ask": true,
|
|
3053
|
+
"when": {
|
|
3054
|
+
"id": "images.route",
|
|
3055
|
+
"is": [
|
|
3056
|
+
"feature"
|
|
3057
|
+
]
|
|
3058
|
+
},
|
|
3059
|
+
"note": "Say roughly what one use costs (about US$0.07 a picture with image-default) so the owner can judge. The cap is the project's production cap for the `images` tool in the Gateway, shared by every feature that uses it: set it with Workbench Control's `gw_budget_set` (env production, tool images, monthly_usd). Raising a cap waits for the owner's approval on Control's approval page. When it is reached, calls fail with `budget_exceeded`: the page says the feature is resting until next month, never an error."
|
|
3060
|
+
},
|
|
3061
|
+
{
|
|
3062
|
+
"id": "images.what",
|
|
3063
|
+
"sets": [
|
|
3064
|
+
"content.name",
|
|
3065
|
+
"content.about"
|
|
3066
|
+
],
|
|
3067
|
+
"ask": "What picture do you need?",
|
|
3068
|
+
"style": "cards",
|
|
3069
|
+
"answers": [
|
|
3070
|
+
{
|
|
3071
|
+
"label": "A hero image",
|
|
3072
|
+
"value": "hero",
|
|
3073
|
+
"means": "The large picture across the top of a page."
|
|
3074
|
+
},
|
|
3075
|
+
{
|
|
3076
|
+
"label": "An illustration",
|
|
3077
|
+
"value": "illustration",
|
|
3078
|
+
"means": "A drawing for a page or a section."
|
|
3079
|
+
},
|
|
3080
|
+
{
|
|
3081
|
+
"label": "A product mock-up",
|
|
3082
|
+
"value": "mockup",
|
|
3083
|
+
"means": "A product shown in use or in a setting."
|
|
3084
|
+
}
|
|
3085
|
+
],
|
|
3086
|
+
"other": {
|
|
3087
|
+
"kind": "text",
|
|
3088
|
+
"min": 3,
|
|
3089
|
+
"max": 200,
|
|
3090
|
+
"description": "What the picture is, in a few words."
|
|
3091
|
+
},
|
|
3092
|
+
"when": {
|
|
3093
|
+
"id": "images.route",
|
|
3094
|
+
"is": [
|
|
3095
|
+
"content"
|
|
3096
|
+
]
|
|
3097
|
+
},
|
|
3098
|
+
"note": "Name the picture after where it goes (home_hero): lower case and underscores. The client's own words about what it shows and the feel they want go in --about."
|
|
3099
|
+
},
|
|
3100
|
+
{
|
|
3101
|
+
"id": "images.shape",
|
|
3102
|
+
"sets": "content.aspect",
|
|
3103
|
+
"ask": "What shape should it be?",
|
|
3104
|
+
"style": "cards",
|
|
3105
|
+
"answers": [
|
|
3106
|
+
{
|
|
3107
|
+
"label": "Landscape (3:2)",
|
|
3108
|
+
"value": "3:2",
|
|
3109
|
+
"means": "Wider than tall, the usual shape for a page."
|
|
3110
|
+
},
|
|
3111
|
+
{
|
|
3112
|
+
"label": "Wide banner (16:9)",
|
|
3113
|
+
"value": "16:9",
|
|
3114
|
+
"means": "For a picture across the top of a page."
|
|
3115
|
+
},
|
|
3116
|
+
{
|
|
3117
|
+
"label": "Square (1:1)",
|
|
3118
|
+
"value": "1:1",
|
|
3119
|
+
"means": "For cards and social posts."
|
|
3120
|
+
},
|
|
3121
|
+
{
|
|
3122
|
+
"label": "Portrait (2:3)",
|
|
3123
|
+
"value": "2:3",
|
|
3124
|
+
"means": "Taller than wide."
|
|
3125
|
+
}
|
|
3126
|
+
],
|
|
3127
|
+
"when": {
|
|
3128
|
+
"id": "images.route",
|
|
3129
|
+
"is": [
|
|
3130
|
+
"content"
|
|
3131
|
+
]
|
|
3132
|
+
},
|
|
3133
|
+
"note": "Recommend the banner for a hero image. Pass it to the drafts command as --aspect."
|
|
3134
|
+
}
|
|
3135
|
+
],
|
|
3136
|
+
"not_asked": [
|
|
3137
|
+
{
|
|
3138
|
+
"sets": "model",
|
|
3139
|
+
"why": "Drafts and features use image-default. image-pro costs about twice as much for finer detail and image-openai is cheapest; suggest one only when the client asks about quality or cost."
|
|
3140
|
+
},
|
|
3141
|
+
{
|
|
3142
|
+
"sets": "references",
|
|
3143
|
+
"why": "A reference picture (to make something like it) is only for a feature that needs one, and works with Google aliases only; offer it when the client mentions one."
|
|
3144
|
+
}
|
|
3145
|
+
],
|
|
3146
|
+
"drafts": {
|
|
3147
|
+
"of": "pictures",
|
|
3148
|
+
"surface": "images",
|
|
3149
|
+
"alias": "image-default",
|
|
3150
|
+
"count": 3,
|
|
3151
|
+
"max_rounds": 3,
|
|
3152
|
+
"job": "images.drafts",
|
|
3153
|
+
"command": "npx workbench-ai drafts image <name> --about \"<what it shows, in the client's words>\" --aspect <shape>"
|
|
3154
|
+
}
|
|
3155
|
+
},
|
|
2434
3156
|
"delivery": {
|
|
2435
3157
|
"choice": "built_in",
|
|
2436
|
-
"intro": "Pictures made by AI from a description."
|
|
2437
|
-
"when": "The client wants a picture made by AI, such as an illustration, a hero image or a product mock-up, as a feature visitors use or once for the site."
|
|
3158
|
+
"intro": "Pictures made by AI from a description."
|
|
2438
3159
|
}
|
|
2439
3160
|
},
|
|
2440
3161
|
"pdf": {
|
|
@@ -2985,13 +3706,38 @@ export const capabilities = {
|
|
|
2985
3706
|
"note": "In the Worker itself: compares money (US$0.0042, US$12.50, and an en dash for nothing), duration (640 ms, 2.35 s, 3 min 5 s) and timeLeft against a fixed now (42 minutes left) with the expected text, and checks when and shortWhen write one fixed moment as its Manila day and hour with UTC beside it"
|
|
2986
3707
|
}
|
|
2987
3708
|
],
|
|
3709
|
+
"offer": {
|
|
3710
|
+
"pattern": "switch_on",
|
|
3711
|
+
"when": "The client wants a page only the owner or the app's admins see: a dashboard, a list, a settings page or a status page.",
|
|
3712
|
+
"say": "I'll build this with the Workbench owner-page look, the same top bar, cards and pills as the other admin pages, so it's quick to build and consistent. Your customers never see it.",
|
|
3713
|
+
"answers_file": "workbench/ui.json",
|
|
3714
|
+
"answers_format": "`{ \"format\": 1, \"pages\": [{ \"path\": \"/admin/orders\", \"what\": \"every order this month, newest first\", \"who\": \"admins\" }] }`. Build each page with `shell`, `topBar`, `card` and `pill`. An `admins` page lives under `/admin/` and checks `requireUser` and `app_admins` (the workbench-sign-in skill); an `owner` page lives under `/owner/` and is behind Access in production.",
|
|
3715
|
+
"questions": [
|
|
3716
|
+
{
|
|
3717
|
+
"id": "ui.pages",
|
|
3718
|
+
"sets": "pages",
|
|
3719
|
+
"ask": "Which admin pages should the app have?",
|
|
3720
|
+
"style": "table",
|
|
3721
|
+
"note": "Propose the pages the request needs, each with its path, what it shows or lets them change in the client's words, and who sees it: `admins` (the business's people, who sign in to the app) or `owner` (whoever runs the app's Workbench, through Access). Recommend `admins` unless the page is about running the app itself, such as a status page. The client accepts, removes or adds pages."
|
|
3722
|
+
}
|
|
3723
|
+
],
|
|
3724
|
+
"not_asked": [
|
|
3725
|
+
{
|
|
3726
|
+
"sets": "look",
|
|
3727
|
+
"why": "Every admin page has the same Workbench look, so the business's people learn it once. Restyle it in project.css (see Restyling) if the client wants their colours."
|
|
3728
|
+
},
|
|
3729
|
+
{
|
|
3730
|
+
"sets": "formats",
|
|
3731
|
+
"why": "Times, amounts and durations on these pages come from workbench-ui's `when`, `money` and `duration`. What customers see uses the readers' formats (the workbench-country skill)."
|
|
3732
|
+
}
|
|
3733
|
+
]
|
|
3734
|
+
},
|
|
2988
3735
|
"styles": {
|
|
2989
3736
|
"prefix": "wb-ui-"
|
|
2990
3737
|
},
|
|
2991
3738
|
"delivery": {
|
|
2992
3739
|
"choice": "optional",
|
|
2993
|
-
"intro": "A ready-made look for the pages only you and your admins see."
|
|
2994
|
-
"when": "The client wants a page only the owner or the app's admins see: a dashboard, a list, a settings page or a status page."
|
|
3740
|
+
"intro": "A ready-made look for the pages only you and your admins see."
|
|
2995
3741
|
}
|
|
2996
3742
|
}
|
|
2997
3743
|
};
|