@mccaskie-labs/workbench-config 0.1.39 → 0.1.41
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/email-inbound.json +1 -1
- package/capabilities/email-inbound.md +1 -1
- package/capabilities/email-sending.json +2 -2
- package/capabilities/email-sending.md +3 -3
- package/dist/capabilities.gen.d.ts +4 -4
- package/dist/capabilities.gen.js +4 -4
- package/dist/skills.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @mccaskie-labs/workbench-config
|
|
2
2
|
|
|
3
|
+
## 0.1.41
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- The email-sending and email-inbound guides and manifests no longer name one install's domain. They say `<projects domain>` and tell Claude to read it from the project's README (hard rule 13).
|
|
8
|
+
|
|
9
|
+
## 0.1.40
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- A skill whose client questions aren't written yet (pdf, email) also gets its "Restyling" section, which now says PDFs and emails take project.css too.
|
|
14
|
+
|
|
3
15
|
## 0.1.39
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"title": "Store inbound mail",
|
|
106
106
|
"lang": "ts",
|
|
107
107
|
"probe": "email-inbound.roundtrip",
|
|
108
|
-
"code": "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox
|
|
108
|
+
"code": "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox@<id>-staging.<projects domain>')) return reject('Unknown mailbox')\n await saveMail(env, { message_id: mail.message_id, subject: mail.subject, text: mail.text, received_at: mail.received_at })\n}"
|
|
109
109
|
}
|
|
110
110
|
],
|
|
111
111
|
"probes": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Inbound email
|
|
2
2
|
|
|
3
|
-
A project receives mail on a domain in its namespace, for example
|
|
3
|
+
A project receives mail on a domain in its namespace, for example `<id>-staging.<projects domain>`, and each address it uses is routed to one of its own Workers. `<projects domain>` is the domain this Workbench install keeps its projects under: it is the last part of the project's staging address in its README, so read it there and never assume one. A domain the project owns joins the namespace with `cf_zone_attach` (phase 6).
|
|
4
4
|
|
|
5
5
|
## Setting it up (Claude, through Control)
|
|
6
6
|
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
{ "code": "missing_permission", "http": 403, "retryable": false, "meaning": "Control's Cloudflare token lacks Email Sending (edit)" }
|
|
25
25
|
],
|
|
26
26
|
"rules": [
|
|
27
|
-
{ "id": "email-sending.namespace-only", "kind": "must", "text": "Onboard a domain in the project's own namespace, for example mail.<id
|
|
27
|
+
{ "id": "email-sending.namespace-only", "kind": "must", "text": "Onboard a domain in the project's own namespace, for example mail.<id>.<projects domain> (the domain this install keeps its projects under). A domain the project owns follows cf_zone_attach (step 6.1).", "enforced_by": "control", "probe": "email-sending.onboard" },
|
|
28
28
|
{ "id": "email-sending.onboard-before-sender", "kind": "must", "text": "Onboard the domain before adding senders on it. gw_sender_add refuses a domain the project hasn't onboarded.", "enforced_by": "control", "probe": "email-sending.sender-add" },
|
|
29
29
|
{ "id": "email-sending.never-adopt", "kind": "must_not", "text": "Expect Control to take over a domain onboarded by hand. It refuses with name_taken.", "enforced_by": "control", "probe": "email-sending.onboard" },
|
|
30
30
|
{ "id": "email-sending.verified-over-doh", "kind": "must", "text": "Treat a domain as ready only when cf_email_sending_status says ready: every expected record is in the zone and visible over DNS-over-HTTPS.", "enforced_by": "control", "probe": "email-sending.status" }
|
|
31
31
|
],
|
|
32
32
|
"probes": [
|
|
33
|
-
{ "id": "email-sending.onboard", "half": "drill", "expect": "pass", "cost_hint_usd": 0, "note": "cf_email_sending_onboard on mail.<id
|
|
33
|
+
{ "id": "email-sending.onboard", "half": "drill", "expect": "pass", "cost_hint_usd": 0, "note": "cf_email_sending_onboard on mail.<id>.<projects domain>; a second call changes nothing" },
|
|
34
34
|
{ "id": "email-sending.status", "half": "drill", "expect": "pass", "cost_hint_usd": 0 },
|
|
35
35
|
{ "id": "email-sending.sender-add", "half": "drill", "expect": "pass", "cost_hint_usd": 0, "note": "Then a runtime send from the new address (email.send.transactional)" },
|
|
36
36
|
{ "id": "email-sending.out-of-scope", "half": "drill", "expect": "refused_as_expected", "refusal": "out_of_scope", "cost_hint_usd": 0, "note": "Another project's namespace" }
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Email sending domains
|
|
2
2
|
|
|
3
|
-
A project sends from addresses on a domain Control onboarded for it. Today that is a domain in the project's namespace
|
|
3
|
+
A project sends from addresses on a domain Control onboarded for it. Today that is a domain in the project's namespace under the install's projects domain, usually `mail.<id>.<projects domain>`. `<projects domain>` is the domain this Workbench install keeps its projects under: it is the last part of the project's staging address in its README, so read it there and never assume one. A domain the project owns follows `cf_zone_attach` in step 6.1.
|
|
4
4
|
|
|
5
|
-
1. `cf_email_sending_onboard domain=mail.<id
|
|
5
|
+
1. `cf_email_sending_onboard domain=mail.<id>.<projects domain>` creates the Email Sending subdomain in the projects account, adds the records Cloudflare expects (the `cf-bounce` MX and SPF, and DKIM) and the domain's own DMARC record (`p=reject; adkim=s; aspf=r`), records them, and checks each over DNS-over-HTTPS. A record in the way stops it; it changes nothing it didn't make.
|
|
6
6
|
2. `cf_email_sending_status` says `ready` once every record is visible. Records can take a few minutes.
|
|
7
|
-
3. `gw_sender_add address=hello@mail.<id
|
|
7
|
+
3. `gw_sender_add address=hello@mail.<id>.<projects domain>` allows the address. The Gateway accepts it within a minute.
|
|
8
8
|
|
|
9
9
|
The DNS records are ordinary `dns_record` rows for the project, so removing one is `cf_dns_delete` (two-step).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const MANIFEST_VERSION: "
|
|
1
|
+
export declare const MANIFEST_VERSION: "b986177e8690";
|
|
2
2
|
export declare const capabilities: {
|
|
3
3
|
readonly ai: {
|
|
4
4
|
readonly $schema: "./schema.json";
|
|
@@ -985,7 +985,7 @@ export declare const capabilities: {
|
|
|
985
985
|
readonly id: "email-inbound.example.handler";
|
|
986
986
|
readonly title: "Store inbound mail";
|
|
987
987
|
readonly lang: "ts";
|
|
988
|
-
readonly code: "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox
|
|
988
|
+
readonly code: "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox@<id>-staging.<projects domain>')) return reject('Unknown mailbox')\n await saveMail(env, { message_id: mail.message_id, subject: mail.subject, text: mail.text, received_at: mail.received_at })\n}";
|
|
989
989
|
readonly probe: "email-inbound.roundtrip";
|
|
990
990
|
}];
|
|
991
991
|
readonly probes: readonly [{
|
|
@@ -1070,7 +1070,7 @@ export declare const capabilities: {
|
|
|
1070
1070
|
readonly rules: readonly [{
|
|
1071
1071
|
readonly id: "email-sending.namespace-only";
|
|
1072
1072
|
readonly kind: "must";
|
|
1073
|
-
readonly text: "Onboard a domain in the project's own namespace, for example mail.<id
|
|
1073
|
+
readonly text: "Onboard a domain in the project's own namespace, for example mail.<id>.<projects domain> (the domain this install keeps its projects under). A domain the project owns follows cf_zone_attach (step 6.1).";
|
|
1074
1074
|
readonly enforced_by: "control";
|
|
1075
1075
|
readonly probe: "email-sending.onboard";
|
|
1076
1076
|
}, {
|
|
@@ -1097,7 +1097,7 @@ export declare const capabilities: {
|
|
|
1097
1097
|
readonly half: "drill";
|
|
1098
1098
|
readonly expect: "pass";
|
|
1099
1099
|
readonly cost_hint_usd: 0;
|
|
1100
|
-
readonly note: "cf_email_sending_onboard on mail.<id
|
|
1100
|
+
readonly note: "cf_email_sending_onboard on mail.<id>.<projects domain>; a second call changes nothing";
|
|
1101
1101
|
}, {
|
|
1102
1102
|
readonly id: "email-sending.status";
|
|
1103
1103
|
readonly half: "drill";
|
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 = "b986177e8690";
|
|
4
4
|
export const capabilities = {
|
|
5
5
|
"ai": {
|
|
6
6
|
"$schema": "./schema.json",
|
|
@@ -1344,7 +1344,7 @@ export const capabilities = {
|
|
|
1344
1344
|
"id": "email-inbound.example.handler",
|
|
1345
1345
|
"title": "Store inbound mail",
|
|
1346
1346
|
"lang": "ts",
|
|
1347
|
-
"code": "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox
|
|
1347
|
+
"code": "export async function handleEmail(mail, env, ctx, { reject }) {\n if (!mail.to.some((t) => t.address === 'inbox@<id>-staging.<projects domain>')) return reject('Unknown mailbox')\n await saveMail(env, { message_id: mail.message_id, subject: mail.subject, text: mail.text, received_at: mail.received_at })\n}",
|
|
1348
1348
|
"probe": "email-inbound.roundtrip"
|
|
1349
1349
|
}
|
|
1350
1350
|
],
|
|
@@ -1452,7 +1452,7 @@ export const capabilities = {
|
|
|
1452
1452
|
{
|
|
1453
1453
|
"id": "email-sending.namespace-only",
|
|
1454
1454
|
"kind": "must",
|
|
1455
|
-
"text": "Onboard a domain in the project's own namespace, for example mail.<id
|
|
1455
|
+
"text": "Onboard a domain in the project's own namespace, for example mail.<id>.<projects domain> (the domain this install keeps its projects under). A domain the project owns follows cf_zone_attach (step 6.1).",
|
|
1456
1456
|
"enforced_by": "control",
|
|
1457
1457
|
"probe": "email-sending.onboard"
|
|
1458
1458
|
},
|
|
@@ -1484,7 +1484,7 @@ export const capabilities = {
|
|
|
1484
1484
|
"half": "drill",
|
|
1485
1485
|
"expect": "pass",
|
|
1486
1486
|
"cost_hint_usd": 0,
|
|
1487
|
-
"note": "cf_email_sending_onboard on mail.<id
|
|
1487
|
+
"note": "cf_email_sending_onboard on mail.<id>.<projects domain>; a second call changes nothing"
|
|
1488
1488
|
},
|
|
1489
1489
|
{
|
|
1490
1490
|
"id": "email-sending.status",
|
package/dist/skills.js
CHANGED
|
@@ -144,7 +144,7 @@ export function renderSkill(m, guide) {
|
|
|
144
144
|
...beforeBlock(m),
|
|
145
145
|
];
|
|
146
146
|
if (!o) {
|
|
147
|
-
out.push("", "## Questions", "", "This tool's questions for the client aren't written yet. Use it with its defaults, tell the client that is what you did, and invent no setting. A choice only the client can make goes to them as a plain question.", "", ...useBlock(m, guide));
|
|
147
|
+
out.push("", "## Questions", "", "This tool's questions for the client aren't written yet. Use it with its defaults, tell the client that is what you did, and invent no setting. A choice only the client can make goes to them as a plain question.", ...(m.styles ? ["", "## Restyling", "", restyleLine(m.styles.prefix)] : []), "", ...useBlock(m, guide));
|
|
148
148
|
return `${out.join("\n")}\n`;
|
|
149
149
|
}
|
|
150
150
|
out.push("", "## What to say", "", d.choice === "optional"
|
|
@@ -162,7 +162,7 @@ export function renderSkill(m, guide) {
|
|
|
162
162
|
}
|
|
163
163
|
/** How a project restyles what a component draws (docs/capabilities-manifest.md §10). */
|
|
164
164
|
function restyleLine(prefix) {
|
|
165
|
-
return `Everything this tool draws (on a page, in a PDF or in an email) has a \`${prefix}\` class with a default Workbench style, and its colours and sizes are \`--${prefix}*\` variables. All of them are listed, each with what it is, in \`public/styles/workbench.css\`, which \`npx workbench-ui styles\` generates: never edit it. To match the project's own look, write rules for those classes, or set the variables to the project's own colours, in \`public/styles/project.css\`. It loads after workbench.css and always wins. When the client asks for a different look, change project.css, never the tool's markup.`;
|
|
165
|
+
return `Everything this tool draws (on a page, in a PDF or in an email) has a \`${prefix}\` class with a default Workbench style, and its colours and sizes are \`--${prefix}*\` variables. All of them are listed, each with what it is, in \`public/styles/workbench.css\`, which \`npx workbench-ui styles\` generates: never edit it. To match the project's own look, write rules for those classes, or set the variables to the project's own colours, in \`public/styles/project.css\`. It loads after workbench.css and always wins, and PDFs and emails take it too (\`src/lib/project-css.ts\`). When the client asks for a different look, change project.css, never the tool's markup.`;
|
|
166
166
|
}
|
|
167
167
|
/** The `workbench-start` skill: every tool introduced to the owner, and how their choices are recorded (§9.6). */
|
|
168
168
|
export function renderStart(manifests) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mccaskie-labs/workbench-config",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "Workbench app configuration: WORKBENCH_ENV, typed variables that fail by name, secrets that are never printed, and the capabilities manifest.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|