showpane 0.4.13 → 0.4.15

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 (55) hide show
  1. package/README.md +2 -1
  2. package/bundle/meta/scaffold-manifest.json +10 -10
  3. package/bundle/scaffold/VERSION +1 -1
  4. package/bundle/scaffold/prisma/seed.ts +40 -35
  5. package/bundle/scaffold/src/__tests__/portal-contracts.test.ts +7 -0
  6. package/bundle/scaffold/src/app/(portal)/client/example/example-client.tsx +1 -2
  7. package/bundle/scaffold/src/app/(portal)/client/page.tsx +5 -4
  8. package/bundle/scaffold/src/app/page.tsx +43 -6
  9. package/bundle/scaffold/src/components/portal-shell.tsx +23 -0
  10. package/bundle/scaffold/src/lib/portal-contracts.ts +33 -0
  11. package/bundle/toolchain/CLI_VERSION +1 -0
  12. package/bundle/toolchain/TELEMETRY_CONFIG.json +4 -0
  13. package/bundle/toolchain/VERSION +1 -1
  14. package/bundle/toolchain/bin/ensure-cloud-project-link.ts +34 -1
  15. package/bundle/toolchain/bin/showpane-config +108 -29
  16. package/bundle/toolchain/bin/showpane-telemetry-log +84 -0
  17. package/bundle/toolchain/bin/showpane-telemetry-sync +212 -0
  18. package/bundle/toolchain/bin/showpane-update-check +130 -0
  19. package/bundle/toolchain/skills/SKILL.md.tmpl +13 -0
  20. package/bundle/toolchain/skills/VERSION +1 -1
  21. package/bundle/toolchain/skills/portal-analytics/SKILL.md +60 -38
  22. package/bundle/toolchain/skills/portal-analytics/SKILL.md.tmpl +192 -0
  23. package/bundle/toolchain/skills/portal-create/SKILL.md +65 -67
  24. package/bundle/toolchain/skills/portal-create/SKILL.md.tmpl +264 -0
  25. package/bundle/toolchain/skills/portal-credentials/SKILL.md +66 -49
  26. package/bundle/toolchain/skills/portal-credentials/SKILL.md.tmpl +198 -0
  27. package/bundle/toolchain/skills/portal-delete/SKILL.md +63 -41
  28. package/bundle/toolchain/skills/portal-delete/SKILL.md.tmpl +194 -0
  29. package/bundle/toolchain/skills/portal-deploy/SKILL.md +57 -47
  30. package/bundle/toolchain/skills/portal-deploy/SKILL.md.tmpl +452 -0
  31. package/bundle/toolchain/skills/portal-dev/SKILL.md +65 -47
  32. package/bundle/toolchain/skills/portal-dev/SKILL.md.tmpl +228 -0
  33. package/bundle/toolchain/skills/portal-list/SKILL.md +64 -43
  34. package/bundle/toolchain/skills/portal-list/SKILL.md.tmpl +181 -0
  35. package/bundle/toolchain/skills/portal-onboard/SKILL.md +331 -162
  36. package/bundle/toolchain/skills/portal-onboard/SKILL.md.tmpl +340 -0
  37. package/bundle/toolchain/skills/portal-preview/SKILL.md +65 -44
  38. package/bundle/toolchain/skills/portal-preview/SKILL.md.tmpl +171 -0
  39. package/bundle/toolchain/skills/portal-setup/SKILL.md +79 -60
  40. package/bundle/toolchain/skills/portal-setup/SKILL.md.tmpl +227 -0
  41. package/bundle/toolchain/skills/portal-share/SKILL.md +69 -47
  42. package/bundle/toolchain/skills/portal-share/SKILL.md.tmpl +162 -0
  43. package/bundle/toolchain/skills/portal-status/SKILL.md +58 -37
  44. package/bundle/toolchain/skills/portal-status/SKILL.md.tmpl +196 -0
  45. package/bundle/toolchain/skills/portal-update/SKILL.md +60 -46
  46. package/bundle/toolchain/skills/portal-update/SKILL.md.tmpl +269 -0
  47. package/bundle/toolchain/skills/portal-upgrade/SKILL.md +55 -33
  48. package/bundle/toolchain/skills/portal-upgrade/SKILL.md.tmpl +164 -0
  49. package/bundle/toolchain/skills/portal-verify/SKILL.md +69 -14
  50. package/bundle/toolchain/skills/portal-verify/SKILL.md.tmpl +224 -0
  51. package/bundle/toolchain/skills/shared/preamble.md +30 -126
  52. package/bundle/toolchain/skills/shared/runtime-principles.md +25 -0
  53. package/bundle/toolchain/templates/sales-followup/sales-followup-client.tsx +1 -1
  54. package/dist/index.js +79 -14
  55. package/package.json +5 -2
@@ -11,14 +11,17 @@ allowed-tools: [Bash, Read, Write, Edit, Glob, Grep]
11
11
  Before doing anything else, execute this block in a Bash tool call:
12
12
 
13
13
  ```bash
14
- CONFIG="$HOME/.showpane/config.json"
14
+ SHOWPANE_HOME="$HOME/.showpane"
15
+ SHOWPANE_BIN="$SHOWPANE_HOME/bin"
16
+ CONFIG="$SHOWPANE_HOME/config.json"
15
17
  if [ ! -f "$CONFIG" ]; then
16
- echo "Showpane not configured. Run /portal setup first."
18
+ echo "Showpane not configured. Run /portal-setup first."
17
19
  exit 1
18
20
  fi
19
- APP_PATH=$(cat "$CONFIG" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('app_path',''))" 2>/dev/null)
20
- DEPLOY_MODE=$(cat "$CONFIG" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('deploy_mode','local'))" 2>/dev/null)
21
- 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)
21
+
22
+ 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)
23
+ 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")
24
+ 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)
22
25
  APP_PATH="${SHOWPANE_APP_PATH:-$APP_PATH}"
23
26
  if [ -f "$APP_PATH/.env" ]; then set -a && source "$APP_PATH/.env" && set +a; fi
24
27
  DATABASE_URL="${DATABASE_URL:-}"
@@ -26,20 +29,26 @@ if [ ! -d "$APP_PATH/node_modules/.prisma" ]; then
26
29
  echo "App dependencies not installed. Run: cd $APP_PATH && npm install"
27
30
  exit 1
28
31
  fi
29
- SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$HOME/.showpane/current}"
32
+
33
+ SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$SHOWPANE_HOME/current}"
30
34
  SKILL_VERSION=$(cat "$SKILL_DIR/VERSION" 2>/dev/null || echo "unknown")
31
- echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
32
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
35
+ _UPD=$("$SHOWPANE_BIN/showpane-update-check" 2>/dev/null || true)
36
+ [ -n "$_UPD" ] && echo "$_UPD" || true
37
+ mkdir -p "$SHOWPANE_HOME/sessions" "$SHOWPANE_HOME/analytics" "$SHOWPANE_HOME/checkpoints"
38
+ touch "$SHOWPANE_HOME/sessions/$PPID"
39
+ find "$SHOWPANE_HOME/sessions" -mmin +120 -type f -delete 2>/dev/null || true
40
+ TEL=$("$SHOWPANE_BIN/showpane-config" get telemetry 2>/dev/null || echo "anonymous")
41
+ TEL_PROMPTED=$([ -f "$SHOWPANE_HOME/.telemetry-prompted" ] && echo "yes" || echo "no")
42
+ _TEL_START=$(date +%s)
43
+ _SESSION_ID="${PPID:-0}-$(date +%s)"
44
+
45
+ LEARN_FILE="$SHOWPANE_HOME/learnings.jsonl"
33
46
  [ -f "$LEARN_FILE" ] && echo "LEARNINGS: $(wc -l < "$LEARN_FILE" | tr -d ' ') loaded" || echo "LEARNINGS: 0"
34
-
35
- # Predictive next-skill suggestion
36
- if [ -f "$HOME/.showpane/timeline.jsonl" ]; then
37
- _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)
47
+ if [ -f "$SHOWPANE_HOME/timeline.jsonl" ]; then
48
+ _RECENT=$(grep '"event":"completed"' "$SHOWPANE_HOME/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '
49
+ ' ',' | sed 's/,$//' || true)
38
50
  [ -n "$_RECENT" ] && echo "RECENT_SKILLS: $_RECENT"
39
51
  fi
40
-
41
- # Search relevant learnings
42
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
43
52
  if [ -f "$LEARN_FILE" ]; then
44
53
  _LEARN_COUNT=$(wc -l < "$LEARN_FILE" 2>/dev/null | tr -d ' ')
45
54
  echo "LEARNINGS: $_LEARN_COUNT entries"
@@ -49,23 +58,39 @@ if [ -f "$LEARN_FILE" ]; then
49
58
  fi
50
59
  fi
51
60
 
52
- # Track skill execution
53
- SHOWPANE_TIMELINE="$HOME/.showpane/timeline.jsonl"
61
+ SHOWPANE_TIMELINE="$SHOWPANE_HOME/timeline.jsonl"
54
62
  mkdir -p "$(dirname "$SHOWPANE_TIMELINE")"
55
63
  echo '{"skill":"portal-upgrade","event":"started","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$SHOWPANE_TIMELINE" 2>/dev/null
64
+ echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
65
+ echo "TELEMETRY: $TEL"
66
+ echo "TEL_PROMPTED: $TEL_PROMPTED"
56
67
  ```
57
68
 
58
- If RECENT_SKILLS is shown, suggest the likely next skill:
69
+ If output shows `JUST_UPGRADED <from> <to>`, tell the user Showpane was just upgraded and continue.
70
+
71
+ If output shows `UPGRADE_AVAILABLE <old> <new>`, tell the user a newer Showpane toolchain is available and recommend `/portal-upgrade`.
72
+
73
+ If `TEL_PROMPTED` is `no`, default telemetry to `anonymous` without interrupting the flow. Do not mention telemetry unless the user asks.
74
+
75
+ Run:
76
+ ```bash
77
+ "$SHOWPANE_BIN/showpane-config" set telemetry anonymous
78
+ touch "$SHOWPANE_HOME/.telemetry-prompted"
79
+ ```
80
+
81
+ If `RECENT_SKILLS` is shown, suggest the likely next skill:
59
82
  - After portal-create → suggest /portal-preview
60
- - After portal-preview → suggest /portal-deploy or /portal-share
83
+ - After portal-preview → suggest /portal-deploy
61
84
  - After portal-deploy → suggest /portal-status or /portal-verify
62
- - After portal-setup → suggest /portal-create
63
- - After portal-credentials → suggest /portal-share
64
- - After portal-update → suggest /portal-deploy
85
+ - After portal-setup → suggest /portal-onboard for a first run, or /portal-create for the fast path
86
+ - After portal-credentials → suggest /portal-deploy before external sharing
87
+ - After portal-update → suggest /portal-preview or /portal-deploy
65
88
 
66
- If RECENT_LEARNINGS is shown, review them before proceeding. Past learnings may contain
67
- relevant warnings or tips for this operation. Apply them where relevant but don't
68
- mention them unless they directly affect the current task.
89
+ 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.
90
+
91
+ Read `skills/shared/runtime-principles.md` once near the start of the skill and apply the relevant product defaults.
92
+
93
+ If `skills/shared/platform-constraints.md` exists, read it once near the start of the skill and apply only the relevant limits.
69
94
 
70
95
  ## Overview
71
96
 
@@ -210,7 +235,7 @@ If no changelog exists, the CLI dry-run summary serves as the change summary.
210
235
 
211
236
  ## Upgrade Frequency
212
237
 
213
- There is no auto-upgrade mechanism. The user must explicitly run `/portal upgrade` to check for and apply updates.
238
+ There is no auto-upgrade mechanism. The user must explicitly run `/portal-upgrade` to check for and apply updates.
214
239
 
215
240
  Suggested upgrade frequency: monthly, or when the user encounters an issue that may have been fixed upstream. The skill does not nag or remind.
216
241
 
@@ -222,14 +247,11 @@ If a new version introduces changes to the learnings format, the changelog or se
222
247
 
223
248
  ## Completion
224
249
 
225
- As a final step, log skill completion:
250
+ As a final step, log skill completion and telemetry:
226
251
 
227
252
  ```bash
228
253
  echo '{"skill":"portal-upgrade","event":"completed","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$HOME/.showpane/timeline.jsonl" 2>/dev/null
254
+ _TEL_END=$(date +%s)
255
+ _TEL_DUR=$(( _TEL_END - ${_TEL_START:-_TEL_END} ))
256
+ "$HOME/.showpane/bin/showpane-telemetry-log" --skill "portal-upgrade" --duration "$_TEL_DUR" --outcome success --session-id "${_SESSION_ID:-}" 2>/dev/null || true
229
257
  ```
230
-
231
- ## Related Skills
232
-
233
- - `/portal setup` -- re-run setup independently if the upgraded project needs reconfiguration
234
- - `/portal status` -- check that all portals are healthy after an upgrade
235
- - `/portal dev` -- restart the dev server to pick up any app changes
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: portal-upgrade
3
+ description: |
4
+ Self-update the Showpane skill pack to the latest version. Use when asked to "upgrade",
5
+ "update showpane", "update skills", "get latest version", or "check for updates". (showpane)
6
+ allowed-tools: [Bash, Read, Write, Edit, Glob, Grep]
7
+ ---
8
+
9
+ {{PREAMBLE}}
10
+
11
+ ## Overview
12
+
13
+ This skill updates both the global Showpane toolchain and the current project using the packaged Showpane CLI. The upgrade is versioned -- it does not depend on the user's project being a git clone of the upstream Showpane repository.
14
+
15
+ The flow is:
16
+ 1. Check the current installed Showpane/toolchain version
17
+ 2. Check the latest published CLI version on npm
18
+ 3. Run a dry-run project upgrade to detect conflicts
19
+ 4. Sync the matching global toolchain
20
+ 5. Apply the project upgrade
21
+
22
+ ## Steps
23
+
24
+ ### Step 1: Check current version
25
+
26
+ Read the current skill pack version from the VERSION file:
27
+
28
+ ```bash
29
+ cat $SKILL_DIR/VERSION
30
+ ```
31
+
32
+ This was already captured by the preamble, but read it explicitly here so you have the full version string (e.g., "1.0.0 (requires app >= 0.1.0)").
33
+
34
+ Display the current version:
35
+
36
+ "Current version: 1.0.0"
37
+
38
+ ### Step 2: Check the latest published Showpane version
39
+
40
+ Run:
41
+
42
+ ```bash
43
+ npm view showpane version
44
+ ```
45
+
46
+ If the command fails, report:
47
+
48
+ "Could not reach the npm registry. Check your network connection and try again."
49
+
50
+ If the returned version matches the current Showpane version, inform the user that no published upgrade is available and stop.
51
+
52
+ ### Step 3: Dry-run the project upgrade
53
+
54
+ Run a dry-run against the user's project before changing anything:
55
+
56
+ ```bash
57
+ npx showpane@latest upgrade --project "$APP_PATH" --dry-run
58
+ ```
59
+
60
+ If the dry-run reports conflicts, stop and show the conflicted managed files. Explain:
61
+
62
+ "Showpane found local edits in framework-managed files. Review or revert those files before running the upgrade."
63
+
64
+ ### Step 4: Sync the latest toolchain
65
+
66
+ Install the matching global Showpane toolchain and Claude Code skill links:
67
+
68
+ ```bash
69
+ npx showpane@latest sync
70
+ ```
71
+
72
+ If sync fails, stop and report the error. Do not continue to the project upgrade.
73
+
74
+ ### Step 5: Apply the project upgrade
75
+
76
+ Run:
77
+
78
+ ```bash
79
+ npx showpane@latest upgrade --project "$APP_PATH"
80
+ ```
81
+
82
+ This applies packaged scaffold updates to managed files only. It does not rely on upstream git history.
83
+
84
+ ### Step 6: Display the resulting version
85
+
86
+ Read the project version file:
87
+
88
+ ```bash
89
+ cat "$APP_PATH/VERSION"
90
+ ```
91
+
92
+ Display a short confirmation:
93
+
94
+ ```
95
+ ════════════════════════════════════════
96
+ Showpane upgraded!
97
+
98
+ Toolchain: latest published version
99
+ App: <APP_PATH/VERSION>
100
+ ════════════════════════════════════════
101
+ ```
102
+
103
+ ## Version Compatibility
104
+
105
+ The VERSION file format remains: `<skill_version> (requires app >= <min_app_version>)`
106
+
107
+ After syncing the toolchain, compare:
108
+ - Read the new minimum app version from `"$SKILL_DIR/skills/VERSION"`
109
+ - Read the current app version from `"$APP_PATH/VERSION"`
110
+ - If the app version is below the minimum, warn the user
111
+
112
+ ## Conventions
113
+
114
+ - Always show the current version before checking for updates. This gives the user a reference point.
115
+ - Always run the dry-run first. No silent updates.
116
+ - Use double-line box drawing (`═`) for the version display boxes.
117
+ - If the user runs upgrade frequently (check learnings), keep output minimal: just the version change and commit count.
118
+ - Do not auto-upgrade on other skill invocations. The upgrade is only triggered explicitly by this skill.
119
+
120
+ ## Edge Cases
121
+
122
+ - **Dry-run conflicts**: Stop and surface the file list. Do not attempt a force-upgrade.
123
+ - **Registry/network failure**: If `npm view` or `npx showpane@latest ...` fails due to connectivity, report it and stop.
124
+ - **Toolchain sync fails**: Do not continue to the project upgrade.
125
+
126
+ ## Error Handling
127
+
128
+ - If the preamble fails, stop and display the error.
129
+ - If the dry-run fails, report the error and stop.
130
+ - If the real upgrade fails after the dry-run succeeded, show the CLI error output and stop.
131
+ - Do not attempt to recover with git commands.
132
+
133
+ ## Changelog Awareness
134
+
135
+ After a successful upgrade, check if a CHANGELOG.md exists in the project root:
136
+
137
+ ```bash
138
+ cat "$APP_PATH/CHANGELOG.md" 2>/dev/null | head -50
139
+ ```
140
+
141
+ If a changelog exists, extract the entries between the previous and current version and display them as a "What's new" section:
142
+
143
+ ```
144
+ What's new in 1.1.0:
145
+ - Portal analytics now shows trend comparisons
146
+ - Fixed credential rotation not bumping version number
147
+ - Preamble now includes telemetry opt-in status
148
+ ```
149
+
150
+ If no changelog exists, the CLI dry-run summary serves as the change summary.
151
+
152
+ ## Upgrade Frequency
153
+
154
+ There is no auto-upgrade mechanism. The user must explicitly run `/portal-upgrade` to check for and apply updates.
155
+
156
+ Suggested upgrade frequency: monthly, or when the user encounters an issue that may have been fixed upstream. The skill does not nag or remind.
157
+
158
+ ## Learnings Preservation
159
+
160
+ Upgrading does not affect the user's learnings file (`~/.showpane/learnings.jsonl`). Learnings are stored outside the project and persist across upgrades. Similarly, the config file (`~/.showpane/config.json`) and telemetry data (`~/.showpane/telemetry.jsonl`) are not touched by the upgrade.
161
+
162
+ If a new version introduces changes to the learnings format, the changelog or setup script should handle migration transparently.
163
+
164
+ {{COMPLETION}}
@@ -8,21 +8,20 @@ allowed-tools: [Bash, Read, Glob, Grep]
8
8
 
9
9
  ## Preamble (run first)
10
10
 
11
+ Before doing anything else, execute this block in a Bash tool call:
12
+
11
13
  ```bash
12
- # Read config
13
- CONFIG="$HOME/.showpane/config.json"
14
+ SHOWPANE_HOME="$HOME/.showpane"
15
+ SHOWPANE_BIN="$SHOWPANE_HOME/bin"
16
+ CONFIG="$SHOWPANE_HOME/config.json"
14
17
  if [ ! -f "$CONFIG" ]; then
15
18
  echo "Showpane not configured. Run /portal-setup first."
16
19
  exit 1
17
20
  fi
18
- APP_PATH=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('app_path',''))" 2>/dev/null)
19
- DEPLOY_MODE=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('deploy_mode','local'))" 2>/dev/null)
20
- ORG_SLUG=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('orgSlug','') or d.get('org_slug',''))" 2>/dev/null)
21
- CLOUD_API_TOKEN=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('cloud',d).get('api_token', d.get('accessToken','')))" 2>/dev/null)
22
- CLOUD_ORG_SLUG=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('cloud',d).get('org_slug', d.get('orgSlug','')))" 2>/dev/null)
23
- CLOUD_PORTAL_URL=$(python3 -c "import json; d=json.load(open('$CONFIG')); print(d.get('cloud',d).get('portal_url', d.get('portalUrl','')))" 2>/dev/null)
24
- CLOUD_API_BASE="${SHOWPANE_CLOUD_URL:-https://app.showpane.com}"
25
- CLOUD_EVENTS_URL="${CLOUD_EVENTS_URL:-$CLOUD_API_BASE}"
21
+
22
+ 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)
23
+ 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")
24
+ 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)
26
25
  APP_PATH="${SHOWPANE_APP_PATH:-$APP_PATH}"
27
26
  if [ -f "$APP_PATH/.env" ]; then set -a && source "$APP_PATH/.env" && set +a; fi
28
27
  DATABASE_URL="${DATABASE_URL:-}"
@@ -30,13 +29,69 @@ if [ ! -d "$APP_PATH/node_modules/.prisma" ]; then
30
29
  echo "App dependencies not installed. Run: cd $APP_PATH && npm install"
31
30
  exit 1
32
31
  fi
33
- SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$HOME/.showpane/current}"
32
+
33
+ SKILL_DIR="${SHOWPANE_TOOLCHAIN_DIR:-$SHOWPANE_HOME/current}"
34
34
  SKILL_VERSION=$(cat "$SKILL_DIR/VERSION" 2>/dev/null || echo "unknown")
35
- echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
36
- LEARN_FILE="$HOME/.showpane/learnings.jsonl"
35
+ _UPD=$("$SHOWPANE_BIN/showpane-update-check" 2>/dev/null || true)
36
+ [ -n "$_UPD" ] && echo "$_UPD" || true
37
+ mkdir -p "$SHOWPANE_HOME/sessions" "$SHOWPANE_HOME/analytics" "$SHOWPANE_HOME/checkpoints"
38
+ touch "$SHOWPANE_HOME/sessions/$PPID"
39
+ find "$SHOWPANE_HOME/sessions" -mmin +120 -type f -delete 2>/dev/null || true
40
+ TEL=$("$SHOWPANE_BIN/showpane-config" get telemetry 2>/dev/null || echo "anonymous")
41
+ TEL_PROMPTED=$([ -f "$SHOWPANE_HOME/.telemetry-prompted" ] && echo "yes" || echo "no")
42
+ _TEL_START=$(date +%s)
43
+ _SESSION_ID="${PPID:-0}-$(date +%s)"
44
+
45
+ LEARN_FILE="$SHOWPANE_HOME/learnings.jsonl"
37
46
  [ -f "$LEARN_FILE" ] && echo "LEARNINGS: $(wc -l < "$LEARN_FILE" | tr -d ' ') loaded" || echo "LEARNINGS: 0"
47
+ if [ -f "$SHOWPANE_HOME/timeline.jsonl" ]; then
48
+ _RECENT=$(grep '"event":"completed"' "$SHOWPANE_HOME/timeline.jsonl" 2>/dev/null | tail -3 | grep -o '"skill":"[^"]*"' | sed 's/"skill":"//;s/"//' | tr '
49
+ ' ',' | sed 's/,$//' || true)
50
+ [ -n "$_RECENT" ] && echo "RECENT_SKILLS: $_RECENT"
51
+ fi
52
+ if [ -f "$LEARN_FILE" ]; then
53
+ _LEARN_COUNT=$(wc -l < "$LEARN_FILE" 2>/dev/null | tr -d ' ')
54
+ echo "LEARNINGS: $_LEARN_COUNT entries"
55
+ if [ "$_LEARN_COUNT" -gt 0 ] 2>/dev/null; then
56
+ echo "RECENT_LEARNINGS:"
57
+ tail -5 "$LEARN_FILE" 2>/dev/null
58
+ fi
59
+ fi
60
+
61
+ SHOWPANE_TIMELINE="$SHOWPANE_HOME/timeline.jsonl"
62
+ mkdir -p "$(dirname "$SHOWPANE_TIMELINE")"
63
+ echo '{"skill":"portal-verify","event":"started","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' >> "$SHOWPANE_TIMELINE" 2>/dev/null
64
+ echo "SHOWPANE: v$SKILL_VERSION | MODE: $DEPLOY_MODE | APP: $APP_PATH"
65
+ echo "TELEMETRY: $TEL"
66
+ echo "TEL_PROMPTED: $TEL_PROMPTED"
38
67
  ```
39
68
 
69
+ If output shows `JUST_UPGRADED <from> <to>`, tell the user Showpane was just upgraded and continue.
70
+
71
+ If output shows `UPGRADE_AVAILABLE <old> <new>`, tell the user a newer Showpane toolchain is available and recommend `/portal-upgrade`.
72
+
73
+ If `TEL_PROMPTED` is `no`, default telemetry to `anonymous` without interrupting the flow. Do not mention telemetry unless the user asks.
74
+
75
+ Run:
76
+ ```bash
77
+ "$SHOWPANE_BIN/showpane-config" set telemetry anonymous
78
+ touch "$SHOWPANE_HOME/.telemetry-prompted"
79
+ ```
80
+
81
+ If `RECENT_SKILLS` is shown, suggest the likely next skill:
82
+ - After portal-create → suggest /portal-preview
83
+ - After portal-preview → suggest /portal-deploy
84
+ - After portal-deploy → suggest /portal-status or /portal-verify
85
+ - After portal-setup → suggest /portal-onboard for a first run, or /portal-create for the fast path
86
+ - After portal-credentials → suggest /portal-deploy before external sharing
87
+ - After portal-update → suggest /portal-preview or /portal-deploy
88
+
89
+ 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.
90
+
91
+ Read `skills/shared/runtime-principles.md` once near the start of the skill and apply the relevant product defaults.
92
+
93
+ If `skills/shared/platform-constraints.md` exists, read it once near the start of the skill and apply only the relevant limits.
94
+
40
95
  ## Steps
41
96
 
42
97
  ### Step 1: URL Reachability
@@ -45,7 +100,7 @@ Determine the portal URL and check that it responds.
45
100
 
46
101
  ```bash
47
102
  if [ -z "$CLOUD_PORTAL_URL" ] && [ -z "$CLOUD_ORG_SLUG" ]; then
48
- echo "No hosted portal URL configured. Run /portal deploy first."
103
+ echo "No hosted portal URL configured. Run /portal-deploy first."
49
104
  exit 1
50
105
  fi
51
106
  PORTAL_URL="${CLOUD_PORTAL_URL:-https://$CLOUD_ORG_SLUG.showpane.com}"
@@ -0,0 +1,224 @@
1
+ ---
2
+ name: portal-verify
3
+ description: |
4
+ Verify a Showpane Cloud portal after publish: DNS, SSL, login page, content rendering, engagement tracking.
5
+ Trigger phrases: "verify portal", "check deployment", "is my portal working", "portal health". (showpane)
6
+ allowed-tools: [Bash, Read, Glob, Grep]
7
+ ---
8
+
9
+ {{PREAMBLE}}
10
+
11
+ ## Steps
12
+
13
+ ### Step 1: URL Reachability
14
+
15
+ Determine the portal URL and check that it responds.
16
+
17
+ ```bash
18
+ if [ -z "$CLOUD_PORTAL_URL" ] && [ -z "$CLOUD_ORG_SLUG" ]; then
19
+ echo "No hosted portal URL configured. Run /portal-deploy first."
20
+ exit 1
21
+ fi
22
+ PORTAL_URL="${CLOUD_PORTAL_URL:-https://$CLOUD_ORG_SLUG.showpane.com}"
23
+ echo "Checking app URL: $CLOUD_API_BASE"
24
+ APP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$CLOUD_API_BASE/api/health" 2>/dev/null)
25
+ echo "App health: $APP_CODE"
26
+
27
+ echo "Checking org URL: $PORTAL_URL"
28
+ ORG_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$PORTAL_URL" 2>/dev/null)
29
+ echo "Org portal: $ORG_CODE"
30
+
31
+ if [ "$ORG_CODE" = "200" ]; then
32
+ URL_STATUS="ok"
33
+ else
34
+ URL_STATUS="unreachable ($ORG_CODE)"
35
+ fi
36
+ ```
37
+
38
+ If the URL is unreachable, warn the user but continue with remaining checks. DNS propagation or cold starts can cause brief unavailability.
39
+
40
+ ### Step 2: SSL Verification (cloud only)
41
+
42
+ For cloud deploys, verify the SSL certificate is valid and HTTPS redirect works.
43
+
44
+ ```bash
45
+ if [ "$DEPLOY_MODE" = "cloud" ] && [ -n "$CLOUD_ORG_SLUG" ]; then
46
+ HTTPS_URL="https://${CLOUD_ORG_SLUG}.showpane.com"
47
+ echo "Checking SSL for $HTTPS_URL..."
48
+
49
+ # Check certificate validity and expiry
50
+ SSL_INFO=$(echo | openssl s_client -servername "${CLOUD_ORG_SLUG}.showpane.com" \
51
+ -connect "${CLOUD_ORG_SLUG}.showpane.com:443" 2>/dev/null \
52
+ | openssl x509 -noout -dates 2>/dev/null)
53
+
54
+ if [ -n "$SSL_INFO" ]; then
55
+ SSL_EXPIRY=$(echo "$SSL_INFO" | grep 'notAfter' | cut -d= -f2)
56
+ echo "SSL valid, expires: $SSL_EXPIRY"
57
+ SSL_STATUS="valid, expires $SSL_EXPIRY"
58
+ else
59
+ echo "SSL certificate not found or invalid"
60
+ SSL_STATUS="not found"
61
+ fi
62
+
63
+ # Check HTTPS redirect from HTTP
64
+ HTTP_URL="http://${CLOUD_ORG_SLUG}.showpane.com"
65
+ REDIRECT_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$HTTP_URL" 2>/dev/null)
66
+ if [ "$REDIRECT_CODE" = "301" ] || [ "$REDIRECT_CODE" = "308" ]; then
67
+ echo "HTTP->HTTPS redirect: OK ($REDIRECT_CODE)"
68
+ else
69
+ echo "HTTP->HTTPS redirect: $REDIRECT_CODE (expected 301 or 308)"
70
+ fi
71
+ else
72
+ SSL_STATUS="n/a (no cloud org configured)"
73
+ fi
74
+ ```
75
+
76
+ ### Step 3: Portal Login Pages
77
+
78
+ List all active portals from the database and verify each login page loads.
79
+
80
+ ```bash
81
+ cd "$APP_PATH" && PORTAL_LIST=$(npx tsx -e "
82
+ const { prisma } = require('./src/lib/db');
83
+ prisma.clientPortal.findMany({ where: { isActive: true }, select: { slug: true, clientName: true } })
84
+ .then(portals => console.log(JSON.stringify(portals)))
85
+ .finally(() => prisma.\$disconnect());
86
+ " 2>/dev/null)
87
+
88
+ echo "Active portals: $PORTAL_LIST"
89
+ ```
90
+
91
+ For each portal, verify the login page returns a response and contains auth-related content:
92
+
93
+ ```bash
94
+ PORTAL_URL="${CLOUD_PORTAL_URL:-https://$CLOUD_ORG_SLUG.showpane.com}"
95
+ echo "$PORTAL_LIST" | python3 -c "
96
+ import sys, json
97
+ portals = json.load(sys.stdin)
98
+ for p in portals:
99
+ slug = p['slug']
100
+ name = p.get('clientName', slug)
101
+ print(f' {name} ({slug})')
102
+ print(f'{len(portals)} active portals')
103
+ " 2>/dev/null
104
+ ```
105
+
106
+ Then for each portal slug, check the login page:
107
+
108
+ ```bash
109
+ for SLUG in $(echo "$PORTAL_LIST" | python3 -c "
110
+ import sys, json
111
+ for p in json.load(sys.stdin): print(p['slug'])
112
+ " 2>/dev/null); do
113
+ PAGE_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$PORTAL_URL/client/$SLUG" 2>/dev/null)
114
+ PAGE_BODY=$(curl -s "$PORTAL_URL/client/$SLUG" 2>/dev/null | head -c 5000)
115
+ HAS_AUTH=$(echo "$PAGE_BODY" | grep -ci 'password\|login\|sign.in\|auth' 2>/dev/null || echo "0")
116
+ if [ "$PAGE_CODE" = "200" ] && [ "$HAS_AUTH" -gt 0 ]; then
117
+ echo " $SLUG: Login page OK"
118
+ elif [ "$PAGE_CODE" = "200" ]; then
119
+ echo " $SLUG: Page loads ($PAGE_CODE) but no auth content detected"
120
+ else
121
+ echo " $SLUG: FAILED ($PAGE_CODE)"
122
+ fi
123
+ done
124
+ ```
125
+
126
+ ### Step 4: Engagement Tracking
127
+
128
+ Verify the client events API endpoint responds.
129
+
130
+ ```bash
131
+ PORTAL_URL="${CLOUD_PORTAL_URL:-http://localhost:3000}"
132
+ EVENTS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X OPTIONS "$PORTAL_URL/api/client-events" 2>/dev/null)
133
+ echo "Events endpoint: $EVENTS_CODE"
134
+ ```
135
+
136
+ For cloud deploys, also verify the cloud events URL is reachable:
137
+
138
+ ```bash
139
+ if [ "$DEPLOY_MODE" = "cloud" ] && [ -n "$CLOUD_EVENTS_URL" ]; then
140
+ CLOUD_EVENTS_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X OPTIONS "$CLOUD_EVENTS_URL/api/client-events" 2>/dev/null)
141
+ echo "Cloud events endpoint: $CLOUD_EVENTS_CODE"
142
+ fi
143
+ ```
144
+
145
+ The events endpoint should return 200 or 204 for OPTIONS requests. A 404 means the route is not deployed. A 405 (Method Not Allowed) is also acceptable — it means the route exists but only accepts POST.
146
+
147
+ ### Step 5: File Downloads
148
+
149
+ Check if any PortalFile records exist and verify file download endpoints work.
150
+
151
+ ```bash
152
+ cd "$APP_PATH" && FILE_INFO=$(npx tsx -e "
153
+ const { prisma } = require('./src/lib/db');
154
+ prisma.portalFile.findMany({ select: { id: true, filename: true, portalId: true } })
155
+ .then(files => console.log(JSON.stringify({ count: files.length, files: files.slice(0, 5) })))
156
+ .catch(() => console.log(JSON.stringify({ count: 0, files: [] })))
157
+ .finally(() => prisma.\$disconnect());
158
+ " 2>/dev/null)
159
+
160
+ FILE_COUNT=$(echo "$FILE_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('count',0))" 2>/dev/null)
161
+ echo "Hosted files: $FILE_COUNT"
162
+ ```
163
+
164
+ If files exist, verify a sample file download endpoint responds:
165
+
166
+ ```bash
167
+ if [ "$FILE_COUNT" -gt 0 ]; then
168
+ SAMPLE_FILE_ID=$(echo "$FILE_INFO" | python3 -c "
169
+ import sys, json
170
+ files = json.load(sys.stdin).get('files', [])
171
+ if files: print(files[0]['id'])
172
+ " 2>/dev/null)
173
+ if [ -n "$SAMPLE_FILE_ID" ]; then
174
+ PORTAL_URL="${CLOUD_PORTAL_URL:-http://localhost:3000}"
175
+ DL_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$PORTAL_URL/api/files/$SAMPLE_FILE_ID" 2>/dev/null)
176
+ echo "File download endpoint: $DL_CODE"
177
+ if [ "$DL_CODE" = "200" ] || [ "$DL_CODE" = "302" ]; then
178
+ FILE_STATUS="accessible"
179
+ else
180
+ FILE_STATUS="endpoint returned $DL_CODE"
181
+ fi
182
+ fi
183
+ else
184
+ FILE_STATUS="none hosted"
185
+ fi
186
+ ```
187
+
188
+ ### Step 6: Report
189
+
190
+ Compile all check results into a health report. Print it in this format:
191
+
192
+ ```
193
+ Portal Health Report
194
+ ====================
195
+ URL: https://orgslug.showpane.com [ok/unreachable]
196
+ SSL: Valid, expires 2027-01-15 [ok/not found/n/a]
197
+ Portals: 3 active
198
+ acme: Login page [ok/failed], Events [ok/failed]
199
+ betacorp: Login page [ok/failed], Events [ok/failed]
200
+ demo: Login page [ok/failed], Events [ok/failed]
201
+ Files: 5 hosted, all accessible [ok/issues]
202
+
203
+ Overall: HEALTHY / DEGRADED / UNHEALTHY
204
+ ```
205
+
206
+ Rules for the overall status:
207
+ - **HEALTHY**: All checks pass (URL reachable, SSL valid for cloud, all portals load, events endpoint responds)
208
+ - **DEGRADED**: URL reachable but some portals fail, or SSL is pending, or events endpoint is down
209
+ - **UNHEALTHY**: URL is unreachable, or no portals load
210
+
211
+ After the report, suggest next steps:
212
+ - If UNHEALTHY: "Run /portal-deploy to redeploy, or /investigate to debug."
213
+ - If DEGRADED: "Check individual portal issues above. Run /portal-status for ongoing monitoring."
214
+ - If HEALTHY: "All systems operational. Run /portal-status for ongoing monitoring."
215
+
216
+ ## Conventions
217
+
218
+ - This skill is read-only — it never modifies the deployment or database
219
+ - All checks use curl with short timeouts to avoid hanging on unreachable endpoints
220
+ - Cloud checks verify both the control plane (app.showpane.com) and the org portal (orgslug.showpane.com)
221
+ - The PortalFile model may not exist in all schema versions — catch errors gracefully
222
+ - If the database is unreachable, skip DB-dependent checks (Steps 3, 5) and note it in the report
223
+ - SSL checks only apply when a cloud portal URL is configured
224
+ - The events endpoint check uses OPTIONS to avoid creating spurious event records