@somewhere-cloud/cli 0.38.12 → 0.38.13

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.
@@ -48,6 +48,8 @@ Declare tables in \`db/schema.ts\`; pages use \`somewhere:data\`
48
48
  (\`data.notes.list()\`, \`.create()\`, \`.update(id, …)\`) without API files.
49
49
  Use \`owner()\` for personal rows, \`group()\` for invited teams, \`appRole()\`
50
50
  for app-wide roles, \`anyOf()\` for owner or a role, \`allOf()\` for members-only rows.
51
+ Sharing your own rows with specific people: \`anyOf(owner(), grant())\`
52
+ (\`somewhere docs declared-data --section per-owner-sharing\`).
51
53
  Booking/help desk: \`somewhere docs sw.db --section provider-or-booker-and-owner-or-staff-recipes\`.
52
54
  Keep fitting scopes when an exceptional write needs \`sw.db.server.tx\`.
53
55
  \`shared()\` gives signed-in reads and creator-only writes. \`client\` sets browser
@@ -93,7 +95,8 @@ export const SKILLS_POINTER = `Skills: \`${SKILLS_DIR}/\` — `
93
95
  * AGENT_WORKFLOW, which is a byte mirror of the platform's agent workflow. */
94
96
  export const DECLARED_ACCESS_POINTER = 'Access rules: before choosing `serverOnly()` plus hand-written checks, read the declared-access recipes: '
95
97
  + 'teams, creator-or-owner and parent rows in `somewhere docs sw.db --section owner-or-member-and-parent-access`; '
96
- + 'bookings and help desks in `somewhere docs sw.db --section provider-or-booker-and-owner-or-staff-recipes`.';
98
+ + 'bookings and help desks in `somewhere docs sw.db --section provider-or-booker-and-owner-or-staff-recipes`; '
99
+ + 'sharing your own rows with specific people (read-only sharing, co-authors) in `somewhere docs declared-data --section per-owner-sharing`.';
97
100
  export const INIT_AGENTS_MD = `# somewhere.cloud project contract\n${SKILLS_POINTER}\n${DECLARED_ACCESS_POINTER}\n${AGENT_WORKFLOW}\n`;
98
101
  export const INIT_CLAUDE_MD = 'Read AGENTS.md for project instructions.\n';
99
102
  //# sourceMappingURL=init-agent-guide.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-agent-guide.js","sourceRoot":"","sources":["../../src/lib/init-agent-guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiF7B,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,UAAU,QAAQ;MACzD,UAAU,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;MACvE,oJAAoJ,CAAC;AAEzJ;;;+EAG+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAG,2GAA2G;MAC9I,iHAAiH;MACjH,4GAA4G,CAAC;AAEjH,MAAM,CAAC,MAAM,cAAc,GAAG,uCAAuC,cAAc,KAAK,uBAAuB,KAAK,cAAc,IAAI,CAAC;AACvI,MAAM,CAAC,MAAM,cAAc,GAAG,4CAA4C,CAAC"}
1
+ {"version":3,"file":"init-agent-guide.js","sourceRoot":"","sources":["../../src/lib/init-agent-guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1D,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmF7B,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,UAAU,QAAQ;MACzD,UAAU,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;MACvE,oJAAoJ,CAAC;AAEzJ;;;+EAG+E;AAC/E,MAAM,CAAC,MAAM,uBAAuB,GAAG,2GAA2G;MAC9I,iHAAiH;MACjH,6GAA6G;MAC7G,2IAA2I,CAAC;AAEhJ,MAAM,CAAC,MAAM,cAAc,GAAG,uCAAuC,cAAc,KAAK,uBAAuB,KAAK,cAAc,IAAI,CAAC;AACvI,MAAM,CAAC,MAAM,cAAc,GAAG,4CAA4C,CAAC"}
@@ -138,6 +138,8 @@ it is not the default for your app's data. Choose fitting declared access
138
138
  before the first deploy: \`owner()\` for personal rows, \`group()\` for teams,
139
139
  and \`anyOf()\` for combined access. For booking and help-desk rules, read:
140
140
  \`somewhere docs sw.db --section provider-or-booker-and-owner-or-staff-recipes\`
141
+ To share your own rows with specific people, read:
142
+ \`somewhere docs declared-data --section per-owner-sharing\`
141
143
 
142
144
  \`\`\`sh
143
145
  somewhere typecheck
@@ -1 +1 @@
1
- {"version":3,"file":"init-green-template.js","sourceRoot":"","sources":["../../src/lib/init-green-template.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBpB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,MAAM,SAAS,GAAG;;;CAGjB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;CAUd,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;CAQX,CAAC;AAEF,MAAM,OAAO,GAAG;;;;;;;CAOf,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBX,CAAC;AAEF,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAcd,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Bd,CAAC;AAEF,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,yJAAyJ,EAAE;QAC1L,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;QACtC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC5C;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,oUAAoU;SAC9U;QACD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE;QACrC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;QACvC,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE;QACtD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE;QAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE;QACzC,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,2EAA2E,EAAE;QACvH,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE;QACzC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE;KAC7C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"init-green-template.js","sourceRoot":"","sources":["../../src/lib/init-green-template.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBpB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,MAAM,SAAS,GAAG;;;CAGjB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;CAUd,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;CAQX,CAAC;AAEF,MAAM,OAAO,GAAG;;;;;;;CAOf,CAAC;AAEF,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBX,CAAC;AAEF,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAcd,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCd,CAAC;AAEF,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,yJAAyJ,EAAE;QAC1L,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC9C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE;QACtC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC5C;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,oUAAoU;SAC9U;QACD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE;QACrC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;QACvC,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE;QACtD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE;QAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE;QACzC,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,2EAA2E,EAAE;QACvH,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE;QACzC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE;KAC7C,CAAC;AACJ,CAAC"}
@@ -1,8 +1,8 @@
1
1
  export const BUNDLED_SKILLS_PACK = {
2
2
  "schema": 1,
3
3
  "name": "somewhere-skills",
4
- "version": "1+e9c2e63a2883",
5
- "sha256": "e9c2e63a2883be49882eefce95247feed462a3291e0456c752bc930082427da0",
4
+ "version": "1+9dcf2d17607c",
5
+ "sha256": "9dcf2d17607c72a8f9a7c8a6abfb839f2874583801b81a9c8a7c85f3b4ef0f74",
6
6
  "files": [
7
7
  {
8
8
  "path": "deploy-verify-loop/SKILL.md",
@@ -11,13 +11,13 @@ export const BUNDLED_SKILLS_PACK = {
11
11
  },
12
12
  {
13
13
  "path": "schema-changes/SKILL.md",
14
- "sha256": "c444066ee021b82979a2fa998a9f44a1f463aa9ed5d6429cce9d8f181cd7560f",
15
- "content": "---\nname: schema-changes\ndescription: Before adding, changing, or removing a table or column in db/schema.ts.\n---\n\n# Change the database schema safely\n\n## The file is the contract\n\nThe default `somewhere init` starter has no `db/schema.ts`: create it at the project root, or start with `somewhere init --features private-data`, which includes one.\n\n```ts\n// db/schema.ts\nimport { id, owner, schema, table, text, timestamp } from 'somewhere/db';\n\nexport default schema({\n notes: table(\n {\n id: id(),\n title: text(),\n body: text({ default: '' }),\n created_at: timestamp({ default: 'now' }),\n },\n {\n scope: owner(),\n client: {\n read: ['id', 'title', 'body', 'created_at'],\n create: ['title', 'body'],\n update: ['title', 'body'],\n delete: true,\n },\n },\n ),\n});\n```\n\nA table without a `client` block can't be reached from the browser at all.\n\nBefore the first deploy, delete an unused starter table declaration outright: there is no deployed table to retire. After a table has been deployed, mark it `removedTable()` to retire it with 30-day data retention, including when the table is empty.\n\nDeclare a file collection in `db/schema.ts`: who may upload, read, replace and delete its files.\n\nRun `somewhere typecheck` before deploying schema changes.\n\n## What a deploy does with it\n\n- **Additive changes apply**: a new table, a new nullable-or-defaulted column, a new index, a new unique group. Unchanged schema is a no-op.\n- **Unmarked removals and shape changes refuse** with `409 SCHEMA_DEPLOY_REFUSED` and a message naming the change.\n- **Removing a table** is `old_table: removedTable()`.\n- once the new version is live it retires the table and keeps its data for 30 days.\n- a production deploy or a promotion that would remove or rename a column is refused before anything changes, so a running release never loses a column it uses. Keep the column declared and leave its data in place.\n\n## Failure: raw SQL refused after the schema file deploys\n\nOn an older shared database, ordinary `sw.db.query` / `sw.db.batch` fail before transport with `MANAGED_RAW_SQL_REQUIRES_SERVER_AUTHORITY`, including in job, queue, and cron handlers; with a separate SQL database they run there and never see declared tables. Fix: write with `sw.db.insert` / `sw.db.update` / `sw.db.remove` (the table needs a declared intent)\n\nSources (`somewhere docs <topic>`): declared-data, declared-files, getting-started, sw.db, troubleshooting.\n"
14
+ "sha256": "71fafce1ed983f1de2667253b4be41f8a0ec15e61fc5eda22ecfe05310746f49",
15
+ "content": "---\nname: schema-changes\ndescription: Before adding, changing, or removing a table or column in db/schema.ts.\n---\n\n# Change the database schema safely\n\n## The file is the contract\n\nThe default `somewhere init` starter has no `db/schema.ts`: create it at the project root, or start with `somewhere init --features private-data`, which includes one.\n\n```ts\n// db/schema.ts\nimport { id, owner, schema, table, text, timestamp } from 'somewhere/db';\n\nexport default schema({\n notes: table(\n {\n id: id(),\n title: text(),\n body: text({ default: '' }),\n created_at: timestamp({ default: 'now' }),\n },\n {\n scope: owner(),\n client: {\n read: ['id', 'title', 'body', 'created_at'],\n create: ['title', 'body'],\n update: ['title', 'body'],\n delete: true,\n },\n },\n ),\n});\n```\n\nA table without a `client` block can't be reached from the browser at all.\n\nBefore the first deploy, delete an unused starter table declaration outright: there is no deployed table to retire. After a table has been deployed, mark it `removedTable()` to retire it with 30-day data retention, including when the table is empty.\n\nRun `somewhere typecheck` before deploying schema changes.\n\n## What a deploy does with it\n\n- **Additive changes apply**: a new table, a new nullable-or-defaulted column, a new index, a new unique group. Unchanged schema is a no-op.\n- **Unmarked removals and shape changes refuse** with `409 SCHEMA_DEPLOY_REFUSED` and a message naming the change.\n- **Access-rule changes apply in place**: a later deploy can change an existing table's scope, and its rows stay.\n- a production deploy or a promotion that would remove or rename a column is refused before anything changes, so a running release never loses a column it uses. Keep the column declared and leave its data in place.\n\n## Failure: raw SQL refused after the schema file deploys\n\nOn an older shared database, ordinary `sw.db.query` / `sw.db.batch` fail before transport with `MANAGED_RAW_SQL_REQUIRES_SERVER_AUTHORITY`, including in job, queue, and cron handlers; with a separate SQL database they run there and never see declared tables. Fix: write with `sw.db.insert` / `sw.db.update` / `sw.db.remove` (the table needs a declared intent)\n\nSources (`somewhere docs <topic>`): declared-data, getting-started, sw.db, troubleshooting.\n"
16
16
  },
17
17
  {
18
18
  "path": "sign-in-setup/SKILL.md",
19
- "sha256": "6b729ec43cf5572321ba4cd7ff4eccb28c35ebacb925d22ef1b8fb0eca4c5093",
20
- "content": "---\nname: sign-in-setup\ndescription: When the app needs users to sign up, sign in, or sign out.\n---\n\n# Set up sign-in\n\n## Server: one route file\n\n`login` / `signup` are developer-key-gated (the browser can't call them), so one server route mediates them and sets the session cookies.\n\n```ts\n// api/auth/[...path].ts\nexport { somewhereAuth as default } from '@somewhere-cloud/sdk/server';\n```\n\nIt serves `POST /signup`, `/login`, `/logout`, `/magic-link`, `/magic-link/verify`, `GET /me`, and the Google/GitHub/Discord `GET /<provider>-url` + `POST /<provider>` code exchange.\n\n## Client and React state reference\n\nRead `docs({ topic: 'auth-client', section: 'react-auth-state' })` for the SDK's React state contract. Extend the starter's existing provider and auth client.\n\n## Page: the SDK client\n\n```bash\nnpm i @somewhere-cloud/sdk\n```\n\n```ts\n// src/auth.ts — page code\nimport { createSomewhereAuth } from '@somewhere-cloud/sdk/auth'\n\nexport const auth = createSomewhereAuth()\n\n// Call from your sign-up form; throws AuthError with the message on failure.\nexport async function signUp(email: string, password: string) {\n await auth.signUp({ email, password }) // or auth.signIn({ email, password })\n return auth.getUser() // the signed-in user, or null\n}\nexport async function signOut() {\n await auth.signOut();\n if (auth.getState().signOutUnconfirmed) {\n throw new Error('Sign-out could not be confirmed. Please try again.');\n }\n // Only navigate or reload after confirmed logout.\n}\n```\n\nAwait `signOut()` in the click handler before navigating or reloading. While it is pending, keep the current screen or show a disabled signing-out state. Do not use the appearance of a signed-out form as proof that the server session has ended. After awaiting, check `auth.getState().signOutUnconfirmed`; show a retry message when true. `signOut()` can settle without confirming server logout.\n\nCalls to your own `api/*` functions just send `credentials: 'include'`.\n\nDon't write `getCookie()` / token-parsing helpers → `sw.auth.fromRequest(req)` reads cookie + Bearer header and returns the validated user (or null) in one call.\n\nMail to `<name>@<project>.test.somewhere.site` is read with `somewhere email test-inbox <address>`.\n\n## Failure 1: sign-in errors\n\nexpected failures (wrong password, duplicate email, weak password) come back as structured 4xx with the real message, never an opaque 500.\n\n## Failure 2: AUTH_REQUIRED from an owner() table\n\nThe table is user-owned, so the platform scopes it to a principal, and this request had none: there is no signed-in user, and this table does not declare `owner({ visitors: true })`, which is the declaration that accepts a stable anonymous visitor identity.\n\nSources (`somewhere docs <topic>`): auth-client, common-mistakes, recipe-signed-in-app, sdk, troubleshooting.\n"
19
+ "sha256": "ffc4f29eb96c0a18c5ea0ce10308f696f227ec842c37e0bd70951b2284d885ba",
20
+ "content": "---\nname: sign-in-setup\ndescription: When the app needs users to sign up, sign in, or sign out.\n---\n\n# Set up sign-in\n\n## Server: one route file\n\n`login` / `signup` are developer-key-gated (the browser can't call them), so one server route mediates them and sets the session cookies.\n\n```ts\n// api/auth/[...path].ts\nexport { somewhereAuth as default } from '@somewhere-cloud/sdk/server';\n```\n\nIt serves `POST /signup`, `/login`, `/logout`, `/magic-link`, `/magic-link/verify`, `GET /me`, and the Google/GitHub/Discord `GET /<provider>-url` + `POST /<provider>` code exchange, and `POST /mfa/challenge`, the email sign-in code step: in the page, `auth.completeMfa({ code })` finishes a sign-in that rejected with code `MFA_REQUIRED` (`sw.auth` → `email-sign-in-codes`).\n\n## Client and React state reference\n\nRead `docs({ topic: 'auth-client', section: 'react-auth-state' })` for the SDK's React state contract. Extend the starter's existing provider and auth client.\n\n## Page: the SDK client\n\n```bash\nnpm i @somewhere-cloud/sdk\n```\n\n```ts\n// src/auth.ts — page code\nimport { createSomewhereAuth } from '@somewhere-cloud/sdk/auth'\n\nexport const auth = createSomewhereAuth()\n\n// Call from your sign-up form; throws AuthError with the message on failure.\nexport async function signUp(email: string, password: string) {\n await auth.signUp({ email, password }) // or auth.signIn({ email, password })\n return auth.getUser() // the signed-in user, or null\n}\nexport async function signOut() {\n await auth.signOut();\n if (auth.getState().signOutUnconfirmed) {\n throw new Error('Sign-out could not be confirmed. Please try again.');\n }\n // Only navigate or reload after confirmed logout.\n}\n```\n\nAwait `signOut()` in the click handler before navigating or reloading. While it is pending, keep the current screen or show a disabled signing-out state. Do not use the appearance of a signed-out form as proof that the server session has ended. After awaiting, check `auth.getState().signOutUnconfirmed`; show a retry message when true. `signOut()` can settle without confirming server logout.\n\nCalls to your own `api/*` functions just send `credentials: 'include'`.\n\nDon't write `getCookie()` / token-parsing helpers → `sw.auth.fromRequest(req)` reads cookie + Bearer header and returns the validated user (or null) in one call.\n\nMail to `<name>@<project>.test.somewhere.site` is read with `somewhere email test-inbox <address>`.\n\n## Failure 1: sign-in errors\n\nexpected failures (wrong password, duplicate email, weak password) come back as structured 4xx with the real message, never an opaque 500.\n\n## Failure 2: AUTH_REQUIRED from an owner() table\n\nThe table is user-owned, so the platform scopes it to a principal, and this request had none: there is no signed-in user, and this table does not declare `owner({ visitors: true })`, which is the declaration that accepts a stable anonymous visitor identity.\n\nSources (`somewhere docs <topic>`): auth-client, common-mistakes, recipe-signed-in-app, sdk, troubleshooting.\n"
21
21
  },
22
22
  {
23
23
  "path": "troubleshooting/SKILL.md",
@@ -36,8 +36,8 @@ export const BUNDLED_SKILLS_PACK = {
36
36
  },
37
37
  {
38
38
  "path": "design/SKILL.md",
39
- "sha256": "ae27b177f671b2cb126228ec8752bb6d8a4f0a692b4ed5ae7001bf45bd5b2efe",
40
- "content": "---\nname: design\ndescription: Before building or changing a page, form, list or layout: the UI kit in src/ui, the tokens, and the mistakes that make a page look unfinished.\n---\n\n# Build pages that look finished\n\n## The starter is a system\n\nThe starter is a small design system, and pages built with it look finished; pages built around it look like a form from 2009.\n\n| `src/ui/` | The UI kit: `Button`, `TextField`, `SelectField`, `TextareaField`, `CheckboxField`, `FormRow`, `Card`, `Table`, `Stat`, `Badge`, `Tabs`, `Dialog`, `Notice`, `Skeleton`, `Stack`, `Grid`, `Inline`, `PageHeader`; plus `AppShell` (the frame), `AuthCard` (sign-in) and `feedback.tsx` (`LoadingScreen`, `Alert`, `EmptyState`). |\n| `src/pages/HomePage.tsx` | A worked example of the kit: a header with the one main action, a stat row, a table in a card, a dialog form. Copy its shape. |\n\n## Rules\n\n- Every control is a kit component. A bare `<input>`, `<select>` or `<button>` in a page renders with browser defaults next to styled controls; use `TextField`, `SelectField` and `Button`.\n- Never write a colour, font or size in a page: every value is a token such as `var(--color-accent)` or `var(--space-4)`. A missing token goes in `tokens.css`, in both the light and the dark block.\n- Never restyle a tag globally (`select { … }`, `input { … }`). Add a class at the end of `app.css`.\n- One h1 and one primary `Button` per page, both in `PageHeader`; everything else is secondary, quiet or a link. Two primary buttons means neither is.\n- Cards group peers: a list, a form, two to four `Stat`s in a `Grid`. A page that is nothing but identical cards has no hierarchy; the main number goes in the header and the rest in a `Table`.\n- Empty, loading and error are states to design, not afterthoughts: `EmptyState` with one action, `Skeleton` while loading, `Notice` with a retry when a request fails. Design the empty state before the populated one.\n- Everything reflows at phone width: `Grid` and `FormRow` stack their children, and a `Table` scrolls inside its `Card` instead of widening the page.\n\n## The sign-in page\n\n`AuthCard` has two slots: `providers` above the email form and `children` below it. Nothing is added as a sibling of the card: its two-column grid holds exactly the intro and the form, and a third child lands in its own row.\n\n## Before deploy\n\nAfter deploying, run `somewhere verify` and check the live page at desktop and phone size; its layout line reports contrast, overflow and tap targets under 44px, and each is a regression.\n\n## Failure 1: it is all cards\n\nA page that is six white boxes with the same shadow: move the main number into `PageHeader`, group the peers into one `Card` with a `Table`, and put the form in a `Dialog` behind the primary button.\n\n## Failure 2: an unstyled select\n\nA `<select>` with the browser's grey box and square arrow: it is not a `SelectField`.\n\nSources (`somewhere docs <topic>`): design-system.\n"
39
+ "sha256": "30ae56053da63ed2eb1b0ea5d52109dadb547eebb9eb312017dfcd1a8bfaeeab",
40
+ "content": "---\nname: design\ndescription: Before building or changing a page, form, list or layout: the UI kit in src/ui, the tokens, and the mistakes that make a page look unfinished.\n---\n\n# Build pages that look finished\n\n## The starter is a system\n\nThe starter is a small design system, and pages built with it look finished; pages built around it look like a form from 2009.\n\n| `src/ui/` | The UI kit: `Button`, `TextField`, `SelectField`, `TextareaField`, `CheckboxField`, `FormRow`, `Card`, `Table`, `Stat`, `Badge`, `Tabs`, `Dialog`, `Notice`, `Skeleton`, `Stack`, `Grid`, `Inline`, `PageHeader`; plus `AppShell` (the frame), `AuthCard` (sign-in) and `feedback.tsx` (`Alert`, `EmptyState`). |\n| `src/pages/HomePage.tsx` | A worked example of the kit: a header with the one main action, a stat row, a table in a card, a dialog form. Copy its shape. |\n\n## Rules\n\n- Every control is a kit component. A bare `<input>`, `<select>` or `<button>` in a page renders with browser defaults next to styled controls; use `TextField`, `SelectField` and `Button`.\n- Never write a colour, font or size in a page: every value is a token such as `var(--color-accent)` or `var(--space-4)`. A missing token goes in `tokens.css`, in both the light and the dark block.\n- Never restyle a tag globally (`select { … }`, `input { … }`). Add a class at the end of `app.css`.\n- One h1 and one primary `Button` per page, both in `PageHeader`; everything else is secondary, quiet or a link. Two primary buttons means neither is.\n- Cards group peers: a list, a form, two to four `Stat`s in a `Grid`. A page that is nothing but identical cards has no hierarchy; the main number goes in the header and the rest in a `Table`.\n- Empty, loading and error are states to design, not afterthoughts: `EmptyState` with one action, `Skeleton` while loading, `Notice` with a retry when a request fails. Design the empty state before the populated one.\n- Everything reflows at phone width: `Grid` and `FormRow` stack their children, and a `Table` scrolls inside its `Card` instead of widening the page.\n\n## The sign-in page\n\n`AuthCard` has two slots: `providers` above the email form and `children` below it. Nothing is added as a sibling of the card: its two-column grid holds exactly the intro and the form, and a third child lands in its own row.\n\n## Before deploy\n\nAfter deploying, run `somewhere verify` and check the live page at desktop and phone size; its layout line reports contrast, overflow and tap targets under 44px, and each is a regression.\n\n## Failure 1: it is all cards\n\nA page that is six white boxes with the same shadow: move the main number into `PageHeader`, group the peers into one `Card` with a `Table`, and put the form in a `Dialog` behind the primary button.\n\n## Failure 2: an unstyled select\n\nA `<select>` with the browser's grey box and square arrow: it is not a `SelectField`.\n\nSources (`somewhere docs <topic>`): design-system.\n"
41
41
  }
42
42
  ]
43
43
  };
@@ -1 +1 @@
1
- {"version":3,"file":"skills-pack.generated.js","sourceRoot":"","sources":["../../src/lib/skills-pack.generated.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,gBAAgB;IAC3B,QAAQ,EAAE,kEAAkE;IAC5E,OAAO,EAAE;QACP;YACE,MAAM,EAAE,6BAA6B;YACrC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mnEAAmnE;SAC/nE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,y/EAAy/E;SACrgF;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k2FAAk2F;SAC92F;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,s2DAAs2D;SACl3D;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,yxEAAyxE;SACryE;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k3DAAk3D;SAC93D;QACD;YACE,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,65FAA65F;SACz6F;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"skills-pack.generated.js","sourceRoot":"","sources":["../../src/lib/skills-pack.generated.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,QAAQ,EAAE,CAAC;IACX,MAAM,EAAE,kBAAkB;IAC1B,SAAS,EAAE,gBAAgB;IAC3B,QAAQ,EAAE,kEAAkE;IAC5E,OAAO,EAAE;QACP;YACE,MAAM,EAAE,6BAA6B;YACrC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,mnEAAmnE;SAC/nE;QACD;YACE,MAAM,EAAE,yBAAyB;YACjC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,22EAA22E;SACv3E;QACD;YACE,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,miGAAmiG;SAC/iG;QACD;YACE,MAAM,EAAE,0BAA0B;YAClC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,s2DAAs2D;SACl3D;QACD;YACE,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,yxEAAyxE;SACryE;QACD;YACE,MAAM,EAAE,+BAA+B;YACvC,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,k3DAAk3D;SAC93D;QACD;YACE,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,kEAAkE;YAC5E,SAAS,EAAE,44FAA44F;SACx5F;KACF;CACF,CAAC"}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@somewhere-cloud/cli",
3
- "version": "0.38.12",
3
+ "version": "0.38.13",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@somewhere-cloud/cli",
9
- "version": "0.38.12",
9
+ "version": "0.38.13",
10
10
  "bundleDependencies": [
11
11
  "@modelcontextprotocol/sdk",
12
12
  "chokidar",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somewhere-cloud/cli",
3
- "version": "0.38.12",
3
+ "version": "0.38.13",
4
4
  "description": "CLI for somewhere.cloud — auth, projects, deploy, pull, promote, db, logs, env, MCP bridge.",
5
5
  "keywords": [
6
6
  "somewhere",