@dadado/agent-kit-cli 5.15.1 → 5.17.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.
Files changed (72) hide show
  1. package/dashboard/dashboard-data.mjs +69 -65
  2. package/dashboard/lib/guards.d.mts +5 -0
  3. package/dashboard/lib/guards.mjs +31 -0
  4. package/dashboard/lib/identity-probe.mjs +56 -0
  5. package/dashboard/lib/pipeline-cache.mjs +58 -0
  6. package/dashboard/lib/processes.mjs +71 -0
  7. package/dashboard/serve.mjs +43 -1
  8. package/dashboard/start-broadcast.mjs +2 -12
  9. package/dashboard/start.mjs +2 -13
  10. package/dist/add-HTYIFKMN.js +150 -0
  11. package/dist/chunk-2IPXQFJE.js +253 -0
  12. package/dist/chunk-2RDRMGD3.js +82 -0
  13. package/dist/chunk-2YU2H7I6.js +42 -0
  14. package/dist/chunk-4IWG5CVE.js +214 -0
  15. package/dist/chunk-5VCOWTTP.js +6 -0
  16. package/dist/chunk-77V75A7O.js +39 -0
  17. package/dist/chunk-7HDQEK6T.js +26 -0
  18. package/dist/chunk-AW74INUW.js +1456 -0
  19. package/dist/chunk-B73KQ5KX.js +972 -0
  20. package/dist/chunk-CBCW5R5J.js +484 -0
  21. package/dist/chunk-DE3LQFSJ.js +18 -0
  22. package/dist/chunk-DQA434Y4.js +106 -0
  23. package/dist/chunk-F4VMYR7U.js +318 -0
  24. package/dist/chunk-F6C3GFKV.js +57 -0
  25. package/dist/chunk-HFUH3HVS.js +282 -0
  26. package/dist/chunk-HS7LVVLO.js +74 -0
  27. package/dist/chunk-IHROBTNM.js +135 -0
  28. package/dist/chunk-KD2MYBB6.js +213 -0
  29. package/dist/chunk-MAPOQEA2.js +43 -0
  30. package/dist/chunk-N3HTJVBR.js +341 -0
  31. package/dist/chunk-NQ7IQ5XT.js +26 -0
  32. package/dist/chunk-OUQZC744.js +1315 -0
  33. package/dist/chunk-PCCQUWE5.js +817 -0
  34. package/dist/chunk-PNFF6OU3.js +273 -0
  35. package/dist/chunk-PNG7LO2F.js +53 -0
  36. package/dist/chunk-QTON2GQX.js +203 -0
  37. package/dist/chunk-S6GMFDKV.js +50 -0
  38. package/dist/chunk-SMGFN3Z4.js +503 -0
  39. package/dist/chunk-STGFBAYT.js +641 -0
  40. package/dist/chunk-TFZ2JUXH.js +1081 -0
  41. package/dist/chunk-VY7MTPJ2.js +205 -0
  42. package/dist/chunk-W24CMQ32.js +525 -0
  43. package/dist/chunk-WW3YZKHW.js +165 -0
  44. package/dist/chunk-ZB43YMHW.js +20 -0
  45. package/dist/chunk-ZCTSUQRR.js +874 -0
  46. package/dist/chunk-ZXKZBTXE.js +17 -0
  47. package/dist/contribute-C6AW2P6J.js +367 -0
  48. package/dist/cursor-awareness-KTL2RGKD.js +77 -0
  49. package/dist/dashboard-YSNUGBFY.js +21 -0
  50. package/dist/dashboard-broadcast-M4CMW7RX.js +119 -0
  51. package/dist/diff-VHNR62SI.js +74 -0
  52. package/dist/doctor-PET2HRRJ.js +236 -0
  53. package/dist/dogfood-KKFVRWT6.js +366 -0
  54. package/dist/guard-EHXF76ID.js +530 -0
  55. package/dist/handoff-3UI6VKVG.js +302 -0
  56. package/dist/hook-DYIMKJYL.js +1074 -0
  57. package/dist/index.js +62 -14068
  58. package/dist/init-Q4LBM6KT.js +127 -0
  59. package/dist/install-RHOS3OYZ.js +34 -0
  60. package/dist/mission-control-LJACEVVN.js +89 -0
  61. package/dist/monitors-QV2IS3MP.js +176 -0
  62. package/dist/plan-index-JMC7Z4DW.js +44 -0
  63. package/dist/public-inbound-radar-WP3XF7GS.js +68 -0
  64. package/dist/remote-issues-SZ4HDQL5.js +44 -0
  65. package/dist/run-I3BFGULT.js +243 -0
  66. package/dist/run-plan-FO7CL4M3.js +118 -0
  67. package/dist/scan-NI2SWJ2E.js +33 -0
  68. package/dist/setup-global-M42GEODI.js +340 -0
  69. package/dist/status-XPVQVQMX.js +150 -0
  70. package/dist/update-FJ2EBZVO.js +283 -0
  71. package/dist/validate-V2CW7J4B.js +201 -0
  72. package/package.json +3 -3
@@ -0,0 +1,17 @@
1
+ import {
2
+ writeJson
3
+ } from "./chunk-77V75A7O.js";
4
+
5
+ // src/scanner/snapshot.ts
6
+ import path from "path";
7
+ var READINESS_SNAPSHOT_RELATIVE_PATH = ".cursor/context/readiness.json";
8
+ async function writeReadinessSnapshot(rootDir, report) {
9
+ const snapshotPath = path.join(rootDir, READINESS_SNAPSHOT_RELATIVE_PATH);
10
+ await writeJson(snapshotPath, report);
11
+ return snapshotPath;
12
+ }
13
+
14
+ export {
15
+ READINESS_SNAPSHOT_RELATIVE_PATH,
16
+ writeReadinessSnapshot
17
+ };
@@ -0,0 +1,367 @@
1
+ import {
2
+ REGISTRY_CLI_ARGS,
3
+ resolveRegistryFromCli
4
+ } from "./chunk-PNG7LO2F.js";
5
+ import {
6
+ logger
7
+ } from "./chunk-ZB43YMHW.js";
8
+ import {
9
+ managedPairs
10
+ } from "./chunk-N3HTJVBR.js";
11
+ import {
12
+ loadAgentKitManifest,
13
+ normalizeRelPath,
14
+ resolveContained
15
+ } from "./chunk-AW74INUW.js";
16
+ import "./chunk-5VCOWTTP.js";
17
+ import "./chunk-77V75A7O.js";
18
+
19
+ // src/commands/contribute.ts
20
+ import { defineCommand } from "citty";
21
+
22
+ // src/lifecycle/contribute.ts
23
+ import { mkdir, readFile, writeFile } from "fs/promises";
24
+ import path from "path";
25
+
26
+ // src/lifecycle/contribute-gate.ts
27
+ var SECRET_PATTERNS = [
28
+ {
29
+ code: "secret-aws",
30
+ re: /AKIA[0-9A-Z]{16}/,
31
+ message: "Looks like an AWS access key id"
32
+ },
33
+ {
34
+ code: "secret-private-key",
35
+ re: /-----BEGIN (?:RSA |OPENSSH |EC )?PRIVATE KEY-----/,
36
+ message: "Contains a private key block"
37
+ },
38
+ {
39
+ code: "secret-bearer",
40
+ re: /(?:api[_-]?key|token|secret|password)\s*[:=]\s*['"][^'"]{12,}['"]/i,
41
+ message: "Looks like an inline API key / token / password"
42
+ },
43
+ {
44
+ code: "secret-github-pat",
45
+ re: /\bghp_[A-Za-z0-9]{20,}\b/,
46
+ message: "Looks like a GitHub personal access token"
47
+ }
48
+ ];
49
+ var HYGIENE_PATTERNS = [
50
+ {
51
+ code: "meta-agent",
52
+ re: /\b(como IA|as an AI|no meu racioc[ií]nio|vou usar a tool|contexto do chat)\b/i,
53
+ message: "Agent metalinguage \u2014 not allowed in versioned kit artifacts"
54
+ },
55
+ {
56
+ code: "session-transient",
57
+ re: /\b(conforme falamos|no chat anterior|WIP do agente|hoje eu configurei)\b/i,
58
+ message: "Session / chat-transient wording \u2014 rewrite in project voice"
59
+ }
60
+ ];
61
+ var BLOCKED_PATH_GLOBS = [
62
+ /^\.cursor\/HANDOFF\.md$/i,
63
+ /^\.cursor\/plans\//i,
64
+ /^\.cursor\/memory\//i,
65
+ /^\.cursor\/context\//i,
66
+ /^\.env/i,
67
+ /(^|\/)credentials?\./i,
68
+ /(^|\/)secrets?\./i
69
+ ];
70
+ var MAX_BYTES = 2e5;
71
+ function gateContributePath(projectRel) {
72
+ const posix = projectRel.split("\\").join("/");
73
+ const issues = [];
74
+ for (const re of BLOCKED_PATH_GLOBS) {
75
+ if (re.test(posix)) {
76
+ issues.push({
77
+ code: "path-blocked",
78
+ message: `Path is session/L3 or secret-like \u2014 cannot contribute: ${posix}`
79
+ });
80
+ }
81
+ }
82
+ return issues;
83
+ }
84
+ function gateContributeContent(content, projectRel) {
85
+ const issues = [...gateContributePath(projectRel)];
86
+ const bytes = Buffer.byteLength(content, "utf8");
87
+ if (bytes > MAX_BYTES) {
88
+ issues.push({
89
+ code: "too-large",
90
+ message: `File too large (${bytes} bytes; max ${MAX_BYTES})`
91
+ });
92
+ }
93
+ for (const p of SECRET_PATTERNS) {
94
+ if (p.re.test(content)) issues.push({ code: p.code, message: p.message });
95
+ }
96
+ for (const p of HYGIENE_PATTERNS) {
97
+ if (p.re.test(content)) issues.push({ code: p.code, message: p.message });
98
+ }
99
+ return { ok: issues.length === 0, issues };
100
+ }
101
+
102
+ // src/lifecycle/contribute.ts
103
+ async function readLocal(projectRoot, rel) {
104
+ try {
105
+ return await readFile(resolveContained(projectRoot, rel), "utf8");
106
+ } catch {
107
+ return null;
108
+ }
109
+ }
110
+ async function buildRegistryPathMap(registryRoot, manifest) {
111
+ const map = /* @__PURE__ */ new Map();
112
+ for (const { sourceRel, targetRel } of (await managedPairs(registryRoot, manifest)).pairs) {
113
+ map.set(targetRel, sourceRel);
114
+ }
115
+ return map;
116
+ }
117
+ function guessRegistryPath(projectRel) {
118
+ const p = projectRel.split(path.sep).join("/");
119
+ if (p.startsWith(".cursor/skills/")) {
120
+ const rest = p.slice(".cursor/skills/".length);
121
+ const parts = rest.split("/");
122
+ if (parts.length >= 3 && (parts[0] === "core" || parts[0] === "community")) {
123
+ return path.posix.join("registry/skills", rest);
124
+ }
125
+ const skillId = parts[0];
126
+ if (parts.length >= 2 && skillId) {
127
+ return path.posix.join("registry/skills", "community", rest);
128
+ }
129
+ }
130
+ if (p.startsWith(".cursor/rules/")) {
131
+ return p;
132
+ }
133
+ if (p.startsWith(".cursor/commands/")) {
134
+ return p;
135
+ }
136
+ if (p.startsWith(".cursor/agents/")) {
137
+ return p;
138
+ }
139
+ if (p.startsWith(".cursor/hooks/")) {
140
+ return p;
141
+ }
142
+ if (p.startsWith("autogit/")) {
143
+ return p;
144
+ }
145
+ return null;
146
+ }
147
+ async function planContribute(options) {
148
+ const includeDrift = options.includeDrift !== false;
149
+ const pathMap = await buildRegistryPathMap(options.registryRoot, options.manifest);
150
+ const candidates = [];
151
+ const seen = /* @__PURE__ */ new Set();
152
+ const push = async (kind, projectPath, registryPath) => {
153
+ const key = projectPath.split(path.sep).join("/");
154
+ if (seen.has(key)) return;
155
+ seen.add(key);
156
+ const content = await readLocal(options.projectRoot, projectPath);
157
+ if (content === null) {
158
+ return;
159
+ }
160
+ if (kind === "drift") {
161
+ try {
162
+ const upstream = await readFile(
163
+ resolveContained(options.registryRoot, registryPath),
164
+ "utf8"
165
+ );
166
+ if (upstream === content) return;
167
+ } catch {
168
+ }
169
+ }
170
+ const gate = gateContributeContent(content, key);
171
+ candidates.push({
172
+ kind,
173
+ projectPath: key,
174
+ registryPath,
175
+ gateOk: gate.ok,
176
+ issues: gate.issues
177
+ });
178
+ };
179
+ if (includeDrift) {
180
+ for (const [projectPath, registryPath] of pathMap) {
181
+ await push("drift", projectPath, registryPath);
182
+ }
183
+ }
184
+ for (const raw of options.extraPaths ?? []) {
185
+ const projectPath = path.posix.normalize(normalizeRelPath(raw));
186
+ const escapes = path.posix.isAbsolute(projectPath) || /^[A-Za-z]:\//.test(projectPath) || projectPath === ".." || projectPath.startsWith("../");
187
+ const blocked = escapes ? [
188
+ {
189
+ code: "path-blocked",
190
+ message: `Path is absolute or escapes the project root \u2014 cannot contribute: ${projectPath}`
191
+ }
192
+ ] : gateContributePath(projectPath);
193
+ if (blocked.length > 0) {
194
+ if (!seen.has(projectPath)) {
195
+ seen.add(projectPath);
196
+ candidates.push({
197
+ kind: "path",
198
+ projectPath,
199
+ registryPath: "",
200
+ gateOk: false,
201
+ issues: blocked
202
+ });
203
+ }
204
+ continue;
205
+ }
206
+ const mapped = pathMap.get(projectPath) ?? guessRegistryPath(projectPath);
207
+ if (!mapped) {
208
+ candidates.push({
209
+ kind: "path",
210
+ projectPath,
211
+ registryPath: "",
212
+ gateOk: false,
213
+ issues: [
214
+ {
215
+ code: "unmapped",
216
+ message: "Cannot map to a registry path \u2014 pass an installed kit artifact or .cursor/{rules,commands,skills,agents,hooks}/*"
217
+ }
218
+ ]
219
+ });
220
+ continue;
221
+ }
222
+ await push("path", projectPath, mapped);
223
+ }
224
+ return {
225
+ candidates,
226
+ accepted: candidates.filter((c) => c.gateOk),
227
+ rejected: candidates.filter((c) => !c.gateOk)
228
+ };
229
+ }
230
+ async function writeContributeToRegistry(projectRoot, registryRoot, accepted) {
231
+ const written = [];
232
+ for (const c of accepted) {
233
+ if (!c.registryPath) continue;
234
+ const content = await readFile(resolveContained(projectRoot, c.projectPath), "utf8");
235
+ const dest = resolveContained(registryRoot, c.registryPath);
236
+ await mkdir(path.dirname(dest), { recursive: true });
237
+ await writeFile(dest, content, "utf8");
238
+ written.push(c.registryPath);
239
+ }
240
+ return written;
241
+ }
242
+ function formatPrBody(accepted) {
243
+ const bullets = accepted.map((c) => `- \`${c.projectPath}\` \u2192 \`${c.registryPath}\``).join("\n");
244
+ return [
245
+ "## Summary",
246
+ "Upstream contribution from a consumer project via `agent-kit contribute`.",
247
+ "",
248
+ "### Files",
249
+ bullets || "- (none)",
250
+ "",
251
+ "## Checklist",
252
+ "- [ ] Anti-slop / hygiene gate passed locally",
253
+ "- [ ] No secrets or session state (HANDOFF/plans/memory)",
254
+ "- [ ] Docs / registry index updated if this adds a skill or pack member",
255
+ ""
256
+ ].join("\n");
257
+ }
258
+
259
+ // src/commands/contribute.ts
260
+ function parsePaths(raw) {
261
+ if (!raw?.trim()) return [];
262
+ return [
263
+ ...new Set(
264
+ raw.split(",").map((s) => s.trim()).filter(Boolean)
265
+ )
266
+ ];
267
+ }
268
+ var contributeCommand = defineCommand({
269
+ meta: {
270
+ name: "contribute",
271
+ description: "Propose upstream changes: detect local drift/new kit artifacts, run anti-slop gate, optionally write into a kit checkout for a PR."
272
+ },
273
+ args: {
274
+ cwd: {
275
+ type: "string",
276
+ default: process.cwd()
277
+ },
278
+ path: {
279
+ type: "string",
280
+ description: "Comma-separated project-relative paths to contribute (new or edited)"
281
+ },
282
+ drift: {
283
+ type: "boolean",
284
+ description: "Include drifted installed L0/pack/skill files vs registry (default: true)",
285
+ default: true
286
+ },
287
+ write: {
288
+ type: "boolean",
289
+ description: "Copy accepted files into the local kit/registry checkout (--registry required / resolved)",
290
+ default: false
291
+ },
292
+ ...REGISTRY_CLI_ARGS
293
+ },
294
+ async run({ args }) {
295
+ const manifest = await loadAgentKitManifest(args.cwd, { onWarning: logger.warn });
296
+ if (!manifest) {
297
+ logger.warn("No .cursor/agent-kit.json \u2014 run agent-kit install first.");
298
+ return;
299
+ }
300
+ const registry = await resolveRegistryFromCli({
301
+ cwd: args.cwd,
302
+ registry: args.registry,
303
+ url: args.url,
304
+ ref: args.ref,
305
+ refresh: args.refresh,
306
+ manifest
307
+ });
308
+ try {
309
+ if (registry.source !== "flag" && args.write) {
310
+ logger.warn(
311
+ "contribute --write needs a local kit checkout. Pass --registry /path/to/agent-kit."
312
+ );
313
+ return;
314
+ }
315
+ logger.info(`Registry: ${registry.root} (${registry.source})`);
316
+ const plan = await planContribute({
317
+ registryRoot: registry.root,
318
+ projectRoot: args.cwd,
319
+ manifest,
320
+ extraPaths: parsePaths(args.path),
321
+ includeDrift: args.drift
322
+ });
323
+ console.log(
324
+ `Contribute plan: accepted=${plan.accepted.length} rejected=${plan.rejected.length} (drift scan=${args.drift})`
325
+ );
326
+ if (plan.candidates.length === 0) {
327
+ logger.success("Nothing to contribute (no drift / no --path).");
328
+ return;
329
+ }
330
+ for (const c of plan.candidates) {
331
+ const mark = c.gateOk ? "ok" : "FAIL";
332
+ console.log(
333
+ `${mark.padEnd(4)} ${c.kind.padEnd(5)} ${c.projectPath} \u2192 ${c.registryPath || "(unmapped)"}`
334
+ );
335
+ for (const issue of c.issues) {
336
+ console.log(` [${issue.code}] ${issue.message}`);
337
+ }
338
+ }
339
+ if (plan.accepted.length === 0) {
340
+ logger.warn("No files passed the contribute gate.");
341
+ return;
342
+ }
343
+ console.log("\n--- Suggested PR body ---\n");
344
+ console.log(formatPrBody(plan.accepted));
345
+ if (!args.write) {
346
+ logger.info(
347
+ "Dry run. Re-run with --write --registry /path/to/agent-kit to copy accepted files into the kit checkout, then open a PR (gh pr create --base main)."
348
+ );
349
+ return;
350
+ }
351
+ const written = await writeContributeToRegistry(args.cwd, registry.root, plan.accepted);
352
+ logger.success(`Wrote ${written.length} file(s) into ${registry.root}`);
353
+ for (const p of written) console.log(` + ${p}`);
354
+ console.log("\nNext (HITL \u2014 review before push):");
355
+ console.log(` cd ${registry.root}`);
356
+ console.log(" git checkout -b contribute/<short-topic>");
357
+ console.log(' git add <files> && git commit -m "feat: contribute <topic> from consumer"');
358
+ console.log(" git push -u origin HEAD");
359
+ console.log(' gh pr create --base main --title "feat: contribute <topic>" --body-file -');
360
+ } finally {
361
+ await registry.unlock?.();
362
+ }
363
+ }
364
+ });
365
+ export {
366
+ contributeCommand
367
+ };
@@ -0,0 +1,77 @@
1
+ import {
2
+ checkCursorUpdateAwareness
3
+ } from "./chunk-CBCW5R5J.js";
4
+ import {
5
+ logger
6
+ } from "./chunk-ZB43YMHW.js";
7
+ import "./chunk-NQ7IQ5XT.js";
8
+ import "./chunk-77V75A7O.js";
9
+
10
+ // src/commands/cursor-awareness.ts
11
+ import { defineCommand } from "citty";
12
+ var cursorAwarenessCommand = defineCommand({
13
+ meta: {
14
+ name: "cursor-awareness",
15
+ description: "Opt-in advisory: Cursor changelog vs native-audit gaps (never apply)."
16
+ },
17
+ args: {
18
+ cwd: {
19
+ type: "string",
20
+ default: process.cwd()
21
+ },
22
+ check: {
23
+ type: "boolean",
24
+ description: "Check-only (default true; apply is never supported)",
25
+ default: true
26
+ },
27
+ json: {
28
+ type: "boolean",
29
+ description: "Print machine-readable JSON",
30
+ default: false
31
+ },
32
+ "respect-prefs": {
33
+ type: "boolean",
34
+ description: "Honor cursorUpdateCheck.enabled and intervalDays from .cursor/context/config.json",
35
+ default: false
36
+ },
37
+ stamp: {
38
+ type: "boolean",
39
+ description: "Persist cursorUpdateCheck.lastCheckedAt / lastSeenCursorVersion",
40
+ default: false
41
+ },
42
+ offline: {
43
+ type: "boolean",
44
+ description: "Skip changelog network fetch; inventory-only advisory",
45
+ default: false
46
+ }
47
+ },
48
+ async run({ args }) {
49
+ void args.check;
50
+ const result = await checkCursorUpdateAwareness(args.cwd, {
51
+ respectPrefs: Boolean(args["respect-prefs"]),
52
+ stamp: Boolean(args.stamp),
53
+ offline: Boolean(args.offline)
54
+ });
55
+ if (args.json) {
56
+ console.log(JSON.stringify(result, null, 2));
57
+ } else {
58
+ const line = `[${result.status}] ${result.message}`;
59
+ if (result.status === "error") logger.error(line);
60
+ else if (result.status === "gaps-found") logger.warn(line);
61
+ else if (result.status.startsWith("skipped-")) logger.warn(line);
62
+ else logger.info(line);
63
+ if (result.gaps.length > 0 && !args.json) {
64
+ for (const gap of result.gaps.slice(0, 12)) {
65
+ logger.info(`- ${gap.id} (${gap.severity}): ${gap.evidence} \u2192 ${gap.suggestedRoute}`);
66
+ }
67
+ if (result.gaps.length > 12) {
68
+ logger.info(`\u2026 and ${result.gaps.length - 12} more (use --json)`);
69
+ }
70
+ }
71
+ }
72
+ if (result.status === "error") process.exitCode = 2;
73
+ }
74
+ });
75
+ export {
76
+ cursorAwarenessCommand
77
+ };
@@ -0,0 +1,21 @@
1
+ import {
2
+ applyDashboardOpenEnv,
3
+ bundledDashboardCandidates,
4
+ dashboardCommand,
5
+ dashboardProcessTitle,
6
+ dashboardSpawnEnv,
7
+ findDashboardStart,
8
+ readPreferredBrowserFromWorkspace,
9
+ resolveDashboardSnapshotRoot
10
+ } from "./chunk-HFUH3HVS.js";
11
+ import "./chunk-ZB43YMHW.js";
12
+ export {
13
+ applyDashboardOpenEnv,
14
+ bundledDashboardCandidates,
15
+ dashboardCommand,
16
+ dashboardProcessTitle,
17
+ dashboardSpawnEnv,
18
+ findDashboardStart,
19
+ readPreferredBrowserFromWorkspace,
20
+ resolveDashboardSnapshotRoot
21
+ };
@@ -0,0 +1,119 @@
1
+ import {
2
+ bundledDashboardCandidates,
3
+ dashboardProcessTitle,
4
+ dashboardSpawnEnv,
5
+ findDashboardStart,
6
+ resolveDashboardSnapshotRoot
7
+ } from "./chunk-HFUH3HVS.js";
8
+ import {
9
+ logger
10
+ } from "./chunk-ZB43YMHW.js";
11
+
12
+ // src/commands/dashboard-broadcast.ts
13
+ import { spawn } from "child_process";
14
+ import { access } from "fs/promises";
15
+ import path from "path";
16
+ import { defineCommand } from "citty";
17
+ async function findDashboardBroadcastStart(cwd, env = process.env, options = {}) {
18
+ let dir = path.resolve(cwd);
19
+ for (; ; ) {
20
+ const candidate = path.join(dir, "dashboard", "start-broadcast.mjs");
21
+ try {
22
+ await access(candidate);
23
+ return candidate;
24
+ } catch {
25
+ }
26
+ const parent = path.dirname(dir);
27
+ if (parent === dir) break;
28
+ dir = parent;
29
+ }
30
+ for (const key of ["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]) {
31
+ const base = env[key];
32
+ if (!base || typeof base !== "string" || !base.trim()) continue;
33
+ const candidate = path.join(path.resolve(base.trim()), "dashboard", "start-broadcast.mjs");
34
+ try {
35
+ await access(candidate);
36
+ return candidate;
37
+ } catch {
38
+ }
39
+ }
40
+ const sibling = path.join(
41
+ path.resolve(cwd),
42
+ "..",
43
+ "agent-kit",
44
+ "dashboard",
45
+ "start-broadcast.mjs"
46
+ );
47
+ try {
48
+ await access(sibling);
49
+ return path.resolve(sibling);
50
+ } catch {
51
+ }
52
+ for (const candidate of bundledDashboardCandidates(
53
+ "start-broadcast.mjs",
54
+ options.moduleUrl ?? import.meta.url
55
+ )) {
56
+ try {
57
+ await access(candidate);
58
+ return path.resolve(candidate);
59
+ } catch {
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ function runStartScript(startPath, env) {
65
+ return new Promise((resolve, reject) => {
66
+ const child = spawn(process.execPath, [startPath], {
67
+ cwd: path.dirname(path.dirname(startPath)),
68
+ env,
69
+ stdio: "inherit"
70
+ });
71
+ child.on("error", reject);
72
+ child.on("close", (code) => resolve(code ?? 1));
73
+ });
74
+ }
75
+ var dashboardBroadcastCommand = defineCommand({
76
+ meta: {
77
+ name: "dashboard-broadcast",
78
+ description: "Opt-in LAN Mission Control (token-gated). Terminal counterpart to /dashboard-broadcast. Does not change loopback /dashboard."
79
+ },
80
+ args: {
81
+ cwd: {
82
+ type: "string",
83
+ default: process.cwd(),
84
+ description: "Directory to search upward for dashboard/start-broadcast.mjs"
85
+ },
86
+ "no-open": {
87
+ type: "boolean",
88
+ default: false,
89
+ description: "Do not open a browser; only ensure the server is up and print Share URL (when masking is on) plus token / LAN lines"
90
+ },
91
+ browser: {
92
+ type: "string",
93
+ description: "Preferred browser app/binary for this launch (overrides config missionControl.preferredBrowser)"
94
+ }
95
+ },
96
+ async run({ args }) {
97
+ const startPath = await findDashboardBroadcastStart(args.cwd);
98
+ if (!startPath) {
99
+ const loopback = await findDashboardStart(args.cwd);
100
+ logger.error(
101
+ loopback ? "No dashboard/start-broadcast.mjs found beside dashboard/start.mjs. Update the agent-kit tree or reinstall a CLI that ships dashboard/, then retry." : "No dashboard/start-broadcast.mjs found. After a CLI publish that ships dashboard/ (Path C), reinstall @dadado/agent-kit-cli. Or run from an agent-kit tree that includes dashboard/."
102
+ );
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ const snapshotRoot = resolveDashboardSnapshotRoot(args.cwd);
107
+ const env = dashboardSpawnEnv({ ...process.env }, snapshotRoot, {
108
+ noOpen: Boolean(args["no-open"]),
109
+ browser: args.browser
110
+ });
111
+ process.title = dashboardProcessTitle(snapshotRoot);
112
+ const code = await runStartScript(startPath, env);
113
+ if (code !== 0) process.exitCode = code;
114
+ }
115
+ });
116
+ export {
117
+ dashboardBroadcastCommand,
118
+ findDashboardBroadcastStart
119
+ };
@@ -0,0 +1,74 @@
1
+ import {
2
+ REGISTRY_CLI_ARGS,
3
+ resolveRegistryFromCli
4
+ } from "./chunk-PNG7LO2F.js";
5
+ import {
6
+ logger
7
+ } from "./chunk-ZB43YMHW.js";
8
+ import {
9
+ diffAgainstRegistry,
10
+ summarizeDiff
11
+ } from "./chunk-2RDRMGD3.js";
12
+ import "./chunk-N3HTJVBR.js";
13
+ import {
14
+ loadAgentKitManifest
15
+ } from "./chunk-AW74INUW.js";
16
+ import "./chunk-5VCOWTTP.js";
17
+ import "./chunk-77V75A7O.js";
18
+
19
+ // src/commands/diff.ts
20
+ import { defineCommand } from "citty";
21
+ var diffCommand = defineCommand({
22
+ meta: {
23
+ name: "diff",
24
+ description: "Compare installed kit artifacts to the registry (respects L3 protected)."
25
+ },
26
+ args: {
27
+ cwd: {
28
+ type: "string",
29
+ default: process.cwd()
30
+ },
31
+ all: {
32
+ type: "boolean",
33
+ description: "Include matching files in the report",
34
+ default: false
35
+ },
36
+ ...REGISTRY_CLI_ARGS
37
+ },
38
+ async run({ args }) {
39
+ const manifest = await loadAgentKitManifest(args.cwd, { onWarning: logger.warn });
40
+ if (!manifest) {
41
+ logger.warn("No .cursor/agent-kit.json \u2014 run agent-kit install first.");
42
+ return;
43
+ }
44
+ const registry = await resolveRegistryFromCli({
45
+ cwd: args.cwd,
46
+ registry: args.registry,
47
+ url: args.url,
48
+ ref: args.ref,
49
+ refresh: args.refresh,
50
+ manifest
51
+ });
52
+ try {
53
+ logger.info(`Registry: ${registry.root} (${registry.source})`);
54
+ const entries = await diffAgainstRegistry(registry.root, args.cwd, manifest);
55
+ const summary = summarizeDiff(entries);
56
+ console.log(
57
+ `Summary: match=${summary.match} drift=${summary.drift} missing-local=${summary["missing-local"]} missing-registry=${summary["missing-registry"]} protected=${summary.protected}`
58
+ );
59
+ const rows = args.all ? entries : entries.filter((e) => e.status !== "match");
60
+ if (rows.length === 0) {
61
+ logger.success("No drift (matches only).");
62
+ return;
63
+ }
64
+ for (const e of rows) {
65
+ console.log(`${e.status.padEnd(18)} ${e.path}`);
66
+ }
67
+ } finally {
68
+ await registry.unlock?.();
69
+ }
70
+ }
71
+ });
72
+ export {
73
+ diffCommand
74
+ };