@mccaskie-labs/workbench-config 0.2.4 → 0.3.0
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/analytics.json +47 -3
- package/capabilities/country.json +160 -3
- package/capabilities/database.json +32 -3
- package/capabilities/email-inbound.json +47 -3
- package/capabilities/email.json +66 -2
- package/capabilities/schema.json +0 -4
- package/capabilities/strings.json +46 -3
- package/capabilities/ui.json +27 -2
- package/dist/capabilities.gen.d.ts +337 -8
- package/dist/capabilities.gen.js +421 -15
- package/dist/capability-schema.d.ts +0 -7
- package/dist/capability-schema.js +1 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +4 -8
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const MANIFEST_VERSION: "
|
|
1
|
+
export declare const MANIFEST_VERSION: "de365af27674";
|
|
2
2
|
export declare const capabilities: {
|
|
3
3
|
readonly ai: {
|
|
4
4
|
readonly $schema: "./schema.json";
|
|
@@ -413,10 +413,45 @@ export declare const capabilities: {
|
|
|
413
413
|
readonly cost_hint_usd: 0;
|
|
414
414
|
readonly note: "Create the site, drive page views, query them back (cf_analytics_query, later)";
|
|
415
415
|
}];
|
|
416
|
+
readonly offer: {
|
|
417
|
+
readonly pattern: "switch_on";
|
|
418
|
+
readonly 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.";
|
|
419
|
+
readonly 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.";
|
|
420
|
+
readonly answers_file: "workbench/analytics.json";
|
|
421
|
+
readonly 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.";
|
|
422
|
+
readonly questions: readonly [{
|
|
423
|
+
readonly id: "analytics.page-views";
|
|
424
|
+
readonly sets: "page_views";
|
|
425
|
+
readonly ask: "Should the site count its page views?";
|
|
426
|
+
readonly style: "cards";
|
|
427
|
+
readonly answers: readonly [{
|
|
428
|
+
readonly label: "Yes";
|
|
429
|
+
readonly value: true;
|
|
430
|
+
readonly means: "How many people visit and which pages they open, counted by Cloudflare. No cookies, and no personal details kept.";
|
|
431
|
+
}, {
|
|
432
|
+
readonly label: "No";
|
|
433
|
+
readonly value: false;
|
|
434
|
+
readonly means: "Nothing is counted on the site's pages.";
|
|
435
|
+
}];
|
|
436
|
+
readonly note: "Only pages customers see; never the owner's or admins' pages.";
|
|
437
|
+
}, {
|
|
438
|
+
readonly id: "analytics.actions";
|
|
439
|
+
readonly sets: "events";
|
|
440
|
+
readonly ask: "Which actions should be counted?";
|
|
441
|
+
readonly style: "table";
|
|
442
|
+
readonly 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.";
|
|
443
|
+
}];
|
|
444
|
+
readonly not_asked: readonly [{
|
|
445
|
+
readonly sets: "consent";
|
|
446
|
+
readonly 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.";
|
|
447
|
+
}, {
|
|
448
|
+
readonly sets: "reports";
|
|
449
|
+
readonly 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.";
|
|
450
|
+
}];
|
|
451
|
+
};
|
|
416
452
|
readonly delivery: {
|
|
417
453
|
readonly choice: "optional";
|
|
418
454
|
readonly intro: "Counting page views and the things visitors do on the site.";
|
|
419
|
-
readonly 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.";
|
|
420
455
|
};
|
|
421
456
|
};
|
|
422
457
|
readonly config: {
|
|
@@ -565,10 +600,137 @@ export declare const capabilities: {
|
|
|
565
600
|
readonly cost_hint_usd: 0;
|
|
566
601
|
readonly 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";
|
|
567
602
|
}];
|
|
603
|
+
readonly offer: {
|
|
604
|
+
readonly pattern: "project";
|
|
605
|
+
readonly 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.";
|
|
606
|
+
readonly 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.";
|
|
607
|
+
readonly answers_file: "workbench/country.json";
|
|
608
|
+
readonly 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.";
|
|
609
|
+
readonly questions: readonly [{
|
|
610
|
+
readonly id: "country.where";
|
|
611
|
+
readonly sets: "audience.country";
|
|
612
|
+
readonly ask: "Where are most of the site's readers?";
|
|
613
|
+
readonly style: "cards";
|
|
614
|
+
readonly answers: readonly [{
|
|
615
|
+
readonly label: "Australia";
|
|
616
|
+
readonly value: "AU";
|
|
617
|
+
readonly means: "26 September 2026, A$1,400, Sydney time, Australian spelling.";
|
|
618
|
+
}, {
|
|
619
|
+
readonly label: "The Philippines";
|
|
620
|
+
readonly value: "PH";
|
|
621
|
+
readonly means: "September 26, 2026, ₱1,400, Manila time.";
|
|
622
|
+
}, {
|
|
623
|
+
readonly label: "The United Kingdom";
|
|
624
|
+
readonly value: "GB";
|
|
625
|
+
readonly means: "26 September 2026, £1,400, UK time, British spelling.";
|
|
626
|
+
}, {
|
|
627
|
+
readonly label: "The United States";
|
|
628
|
+
readonly value: "US";
|
|
629
|
+
readonly means: "September 26, 2026, US$1,400, Eastern time, American spelling.";
|
|
630
|
+
}];
|
|
631
|
+
readonly other: {
|
|
632
|
+
readonly kind: "text";
|
|
633
|
+
readonly min: 2;
|
|
634
|
+
readonly max: 60;
|
|
635
|
+
readonly description: "Another country, or readers all over the world.";
|
|
636
|
+
};
|
|
637
|
+
readonly 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.";
|
|
638
|
+
}, {
|
|
639
|
+
readonly id: "country.au-time";
|
|
640
|
+
readonly sets: "audience.time_zone.au";
|
|
641
|
+
readonly ask: "Which Australian time should the site show?";
|
|
642
|
+
readonly style: "cards";
|
|
643
|
+
readonly answers: readonly [{
|
|
644
|
+
readonly label: "Sydney, Melbourne, Canberra";
|
|
645
|
+
readonly value: null;
|
|
646
|
+
readonly means: "The pack's own (Australia/Sydney), with daylight saving.";
|
|
647
|
+
}, {
|
|
648
|
+
readonly label: "Brisbane";
|
|
649
|
+
readonly value: "Australia/Brisbane";
|
|
650
|
+
readonly means: "Queensland, no daylight saving.";
|
|
651
|
+
}, {
|
|
652
|
+
readonly label: "Adelaide";
|
|
653
|
+
readonly value: "Australia/Adelaide";
|
|
654
|
+
readonly means: "South Australia, half an hour behind Sydney.";
|
|
655
|
+
}, {
|
|
656
|
+
readonly label: "Perth";
|
|
657
|
+
readonly value: "Australia/Perth";
|
|
658
|
+
readonly means: "Western Australia.";
|
|
659
|
+
}];
|
|
660
|
+
readonly other: {
|
|
661
|
+
readonly kind: "text";
|
|
662
|
+
readonly min: 5;
|
|
663
|
+
readonly max: 40;
|
|
664
|
+
readonly description: "Another Australian time zone, such as Australia/Darwin or Australia/Hobart.";
|
|
665
|
+
};
|
|
666
|
+
readonly when: {
|
|
667
|
+
readonly id: "country.where";
|
|
668
|
+
readonly is: readonly ["AU"];
|
|
669
|
+
};
|
|
670
|
+
readonly note: "The time zone of the business, where bookings and opening hours happen. Hobart follows Sydney; Darwin is Australia/Darwin.";
|
|
671
|
+
}, {
|
|
672
|
+
readonly id: "country.us-time";
|
|
673
|
+
readonly sets: "audience.time_zone.us";
|
|
674
|
+
readonly ask: "Which US time should the site show?";
|
|
675
|
+
readonly style: "cards";
|
|
676
|
+
readonly answers: readonly [{
|
|
677
|
+
readonly label: "Eastern";
|
|
678
|
+
readonly value: null;
|
|
679
|
+
readonly means: "The pack's own (America/New_York).";
|
|
680
|
+
}, {
|
|
681
|
+
readonly label: "Central";
|
|
682
|
+
readonly value: "America/Chicago";
|
|
683
|
+
}, {
|
|
684
|
+
readonly label: "Mountain";
|
|
685
|
+
readonly value: "America/Denver";
|
|
686
|
+
}, {
|
|
687
|
+
readonly label: "Pacific";
|
|
688
|
+
readonly value: "America/Los_Angeles";
|
|
689
|
+
}];
|
|
690
|
+
readonly other: {
|
|
691
|
+
readonly kind: "text";
|
|
692
|
+
readonly min: 5;
|
|
693
|
+
readonly max: 40;
|
|
694
|
+
readonly description: "Another US time zone, such as America/Phoenix or Pacific/Honolulu.";
|
|
695
|
+
};
|
|
696
|
+
readonly when: {
|
|
697
|
+
readonly id: "country.where";
|
|
698
|
+
readonly is: readonly ["US"];
|
|
699
|
+
};
|
|
700
|
+
readonly note: "The time zone of the business.";
|
|
701
|
+
}, {
|
|
702
|
+
readonly id: "country.currency";
|
|
703
|
+
readonly sets: "audience.currency";
|
|
704
|
+
readonly ask: "Which money are prices in?";
|
|
705
|
+
readonly style: "cards";
|
|
706
|
+
readonly answers: readonly [{
|
|
707
|
+
readonly label: "The country's own";
|
|
708
|
+
readonly value: null;
|
|
709
|
+
readonly means: "A$ in Australia, ₱ in the Philippines, £ in the UK, US$ in the US.";
|
|
710
|
+
}, {
|
|
711
|
+
readonly label: "US dollars";
|
|
712
|
+
readonly value: "USD";
|
|
713
|
+
readonly means: "Shown as US$1,400.";
|
|
714
|
+
}];
|
|
715
|
+
readonly other: {
|
|
716
|
+
readonly kind: "text";
|
|
717
|
+
readonly min: 3;
|
|
718
|
+
readonly max: 3;
|
|
719
|
+
readonly description: "Another currency's three-letter code, such as NZD or EUR.";
|
|
720
|
+
};
|
|
721
|
+
readonly 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.";
|
|
722
|
+
}];
|
|
723
|
+
readonly not_asked: readonly [{
|
|
724
|
+
readonly sets: "audience.format";
|
|
725
|
+
readonly 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.";
|
|
726
|
+
}, {
|
|
727
|
+
readonly sets: "audience.owner_pages";
|
|
728
|
+
readonly why: "Pages only the owner sees use workbench-ui's own times and money, not the readers'.";
|
|
729
|
+
}];
|
|
730
|
+
};
|
|
568
731
|
readonly delivery: {
|
|
569
732
|
readonly choice: "optional";
|
|
570
733
|
readonly intro: "Dates, times, numbers and money written the way readers in your country expect.";
|
|
571
|
-
readonly 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.";
|
|
572
734
|
};
|
|
573
735
|
};
|
|
574
736
|
readonly database: {
|
|
@@ -747,10 +909,33 @@ export declare const capabilities: {
|
|
|
747
909
|
readonly cost_hint_usd: 0;
|
|
748
910
|
readonly note: "On a project's staging: cf_turnstile_widget_create and the turnstile_sitekey and turnstile_secret sources; the sign-in page shows the check, /auth/code without a passed token sends no code, and with one it does";
|
|
749
911
|
}];
|
|
912
|
+
readonly offer: {
|
|
913
|
+
readonly pattern: "settings";
|
|
914
|
+
readonly when: "The app needs to store or read data, or the client asks for a change to what is stored: a new table, column, rule or migration.";
|
|
915
|
+
readonly say: "The app's data goes in its own Workbench database, one for testing and one for the live site. I'll propose what to store and who can see it, and change it with a migration you can undo.";
|
|
916
|
+
readonly answers_file: "workbench/database.json";
|
|
917
|
+
readonly answers_format: "`{ \"format\": 1, \"status\": \"draft\", \"tables\": [{ \"name\": \"orders\", \"row\": \"one order\", \"columns\": [{ \"name\": \"total\", \"kind\": \"money\", \"required\": true }], \"read\": \"own\", \"change\": \"own\" }] }`. Then write one migration (`supabase/migrations/<14 digits>_<name>.sql`) with its down file, turning on row-level security with one policy per answer, apply it on staging with Workbench Control (`sb_migration_apply`), and refresh `supabase/staging-columns.json`.";
|
|
918
|
+
readonly questions: readonly [{
|
|
919
|
+
readonly id: "database.tables";
|
|
920
|
+
readonly sets: "tables";
|
|
921
|
+
readonly ask: "What should the app store, and who can see and change it?";
|
|
922
|
+
readonly style: "table";
|
|
923
|
+
readonly note: "Propose the tables the request needs, each with what one row is, its columns (name, kind such as text, number, money, date, yes/no, a link to another table; and whether it is required), and who may read and who may change its rows: `own` (the person who made the row), `admins`, `signed_in` (anyone signed in) or `public` (anyone, read only). Recommend `own` for anything about a person. Show money as whole cents, never a fraction. The client accepts, removes or adds tables and columns.";
|
|
924
|
+
}];
|
|
925
|
+
readonly not_asked: readonly [{
|
|
926
|
+
readonly sets: "keys";
|
|
927
|
+
readonly why: "The app reaches the database as the signed-in person (`dbAs`), so row-level security decides what each person sees; the template holds no secret key.";
|
|
928
|
+
}, {
|
|
929
|
+
readonly sets: "hosting";
|
|
930
|
+
readonly why: "Each project has its own staging and production databases, made by Workbench Control in the region set for the install.";
|
|
931
|
+
}, {
|
|
932
|
+
readonly sets: "sign_in_settings";
|
|
933
|
+
readonly why: "The database's sign-in settings follow the Workbench baseline (the workbench-sign-in skill).";
|
|
934
|
+
}];
|
|
935
|
+
};
|
|
750
936
|
readonly delivery: {
|
|
751
937
|
readonly choice: "built_in";
|
|
752
938
|
readonly intro: "The app's own database, one for testing and one for the live site.";
|
|
753
|
-
readonly when: "The app needs to store or read data, or the client asks for a change to what is stored: a new table, column, rule or migration.";
|
|
754
939
|
};
|
|
755
940
|
};
|
|
756
941
|
readonly email: {
|
|
@@ -995,13 +1180,67 @@ export declare const capabilities: {
|
|
|
995
1180
|
readonly cost_hint_usd: 0;
|
|
996
1181
|
readonly note: "GET brand.json's logo.url from outside with no sign-in answers 200 with an image content type";
|
|
997
1182
|
}];
|
|
1183
|
+
readonly offer: {
|
|
1184
|
+
readonly pattern: "settings";
|
|
1185
|
+
readonly when: "The app needs to send an email: a confirmation, receipt, notification, invitation or sign-in code.";
|
|
1186
|
+
readonly say: "I'll send these with Workbench email, which sends from the app's own address in your brand, with no email key in the app. The sign-in codes are already there; I'll add yours beside them.";
|
|
1187
|
+
readonly answers_file: "workbench/email.json";
|
|
1188
|
+
readonly answers_format: "`{ \"format\": 1, \"status\": \"draft\", \"reply_to\": null, \"emails\": [{ \"id\": \"order_confirmed\", \"when\": \"a customer sends an order\", \"to\": \"the customer\", \"parts\": [\"heading\", \"paragraph\", \"button\"], \"link_changes_something\": false }] }`. Declare each email in `src/lib/emails.ts` with `defineEmails` (stream `transactional`, shell `account`, `decidedBy` naming this answers file), put its words in the strings under `email.<id>.<key>`, and send it with `mailerFor(env)` and an `idempotencyKey` whenever a retry could repeat it.";
|
|
1189
|
+
readonly questions: readonly [{
|
|
1190
|
+
readonly id: "email.emails";
|
|
1191
|
+
readonly sets: "emails";
|
|
1192
|
+
readonly ask: "Which emails should the app send?";
|
|
1193
|
+
readonly style: "table";
|
|
1194
|
+
readonly note: "Propose the emails the request needs, each with an id (snake_case: `order_confirmed`), when it is sent, who gets it, its parts in order (heading, paragraphs, a button and its link, small print) and whether its link changes something (then the link lands on a confirmation page first). Only emails a person's own action or account causes: receipts, confirmations, notices. The client accepts, removes or adds. The wording is drafted afterwards, one email at a time.";
|
|
1195
|
+
}, {
|
|
1196
|
+
readonly id: "email.reply-to";
|
|
1197
|
+
readonly sets: "reply_to";
|
|
1198
|
+
readonly ask: "Where should a reply to these emails go?";
|
|
1199
|
+
readonly style: "cards";
|
|
1200
|
+
readonly answers: readonly [{
|
|
1201
|
+
readonly label: "Nowhere";
|
|
1202
|
+
readonly value: null;
|
|
1203
|
+
readonly means: "The emails come from an address that isn't read. Say so in the small print, with where to get help instead.";
|
|
1204
|
+
}, {
|
|
1205
|
+
readonly label: "To the app";
|
|
1206
|
+
readonly value: "app";
|
|
1207
|
+
readonly means: "Replies go to an address the app reads itself (Workbench inbound email).";
|
|
1208
|
+
}];
|
|
1209
|
+
readonly other: {
|
|
1210
|
+
readonly kind: "text";
|
|
1211
|
+
readonly min: 6;
|
|
1212
|
+
readonly max: 254;
|
|
1213
|
+
readonly description: "An email address someone at the business reads.";
|
|
1214
|
+
};
|
|
1215
|
+
readonly must_ask: true;
|
|
1216
|
+
readonly note: "A typed address goes in each send as `replyTo`; check it looks like an email address. With the app, the workbench-email-inbound skill sets up the address.";
|
|
1217
|
+
}];
|
|
1218
|
+
readonly not_asked: readonly [{
|
|
1219
|
+
readonly sets: "sender";
|
|
1220
|
+
readonly why: "Emails come from the project's own sending address (`FROM` in `src/lib/email.ts`) on its own domain, which Workbench Control sets up.";
|
|
1221
|
+
}, {
|
|
1222
|
+
readonly sets: "marketing";
|
|
1223
|
+
readonly why: "Only transactional email exists: newsletters and other bulk mail are refused until Workbench has a sender for them, so offer none.";
|
|
1224
|
+
}, {
|
|
1225
|
+
readonly sets: "look";
|
|
1226
|
+
readonly why: "Emails take the brand's name, colour and logo, and the project's `project.css` (see Restyling).";
|
|
1227
|
+
}];
|
|
1228
|
+
readonly drafts: {
|
|
1229
|
+
readonly of: "wording for one email";
|
|
1230
|
+
readonly surface: "ai";
|
|
1231
|
+
readonly alias: "claude-default";
|
|
1232
|
+
readonly count: 3;
|
|
1233
|
+
readonly max_rounds: 3;
|
|
1234
|
+
readonly job: "ai.drafts";
|
|
1235
|
+
readonly command: "npx workbench-ai drafts text email_<id> --about \"<what the email is for, who gets it and its parts>\"";
|
|
1236
|
+
};
|
|
1237
|
+
};
|
|
998
1238
|
readonly styles: {
|
|
999
1239
|
readonly prefix: "wb-email-";
|
|
1000
1240
|
};
|
|
1001
1241
|
readonly delivery: {
|
|
1002
1242
|
readonly choice: "built_in";
|
|
1003
1243
|
readonly intro: "The emails the app sends, such as confirmations, receipts and sign-in codes.";
|
|
1004
|
-
readonly when: "The app needs to send an email: a confirmation, receipt, notification, invitation or sign-in code.";
|
|
1005
1244
|
};
|
|
1006
1245
|
};
|
|
1007
1246
|
readonly "email-inbound": {
|
|
@@ -1104,10 +1343,45 @@ export declare const capabilities: {
|
|
|
1104
1343
|
readonly two_step: true;
|
|
1105
1344
|
readonly note: "cf_email_routing_rule_delete returns a confirmation and changes nothing until Robert approves";
|
|
1106
1345
|
}];
|
|
1346
|
+
readonly offer: {
|
|
1347
|
+
readonly pattern: "switch_on";
|
|
1348
|
+
readonly when: "The client wants the app to receive email: replies to its messages, or an address such as hello@ that the app handles.";
|
|
1349
|
+
readonly say: "The project can already receive email with Workbench inbound email: each address goes straight to the app, which decides what to do with every message. I'll switch on the addresses you want.";
|
|
1350
|
+
readonly answers_file: "workbench/email-inbound.json";
|
|
1351
|
+
readonly answers_format: "`{ \"format\": 1, \"addresses\": [{ \"name\": \"hello\", \"does\": \"saves it as a message the admins see\" }] }`. Then set `INBOUND_EMAIL` to `\"on\"` in `wrangler.jsonc`, write `handleEmail` in `src/app.ts` to do what each address `does`, and make the addresses with Workbench Control: `cf_email_routing_enable`, then `cf_email_routing_rule_create` for each address on staging first (the capabilities guide below has the steps).";
|
|
1352
|
+
readonly questions: readonly [{
|
|
1353
|
+
readonly id: "email-inbound.addresses";
|
|
1354
|
+
readonly sets: "addresses";
|
|
1355
|
+
readonly ask: "Which addresses should the app receive, and what should it do with each message?";
|
|
1356
|
+
readonly style: "table";
|
|
1357
|
+
readonly note: "Propose the addresses the request needs, each with its name (the part before @, lower case: `hello`, `bookings`) and what the app does with a message, in the client's words: save it for the admins to read, add it to a booking, answer it automatically. One address, one job. Say plainly that the app reads the mail itself: nothing is forwarded to anyone's inbox.";
|
|
1358
|
+
}, {
|
|
1359
|
+
readonly id: "email-inbound.attachments";
|
|
1360
|
+
readonly sets: "attachments";
|
|
1361
|
+
readonly ask: "What should happen to files attached to these emails?";
|
|
1362
|
+
readonly style: "cards";
|
|
1363
|
+
readonly answers: readonly [{
|
|
1364
|
+
readonly label: "Leave them out";
|
|
1365
|
+
readonly value: "drop";
|
|
1366
|
+
readonly means: "The app keeps the words of each email, not its files. Nothing extra to store or check.";
|
|
1367
|
+
}, {
|
|
1368
|
+
readonly label: "Keep them";
|
|
1369
|
+
readonly value: "keep";
|
|
1370
|
+
readonly means: "The app stores each file for the admins. Files can be large or unsafe, so keep only the types the job needs.";
|
|
1371
|
+
}];
|
|
1372
|
+
readonly note: "With keep, ask which types (photos, PDFs) and store them outside the Worker, in file storage the app already has, or ask the owner before adding some; refuse other types with `reject`.";
|
|
1373
|
+
}];
|
|
1374
|
+
readonly not_asked: readonly [{
|
|
1375
|
+
readonly sets: "domain";
|
|
1376
|
+
readonly why: "Addresses are on the project's own email domain: its staging name first, and the client's own domain once it is attached for production (`cf_zone_attach`).";
|
|
1377
|
+
}, {
|
|
1378
|
+
readonly sets: "forwarding";
|
|
1379
|
+
readonly why: "Workbench never forwards mail outside the project or catches every address: each literal address goes to the app.";
|
|
1380
|
+
}];
|
|
1381
|
+
};
|
|
1107
1382
|
readonly delivery: {
|
|
1108
1383
|
readonly choice: "optional";
|
|
1109
1384
|
readonly intro: "Receiving email at the project's own addresses, for the app to act on.";
|
|
1110
|
-
readonly when: "The client wants the app to receive email: replies to its messages, or an address such as hello@ that the app handles.";
|
|
1111
1385
|
};
|
|
1112
1386
|
};
|
|
1113
1387
|
readonly "email-sending": {
|
|
@@ -2567,10 +2841,45 @@ export declare const capabilities: {
|
|
|
2567
2841
|
readonly cost_hint_usd: 0;
|
|
2568
2842
|
readonly note: "The app's own checkStrings run passes in its tests, and npx workbench-strings check passes in CI";
|
|
2569
2843
|
}];
|
|
2844
|
+
readonly offer: {
|
|
2845
|
+
readonly pattern: "project";
|
|
2846
|
+
readonly when: "The client wants to add or change wording on a page or in an email, or asks about showing the app in another language.";
|
|
2847
|
+
readonly say: "Every word the app shows is kept in one place with Workbench strings, so changing wording never means hunting through code, and other languages can be added later.";
|
|
2848
|
+
readonly answers_file: "workbench/strings.json";
|
|
2849
|
+
readonly answers_format: "`{ \"format\": 1, \"languages\": [\"en-AU\"], \"later\": [\"fil\"] }`: the language the site is written in first, and any the client wants later. New wording goes into `strings/strings.<base>.json` with one key per sentence, and `npm run check:strings` checks it.";
|
|
2850
|
+
readonly questions: readonly [{
|
|
2851
|
+
readonly id: "strings.languages";
|
|
2852
|
+
readonly sets: "languages";
|
|
2853
|
+
readonly ask: "Does the site need to be in any language besides English?";
|
|
2854
|
+
readonly style: "cards";
|
|
2855
|
+
readonly answers: readonly [{
|
|
2856
|
+
readonly label: "English only";
|
|
2857
|
+
readonly value: "none";
|
|
2858
|
+
readonly means: "Every page and email is in English.";
|
|
2859
|
+
}, {
|
|
2860
|
+
readonly label: "Another language later";
|
|
2861
|
+
readonly value: "later";
|
|
2862
|
+
readonly means: "English now. The words are kept so a translation can be added, checked by a native speaker, without changing the code.";
|
|
2863
|
+
}];
|
|
2864
|
+
readonly other: {
|
|
2865
|
+
readonly kind: "text";
|
|
2866
|
+
readonly min: 2;
|
|
2867
|
+
readonly max: 120;
|
|
2868
|
+
readonly description: "The languages, such as Filipino or Spanish.";
|
|
2869
|
+
};
|
|
2870
|
+
readonly note: "Translations come with a Workbench tool that isn't built yet: record the languages under `later`, keep every word in the catalogue, and tell the client a translation goes live only once a named native speaker has checked it.";
|
|
2871
|
+
}];
|
|
2872
|
+
readonly not_asked: readonly [{
|
|
2873
|
+
readonly sets: "base";
|
|
2874
|
+
readonly why: "The site is written first in English, in the readers' spelling from the country answers, so it isn't asked again.";
|
|
2875
|
+
}, {
|
|
2876
|
+
readonly sets: "wording";
|
|
2877
|
+
readonly why: "Wording is content, not a setting: the client says what they want in their own words, or asks for drafts (the workbench-ai skill), and it goes into the catalogue.";
|
|
2878
|
+
}];
|
|
2879
|
+
};
|
|
2570
2880
|
readonly delivery: {
|
|
2571
2881
|
readonly choice: "built_in";
|
|
2572
2882
|
readonly intro: "The words on the app's screens and in its emails, kept in one place for each language.";
|
|
2573
|
-
readonly when: "The client wants to add or change wording on a page or in an email, or asks about showing the app in another language.";
|
|
2574
2883
|
};
|
|
2575
2884
|
};
|
|
2576
2885
|
readonly ui: {
|
|
@@ -2636,13 +2945,33 @@ export declare const capabilities: {
|
|
|
2636
2945
|
readonly cost_hint_usd: 0;
|
|
2637
2946
|
readonly 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";
|
|
2638
2947
|
}];
|
|
2948
|
+
readonly offer: {
|
|
2949
|
+
readonly pattern: "switch_on";
|
|
2950
|
+
readonly 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.";
|
|
2951
|
+
readonly 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.";
|
|
2952
|
+
readonly answers_file: "workbench/ui.json";
|
|
2953
|
+
readonly 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.";
|
|
2954
|
+
readonly questions: readonly [{
|
|
2955
|
+
readonly id: "ui.pages";
|
|
2956
|
+
readonly sets: "pages";
|
|
2957
|
+
readonly ask: "Which admin pages should the app have?";
|
|
2958
|
+
readonly style: "table";
|
|
2959
|
+
readonly 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.";
|
|
2960
|
+
}];
|
|
2961
|
+
readonly not_asked: readonly [{
|
|
2962
|
+
readonly sets: "look";
|
|
2963
|
+
readonly 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.";
|
|
2964
|
+
}, {
|
|
2965
|
+
readonly sets: "formats";
|
|
2966
|
+
readonly 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).";
|
|
2967
|
+
}];
|
|
2968
|
+
};
|
|
2639
2969
|
readonly styles: {
|
|
2640
2970
|
readonly prefix: "wb-ui-";
|
|
2641
2971
|
};
|
|
2642
2972
|
readonly delivery: {
|
|
2643
2973
|
readonly choice: "optional";
|
|
2644
2974
|
readonly intro: "A ready-made look for the pages only you and your admins see.";
|
|
2645
|
-
readonly 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.";
|
|
2646
2975
|
};
|
|
2647
2976
|
};
|
|
2648
2977
|
};
|