@launchsecure/launch-kit 0.0.27 → 0.0.29
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/dist/beacon/beacon.mjs +1003 -440
- package/dist/beacon/beacon.mjs.map +1 -1
- package/dist/beacon/beacon.umd.js +45 -24
- package/dist/beacon/beacon.umd.js.map +1 -1
- package/dist/beacon/types/capture/events.d.ts +20 -0
- package/dist/beacon/types/capture/events.d.ts.map +1 -0
- package/dist/beacon/types/element.d.ts +1 -0
- package/dist/beacon/types/element.d.ts.map +1 -1
- package/dist/beacon/types/index.d.ts +2 -1
- package/dist/beacon/types/index.d.ts.map +1 -1
- package/dist/beacon/types/monitor/dom.d.ts +13 -0
- package/dist/beacon/types/monitor/dom.d.ts.map +1 -0
- package/dist/beacon/types/monitor/index.d.ts +19 -0
- package/dist/beacon/types/monitor/index.d.ts.map +1 -0
- package/dist/beacon/types/monitor/network.d.ts +12 -0
- package/dist/beacon/types/monitor/network.d.ts.map +1 -0
- package/dist/beacon/types/monitor/transport.d.ts +27 -0
- package/dist/beacon/types/monitor/transport.d.ts.map +1 -0
- package/dist/beacon/types/monitor/types.d.ts +117 -0
- package/dist/beacon/types/monitor/types.d.ts.map +1 -0
- package/dist/beacon/types/types.d.ts +10 -0
- package/dist/beacon/types/types.d.ts.map +1 -1
- package/dist/beacon/types/ui/drawer.d.ts +3 -1
- package/dist/beacon/types/ui/drawer.d.ts.map +1 -1
- package/dist/beacon/types/ui/monitor-panel.d.ts +19 -0
- package/dist/beacon/types/ui/monitor-panel.d.ts.map +1 -0
- package/dist/server/beacon-monitor-entry.js +353 -0
- package/dist/server/chart-serve.js +3 -1
- package/dist/server/cli.js +276 -218
- package/dist/server/course-entry.js +246 -0
- package/dist/server/graph-mcp-entry.js +35 -72
- package/dist/server/init-entry.js +1051 -122
- package/dist/server/orbit-entry.js +187 -24
- package/package.json +5 -3
- package/scaffolds/ls-marketplace/.claude-plugin/marketplace.json +15 -0
- package/scaffolds/ls-marketplace/plugins/kit/.claude-plugin/plugin.json +19 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/activate-beacon.md +216 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +46 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-array.md +92 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-clear.md +68 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-pulse.md +80 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-scan.md +62 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/deactivate-statusline.md +34 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/show-mcp-status.md +109 -0
- package/scaffolds/ls-marketplace/plugins/kit/commands/standup.md +191 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
- package/scaffolds/statusline/statusline-mcp.sh +192 -0
- package/scaffolds/statusline/statusline-wrapper.sh +50 -0
|
@@ -923,6 +923,18 @@ function detectPmFromLock(worktreePath) {
|
|
|
923
923
|
if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(worktreePath, "bun.lockb"))) return "bun";
|
|
924
924
|
return "npm";
|
|
925
925
|
}
|
|
926
|
+
function combineOutput(stdout, stderr) {
|
|
927
|
+
const out = (stdout ?? "").trimEnd();
|
|
928
|
+
const err2 = (stderr ?? "").trimEnd();
|
|
929
|
+
if (!out && !err2) return "";
|
|
930
|
+
if (!err2) return out + "\n";
|
|
931
|
+
if (!out) return err2 + "\n";
|
|
932
|
+
return `${out}
|
|
933
|
+
|
|
934
|
+
---STDERR---
|
|
935
|
+
${err2}
|
|
936
|
+
`;
|
|
937
|
+
}
|
|
926
938
|
function saveLog(slug, label, content) {
|
|
927
939
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
928
940
|
const path = (0, import_node_path5.join)(LOG_DIR, `${ts}_${slug}_${label}.log`);
|
|
@@ -1007,12 +1019,31 @@ var init_build_lint = __esm({
|
|
|
1007
1019
|
env: spawnEnv
|
|
1008
1020
|
});
|
|
1009
1021
|
if (installRes.status !== 0) {
|
|
1010
|
-
const log = saveLog(ctx.entry.slug, "install", installRes.
|
|
1022
|
+
const log = saveLog(ctx.entry.slug, "install", combineOutput(installRes.stdout, installRes.stderr));
|
|
1011
1023
|
blockers.push("dependency install failed in ephemeral worktree");
|
|
1012
1024
|
artifacts.install_log = log;
|
|
1013
1025
|
return finalize(checkPath, ctx, blockers, artifacts);
|
|
1014
1026
|
}
|
|
1015
1027
|
}
|
|
1028
|
+
if ((0, import_node_fs7.existsSync)((0, import_node_path5.join)(checkPath, "prisma", "schema.prisma"))) {
|
|
1029
|
+
const prismaCmd = "npx prisma generate";
|
|
1030
|
+
ctx.logger.step(`[build-lint] ${prismaCmd}`);
|
|
1031
|
+
const prismaRes = (0, import_node_child_process5.spawnSync)("bash", ["-c", `cd ${shellQuote2(checkPath)} && ${prismaCmd}`], {
|
|
1032
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1033
|
+
encoding: "utf-8",
|
|
1034
|
+
env: spawnEnv
|
|
1035
|
+
});
|
|
1036
|
+
if (prismaRes.status !== 0) {
|
|
1037
|
+
const log = saveLog(
|
|
1038
|
+
ctx.entry.slug,
|
|
1039
|
+
"prisma-generate",
|
|
1040
|
+
combineOutput(prismaRes.stdout, prismaRes.stderr)
|
|
1041
|
+
);
|
|
1042
|
+
blockers.push(`prisma generate failed (exit ${prismaRes.status}) \u2014 tsc will not be reliable`);
|
|
1043
|
+
artifacts["prisma-generate_log"] = log;
|
|
1044
|
+
return finalize(checkPath, ctx, blockers, artifacts);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1016
1047
|
const tscMode = config.tsc ?? true;
|
|
1017
1048
|
if (tscMode !== false) {
|
|
1018
1049
|
const tscCmd = typeof tscMode === "string" ? tscMode : "npx tsc --noEmit";
|
|
@@ -1023,7 +1054,7 @@ var init_build_lint = __esm({
|
|
|
1023
1054
|
env: spawnEnv
|
|
1024
1055
|
});
|
|
1025
1056
|
if (tscRes.status !== 0) {
|
|
1026
|
-
const log = saveLog(ctx.entry.slug, "tsc", tscRes.stdout
|
|
1057
|
+
const log = saveLog(ctx.entry.slug, "tsc", combineOutput(tscRes.stdout, tscRes.stderr));
|
|
1027
1058
|
blockers.push(`tsc reported errors (exit ${tscRes.status})`);
|
|
1028
1059
|
artifacts.tsc_log = log;
|
|
1029
1060
|
}
|
|
@@ -1039,7 +1070,7 @@ var init_build_lint = __esm({
|
|
|
1039
1070
|
env: spawnEnv
|
|
1040
1071
|
});
|
|
1041
1072
|
if (lintRes.status !== 0) {
|
|
1042
|
-
const log = saveLog(ctx.entry.slug, "lint", lintRes.stdout
|
|
1073
|
+
const log = saveLog(ctx.entry.slug, "lint", combineOutput(lintRes.stdout, lintRes.stderr));
|
|
1043
1074
|
blockers.push(`lint reported errors (exit ${lintRes.status})`);
|
|
1044
1075
|
artifacts.lint_log = log;
|
|
1045
1076
|
}
|
|
@@ -1058,7 +1089,7 @@ var init_build_lint = __esm({
|
|
|
1058
1089
|
env: spawnEnv
|
|
1059
1090
|
});
|
|
1060
1091
|
if (buildRes.status !== 0) {
|
|
1061
|
-
const log = saveLog(ctx.entry.slug, "build", buildRes.stdout
|
|
1092
|
+
const log = saveLog(ctx.entry.slug, "build", combineOutput(buildRes.stdout, buildRes.stderr));
|
|
1062
1093
|
blockers.push(`build reported errors (exit ${buildRes.status})`);
|
|
1063
1094
|
artifacts.build_log = log;
|
|
1064
1095
|
}
|
|
@@ -1234,11 +1265,32 @@ var init_gate_registry = __esm({
|
|
|
1234
1265
|
});
|
|
1235
1266
|
|
|
1236
1267
|
// src/server/orbit/gate-runner.ts
|
|
1237
|
-
async function runMergeGates(manifest, ctx) {
|
|
1268
|
+
async function runMergeGates(manifest, ctx, options = {}) {
|
|
1238
1269
|
const refs = manifest.gates?.merge ?? DEFAULT_GATES;
|
|
1270
|
+
const skip = new Set(options.skipGates ?? []);
|
|
1271
|
+
if (skip.size > 0) {
|
|
1272
|
+
const declared = new Set(refs.map((r) => r.adapter));
|
|
1273
|
+
for (const id of skip) {
|
|
1274
|
+
if (!declared.has(id)) {
|
|
1275
|
+
ctx.logger.warn(
|
|
1276
|
+
`--skip-gate "${id}" does not match any declared gate (declared: ${[...declared].join(", ")})`
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const blockedRequired = refs.filter((r) => r.required && skip.has(r.adapter)).map((r) => r.adapter);
|
|
1281
|
+
if (blockedRequired.length > 0) {
|
|
1282
|
+
throw new Error(
|
|
1283
|
+
`cannot skip required gate(s): ${blockedRequired.join(", ")}. Remove "required": true from orbit.json if you really need to bypass.`
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1239
1287
|
const start = Date.now();
|
|
1240
1288
|
const results = [];
|
|
1241
1289
|
for (const ref of refs) {
|
|
1290
|
+
if (skip.has(ref.adapter)) {
|
|
1291
|
+
ctx.logger.info(`[gate] skip ${ref.adapter} (--skip-gate)`);
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1242
1294
|
const gate = getMergeGate(ref.adapter);
|
|
1243
1295
|
const detect = await gate.detect(ctx);
|
|
1244
1296
|
if (!detect.ok) {
|
|
@@ -1288,7 +1340,7 @@ var init_gate_runner = __esm({
|
|
|
1288
1340
|
"src/server/orbit/gate-runner.ts"() {
|
|
1289
1341
|
"use strict";
|
|
1290
1342
|
init_gate_registry();
|
|
1291
|
-
DEFAULT_GATES = [{ adapter: "builtin/mergeability" }];
|
|
1343
|
+
DEFAULT_GATES = [{ adapter: "builtin/mergeability", required: true }];
|
|
1292
1344
|
}
|
|
1293
1345
|
});
|
|
1294
1346
|
|
|
@@ -1321,14 +1373,50 @@ function validateManifest(raw, sourcePath) {
|
|
|
1321
1373
|
const worktree = validateWorktreeRef(raw.worktree, sourcePath);
|
|
1322
1374
|
const resources = validateResourcesArray(raw.resources, sourcePath);
|
|
1323
1375
|
const gates = validateGates(raw.gates, sourcePath);
|
|
1376
|
+
const profiles = validateProfiles(raw.profiles, resources, sourcePath);
|
|
1324
1377
|
return {
|
|
1325
1378
|
version: 1,
|
|
1326
1379
|
...envFile !== void 0 ? { envFile } : {},
|
|
1327
1380
|
worktree,
|
|
1328
1381
|
resources,
|
|
1329
|
-
...gates !== void 0 ? { gates } : {}
|
|
1382
|
+
...gates !== void 0 ? { gates } : {},
|
|
1383
|
+
...profiles !== void 0 ? { profiles } : {}
|
|
1330
1384
|
};
|
|
1331
1385
|
}
|
|
1386
|
+
function validateProfiles(raw, resources, sourcePath) {
|
|
1387
|
+
if (raw === void 0) return void 0;
|
|
1388
|
+
if (!isRecord(raw)) throw err("profiles must be an object if present", sourcePath);
|
|
1389
|
+
const known = new Set(resources.map((r) => r.name));
|
|
1390
|
+
const out = {};
|
|
1391
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
1392
|
+
if (!name) throw err("profiles keys must be non-empty strings", sourcePath);
|
|
1393
|
+
if (!isRecord(value)) throw err(`profiles.${name} must be an object`, sourcePath);
|
|
1394
|
+
if (!Array.isArray(value.resources)) {
|
|
1395
|
+
throw err(`profiles.${name}.resources must be an array of resource names`, sourcePath);
|
|
1396
|
+
}
|
|
1397
|
+
const list2 = [];
|
|
1398
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1399
|
+
for (let i = 0; i < value.resources.length; i++) {
|
|
1400
|
+
const r = value.resources[i];
|
|
1401
|
+
if (typeof r !== "string" || !r) {
|
|
1402
|
+
throw err(`profiles.${name}.resources[${i}] must be a non-empty string`, sourcePath);
|
|
1403
|
+
}
|
|
1404
|
+
if (!known.has(r)) {
|
|
1405
|
+
throw err(
|
|
1406
|
+
`profiles.${name}.resources[${i}] "${r}" does not match any resource name (known: ${[...known].join(", ") || "(none)"})`,
|
|
1407
|
+
sourcePath
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
if (seen.has(r)) {
|
|
1411
|
+
throw err(`profiles.${name}.resources[${i}] "${r}" duplicated`, sourcePath);
|
|
1412
|
+
}
|
|
1413
|
+
seen.add(r);
|
|
1414
|
+
list2.push(r);
|
|
1415
|
+
}
|
|
1416
|
+
out[name] = { resources: list2 };
|
|
1417
|
+
}
|
|
1418
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1419
|
+
}
|
|
1332
1420
|
function validateGates(raw, sourcePath) {
|
|
1333
1421
|
if (raw === void 0) return void 0;
|
|
1334
1422
|
if (!isRecord(raw)) throw err("gates must be an object if present", sourcePath);
|
|
@@ -1351,7 +1439,15 @@ function validateGates(raw, sourcePath) {
|
|
|
1351
1439
|
if (config !== void 0 && !isRecord(config)) {
|
|
1352
1440
|
throw err(`gates.merge[${i}].config must be an object if present`, sourcePath);
|
|
1353
1441
|
}
|
|
1354
|
-
|
|
1442
|
+
const required = g.required;
|
|
1443
|
+
if (required !== void 0 && typeof required !== "boolean") {
|
|
1444
|
+
throw err(`gates.merge[${i}].required must be a boolean if present`, sourcePath);
|
|
1445
|
+
}
|
|
1446
|
+
list2.push({
|
|
1447
|
+
adapter: g.adapter,
|
|
1448
|
+
config,
|
|
1449
|
+
...required ? { required: true } : {}
|
|
1450
|
+
});
|
|
1355
1451
|
}
|
|
1356
1452
|
out.merge = list2;
|
|
1357
1453
|
}
|
|
@@ -1453,6 +1549,12 @@ async function create(opts) {
|
|
|
1453
1549
|
if (lookupWorktree(slug)) {
|
|
1454
1550
|
throw new Error(`worktree "${slug}" already registered. Run \`launch-orbit drop ${slug}\` first.`);
|
|
1455
1551
|
}
|
|
1552
|
+
const effectiveResources = resolveProfile(manifest, opts.profile);
|
|
1553
|
+
if (opts.profile) {
|
|
1554
|
+
opts.logger.info(
|
|
1555
|
+
`profile "${opts.profile}" \u2192 resources: ${effectiveResources.map((r) => r.name).join(", ") || "(none)"}`
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1456
1558
|
const worktreeAdapter = getWorktreeAdapter(manifest.worktree.adapter);
|
|
1457
1559
|
const wtDetect = await worktreeAdapter.detect(ctx);
|
|
1458
1560
|
if (!wtDetect.ok) throw new Error(`worktree adapter "${worktreeAdapter.id}" unavailable: ${wtDetect.reason}`);
|
|
@@ -1474,7 +1576,7 @@ async function create(opts) {
|
|
|
1474
1576
|
const resourceStates = {};
|
|
1475
1577
|
const rewriteFns = {};
|
|
1476
1578
|
try {
|
|
1477
|
-
for (const ref of
|
|
1579
|
+
for (const ref of effectiveResources) {
|
|
1478
1580
|
const adapter = getResourceAdapter(ref.adapter);
|
|
1479
1581
|
const detect = await adapter.detect(ctx);
|
|
1480
1582
|
if (!detect.ok) throw new Error(`resource adapter "${adapter.id}" unavailable: ${detect.reason}`);
|
|
@@ -1622,7 +1724,7 @@ async function checkMergeable(opts) {
|
|
|
1622
1724
|
logger: opts.logger
|
|
1623
1725
|
};
|
|
1624
1726
|
opts.logger.step(`running merge gates against target "${opts.target}"`);
|
|
1625
|
-
const agg = await runMergeGates(manifest, gateCtx);
|
|
1727
|
+
const agg = await runMergeGates(manifest, gateCtx, { skipGates: opts.skipGates });
|
|
1626
1728
|
opts.logger.info(formatGateResults(agg.results));
|
|
1627
1729
|
return {
|
|
1628
1730
|
slug,
|
|
@@ -1639,6 +1741,7 @@ async function merge(opts) {
|
|
|
1639
1741
|
const check = await checkMergeable({
|
|
1640
1742
|
branch: opts.branch,
|
|
1641
1743
|
target: opts.target,
|
|
1744
|
+
skipGates: opts.skipGates,
|
|
1642
1745
|
projectRoot: opts.projectRoot,
|
|
1643
1746
|
logger: opts.logger
|
|
1644
1747
|
});
|
|
@@ -1750,6 +1853,22 @@ function findWorktreeFor(projectRoot, branch) {
|
|
|
1750
1853
|
return null;
|
|
1751
1854
|
}
|
|
1752
1855
|
}
|
|
1856
|
+
function resolveProfile(manifest, profile) {
|
|
1857
|
+
if (!profile) return manifest.resources;
|
|
1858
|
+
const ref = manifest.profiles?.[profile];
|
|
1859
|
+
if (!ref) {
|
|
1860
|
+
const known = Object.keys(manifest.profiles ?? {});
|
|
1861
|
+
throw new Error(
|
|
1862
|
+
`profile "${profile}" not declared in orbit.json. Available: ${known.length > 0 ? known.join(", ") : "(none \u2014 add a `profiles` block to orbit.json)"}`
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
const byName = new Map(manifest.resources.map((r) => [r.name, r]));
|
|
1866
|
+
return ref.resources.map((name) => {
|
|
1867
|
+
const r = byName.get(name);
|
|
1868
|
+
if (!r) throw new Error(`profile "${profile}" references unknown resource "${name}"`);
|
|
1869
|
+
return r;
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1753
1872
|
function loadManifestOrThrow(projectRoot) {
|
|
1754
1873
|
if (!manifestExists(projectRoot)) {
|
|
1755
1874
|
throw new Error(
|
|
@@ -1832,8 +1951,9 @@ async function handleTool(name, args) {
|
|
|
1832
1951
|
case "orbit.create": {
|
|
1833
1952
|
const branch = String(args.branch ?? "");
|
|
1834
1953
|
const baseRef = args.baseRef;
|
|
1954
|
+
const profile = args.profile;
|
|
1835
1955
|
if (!branch) return text({ error: "branch is required" });
|
|
1836
|
-
const result = await create({ branch, baseRef, projectRoot, logger });
|
|
1956
|
+
const result = await create({ branch, baseRef, profile, projectRoot, logger });
|
|
1837
1957
|
return text(result);
|
|
1838
1958
|
}
|
|
1839
1959
|
case "orbit.list": {
|
|
@@ -1865,7 +1985,9 @@ async function handleTool(name, args) {
|
|
|
1865
1985
|
const target = String(args.target ?? "");
|
|
1866
1986
|
if (!branch) return text({ error: "branch is required" });
|
|
1867
1987
|
if (!target) return text({ error: "target is required" });
|
|
1868
|
-
const
|
|
1988
|
+
const skipGates = parseSkipGates(args.skipGates);
|
|
1989
|
+
if (skipGates instanceof Error) return text({ error: skipGates.message });
|
|
1990
|
+
const result = await checkMergeable({ branch, target, skipGates, projectRoot, logger });
|
|
1869
1991
|
return text(result);
|
|
1870
1992
|
}
|
|
1871
1993
|
case "orbit.merge": {
|
|
@@ -1878,13 +2000,25 @@ async function handleTool(name, args) {
|
|
|
1878
2000
|
if (cleanup === void 0) {
|
|
1879
2001
|
return text({ error: `cleanup must be "full" or "none" (got ${JSON.stringify(cleanupArg)})` });
|
|
1880
2002
|
}
|
|
1881
|
-
const
|
|
2003
|
+
const skipGates = parseSkipGates(args.skipGates);
|
|
2004
|
+
if (skipGates instanceof Error) return text({ error: skipGates.message });
|
|
2005
|
+
const result = await merge({ branch, target, cleanup, skipGates, projectRoot, logger });
|
|
1882
2006
|
return text(result);
|
|
1883
2007
|
}
|
|
1884
2008
|
default:
|
|
1885
2009
|
return text({ error: `unknown tool: ${name}` });
|
|
1886
2010
|
}
|
|
1887
2011
|
}
|
|
2012
|
+
function parseSkipGates(raw) {
|
|
2013
|
+
if (raw === void 0 || raw === null) return void 0;
|
|
2014
|
+
if (!Array.isArray(raw)) return new Error("skipGates must be an array of adapter ids");
|
|
2015
|
+
const out = [];
|
|
2016
|
+
for (const v of raw) {
|
|
2017
|
+
if (typeof v !== "string" || !v) return new Error("skipGates entries must be non-empty strings");
|
|
2018
|
+
out.push(v);
|
|
2019
|
+
}
|
|
2020
|
+
return out.length > 0 ? out : void 0;
|
|
2021
|
+
}
|
|
1888
2022
|
function text(payload) {
|
|
1889
2023
|
const t = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2);
|
|
1890
2024
|
return { content: [{ type: "text", text: t }] };
|
|
@@ -1973,12 +2107,16 @@ var init_orbit_mcp = __esm({
|
|
|
1973
2107
|
TOOLS = [
|
|
1974
2108
|
{
|
|
1975
2109
|
name: "orbit.create",
|
|
1976
|
-
description: "Create an isolated worktree environment for a branch. Forks the resources declared in orbit.json (database, ports, etc.) so the new worktree is fully independent from the main one.\n\nReturns: { slug, branch, path, envFile, durationMs, resources, nextAction }. The `path` is the absolute worktree directory \u2014 the caller should `cd` into it for subsequent commands. `nextAction` contains the exact shell command to do so.",
|
|
2110
|
+
description: "Create an isolated worktree environment for a branch. Forks the resources declared in orbit.json (database, ports, etc.) so the new worktree is fully independent from the main one.\n\nPass `profile` to fork only a named subset of resources from orbit.json's `profiles` block \u2014 e.g. a frontend-only task can use a `fe` profile that skips the DB clone. Without `profile`, all manifest resources are forked.\n\nReturns: { slug, branch, path, envFile, durationMs, resources, nextAction }. The `path` is the absolute worktree directory \u2014 the caller should `cd` into it for subsequent commands. `nextAction` contains the exact shell command to do so.",
|
|
1977
2111
|
inputSchema: {
|
|
1978
2112
|
type: "object",
|
|
1979
2113
|
properties: {
|
|
1980
2114
|
branch: { type: "string", description: "Git branch name to create (also the slug source)." },
|
|
1981
|
-
baseRef: { type: "string", description: "Optional ref to branch from (default: current HEAD)." }
|
|
2115
|
+
baseRef: { type: "string", description: "Optional ref to branch from (default: current HEAD)." },
|
|
2116
|
+
profile: {
|
|
2117
|
+
type: "string",
|
|
2118
|
+
description: "Optional profile name from orbit.json's `profiles`. Scopes which resources are forked. Omit to fork all resources."
|
|
2119
|
+
}
|
|
1982
2120
|
},
|
|
1983
2121
|
required: ["branch"]
|
|
1984
2122
|
}
|
|
@@ -2018,19 +2156,24 @@ var init_orbit_mcp = __esm({
|
|
|
2018
2156
|
},
|
|
2019
2157
|
{
|
|
2020
2158
|
name: "orbit.check_mergeable",
|
|
2021
|
-
description:
|
|
2159
|
+
description: 'Run all configured pre-merge gates against an orbit + target branch WITHOUT actually merging. Used by agents to verify before calling orbit.merge. Default gates: builtin/mergeability (textual conflict check) and any others declared in orbit.json\'s `gates.merge`.\n\nPass `skipGates: ["builtin/build-lint"]` to bypass specific gates by adapter id. Gates marked `required: true` in orbit.json reject skipping and throw \u2014 typically used on the textual conflict check.\n\nReturns: { slug, branch, target, passed, gates: [{ gateId, ok, blockers, artifacts }], durationMs }. If `passed` is false, `gates` contains per-gate detail including human-readable blocker lines and paths to artifact logs (tsc output, lint output, etc.).',
|
|
2022
2160
|
inputSchema: {
|
|
2023
2161
|
type: "object",
|
|
2024
2162
|
properties: {
|
|
2025
2163
|
branch: { type: "string", description: "The orbit's branch (slug-able)." },
|
|
2026
|
-
target: { type: "string", description: "Branch we'd merge INTO." }
|
|
2164
|
+
target: { type: "string", description: "Branch we'd merge INTO." },
|
|
2165
|
+
skipGates: {
|
|
2166
|
+
type: "array",
|
|
2167
|
+
items: { type: "string" },
|
|
2168
|
+
description: 'Adapter ids to skip (e.g. ["builtin/build-lint"]). Throws if any id has `required: true` in orbit.json. Warns on unknown ids without failing.'
|
|
2169
|
+
}
|
|
2027
2170
|
},
|
|
2028
2171
|
required: ["branch", "target"]
|
|
2029
2172
|
}
|
|
2030
2173
|
},
|
|
2031
2174
|
{
|
|
2032
2175
|
name: "orbit.merge",
|
|
2033
|
-
description: 'Run gates, and if all pass, perform the merge into the target branch. Default cleanup behavior is `full` \u2014 after a successful merge, the orbit is dropped (DB pg_dump\'d, then DROP DATABASE; worktree removed; branch deleted). Use cleanup="none" to keep the orbit around post-merge.\n\nReturns: { slug, branch, target, merged, mergeSha, gates, cleanedUp, backupPath, durationMs, blockedBy }. If merged is false, blockedBy lists what stopped the merge (gate failures or git errors).',
|
|
2176
|
+
description: 'Run gates, and if all pass, perform the merge into the target branch. Default cleanup behavior is `full` \u2014 after a successful merge, the orbit is dropped (DB pg_dump\'d, then DROP DATABASE; worktree removed; branch deleted). Use cleanup="none" to keep the orbit around post-merge.\n\nPass `skipGates: ["builtin/build-lint"]` to bypass specific gates by adapter id. Gates marked `required: true` in orbit.json reject skipping and throw.\n\nReturns: { slug, branch, target, merged, mergeSha, gates, cleanedUp, backupPath, durationMs, blockedBy }. If merged is false, blockedBy lists what stopped the merge (gate failures or git errors).',
|
|
2034
2177
|
inputSchema: {
|
|
2035
2178
|
type: "object",
|
|
2036
2179
|
properties: {
|
|
@@ -2040,6 +2183,11 @@ var init_orbit_mcp = __esm({
|
|
|
2040
2183
|
type: "string",
|
|
2041
2184
|
enum: ["full", "none"],
|
|
2042
2185
|
description: "Post-merge action. `full` drops the orbit; `none` leaves it intact."
|
|
2186
|
+
},
|
|
2187
|
+
skipGates: {
|
|
2188
|
+
type: "array",
|
|
2189
|
+
items: { type: "string" },
|
|
2190
|
+
description: 'Adapter ids to skip (e.g. ["builtin/build-lint"]). Throws if any id has `required: true` in orbit.json. Warns on unknown ids without failing.'
|
|
2043
2191
|
}
|
|
2044
2192
|
},
|
|
2045
2193
|
required: ["branch", "target"]
|
|
@@ -2056,13 +2204,18 @@ init_orchestrator();
|
|
|
2056
2204
|
init_logger();
|
|
2057
2205
|
function parseFlags(argv) {
|
|
2058
2206
|
const positional = [];
|
|
2059
|
-
const flags = { emitCd: false, noBackup: false };
|
|
2207
|
+
const flags = { emitCd: false, noBackup: false, skipGates: [] };
|
|
2060
2208
|
for (let i = 0; i < argv.length; i++) {
|
|
2061
2209
|
const a = argv[i];
|
|
2062
2210
|
if (a === "--emit-cd") flags.emitCd = true;
|
|
2063
2211
|
else if (a === "--no-backup") flags.noBackup = true;
|
|
2064
2212
|
else if (a === "--base-ref") flags.baseRef = argv[++i];
|
|
2065
|
-
else if (a === "--
|
|
2213
|
+
else if (a === "--profile") flags.profile = argv[++i];
|
|
2214
|
+
else if (a === "--skip-gate") {
|
|
2215
|
+
const id = argv[++i];
|
|
2216
|
+
if (!id) die("--skip-gate requires an adapter id (e.g. --skip-gate builtin/build-lint)");
|
|
2217
|
+
flags.skipGates.push(id);
|
|
2218
|
+
} else if (a === "--cleanup") {
|
|
2066
2219
|
const v = argv[++i];
|
|
2067
2220
|
if (v !== "full" && v !== "none") {
|
|
2068
2221
|
process.stderr.write(`[launch-orbit] --cleanup must be "full" or "none" (got "${v}")
|
|
@@ -2097,10 +2250,11 @@ async function main() {
|
|
|
2097
2250
|
}
|
|
2098
2251
|
case "create": {
|
|
2099
2252
|
const branch = positional[0];
|
|
2100
|
-
if (!branch) die("usage: launch-orbit create <branch> [--base-ref <ref>] [--emit-cd]");
|
|
2253
|
+
if (!branch) die("usage: launch-orbit create <branch> [--base-ref <ref>] [--profile <name>] [--emit-cd]");
|
|
2101
2254
|
const result = await create({
|
|
2102
2255
|
branch,
|
|
2103
2256
|
baseRef: flags.baseRef,
|
|
2257
|
+
profile: flags.profile,
|
|
2104
2258
|
projectRoot,
|
|
2105
2259
|
logger
|
|
2106
2260
|
});
|
|
@@ -2169,11 +2323,12 @@ ${JSON.stringify(result, null, 2)}
|
|
|
2169
2323
|
const branch = positional[0];
|
|
2170
2324
|
const target = positional[1];
|
|
2171
2325
|
if (!branch || !target) {
|
|
2172
|
-
die("usage: launch-orbit check-merge <branch> <target>");
|
|
2326
|
+
die("usage: launch-orbit check-merge <branch> <target> [--skip-gate <id> ...]");
|
|
2173
2327
|
}
|
|
2174
2328
|
const result = await checkMergeable({
|
|
2175
2329
|
branch,
|
|
2176
2330
|
target,
|
|
2331
|
+
skipGates: flags.skipGates.length > 0 ? flags.skipGates : void 0,
|
|
2177
2332
|
projectRoot,
|
|
2178
2333
|
logger
|
|
2179
2334
|
});
|
|
@@ -2187,12 +2342,13 @@ ${JSON.stringify(result, null, 2)}
|
|
|
2187
2342
|
const branch = positional[0];
|
|
2188
2343
|
const target = positional[1];
|
|
2189
2344
|
if (!branch || !target) {
|
|
2190
|
-
die("usage: launch-orbit merge <branch> <target> [--cleanup full|none]");
|
|
2345
|
+
die("usage: launch-orbit merge <branch> <target> [--cleanup full|none] [--skip-gate <id> ...]");
|
|
2191
2346
|
}
|
|
2192
2347
|
const result = await merge({
|
|
2193
2348
|
branch,
|
|
2194
2349
|
target,
|
|
2195
2350
|
cleanup: flags.cleanup ?? "full",
|
|
2351
|
+
skipGates: flags.skipGates.length > 0 ? flags.skipGates : void 0,
|
|
2196
2352
|
projectRoot,
|
|
2197
2353
|
logger
|
|
2198
2354
|
});
|
|
@@ -2255,9 +2411,16 @@ function runInit(projectRoot) {
|
|
|
2255
2411
|
gates: {
|
|
2256
2412
|
merge: [
|
|
2257
2413
|
{ adapter: "builtin/clean-tree" },
|
|
2258
|
-
|
|
2414
|
+
// `required: true` blocks --skip-gate on this one — silently merging a
|
|
2415
|
+
// textual conflict is the obvious footgun. Drop the flag if you really
|
|
2416
|
+
// need to bypass.
|
|
2417
|
+
{ adapter: "builtin/mergeability", required: true },
|
|
2259
2418
|
{ adapter: "builtin/build-lint" }
|
|
2260
2419
|
]
|
|
2420
|
+
},
|
|
2421
|
+
profiles: {
|
|
2422
|
+
fe: { resources: ["ports"] },
|
|
2423
|
+
full: { resources: ["db", "ports"] }
|
|
2261
2424
|
}
|
|
2262
2425
|
};
|
|
2263
2426
|
(0, import_node_fs11.writeFileSync)(path, JSON.stringify(starter, null, 2) + "\n", "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@launchsecure/launch-kit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
4
4
|
"description": "LaunchSecure toolkit — launch-pod (pipeline), launch-chart (project graph MCP), launch-deck (visual playground MCP), launch-kit-beacon (feedback Web Component), launch-recall (file-watcher backup).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "LaunchSecure - AutomateWithUs",
|
|
@@ -52,7 +52,9 @@
|
|
|
52
52
|
"launch-chart": "./dist/server/graph-mcp-entry.js",
|
|
53
53
|
"launch-deck": "./dist/server/deck-mcp-entry.js",
|
|
54
54
|
"launch-recall": "./dist/server/recall-entry.js",
|
|
55
|
-
"launch-orbit": "./dist/server/orbit-entry.js"
|
|
55
|
+
"launch-orbit": "./dist/server/orbit-entry.js",
|
|
56
|
+
"launch-course": "./dist/server/course-entry.js",
|
|
57
|
+
"launch-beacon": "./dist/server/beacon-monitor-entry.js"
|
|
56
58
|
},
|
|
57
59
|
"scripts": {
|
|
58
60
|
"build": "pnpm build:client && pnpm build:chart-client && pnpm build:deck-client && pnpm build:council-client && pnpm build:beacon && pnpm build:server",
|
|
@@ -64,7 +66,7 @@
|
|
|
64
66
|
"build:council-client": "vite build --config vite.council.config.ts",
|
|
65
67
|
"build:client": "vite build",
|
|
66
68
|
"build:chart-client": "vite build --config vite.chart.config.ts",
|
|
67
|
-
"build:server": "esbuild src/server/cli.ts src/server/fb-wizard.ts src/server/graph-mcp-entry.ts src/server/chart-serve.ts src/server/deck-mcp-entry.ts src/server/deck-serve.ts src/server/council-entry.ts src/server/council-serve.ts src/server/recall-entry.ts src/server/init-entry.ts src/server/orbit-entry.ts src/server/parse-worker-entry.ts --bundle --platform=node --target=node18 --outdir=dist/server --external:node-pty --external:ws --external:typescript --external:web-tree-sitter --external:tree-sitter-typescript --external:cloudflared --external:pg --external:pg-native && rm -rf dist/server/public && cp -r ../claude-code-web/src/public dist/server/public && rm -rf dist/server/graph/queries && mkdir -p dist/server/graph && cp -r src/server/graph/queries dist/server/graph/queries",
|
|
69
|
+
"build:server": "esbuild src/server/cli.ts src/server/fb-wizard.ts src/server/graph-mcp-entry.ts src/server/chart-serve.ts src/server/deck-mcp-entry.ts src/server/deck-serve.ts src/server/council-entry.ts src/server/council-serve.ts src/server/recall-entry.ts src/server/init-entry.ts src/server/orbit-entry.ts src/server/course-entry.ts src/server/beacon-monitor-entry.ts src/server/parse-worker-entry.ts --bundle --platform=node --target=node18 --outdir=dist/server --external:node-pty --external:ws --external:typescript --external:web-tree-sitter --external:tree-sitter-typescript --external:cloudflared --external:pg --external:pg-native && rm -rf dist/server/public && cp -r ../claude-code-web/src/public dist/server/public && rm -rf dist/server/graph/queries && mkdir -p dist/server/graph && cp -r src/server/graph/queries dist/server/graph/queries",
|
|
68
70
|
"dev:client": "vite",
|
|
69
71
|
"dev:chart": "pnpm build:server && pnpm build:chart-client && node dist/server/graph-mcp-entry.js serve",
|
|
70
72
|
"dev:server": "pnpm build:server && node dist/server/cli.js",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "launch-secure",
|
|
3
|
+
"description": "LaunchSecure plugins for Claude Code — in-app feedback widget activation, and future LS-namespaced workflows. Distributed locally via launch-kit init today; the same catalog will move to github.com/launchsecure/claude-plugins for centralized updates.",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "LaunchSecure — AutomateWithUs",
|
|
6
|
+
"email": "hello@automatewith.us"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "kit",
|
|
11
|
+
"source": "./plugins/kit",
|
|
12
|
+
"description": "Kit-namespaced slash commands. Exposes /kit:activate-beacon to wire the launch-kit-beacon in-app feedback widget into the current project."
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "LaunchSecure commands for Claude Code — in-app feedback widget activation, daily standups posted to the Comm Hub, and future LS-namespaced workflows.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "LaunchSecure — AutomateWithUs",
|
|
7
|
+
"url": "https://automatewith.us"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/launchsecure/launchsecure-v2",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"launchsecure",
|
|
13
|
+
"launch-kit",
|
|
14
|
+
"launch-kit-beacon",
|
|
15
|
+
"feedback",
|
|
16
|
+
"standup",
|
|
17
|
+
"daily-update"
|
|
18
|
+
]
|
|
19
|
+
}
|