@m-kopa/launchpad-cli 0.27.5 → 0.28.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 +20 -0
- package/dist/cli.js +238 -2
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/telemetry.d.ts +84 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/skills/launchpad-content-pr/SKILL.md +1 -1
- package/skills/launchpad-deploy/SKILL.md +1 -1
- package/skills/launchpad-deploy-status/SKILL.md +1 -1
- package/skills/launchpad-destroy/SKILL.md +1 -1
- package/skills/launchpad-onboard/SKILL.md +1 -1
- package/skills/launchpad-status/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html);
|
|
7
7
|
pre-1.0 minor bumps may carry breaking changes per ADR 0005.
|
|
8
8
|
|
|
9
|
+
## 0.28.0 — 2026-06-17
|
|
10
|
+
|
|
11
|
+
PostHog usage telemetry (sp-phcli2).
|
|
12
|
+
|
|
13
|
+
- The CLI now records one anonymous/signed-in `command_run` event per command
|
|
14
|
+
(command name, exit code, duration, CLI version, OS, Node version, `ci`,
|
|
15
|
+
`environment`) so the platform team can see usage and failures. Identified by
|
|
16
|
+
your M-KOPA email when signed in, by a local anonymous device-id otherwise.
|
|
17
|
+
- **Never sends your data:** a fixed allowlist means command arguments, paths,
|
|
18
|
+
env, secrets, repo/app names, and group ids can **not** be transmitted — only
|
|
19
|
+
the fields above. Email is the only PII, and only on signed-in events.
|
|
20
|
+
- **Never slows or breaks a command:** the event is delivered by a detached,
|
|
21
|
+
`unref`'d background process after the command finishes (the same pattern as
|
|
22
|
+
the update check), bounded by a timeout and fully fail-silent.
|
|
23
|
+
- This is internal staff tooling: telemetry is **on by default and cannot be
|
|
24
|
+
disabled** (`DO_NOT_TRACK` is not honored) — see the new
|
|
25
|
+
[usage analytics](https://get.launchpad.m-kopa.us/docs/concepts/telemetry)
|
|
26
|
+
disclosure page and ADR 0027 / the ADR 0014 amendment. A one-time notice is
|
|
27
|
+
printed on first interactive run.
|
|
28
|
+
|
|
9
29
|
## 0.27.5 — 2026-06-16
|
|
10
30
|
|
|
11
31
|
Post-deploy verification — `launchpad deploy` confirms the live deployment
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var CLI_VERSION = "0.
|
|
22
|
+
var CLI_VERSION = "0.28.0";
|
|
23
23
|
|
|
24
24
|
// src/config.ts
|
|
25
25
|
import * as os from "node:os";
|
|
@@ -11603,6 +11603,234 @@ var refreshUpdateCacheCommand = {
|
|
|
11603
11603
|
}
|
|
11604
11604
|
};
|
|
11605
11605
|
|
|
11606
|
+
// src/telemetry.ts
|
|
11607
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
11608
|
+
import { homedir as homedir5 } from "node:os";
|
|
11609
|
+
import { join as join16 } from "node:path";
|
|
11610
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync20, writeFileSync as writeFileSync9 } from "node:fs";
|
|
11611
|
+
import { randomUUID } from "node:crypto";
|
|
11612
|
+
var INTERNAL_EMIT_VERB = "__emit-telemetry";
|
|
11613
|
+
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
11614
|
+
var POSTHOG_PROJECT_KEY = "phc_D4FKJnWb7wWGCWs8NoTpQ2xFGFd4jQt698pQ68BrdcXt";
|
|
11615
|
+
var CAPTURE_PATH = "/i/v0/e/";
|
|
11616
|
+
var SEND_TIMEOUT_MS = 3000;
|
|
11617
|
+
var APP = "launchpad-cli";
|
|
11618
|
+
var DEVICE_ID_FILE = join16(homedir5(), ".launchpad", "telemetry-id.json");
|
|
11619
|
+
var FIRST_RUN_MARKER = join16(homedir5(), ".launchpad", "telemetry-notice-shown");
|
|
11620
|
+
function buildEvent(ctx, identity, nowMs) {
|
|
11621
|
+
const properties = {
|
|
11622
|
+
app: APP,
|
|
11623
|
+
command: ctx.command,
|
|
11624
|
+
exit_code: ctx.exitCode,
|
|
11625
|
+
duration_ms: ctx.durationMs,
|
|
11626
|
+
cli_version: CLI_VERSION,
|
|
11627
|
+
os: process.platform,
|
|
11628
|
+
node_version: process.version,
|
|
11629
|
+
ci: ctx.ci,
|
|
11630
|
+
environment: ctx.environment
|
|
11631
|
+
};
|
|
11632
|
+
if (!identity.identified)
|
|
11633
|
+
properties.$process_person_profile = false;
|
|
11634
|
+
return {
|
|
11635
|
+
api_key: POSTHOG_PROJECT_KEY,
|
|
11636
|
+
event: "command_run",
|
|
11637
|
+
distinct_id: identity.distinctId,
|
|
11638
|
+
properties,
|
|
11639
|
+
timestamp: new Date(nowMs).toISOString()
|
|
11640
|
+
};
|
|
11641
|
+
}
|
|
11642
|
+
function emittingCommand(argv) {
|
|
11643
|
+
const verb = argv[0];
|
|
11644
|
+
if (verb === undefined)
|
|
11645
|
+
return null;
|
|
11646
|
+
if (verb === "--help" || verb === "-h")
|
|
11647
|
+
return null;
|
|
11648
|
+
if (verb === "--version" || verb === "-v")
|
|
11649
|
+
return null;
|
|
11650
|
+
if (verb === INTERNAL_EMIT_VERB || verb === INTERNAL_REFRESH_VERB)
|
|
11651
|
+
return null;
|
|
11652
|
+
return verb;
|
|
11653
|
+
}
|
|
11654
|
+
function environmentOf(argv, stderrIsTTY) {
|
|
11655
|
+
if (argv.includes("--json"))
|
|
11656
|
+
return "json";
|
|
11657
|
+
return stderrIsTTY ? "tty" : "non-tty";
|
|
11658
|
+
}
|
|
11659
|
+
async function resolveIdentity(deps) {
|
|
11660
|
+
try {
|
|
11661
|
+
const session = await deps.readSession();
|
|
11662
|
+
if (session && typeof session.accessToken === "string") {
|
|
11663
|
+
let payload = null;
|
|
11664
|
+
try {
|
|
11665
|
+
payload = decodeJwtPayload(session.accessToken);
|
|
11666
|
+
} catch {
|
|
11667
|
+
payload = null;
|
|
11668
|
+
}
|
|
11669
|
+
const id = typeof payload?.email === "string" && payload.email ? payload.email : typeof payload?.sub === "string" && payload.sub ? payload.sub : null;
|
|
11670
|
+
if (id)
|
|
11671
|
+
return { distinctId: id, identified: true };
|
|
11672
|
+
}
|
|
11673
|
+
} catch {}
|
|
11674
|
+
return { distinctId: deps.deviceId(), identified: false };
|
|
11675
|
+
}
|
|
11676
|
+
async function resolveIdentityReal() {
|
|
11677
|
+
return resolveIdentity({
|
|
11678
|
+
readSession: async () => {
|
|
11679
|
+
const cfg = loadConfig();
|
|
11680
|
+
return readSession(cfg.sessionPath);
|
|
11681
|
+
},
|
|
11682
|
+
deviceId: getOrCreateDeviceId
|
|
11683
|
+
});
|
|
11684
|
+
}
|
|
11685
|
+
function getOrCreateDeviceId() {
|
|
11686
|
+
try {
|
|
11687
|
+
const raw = JSON.parse(readFileSync20(DEVICE_ID_FILE, "utf8"));
|
|
11688
|
+
const id2 = raw?.deviceId;
|
|
11689
|
+
if (typeof id2 === "string" && id2)
|
|
11690
|
+
return id2;
|
|
11691
|
+
} catch {}
|
|
11692
|
+
const id = randomUUID();
|
|
11693
|
+
try {
|
|
11694
|
+
mkdirSync4(join16(homedir5(), ".launchpad"), { recursive: true });
|
|
11695
|
+
writeFileSync9(DEVICE_ID_FILE, `${JSON.stringify({ deviceId: id })}
|
|
11696
|
+
`, {
|
|
11697
|
+
mode: 384
|
|
11698
|
+
});
|
|
11699
|
+
} catch {}
|
|
11700
|
+
return id;
|
|
11701
|
+
}
|
|
11702
|
+
async function postCapture(event, fetcher = fetch) {
|
|
11703
|
+
const controller = new AbortController;
|
|
11704
|
+
const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);
|
|
11705
|
+
try {
|
|
11706
|
+
await fetcher(`${POSTHOG_HOST}${CAPTURE_PATH}`, {
|
|
11707
|
+
method: "POST",
|
|
11708
|
+
headers: {
|
|
11709
|
+
"content-type": "application/json",
|
|
11710
|
+
"user-agent": `launchpad-cli/${CLI_VERSION}`
|
|
11711
|
+
},
|
|
11712
|
+
body: JSON.stringify(event),
|
|
11713
|
+
signal: controller.signal
|
|
11714
|
+
});
|
|
11715
|
+
} catch {} finally {
|
|
11716
|
+
clearTimeout(timer);
|
|
11717
|
+
}
|
|
11718
|
+
}
|
|
11719
|
+
function recordAfterCommand(argv, exitCode, durationMs, deps) {
|
|
11720
|
+
const command = emittingCommand(argv);
|
|
11721
|
+
if (command === null)
|
|
11722
|
+
return;
|
|
11723
|
+
deps.emit({
|
|
11724
|
+
command,
|
|
11725
|
+
exitCode,
|
|
11726
|
+
durationMs,
|
|
11727
|
+
ci: deps.ci,
|
|
11728
|
+
environment: environmentOf(argv, deps.stderrIsTTY)
|
|
11729
|
+
});
|
|
11730
|
+
}
|
|
11731
|
+
function recordAfterCommandReal(argv, exitCode, durationMs, cliPath = process.argv[1]) {
|
|
11732
|
+
try {
|
|
11733
|
+
recordAfterCommand(argv, exitCode, durationMs, {
|
|
11734
|
+
emit: (ctx) => spawnDetachedEmit(cliPath, ctx),
|
|
11735
|
+
ci: Boolean(process.env.CI),
|
|
11736
|
+
stderrIsTTY: Boolean(process.stderr.isTTY)
|
|
11737
|
+
});
|
|
11738
|
+
} catch {}
|
|
11739
|
+
}
|
|
11740
|
+
function spawnDetachedEmit(cliPath, ctx) {
|
|
11741
|
+
if (!cliPath)
|
|
11742
|
+
return;
|
|
11743
|
+
try {
|
|
11744
|
+
const child = spawn7(process.execPath, [
|
|
11745
|
+
cliPath,
|
|
11746
|
+
INTERNAL_EMIT_VERB,
|
|
11747
|
+
"--command",
|
|
11748
|
+
ctx.command,
|
|
11749
|
+
"--exit",
|
|
11750
|
+
String(ctx.exitCode),
|
|
11751
|
+
"--duration",
|
|
11752
|
+
String(ctx.durationMs),
|
|
11753
|
+
"--environment",
|
|
11754
|
+
ctx.environment,
|
|
11755
|
+
...ctx.ci ? ["--ci"] : []
|
|
11756
|
+
], { detached: true, stdio: "ignore" });
|
|
11757
|
+
child.unref();
|
|
11758
|
+
} catch {}
|
|
11759
|
+
}
|
|
11760
|
+
function telemetryNoticeLine() {
|
|
11761
|
+
return "ℹ launchpad records anonymous + signed-in usage analytics (command, CLI version, OS, outcome — never your arguments, paths, or file contents) to improve the platform. Internal staff tooling. More: https://get.launchpad.m-kopa.us/docs/.";
|
|
11762
|
+
}
|
|
11763
|
+
function firstRunNoticeShown() {
|
|
11764
|
+
try {
|
|
11765
|
+
return existsSync15(FIRST_RUN_MARKER);
|
|
11766
|
+
} catch {
|
|
11767
|
+
return false;
|
|
11768
|
+
}
|
|
11769
|
+
}
|
|
11770
|
+
function markFirstRunNotice() {
|
|
11771
|
+
try {
|
|
11772
|
+
mkdirSync4(join16(homedir5(), ".launchpad"), { recursive: true });
|
|
11773
|
+
writeFileSync9(FIRST_RUN_MARKER, `${Date.now()}
|
|
11774
|
+
`, { mode: 384 });
|
|
11775
|
+
} catch {}
|
|
11776
|
+
}
|
|
11777
|
+
function maybeFirstRunNotice(io, argv, deps) {
|
|
11778
|
+
if (!deps.stderrIsTTY)
|
|
11779
|
+
return;
|
|
11780
|
+
if (argv.includes("--json"))
|
|
11781
|
+
return;
|
|
11782
|
+
if (emittingCommand(argv) === null)
|
|
11783
|
+
return;
|
|
11784
|
+
if (deps.shown())
|
|
11785
|
+
return;
|
|
11786
|
+
io.err(telemetryNoticeLine());
|
|
11787
|
+
deps.mark();
|
|
11788
|
+
}
|
|
11789
|
+
function maybeFirstRunNoticeReal(io, argv) {
|
|
11790
|
+
try {
|
|
11791
|
+
maybeFirstRunNotice(io, argv, {
|
|
11792
|
+
stderrIsTTY: Boolean(process.stderr.isTTY),
|
|
11793
|
+
shown: firstRunNoticeShown,
|
|
11794
|
+
mark: markFirstRunNotice
|
|
11795
|
+
});
|
|
11796
|
+
} catch {}
|
|
11797
|
+
}
|
|
11798
|
+
function parseEmitArgs(args) {
|
|
11799
|
+
const get = (flag) => {
|
|
11800
|
+
const i = args.indexOf(flag);
|
|
11801
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
11802
|
+
};
|
|
11803
|
+
const command = get("--command");
|
|
11804
|
+
const exit = get("--exit");
|
|
11805
|
+
const duration = get("--duration");
|
|
11806
|
+
const environment = get("--environment");
|
|
11807
|
+
if (!command || exit === undefined || duration === undefined)
|
|
11808
|
+
return null;
|
|
11809
|
+
const env = environment === "json" || environment === "non-tty" ? environment : "tty";
|
|
11810
|
+
return {
|
|
11811
|
+
command,
|
|
11812
|
+
exitCode: Number.parseInt(exit, 10) || 0,
|
|
11813
|
+
durationMs: Number.parseInt(duration, 10) || 0,
|
|
11814
|
+
ci: args.includes("--ci"),
|
|
11815
|
+
environment: env
|
|
11816
|
+
};
|
|
11817
|
+
}
|
|
11818
|
+
var emitTelemetryCommand = {
|
|
11819
|
+
name: INTERNAL_EMIT_VERB,
|
|
11820
|
+
summary: "(internal) send a usage-telemetry event",
|
|
11821
|
+
hidden: true,
|
|
11822
|
+
run: async (args) => {
|
|
11823
|
+
try {
|
|
11824
|
+
const ctx = parseEmitArgs(args);
|
|
11825
|
+
if (ctx) {
|
|
11826
|
+
const identity = await resolveIdentityReal();
|
|
11827
|
+
await postCapture(buildEvent(ctx, identity, Date.now()));
|
|
11828
|
+
}
|
|
11829
|
+
} catch {}
|
|
11830
|
+
return 0;
|
|
11831
|
+
}
|
|
11832
|
+
};
|
|
11833
|
+
|
|
11606
11834
|
// src/dispatcher.ts
|
|
11607
11835
|
var COMMANDS = [
|
|
11608
11836
|
loginCommand,
|
|
@@ -11631,7 +11859,8 @@ var COMMANDS = [
|
|
|
11631
11859
|
secretsCommand,
|
|
11632
11860
|
grantEditorCommand,
|
|
11633
11861
|
revokeEditorCommand,
|
|
11634
|
-
refreshUpdateCacheCommand
|
|
11862
|
+
refreshUpdateCacheCommand,
|
|
11863
|
+
emitTelemetryCommand
|
|
11635
11864
|
];
|
|
11636
11865
|
async function dispatch(argv, io, commands = COMMANDS) {
|
|
11637
11866
|
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
@@ -11692,12 +11921,19 @@ var io = {
|
|
|
11692
11921
|
}
|
|
11693
11922
|
};
|
|
11694
11923
|
var args = process.argv.slice(2);
|
|
11924
|
+
var startedAt = Date.now();
|
|
11695
11925
|
dispatch(args, io).then((code) => {
|
|
11926
|
+
const elapsedMs = Date.now() - startedAt;
|
|
11696
11927
|
process.exitCode = code;
|
|
11697
11928
|
notifyAfterCommand(io, args);
|
|
11929
|
+
maybeFirstRunNoticeReal(io, args);
|
|
11930
|
+
recordAfterCommandReal(args, code, elapsedMs);
|
|
11698
11931
|
}).catch((err) => {
|
|
11932
|
+
const elapsedMs = Date.now() - startedAt;
|
|
11699
11933
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11700
11934
|
process.stderr.write(`launchpad: unexpected error: ${msg}
|
|
11701
11935
|
`);
|
|
11702
11936
|
process.exitCode = 70;
|
|
11937
|
+
maybeFirstRunNoticeReal(io, args);
|
|
11938
|
+
recordAfterCommandReal(args, 70, elapsedMs);
|
|
11703
11939
|
});
|
package/dist/dispatcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AAmDA,MAAM,WAAW,KAAK;IACpB,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxE;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,OAAO,EAiCtC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,KAAK,EACT,QAAQ,GAAE,SAAS,OAAO,EAAa,GACtC,OAAO,CAAC,QAAQ,CAAC,CAmBnB;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAyBvE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { CliIo, Command } from "./dispatcher.js";
|
|
2
|
+
/** Internal verb the detached emitter process runs. Hidden from help. */
|
|
3
|
+
export declare const INTERNAL_EMIT_VERB = "__emit-telemetry";
|
|
4
|
+
export declare const POSTHOG_HOST = "https://us.i.posthog.com";
|
|
5
|
+
export declare const POSTHOG_PROJECT_KEY = "phc_D4FKJnWb7wWGCWs8NoTpQ2xFGFd4jQt698pQ68BrdcXt";
|
|
6
|
+
export type Environment = "tty" | "non-tty" | "json";
|
|
7
|
+
/** NON-PII context captured in the foreground and passed to the child. */
|
|
8
|
+
export interface CommandContext {
|
|
9
|
+
readonly command: string;
|
|
10
|
+
readonly exitCode: number;
|
|
11
|
+
readonly durationMs: number;
|
|
12
|
+
readonly ci: boolean;
|
|
13
|
+
readonly environment: Environment;
|
|
14
|
+
}
|
|
15
|
+
export interface Identity {
|
|
16
|
+
readonly distinctId: string;
|
|
17
|
+
readonly identified: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** PostHog capture wire payload (`/i/v0/e/`). */
|
|
20
|
+
export interface PosthogEvent {
|
|
21
|
+
readonly api_key: string;
|
|
22
|
+
readonly event: "command_run";
|
|
23
|
+
readonly distinct_id: string;
|
|
24
|
+
readonly properties: Record<string, unknown>;
|
|
25
|
+
readonly timestamp: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build the `command_run` event from a FIXED ALLOWLIST of properties.
|
|
29
|
+
* This is the PII floor (ADR 0027 D6): nothing outside this set can be
|
|
30
|
+
* sent, so command arguments / paths / env / secrets can never leak.
|
|
31
|
+
* Anonymous events set `$process_person_profile:false` (cheaper tier).
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildEvent(ctx: CommandContext, identity: Identity, nowMs: number): PosthogEvent;
|
|
34
|
+
/**
|
|
35
|
+
* The verb to emit for, or `null` when this invocation must NOT emit:
|
|
36
|
+
* the two internal verbs (the emitter itself — no recursion — and the
|
|
37
|
+
* update-cache refresh), `--help`/`-h`, `--version`/`-v`, and the bare
|
|
38
|
+
* no-arg invocation. Every other registered verb emits.
|
|
39
|
+
*/
|
|
40
|
+
export declare function emittingCommand(argv: readonly string[]): string | null;
|
|
41
|
+
export declare function environmentOf(argv: readonly string[], stderrIsTTY: boolean): Environment;
|
|
42
|
+
export interface IdentityDeps {
|
|
43
|
+
readonly readSession: () => Promise<{
|
|
44
|
+
accessToken: string;
|
|
45
|
+
} | null>;
|
|
46
|
+
readonly deviceId: () => string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Entra email (else `sub`) from the session JWT when a session exists,
|
|
50
|
+
* otherwise a stable anonymous device-id. Resolved INSIDE the detached
|
|
51
|
+
* child so the email never travels on the foreground command line.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveIdentity(deps: IdentityDeps): Promise<Identity>;
|
|
54
|
+
export declare function resolveIdentityReal(): Promise<Identity>;
|
|
55
|
+
/** Read or lazily create the stable anonymous device-id (0600). */
|
|
56
|
+
export declare function getOrCreateDeviceId(): string;
|
|
57
|
+
/** POST the event to PostHog. Bounded by a timeout, totally fail-silent. */
|
|
58
|
+
export declare function postCapture(event: PosthogEvent, fetcher?: typeof fetch): Promise<void>;
|
|
59
|
+
export interface RecordDeps {
|
|
60
|
+
readonly emit: (ctx: CommandContext) => void;
|
|
61
|
+
readonly ci: boolean;
|
|
62
|
+
readonly stderrIsTTY: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** Core: classify the verb and, if it emits, hand a NON-PII context to `emit`. */
|
|
65
|
+
export declare function recordAfterCommand(argv: readonly string[], exitCode: number, durationMs: number, deps: RecordDeps): void;
|
|
66
|
+
/** Real wiring for the bin wrapper. Fully guarded. */
|
|
67
|
+
export declare function recordAfterCommandReal(argv: readonly string[], exitCode: number, durationMs: number, cliPath?: string | undefined): void;
|
|
68
|
+
export declare function telemetryNoticeLine(): string;
|
|
69
|
+
export declare function firstRunNoticeShown(): boolean;
|
|
70
|
+
export declare function markFirstRunNotice(): void;
|
|
71
|
+
export interface NoticeDeps {
|
|
72
|
+
readonly stderrIsTTY: boolean;
|
|
73
|
+
readonly shown: () => boolean;
|
|
74
|
+
readonly mark: () => void;
|
|
75
|
+
}
|
|
76
|
+
/** Show the one-time disclosure on stderr. Never on `--json`, non-TTY, or
|
|
77
|
+
* the non-emitting verbs (help/version/internal/no-arg). */
|
|
78
|
+
export declare function maybeFirstRunNotice(io: CliIo, argv: readonly string[], deps: NoticeDeps): void;
|
|
79
|
+
export declare function maybeFirstRunNoticeReal(io: CliIo, argv: readonly string[]): void;
|
|
80
|
+
/** Parse the NON-PII flags the foreground passed; null if malformed. */
|
|
81
|
+
export declare function parseEmitArgs(args: readonly string[]): CommandContext | null;
|
|
82
|
+
/** Hidden command: resolve identity + POST. Runs in the detached process. */
|
|
83
|
+
export declare const emitTelemetryCommand: Command;
|
|
84
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.28.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-content-pr
|
|
3
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) — subsequent deploys commit directly to the app repo's main and the Pages build runs asynchronously, so verification is its own step. 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.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy
|
|
3
3
|
description: Walk a Launchpad user through deploying an app from their local working directory (Model A — `launchpad init` + `launchpad deploy`). Wraps the CLI verbs end-to-end: detects the app shape, scaffolds `launchpad.yaml`, resolves the allowed Entra group via `launchpad groups`, bundles the CWD via `launchpad deploy`, and watches the rollout via `launchpad status`. Use when someone says "deploy a new app", "ship my app to Launchpad", "/launchpad-deploy", "I have an app locally — get it on Launchpad", or any variant. Resume/abandon for legacy in-flight provisioning is at the bottom.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-deploy-status
|
|
3
3
|
description: Show the current provisioning stage + failure reason for a Launchpad app via `launchpad status` (Model A drift + deployment_verified) and `launchpad apps` (lifecycle bucket). Renders the M-892 stage trace for in-flight provisioning, and is the canonical home for `launchpad recover` (repair a terminal-failed app record that is actually live). Use when someone says "what's the status of demo-X", "/launchpad-deploy-status", "is my deploy stuck", "my app says failed but it's serving", or after `/launchpad-deploy` reports a non-`done` terminal stage.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-destroy
|
|
3
3
|
description: Tear down a Launchpad app end-to-end via `launchpad destroy` — Cloudflare Pages project, edge-auth wiring (gateway KV/audience entries, or the Access app for `auth: access` apps), custom hostname, platform-repo TF, and the app repo (archive-renamed). Owner-only verb with a two-step destructive confirmation. Use when someone says "destroy this app", "/launchpad-destroy", "tear down `<slug>`", "delete the app", or asks to clean up a smoke-test / orphan / retired app.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-onboard
|
|
3
3
|
description: One-time setup for the Launchpad CLI + Claude Code skill bundle. Verifies the `launchpad` CLI is installed and current, runs `launchpad whoami` to confirm the session is fresh, and checks the bundled skills are installed and in lock-step with the CLI. Idempotent — safe to re-run any time. Use when someone says "set me up for Launchpad", "I just got a new machine and want to use Launchpad", "/launchpad-onboard", or any of the other launchpad-* skills fails on a prereq check.
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launchpad-status
|
|
3
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.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- BEGIN shell-contract (managed by scripts/sync-skill-contract.sh — edit skills/_partials/shell-contract.md) -->
|