@dadado/agent-kit-cli 5.6.0 → 5.7.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { defineCommand as defineCommand20, runMain, showUsage } from "citty";
4
+ import { defineCommand as defineCommand21, runMain, showUsage } from "citty";
5
5
 
6
6
  // src/commands/add.ts
7
7
  import { defineCommand } from "citty";
@@ -220,7 +220,14 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
220
220
  "359a142aeadd769a9b89ac909ae5129940e7e6b0892b70256098c584d97631ce",
221
221
  "8eab94f7a78149db1bbbc0fd45f21dc2d874209d534bcff39077fd6e1d2c42fb",
222
222
  "9be406f92f7dca71f3af814b14fb26b011f9f12c37c789f7ddc3d647b1a7ab60",
223
- "bb67ddcdd9ab58ed89287421f5e4b6ebfb3941e6a789287ddec9b9c25b56b1ed"
223
+ "bb67ddcdd9ab58ed89287421f5e4b6ebfb3941e6a789287ddec9b9c25b56b1ed",
224
+ "7343ecd797f484eea1a3ebc11e87c75d90f617bd627bfc367a1eca5a1628bdf1",
225
+ "8a723b4808f14413fc173a6ce33370067ffc78d0c2e05a21c4406d7fa3e66457",
226
+ "65554e304a70b77e07fe40facf0ef305d6216399bfbb811db2491ce2f31d86d7",
227
+ "f8cc89a52fb1ec17f7f26ecd5cb18f79a5e9c7b7ffe7a6899465aa4090433b98",
228
+ "543e6596e7ce9f3ce4de642f1ea7e5d437d553fa28c0d56eb0f244ec8526ce17",
229
+ "71c6d1cce604c4a275db7c9a5c48f1753604bf35e083be054511ebc91f4977e6",
230
+ "8d0fd61bcbb9e035dea3a8b9f298a48c226bb28785923cb07e1154cf084934ad"
224
231
  ]);
225
232
 
226
233
  // src/lifecycle/paths.ts
@@ -1527,6 +1534,11 @@ var L0_ARTIFACTS = [
1527
1534
  target: ".cursor/commands/git-staging.md"
1528
1535
  },
1529
1536
  { source: ".cursor/commands/git-prod.md", target: ".cursor/commands/git-prod.md" },
1537
+ {
1538
+ source: ".cursor/commands/kit-staging.md",
1539
+ target: ".cursor/commands/kit-staging.md"
1540
+ },
1541
+ { source: ".cursor/commands/kit-prod.md", target: ".cursor/commands/kit-prod.md" },
1530
1542
  {
1531
1543
  source: ".cursor/commands/plan-external-review.md",
1532
1544
  target: ".cursor/commands/plan-external-review.md"
@@ -2386,6 +2398,7 @@ import { defineCommand as defineCommand4 } from "citty";
2386
2398
  import { randomBytes, timingSafeEqual } from "crypto";
2387
2399
  import { networkInterfaces } from "os";
2388
2400
  import { resolve } from "path";
2401
+ var REPO_ROOT_ENV = "MISSION_CONTROL_REPO_ROOT";
2389
2402
  var KIT_ROOT_ENV_KEYS = Object.freeze(["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]);
2390
2403
  var CONTEXT_CONFIG_REL = ".cursor/context/config.json";
2391
2404
  var CONFIG_PERSONA_IDS = Object.freeze(["autopilot", "night-shift", "ghost-runner"]);
@@ -2571,14 +2584,14 @@ function resolveDashboardSnapshotRoot(cwd) {
2571
2584
  return abs;
2572
2585
  }
2573
2586
  function runStartScript(startPath, env) {
2574
- return new Promise((resolve2, reject) => {
2587
+ return new Promise((resolve3, reject) => {
2575
2588
  const child = spawn2(process.execPath, [startPath], {
2576
2589
  cwd: path11.dirname(path11.dirname(startPath)),
2577
2590
  env,
2578
2591
  stdio: "inherit"
2579
2592
  });
2580
2593
  child.on("error", reject);
2581
- child.on("close", (code) => resolve2(code ?? 1));
2594
+ child.on("close", (code) => resolve3(code ?? 1));
2582
2595
  });
2583
2596
  }
2584
2597
  var dashboardCommand = defineCommand4({
@@ -2688,14 +2701,14 @@ async function findDashboardBroadcastStart(cwd, env = process.env, options = {})
2688
2701
  return null;
2689
2702
  }
2690
2703
  function runStartScript2(startPath, env) {
2691
- return new Promise((resolve2, reject) => {
2704
+ return new Promise((resolve3, reject) => {
2692
2705
  const child = spawn3(process.execPath, [startPath], {
2693
2706
  cwd: path12.dirname(path12.dirname(startPath)),
2694
2707
  env,
2695
2708
  stdio: "inherit"
2696
2709
  });
2697
2710
  child.on("error", reject);
2698
- child.on("close", (code) => resolve2(code ?? 1));
2711
+ child.on("close", (code) => resolve3(code ?? 1));
2699
2712
  });
2700
2713
  }
2701
2714
  var dashboardBroadcastCommand = defineCommand5({
@@ -3394,9 +3407,9 @@ function buildPillars(scan) {
3394
3407
  check(
3395
3408
  "stack.detected",
3396
3409
  "Stack and package manager",
3397
- scan.stack.language !== "unknown" || scan.purpose.value !== "unknown" ? "ready" : "needs_choice",
3410
+ scan.stack.language !== "unknown" || scan.stack.hasProjectFiles ? "ready" : "needs_choice",
3398
3411
  true,
3399
- scan.stack.packageManagerEvidence ?? scan.purpose.evidence
3412
+ scan.stack.packageManagerEvidence ?? []
3400
3413
  )
3401
3414
  ]),
3402
3415
  pillar("quality-ci", [
@@ -3530,7 +3543,40 @@ async function detectContext(rootDir) {
3530
3543
  )
3531
3544
  };
3532
3545
  }
3546
+ var REPOSITORY_PURPOSE_VALUES = [
3547
+ "application",
3548
+ "library",
3549
+ "monorepo",
3550
+ "documentation",
3551
+ "knowledge",
3552
+ "operations",
3553
+ "automation",
3554
+ "mixed",
3555
+ "unknown"
3556
+ ];
3557
+ function isRepositoryPurpose(value) {
3558
+ return typeof value === "string" && REPOSITORY_PURPOSE_VALUES.includes(value);
3559
+ }
3560
+ async function readConfirmedPurpose(rootDir) {
3561
+ const configuration = await readJson(
3562
+ path16.join(rootDir, ".cursor", "agent-kit.config.json")
3563
+ );
3564
+ const configuredPurpose = configuration?.purpose;
3565
+ if (!configuredPurpose || !isRepositoryPurpose(configuredPurpose.value) || configuredPurpose.value === "unknown") {
3566
+ return void 0;
3567
+ }
3568
+ const categories = Array.isArray(configuredPurpose.categories) ? configuredPurpose.categories.filter(isRepositoryPurpose) : [];
3569
+ const evidence = Array.isArray(configuredPurpose.evidence) ? configuredPurpose.evidence : [];
3570
+ return {
3571
+ value: configuredPurpose.value,
3572
+ categories: categories.length > 0 ? categories : [configuredPurpose.value],
3573
+ confidence: "high",
3574
+ evidence: evidence.length > 0 ? evidence : [{ source: "configuration", value: ".cursor/agent-kit.config.json#purpose.value" }]
3575
+ };
3576
+ }
3533
3577
  async function detectPurpose(rootDir, stack) {
3578
+ const confirmed = await readConfirmedPurpose(rootDir);
3579
+ if (confirmed) return confirmed;
3534
3580
  const entries = await listDirectory(rootDir);
3535
3581
  const lowerEntries = entries.map((entry) => entry.toLowerCase());
3536
3582
  const packageJson = await readJson(path16.join(rootDir, "package.json"));
@@ -3595,6 +3641,13 @@ var REQUIRED_SECRET_PATTERNS = [
3595
3641
  "*credentials*.json",
3596
3642
  "*service-account*.json"
3597
3643
  ];
3644
+ var KIT_OWNED_IGNORE_PATTERNS = [
3645
+ ".cursor/HANDOFF.md",
3646
+ ".cursor/dogfood/",
3647
+ ".cursor/context/readiness.json",
3648
+ ".cursor/context/flight-log.json",
3649
+ ".cursor/context/mission-timing.json"
3650
+ ];
3598
3651
  async function detectSafety(rootDir, trackedFiles) {
3599
3652
  const gitignorePath = path16.join(rootDir, ".gitignore");
3600
3653
  const hasGitignore = await fileExists(gitignorePath);
@@ -3734,7 +3787,8 @@ async function detectProvider(rootDir, remoteUrl) {
3734
3787
  evidence: remoteEvidence
3735
3788
  };
3736
3789
  }
3737
- function inferWorkflow(currentBranch) {
3790
+ function inferWorkflow(currentBranch, hasLocalStaging, hasRemoteStaging) {
3791
+ if (hasLocalStaging || hasRemoteStaging) return "homolog-prod";
3738
3792
  if (!currentBranch) return "unknown";
3739
3793
  if (currentBranch === "main" || currentBranch === "master") return "feature-pr";
3740
3794
  if (currentBranch.includes("develop") || currentBranch.includes("release")) return "gitflow";
@@ -3787,6 +3841,8 @@ async function detectGit(rootDir) {
3787
3841
  const localBranches = localBranchOutput?.split("\n").filter(Boolean);
3788
3842
  const remoteBranches = remoteBranchOutput?.split("\n").filter(Boolean);
3789
3843
  const defaultBranch = remoteHead?.split("/").slice(1).join("/") || (localBranches?.includes("main") ? "main" : localBranches?.includes("master") ? "master" : void 0);
3844
+ const hasLocalStaging = localBranches?.includes("staging") ?? false;
3845
+ const hasRemoteStaging = remoteBranches?.some((branch) => branch === "origin/staging" || branch.endsWith("/staging")) ?? false;
3790
3846
  return {
3791
3847
  provider: provider.provider,
3792
3848
  providerKind: provider.providerKind,
@@ -3799,11 +3855,9 @@ async function detectGit(rootDir) {
3799
3855
  currentBranch,
3800
3856
  defaultBranch,
3801
3857
  isDirty: Boolean(status),
3802
- hasLocalStaging: localBranches?.includes("staging") ?? false,
3803
- hasRemoteStaging: remoteBranches?.some(
3804
- (branch) => branch === "origin/staging" || branch.endsWith("/staging")
3805
- ) ?? false,
3806
- workflow: inferWorkflow(currentBranch)
3858
+ hasLocalStaging,
3859
+ hasRemoteStaging,
3860
+ workflow: inferWorkflow(currentBranch, hasLocalStaging, hasRemoteStaging)
3807
3861
  };
3808
3862
  }
3809
3863
 
@@ -4261,17 +4315,23 @@ function preferenceDefaults(onboarding, onboarded) {
4261
4315
  }
4262
4316
  };
4263
4317
  }
4264
- function mergeSecretIgnores(existing) {
4318
+ function mergeIgnorePatterns(existing, patterns) {
4265
4319
  const activeLines = new Set(
4266
4320
  existing.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"))
4267
4321
  );
4268
- const missing = REQUIRED_SECRET_PATTERNS.filter((pattern) => !activeLines.has(pattern));
4322
+ const missing = patterns.filter((pattern) => !activeLines.has(pattern));
4269
4323
  if (missing.length === 0) return existing;
4270
4324
  const prefix = existing.length === 0 ? "" : existing.endsWith("\n") ? existing : `${existing}
4271
4325
  `;
4272
4326
  return `${prefix}${missing.join("\n")}
4273
4327
  `;
4274
4328
  }
4329
+ function mergeSecretIgnores(existing) {
4330
+ return mergeIgnorePatterns(existing, REQUIRED_SECRET_PATTERNS);
4331
+ }
4332
+ function mergeKitOwnedIgnores(existing) {
4333
+ return mergeIgnorePatterns(existing, KIT_OWNED_IGNORE_PATTERNS);
4334
+ }
4275
4335
  function recordChange(changes, id, relativePath, changed, dryRun, evidence) {
4276
4336
  changes.push({
4277
4337
  id,
@@ -4288,6 +4348,39 @@ function appliedActions(changes) {
4288
4348
  owner: "system"
4289
4349
  }));
4290
4350
  }
4351
+ function withoutGeneratedAtForComparison(profile) {
4352
+ const { generatedAt: _generatedAt, ...detection } = isObject(profile.detection) ? profile.detection : {};
4353
+ return { ...profile, detection };
4354
+ }
4355
+ function reconcileFreshOverExisting(desired, existing) {
4356
+ const merged = { ...existing };
4357
+ for (const [key, value] of Object.entries(desired)) {
4358
+ const existingValue = existing[key];
4359
+ merged[key] = isObject(value) && isObject(existingValue) ? reconcileFreshOverExisting(value, existingValue) : value;
4360
+ }
4361
+ return merged;
4362
+ }
4363
+ async function refreshRepositoryProfile(rootDir, options) {
4364
+ const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
4365
+ const scan = await runScanner(rootDir);
4366
+ const report = createReadinessReport(scan, {
4367
+ generatorVersion: options.generatorVersion,
4368
+ generatedAt
4369
+ });
4370
+ const desiredProfile = createProfile(scan, report, generatedAt);
4371
+ const profilePath = path23.join(scan.rootDir, PROFILE_RELATIVE_PATH);
4372
+ const existingProfile = await readJson(profilePath) ?? {};
4373
+ const reconciled = reconcileFreshOverExisting(desiredProfile, existingProfile);
4374
+ const meaningfulChange = !jsonEqual(
4375
+ withoutGeneratedAtForComparison(existingProfile),
4376
+ withoutGeneratedAtForComparison(reconciled)
4377
+ );
4378
+ if (!meaningfulChange) {
4379
+ return { changed: false, profile: existingProfile };
4380
+ }
4381
+ await writeJson(profilePath, reconciled);
4382
+ return { changed: true, profile: reconciled };
4383
+ }
4291
4384
  async function executeSafeReadinessFixes(rootDir, options) {
4292
4385
  const dryRun = options.dryRun ?? false;
4293
4386
  const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -4313,18 +4406,32 @@ async function executeSafeReadinessFixes(rootDir, options) {
4313
4406
  const gitignoreRelativePath = ".gitignore";
4314
4407
  const gitignorePath = path23.join(beforeScan.rootDir, gitignoreRelativePath);
4315
4408
  const existingGitignore = await fileExists(gitignorePath) ? await readFile13(gitignorePath, "utf8") : "";
4316
- const mergedGitignore = mergeSecretIgnores(existingGitignore);
4409
+ const gitignoreAfterSecrets = mergeSecretIgnores(existingGitignore);
4410
+ const secretsChanged = gitignoreAfterSecrets !== existingGitignore;
4411
+ const mergedGitignore = mergeKitOwnedIgnores(gitignoreAfterSecrets);
4317
4412
  const gitignoreChanged = mergedGitignore !== existingGitignore;
4413
+ const kitOwnedChanged = mergedGitignore !== gitignoreAfterSecrets;
4318
4414
  if (gitignoreChanged && !dryRun) await writeFile5(gitignorePath, mergedGitignore, "utf8");
4319
4415
  recordChange(
4320
4416
  changes,
4321
4417
  "merge-secret-ignores",
4322
4418
  gitignoreRelativePath,
4323
- gitignoreChanged,
4419
+ secretsChanged,
4420
+ dryRun,
4421
+ relativeEvidence(
4422
+ gitignoreRelativePath,
4423
+ secretsChanged ? "required secret patterns are missing" : "required patterns are present"
4424
+ )
4425
+ );
4426
+ recordChange(
4427
+ changes,
4428
+ "merge-kit-owned-ignores",
4429
+ gitignoreRelativePath,
4430
+ kitOwnedChanged,
4324
4431
  dryRun,
4325
4432
  relativeEvidence(
4326
4433
  gitignoreRelativePath,
4327
- gitignoreChanged ? "required secret patterns are missing" : "required patterns are present"
4434
+ kitOwnedChanged ? "kit-owned session/derived paths are missing" : "kit-owned session/derived paths are present"
4328
4435
  )
4329
4436
  );
4330
4437
  const profilePath = path23.join(beforeScan.rootDir, PROFILE_RELATIVE_PATH);
@@ -4388,7 +4495,10 @@ async function writeReadinessSnapshot(rootDir, report) {
4388
4495
 
4389
4496
  // src/welcome/visual-kit.ts
4390
4497
  import { cyan as cyan2, gray, options as koloristOptions } from "kolorist";
4498
+ var KOLORIST_TRUECOLOR = 3;
4391
4499
  var HELMET_OUTLINE = "#e2e8f0";
4500
+ var HELMET_FILL = "#0C8DEB";
4501
+ var HELMET_ACCENT = "#00D0E7";
4392
4502
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4393
4503
  var SPACE_MARKS = {
4394
4504
  star: "\u2726",
@@ -4414,6 +4524,18 @@ function shouldUseWelcomeColor(opts = {}) {
4414
4524
  const tty = opts.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
4415
4525
  return tty;
4416
4526
  }
4527
+ function withKoloristColor(fn) {
4528
+ const prevEnabled = koloristOptions.enabled;
4529
+ const prevLevel = koloristOptions.supportLevel;
4530
+ koloristOptions.enabled = true;
4531
+ koloristOptions.supportLevel = KOLORIST_TRUECOLOR;
4532
+ try {
4533
+ return fn();
4534
+ } finally {
4535
+ koloristOptions.enabled = prevEnabled;
4536
+ koloristOptions.supportLevel = prevLevel;
4537
+ }
4538
+ }
4417
4539
  function shouldUseVisualMotion(opts = {}) {
4418
4540
  if (process.env.AGENT_KIT_REDUCED_MOTION === "1") return false;
4419
4541
  return shouldUseWelcomeColor(opts);
@@ -4562,6 +4684,19 @@ async function runDoctor(cwd, options = {}) {
4562
4684
  await writeReadinessSnapshot(rootDir, execution.after);
4563
4685
  return { report: execution.after, safeChanges: execution.changes, hooks, env };
4564
4686
  }
4687
+ if (options.refreshProfile) {
4688
+ const refresh = await refreshRepositoryProfile(rootDir, {
4689
+ generatorVersion: KIT_VERSION,
4690
+ generatedAt: options.generatedAt
4691
+ });
4692
+ const scan2 = await runScanner(rootDir);
4693
+ const report2 = createReadinessReport(scan2, {
4694
+ generatorVersion: KIT_VERSION,
4695
+ generatedAt: options.generatedAt
4696
+ });
4697
+ await writeReadinessSnapshot(rootDir, report2);
4698
+ return { report: report2, safeChanges: [], hooks, env, profileRefreshed: refresh.changed };
4699
+ }
4565
4700
  const scan = await runScanner(rootDir);
4566
4701
  const report = createReadinessReport(scan, {
4567
4702
  generatorVersion: KIT_VERSION,
@@ -4580,6 +4715,11 @@ function printDoctorSummary(result) {
4580
4715
  );
4581
4716
  console.log(` safe fixes applied: ${fixed}`);
4582
4717
  console.log(` pending actions: ${pendingActions.length}`);
4718
+ if (result.profileRefreshed !== void 0) {
4719
+ console.log(
4720
+ ` profile refreshed: ${result.profileRefreshed ? "yes (facts changed)" : "no (already current)"}`
4721
+ );
4722
+ }
4583
4723
  console.log(`hooks: ${result.hooks.status}`);
4584
4724
  if (result.hooks.reasons.length > 0) {
4585
4725
  for (const reason of result.hooks.reasons.slice(0, 5)) {
@@ -4634,10 +4774,18 @@ var doctorCommand = defineCommand7({
4634
4774
  type: "boolean",
4635
4775
  description: "Apply only local, reversible, merge-safe readiness fixes",
4636
4776
  default: false
4777
+ },
4778
+ "refresh-profile": {
4779
+ type: "boolean",
4780
+ description: "Reconcile .cursor/agent-kit.config.json with current scanner facts: fresh values win on shared keys, unrecognized existing keys are preserved",
4781
+ default: false
4637
4782
  }
4638
4783
  },
4639
4784
  async run({ args }) {
4640
- const run = () => runDoctor(args.cwd, { fixSafe: args["fix-safe"] });
4785
+ const run = () => runDoctor(args.cwd, {
4786
+ fixSafe: args["fix-safe"],
4787
+ refreshProfile: args["refresh-profile"]
4788
+ });
4641
4789
  const result = args.json ? await run() : await withCliProgress("doctor", run);
4642
4790
  if (args.json) {
4643
4791
  console.log(JSON.stringify(result, null, 2));
@@ -5092,13 +5240,13 @@ function printV3Guidance() {
5092
5240
  logger.info("Resume in IDE: /resume, summaries and transcripts.");
5093
5241
  }
5094
5242
  function runCursorHandoff(scriptPath, cwd) {
5095
- return new Promise((resolve2, reject) => {
5243
+ return new Promise((resolve3, reject) => {
5096
5244
  const child = spawn4("sh", [scriptPath, "handoff"], {
5097
5245
  cwd,
5098
5246
  stdio: "inherit"
5099
5247
  });
5100
5248
  child.on("error", (err) => reject(err));
5101
- child.on("close", (code) => resolve2(code ?? 1));
5249
+ child.on("close", (code) => resolve3(code ?? 1));
5102
5250
  });
5103
5251
  }
5104
5252
  var handoffCommand = defineCommand9({
@@ -5180,11 +5328,13 @@ function formatSessionStartOutput(additionalContext, format) {
5180
5328
  var SESSION_START_DEGRADED_MESSAGE = "Agent Kit session-start context is unavailable this session (internal error, fail-open mode). Nothing else is affected; retry next session.";
5181
5329
 
5182
5330
  // src/hooks/pre-compact.ts
5331
+ var CONTEXT_USAGE_CAP_PERCENT = 50;
5183
5332
  function buildPreCompactUserMessage(payload = {}) {
5184
5333
  const pct = payload.context_usage_percent;
5185
5334
  const trigger = payload.trigger || "auto";
5186
5335
  const pctTxt = pct !== void 0 && pct !== null ? `~${pct}%` : "high";
5187
- const msg = `Context compacting (${trigger}, usage ${pctTxt}). Update \`.cursor/HANDOFF.md\` and open a new chat with \`/continue-plan\` so the next agent starts fresh.`;
5336
+ const overCap = pct === void 0 || pct === null || pct >= CONTEXT_USAGE_CAP_PERCENT;
5337
+ const msg = overCap ? `Context compacting (${trigger}, usage ${pctTxt}) \u2014 over the ${CONTEXT_USAGE_CAP_PERCENT}% per-agent context-usage cap. Update \`.cursor/HANDOFF.md\` now (forced checkpoint) and open a new chat with \`/continue-plan\` so the next agent starts fresh.` : `Context compacting (${trigger}, usage ${pctTxt}). Update \`.cursor/HANDOFF.md\` and open a new chat with \`/continue-plan\` so the next agent starts fresh.`;
5188
5338
  return { user_message: msg };
5189
5339
  }
5190
5340
 
@@ -5449,7 +5599,7 @@ async function loadUpdateCheckPrefs(root) {
5449
5599
  }
5450
5600
  }
5451
5601
  function runUpdateCheckJson(root) {
5452
- return new Promise((resolve2) => {
5602
+ return new Promise((resolve3) => {
5453
5603
  const child = spawn5(
5454
5604
  process.execPath,
5455
5605
  [
@@ -5468,20 +5618,20 @@ function runUpdateCheckJson(root) {
5468
5618
  child.stdout?.on("data", (chunk) => {
5469
5619
  out += chunk.toString("utf8");
5470
5620
  });
5471
- child.on("error", () => resolve2(null));
5621
+ child.on("error", () => resolve3(null));
5472
5622
  child.on("close", () => {
5473
5623
  try {
5474
5624
  const parsed = JSON.parse(out.trim());
5475
- resolve2(parsed && typeof parsed === "object" ? parsed : null);
5625
+ resolve3(parsed && typeof parsed === "object" ? parsed : null);
5476
5626
  } catch {
5477
- resolve2(null);
5627
+ resolve3(null);
5478
5628
  }
5479
5629
  });
5480
5630
  });
5481
5631
  }
5482
5632
  async function updateCheckSection(root) {
5483
5633
  if (await loadUpdateCheckPrefs(root) === null) return null;
5484
- const result = await new Promise((resolve2) => {
5634
+ const result = await new Promise((resolve3) => {
5485
5635
  const child = spawn5(
5486
5636
  "agent-kit",
5487
5637
  ["update", "--check", "--json", "--respect-prefs", "--stamp", "--cwd", root],
@@ -5492,17 +5642,17 @@ async function updateCheckSection(root) {
5492
5642
  out += chunk.toString("utf8");
5493
5643
  });
5494
5644
  child.on("error", () => {
5495
- void runUpdateCheckJson(root).then(resolve2);
5645
+ void runUpdateCheckJson(root).then(resolve3);
5496
5646
  });
5497
5647
  child.on("close", (code) => {
5498
5648
  if (code !== 0 && !out.trim()) {
5499
- void runUpdateCheckJson(root).then(resolve2);
5649
+ void runUpdateCheckJson(root).then(resolve3);
5500
5650
  return;
5501
5651
  }
5502
5652
  try {
5503
- resolve2(JSON.parse(out.trim()));
5653
+ resolve3(JSON.parse(out.trim()));
5504
5654
  } catch {
5505
- void runUpdateCheckJson(root).then(resolve2);
5655
+ void runUpdateCheckJson(root).then(resolve3);
5506
5656
  }
5507
5657
  });
5508
5658
  });
@@ -5527,7 +5677,7 @@ async function loadCursorUpdateCheckPrefs(root) {
5527
5677
  }
5528
5678
  }
5529
5679
  function runCursorAwarenessJson(root) {
5530
- return new Promise((resolve2) => {
5680
+ return new Promise((resolve3) => {
5531
5681
  const child = spawn5(
5532
5682
  process.execPath,
5533
5683
  [
@@ -5546,13 +5696,13 @@ function runCursorAwarenessJson(root) {
5546
5696
  child.stdout?.on("data", (chunk) => {
5547
5697
  out += chunk.toString("utf8");
5548
5698
  });
5549
- child.on("error", () => resolve2(null));
5699
+ child.on("error", () => resolve3(null));
5550
5700
  child.on("close", () => {
5551
5701
  try {
5552
5702
  const parsed = JSON.parse(out.trim());
5553
- resolve2(parsed && typeof parsed === "object" ? parsed : null);
5703
+ resolve3(parsed && typeof parsed === "object" ? parsed : null);
5554
5704
  } catch {
5555
- resolve2(null);
5705
+ resolve3(null);
5556
5706
  }
5557
5707
  });
5558
5708
  });
@@ -5569,13 +5719,13 @@ async function cursorAwarenessSection(root, deps = {}) {
5569
5719
  if (await loadCursorUpdateCheckPrefs(root) === null) return null;
5570
5720
  const spawnFn = deps.spawnFn ?? spawn5;
5571
5721
  const runFallback = deps.runFallback ?? runCursorAwarenessJson;
5572
- const result = await new Promise((resolve2) => {
5722
+ const result = await new Promise((resolve3) => {
5573
5723
  let settled = false;
5574
5724
  let fallbackStarted = false;
5575
5725
  const finish = (value) => {
5576
5726
  if (settled) return;
5577
5727
  settled = true;
5578
- resolve2(value);
5728
+ resolve3(value);
5579
5729
  };
5580
5730
  const startFallback = () => {
5581
5731
  if (settled || fallbackStarted) return;
@@ -5617,7 +5767,7 @@ async function cursorAwarenessSection(root, deps = {}) {
5617
5767
  var AUDIT_SESSION_NS_PREFIX = "agent-kit-audit-";
5618
5768
  var AUDIT_SESSION_LIST_TIMEOUT_MS = 2e3;
5619
5769
  function runAuditSessionCommand(cmd, args) {
5620
- return new Promise((resolve2) => {
5770
+ return new Promise((resolve3) => {
5621
5771
  const child = spawn5(cmd, args, {
5622
5772
  stdio: ["ignore", "pipe", "ignore"],
5623
5773
  timeout: AUDIT_SESSION_LIST_TIMEOUT_MS,
@@ -5627,8 +5777,8 @@ function runAuditSessionCommand(cmd, args) {
5627
5777
  child.stdout?.on("data", (chunk) => {
5628
5778
  out += chunk.toString("utf8");
5629
5779
  });
5630
- child.on("error", () => resolve2(null));
5631
- child.on("close", () => resolve2(out));
5780
+ child.on("error", () => resolve3(null));
5781
+ child.on("close", () => resolve3(out));
5632
5782
  });
5633
5783
  }
5634
5784
  function parseTmuxDetachedAuditSessions(out, nowEpochSeconds) {
@@ -6120,6 +6270,10 @@ Mid-session refresh: \`/agent-kit\`.
6120
6270
 
6121
6271
  Cursor Ask questions is not available in this CLI. When a command requires a choice, list the same labels as a numbered list and wait. Skip or cancel means stop. Never \`/git-prod\` without an explicit operator yes.
6122
6272
 
6273
+ ## Commit messages
6274
+
6275
+ Never append \`Co-Authored-By: Claude ...\` or \`Claude-Session: https://claude.ai/code/...\` (or any session-ID trailer) to commit messages, PR descriptions, or PR bodies in this repo. This overrides the harness's default git-commit template. Plain Conventional Commits messages only.
6276
+
6123
6277
  ## Non-goals
6124
6278
 
6125
6279
  - Not Action A7 (Windsurf / VS Code generator parity)
@@ -6134,18 +6288,20 @@ description: Load Agent Kit session context (HANDOFF, project-context, commands)
6134
6288
  disable-model-invocation: true
6135
6289
  ---
6136
6290
 
6137
- Read these files if they exist, then summarize the active plan, next to-do, and any Gaps. Do not scan the whole repository first.
6291
+ Read these files if they exist. Prefer a one-shot ASCII Mission Control snapshot over a plain HANDOFF paraphrase.
6138
6292
 
6139
- 1. \`AGENTS.md\`
6140
- 2. \`.cursor/project-context.md\`
6141
- 3. \`.cursor/HANDOFF.md\`
6142
- 4. The plan file named in HANDOFF \`- **Plan:**\` under \`.cursor/plans/\`
6293
+ 1. Run \`agent-kit mission-control --once\` (or \`npx @dadado/agent-kit-cli mission-control --once\`) in the project root and paste the stdout frame as the snapshot. Do not start a live loop: Claude Code cannot sustain one across turns.
6294
+ 2. If that command is missing or fails, fall back to reading:
6295
+ - \`AGENTS.md\`
6296
+ - \`.cursor/project-context.md\`
6297
+ - \`.cursor/HANDOFF.md\`
6298
+ - The plan file named in HANDOFF \`- **Plan:**\` under \`.cursor/plans/\`
6143
6299
 
6144
6300
  If HANDOFF is missing, say so and point at \`/agent-kit-onboard\` or \`/start-project\` rather than inventing a plan.
6145
6301
 
6146
6302
  HITL: numbered-list fallback for Ask questions labels. Never \`/git-prod\` from this skill.
6147
6303
 
6148
- Non-goals: not audits / \`/plan-external-review\`, not \`--backend claude\` ticks, not A7, not Cursor hook clones.
6304
+ Non-goals: not audits / \`/plan-external-review\`, not \`--backend claude\` ticks, not A7, not Cursor hook clones, not a continuous TUI loop.
6149
6305
  `;
6150
6306
  }
6151
6307
  async function writeUnlessExists(rootDir, relativePath, content) {
@@ -7152,21 +7308,416 @@ ${hint.recovery}
7152
7308
  }
7153
7309
  });
7154
7310
 
7155
- // src/commands/monitors.ts
7156
- import path38 from "path";
7311
+ // src/commands/mission-control.ts
7157
7312
  import { defineCommand as defineCommand13 } from "citty";
7158
7313
 
7159
- // src/invariants/monitors-untriaged.ts
7314
+ // src/mission-control/render.ts
7315
+ import { gray as gray2, trueColor } from "kolorist";
7316
+ var DEFAULT_COLUMNS = 80;
7317
+ var MIN_COLUMNS = 40;
7318
+ var INNER_PAD = 2;
7319
+ function hexPaint(hex, text, color) {
7320
+ if (!color) return text;
7321
+ return withKoloristColor(
7322
+ () => trueColor(
7323
+ Number.parseInt(hex.slice(1, 3), 16),
7324
+ Number.parseInt(hex.slice(3, 5), 16),
7325
+ Number.parseInt(hex.slice(5, 7), 16)
7326
+ )(text)
7327
+ );
7328
+ }
7329
+ function muted(text, color) {
7330
+ if (!color) return text;
7331
+ return withKoloristColor(() => gray2(text));
7332
+ }
7333
+ function box(title, bodyLines, width, color) {
7334
+ const inner = Math.max(8, width - 2);
7335
+ const label = ` ${title} `;
7336
+ const dashCount = Math.max(1, inner - label.length);
7337
+ const top = `\u250C${label}${"\u2500".repeat(dashCount)}\u2510`;
7338
+ const bottom = `\u2514${"\u2500".repeat(inner)}\u2518`;
7339
+ const paintedTop = hexPaint(HELMET_FILL, top, color);
7340
+ const paintedBottom = hexPaint(HELMET_OUTLINE, bottom, color);
7341
+ const rows = bodyLines.map((line) => {
7342
+ const clipped = line.length > inner - INNER_PAD ? line.slice(0, inner - INNER_PAD) : line;
7343
+ const pad = " ".repeat(Math.max(0, inner - INNER_PAD - clipped.length));
7344
+ const content = ` ${clipped}${pad} `;
7345
+ return `${hexPaint(HELMET_OUTLINE, "\u2502", color)}${content}${hexPaint(HELMET_OUTLINE, "\u2502", color)}`;
7346
+ });
7347
+ return [paintedTop, ...rows, paintedBottom];
7348
+ }
7349
+ function lineOrQuiet(text, fallback) {
7350
+ const trimmed = text?.trim();
7351
+ return trimmed ? trimmed : fallback;
7352
+ }
7353
+ function renderMcTui(view, opts = {}) {
7354
+ const color = shouldUseWelcomeColor(opts);
7355
+ const motion = shouldUseVisualMotion(opts);
7356
+ const columns = Math.max(
7357
+ MIN_COLUMNS,
7358
+ Math.floor(opts.columns ?? process.stdout.columns ?? DEFAULT_COLUMNS)
7359
+ );
7360
+ const mark = motion ? spinnerFrame(opts.frameIndex ?? 0) : SPACE_MARKS.tick;
7361
+ const header = hexPaint(
7362
+ HELMET_ACCENT,
7363
+ `${mark} Mission Control ${SPACE_MARKS.star} terminal view (web dashboard unchanged)`,
7364
+ color
7365
+ );
7366
+ const missionBody = view.error ? [wrapNarrow(view.error, columns - 4).split("\n")[0] ?? view.error] : [
7367
+ `status ${view.mission.status}${view.mission.mode ? ` \xB7 ${view.mission.mode}` : ""}`,
7368
+ `plan ${lineOrQuiet(view.mission.planFile, "none")}`,
7369
+ `todos ${view.mission.progressLabel}`,
7370
+ `now ${lineOrQuiet(view.mission.currentTodo, "none")}`,
7371
+ `next ${lineOrQuiet(view.mission.nextTodo, "none")}`
7372
+ ];
7373
+ const nowLabel = view.flightLog.now ? `NOW ${view.flightLog.nowKind ? `(${view.flightLog.nowKind})` : ""} ${view.flightLog.now}` : "NOW All clear";
7374
+ const flightBody = [
7375
+ nowLabel,
7376
+ ...view.flightLog.warnings.length > 0 ? view.flightLog.warnings.map((w) => `warn ${w}`) : [],
7377
+ ...view.flightLog.earlier.length > 0 ? view.flightLog.earlier.map((t) => `Earlier ${t}`) : [muted("Earlier none", color)]
7378
+ ];
7379
+ const checklistBody = view.checklist.length === 0 ? [muted("no open plans", color)] : view.checklist.map((row) => {
7380
+ const todo = row.currentTodo ? ` \xB7 ${row.currentTodo}` : "";
7381
+ return `${row.file} ${row.lifecycle} ${row.progressLabel}${todo}`;
7382
+ });
7383
+ const crewBody = view.crewMonitor.length === 0 ? [muted("quiet", color)] : view.crewMonitor.map((row) => `${row.kind} ${row.label}`);
7384
+ const panels = [
7385
+ ...box("Mission", missionBody, columns, color),
7386
+ ...box("Flight Log", flightBody, columns, color),
7387
+ ...box("Checklist", checklistBody, columns, color),
7388
+ ...box("Crew Monitor", crewBody, columns, color)
7389
+ ];
7390
+ const footer = muted("Third surface \xB7 local snapshot \xB7 q / Ctrl-C to quit live view", color);
7391
+ return [header, ...panels, footer].join("\n");
7392
+ }
7393
+ function shouldLiveRefresh(opts) {
7394
+ if (opts.once) return false;
7395
+ const env = opts.env ?? process.env;
7396
+ if (env.CI != null && env.CI !== "") return false;
7397
+ const tty = opts.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
7398
+ return tty;
7399
+ }
7400
+
7401
+ // src/mission-control/snapshot.ts
7160
7402
  import { execFile as execFile5 } from "child_process";
7161
- import { readFile as readFile20, readdir as readdir8, stat as stat5 } from "fs/promises";
7403
+ import { access as access8 } from "fs/promises";
7162
7404
  import path37 from "path";
7405
+
7406
+ // ../../dashboard/lib/live-refresh.mjs
7407
+ import { join, resolve as resolve2 } from "path";
7408
+ var PERIODIC_REFRESH_MS = 15e3;
7409
+ var SNAPSHOT_REPO_SOURCE_RELS = Object.freeze([
7410
+ ".cursor/plans",
7411
+ ".cursor/HANDOFF.md",
7412
+ ".cursor/agents",
7413
+ ".cursor/commands",
7414
+ ".cursor/memory",
7415
+ ".cursor/context/config.json",
7416
+ ".cursor/context/current",
7417
+ ".cursor/context/readiness.json",
7418
+ ".cursor/context/field-report-dismissals.json",
7419
+ ".cursor/context/mission-timing.json",
7420
+ ".cursor/context/flight-log.json",
7421
+ ".cursor/context/field-report-cadence.json",
7422
+ ".cursor/skills",
7423
+ "package.json"
7424
+ ]);
7425
+
7426
+ // src/mission-control/snapshot.ts
7427
+ var DEFAULT_DATA_TIMEOUT_MS = 6e4;
7428
+ function dataScriptTimeoutMs(env = process.env) {
7429
+ const raw = env.AGENT_KIT_DASHBOARD_DATA_TIMEOUT_MS;
7430
+ const n = raw != null && raw !== "" ? Number(raw) : DEFAULT_DATA_TIMEOUT_MS;
7431
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_DATA_TIMEOUT_MS;
7432
+ }
7433
+ async function firstExisting2(candidates) {
7434
+ for (const candidate2 of candidates) {
7435
+ try {
7436
+ await access8(candidate2);
7437
+ return path37.resolve(candidate2);
7438
+ } catch {
7439
+ }
7440
+ }
7441
+ return null;
7442
+ }
7443
+ async function findDashboardDataScript(cwd, env = process.env, options = {}) {
7444
+ const startPath = await findDashboardStart(cwd, env, options);
7445
+ if (startPath) {
7446
+ const sibling = path37.join(path37.dirname(startPath), "dashboard-data.mjs");
7447
+ try {
7448
+ await access8(sibling);
7449
+ return sibling;
7450
+ } catch {
7451
+ }
7452
+ }
7453
+ return firstExisting2(
7454
+ bundledDashboardCandidates("dashboard-data.mjs", options.moduleUrl ?? import.meta.url)
7455
+ );
7456
+ }
7457
+ async function loadDashboardSnapshot(opts) {
7458
+ const env = opts.env ?? process.env;
7459
+ const timeout = dataScriptTimeoutMs(env);
7460
+ const run = opts.execFileFn ?? execFile5;
7461
+ const snapshotRoot = path37.resolve(opts.snapshotRoot);
7462
+ return new Promise((resolve3) => {
7463
+ run(
7464
+ process.execPath,
7465
+ [opts.dataScript],
7466
+ {
7467
+ cwd: snapshotRoot,
7468
+ encoding: "utf8",
7469
+ maxBuffer: 10 * 1024 * 1024,
7470
+ timeout,
7471
+ env: {
7472
+ ...env,
7473
+ [REPO_ROOT_ENV]: snapshotRoot
7474
+ }
7475
+ },
7476
+ (err, stdout) => {
7477
+ if (err) {
7478
+ const killed = Boolean(
7479
+ err && typeof err === "object" && "killed" in err && err.killed
7480
+ );
7481
+ const message = killed ? `dashboard-data.mjs timed out after ${timeout}ms (set AGENT_KIT_DASHBOARD_DATA_TIMEOUT_MS to raise)` : err.message;
7482
+ resolve3({ ok: false, error: message });
7483
+ return;
7484
+ }
7485
+ try {
7486
+ const parsed = JSON.parse(String(stdout ?? ""));
7487
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
7488
+ resolve3({ ok: false, error: "dashboard-data.mjs returned non-object JSON" });
7489
+ return;
7490
+ }
7491
+ resolve3({ ok: true, snapshot: parsed });
7492
+ } catch {
7493
+ resolve3({ ok: false, error: "dashboard-data.mjs returned invalid JSON" });
7494
+ }
7495
+ }
7496
+ );
7497
+ });
7498
+ }
7499
+
7500
+ // src/mission-control/loop.ts
7501
+ var CLEAR_HOME = "\x1B[2J\x1B[H";
7502
+ var HIDE_CURSOR = "\x1B[?25l";
7503
+ var SHOW_CURSOR = "\x1B[?25h";
7504
+ async function runMcTuiLoop(opts) {
7505
+ const live = shouldLiveRefresh({
7506
+ once: opts.once,
7507
+ stdoutIsTTY: opts.stdoutIsTTY,
7508
+ env: opts.env
7509
+ });
7510
+ let frameIndex = 0;
7511
+ const paint2 = async (clear) => {
7512
+ const view = await opts.loadView();
7513
+ const frame = renderMcTui(view, {
7514
+ ...opts.renderOpts,
7515
+ stdoutIsTTY: opts.stdoutIsTTY,
7516
+ frameIndex
7517
+ });
7518
+ frameIndex += 1;
7519
+ opts.hooks.write(clear ? `${CLEAR_HOME}${frame}
7520
+ ` : `${frame}
7521
+ `);
7522
+ };
7523
+ await paint2(false);
7524
+ if (!live) return null;
7525
+ opts.hooks.write(HIDE_CURSOR);
7526
+ const intervalMs = opts.intervalMs ?? PERIODIC_REFRESH_MS;
7527
+ const setInt = opts.hooks.setIntervalFn ?? setInterval;
7528
+ const clearInt = opts.hooks.clearIntervalFn ?? clearInterval;
7529
+ const timer = setInt(() => {
7530
+ void paint2(true);
7531
+ }, intervalMs);
7532
+ const stop = () => {
7533
+ clearInt(timer);
7534
+ opts.hooks.write(SHOW_CURSOR);
7535
+ };
7536
+ return { stop };
7537
+ }
7538
+
7539
+ // src/mission-control/view.ts
7540
+ var CHECKLIST_CAP = 8;
7541
+ var CREW_CAP = 12;
7542
+ var EARLIER_CAP = 4;
7543
+ var WARNING_CAP = 5;
7544
+ function asRecord(value) {
7545
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
7546
+ return value;
7547
+ }
7548
+ function asString(value) {
7549
+ if (typeof value !== "string") return null;
7550
+ const trimmed = value.trim();
7551
+ return trimmed.length > 0 ? trimmed : null;
7552
+ }
7553
+ function compactTodo(value) {
7554
+ const rec = asRecord(value);
7555
+ if (!rec) return asString(value);
7556
+ return asString(rec.id) ?? asString(rec.content) ?? asString(rec.label);
7557
+ }
7558
+ function progressLabel(progress) {
7559
+ const rec = asRecord(progress);
7560
+ if (!rec) return "0 of 0 complete";
7561
+ const labeled = asString(rec.label);
7562
+ if (labeled) return labeled;
7563
+ const completed = typeof rec.completed === "number" ? rec.completed : 0;
7564
+ const total = typeof rec.total === "number" ? rec.total : 0;
7565
+ return `${completed} of ${total} complete`;
7566
+ }
7567
+ function emptyMission() {
7568
+ return {
7569
+ status: "idle",
7570
+ planFile: null,
7571
+ mode: null,
7572
+ progressLabel: "0 of 0 complete",
7573
+ currentTodo: null,
7574
+ nextTodo: null,
7575
+ gaps: null
7576
+ };
7577
+ }
7578
+ function emptyFlightLog() {
7579
+ return { now: null, nowKind: null, earlier: [], warnings: [] };
7580
+ }
7581
+ function buildMcTuiView(snapshot, error = null) {
7582
+ if (error) {
7583
+ return {
7584
+ mission: emptyMission(),
7585
+ flightLog: emptyFlightLog(),
7586
+ checklist: [],
7587
+ crewMonitor: [],
7588
+ error
7589
+ };
7590
+ }
7591
+ const mc = asRecord(snapshot?.missionControl);
7592
+ const now2 = asRecord(mc?.now);
7593
+ const mission = now2 ? {
7594
+ status: asString(now2.status) ?? "idle",
7595
+ planFile: asString(now2.planFile),
7596
+ mode: asString(now2.mode),
7597
+ progressLabel: progressLabel(now2.progress),
7598
+ currentTodo: compactTodo(now2.currentTodo),
7599
+ nextTodo: compactTodo(now2.nextTodo),
7600
+ gaps: asString(now2.gaps)
7601
+ } : emptyMission();
7602
+ const flight = asRecord(mc?.flightLog);
7603
+ const earlierRaw = Array.isArray(flight?.past) ? flight.past : [];
7604
+ const warningRaw = Array.isArray(flight?.warnings) ? flight.warnings : [];
7605
+ const flightLog = flight ? {
7606
+ now: asString(flight.current),
7607
+ nowKind: asString(flight.currentKind),
7608
+ earlier: earlierRaw.map((entry) => asString(asRecord(entry)?.text) ?? asString(entry)).filter((text) => Boolean(text)).slice(0, EARLIER_CAP),
7609
+ warnings: warningRaw.map((entry) => asString(asRecord(entry)?.text) ?? asString(asRecord(entry)?.title)).filter((text) => Boolean(text)).slice(0, WARNING_CAP)
7610
+ } : emptyFlightLog();
7611
+ const plansRaw = Array.isArray(mc?.plans) ? mc.plans : [];
7612
+ const checklist = plansRaw.map((plan) => {
7613
+ const rec = asRecord(plan);
7614
+ if (!rec) return null;
7615
+ const file = asString(rec.file);
7616
+ if (!file) return null;
7617
+ const lifecycle = asString(rec.lifecycle) ?? "unknown";
7618
+ if (lifecycle === "completed") return null;
7619
+ return {
7620
+ file,
7621
+ lifecycle,
7622
+ progressLabel: progressLabel(rec.progress),
7623
+ currentTodo: compactTodo(rec.currentTodo)
7624
+ };
7625
+ }).filter((row) => Boolean(row)).slice(0, CHECKLIST_CAP);
7626
+ const feedCap = typeof mc?.monitorFeedCap === "number" && mc.monitorFeedCap > 0 ? Math.min(CREW_CAP, Math.floor(mc.monitorFeedCap)) : CREW_CAP;
7627
+ const activityRaw = Array.isArray(mc?.activity) ? mc.activity : [];
7628
+ const crewMonitor = activityRaw.map((event) => {
7629
+ const rec = asRecord(event);
7630
+ if (!rec) return null;
7631
+ const label = asString(rec.label) ?? asString(rec.labelFull);
7632
+ if (!label) return null;
7633
+ return { kind: asString(rec.kind) ?? "activity", label };
7634
+ }).filter((row) => Boolean(row)).slice(0, feedCap);
7635
+ return { mission, flightLog, checklist, crewMonitor, error: null };
7636
+ }
7637
+
7638
+ // src/commands/mission-control.ts
7639
+ var missionControlCommand = defineCommand13({
7640
+ meta: {
7641
+ name: "mission-control",
7642
+ description: "ASCII Mission Control (mission, flight log, checklist, crew monitor) without a browser."
7643
+ },
7644
+ args: {
7645
+ cwd: {
7646
+ type: "string",
7647
+ default: process.cwd(),
7648
+ description: "Workspace to snapshot (nearest .cursor/agent-kit.json, else git root)"
7649
+ },
7650
+ once: {
7651
+ type: "boolean",
7652
+ default: false,
7653
+ description: "Print one frame and exit (Claude Code / non-TTY / CI)"
7654
+ }
7655
+ },
7656
+ async run({ args }) {
7657
+ const snapshotRoot = resolveDashboardSnapshotRoot(args.cwd);
7658
+ const dataScript = await findDashboardDataScript(args.cwd);
7659
+ if (!dataScript) {
7660
+ logger.error("No dashboard/dashboard-data.mjs found.");
7661
+ console.error(
7662
+ [
7663
+ "",
7664
+ "The Mission Control snapshot script is not available in this workspace.",
7665
+ "The TUI reuses the Path C dashboard data collector; it does not start an HTTP server.",
7666
+ "",
7667
+ "Recovery (pick one):",
7668
+ " 1. Upgrade the CLI: npx @dadado/agent-kit-cli@latest mission-control",
7669
+ " 2. Set MISSION_CONTROL_KIT_ROOT or AGENT_KIT_HOME to an agent-kit checkout",
7670
+ " 3. Place an agent-kit sibling: ../agent-kit/dashboard/dashboard-data.mjs",
7671
+ ""
7672
+ ].join("\n")
7673
+ );
7674
+ process.exitCode = 1;
7675
+ return;
7676
+ }
7677
+ const handle = await runMcTuiLoop({
7678
+ once: Boolean(args.once),
7679
+ stdoutIsTTY: Boolean(process.stdout.isTTY),
7680
+ env: process.env,
7681
+ renderOpts: { stdoutIsTTY: Boolean(process.stdout.isTTY) },
7682
+ loadView: async () => {
7683
+ const loaded = await loadDashboardSnapshot({
7684
+ dataScript,
7685
+ snapshotRoot
7686
+ });
7687
+ if (!loaded.ok) return buildMcTuiView(null, loaded.error);
7688
+ return buildMcTuiView(loaded.snapshot);
7689
+ },
7690
+ hooks: {
7691
+ write: (chunk) => {
7692
+ process.stdout.write(chunk);
7693
+ }
7694
+ }
7695
+ });
7696
+ if (!handle) return;
7697
+ const onSignal = () => {
7698
+ handle.stop();
7699
+ process.exit(0);
7700
+ };
7701
+ process.on("SIGINT", onSignal);
7702
+ process.on("SIGTERM", onSignal);
7703
+ }
7704
+ });
7705
+
7706
+ // src/commands/monitors.ts
7707
+ import path39 from "path";
7708
+ import { defineCommand as defineCommand14 } from "citty";
7709
+
7710
+ // src/invariants/monitors-untriaged.ts
7711
+ import { execFile as execFile6 } from "child_process";
7712
+ import { readFile as readFile20, readdir as readdir8, stat as stat5 } from "fs/promises";
7713
+ import path38 from "path";
7163
7714
  import { promisify as promisify5 } from "util";
7164
7715
 
7165
7716
  // src/invariants/triage-heading.ts
7166
7717
  var TRIAGE_HEADING_RE = /^#{2,6}\s+(?:Triage note|Follow-?up plan|Residuals plan)\b/im;
7167
7718
 
7168
7719
  // src/invariants/monitors-untriaged.ts
7169
- var execFileAsync4 = promisify5(execFile5);
7720
+ var execFileAsync4 = promisify5(execFile6);
7170
7721
  var CITE4 = "agent-kit monitors --untriaged (ADR 2026-07-27_plan-review-triage-untriaged-not-mtime; never newest-mtime-wins)";
7171
7722
  function hasOpenGaps(content) {
7172
7723
  if (/###\s+Still open[^\n]*\n+(?:\s*\n)*(?:None\.|none\.|\*None\*)/i.test(content)) {
@@ -7200,7 +7751,7 @@ async function gitFreshMonitorNames(rootDir) {
7200
7751
  for (const line of stdout.split("\n")) {
7201
7752
  if (!line.trim()) continue;
7202
7753
  const file = line.slice(3).trim().replace(/^.* -> /, "");
7203
- const base = path37.basename(file);
7754
+ const base = path38.basename(file);
7204
7755
  if (base.startsWith("plan-monitor-") && base.endsWith(".md")) {
7205
7756
  names.add(base);
7206
7757
  }
@@ -7223,13 +7774,13 @@ function monitorSlugFromName(fileName) {
7223
7774
  return fileName.replace(/^plan-monitor-/, "").replace(/\.md$/, "").toLowerCase();
7224
7775
  }
7225
7776
  async function selectUntriagedMonitors(rootDir) {
7226
- const root = path37.resolve(rootDir);
7227
- const memoryDir = path37.join(root, ".cursor", "memory");
7777
+ const root = path38.resolve(rootDir);
7778
+ const memoryDir = path38.join(root, ".cursor", "memory");
7228
7779
  const allNames = await listMonitorFiles(memoryDir);
7229
7780
  const selectionOrder = ["git-fresh", "handoff-aligned", "untriaged-scan"];
7230
7781
  const byName = /* @__PURE__ */ new Map();
7231
7782
  for (const name of allNames) {
7232
- const abs = path37.join(memoryDir, name);
7783
+ const abs = path38.join(memoryDir, name);
7233
7784
  try {
7234
7785
  const [content, st] = await Promise.all([readFile20(abs, "utf8"), stat5(abs)]);
7235
7786
  byName.set(name, { content, mtimeMs: st.mtimeMs });
@@ -7244,7 +7795,7 @@ async function selectUntriagedMonitors(rootDir) {
7244
7795
  const gitFreshSet = [...gitFresh].filter(untriaged).sort();
7245
7796
  let handoff = "";
7246
7797
  try {
7247
- handoff = await readFile20(path37.join(root, ".cursor", "HANDOFF.md"), "utf8");
7798
+ handoff = await readFile20(path38.join(root, ".cursor", "HANDOFF.md"), "utf8");
7248
7799
  } catch {
7249
7800
  handoff = "";
7250
7801
  }
@@ -7264,8 +7815,8 @@ async function selectUntriagedMonitors(rootDir) {
7264
7815
  const row = byName.get(name);
7265
7816
  if (!row) continue;
7266
7817
  entries.push({
7267
- path: path37.join(memoryDir, name),
7268
- relativePath: path37.relative(root, path37.join(memoryDir, name)).split(path37.sep).join("/"),
7818
+ path: path38.join(memoryDir, name),
7819
+ relativePath: path38.relative(root, path38.join(memoryDir, name)).split(path38.sep).join("/"),
7269
7820
  mtimeMs: row.mtimeMs,
7270
7821
  hasTriageHeading: false,
7271
7822
  hasOpenGaps: hasOpenGaps(row.content),
@@ -7284,7 +7835,7 @@ async function selectUntriagedMonitors(rootDir) {
7284
7835
  }
7285
7836
 
7286
7837
  // src/commands/monitors.ts
7287
- var monitorsCommand = defineCommand13({
7838
+ var monitorsCommand = defineCommand14({
7288
7839
  meta: {
7289
7840
  name: "monitors",
7290
7841
  description: "Select untriaged plan monitors (--untriaged; SoT for chat triage)."
@@ -7311,7 +7862,7 @@ var monitorsCommand = defineCommand13({
7311
7862
  process.exitCode = 2;
7312
7863
  return;
7313
7864
  }
7314
- const result = await selectUntriagedMonitors(path38.resolve(args.cwd));
7865
+ const result = await selectUntriagedMonitors(path39.resolve(args.cwd));
7315
7866
  if (args.json) {
7316
7867
  console.log(JSON.stringify(result, null, 2));
7317
7868
  return;
@@ -7327,8 +7878,8 @@ var monitorsCommand = defineCommand13({
7327
7878
  });
7328
7879
 
7329
7880
  // src/commands/run-plan.ts
7330
- import path43 from "path";
7331
- import { defineCommand as defineCommand14 } from "citty";
7881
+ import path44 from "path";
7882
+ import { defineCommand as defineCommand15 } from "citty";
7332
7883
 
7333
7884
  // src/plan-loop/backends.ts
7334
7885
  import { execFileSync as execFileSync2, spawn as spawn6 } from "child_process";
@@ -7342,7 +7893,7 @@ async function which(bin) {
7342
7893
  }
7343
7894
  }
7344
7895
  function spawnLogged(command, args, logPath) {
7345
- return new Promise((resolve2, reject) => {
7896
+ return new Promise((resolve3, reject) => {
7346
7897
  const out = createWriteStream(logPath, { flags: "w" });
7347
7898
  const child = spawn6(command, args, {
7348
7899
  stdio: ["ignore", "pipe", "pipe"]
@@ -7358,7 +7909,7 @@ function spawnLogged(command, args, logPath) {
7358
7909
  reject(err);
7359
7910
  });
7360
7911
  child.on("close", (code) => {
7361
- out.end(() => resolve2({ exitCode: code ?? 1 }));
7912
+ out.end(() => resolve3({ exitCode: code ?? 1 }));
7362
7913
  });
7363
7914
  });
7364
7915
  }
@@ -7413,13 +7964,13 @@ function listBackendIds() {
7413
7964
 
7414
7965
  // src/plan-loop/run-loop.ts
7415
7966
  import { mkdir as mkdir6, readFile as readFile23, rm as rm2, unlink as unlink2 } from "fs/promises";
7416
- import path42 from "path";
7967
+ import path43 from "path";
7417
7968
 
7418
7969
  // src/plan-loop/external-review.ts
7419
7970
  import { spawn as spawn7 } from "child_process";
7420
- import path39 from "path";
7421
- var CANONICAL_REL = path39.join(".cursor", "scripts", "plan-external-review.sh");
7422
- var FALLBACK_REL = path39.join("scripts", "plan-external-review.sh");
7971
+ import path40 from "path";
7972
+ var CANONICAL_REL = path40.join(".cursor", "scripts", "plan-external-review.sh");
7973
+ var FALLBACK_REL = path40.join("scripts", "plan-external-review.sh");
7423
7974
  function isPlanExhaustedReason(reason) {
7424
7975
  const r = reason.trim().toLowerCase();
7425
7976
  if (!r) return false;
@@ -7441,8 +7992,8 @@ async function armExternalPlanReview(root, options = {}) {
7441
7992
  const existsFn = options.existsFn ?? fileExists;
7442
7993
  const log = options.log ?? ((line) => console.log(line));
7443
7994
  const force = options.force === true;
7444
- const canonicalPath = path39.join(root, CANONICAL_REL);
7445
- const fallbackPath = path39.join(root, FALLBACK_REL);
7995
+ const canonicalPath = path40.join(root, CANONICAL_REL);
7996
+ const fallbackPath = path40.join(root, FALLBACK_REL);
7446
7997
  let scriptPath = null;
7447
7998
  let scriptRel = CANONICAL_REL;
7448
7999
  if (await existsFn(canonicalPath)) {
@@ -7460,7 +8011,7 @@ async function armExternalPlanReview(root, options = {}) {
7460
8011
  }
7461
8012
  log("Plan exhausted: arming optional external plan review (opt-in handled by script)...");
7462
8013
  const args = force ? [scriptPath, "--force", "--print"] : [scriptPath, "--print"];
7463
- return new Promise((resolve2) => {
8014
+ return new Promise((resolve3) => {
7464
8015
  const child = spawnFn("bash", args, {
7465
8016
  cwd: root,
7466
8017
  env: { ...process.env, AGENT_KIT_HEADLESS: "1" }
@@ -7481,7 +8032,7 @@ async function armExternalPlanReview(root, options = {}) {
7481
8032
  log(
7482
8033
  `tip: external plan review launcher failed (${err.message}). Manual: ${scriptRel} or /plan-external-review`
7483
8034
  );
7484
- resolve2({ invoked: true, exitCode: null, output });
8035
+ resolve3({ invoked: true, exitCode: null, output });
7485
8036
  });
7486
8037
  child.on("close", (code) => {
7487
8038
  if (code !== 0 && code !== null) {
@@ -7489,17 +8040,17 @@ async function armExternalPlanReview(root, options = {}) {
7489
8040
  `tip: external plan review exited ${code} (ignored; does not fail the loop). Manual: ${scriptRel} or /plan-external-review`
7490
8041
  );
7491
8042
  }
7492
- resolve2({ invoked: true, exitCode: code, output });
8043
+ resolve3({ invoked: true, exitCode: code, output });
7493
8044
  });
7494
8045
  });
7495
8046
  }
7496
8047
 
7497
8048
  // src/plan-loop/persona-banners.ts
7498
- import path40 from "path";
8049
+ import path41 from "path";
7499
8050
  import {
7500
8051
  blue,
7501
8052
  cyan as cyan4,
7502
- gray as gray2,
8053
+ gray as gray3,
7503
8054
  green as green3,
7504
8055
  lightGray,
7505
8056
  lightGreen,
@@ -7512,7 +8063,7 @@ var CLI_RUN_PLAN_MODE = "cli-run-plan";
7512
8063
  var DEFAULT_CLI_PERSONA_ID = "ghost-runner";
7513
8064
  var COLORS = {
7514
8065
  white,
7515
- gray: gray2,
8066
+ gray: gray3,
7516
8067
  green: green3,
7517
8068
  cyan: cyan4,
7518
8069
  magenta,
@@ -7531,7 +8082,7 @@ function resolveColor(name, fallback) {
7531
8082
  async function resolveCliPersonaId(root) {
7532
8083
  try {
7533
8084
  const cfg = await readJson(
7534
- path40.join(root, ".cursor", "context", "config.json")
8085
+ path41.join(root, ".cursor", "context", "config.json")
7535
8086
  );
7536
8087
  const modes = cfg?.agentPersona?.modes ?? cfg?.workspaceSkin?.modes;
7537
8088
  const id = modes?.[CLI_RUN_PLAN_MODE];
@@ -7542,7 +8093,7 @@ async function resolveCliPersonaId(root) {
7542
8093
  }
7543
8094
  async function loadPersonaPack(root, personaId) {
7544
8095
  try {
7545
- const personaPath = path40.join(root, "registry", "personas", "core", personaId, "persona.json");
8096
+ const personaPath = path41.join(root, "registry", "personas", "core", personaId, "persona.json");
7546
8097
  const pack = await readJson(personaPath);
7547
8098
  if (!pack || typeof pack.id !== "string") return null;
7548
8099
  return pack;
@@ -7559,7 +8110,7 @@ function createPersonaBannerPrinter(persona) {
7559
8110
  const banners = persona.cliBanners;
7560
8111
  if (!banners.tickStart && !banners.tickEnd && !banners.phaseComplete) return null;
7561
8112
  const primary = resolveColor(persona.ansiPalette?.primary, white);
7562
- const secondary = resolveColor(persona.ansiPalette?.secondary, gray2);
8113
+ const secondary = resolveColor(persona.ansiPalette?.secondary, gray3);
7563
8114
  const accent = resolveColor(persona.ansiPalette?.accent, green3);
7564
8115
  return {
7565
8116
  tickStart(detail) {
@@ -7592,7 +8143,7 @@ function createPersonaBannerPrinter(persona) {
7592
8143
 
7593
8144
  // src/plan-loop/plan-state.ts
7594
8145
  import { readFile as readFile21, readdir as readdir9 } from "fs/promises";
7595
- import path41 from "path";
8146
+ import path42 from "path";
7596
8147
  function countPendingTodos(raw) {
7597
8148
  const lines = raw.split(/\r?\n/);
7598
8149
  let inFront = 0;
@@ -7620,7 +8171,7 @@ function countPendingTodos(raw) {
7620
8171
  async function findActivePlanFile(plansDir) {
7621
8172
  if (!await fileExists(plansDir)) return null;
7622
8173
  const files = (await readdir9(plansDir)).filter((f) => f.endsWith(".plan.md")).sort();
7623
- return files[0] ? path41.join(plansDir, files[0]) : null;
8174
+ return files[0] ? path42.join(plansDir, files[0]) : null;
7624
8175
  }
7625
8176
  async function readPlan(planPath) {
7626
8177
  return readFile21(planPath, "utf8");
@@ -7697,9 +8248,9 @@ function sleep(ms) {
7697
8248
  return new Promise((r) => setTimeout(r, ms));
7698
8249
  }
7699
8250
  async function runPlanLoop(opts) {
7700
- const plansDir = path42.join(opts.root, ".cursor", "plans");
7701
- const stopFile = path42.join(opts.root, ".cursor", "loop.stop");
7702
- const logDir = path42.join(opts.root, ".cursor", "loop-logs");
8251
+ const plansDir = path43.join(opts.root, ".cursor", "plans");
8252
+ const stopFile = path43.join(opts.root, ".cursor", "loop.stop");
8253
+ const logDir = path43.join(opts.root, ".cursor", "loop-logs");
7703
8254
  const planPath = await findActivePlanFile(plansDir);
7704
8255
  if (!planPath) {
7705
8256
  logger.error("No active plan in .cursor/plans/");
@@ -7720,7 +8271,7 @@ async function runPlanLoop(opts) {
7720
8271
  try {
7721
8272
  const persona = await loadCliRunPlanPersona(opts.root);
7722
8273
  const banners = createPersonaBannerPrinter(persona);
7723
- console.log(`Active plan: ${path42.basename(planPath)}`);
8274
+ console.log(`Active plan: ${path43.basename(planPath)}`);
7724
8275
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
7725
8276
  console.log(`Backend: ${opts.backend.id}`);
7726
8277
  if (persona) {
@@ -7763,8 +8314,8 @@ async function runPlanLoop(opts) {
7763
8314
  planExhausted = true;
7764
8315
  break;
7765
8316
  }
7766
- const logPath = path42.join(logDir, `tick-${stamp()}.log`);
7767
- const relLog = path42.relative(opts.root, logPath);
8317
+ const logPath = path43.join(logDir, `tick-${stamp()}.log`);
8318
+ const relLog = path43.relative(opts.root, logPath);
7768
8319
  console.log("");
7769
8320
  const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
7770
8321
  if (banners) banners.tickStart(tickLine);
@@ -7843,7 +8394,7 @@ async function runPlanLoop(opts) {
7843
8394
  const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
7844
8395
  if (banners) banners.phaseComplete(finishDetail);
7845
8396
  console.log(
7846
- `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path42.relative(opts.root, logDir)}/`
8397
+ `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path43.relative(opts.root, logDir)}/`
7847
8398
  );
7848
8399
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
7849
8400
  await armExternalPlanReview(opts.root);
@@ -7855,7 +8406,7 @@ async function runPlanLoop(opts) {
7855
8406
  }
7856
8407
 
7857
8408
  // src/commands/run-plan.ts
7858
- var runPlanCommand = defineCommand14({
8409
+ var runPlanCommand = defineCommand15({
7859
8410
  meta: {
7860
8411
  name: "run-plan",
7861
8412
  description: "Headless continuous plan runner (one fresh agent per tick). Never git-prod."
@@ -7914,7 +8465,7 @@ var runPlanCommand = defineCommand14({
7914
8465
  return;
7915
8466
  }
7916
8467
  const code = await runPlanLoop({
7917
- root: path43.resolve(args.cwd),
8468
+ root: path44.resolve(args.cwd),
7918
8469
  maxTicks,
7919
8470
  sleepSeconds,
7920
8471
  model: args.model ? String(args.model) : void 0,
@@ -7926,8 +8477,8 @@ var runPlanCommand = defineCommand14({
7926
8477
  });
7927
8478
 
7928
8479
  // src/commands/scan.ts
7929
- import { defineCommand as defineCommand15 } from "citty";
7930
- var scanCommand = defineCommand15({
8480
+ import { defineCommand as defineCommand16 } from "citty";
8481
+ var scanCommand = defineCommand16({
7931
8482
  meta: {
7932
8483
  name: "scan",
7933
8484
  description: "Scan the repository and print the detected profile."
@@ -7951,9 +8502,9 @@ var scanCommand = defineCommand15({
7951
8502
  import { spawn as spawn8 } from "child_process";
7952
8503
  import { appendFile, mkdir as mkdir7, readFile as readFile24, writeFile as writeFile12 } from "fs/promises";
7953
8504
  import { homedir as homedir4 } from "os";
7954
- import path44 from "path";
8505
+ import path45 from "path";
7955
8506
  import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
7956
- import { defineCommand as defineCommand16 } from "citty";
8507
+ import { defineCommand as defineCommand17 } from "citty";
7957
8508
  import { cyan as cyan5, green as green4, yellow as yellow3 } from "kolorist";
7958
8509
  var NPM_GLOBAL_DIR_NAME = ".npm-global";
7959
8510
  var SETUP_GLOBAL_MARKER = "# agent-kit setup-global";
@@ -7961,9 +8512,9 @@ var DEFAULT_PACKAGE_SPEC = "@dadado/agent-kit-cli";
7961
8512
  function planSetupGlobalSteps(env, options = {}) {
7962
8513
  const homeDir = options.homeDir ?? homedir4();
7963
8514
  const packageSpec = options.packageSpec ?? DEFAULT_PACKAGE_SPEC;
7964
- const npmGlobalDir = path44.join(homeDir, NPM_GLOBAL_DIR_NAME);
7965
- const npmGlobalBin = path44.join(npmGlobalDir, "bin");
7966
- const npmrcPath = path44.join(homeDir, ".npmrc");
8515
+ const npmGlobalDir = path45.join(homeDir, NPM_GLOBAL_DIR_NAME);
8516
+ const npmGlobalBin = path45.join(npmGlobalDir, "bin");
8517
+ const npmrcPath = path45.join(homeDir, ".npmrc");
7967
8518
  const npmrcPrefixValue = `~/${NPM_GLOBAL_DIR_NAME}`;
7968
8519
  const pathExportLine = `export PATH="${npmGlobalBin}:$PATH"`;
7969
8520
  const shellProfile = env.shellProfile;
@@ -8042,12 +8593,12 @@ async function safeReadFile(fs, filePath) {
8042
8593
  return "";
8043
8594
  }
8044
8595
  }
8045
- var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve2) => {
8596
+ var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve3) => {
8046
8597
  const child = spawn8("npm", ["i", "-g", packageSpec], { stdio: "inherit" });
8047
- child.on("error", (error) => resolve2({ ok: false, error }));
8598
+ child.on("error", (error) => resolve3({ ok: false, error }));
8048
8599
  child.on("close", (code) => {
8049
- if (code === 0) resolve2({ ok: true });
8050
- else resolve2({ ok: false, error: new Error(`npm exited with code ${code ?? "unknown"}`) });
8600
+ if (code === 0) resolve3({ ok: true });
8601
+ else resolve3({ ok: false, error: new Error(`npm exited with code ${code ?? "unknown"}`) });
8051
8602
  });
8052
8603
  });
8053
8604
  var defaultConfirmImpl = async (message) => {
@@ -8196,7 +8747,7 @@ ${verifyStep.title}`);
8196
8747
  }
8197
8748
  return { exitCode: 0, mutated, outcome: "completed", env, plan };
8198
8749
  }
8199
- var setupGlobalCommand = defineCommand16({
8750
+ var setupGlobalCommand = defineCommand17({
8200
8751
  meta: {
8201
8752
  name: "setup-global",
8202
8753
  description: "Self-heal a root-owned npm prefix: relocate to ~/.npm-global, fix PATH, reinstall globally."
@@ -8225,8 +8776,8 @@ var setupGlobalCommand = defineCommand16({
8225
8776
  });
8226
8777
 
8227
8778
  // src/commands/status.ts
8228
- import path45 from "path";
8229
- import { defineCommand as defineCommand17 } from "citty";
8779
+ import path46 from "path";
8780
+ import { defineCommand as defineCommand18 } from "citty";
8230
8781
  function profileStatus(profile) {
8231
8782
  if (!profile) return { origin: "none", evidence: [], profile: null };
8232
8783
  if ("detection" in profile && profile.detection && typeof profile.detection === "object") {
@@ -8239,7 +8790,7 @@ function profileStatus(profile) {
8239
8790
  }
8240
8791
  return { origin: "legacy-wizard", evidence: [], profile };
8241
8792
  }
8242
- var statusCommand = defineCommand17({
8793
+ var statusCommand = defineCommand18({
8243
8794
  meta: {
8244
8795
  name: "status",
8245
8796
  description: "Show installed kit version, manifest, and optional profile."
@@ -8256,11 +8807,11 @@ var statusCommand = defineCommand17({
8256
8807
  }
8257
8808
  },
8258
8809
  async run({ args }) {
8259
- const rootDir = path45.resolve(args.cwd);
8810
+ const rootDir = path46.resolve(args.cwd);
8260
8811
  const [manifest, rawProfile, scan] = await Promise.all([
8261
8812
  loadAgentKitManifest(rootDir),
8262
8813
  readJson(
8263
- path45.join(rootDir, ".cursor", "agent-kit.config.json")
8814
+ path46.join(rootDir, ".cursor", "agent-kit.config.json")
8264
8815
  ),
8265
8816
  runScanner(rootDir)
8266
8817
  ]);
@@ -8315,13 +8866,13 @@ var statusCommand = defineCommand17({
8315
8866
  });
8316
8867
 
8317
8868
  // src/commands/update.ts
8318
- import { defineCommand as defineCommand18 } from "citty";
8869
+ import { defineCommand as defineCommand19 } from "citty";
8319
8870
 
8320
8871
  // src/lifecycle/check-updates.ts
8321
- import { execFile as execFile6 } from "child_process";
8322
- import path46 from "path";
8872
+ import { execFile as execFile7 } from "child_process";
8873
+ import path47 from "path";
8323
8874
  import { promisify as promisify6 } from "util";
8324
- var execFileAsync5 = promisify6(execFile6);
8875
+ var execFileAsync5 = promisify6(execFile7);
8325
8876
  var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/i;
8326
8877
  var FACTORY_URL_MARKERS = ["agent-kit-dev"];
8327
8878
  var FACTORY_REFS = /* @__PURE__ */ new Set(["staging", "homologacao", "develop", "dev"]);
@@ -8410,11 +8961,11 @@ function intervalElapsed2(lastCheckedAt, intervalDays) {
8410
8961
  return Date.now() - last >= ms;
8411
8962
  }
8412
8963
  async function loadContextConfig2(cwd) {
8413
- const configPath = path46.join(cwd, ".cursor", "context", "config.json");
8964
+ const configPath = path47.join(cwd, ".cursor", "context", "config.json");
8414
8965
  return readJson(configPath);
8415
8966
  }
8416
8967
  async function stampLastCheckedAt(cwd) {
8417
- const configPath = path46.join(cwd, ".cursor", "context", "config.json");
8968
+ const configPath = path47.join(cwd, ".cursor", "context", "config.json");
8418
8969
  const existing = await loadContextConfig2(cwd) ?? {};
8419
8970
  const prev = existing.updateCheck && typeof existing.updateCheck === "object" ? { ...existing.updateCheck } : {};
8420
8971
  existing.updateCheck = {
@@ -8426,7 +8977,7 @@ async function stampLastCheckedAt(cwd) {
8426
8977
  }
8427
8978
  async function readLocalKitVersion(registryRoot) {
8428
8979
  for (const rel of ["packages/cli/package.json", "package.json"]) {
8429
- const data = await readJson(path46.join(registryRoot, rel));
8980
+ const data = await readJson(path47.join(registryRoot, rel));
8430
8981
  if (data && typeof data.version === "string" && data.version.length > 0) {
8431
8982
  return data.version;
8432
8983
  }
@@ -8447,7 +8998,7 @@ async function checkAgainstLocalRegistry(cwd, manifest, options) {
8447
8998
  status: "error",
8448
8999
  installedVersion: manifest.version,
8449
9000
  latestVersion: null,
8450
- registryUrl: path46.resolve(registryPath),
9001
+ registryUrl: path47.resolve(registryPath),
8451
9002
  registryRef: "local",
8452
9003
  applyRecommended: false,
8453
9004
  message: `Failed to resolve --registry: ${msg}`
@@ -8669,7 +9220,7 @@ async function checkForUpdates(cwd, options = {}) {
8669
9220
  }
8670
9221
 
8671
9222
  // src/commands/update.ts
8672
- var updateCommand = defineCommand18({
9223
+ var updateCommand = defineCommand19({
8673
9224
  meta: {
8674
9225
  name: "update",
8675
9226
  description: "Re-apply L0/packs/skills from the registry (never overwrites L3). --check = notify-only."
@@ -8804,8 +9355,8 @@ ${err.recovery}
8804
9355
 
8805
9356
  // src/commands/validate.ts
8806
9357
  import { readFile as readFile25 } from "fs/promises";
8807
- import path47 from "path";
8808
- import { defineCommand as defineCommand19 } from "citty";
9358
+ import path48 from "path";
9359
+ import { defineCommand as defineCommand20 } from "citty";
8809
9360
 
8810
9361
  // src/invariants/plan-schema.ts
8811
9362
  var CITE5 = "agent-kit validate plan (.cursor/context/templates/plan.md)";
@@ -8851,7 +9402,7 @@ function validatePlanFrontmatterText(text) {
8851
9402
  // src/commands/validate.ts
8852
9403
  async function resolveEditedPath(cwd, explicit) {
8853
9404
  if (explicit) {
8854
- const filePath2 = path47.resolve(cwd, explicit);
9405
+ const filePath2 = path48.resolve(cwd, explicit);
8855
9406
  try {
8856
9407
  return { filePath: filePath2, content: await readFile25(filePath2, "utf8") };
8857
9408
  } catch {
@@ -8861,7 +9412,7 @@ async function resolveEditedPath(cwd, explicit) {
8861
9412
  const payload = await readStdinJson();
8862
9413
  const rel = typeof payload.file_path === "string" && payload.file_path || typeof payload.path === "string" && payload.path || typeof payload.file === "string" && payload.file || "";
8863
9414
  if (!rel) return null;
8864
- const filePath = path47.isAbsolute(rel) ? rel : path47.resolve(cwd, rel);
9415
+ const filePath = path48.isAbsolute(rel) ? rel : path48.resolve(cwd, rel);
8865
9416
  try {
8866
9417
  return { filePath, content: await readFile25(filePath, "utf8") };
8867
9418
  } catch {
@@ -8875,13 +9426,13 @@ function isPlanPath(filePath) {
8875
9426
  const norm = filePath.replace(/\\/g, "/");
8876
9427
  return norm.includes("/.cursor/plans/") && norm.endsWith(".plan.md");
8877
9428
  }
8878
- var validateCommand = defineCommand19({
9429
+ var validateCommand = defineCommand20({
8879
9430
  meta: {
8880
9431
  name: "validate",
8881
9432
  description: "Advisory validators for HANDOFF / plan frontmatter (hook adapter)."
8882
9433
  },
8883
9434
  subCommands: {
8884
- handoff: defineCommand19({
9435
+ handoff: defineCommand20({
8885
9436
  meta: { name: "handoff", description: "Validate HANDOFF machine fields" },
8886
9437
  args: {
8887
9438
  cwd: { type: "string", default: process.cwd() },
@@ -8891,7 +9442,7 @@ var validateCommand = defineCommand19({
8891
9442
  async run({ args }) {
8892
9443
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
8893
9444
  const fileArg = typeof args.file === "string" ? args.file : void 0;
8894
- const filePath = fileArg ? path47.resolve(cwd, fileArg) : path47.join(path47.resolve(cwd), ".cursor", "HANDOFF.md");
9445
+ const filePath = fileArg ? path48.resolve(cwd, fileArg) : path48.join(path48.resolve(cwd), ".cursor", "HANDOFF.md");
8895
9446
  let content = "";
8896
9447
  try {
8897
9448
  content = await readFile25(filePath, "utf8");
@@ -8903,7 +9454,7 @@ var validateCommand = defineCommand19({
8903
9454
  console.log(JSON.stringify({ ok: warnings.length === 0, warnings }));
8904
9455
  }
8905
9456
  }),
8906
- plan: defineCommand19({
9457
+ plan: defineCommand20({
8907
9458
  meta: { name: "plan", description: "Validate plan frontmatter" },
8908
9459
  args: {
8909
9460
  cwd: { type: "string", default: process.cwd() },
@@ -8918,7 +9469,7 @@ var validateCommand = defineCommand19({
8918
9469
  process.exitCode = 2;
8919
9470
  return;
8920
9471
  }
8921
- const filePath = path47.resolve(cwd, fileArg);
9472
+ const filePath = path48.resolve(cwd, fileArg);
8922
9473
  let content = "";
8923
9474
  try {
8924
9475
  content = await readFile25(filePath, "utf8");
@@ -8930,7 +9481,7 @@ var validateCommand = defineCommand19({
8930
9481
  console.log(JSON.stringify({ ok: warnings.length === 0, warnings }));
8931
9482
  }
8932
9483
  }),
8933
- "after-edit": defineCommand19({
9484
+ "after-edit": defineCommand20({
8934
9485
  meta: {
8935
9486
  name: "after-edit",
8936
9487
  description: "Advisory afterFileEdit: annotate HANDOFF/plan issues (never block)"
@@ -8940,7 +9491,7 @@ var validateCommand = defineCommand19({
8940
9491
  },
8941
9492
  async run({ args }) {
8942
9493
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
8943
- const resolved = await resolveEditedPath(path47.resolve(cwd));
9494
+ const resolved = await resolveEditedPath(path48.resolve(cwd));
8944
9495
  if (!resolved) {
8945
9496
  console.log(JSON.stringify({}));
8946
9497
  return;
@@ -8983,19 +9534,10 @@ var validateCommand = defineCommand19({
8983
9534
  });
8984
9535
 
8985
9536
  // src/welcome/help-groups.ts
8986
- import { bold as bold2, gray as gray4, underline } from "kolorist";
9537
+ import { bold as bold2, gray as gray5, underline } from "kolorist";
8987
9538
 
8988
9539
  // src/welcome/screen.ts
8989
- import {
8990
- blue as blue2,
8991
- cyan as cyan6,
8992
- gray as gray3,
8993
- options as koloristOptions3,
8994
- lightCyan,
8995
- trueColor,
8996
- white as white2
8997
- } from "kolorist";
8998
- var KOLORIST_TRUECOLOR = 3;
9540
+ import { blue as blue2, cyan as cyan6, gray as gray4, lightCyan, trueColor as trueColor2, white as white2 } from "kolorist";
8999
9541
  var HELMET_ASCII = [
9000
9542
  " ____",
9001
9543
  " .-' '-.",
@@ -9016,19 +9558,7 @@ function hexToRgb(hex) {
9016
9558
  }
9017
9559
  function outlineAnsi(line) {
9018
9560
  const [r, g, b] = hexToRgb(HELMET_OUTLINE);
9019
- return trueColor(r, g, b)(line);
9020
- }
9021
- function withKoloristColor(fn) {
9022
- const prevEnabled = koloristOptions3.enabled;
9023
- const prevLevel = koloristOptions3.supportLevel;
9024
- koloristOptions3.enabled = true;
9025
- koloristOptions3.supportLevel = KOLORIST_TRUECOLOR;
9026
- try {
9027
- return fn();
9028
- } finally {
9029
- koloristOptions3.enabled = prevEnabled;
9030
- koloristOptions3.supportLevel = prevLevel;
9031
- }
9561
+ return trueColor2(r, g, b)(line);
9032
9562
  }
9033
9563
  function hasCliSubcommand(rawArgs) {
9034
9564
  return Boolean(rawArgs?.some((arg) => !arg.startsWith("-")));
@@ -9048,6 +9578,7 @@ var WELCOME_UTILITY_HINTS = [
9048
9578
  { cmd: "agent-kit doctor", hint: "repository readiness" },
9049
9579
  { cmd: "agent-kit status", hint: "installed kit version" },
9050
9580
  { cmd: "agent-kit dashboard", hint: "Mission Control panel" },
9581
+ { cmd: "agent-kit mission-control", hint: "Mission Control TUI" },
9051
9582
  { cmd: "agent-kit init", hint: "guided install entry" }
9052
9583
  ];
9053
9584
  function renderWelcomeScreen(opts = {}) {
@@ -9055,27 +9586,27 @@ function renderWelcomeScreen(opts = {}) {
9055
9586
  const color = shouldUseWelcomeColor(opts);
9056
9587
  const title = color ? white2("Mission Kit") : "Mission Kit";
9057
9588
  const product = color ? cyan6("agent-kit") : "agent-kit";
9058
- const muted = (s) => color ? gray3(s) : s;
9589
+ const muted2 = (s) => color ? gray4(s) : s;
9059
9590
  const lines = [
9060
9591
  renderHelmetAscii(color),
9061
9592
  "",
9062
9593
  `${title} \xB7 ${product} v${version}`,
9063
- muted("HITL framework for AI-assisted IDEs \xB7 @dadado/agent-kit-cli"),
9594
+ muted2("HITL framework for AI-assisted IDEs \xB7 @dadado/agent-kit-cli"),
9064
9595
  "",
9065
- muted("Try:"),
9596
+ muted2("Try:"),
9066
9597
  ...(() => {
9067
9598
  const width = Math.max(...WELCOME_UTILITY_HINTS.map(({ cmd }) => cmd.length));
9068
9599
  return WELCOME_UTILITY_HINTS.map(({ cmd, hint }) => {
9069
9600
  const pad = " ".repeat(width - cmd.length + 2);
9070
9601
  const left = color ? cyan6(` ${cmd}`) : ` ${cmd}`;
9071
- return `${left}${pad}${muted(hint)}`;
9602
+ return `${left}${pad}${muted2(hint)}`;
9072
9603
  });
9073
9604
  })(),
9074
9605
  "",
9075
- muted(
9606
+ muted2(
9076
9607
  "Chat HITL (start-project, git-staging/prod, run-plan-all) stays in Cursor slash commands."
9077
9608
  ),
9078
- muted(
9609
+ muted2(
9079
9610
  `${shouldUseVisualMotion(opts) ? SPACE_MARKS.star : SPACE_MARKS.tick} ${tipAt(
9080
9611
  [...version].reduce((n, c) => n + c.charCodeAt(0), 0)
9081
9612
  )}`
@@ -9103,7 +9634,7 @@ var CLI_HELP_GROUPS = [
9103
9634
  {
9104
9635
  id: "dashboard",
9105
9636
  title: "DASHBOARD",
9106
- commands: ["dashboard", "dashboard-broadcast", "monitors"]
9637
+ commands: ["dashboard", "dashboard-broadcast", "mission-control", "monitors"]
9107
9638
  },
9108
9639
  {
9109
9640
  id: "integrity",
@@ -9129,7 +9660,7 @@ async function resolveSubMeta(subCommands) {
9129
9660
  async function renderGroupedRootHelp(cmd) {
9130
9661
  const color = shouldUseWelcomeColor();
9131
9662
  const u = (s) => color ? underline(bold2(s)) : s;
9132
- const g = (s) => color ? gray4(s) : s;
9663
+ const g = (s) => color ? gray5(s) : s;
9133
9664
  const meta = await resolveCommandMeta(cmd.meta);
9134
9665
  const name = meta?.name ?? "agent-kit";
9135
9666
  const version = meta?.version ?? KIT_VERSION;
@@ -9173,7 +9704,7 @@ async function renderGroupedRootHelp(cmd) {
9173
9704
  }
9174
9705
 
9175
9706
  // src/index.ts
9176
- var main = defineCommand20({
9707
+ var main = defineCommand21({
9177
9708
  meta: {
9178
9709
  name: "agent-kit",
9179
9710
  description: "HITL framework for AI-assisted IDEs (Mission Kit family)",
@@ -9195,6 +9726,7 @@ var main = defineCommand20({
9195
9726
  "run-plan": runPlanCommand,
9196
9727
  dashboard: dashboardCommand,
9197
9728
  "dashboard-broadcast": dashboardBroadcastCommand,
9729
+ "mission-control": missionControlCommand,
9198
9730
  hook: hookCommand,
9199
9731
  guard: guardCommand,
9200
9732
  monitors: monitorsCommand,