@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,69 @@
|
|
|
1
|
+
import type { CliIo, Command } from "./dispatcher.js";
|
|
2
|
+
import { resolveLatestVersion, type InstallChannel } from "./commands/update.js";
|
|
3
|
+
/** Internal verb the detached refresh process runs. Hidden from help. */
|
|
4
|
+
export declare const INTERNAL_REFRESH_VERB = "__refresh-update-cache";
|
|
5
|
+
/** Re-check the registry at most once per this window (24h). */
|
|
6
|
+
export declare const CHECK_INTERVAL_MS: number;
|
|
7
|
+
/** Persisted shape of {@link CACHE_FILE}. */
|
|
8
|
+
export interface CacheState {
|
|
9
|
+
/** `Date.now()` at the last completed refresh (success OR failure). */
|
|
10
|
+
readonly checkedAt: number;
|
|
11
|
+
/** Latest version last seen, or null if never successfully fetched. */
|
|
12
|
+
readonly latest: string | null;
|
|
13
|
+
}
|
|
14
|
+
/** Read + parse the cache file; null on any error (missing/corrupt). */
|
|
15
|
+
export declare function readCache(): CacheState | null;
|
|
16
|
+
/** Write the cache file (0600), creating ~/.launchpad if needed. Best-effort. */
|
|
17
|
+
export declare function writeCache(state: CacheState): void;
|
|
18
|
+
/** Context derived from the running process, passed in for testability. */
|
|
19
|
+
export interface NotifyContext {
|
|
20
|
+
readonly argv: readonly string[];
|
|
21
|
+
readonly env: NodeJS.ProcessEnv;
|
|
22
|
+
readonly stderrIsTTY: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Injectable surface so the core is testable without fs/clock/spawn. */
|
|
25
|
+
export interface NotifierDeps {
|
|
26
|
+
readonly cliVersion: string;
|
|
27
|
+
readonly channel: () => InstallChannel;
|
|
28
|
+
readonly readCache: () => CacheState | null;
|
|
29
|
+
readonly now: () => number;
|
|
30
|
+
/** Kick off the detached background refresh (no-op in tests). */
|
|
31
|
+
readonly spawnRefresh: () => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Should the notifier stay silent entirely (no notice, no refresh)?
|
|
35
|
+
* Keeps the CLI quiet in every non-interactive / machine context.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isSuppressed(ctx: NotifyContext): boolean;
|
|
38
|
+
/** The one-line, channel-appropriate notice. */
|
|
39
|
+
export declare function noticeLine(current: string, latest: string, channel: InstallChannel): string;
|
|
40
|
+
/**
|
|
41
|
+
* Core notifier: print a cached notice if a newer version is known, and
|
|
42
|
+
* trigger a background refresh when the cache is stale. Synchronous and
|
|
43
|
+
* allocation-light on the hot path; the only async work (the network)
|
|
44
|
+
* happens in the detached process `spawnRefresh` launches.
|
|
45
|
+
*/
|
|
46
|
+
export declare function maybeNotify(io: CliIo, ctx: NotifyContext, deps: NotifierDeps): void;
|
|
47
|
+
/**
|
|
48
|
+
* Entry point for the bin wrapper, invoked AFTER the command resolves.
|
|
49
|
+
* Builds the real deps from `process.*` and runs the core, fully
|
|
50
|
+
* guarded so a notifier fault can never affect the command's result.
|
|
51
|
+
*/
|
|
52
|
+
export declare function notifyAfterCommand(io: CliIo, argv: readonly string[], cliPath?: string | undefined): void;
|
|
53
|
+
/** Injectable surface for {@link refreshUpdateCache}. */
|
|
54
|
+
export interface RefreshDeps {
|
|
55
|
+
readonly resolveLatestVersion: typeof resolveLatestVersion;
|
|
56
|
+
readonly readCache: () => CacheState | null;
|
|
57
|
+
readonly writeCache: (s: CacheState) => void;
|
|
58
|
+
readonly now: () => number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Refresh the cached latest-version marker. Always bumps `checkedAt`
|
|
62
|
+
* (success OR failure) so a flaky/offline registry backs off for the
|
|
63
|
+
* full interval rather than re-spawning on every command; preserves the
|
|
64
|
+
* previously-seen `latest` on failure.
|
|
65
|
+
*/
|
|
66
|
+
export declare function refreshUpdateCache(deps?: RefreshDeps): Promise<void>;
|
|
67
|
+
/** Hidden command: the detached background refresh. Not shown in help. */
|
|
68
|
+
export declare const refreshUpdateCacheCommand: Command;
|
|
69
|
+
//# sourceMappingURL=update-notifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-notifier.d.ts","sourceRoot":"","sources":["../src/update-notifier.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAIL,oBAAoB,EACpB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAE9B,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAE9D,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,QAAsB,CAAC;AAQrD,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wEAAwE;AACxE,wBAAgB,SAAS,IAAI,UAAU,GAAG,IAAI,CAkB7C;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAOlD;AAID,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,cAAc,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAQxD;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,cAAc,GACtB,MAAM,CAMR;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,KAAK,EACT,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,YAAY,GACjB,IAAI,CAcN;AAwBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,KAAK,EACT,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE,MAAM,GAAG,SAA2B,GAC5C,IAAI,CAoBN;AAID,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,UAAU,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;CAC5B;AASD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,WAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CASf;AAED,0EAA0E;AAC1E,eAAO,MAAM,yBAAyB,EAAE,OAQvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,WAAW,WAAW,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@m-kopa/launchpad-cli",
|
|
3
|
+
"version": "0.23.0",
|
|
4
|
+
"description": "Launchpad CLI — clone / deploy / review / merge against Launchpad-managed apps. Talks to the portal-bot endpoints (SCOPE-M-760 / T4).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"launchpad": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"skills",
|
|
12
|
+
"README.md",
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"registry": "https://registry.npmjs.org",
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/M-KOPA/launchpad-platform.git",
|
|
26
|
+
"directory": "packages/launchpad-cli"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/M-KOPA/launchpad-platform/tree/main/packages/launchpad-cli#readme",
|
|
29
|
+
"license": "UNLICENSED",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"esbuild": "0.27.3",
|
|
32
|
+
"yaml": "2.9.0",
|
|
33
|
+
"zod": "4.4.3"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "22.18.10",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "8.46.4",
|
|
38
|
+
"@typescript-eslint/parser": "8.46.4",
|
|
39
|
+
"@vitest/coverage-istanbul": "4.1.5",
|
|
40
|
+
"eslint": "9.39.4",
|
|
41
|
+
"typescript": "5.9.3",
|
|
42
|
+
"vitest": "4.1.5",
|
|
43
|
+
"@m-kopa/launchpad-engine": "workspace:*"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "rm -rf dist && bun build src/cli.ts src/postinstall.ts --target=node --outdir=dist --external yaml --external zod --external esbuild --external '@m-kopa/platform-auth' && chmod +x dist/cli.js && tsc -p tsconfig.build.json --emitDeclarationOnly --declarationDir dist",
|
|
47
|
+
"postinstall": "node dist/postinstall.js",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:watch": "vitest",
|
|
50
|
+
"lint": "eslint src tests",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"check:version-sync": "bash scripts/check-version-sync.sh",
|
|
53
|
+
"check:installer-syntax": "bash scripts/check-installer-syntax.sh",
|
|
54
|
+
"check:skill-contract": "bash scripts/sync-skill-contract.sh --check",
|
|
55
|
+
"check:skill-bash-dialect": "bash scripts/check-skill-bash-dialect.sh",
|
|
56
|
+
"check:skill-bash-parse": "bash scripts/check-skill-bash-parse.sh",
|
|
57
|
+
"check:skills": "bun run check:skill-contract && bun run check:skill-bash-dialect && bun run check:skill-bash-parse",
|
|
58
|
+
"sync:skill-contract": "bash scripts/sync-skill-contract.sh write",
|
|
59
|
+
"version:patch": "npm version patch --no-git-tag-version",
|
|
60
|
+
"version:minor": "npm version minor --no-git-tag-version"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Launchpad Claude Code skill bundle
|
|
2
|
+
|
|
3
|
+
This directory ships the Claude Code slash-commands that
|
|
4
|
+
`launchpad skills install` copies into `~/.claude/skills/`.
|
|
5
|
+
|
|
6
|
+
```text
|
|
7
|
+
skills/
|
|
8
|
+
├── _partials/
|
|
9
|
+
│ └── shell-contract.md # single source of truth for the
|
|
10
|
+
│ # Shell Contract block at the top
|
|
11
|
+
│ # of every launchpad-* SKILL.md
|
|
12
|
+
├── launchpad-onboard/SKILL.md
|
|
13
|
+
├── launchpad-deploy/SKILL.md
|
|
14
|
+
├── launchpad-deploy-status/SKILL.md
|
|
15
|
+
├── launchpad-content-pr/SKILL.md
|
|
16
|
+
├── launchpad-status/SKILL.md
|
|
17
|
+
├── launchpad-destroy/SKILL.md
|
|
18
|
+
└── marquee-share/ # vendored from M-KOPA/marquee, do
|
|
19
|
+
# not hand-edit — managed by
|
|
20
|
+
# scripts/sync-marquee-share-skill.sh
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Cross-platform shell contract
|
|
24
|
+
|
|
25
|
+
Claude Code's `Bash` tool **always** runs `bash`, on every OS — on
|
|
26
|
+
Windows it resolves to Git for Windows / MSYS bash. Skills that
|
|
27
|
+
contain bash blocks must be unambiguously bash, because models will
|
|
28
|
+
otherwise sometimes transliterate to PowerShell on Windows and the
|
|
29
|
+
bash tool will then fail with `/usr/bin/bash: syntax error`.
|
|
30
|
+
|
|
31
|
+
To make this explicit, each `launchpad-*` SKILL.md starts with a
|
|
32
|
+
**Shell contract** preamble that tells the agent not to translate:
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
<!-- BEGIN shell-contract (managed by …) -->
|
|
36
|
+
## Shell contract — read this first
|
|
37
|
+
|
|
38
|
+
Every fenced `bash` block below MUST be sent to the `Bash` tool
|
|
39
|
+
verbatim. Do not rewrite into PowerShell, cmd, …
|
|
40
|
+
<!-- END shell-contract -->
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The canonical body lives at `_partials/shell-contract.md`. **Do not
|
|
44
|
+
edit the copies in the four launchpad-* SKILL.md files directly** —
|
|
45
|
+
edit the partial, then run:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bun run sync:skill-contract
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
CI (`bun run check:skills`) fails if any SKILL.md drifts from the
|
|
52
|
+
partial, contains a PowerShell token inside a bash fence, or fails
|
|
53
|
+
`bash -n` parse.
|
|
54
|
+
|
|
55
|
+
## Versioning
|
|
56
|
+
|
|
57
|
+
The `version:` frontmatter line in each `launchpad-*/SKILL.md` is
|
|
58
|
+
**stamped** from `package.json` by `scripts/sync-skill-contract.sh`.
|
|
59
|
+
Do not hand-bump it.
|
|
60
|
+
|
|
61
|
+
Workflow:
|
|
62
|
+
|
|
63
|
+
1. Bump `package.json` (`bun run version:patch` / `:minor`) and
|
|
64
|
+
`src/version.ts`'s `CLI_VERSION`.
|
|
65
|
+
2. Run `bun run sync:skill-contract` — this rewrites each SKILL.md's
|
|
66
|
+
`version:` line and re-stamps the Shell Contract block.
|
|
67
|
+
3. Commit the result.
|
|
68
|
+
|
|
69
|
+
CI gate `bun run check:skills` will reject the PR if step 2 was
|
|
70
|
+
skipped (the rendered SKILL.md disagrees with the partial or the
|
|
71
|
+
package.json version).
|
|
72
|
+
|
|
73
|
+
## Authoring guidance
|
|
74
|
+
|
|
75
|
+
When you write or edit a `launchpad-*` SKILL.md, follow these rules.
|
|
76
|
+
They keep the bash blocks portable to Git Bash on Windows without
|
|
77
|
+
forking the skill into per-OS versions.
|
|
78
|
+
|
|
79
|
+
| Do | Don't |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `"$HOME/.launchpad/session.json"` | `~/.launchpad/session.json` (parses fine, but visually nudges the agent toward `$env:USERPROFILE`) |
|
|
82
|
+
| `"$TOKEN"`, `"$BOT"` (quoted) | bare `$TOKEN`, `$BOT` |
|
|
83
|
+
| `${TMPDIR:-/tmp}/foo` | `/tmp/foo` (Git Bash needs `$TMPDIR`) |
|
|
84
|
+
| `case "$(uname -s)" in …` | per-OS prose ("on macOS … on Linux …") |
|
|
85
|
+
| `[ -n "$VAR" ] \|\| { echo …; exit 1; }` for nullable inputs | unchecked `$(jq -r .field file)` pipes |
|
|
86
|
+
| `gh auth status --hostname github.com` | `gh auth status` (lenient about which host) |
|
|
87
|
+
|
|
88
|
+
Forbidden tokens (CI grep blocks these inside ```bash``` fences):
|
|
89
|
+
`Test-Path`, `Get-Content`, `Get-ChildItem`, `Where-Object`,
|
|
90
|
+
`Write-Output`, `Write-Host`, `$env:`, `Set-Location`, `New-Item`,
|
|
91
|
+
`Remove-Item`. Update the list in `scripts/check-skill-bash-dialect.sh`
|
|
92
|
+
and `tests/skill-contract.test.ts` together if you need to extend it.
|
|
93
|
+
|
|
94
|
+
## Why not ship a PowerShell version of each skill?
|
|
95
|
+
|
|
96
|
+
The audience is Claude Code users, and Claude Code's `Bash` tool runs
|
|
97
|
+
bash. There is no audience for a PowerShell version of these skills.
|
|
98
|
+
Per-OS forks would also double the maintenance burden and risk drift
|
|
99
|
+
between variants. One skill, one shell, OS-branched inside bash with
|
|
100
|
+
`case "$(uname -s)"` where it actually matters.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
shell-contract.md — single source of truth for the "Shell contract"
|
|
3
|
+
preamble that every launchpad-* skill must carry verbatim.
|
|
4
|
+
|
|
5
|
+
Why this exists: Claude Code's `Bash` tool always invokes `bash`,
|
|
6
|
+
even on Windows (where it resolves to Git for Windows / MSYS bash).
|
|
7
|
+
Without an explicit contract, models will sometimes transliterate
|
|
8
|
+
the fenced bash blocks into PowerShell on Windows ("$env:USERPROFILE",
|
|
9
|
+
Test-Path, Get-Content, etc.), which then fails with a confusing
|
|
10
|
+
`/usr/bin/bash: syntax error` because the bash tool is still what
|
|
11
|
+
runs the command.
|
|
12
|
+
|
|
13
|
+
The block below is short and imperative on purpose — models follow
|
|
14
|
+
brief rules far better than verbose ones. Edit cautiously; CI
|
|
15
|
+
asserts that the rendered block in each SKILL.md is byte-identical
|
|
16
|
+
to this file (scripts/check-skill-contract.sh).
|
|
17
|
+
|
|
18
|
+
Do NOT edit the launchpad-*/SKILL.md copies of this block directly.
|
|
19
|
+
Edit this file, then run `bun run sync:skill-contract` to re-stamp
|
|
20
|
+
the four launchpad-* skills.
|
|
21
|
+
-->
|
|
22
|
+
## Shell contract — read this first
|
|
23
|
+
|
|
24
|
+
Every fenced `bash` block below MUST be sent to the `Bash` tool **verbatim**.
|
|
25
|
+
Do not rewrite into PowerShell, cmd, zsh-isms, or "equivalent" forms.
|
|
26
|
+
|
|
27
|
+
- macOS / Linux: the `Bash` tool runs system bash.
|
|
28
|
+
- Windows: the `Bash` tool runs Git for Windows (MSYS) bash. `$HOME`,
|
|
29
|
+
forward slashes, `test -f`, `command -v`, heredocs, and `[[ … ]]` all
|
|
30
|
+
work. There is no reason to translate to `Test-Path`, `$env:USERPROFILE`,
|
|
31
|
+
`Get-Content`, `Where-Object`, `Get-ChildItem`, or backslash paths —
|
|
32
|
+
doing so will fail with `/usr/bin/bash: syntax error`.
|
|
33
|
+
|
|
34
|
+
If a step genuinely needs OS branching, branch *inside* bash:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
case "$(uname -s)" in
|
|
38
|
+
Darwin) : ;;
|
|
39
|
+
Linux) : ;;
|
|
40
|
+
MINGW*|MSYS*|CYGWIN*) : ;;
|
|
41
|
+
esac
|
|
42
|
+
```
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: launchpad-content-pr
|
|
3
|
+
description: Push a content change to a Launchpad app via `launchpad deploy` and verify it shipped via `launchpad status`. Covers the post-first-deploy iteration loop (edit → deploy → verify) and the stack-fit pre-flight that the bot enforces server-side. Use when someone says "push a content change", "ship an update", "/launchpad-content-pr", "verify my deploy", or after `/launchpad-deploy` reports `done` and they want to follow up with an edit.
|
|
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-content-pr
|
|
32
|
+
|
|
33
|
+
Push a content change to an already-provisioned Launchpad app, then
|
|
34
|
+
verify it shipped.
|
|
35
|
+
|
|
36
|
+
Under Model A the first deploy and the first content are the same
|
|
37
|
+
event — `launchpad init` + `launchpad deploy` from the user's CWD
|
|
38
|
+
opens a PR that contains their working tree, the bot waits for the
|
|
39
|
+
Cloudflare Pages deployment to come up green (`deployment_verified`
|
|
40
|
+
lifecycle gate), and the lifecycle flips to `live`. There is no
|
|
41
|
+
separate "now push content" step.
|
|
42
|
+
|
|
43
|
+
This skill is therefore the **iteration** companion to
|
|
44
|
+
`/launchpad-deploy`: once an app is live, how do you ship the next
|
|
45
|
+
change? It is also the canonical place to find the stack-fit
|
|
46
|
+
pre-flight (the rules the bot enforces server-side on every bundle).
|
|
47
|
+
|
|
48
|
+
## Pre-flight
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
launchpad whoami
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If that fails, run `/launchpad-onboard` first. You also need to be
|
|
55
|
+
an owner or editor on the slug — `launchpad apps` lists every app
|
|
56
|
+
the caller can see along with the role per app.
|
|
57
|
+
|
|
58
|
+
## Confirm the app is live
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
launchpad apps
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Look for the slug in the `live` lifecycle bucket. If it's in
|
|
65
|
+
`provisioning` / `failed` / `destroying` / `destroyed`, the
|
|
66
|
+
iteration loop is not the right tool — route to
|
|
67
|
+
`/launchpad-deploy-status` (in-flight) or `/launchpad-destroy`
|
|
68
|
+
(teardown) instead.
|
|
69
|
+
|
|
70
|
+
## Edit and ship
|
|
71
|
+
|
|
72
|
+
The iteration loop is two verbs:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# 1. Edit your working tree.
|
|
76
|
+
|
|
77
|
+
# 2. Ship it.
|
|
78
|
+
launchpad deploy --message "<one-line description>"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The CLI bundles the CWD (using `git ls-files -co --exclude-standard`
|
|
82
|
+
where available; falling back to a pure-FS walker honouring
|
|
83
|
+
`.gitignore` and a default-ignore set), gzips it, uploads to the
|
|
84
|
+
bot, and the bot opens a content PR on `launchpad-app-<slug>`.
|
|
85
|
+
Cloudflare Pages auto-deploys on merge to `main`; the bot waits for
|
|
86
|
+
the deploy to come up green via the `deployment_verified` lifecycle
|
|
87
|
+
gate before reporting `done`.
|
|
88
|
+
|
|
89
|
+
Common flags:
|
|
90
|
+
|
|
91
|
+
- **`--slug <slug>`** — explicit override. Defaults to the slug from
|
|
92
|
+
`./launchpad.yaml`, or the cwd-name parse if you're in a
|
|
93
|
+
`launchpad-app-<slug>/` clone.
|
|
94
|
+
- **`--message <text>`** — threaded as the PR description. Useful
|
|
95
|
+
for change logs and audit trails.
|
|
96
|
+
- **`--file <path>`** — point at a non-default manifest path.
|
|
97
|
+
|
|
98
|
+
Exit codes:
|
|
99
|
+
|
|
100
|
+
- **0** — content PR opened + Cloudflare Pages deployment verified.
|
|
101
|
+
- **non-zero** — see `/launchpad-deploy-status <slug>` for the
|
|
102
|
+
failure reason.
|
|
103
|
+
|
|
104
|
+
## Stack-fit — what the bot enforces server-side
|
|
105
|
+
|
|
106
|
+
The bot rejects bundles that contain shapes the Cloudflare Pages +
|
|
107
|
+
Workers runtime cannot host. The validation runs on every
|
|
108
|
+
`launchpad deploy`; you do not need to pre-flight it locally, but
|
|
109
|
+
**knowing what's enforced saves the round-trip when a bundle is
|
|
110
|
+
going to fail**.
|
|
111
|
+
|
|
112
|
+
The accepted Launchpad stack is the single source of truth in:
|
|
113
|
+
|
|
114
|
+
- `launchpad-platform/ARCHITECTURE.md § Tech Stack`
|
|
115
|
+
- `launchpad-platform/PATTERNS.md § Approved Libraries`
|
|
116
|
+
- `launchpad-platform/ANTI-PATTERNS.md`
|
|
117
|
+
|
|
118
|
+
### Forbidden runtime dependencies
|
|
119
|
+
|
|
120
|
+
The bot rejects bundles whose `package.json` declares any of these
|
|
121
|
+
runtime dependencies — they do not work in the Workers runtime
|
|
122
|
+
without a non-trivial port:
|
|
123
|
+
|
|
124
|
+
| Forbidden | Replacement on Launchpad |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `fastify` / `express` / `koa` / `hapi` / `@nestjs/*` | `hono` mounted at `functions/api/[[path]].ts` — the only server framework (PATTERNS.md). |
|
|
127
|
+
| `better-sqlite3` / native `sqlite3` | Cloudflare D1 binding (`wrangler.toml [[d1_databases]]`). |
|
|
128
|
+
| `pg` / `mysql2` / `mongodb` / `mongoose` / `redis` / `ioredis` | Neon (Postgres over HTTP) or another HTTP-driver backend. Native TCP drivers do not work in the Workers runtime. |
|
|
129
|
+
| `dotenv` | `c.env.*` bindings; `wrangler secret put` (or `launchpad envvars` / `launchpad secrets push`) for secrets. |
|
|
130
|
+
| `pm2` / `forever` / `nodemon` | Cloudflare Cron Triggers (`wrangler.toml [triggers] crons`). |
|
|
131
|
+
|
|
132
|
+
### Forbidden top-level files
|
|
133
|
+
|
|
134
|
+
The bot rejects bundles whose root contains any of these (on non-
|
|
135
|
+
container app-types):
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
Dockerfile · docker-compose.yml · docker-compose.yaml · nginx.conf
|
|
139
|
+
pm2.config.js · ecosystem.config.js · Procfile
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Their presence is the smoking gun that the app was copied from a
|
|
143
|
+
long-running-server stack without removing the legacy infra.
|
|
144
|
+
|
|
145
|
+
### Forbidden source patterns
|
|
146
|
+
|
|
147
|
+
The bot's secret-scan + build-command policy rejects bundles where
|
|
148
|
+
the source tree contains:
|
|
149
|
+
|
|
150
|
+
- `process.env.X` / `process.env['X']` reads — switch to `c.env.*`
|
|
151
|
+
bindings.
|
|
152
|
+
- `setInterval` / `setTimeout` daemons — Workers do not run between
|
|
153
|
+
requests; use Cron Triggers for periodic work.
|
|
154
|
+
- High-signal secret patterns (AWS access keys, GitHub PATs / OAuth
|
|
155
|
+
/ app tokens, Slack tokens, SSH/RSA/EC/PGP keys, generic
|
|
156
|
+
`api_key` shapes). These never belong in a bundle — push them
|
|
157
|
+
through `launchpad secrets push` instead.
|
|
158
|
+
|
|
159
|
+
### `react+api` requires `nodejs_compat`
|
|
160
|
+
|
|
161
|
+
The bot checks that `wrangler.toml` declares
|
|
162
|
+
`compatibility_flags = ["nodejs_compat"]` for any `react+api` app
|
|
163
|
+
(ADR-0011 carve-out).
|
|
164
|
+
|
|
165
|
+
### Verifying locally before you ship
|
|
166
|
+
|
|
167
|
+
The CLI ships an offline validator that catches the schema-level
|
|
168
|
+
issues without uploading anything:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
launchpad validate
|
|
172
|
+
launchpad plan
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Neither verb talks to the bot. Catch what you can locally; the bot
|
|
176
|
+
catches the rest server-side.
|
|
177
|
+
|
|
178
|
+
## Verify after merge
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
launchpad status <slug>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Three possible states (see `/launchpad-status` for the canonical
|
|
185
|
+
reference):
|
|
186
|
+
|
|
187
|
+
- **`in sync`** — local matches deployed; the deploy landed and
|
|
188
|
+
`deployment_verified` is green. You're done.
|
|
189
|
+
- **`drift: <fields>`** — your local manifest diverges from what was
|
|
190
|
+
deployed. Either re-run `launchpad deploy` to ship the local, or
|
|
191
|
+
`launchpad pull <slug> --out launchpad.yaml` to bring the local
|
|
192
|
+
into line with deployed.
|
|
193
|
+
- **`no deployed manifest yet`** — the deploy is still in flight or
|
|
194
|
+
failed. Re-check in a minute, or run `/launchpad-deploy-status
|
|
195
|
+
<slug>`.
|
|
196
|
+
|
|
197
|
+
You can also point a browser at `https://<slug>.launchpad.m-kopa.us`
|
|
198
|
+
once status reports `in sync`. An SSO gate sits in front of the app:
|
|
199
|
+
for a gateway-fronted app (the default, `auth: gateway`) expect a
|
|
200
|
+
redirect to the Entra-OIDC gateway (Microsoft sign-in) on the first
|
|
201
|
+
request; for an `auth: access` app expect a redirect to
|
|
202
|
+
`*.cloudflareaccess.com`. Either way you land on your app after sign-in.
|
|
203
|
+
|
|
204
|
+
If the URL serves the wrong thing:
|
|
205
|
+
|
|
206
|
+
- **`200 OK` with no SSO redirect** → the edge gate is missing or
|
|
207
|
+
open. Check the app's auth (gateway KV entry, or the Access policy
|
|
208
|
+
via the portal admin UI); the
|
|
209
|
+
access-lockout runbook lives in
|
|
210
|
+
`launchpad-platform/docs/runbooks/access-lockout.md`.
|
|
211
|
+
- **`404`** → Pages deploy hasn't finished, or build failed. Run
|
|
212
|
+
`launchpad status <slug> --json` to see the most recent error.
|
|
213
|
+
- **`5xx` from Cloudflare** → wait + retry; cert issuance can lag a
|
|
214
|
+
few minutes on a brand-new hostname.
|
|
215
|
+
|
|
216
|
+
## Ongoing-deploy verbs
|
|
217
|
+
|
|
218
|
+
Once you've shipped first content, the daily-use verbs are:
|
|
219
|
+
|
|
220
|
+
- **`launchpad status`** (`/launchpad-status`) — is my local
|
|
221
|
+
`launchpad.yaml` in sync with what's deployed?
|
|
222
|
+
- **`launchpad pull <slug>`** (`/launchpad-status`) — read the
|
|
223
|
+
currently-deployed `launchpad.yaml`.
|
|
224
|
+
- **`launchpad deploy`** — package the working tree + open an
|
|
225
|
+
update PR via the bot.
|
|
226
|
+
- **`launchpad envvars`** — list / set / remove non-secret
|
|
227
|
+
production env vars.
|
|
228
|
+
- **`launchpad secrets push`** — push secrets (never via git).
|
|
229
|
+
- **`launchpad logs <slug>`** — recent Cloudflare Pages deployment
|
|
230
|
+
history.
|
|
231
|
+
- **`launchpad rollback`** — revert manifest to a prior git SHA +
|
|
232
|
+
re-apply.
|
|
233
|
+
|
|
234
|
+
## Don'ts
|
|
235
|
+
|
|
236
|
+
- Do **not** shell out to `gh`, `jq`, `curl`, or `git` from this
|
|
237
|
+
skill. Every step is a `launchpad` verb. External users without
|
|
238
|
+
M-KOPA GitHub access need this skill to work end-to-end on the
|
|
239
|
+
CLI alone.
|
|
240
|
+
- Do **not** open content PRs by hand against the app repo — the
|
|
241
|
+
bot's bootstrap ruleset gates auto-merge, and a hand-rolled PR
|
|
242
|
+
bypasses the bundle scan, secret-scan, and build-command policy.
|
|
243
|
+
Use `launchpad deploy`.
|
|
244
|
+
- Do **not** treat the stack-fit pre-flight as something the user
|
|
245
|
+
re-implements locally. The bot enforces it server-side on every
|
|
246
|
+
bundle; the playbook describes what's enforced, not how to
|
|
247
|
+
re-implement it.
|
|
248
|
+
- Do **not** force-merge if the bot's PR checks are red. The
|
|
249
|
+
bundle-policy / secret-scan / build-command checks are detecting
|
|
250
|
+
real things; surface the failure verbatim and let the user fix
|
|
251
|
+
the bundle.
|
|
252
|
+
- Do **not** edit `launchpad.yaml`'s `production_env:` block to
|
|
253
|
+
contain secret values. That block is non-secret by contract;
|
|
254
|
+
`launchpad status` warns when a value looks like a secret. Use
|
|
255
|
+
`launchpad secrets push` for the real secret path.
|