@m-kopa/launchpad-cli 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +854 -0
- package/README.md +109 -0
- package/dist/auth/browser.d.ts +18 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/callback-server.d.ts +24 -0
- package/dist/auth/callback-server.d.ts.map +1 -0
- package/dist/auth/discovery.d.ts +25 -0
- package/dist/auth/discovery.d.ts.map +1 -0
- package/dist/auth/flow.d.ts +39 -0
- package/dist/auth/flow.d.ts.map +1 -0
- package/dist/auth/jwt.d.ts +27 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/pkce.d.ts +26 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/registration.d.ts +8 -0
- package/dist/auth/registration.d.ts.map +1 -0
- package/dist/auth/session.d.ts +54 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/token.d.ts +37 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/bundle/cron-bundle.d.ts +77 -0
- package/dist/bundle/cron-bundle.d.ts.map +1 -0
- package/dist/bundle/cwd-walker.d.ts +43 -0
- package/dist/bundle/cwd-walker.d.ts.map +1 -0
- package/dist/bundle/orchestrate.d.ts +51 -0
- package/dist/bundle/orchestrate.d.ts.map +1 -0
- package/dist/bundle/upload.d.ts +66 -0
- package/dist/bundle/upload.d.ts.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +9757 -0
- package/dist/clone/git-init.d.ts +18 -0
- package/dist/clone/git-init.d.ts.map +1 -0
- package/dist/clone/tar-extract.d.ts +59 -0
- package/dist/clone/tar-extract.d.ts.map +1 -0
- package/dist/commands/apps.d.ts +14 -0
- package/dist/commands/apps.d.ts.map +1 -0
- package/dist/commands/channel-auth.d.ts +31 -0
- package/dist/commands/channel-auth.d.ts.map +1 -0
- package/dist/commands/clone.d.ts +3 -0
- package/dist/commands/clone.d.ts.map +1 -0
- package/dist/commands/create.d.ts +27 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/deploy-flags.d.ts +75 -0
- package/dist/commands/deploy-flags.d.ts.map +1 -0
- package/dist/commands/deploy-modes.d.ts +59 -0
- package/dist/commands/deploy-modes.d.ts.map +1 -0
- package/dist/commands/deploy.d.ts +29 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/destroy.d.ts +14 -0
- package/dist/commands/destroy.d.ts.map +1 -0
- package/dist/commands/envvars.d.ts +28 -0
- package/dist/commands/envvars.d.ts.map +1 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/groups-whoami.d.ts +3 -0
- package/dist/commands/groups-whoami.d.ts.map +1 -0
- package/dist/commands/groups.d.ts +3 -0
- package/dist/commands/groups.d.ts.map +1 -0
- package/dist/commands/init.d.ts +44 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logs.d.ts +16 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/merge.d.ts +29 -0
- package/dist/commands/merge.d.ts.map +1 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/pull.d.ts +12 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/review.d.ts +22 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/rollback.d.ts +3 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/secrets-template.d.ts +3 -0
- package/dist/commands/secrets-template.d.ts.map +1 -0
- package/dist/commands/secrets.d.ts +3 -0
- package/dist/commands/secrets.d.ts.map +1 -0
- package/dist/commands/skills.d.ts +13 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/status.d.ts +54 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/update.d.ts +114 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/deploy/apply.d.ts +29 -0
- package/dist/deploy/apply.d.ts.map +1 -0
- package/dist/deploy/dry-run.d.ts +13 -0
- package/dist/deploy/dry-run.d.ts.map +1 -0
- package/dist/deploy/git-files.d.ts +33 -0
- package/dist/deploy/git-files.d.ts.map +1 -0
- package/dist/deploy/group-pin.d.ts +66 -0
- package/dist/deploy/group-pin.d.ts.map +1 -0
- package/dist/deploy/manifest-state.d.ts +20 -0
- package/dist/deploy/manifest-state.d.ts.map +1 -0
- package/dist/deploy/manifest-status.d.ts +11 -0
- package/dist/deploy/manifest-status.d.ts.map +1 -0
- package/dist/deploy/resolve.d.ts +53 -0
- package/dist/deploy/resolve.d.ts.map +1 -0
- package/dist/deploy/rollback.d.ts +23 -0
- package/dist/deploy/rollback.d.ts.map +1 -0
- package/dist/deploy/runner.d.ts +29 -0
- package/dist/deploy/runner.d.ts.map +1 -0
- package/dist/deploy/stage-exit-codes.d.ts +41 -0
- package/dist/deploy/stage-exit-codes.d.ts.map +1 -0
- package/dist/deploy/status-polling.d.ts +37 -0
- package/dist/deploy/status-polling.d.ts.map +1 -0
- package/dist/deploy/tar-pack.d.ts +22 -0
- package/dist/deploy/tar-pack.d.ts.map +1 -0
- package/dist/detect/index.d.ts +53 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/dispatcher.d.ts +30 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/groups/client.d.ts +62 -0
- package/dist/groups/client.d.ts.map +1 -0
- package/dist/http/api-client.d.ts +33 -0
- package/dist/http/api-client.d.ts.map +1 -0
- package/dist/http/errors.d.ts +31 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/manifest/load.d.ts +38 -0
- package/dist/manifest/load.d.ts.map +1 -0
- package/dist/manifest/schema.d.ts +3 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +37 -0
- package/dist/secrets/env-parse.d.ts +19 -0
- package/dist/secrets/env-parse.d.ts.map +1 -0
- package/dist/secrets/push.d.ts +13 -0
- package/dist/secrets/push.d.ts.map +1 -0
- package/dist/secrets/set.d.ts +19 -0
- package/dist/secrets/set.d.ts.map +1 -0
- package/dist/secrets/status.d.ts +19 -0
- package/dist/secrets/status.d.ts.map +1 -0
- package/dist/types/api.d.ts +112 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/update-notifier.d.ts +69 -0
- package/dist/update-notifier.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +62 -0
- package/skills/README.md +100 -0
- package/skills/_partials/shell-contract.md +42 -0
- package/skills/launchpad-content-pr/SKILL.md +255 -0
- package/skills/launchpad-deploy/SKILL.md +415 -0
- package/skills/launchpad-deploy-status/SKILL.md +231 -0
- package/skills/launchpad-destroy/SKILL.md +317 -0
- package/skills/launchpad-onboard/SKILL.md +179 -0
- package/skills/launchpad-status/SKILL.md +263 -0
- package/skills/marquee-share/README.md +155 -0
- package/skills/marquee-share/SKILL.md +94 -0
- package/skills/marquee-share/SYNC.md +27 -0
- package/skills/marquee-share/dist/cli.js +896 -0
- package/skills/marquee-share/eslint.config.mjs +71 -0
- package/skills/marquee-share/install.sh +103 -0
- package/skills/marquee-share/package-lock.json +3946 -0
- package/skills/marquee-share/package.json +30 -0
- package/skills/marquee-share/src/auth/PROVENANCE.md +103 -0
- package/skills/marquee-share/src/auth/browser.ts +75 -0
- package/skills/marquee-share/src/auth/callback-server.ts +171 -0
- package/skills/marquee-share/src/auth/discovery.ts +171 -0
- package/skills/marquee-share/src/auth/flow.ts +262 -0
- package/skills/marquee-share/src/auth/index.ts +171 -0
- package/skills/marquee-share/src/auth/jwt.ts +77 -0
- package/skills/marquee-share/src/auth/pkce.ts +79 -0
- package/skills/marquee-share/src/auth/registration.ts +87 -0
- package/skills/marquee-share/src/auth/session.ts +205 -0
- package/skills/marquee-share/src/auth/token.ts +162 -0
- package/skills/marquee-share/src/cli.ts +246 -0
- package/skills/marquee-share/src/config.ts +101 -0
- package/skills/marquee-share/src/render/template.ts +171 -0
- package/skills/marquee-share/src/upload/index.ts +11 -0
- package/skills/marquee-share/src/upload/upload.ts +191 -0
- package/skills/marquee-share/tests/cli.test.ts +281 -0
- package/skills/marquee-share/tests/config.test.ts +119 -0
- package/skills/marquee-share/tests/flow.test.ts +356 -0
- package/skills/marquee-share/tests/no-token-leak.test.ts +240 -0
- package/skills/marquee-share/tests/pkce.test.ts +121 -0
- package/skills/marquee-share/tests/session.test.ts +173 -0
- package/skills/marquee-share/tests/template.test.ts +170 -0
- package/skills/marquee-share/tests/upload.test.ts +311 -0
- package/skills/marquee-share/tsconfig.json +23 -0
- package/skills/marquee-share/vitest.config.ts +15 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: launchpad-status
|
|
3
|
+
description: Show whether a Launchpad app's local launchpad.yaml matches what's deployed, and read the deployed manifest. Wraps `launchpad pull` (fetch deployed YAML) and `launchpad status` (drift report). Use when someone says "is my app in sync", "what's deployed", "show drift", "/launchpad-status", "/launchpad-pull", or after `launchpad deploy` to verify the change landed.
|
|
4
|
+
version: 0.23.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
8
|
+
## Shell contract — read this first
|
|
9
|
+
|
|
10
|
+
Every fenced `bash` block below MUST be sent to the `Bash` tool **verbatim**.
|
|
11
|
+
Do not rewrite into PowerShell, cmd, zsh-isms, or "equivalent" forms.
|
|
12
|
+
|
|
13
|
+
- macOS / Linux: the `Bash` tool runs system bash.
|
|
14
|
+
- Windows: the `Bash` tool runs Git for Windows (MSYS) bash. `$HOME`,
|
|
15
|
+
forward slashes, `test -f`, `command -v`, heredocs, and `[[ … ]]` all
|
|
16
|
+
work. There is no reason to translate to `Test-Path`, `$env:USERPROFILE`,
|
|
17
|
+
`Get-Content`, `Where-Object`, `Get-ChildItem`, or backslash paths —
|
|
18
|
+
doing so will fail with `/usr/bin/bash: syntax error`.
|
|
19
|
+
|
|
20
|
+
If a step genuinely needs OS branching, branch *inside* bash:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
case "$(uname -s)" in
|
|
24
|
+
Darwin) : ;;
|
|
25
|
+
Linux) : ;;
|
|
26
|
+
MINGW*|MSYS*|CYGWIN*) : ;;
|
|
27
|
+
esac
|
|
28
|
+
```
|
|
29
|
+
<!-- END shell-contract -->
|
|
30
|
+
|
|
31
|
+
# /launchpad-status
|
|
32
|
+
|
|
33
|
+
Read-only verbs. Zero local platform-repo / terraform / GitHub
|
|
34
|
+
credentials needed. Both go through the bot's `/manifest/state`
|
|
35
|
+
endpoint; the bot reads launchpad-platform's TF state to find the
|
|
36
|
+
last-applied manifest sha, then fetches launchpad.yaml from the app
|
|
37
|
+
repo at that sha. The CLI is a thin client.
|
|
38
|
+
|
|
39
|
+
## When to use which verb
|
|
40
|
+
|
|
41
|
+
- **`launchpad pull <slug>`** — read the deployed `launchpad.yaml`.
|
|
42
|
+
Use when you want to see what's actually running, or when you need
|
|
43
|
+
a starting point for editing a manifest.
|
|
44
|
+
- **`launchpad status [<slug>] [--strict] [--json]`** — compare local
|
|
45
|
+
`./launchpad.yaml` against what's deployed and report drift. Use
|
|
46
|
+
before `launchpad deploy` to see what will change, or after to
|
|
47
|
+
confirm the change landed.
|
|
48
|
+
|
|
49
|
+
If the operator is asking "did my deploy work" → `launchpad status`
|
|
50
|
+
inside the app repo's clone is the answer.
|
|
51
|
+
|
|
52
|
+
If they're asking "what was actually deployed" → `launchpad pull` is
|
|
53
|
+
the answer.
|
|
54
|
+
|
|
55
|
+
## Pre-flight
|
|
56
|
+
|
|
57
|
+
Both verbs need a current Cf Access session. If `~/.launchpad/session.json`
|
|
58
|
+
is missing or expired, surface the run-login hint:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
launchpad whoami
|
|
62
|
+
# If this fails: launchpad login
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The app must exist in the registry (`launchpad apps` lists yours).
|
|
66
|
+
Both verbs are owner/editor-scoped — non-members get HTTP 403 with
|
|
67
|
+
"not authorised for app X (you must be an owner or editor)".
|
|
68
|
+
|
|
69
|
+
## Slug resolution
|
|
70
|
+
|
|
71
|
+
Both verbs accept the slug three ways, with this precedence:
|
|
72
|
+
|
|
73
|
+
1. **`--slug <slug>`** — explicit, wins over everything.
|
|
74
|
+
2. **Positional argument** — `launchpad pull horizon-clone`.
|
|
75
|
+
3. **Current directory inference** — if cwd is named
|
|
76
|
+
`launchpad-app-<slug>/`, the slug is extracted automatically.
|
|
77
|
+
This is the default when you've `launchpad clone`d an app.
|
|
78
|
+
|
|
79
|
+
`--file <path>` on `launchpad status` only changes which **local**
|
|
80
|
+
manifest is read; it does NOT change slug resolution.
|
|
81
|
+
|
|
82
|
+
## `launchpad pull`
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Write deployed launchpad.yaml to stdout
|
|
86
|
+
launchpad pull horizon
|
|
87
|
+
|
|
88
|
+
# Write to a file
|
|
89
|
+
launchpad pull horizon --out /tmp/deployed.yaml
|
|
90
|
+
|
|
91
|
+
# Inside an app-repo clone — slug inferred from cwd
|
|
92
|
+
launchpad clone horizon
|
|
93
|
+
cd launchpad-app-horizon
|
|
94
|
+
launchpad pull
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Exit codes:
|
|
98
|
+
|
|
99
|
+
- **0** — manifest written successfully.
|
|
100
|
+
- **1** — error (no deployed manifest yet, 401, 403, 404, network).
|
|
101
|
+
|
|
102
|
+
## `launchpad status`
|
|
103
|
+
|
|
104
|
+
Reads `./launchpad.yaml` by default, compares to the deployed
|
|
105
|
+
manifest, reports state.
|
|
106
|
+
|
|
107
|
+
### Three possible states
|
|
108
|
+
|
|
109
|
+
- **`in sync`** — local and deployed are equivalent. The
|
|
110
|
+
equivalence relation is normalised-AST: whitespace, comments, and
|
|
111
|
+
key ordering do NOT count as drift. Schema defaults are honoured
|
|
112
|
+
(absent key with a default == explicit default).
|
|
113
|
+
- **`drift: <field list>`** — local and deployed differ on at least
|
|
114
|
+
one field in the v1 closed set:
|
|
115
|
+
`metadata.name`, `metadata.team`, `metadata.owner`,
|
|
116
|
+
`metadata.description`, `deployment.type`,
|
|
117
|
+
`access.allowed_entra_group`, `hostnames[0]`, `build.command`,
|
|
118
|
+
`build.destination_dir`, `build.root_dir`, `production_env.*`.
|
|
119
|
+
- **`no deployed manifest yet`** — bot reports no
|
|
120
|
+
`output "<slug>_manifest_sha"`. Run `launchpad deploy` first.
|
|
121
|
+
|
|
122
|
+
### Three-state surfacing
|
|
123
|
+
|
|
124
|
+
Beyond drift, status also surfaces the relationship between the app
|
|
125
|
+
repo's main HEAD sha and the last-applied manifest sha. If HEAD is
|
|
126
|
+
ahead of deployed:
|
|
127
|
+
|
|
128
|
+
- With an open PR → "an apply may be queued (see PR #N)"
|
|
129
|
+
- Without an open PR → "main is ahead of deployed"
|
|
130
|
+
|
|
131
|
+
This is the load-bearing answer to "is my change going to land"
|
|
132
|
+
without polling tf-apply.
|
|
133
|
+
|
|
134
|
+
### Exit codes
|
|
135
|
+
|
|
136
|
+
- **0** — in sync, OR drift in default (report-only) mode.
|
|
137
|
+
- **1** — drift, when `--strict` is set.
|
|
138
|
+
- **2** — error (missing local manifest, network, auth, etc.).
|
|
139
|
+
|
|
140
|
+
The default is report-only so casual interactive use never surprises
|
|
141
|
+
the operator. For CI guards, use `--strict`:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Interactive (default): show drift, exit 0
|
|
145
|
+
launchpad status horizon
|
|
146
|
+
|
|
147
|
+
# CI guard: fail the script if local differs from deployed
|
|
148
|
+
launchpad status --strict horizon && launchpad deploy
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### --json output
|
|
152
|
+
|
|
153
|
+
For downstream scripts (M-1187 destroy, M-1189 update-skill, ad-hoc
|
|
154
|
+
CI):
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
launchpad status horizon --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"state": "drift",
|
|
163
|
+
"slug": "horizon",
|
|
164
|
+
"deployedSha": "<40-hex>",
|
|
165
|
+
"headSha": "<40-hex>",
|
|
166
|
+
"hasOpenPr": true,
|
|
167
|
+
"openPrNumber": 42,
|
|
168
|
+
"driftFields": ["metadata.owner", "production_env.API_BASE"],
|
|
169
|
+
"driftDetails": [
|
|
170
|
+
{ "path": "metadata.owner", "local": "alice@m-kopa.com", "deployed": "bob@m-kopa.com" },
|
|
171
|
+
{ "path": "production_env.API_BASE", "local": "https://new", "deployed": "https://old" }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### production_env secret-shape warning
|
|
177
|
+
|
|
178
|
+
If any `production_env.<KEY>` value matches a basic secret-shape
|
|
179
|
+
heuristic — both a known prefix (`sk-`, `ghp_`, `gho_`, `ghu_`, `AKIA`,
|
|
180
|
+
`xoxb-`, `xoxa-`, `xoxp-`) AND length ≥ 32 in a base64-shaped
|
|
181
|
+
character set — status warns on stderr:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
launchpad status: production_env.OPENAI_KEY looks like a secret.
|
|
185
|
+
production_env is non-secret by contract; move secrets to the
|
|
186
|
+
secrets bindings path. (This is informational; status will continue.)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Warning, not block. If you see this: open `launchpad.yaml`, move the
|
|
190
|
+
secret out of `production_env:` and into the `secrets:` bindings
|
|
191
|
+
section (which gets written via `wrangler secret put`, never via
|
|
192
|
+
git).
|
|
193
|
+
|
|
194
|
+
## Common error patterns + fixes
|
|
195
|
+
|
|
196
|
+
### "session expired, run `launchpad login`"
|
|
197
|
+
|
|
198
|
+
The Cf Access token is gone or stale. Run `launchpad login` once;
|
|
199
|
+
both verbs work after that for the next ~24 hours (Cf Access session
|
|
200
|
+
length).
|
|
201
|
+
|
|
202
|
+
### "not authorised for app X (you must be an owner or editor)"
|
|
203
|
+
|
|
204
|
+
You're not on the app's `owner` or `editor` list, or in the
|
|
205
|
+
break-glass admin group. Either:
|
|
206
|
+
|
|
207
|
+
- Ask the app's current owner to add you as an editor via the portal
|
|
208
|
+
dashboard.
|
|
209
|
+
- If you genuinely need break-glass access for this incident, talk to
|
|
210
|
+
platform-team.
|
|
211
|
+
|
|
212
|
+
### "no deployed manifest for X yet"
|
|
213
|
+
|
|
214
|
+
The app exists in the registry but `tf-apply` hasn't run yet (the
|
|
215
|
+
first deploy may still be queuing) or the apply failed. Check:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
launchpad apps # confirm lifecycle is `live`
|
|
219
|
+
# If lifecycle is `provisioning` or `failed`, use:
|
|
220
|
+
/launchpad-deploy-status # diagnose the M-892 stage trace
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### "drift: hostnames[0]"
|
|
224
|
+
|
|
225
|
+
The hostname changed in your local manifest but the deployed app
|
|
226
|
+
still has the old hostname. This is a manifest-side change — run
|
|
227
|
+
`launchpad deploy` to roll it out. (Hostname changes also require
|
|
228
|
+
edge-auth + cert re-issuance — the gateway hostname/cert for an
|
|
229
|
+
`auth: gateway` app, or the Cf Access app for an `auth: access` one —
|
|
230
|
+
which the bot handles.)
|
|
231
|
+
|
|
232
|
+
### "drift: access.allowed_entra_group"
|
|
233
|
+
|
|
234
|
+
Group binding changed in your local manifest. This is the
|
|
235
|
+
**load-bearing** drift — it controls who can access the app. After
|
|
236
|
+
`launchpad deploy`, the resulting PR will require the
|
|
237
|
+
`allowed-groups-change: true` label from a non-author human reviewer
|
|
238
|
+
(AC-S4) before it can auto-merge.
|
|
239
|
+
|
|
240
|
+
## Related skills
|
|
241
|
+
|
|
242
|
+
- **`/launchpad-deploy`** — provision a new app (uses `launchpad
|
|
243
|
+
create` not `deploy`; see skill for naming history).
|
|
244
|
+
- **`/launchpad-deploy-status`** — interrogate provisioning state
|
|
245
|
+
(M-892 stages). Use during initial provisioning; once the app is
|
|
246
|
+
`live`, `launchpad status` is the daily-use tool.
|
|
247
|
+
- **`/launchpad-content-pr`** — push first content to a freshly
|
|
248
|
+
provisioned app. After the first content lands, `launchpad
|
|
249
|
+
status` is how you check ongoing deploys.
|
|
250
|
+
|
|
251
|
+
## Anti-patterns
|
|
252
|
+
|
|
253
|
+
- **Don't** try `--platform-repo /path/to/clone` — that flag was
|
|
254
|
+
removed in M-1188. Both verbs are bot-relayed; the operator never
|
|
255
|
+
needs a local platform-repo clone.
|
|
256
|
+
- **Don't** parse the prose output of `launchpad status` in CI
|
|
257
|
+
scripts. Use `--json` and `--strict`.
|
|
258
|
+
- **Don't** rely on exit-1 firing without `--strict`. The default
|
|
259
|
+
behaviour is report-only.
|
|
260
|
+
|
|
261
|
+
## Version
|
|
262
|
+
|
|
263
|
+
This skill ships in launchpad-cli v0.13.0+ (M-1188 release).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# marquee-share-skill
|
|
2
|
+
|
|
3
|
+
A Claude Code skill that uploads an AI-chat HTML artefact to
|
|
4
|
+
[Marquee](https://marquee.launchpad.m-kopa.us) `POST /api/uploads`,
|
|
5
|
+
attributed to the **real signed-in user** (not a service token).
|
|
6
|
+
|
|
7
|
+
This directory is a **self-contained Node program**, isolated from the
|
|
8
|
+
Marquee Cloudflare Pages app at the repo root — it has its own
|
|
9
|
+
`package.json`, `tsconfig.json`, ESLint and Vitest config. It is not
|
|
10
|
+
part of the Pages build and does not deploy with the site.
|
|
11
|
+
|
|
12
|
+
The skill runs from a **pre-built, dependency-free bundle**,
|
|
13
|
+
`dist/cli.js`, which needs only Node 22+ — no `tsx`, no runtime
|
|
14
|
+
`node_modules`. `dist/cli.js` is a **committed build artefact**
|
|
15
|
+
(`npm run build` regenerates it). This matters because the skill is
|
|
16
|
+
distributed by file-copy: the Launchpad CLI skills bundle copies
|
|
17
|
+
`skill/` to `~/.claude/skills/marquee-share/` *without* `node_modules`,
|
|
18
|
+
so the built bundle must be present in the tree.
|
|
19
|
+
|
|
20
|
+
The skill is complete: a Claude Code [`SKILL.md`](./SKILL.md) drives a
|
|
21
|
+
CLI that authenticates the user, wraps an AI-chat result in an
|
|
22
|
+
M-KOPA-branded HTML document, uploads it, and returns a shareable
|
|
23
|
+
`view_url`.
|
|
24
|
+
|
|
25
|
+
## How it works
|
|
26
|
+
|
|
27
|
+
A user says *"share this via Marquee"* in a Claude Code session.
|
|
28
|
+
Claude renders the current result to an inner-content HTML fragment
|
|
29
|
+
and runs the `share` command. The command wraps that fragment in the
|
|
30
|
+
branded template, uploads the document to Marquee, and prints the
|
|
31
|
+
`view_url`, which Claude returns to the user.
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
Claude (renders content HTML)
|
|
35
|
+
└─ marquee-share share src/cli.ts
|
|
36
|
+
├─ renderBrandedDocument src/render/template.ts (M-KOPA shell)
|
|
37
|
+
├─ getValidToken src/auth/index.ts (PKCE session)
|
|
38
|
+
└─ POST /api/uploads src/upload/index.ts → view_url
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Install (personal)
|
|
42
|
+
|
|
43
|
+
To use this skill in your own Claude Code, link it into your personal
|
|
44
|
+
skills directory. Claude Code discovers skills by reading `SKILL.md`
|
|
45
|
+
from each subdirectory of `~/.claude/skills/`; the install script
|
|
46
|
+
symlinks `~/.claude/skills/marquee-share` at this `skill/` directory.
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
cd skill
|
|
50
|
+
./install.sh # symlink the skill into ~/.claude/skills/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
No `npm install` is needed to *use* the skill — it runs from the
|
|
54
|
+
committed, dependency-free `dist/cli.js` bundle. (`npm install` is only
|
|
55
|
+
needed to *develop* the skill — see Development below.)
|
|
56
|
+
|
|
57
|
+
`install.sh` is idempotent — re-running it is a no-op once the link is
|
|
58
|
+
in place. Because it is a symlink, the skill you run always reflects
|
|
59
|
+
this checkout: pull the branch and the skill updates with it. Restart
|
|
60
|
+
Claude Code (or open a new session) to pick up the skill.
|
|
61
|
+
|
|
62
|
+
To remove it:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
cd skill
|
|
66
|
+
./install.sh --uninstall
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This is the **personal-developer** install path. M-KOPA-wide
|
|
70
|
+
distribution goes through the Launchpad CLI skills bundle, which
|
|
71
|
+
mirrors this directory as its canonical source.
|
|
72
|
+
|
|
73
|
+
## CLI
|
|
74
|
+
|
|
75
|
+
The skill ships a single command, `marquee-share`, with three
|
|
76
|
+
subcommands. Run the built bundle from this directory:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
node dist/cli.js login # one-time browser sign-in
|
|
80
|
+
node dist/cli.js logout # clear the cached session
|
|
81
|
+
node dist/cli.js share [file] # wrap + upload; prints the view_url
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`share` reads a complete inner-content HTML fragment from `[file]` or,
|
|
85
|
+
when no file is given, from stdin. `--title "<text>"` sets the
|
|
86
|
+
document title. On success it prints **only** the `view_url` to
|
|
87
|
+
stdout; diagnostics go to stderr. On a first run with no session it
|
|
88
|
+
triggers the browser login automatically, then proceeds. The bearer
|
|
89
|
+
token is never printed or logged.
|
|
90
|
+
|
|
91
|
+
`src/cli.ts` is the entrypoint source — a thin dispatcher that wires
|
|
92
|
+
the auth and upload layers together. Its `run()` core takes every side
|
|
93
|
+
effect as an injected dependency, so `tests/cli.test.ts` exercises it
|
|
94
|
+
with fakes (no network, no browser, no real session file).
|
|
95
|
+
|
|
96
|
+
`npm run build` bundles `src/cli.ts` and its imports into a single
|
|
97
|
+
`dist/cli.js` with `bun build --target node`. The skill has zero
|
|
98
|
+
runtime dependencies (auth and upload use only Node built-ins), so the
|
|
99
|
+
bundle is fully self-contained. `dist/cli.js` carries a
|
|
100
|
+
`#!/usr/bin/env node` shebang and is what the installed skill runs.
|
|
101
|
+
|
|
102
|
+
Requires Node `>=22`. The shipped skill runs the built `dist/cli.js`
|
|
103
|
+
under plain Node — no `tsx`, no `node_modules`. `tsx` is a
|
|
104
|
+
devDependency, used only by the `typecheck`/`test` loop below.
|
|
105
|
+
|
|
106
|
+
## Auth layer
|
|
107
|
+
|
|
108
|
+
`src/auth/` is a vendored copy of the Launchpad CLI's Cloudflare
|
|
109
|
+
Access Managed-OAuth / PKCE flow — see
|
|
110
|
+
[`src/auth/PROVENANCE.md`](./src/auth/PROVENANCE.md) for the source
|
|
111
|
+
commit and the Marquee-specific adaptations.
|
|
112
|
+
|
|
113
|
+
The public surface is `src/auth/index.ts`:
|
|
114
|
+
|
|
115
|
+
| Export | Purpose |
|
|
116
|
+
|--------|---------|
|
|
117
|
+
| `login()` | One-time interactive browser PKCE login; persists a session. |
|
|
118
|
+
| `logout()` | Clears the cached session. |
|
|
119
|
+
| `getValidToken()` | Returns a still-valid access token — reuses a cached session while fresh, silently refreshes on expiry, re-logins when the grant has expired. |
|
|
120
|
+
|
|
121
|
+
### Security properties
|
|
122
|
+
|
|
123
|
+
- **PKCE public client** — no client secret is generated, received,
|
|
124
|
+
or stored anywhere in the shipped skill.
|
|
125
|
+
- **Session cached at `~/.marquee/session.json`, mode `0600`**;
|
|
126
|
+
parent dir `0700`. Override the path with `MARQUEE_SESSION_PATH`
|
|
127
|
+
(used by tests). Override the Marquee base URL with
|
|
128
|
+
`MARQUEE_RESOURCE_URL`.
|
|
129
|
+
- **The credential is never logged, echoed, or committed.** The auth
|
|
130
|
+
layer prints only non-secret diagnostics (auth URLs, the session
|
|
131
|
+
file *path*). `tests/no-token-leak.test.ts` enforces this.
|
|
132
|
+
- **No client-side JWT verification.** The skill is an OAuth client:
|
|
133
|
+
it presents the token; Marquee's Pages Functions verify it. (See
|
|
134
|
+
the repo's `ANTI-PATTERNS.md`.)
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
Developing the skill requires [**Bun**](https://bun.sh) installed on
|
|
139
|
+
your `PATH` — `npm run build` invokes `bun build` to produce the
|
|
140
|
+
dependency-free `dist/cli.js` bundle. Bun is a build-time prerequisite
|
|
141
|
+
only; the shipped skill itself runs under plain Node 22+.
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
cd skill
|
|
145
|
+
npm install
|
|
146
|
+
npm run typecheck
|
|
147
|
+
npm run lint
|
|
148
|
+
npm test
|
|
149
|
+
npm run build # regenerate dist/cli.js — commit the result
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`dist/cli.js` is a committed build artefact. Any change under `src/`
|
|
153
|
+
must be followed by `npm run build`, and the regenerated `dist/cli.js`
|
|
154
|
+
committed alongside the source change — the skill is distributed by
|
|
155
|
+
file-copy, so a stale or missing bundle ships a stale or broken skill.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: marquee-share
|
|
3
|
+
description: >-
|
|
4
|
+
Publish the current AI-chat result to Marquee as an M-KOPA-branded,
|
|
5
|
+
shareable web page and return its view URL. Use when the user says
|
|
6
|
+
"share this via Marquee", "share via marquee", "publish this to
|
|
7
|
+
Marquee", "put this on Marquee", or otherwise asks to share or
|
|
8
|
+
publish the current result as a Marquee link.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Marquee share
|
|
12
|
+
|
|
13
|
+
Turn the current chat result into a self-contained, M-KOPA-branded HTML
|
|
14
|
+
page hosted on [Marquee](https://marquee.launchpad.m-kopa.us) and give
|
|
15
|
+
the user back a shareable `view_url`. The page is attributed to the
|
|
16
|
+
real signed-in user (Cloudflare Access), not a service account.
|
|
17
|
+
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
Invoke when the user asks to share or publish the current result to
|
|
21
|
+
Marquee — e.g. "share this via Marquee", "publish this to Marquee".
|
|
22
|
+
|
|
23
|
+
## How to share
|
|
24
|
+
|
|
25
|
+
All commands run from the `skill/` directory and invoke the bundled
|
|
26
|
+
CLI directly with Node — `node dist/cli.js …`. `dist/cli.js` is a
|
|
27
|
+
self-contained build that needs only Node 22+ on PATH; it has no
|
|
28
|
+
runtime dependencies and does not require `npm install` or
|
|
29
|
+
`node_modules/`.
|
|
30
|
+
|
|
31
|
+
1. **Render the result to inner-content HTML.** Take whatever you just
|
|
32
|
+
produced for the user — prose, markdown, a code block, a table, a
|
|
33
|
+
short report — and write it out as clean, valid **HTML fragment**
|
|
34
|
+
(the inner body content only). Guidance:
|
|
35
|
+
- Headings → `<h2>`/`<h3>`; paragraphs → `<p>`; lists → `<ul>`/`<ol>`.
|
|
36
|
+
- Code → `<pre><code>…</code></pre>`; tables → real `<table>` markup.
|
|
37
|
+
- Escape any literal `<`, `>`, `&` that are meant as text.
|
|
38
|
+
- Write **only the content** — do **not** add `<html>`, `<head>`,
|
|
39
|
+
`<body>`, `<style>`, or `<script>`. Do **not** add your own
|
|
40
|
+
colours, fonts, or layout CSS.
|
|
41
|
+
- The white background and M-KOPA green/black branding are applied
|
|
42
|
+
for you by the skill's branded template — the `share` command
|
|
43
|
+
wraps your content in a complete, self-contained M-KOPA document.
|
|
44
|
+
|
|
45
|
+
2. **Run the `share` command**, passing the HTML fragment on stdin and
|
|
46
|
+
a short human title:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
node dist/cli.js share --title "Quarterly summary" < content.html
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
or pipe the HTML directly:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
printf '%s' "$CONTENT_HTML" | node dist/cli.js share --title "Quarterly summary"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `share` command prints **only** the resulting `view_url` to
|
|
59
|
+
stdout. Capture that single line.
|
|
60
|
+
|
|
61
|
+
3. **Return the `view_url`** to the user as the shareable link. Do not
|
|
62
|
+
print anything else from the command's output as the result.
|
|
63
|
+
|
|
64
|
+
## One-time browser sign-in
|
|
65
|
+
|
|
66
|
+
The first time `share` runs on a machine with no Marquee session, it
|
|
67
|
+
opens a browser for a one-time Cloudflare Access sign-in, then
|
|
68
|
+
continues automatically — no separate step needed. The user can also
|
|
69
|
+
sign in ahead of time:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
node dist/cli.js login
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The session is cached locally (`~/.marquee/session.json`, mode `0600`)
|
|
76
|
+
and refreshed silently. The skill never prints or logs the token.
|
|
77
|
+
|
|
78
|
+
To sign out:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
node dist/cli.js logout
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Notes
|
|
85
|
+
|
|
86
|
+
- Requires Node `>=22`. No `npm install` is needed to run the skill —
|
|
87
|
+
`dist/cli.js` is a pre-built, dependency-free bundle.
|
|
88
|
+
- This skill is installed by symlinking `~/.claude/skills/marquee-share`
|
|
89
|
+
at the repo's `skill/` directory — see `skill/install.sh` and
|
|
90
|
+
`skill/README.md` for the install/uninstall steps.
|
|
91
|
+
- `dist/cli.js` is a committed build artefact. After changing anything
|
|
92
|
+
under `src/`, regenerate it with `npm run build` in `skill/`.
|
|
93
|
+
- If `share` exits non-zero, it prints a short `error: …` line on
|
|
94
|
+
stderr — report that to the user; do not retry blindly.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Vendored skill — DO NOT EDIT BY HAND
|
|
2
|
+
|
|
3
|
+
This directory is a **mirror** of the `marquee-share` skill. Its
|
|
4
|
+
canonical source is the `M-KOPA/marquee` repository, under `skill/`.
|
|
5
|
+
|
|
6
|
+
It is vendored here so `launchpad skills install` can copy a working
|
|
7
|
+
skill into `~/.claude/skills/` straight from the published
|
|
8
|
+
`@m-kopa/launchpad-cli` npm package.
|
|
9
|
+
|
|
10
|
+
## Provenance
|
|
11
|
+
|
|
12
|
+
- source repo: `M-KOPA/marquee`
|
|
13
|
+
- source path: `skill/`
|
|
14
|
+
- source commit: `eb8261a621244667edc23d80850d5c39c1b54ee4`
|
|
15
|
+
- synced by: `packages/launchpad-cli/scripts/sync-marquee-share-skill.sh`
|
|
16
|
+
|
|
17
|
+
## Updating
|
|
18
|
+
|
|
19
|
+
Do **not** edit files in this directory directly — changes will be
|
|
20
|
+
overwritten and will drift from the canonical source. To pull a new
|
|
21
|
+
version of the skill:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
packages/launchpad-cli/scripts/sync-marquee-share-skill.sh <marquee-checkout> [ref]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
then review the diff and commit. Run this at marquee-share release time.
|