showpane 0.4.13 → 0.4.14

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.
Files changed (51) hide show
  1. package/README.md +2 -1
  2. package/bundle/meta/scaffold-manifest.json +7 -7
  3. package/bundle/scaffold/VERSION +1 -1
  4. package/bundle/scaffold/src/__tests__/portal-contracts.test.ts +7 -0
  5. package/bundle/scaffold/src/app/page.tsx +43 -6
  6. package/bundle/scaffold/src/components/portal-shell.tsx +23 -0
  7. package/bundle/scaffold/src/lib/portal-contracts.ts +33 -0
  8. package/bundle/toolchain/CLI_VERSION +1 -0
  9. package/bundle/toolchain/TELEMETRY_CONFIG.json +4 -0
  10. package/bundle/toolchain/VERSION +1 -1
  11. package/bundle/toolchain/bin/ensure-cloud-project-link.ts +34 -1
  12. package/bundle/toolchain/bin/showpane-config +108 -29
  13. package/bundle/toolchain/bin/showpane-telemetry-log +84 -0
  14. package/bundle/toolchain/bin/showpane-telemetry-sync +212 -0
  15. package/bundle/toolchain/bin/showpane-update-check +130 -0
  16. package/bundle/toolchain/skills/SKILL.md.tmpl +13 -0
  17. package/bundle/toolchain/skills/VERSION +1 -1
  18. package/bundle/toolchain/skills/portal-analytics/SKILL.md +59 -34
  19. package/bundle/toolchain/skills/portal-analytics/SKILL.md.tmpl +192 -0
  20. package/bundle/toolchain/skills/portal-create/SKILL.md +59 -58
  21. package/bundle/toolchain/skills/portal-create/SKILL.md.tmpl +264 -0
  22. package/bundle/toolchain/skills/portal-credentials/SKILL.md +62 -42
  23. package/bundle/toolchain/skills/portal-credentials/SKILL.md.tmpl +198 -0
  24. package/bundle/toolchain/skills/portal-delete/SKILL.md +56 -31
  25. package/bundle/toolchain/skills/portal-delete/SKILL.md.tmpl +194 -0
  26. package/bundle/toolchain/skills/portal-deploy/SKILL.md +59 -46
  27. package/bundle/toolchain/skills/portal-deploy/SKILL.md.tmpl +452 -0
  28. package/bundle/toolchain/skills/portal-dev/SKILL.md +62 -41
  29. package/bundle/toolchain/skills/portal-dev/SKILL.md.tmpl +228 -0
  30. package/bundle/toolchain/skills/portal-list/SKILL.md +56 -32
  31. package/bundle/toolchain/skills/portal-list/SKILL.md.tmpl +181 -0
  32. package/bundle/toolchain/skills/portal-onboard/SKILL.md +310 -161
  33. package/bundle/toolchain/skills/portal-onboard/SKILL.md.tmpl +317 -0
  34. package/bundle/toolchain/skills/portal-preview/SKILL.md +58 -34
  35. package/bundle/toolchain/skills/portal-preview/SKILL.md.tmpl +171 -0
  36. package/bundle/toolchain/skills/portal-setup/SKILL.md +73 -56
  37. package/bundle/toolchain/skills/portal-setup/SKILL.md.tmpl +222 -0
  38. package/bundle/toolchain/skills/portal-share/SKILL.md +62 -37
  39. package/bundle/toolchain/skills/portal-share/SKILL.md.tmpl +162 -0
  40. package/bundle/toolchain/skills/portal-status/SKILL.md +57 -33
  41. package/bundle/toolchain/skills/portal-status/SKILL.md.tmpl +196 -0
  42. package/bundle/toolchain/skills/portal-update/SKILL.md +58 -41
  43. package/bundle/toolchain/skills/portal-update/SKILL.md.tmpl +269 -0
  44. package/bundle/toolchain/skills/portal-upgrade/SKILL.md +56 -31
  45. package/bundle/toolchain/skills/portal-upgrade/SKILL.md.tmpl +164 -0
  46. package/bundle/toolchain/skills/portal-verify/SKILL.md +72 -14
  47. package/bundle/toolchain/skills/portal-verify/SKILL.md.tmpl +224 -0
  48. package/bundle/toolchain/skills/shared/preamble.md +30 -126
  49. package/bundle/toolchain/skills/shared/runtime-principles.md +25 -0
  50. package/dist/index.js +51 -9
  51. package/package.json +5 -2
@@ -14,38 +14,42 @@ hooks:
14
14
 
15
15
  ## Preamble (run first)
16
16
 
17
- This skill's preamble is different from other skills it does NOT require config.json to exist, because this skill creates it.
17
+ This skill's preamble is tolerant of first-run state because setup may create the config.
18
18
 
19
19
  ```bash
20
- # --- Portal Setup Preamble ---
21
- CONFIG="$HOME/.showpane/config.json"
20
+ SHOWPANE_HOME="$HOME/.showpane"
21
+ SHOWPANE_BIN="$SHOWPANE_HOME/bin"
22
+ CONFIG="$SHOWPANE_HOME/config.json"
23
+ APP_PATH=""
24
+ DEPLOY_MODE="local"
25
+ ORG_SLUG=""
22
26
  EXISTING_CONFIG=false
27
+
23
28
  if [ -f "$CONFIG" ]; then
24
29
  EXISTING_CONFIG=true
25
30
  APP_PATH=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('app_path',''))" 2>/dev/null || true)
26
- DEPLOY_MODE=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('deploy_mode',''))" 2>/dev/null || true)
31
+ DEPLOY_MODE=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('deploy_mode','local'))" 2>/dev/null || echo "local")
27
32
  ORG_SLUG=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('orgSlug','') or d.get('org_slug',''))" 2>/dev/null || true)
28
- echo "EXISTING_CONFIG: true"
29
- echo "APP_PATH: $APP_PATH"
30
- echo "DEPLOY_MODE: $DEPLOY_MODE"
31
- echo "ORG_SLUG: $ORG_SLUG"
32
- else
33
- echo "EXISTING_CONFIG: false"
34
- echo "No config found. Starting fresh setup."
35
33
  fi
36
34
 
37
- SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$HOME/.showpane/current}"
38
- SKILL_VERSION=$(head -1 "$SKILL_DIR/skills/VERSION" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
39
- echo "SHOWPANE: v$SKILL_VERSION | SETUP MODE"
40
-
41
- # Predictive next-skill suggestion
42
- if [ -f "$HOME/.showpane/timeline.jsonl" ]; then
43
- _RECENT=$(grep '"event":"completed"' "$HOME/.showpane/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '\n' ',' | sed 's/,$//' || true)
35
+ SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$SHOWPANE_HOME/current}"
36
+ SKILL_VERSION=$(cat "$SKILL_DIR/VERSION" 2>/dev/null || echo "unknown")
37
+ _UPD=$("$SHOWPANE_BIN/showpane-update-check" 2>/dev/null || true)
38
+ [ -n "$_UPD" ] && echo "$_UPD" || true
39
+ mkdir -p "$SHOWPANE_HOME/sessions" "$SHOWPANE_HOME/analytics" "$SHOWPANE_HOME/checkpoints"
40
+ touch "$SHOWPANE_HOME/sessions/$PPID"
41
+ find "$SHOWPANE_HOME/sessions" -mmin +120 -type f -delete 2>/dev/null || true
42
+ TEL=$("$SHOWPANE_BIN/showpane-config" get telemetry 2>/dev/null || echo "anonymous")
43
+ TEL_PROMPTED=$([ -f "$SHOWPANE_HOME/.telemetry-prompted" ] && echo "yes" || echo "no")
44
+ _TEL_START=$(date +%s)
45
+ _SESSION_ID="${PPID:-0}-$(date +%s)"
46
+
47
+ LEARN_FILE="$SHOWPANE_HOME/learnings.jsonl"
48
+ if [ -f "$SHOWPANE_HOME/timeline.jsonl" ]; then
49
+ _RECENT=$(grep '"event":"completed"' "$SHOWPANE_HOME/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '
50
+ ' ',' | sed 's/,$//' || true)
44
51
  [ -n "$_RECENT" ] && echo "RECENT_SKILLS: $_RECENT"
45
52
  fi
46
-
47
- # Search relevant learnings
48
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
49
53
  if [ -f "$LEARN_FILE" ]; then
50
54
  _LEARN_COUNT=$(wc -l < "$LEARN_FILE" 2>/dev/null | tr -d ' ')
51
55
  echo "LEARNINGS: $_LEARN_COUNT entries"
@@ -55,24 +59,46 @@ if [ -f "$LEARN_FILE" ]; then
55
59
  fi
56
60
  fi
57
61
 
58
- # Track skill execution
59
- SHOWPANE_TIMELINE="$HOME/.showpane/timeline.jsonl"
62
+ SHOWPANE_TIMELINE="$SHOWPANE_HOME/timeline.jsonl"
60
63
  mkdir -p "$(dirname "$SHOWPANE_TIMELINE")"
61
64
  echo '{"skill":"portal-setup","event":"started","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$SHOWPANE_TIMELINE" 2>/dev/null
62
- # --- End Preamble ---
65
+ echo "SHOWPANE: v$SKILL_VERSION | SETUP MODE"
66
+ echo "EXISTING_CONFIG: $EXISTING_CONFIG"
67
+ echo "APP_PATH: ${APP_PATH:-missing}"
68
+ echo "DEPLOY_MODE: $DEPLOY_MODE"
69
+ echo "ORG_SLUG: ${ORG_SLUG:-missing}"
70
+ echo "TELEMETRY: $TEL"
71
+ echo "TEL_PROMPTED: $TEL_PROMPTED"
72
+ ```
73
+
74
+ If output shows `JUST_UPGRADED <from> <to>`, tell the user Showpane was just upgraded and continue.
75
+
76
+ If output shows `UPGRADE_AVAILABLE <old> <new>`, tell the user a newer Showpane toolchain is available and recommend `/portal upgrade`.
77
+
78
+ If `TEL_PROMPTED` is `no`, ask the user once about telemetry and then record the decision:
79
+
80
+ - anonymous — local analytics plus anonymous remote sync, with no stable device id
81
+ - off — local analytics only, no remote sync
82
+
83
+ After the user chooses, run:
84
+ ```bash
85
+ "$SHOWPANE_BIN/showpane-config" set telemetry <anonymous|off>
86
+ touch "$SHOWPANE_HOME/.telemetry-prompted"
63
87
  ```
64
88
 
65
- If RECENT_SKILLS is shown, suggest the likely next skill:
89
+ If `RECENT_SKILLS` is shown, suggest the likely next skill:
66
90
  - After portal-create → suggest /portal-preview
67
- - After portal-preview → suggest /portal-deploy or /portal-share
91
+ - After portal-preview → suggest /portal-deploy
68
92
  - After portal-deploy → suggest /portal-status or /portal-verify
69
- - After portal-setup → suggest /portal-create
70
- - After portal-credentials → suggest /portal-share
71
- - After portal-update → suggest /portal-deploy
93
+ - After portal-setup → suggest /portal-onboard for a first run, or /portal-create for the fast path
94
+ - After portal-credentials → suggest /portal-deploy before external sharing
95
+ - After portal-update → suggest /portal-preview or /portal-deploy
72
96
 
73
- If RECENT_LEARNINGS is shown, review them before proceeding. Past learnings may contain
74
- relevant warnings or tips for this operation. Apply them where relevant but don't
75
- mention them unless they directly affect the current task.
97
+ If `RECENT_LEARNINGS` is shown, review them before proceeding. Apply them where relevant but do not mention them unless they materially affect the current task.
98
+
99
+ Read `skills/shared/runtime-principles.md` once near the start of the skill and apply the relevant product defaults.
100
+
101
+ If `skills/shared/platform-constraints.md` exists, read it once near the start of the skill and apply only the relevant limits.
76
102
 
77
103
  ## Steps
78
104
 
@@ -203,18 +229,17 @@ Update the Organization record with `primaryColor` set to the validated hex valu
203
229
 
204
230
  If the user says "skip" or "default", use `#1a1a1a`. Brand color can always be changed later by running `/portal setup` again.
205
231
 
206
- ### Step 8: Telemetry opt-in
232
+ ### Step 8: Telemetry reminder
207
233
 
208
- Ask the user about anonymous usage telemetry:
234
+ Do not re-run the global telemetry interview here.
209
235
 
210
- > "Help Showpane improve! Share anonymous usage data (which skills you use, how long they take). No code, file paths, or portal content is ever sent."
236
+ If the shared runtime preamble already set telemetry, keep that value. If it has
237
+ not been set yet for some reason, default to:
211
238
 
212
- Options:
213
- - **community** — anonymous usage stats with a stable device ID for deduplication
214
- - **anonymous** — anonymous usage stats with no device ID
215
- - **off** — no telemetry (default)
239
+ - **anonymous** — local analytics plus anonymous remote sync, no stable device ID
240
+ - **off** — local analytics only, no remote sync
216
241
 
217
- Store the choice in config.
242
+ If you must set it manually, write the chosen value into config.
218
243
 
219
244
  ### Step 9: Save configuration
220
245
 
@@ -232,7 +257,7 @@ cat > "$HOME/.showpane/config.json" << 'CONFIGEOF'
232
257
  "app_path": "<resolved_absolute_path>",
233
258
  "deploy_mode": "local",
234
259
  "orgSlug": "<org_slug>",
235
- "telemetry": "<community|anonymous|off>"
260
+ "telemetry": "<anonymous|off>"
236
261
  }
237
262
  CONFIGEOF
238
263
  chmod 600 "$HOME/.showpane/config.json"
@@ -251,11 +276,11 @@ Showpane setup complete!
251
276
  Deploy mode: local
252
277
  Organization: Acme Consulting (acme-consulting)
253
278
  Brand color: #2563eb
254
- Telemetry: off
279
+ Telemetry: anonymous
255
280
 
256
281
  Next steps:
257
- 1. Start the dev server: /portal dev
258
- 2. Create your first portal: /portal create <slug>
282
+ 1. Recommended first run: /portal onboard
283
+ 2. Fast repeat-user path: /portal create <slug>
259
284
  3. View the example portal: open http://localhost:3000/client/example
260
285
  ```
261
286
 
@@ -282,19 +307,11 @@ Never silently continue past a failure. Each step depends on the previous step s
282
307
 
283
308
  ## Completion
284
309
 
285
- As a final step, log skill completion:
310
+ As a final step, log skill completion and telemetry:
286
311
 
287
312
  ```bash
288
313
  echo '{"skill":"portal-setup","event":"completed","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$HOME/.showpane/timeline.jsonl" 2>/dev/null
314
+ _TEL_END=$(date +%s)
315
+ _TEL_DUR=$(( _TEL_END - ${_TEL_START:-_TEL_END} ))
316
+ "$HOME/.showpane/bin/showpane-telemetry-log" --skill "portal-setup" --duration "$_TEL_DUR" --outcome success --session-id "${_SESSION_ID:-}" 2>/dev/null || true
289
317
  ```
290
-
291
- ## Conventions
292
-
293
- - Never store DATABASE_URL or AUTH_SECRET in config.json — these live in the app's `.env` file
294
- - Config file permissions must be 600 (owner read/write only)
295
- - The orgSlug in config.json determines which Organization record is used by all other skills
296
- - All user-facing output should be concise and scannable — use indented key-value pairs, not paragraphs
297
- - If any step fails, provide a clear error message and suggest how to fix it, but do not silently continue
298
- - The setup wizard is interactive — ask one question at a time, don't dump all questions at once
299
- - When reconfiguring, show current values as defaults so the user can press enter to keep them
300
- - The setup wizard should complete in under 5 minutes for a user with Node.js, internet access, and a generated Showpane project
@@ -0,0 +1,222 @@
1
+ ---
2
+ name: portal-setup
3
+ description: |
4
+ Interactive setup wizard for Showpane. Creates config, installs deps, applies the local SQLite schema, and creates the organization.
5
+ Trigger phrases: "portal setup", "configure showpane", "set up showpane", "initialize showpane". (showpane)
6
+ allowed-tools: [Bash, Read, Write, Edit, Glob, Grep]
7
+ hooks:
8
+ PreToolUse:
9
+ - matcher: "Bash"
10
+ hooks:
11
+ - type: command
12
+ command: "bash ${CLAUDE_SKILL_DIR}/../showpane-shared/bin/check-portal-guard.sh"
13
+ ---
14
+
15
+ {{PREAMBLE}}
16
+
17
+ ## Steps
18
+
19
+ ### Step 1: Check for existing configuration
20
+
21
+ If the preamble output shows `EXISTING_CONFIG: true`, inform the user that Showpane is already configured and show the current settings. Ask if they want to reconfigure. If they say no, exit gracefully. If they say yes, continue with the setup — existing values become defaults the user can accept or change.
22
+
23
+ ### Step 2: Detect or ask for app_path
24
+
25
+ Try to find the Showpane app automatically by checking these locations in order:
26
+
27
+ 1. Current working directory — look for `package.json` containing `"name"` with "showpane" in it
28
+ 2. Parent directory — check `../app/` for the same
29
+ 3. Common locations: `~/git/showpane/`, `~/showpane/`
30
+ 4. The `SHOWPANE_APP_PATH` environment variable
31
+
32
+ Run the detection:
33
+
34
+ ```bash
35
+ for candidate in "$(pwd)" "$(pwd)/../app" "$HOME/git/showpane/app" "$HOME/showpane/app"; do
36
+ if [ -f "$candidate/package.json" ] && { [ -f "$candidate/prisma/schema.local.prisma" ] || [ -f "$candidate/prisma.config.ts" ]; }; then
37
+ echo "FOUND: $(cd "$candidate" && pwd)"
38
+ break
39
+ fi
40
+ done
41
+ ```
42
+
43
+ If found, confirm with the user: "Found Showpane app at /path/to/app. Use this? (Y/n)"
44
+
45
+ If not found, ask the user to provide the path. Validate that the path exists and contains `package.json` plus either `prisma/schema.local.prisma` or `prisma.config.ts`. If those markers are missing, the path is not a valid Showpane app directory — explain which file is missing and ask again.
46
+
47
+ Resolve the path to an absolute path (no `~` or relative components) before storing it. Use `cd "$path" && pwd` to resolve.
48
+
49
+ Store the resolved absolute path as `APP_PATH`.
50
+
51
+ #### Packaged Installer Mode
52
+
53
+ When the user is inside a freshly generated Showpane project, the setup should:
54
+ - Prefer the current working directory as `APP_PATH`
55
+ - Skip any suggestion to clone the upstream Showpane repository
56
+ - Auto-detect SQLite from DATABASE_URL (if it starts with "file:" it's SQLite)
57
+ - Still ask for org name, contact details, and website URL
58
+ - Be concise — the user just ran `npx showpane` and wants to get going fast
59
+
60
+ ### Step 3: Set the workspace mode
61
+
62
+ Use `local` as the setup mode.
63
+
64
+ Store `DEPLOY_MODE=local` in the config written later in this flow.
65
+
66
+ ### Step 4: Install dependencies
67
+
68
+ Check if `$APP_PATH/node_modules` exists. If not, run:
69
+
70
+ ```bash
71
+ cd "$APP_PATH" && npm install
72
+ ```
73
+
74
+ If node_modules exists but `.prisma` client is missing, run:
75
+
76
+ ```bash
77
+ cd "$APP_PATH" && npm run prisma:generate
78
+ ```
79
+
80
+ Wait for installation to complete before proceeding.
81
+
82
+ ### Step 5: Apply the local database schema
83
+
84
+ Source the app's `.env` file to get `DATABASE_URL`:
85
+
86
+ ```bash
87
+ if [ -f "$APP_PATH/.env" ]; then set -a && source "$APP_PATH/.env" && set +a; fi
88
+ ```
89
+
90
+ The supported setup path is SQLite. Apply the local schema:
91
+
92
+ ```bash
93
+ cd "$APP_PATH" && npm run prisma:db-push
94
+ ```
95
+
96
+ If `DATABASE_URL` is not set in `.env`, inform the user they need to configure it. Provide guidance:
97
+ - For local development: `file:./dev.db`
98
+
99
+ If `DATABASE_URL` is set to anything other than a `file:` URL, explain that the supported setup flow is SQLite-first and suggest resetting `.env` back to `file:./dev.db`.
100
+
101
+ Do NOT proceed until the local schema is applied successfully.
102
+
103
+ ### Step 6: Create or find Organization record
104
+
105
+ Ask the user for their organization details one at a time. Do not present all questions at once — guide them through the process conversationally.
106
+
107
+ 1. **Organization name** (required) — e.g., "Acme Consulting". This is the name that appears in portal headers alongside the client name.
108
+ 2. **Contact name** (required) — the person who appears on portal footers as the point of contact, e.g., "Jane Smith". This is typically the account manager or sales rep.
109
+ 3. **Contact email** (required) — e.g., "jane@acme.com". Displayed in the portal footer as a mailto link.
110
+ 4. **Contact title** (optional, default: "Account Manager") — e.g., "Director", "Partner", "Client Success Lead". Shown next to the contact name in the portal footer.
111
+ 5. **Contact phone** (optional) — e.g., "+44 7700 900000". If provided, displayed alongside email in the portal footer.
112
+ 6. **Company website URL** (optional) — e.g., "acme.com". Used to auto-fetch the company logo via Clearbit.
113
+ - If provided, fetch logo URL: `https://logo.clearbit.com/{domain}` and store in `Organization.logoUrl`
114
+ - Also store the URL in `Organization.websiteUrl`
115
+ 7. **Contact avatar**: Auto-populated from the contact email via Gravatar. No need to ask — just use `getAvatarUrl(email, contactName)` from `app/src/lib/branding.ts` and store in `Organization.contactAvatar`
116
+
117
+ Generate an org slug from the organization name: lowercase, replace spaces with hyphens, strip non-alphanumeric characters except hyphens, remove consecutive hyphens. For example, "Acme Consulting Ltd." becomes `acme-consulting-ltd`. Confirm the generated slug with the user and allow them to override it.
118
+
119
+ Create the organization record in the database using the app's Prisma client. The Organization model stores:
120
+ - `name`, `slug`, `contactName`, `contactEmail`, `contactTitle`, `contactPhone`
121
+
122
+ If an Organization with that slug already exists in the database, present two options:
123
+ 1. Use the existing organization (show its current details so the user can verify)
124
+ 2. Create a new organization with a different slug
125
+
126
+ If the user chooses to use the existing org, skip creation and proceed with that org's slug. This is common when reconfiguring or when multiple people set up the same Showpane instance.
127
+
128
+ ### Step 7: Theme configuration
129
+
130
+ Ask the user for their primary brand color as a hex value. This color is used for active tab indicators, bullet point accents, and interactive elements throughout the portal. Provide suggestions:
131
+
132
+ - Default: `#1a1a1a` (near-black, professional — works well for most brands)
133
+ - Common choices: `#2563eb` (blue), `#059669` (green), `#dc2626` (red), `#7c3aed` (purple)
134
+ - Tip: if the user has a brand guidelines document or website, suggest pulling the primary color from there
135
+
136
+ Validate the input is a valid hex color:
137
+ - Accept with or without `#` prefix (add `#` if missing)
138
+ - Accept 3-digit shorthand (`#abc` expands to `#aabbcc`)
139
+ - Accept 6-digit full form (`#2563eb`)
140
+ - Reject anything else with a clear message: "Please enter a valid hex color like #2563eb"
141
+
142
+ Update the Organization record with `primaryColor` set to the validated hex value. The portal app reads this value and applies it via CSS custom properties (the `--primary` variable in the Tailwind theme).
143
+
144
+ If the user says "skip" or "default", use `#1a1a1a`. Brand color can always be changed later by running `/portal setup` again.
145
+
146
+ ### Step 8: Telemetry reminder
147
+
148
+ Do not re-run the global telemetry interview here.
149
+
150
+ If the shared runtime preamble already set telemetry, keep that value. If it has
151
+ not been set yet for some reason, default to:
152
+
153
+ - **anonymous** — local analytics plus anonymous remote sync, no stable device ID
154
+ - **off** — local analytics only, no remote sync
155
+
156
+ If you must set it manually, write the chosen value into config.
157
+
158
+ ### Step 9: Save configuration
159
+
160
+ Create the `~/.showpane/` directory if it doesn't exist:
161
+
162
+ ```bash
163
+ mkdir -p "$HOME/.showpane"
164
+ ```
165
+
166
+ Write the config file:
167
+
168
+ ```bash
169
+ cat > "$HOME/.showpane/config.json" << 'CONFIGEOF'
170
+ {
171
+ "app_path": "<resolved_absolute_path>",
172
+ "deploy_mode": "local",
173
+ "orgSlug": "<org_slug>",
174
+ "telemetry": "<anonymous|off>"
175
+ }
176
+ CONFIGEOF
177
+ chmod 600 "$HOME/.showpane/config.json"
178
+ ```
179
+
180
+ Replace the placeholder values with the actual values collected. Use `chmod 600` so only the owner can read/write the config (it may contain sensitive paths).
181
+
182
+ ### Step 10: Print success summary
183
+
184
+ Display a clear summary:
185
+
186
+ ```
187
+ Showpane setup complete!
188
+
189
+ App path: /path/to/showpane-project
190
+ Deploy mode: local
191
+ Organization: Acme Consulting (acme-consulting)
192
+ Brand color: #2563eb
193
+ Telemetry: anonymous
194
+
195
+ Next steps:
196
+ 1. Recommended first run: /portal onboard
197
+ 2. Fast repeat-user path: /portal create <slug>
198
+ 3. View the example portal: open http://localhost:3000/client/example
199
+ ```
200
+
201
+ ### Step 11: Record learning (optional)
202
+
203
+ If this is the first setup, create an initial learning entry:
204
+
205
+ ```bash
206
+ mkdir -p "$HOME/.showpane"
207
+ echo '{"skill":"portal-setup","key":"initial-setup","insight":"Setup completed. Deploy mode: <mode>. Org: <name>.","confidence":10,"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$HOME/.showpane/learnings.jsonl"
208
+ ```
209
+
210
+ ## Error Handling
211
+
212
+ Each step can fail independently. Handle failures gracefully:
213
+
214
+ - **App path not found**: Ask the user to run `npx showpane` first or point setup at an existing generated Showpane project
215
+ - **npm install fails**: Check Node.js version (requires 18+), check internet connectivity, suggest clearing `node_modules` and retrying
216
+ - **Prisma db push fails**: Check that DATABASE_URL is set to `file:./dev.db` (or another valid SQLite `file:` URL) in `.env`
217
+ - **Organization creation fails**: Check database connectivity. If the Prisma client throws a connection error, verify DATABASE_URL in `.env`
218
+ - **Config write fails**: Check that `$HOME/.showpane/` is writable. On some systems, home directory permissions may block directory creation
219
+
220
+ Never silently continue past a failure. Each step depends on the previous step succeeding.
221
+
222
+ {{COMPLETION}}
@@ -14,14 +14,17 @@ If the user asks for broader share-link capabilities than Showpane supports, rea
14
14
  Before doing anything else, execute this block in a Bash tool call:
15
15
 
16
16
  ```bash
17
- CONFIG="$HOME/.showpane/config.json"
17
+ SHOWPANE_HOME="$HOME/.showpane"
18
+ SHOWPANE_BIN="$SHOWPANE_HOME/bin"
19
+ CONFIG="$SHOWPANE_HOME/config.json"
18
20
  if [ ! -f "$CONFIG" ]; then
19
21
  echo "Showpane not configured. Run /portal setup first."
20
22
  exit 1
21
23
  fi
22
- APP_PATH=$(cat "$CONFIG" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('app_path',''))" 2>/dev/null)
23
- DEPLOY_MODE=$(cat "$CONFIG" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('deploy_mode','local'))" 2>/dev/null)
24
- ORG_SLUG=$(cat "$CONFIG" | python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('orgSlug','') or d.get('org_slug',''))" 2>/dev/null)
24
+
25
+ APP_PATH=$("$SHOWPANE_BIN/showpane-config" get app_path 2>/dev/null || python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('app_path',''))" 2>/dev/null)
26
+ DEPLOY_MODE=$("$SHOWPANE_BIN/showpane-config" get deploy_mode 2>/dev/null || python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('deploy_mode','local'))" 2>/dev/null || echo "local")
27
+ ORG_SLUG=$("$SHOWPANE_BIN/showpane-config" get orgSlug 2>/dev/null || python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('orgSlug','') or d.get('org_slug',''))" 2>/dev/null || true)
25
28
  APP_PATH="${SHOWPANE_APP_PATH:-$APP_PATH}"
26
29
  if [ -f "$APP_PATH/.env" ]; then set -a && source "$APP_PATH/.env" && set +a; fi
27
30
  DATABASE_URL="${DATABASE_URL:-}"
@@ -29,20 +32,26 @@ if [ ! -d "$APP_PATH/node_modules/.prisma" ]; then
29
32
  echo "App dependencies not installed. Run: cd $APP_PATH && npm install"
30
33
  exit 1
31
34
  fi
32
- SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$HOME/.showpane/current}"
35
+
36
+ SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$SHOWPANE_HOME/current}"
33
37
  SKILL_VERSION=$(cat "$SKILL_DIR/VERSION" 2>/dev/null || echo "unknown")
34
- echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
35
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
38
+ _UPD=$("$SHOWPANE_BIN/showpane-update-check" 2>/dev/null || true)
39
+ [ -n "$_UPD" ] && echo "$_UPD" || true
40
+ mkdir -p "$SHOWPANE_HOME/sessions" "$SHOWPANE_HOME/analytics" "$SHOWPANE_HOME/checkpoints"
41
+ touch "$SHOWPANE_HOME/sessions/$PPID"
42
+ find "$SHOWPANE_HOME/sessions" -mmin +120 -type f -delete 2>/dev/null || true
43
+ TEL=$("$SHOWPANE_BIN/showpane-config" get telemetry 2>/dev/null || echo "anonymous")
44
+ TEL_PROMPTED=$([ -f "$SHOWPANE_HOME/.telemetry-prompted" ] && echo "yes" || echo "no")
45
+ _TEL_START=$(date +%s)
46
+ _SESSION_ID="${PPID:-0}-$(date +%s)"
47
+
48
+ LEARN_FILE="$SHOWPANE_HOME/learnings.jsonl"
36
49
  [ -f "$LEARN_FILE" ] && echo "LEARNINGS: $(wc -l < "$LEARN_FILE" | tr -d ' ') loaded" || echo "LEARNINGS: 0"
37
-
38
- # Predictive next-skill suggestion
39
- if [ -f "$HOME/.showpane/timeline.jsonl" ]; then
40
- _RECENT=$(grep '"event":"completed"' "$HOME/.showpane/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '\n' ',' | sed 's/,$//' || true)
50
+ if [ -f "$SHOWPANE_HOME/timeline.jsonl" ]; then
51
+ _RECENT=$(grep '"event":"completed"' "$SHOWPANE_HOME/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '
52
+ ' ',' | sed 's/,$//' || true)
41
53
  [ -n "$_RECENT" ] && echo "RECENT_SKILLS: $_RECENT"
42
54
  fi
43
-
44
- # Search relevant learnings
45
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
46
55
  if [ -f "$LEARN_FILE" ]; then
47
56
  _LEARN_COUNT=$(wc -l < "$LEARN_FILE" 2>/dev/null | tr -d ' ')
48
57
  echo "LEARNINGS: $_LEARN_COUNT entries"
@@ -52,27 +61,46 @@ if [ -f "$LEARN_FILE" ]; then
52
61
  fi
53
62
  fi
54
63
 
55
- # Track skill execution
56
- SHOWPANE_TIMELINE="$HOME/.showpane/timeline.jsonl"
64
+ SHOWPANE_TIMELINE="$SHOWPANE_HOME/timeline.jsonl"
57
65
  mkdir -p "$(dirname "$SHOWPANE_TIMELINE")"
58
66
  echo '{"skill":"portal-share","event":"started","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$SHOWPANE_TIMELINE" 2>/dev/null
67
+ echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
68
+ echo "TELEMETRY: $TEL"
69
+ echo "TEL_PROMPTED: $TEL_PROMPTED"
59
70
  ```
60
71
 
61
- If RECENT_SKILLS is shown, suggest the likely next skill:
72
+ If output shows `JUST_UPGRADED <from> <to>`, tell the user Showpane was just upgraded and continue.
73
+
74
+ If output shows `UPGRADE_AVAILABLE <old> <new>`, tell the user a newer Showpane toolchain is available and recommend `/portal upgrade`.
75
+
76
+ If `TEL_PROMPTED` is `no`, ask the user once about telemetry and then record the decision:
77
+
78
+ - anonymous — local analytics plus anonymous remote sync, with no stable device id
79
+ - off — local analytics only, no remote sync
80
+
81
+ After the user chooses, run:
82
+ ```bash
83
+ "$SHOWPANE_BIN/showpane-config" set telemetry <anonymous|off>
84
+ touch "$SHOWPANE_HOME/.telemetry-prompted"
85
+ ```
86
+
87
+ If `RECENT_SKILLS` is shown, suggest the likely next skill:
62
88
  - After portal-create → suggest /portal-preview
63
- - After portal-preview → suggest /portal-deploy or /portal-share
89
+ - After portal-preview → suggest /portal-deploy
64
90
  - After portal-deploy → suggest /portal-status or /portal-verify
65
- - After portal-setup → suggest /portal-create
66
- - After portal-credentials → suggest /portal-share
67
- - After portal-update → suggest /portal-deploy
91
+ - After portal-setup → suggest /portal-onboard for a first run, or /portal-create for the fast path
92
+ - After portal-credentials → suggest /portal-deploy before external sharing
93
+ - After portal-update → suggest /portal-preview or /portal-deploy
68
94
 
69
- If RECENT_LEARNINGS is shown, review them before proceeding. Past learnings may contain
70
- relevant warnings or tips for this operation. Apply them where relevant but don't
71
- mention them unless they directly affect the current task.
95
+ If `RECENT_LEARNINGS` is shown, review them before proceeding. Apply them where relevant but do not mention them unless they materially affect the current task.
96
+
97
+ Read `skills/shared/runtime-principles.md` once near the start of the skill and apply the relevant product defaults.
98
+
99
+ If `skills/shared/platform-constraints.md` exists, read it once near the start of the skill and apply only the relevant limits.
72
100
 
73
101
  ## Overview
74
102
 
75
- This skill generates a signed share link that allows a client to access their portal without entering a username and password. The link is useful for initial onboarding, sending to a client after a meeting, or providing access to someone who does not have the portal credentials.
103
+ This skill generates a signed share link that allows someone to access a hosted portal without entering a username and password. Treat it as a hosted convenience after publish, not as the default answer to first-run sharing.
76
104
 
77
105
  Share links use HMAC-SHA256 signed tokens. The token encodes the portal slug, a share scope, and the current credential version. Share links do not expire automatically. If credentials are rotated after the link is generated, the link becomes invalid automatically -- this is by design.
78
106
 
@@ -92,7 +120,7 @@ Run the share link generator:
92
120
  cd $APP_PATH && NODE_PATH="$APP_PATH/node_modules" npx tsx --tsconfig $APP_PATH/tsconfig.json $SKILL_DIR/bin/generate-share-link.ts --slug <slug> --org-id <org_id>
93
121
  ```
94
122
 
95
- The script reads AUTH_SECRET from the app's `.env` file (sourced by the preamble) and uses the `signShareToken` function from the app's `client-auth.ts` module. It constructs a full URL using NEXT_PUBLIC_APP_URL (also from `.env`).
123
+ The script reads AUTH_SECRET from the app's `.env` file (sourced by the preamble) and uses the `signShareToken` function from the app's `client-auth.ts` module. It constructs a full URL using NEXT_PUBLIC_APP_URL (also from `.env`), so for external sharing the recommended path is: deploy first, then generate the share link.
96
124
 
97
125
  Expected success response:
98
126
 
@@ -127,7 +155,7 @@ Present the link in a clear, copy-friendly ASCII box:
127
155
 
128
156
  After displaying the link, add this note:
129
157
 
130
- "Send this link to the client. They can access the portal without logging in. The link stays valid until the portal credentials are rotated or the portal is deactivated."
158
+ "This link is meant for the hosted portal. The link stays valid until the portal credentials are rotated or the portal is deactivated."
131
159
 
132
160
  If the user has previously generated share links (check learnings for patterns), you can skip the explanation and just show the link.
133
161
 
@@ -147,7 +175,7 @@ Do NOT log the share URL to learnings or telemetry. The URL contains the signed
147
175
  - Always display the full URL, never truncate or abbreviate it. The user needs to copy-paste it.
148
176
  - Make it clear that the link does not expire automatically and is revoked by credential rotation or portal deactivation.
149
177
  - Use double-line box drawing (`═`) for the border around the link.
150
- - If NEXT_PUBLIC_APP_URL is `http://localhost:3000`, warn the user: "This is a local development URL. The client won't be able to access it remotely. Deploy the app with /portal deploy, then generate the share link again."
178
+ - If NEXT_PUBLIC_APP_URL is `http://localhost:3000`, warn the user immediately: "This is a local development URL. Do not send this to a client. Publish with /portal deploy first, then generate the share link again."
151
179
 
152
180
  ## Error Handling
153
181
 
@@ -186,11 +214,11 @@ The signature is computed using AUTH_SECRET from the app's `.env`. If AUTH_SECRE
186
214
 
187
215
  Common patterns for using share links in practice:
188
216
 
189
- **After a meeting**: Create the portal with `/portal create`, set up credentials with `/portal credentials`, then immediately generate a share link. Send the link in the follow-up email. The client can access the portal instantly without needing to remember a password.
217
+ **After publish**: Deploy the portal with `/portal deploy`, then generate a share link if you want a direct hosted access URL instead of asking the client to log in with credentials.
190
218
 
191
219
  **For quick reviews**: If a colleague or stakeholder needs to see the portal but should not have permanent credentials, a share link is ideal. It can be reused and does not create a full operator login.
192
220
 
193
- **Re-sharing after content update**: If you update portal content with `/portal update` and want the client to see the changes, generate a fresh share link and send it. This is often easier than asking them to log in again.
221
+ **Re-sharing after content update**: If you update portal content with `/portal update`, publish the latest version if needed, then generate a fresh share link and send it.
194
222
 
195
223
  ## Learnings Integration
196
224
 
@@ -220,14 +248,11 @@ If the user wants to revoke all outstanding share links immediately, the mechani
220
248
 
221
249
  ## Completion
222
250
 
223
- As a final step, log skill completion:
251
+ As a final step, log skill completion and telemetry:
224
252
 
225
253
  ```bash
226
254
  echo '{"skill":"portal-share","event":"completed","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$HOME/.showpane/timeline.jsonl" 2>/dev/null
255
+ _TEL_END=$(date +%s)
256
+ _TEL_DUR=$(( _TEL_END - ${_TEL_START:-_TEL_END} ))
257
+ "$HOME/.showpane/bin/showpane-telemetry-log" --skill "portal-share" --duration "$_TEL_DUR" --outcome success --session-id "${_SESSION_ID:-}" 2>/dev/null || true
227
258
  ```
228
-
229
- ## Related Skills
230
-
231
- - `/portal credentials` -- set up or rotate credentials (required before sharing)
232
- - `/portal preview` -- open the portal locally to verify content before sharing
233
- - `/portal analytics` -- check engagement after sharing to see if the client accessed the portal