@dadado/agent-kit-cli 5.5.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";
@@ -219,7 +219,15 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
219
219
  "34e559ad9036d93d9cbc96d394bc2bbeb10ce50ead00d58a914158ae19daa76c",
220
220
  "359a142aeadd769a9b89ac909ae5129940e7e6b0892b70256098c584d97631ce",
221
221
  "8eab94f7a78149db1bbbc0fd45f21dc2d874209d534bcff39077fd6e1d2c42fb",
222
- "9be406f92f7dca71f3af814b14fb26b011f9f12c37c789f7ddc3d647b1a7ab60"
222
+ "9be406f92f7dca71f3af814b14fb26b011f9f12c37c789f7ddc3d647b1a7ab60",
223
+ "bb67ddcdd9ab58ed89287421f5e4b6ebfb3941e6a789287ddec9b9c25b56b1ed",
224
+ "7343ecd797f484eea1a3ebc11e87c75d90f617bd627bfc367a1eca5a1628bdf1",
225
+ "8a723b4808f14413fc173a6ce33370067ffc78d0c2e05a21c4406d7fa3e66457",
226
+ "65554e304a70b77e07fe40facf0ef305d6216399bfbb811db2491ce2f31d86d7",
227
+ "f8cc89a52fb1ec17f7f26ecd5cb18f79a5e9c7b7ffe7a6899465aa4090433b98",
228
+ "543e6596e7ce9f3ce4de642f1ea7e5d437d553fa28c0d56eb0f244ec8526ce17",
229
+ "71c6d1cce604c4a275db7c9a5c48f1753604bf35e083be054511ebc91f4977e6",
230
+ "8d0fd61bcbb9e035dea3a8b9f298a48c226bb28785923cb07e1154cf084934ad"
223
231
  ]);
224
232
 
225
233
  // src/lifecycle/paths.ts
@@ -1517,11 +1525,20 @@ var L0_ARTIFACTS = [
1517
1525
  source: ".cursor/commands/dashboard.md",
1518
1526
  target: ".cursor/commands/dashboard.md"
1519
1527
  },
1528
+ {
1529
+ source: ".cursor/commands/dashboard-broadcast.md",
1530
+ target: ".cursor/commands/dashboard-broadcast.md"
1531
+ },
1520
1532
  {
1521
1533
  source: ".cursor/commands/git-staging.md",
1522
1534
  target: ".cursor/commands/git-staging.md"
1523
1535
  },
1524
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" },
1525
1542
  {
1526
1543
  source: ".cursor/commands/plan-external-review.md",
1527
1544
  target: ".cursor/commands/plan-external-review.md"
@@ -1545,6 +1562,10 @@ var L0_ARTIFACTS = [
1545
1562
  source: ".cursor/commands/cursor-update-awareness.md",
1546
1563
  target: ".cursor/commands/cursor-update-awareness.md"
1547
1564
  },
1565
+ {
1566
+ source: ".cursor/commands/update.md",
1567
+ target: ".cursor/commands/update.md"
1568
+ },
1548
1569
  // Context (templates + example config; private config.json is not L0)
1549
1570
  {
1550
1571
  source: ".cursor/context/templates/plan-external-review-prompt.md",
@@ -2377,6 +2398,7 @@ import { defineCommand as defineCommand4 } from "citty";
2377
2398
  import { randomBytes, timingSafeEqual } from "crypto";
2378
2399
  import { networkInterfaces } from "os";
2379
2400
  import { resolve } from "path";
2401
+ var REPO_ROOT_ENV = "MISSION_CONTROL_REPO_ROOT";
2380
2402
  var KIT_ROOT_ENV_KEYS = Object.freeze(["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]);
2381
2403
  var CONTEXT_CONFIG_REL = ".cursor/context/config.json";
2382
2404
  var CONFIG_PERSONA_IDS = Object.freeze(["autopilot", "night-shift", "ghost-runner"]);
@@ -2562,14 +2584,14 @@ function resolveDashboardSnapshotRoot(cwd) {
2562
2584
  return abs;
2563
2585
  }
2564
2586
  function runStartScript(startPath, env) {
2565
- return new Promise((resolve2, reject) => {
2587
+ return new Promise((resolve3, reject) => {
2566
2588
  const child = spawn2(process.execPath, [startPath], {
2567
2589
  cwd: path11.dirname(path11.dirname(startPath)),
2568
2590
  env,
2569
2591
  stdio: "inherit"
2570
2592
  });
2571
2593
  child.on("error", reject);
2572
- child.on("close", (code) => resolve2(code ?? 1));
2594
+ child.on("close", (code) => resolve3(code ?? 1));
2573
2595
  });
2574
2596
  }
2575
2597
  var dashboardCommand = defineCommand4({
@@ -2679,14 +2701,14 @@ async function findDashboardBroadcastStart(cwd, env = process.env, options = {})
2679
2701
  return null;
2680
2702
  }
2681
2703
  function runStartScript2(startPath, env) {
2682
- return new Promise((resolve2, reject) => {
2704
+ return new Promise((resolve3, reject) => {
2683
2705
  const child = spawn3(process.execPath, [startPath], {
2684
2706
  cwd: path12.dirname(path12.dirname(startPath)),
2685
2707
  env,
2686
2708
  stdio: "inherit"
2687
2709
  });
2688
2710
  child.on("error", reject);
2689
- child.on("close", (code) => resolve2(code ?? 1));
2711
+ child.on("close", (code) => resolve3(code ?? 1));
2690
2712
  });
2691
2713
  }
2692
2714
  var dashboardBroadcastCommand = defineCommand5({
@@ -3385,9 +3407,9 @@ function buildPillars(scan) {
3385
3407
  check(
3386
3408
  "stack.detected",
3387
3409
  "Stack and package manager",
3388
- scan.stack.language !== "unknown" || scan.purpose.value !== "unknown" ? "ready" : "needs_choice",
3410
+ scan.stack.language !== "unknown" || scan.stack.hasProjectFiles ? "ready" : "needs_choice",
3389
3411
  true,
3390
- scan.stack.packageManagerEvidence ?? scan.purpose.evidence
3412
+ scan.stack.packageManagerEvidence ?? []
3391
3413
  )
3392
3414
  ]),
3393
3415
  pillar("quality-ci", [
@@ -3521,7 +3543,40 @@ async function detectContext(rootDir) {
3521
3543
  )
3522
3544
  };
3523
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
+ }
3524
3577
  async function detectPurpose(rootDir, stack) {
3578
+ const confirmed = await readConfirmedPurpose(rootDir);
3579
+ if (confirmed) return confirmed;
3525
3580
  const entries = await listDirectory(rootDir);
3526
3581
  const lowerEntries = entries.map((entry) => entry.toLowerCase());
3527
3582
  const packageJson = await readJson(path16.join(rootDir, "package.json"));
@@ -3586,6 +3641,13 @@ var REQUIRED_SECRET_PATTERNS = [
3586
3641
  "*credentials*.json",
3587
3642
  "*service-account*.json"
3588
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
+ ];
3589
3651
  async function detectSafety(rootDir, trackedFiles) {
3590
3652
  const gitignorePath = path16.join(rootDir, ".gitignore");
3591
3653
  const hasGitignore = await fileExists(gitignorePath);
@@ -3725,7 +3787,8 @@ async function detectProvider(rootDir, remoteUrl) {
3725
3787
  evidence: remoteEvidence
3726
3788
  };
3727
3789
  }
3728
- function inferWorkflow(currentBranch) {
3790
+ function inferWorkflow(currentBranch, hasLocalStaging, hasRemoteStaging) {
3791
+ if (hasLocalStaging || hasRemoteStaging) return "homolog-prod";
3729
3792
  if (!currentBranch) return "unknown";
3730
3793
  if (currentBranch === "main" || currentBranch === "master") return "feature-pr";
3731
3794
  if (currentBranch.includes("develop") || currentBranch.includes("release")) return "gitflow";
@@ -3778,6 +3841,8 @@ async function detectGit(rootDir) {
3778
3841
  const localBranches = localBranchOutput?.split("\n").filter(Boolean);
3779
3842
  const remoteBranches = remoteBranchOutput?.split("\n").filter(Boolean);
3780
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;
3781
3846
  return {
3782
3847
  provider: provider.provider,
3783
3848
  providerKind: provider.providerKind,
@@ -3790,11 +3855,9 @@ async function detectGit(rootDir) {
3790
3855
  currentBranch,
3791
3856
  defaultBranch,
3792
3857
  isDirty: Boolean(status),
3793
- hasLocalStaging: localBranches?.includes("staging") ?? false,
3794
- hasRemoteStaging: remoteBranches?.some(
3795
- (branch) => branch === "origin/staging" || branch.endsWith("/staging")
3796
- ) ?? false,
3797
- workflow: inferWorkflow(currentBranch)
3858
+ hasLocalStaging,
3859
+ hasRemoteStaging,
3860
+ workflow: inferWorkflow(currentBranch, hasLocalStaging, hasRemoteStaging)
3798
3861
  };
3799
3862
  }
3800
3863
 
@@ -4252,17 +4315,23 @@ function preferenceDefaults(onboarding, onboarded) {
4252
4315
  }
4253
4316
  };
4254
4317
  }
4255
- function mergeSecretIgnores(existing) {
4318
+ function mergeIgnorePatterns(existing, patterns) {
4256
4319
  const activeLines = new Set(
4257
4320
  existing.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"))
4258
4321
  );
4259
- const missing = REQUIRED_SECRET_PATTERNS.filter((pattern) => !activeLines.has(pattern));
4322
+ const missing = patterns.filter((pattern) => !activeLines.has(pattern));
4260
4323
  if (missing.length === 0) return existing;
4261
4324
  const prefix = existing.length === 0 ? "" : existing.endsWith("\n") ? existing : `${existing}
4262
4325
  `;
4263
4326
  return `${prefix}${missing.join("\n")}
4264
4327
  `;
4265
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
+ }
4266
4335
  function recordChange(changes, id, relativePath, changed, dryRun, evidence) {
4267
4336
  changes.push({
4268
4337
  id,
@@ -4279,6 +4348,39 @@ function appliedActions(changes) {
4279
4348
  owner: "system"
4280
4349
  }));
4281
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
+ }
4282
4384
  async function executeSafeReadinessFixes(rootDir, options) {
4283
4385
  const dryRun = options.dryRun ?? false;
4284
4386
  const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
@@ -4304,18 +4406,32 @@ async function executeSafeReadinessFixes(rootDir, options) {
4304
4406
  const gitignoreRelativePath = ".gitignore";
4305
4407
  const gitignorePath = path23.join(beforeScan.rootDir, gitignoreRelativePath);
4306
4408
  const existingGitignore = await fileExists(gitignorePath) ? await readFile13(gitignorePath, "utf8") : "";
4307
- const mergedGitignore = mergeSecretIgnores(existingGitignore);
4409
+ const gitignoreAfterSecrets = mergeSecretIgnores(existingGitignore);
4410
+ const secretsChanged = gitignoreAfterSecrets !== existingGitignore;
4411
+ const mergedGitignore = mergeKitOwnedIgnores(gitignoreAfterSecrets);
4308
4412
  const gitignoreChanged = mergedGitignore !== existingGitignore;
4413
+ const kitOwnedChanged = mergedGitignore !== gitignoreAfterSecrets;
4309
4414
  if (gitignoreChanged && !dryRun) await writeFile5(gitignorePath, mergedGitignore, "utf8");
4310
4415
  recordChange(
4311
4416
  changes,
4312
4417
  "merge-secret-ignores",
4313
4418
  gitignoreRelativePath,
4314
- 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,
4315
4431
  dryRun,
4316
4432
  relativeEvidence(
4317
4433
  gitignoreRelativePath,
4318
- 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"
4319
4435
  )
4320
4436
  );
4321
4437
  const profilePath = path23.join(beforeScan.rootDir, PROFILE_RELATIVE_PATH);
@@ -4379,7 +4495,10 @@ async function writeReadinessSnapshot(rootDir, report) {
4379
4495
 
4380
4496
  // src/welcome/visual-kit.ts
4381
4497
  import { cyan as cyan2, gray, options as koloristOptions } from "kolorist";
4498
+ var KOLORIST_TRUECOLOR = 3;
4382
4499
  var HELMET_OUTLINE = "#e2e8f0";
4500
+ var HELMET_FILL = "#0C8DEB";
4501
+ var HELMET_ACCENT = "#00D0E7";
4383
4502
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4384
4503
  var SPACE_MARKS = {
4385
4504
  star: "\u2726",
@@ -4405,6 +4524,18 @@ function shouldUseWelcomeColor(opts = {}) {
4405
4524
  const tty = opts.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
4406
4525
  return tty;
4407
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
+ }
4408
4539
  function shouldUseVisualMotion(opts = {}) {
4409
4540
  if (process.env.AGENT_KIT_REDUCED_MOTION === "1") return false;
4410
4541
  return shouldUseWelcomeColor(opts);
@@ -4553,6 +4684,19 @@ async function runDoctor(cwd, options = {}) {
4553
4684
  await writeReadinessSnapshot(rootDir, execution.after);
4554
4685
  return { report: execution.after, safeChanges: execution.changes, hooks, env };
4555
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
+ }
4556
4700
  const scan = await runScanner(rootDir);
4557
4701
  const report = createReadinessReport(scan, {
4558
4702
  generatorVersion: KIT_VERSION,
@@ -4571,6 +4715,11 @@ function printDoctorSummary(result) {
4571
4715
  );
4572
4716
  console.log(` safe fixes applied: ${fixed}`);
4573
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
+ }
4574
4723
  console.log(`hooks: ${result.hooks.status}`);
4575
4724
  if (result.hooks.reasons.length > 0) {
4576
4725
  for (const reason of result.hooks.reasons.slice(0, 5)) {
@@ -4625,10 +4774,18 @@ var doctorCommand = defineCommand7({
4625
4774
  type: "boolean",
4626
4775
  description: "Apply only local, reversible, merge-safe readiness fixes",
4627
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
4628
4782
  }
4629
4783
  },
4630
4784
  async run({ args }) {
4631
- 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
+ });
4632
4789
  const result = args.json ? await run() : await withCliProgress("doctor", run);
4633
4790
  if (args.json) {
4634
4791
  console.log(JSON.stringify(result, null, 2));
@@ -5083,13 +5240,13 @@ function printV3Guidance() {
5083
5240
  logger.info("Resume in IDE: /resume, summaries and transcripts.");
5084
5241
  }
5085
5242
  function runCursorHandoff(scriptPath, cwd) {
5086
- return new Promise((resolve2, reject) => {
5243
+ return new Promise((resolve3, reject) => {
5087
5244
  const child = spawn4("sh", [scriptPath, "handoff"], {
5088
5245
  cwd,
5089
5246
  stdio: "inherit"
5090
5247
  });
5091
5248
  child.on("error", (err) => reject(err));
5092
- child.on("close", (code) => resolve2(code ?? 1));
5249
+ child.on("close", (code) => resolve3(code ?? 1));
5093
5250
  });
5094
5251
  }
5095
5252
  var handoffCommand = defineCommand9({
@@ -5171,11 +5328,13 @@ function formatSessionStartOutput(additionalContext, format) {
5171
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.";
5172
5329
 
5173
5330
  // src/hooks/pre-compact.ts
5331
+ var CONTEXT_USAGE_CAP_PERCENT = 50;
5174
5332
  function buildPreCompactUserMessage(payload = {}) {
5175
5333
  const pct = payload.context_usage_percent;
5176
5334
  const trigger = payload.trigger || "auto";
5177
5335
  const pctTxt = pct !== void 0 && pct !== null ? `~${pct}%` : "high";
5178
- 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.`;
5179
5338
  return { user_message: msg };
5180
5339
  }
5181
5340
 
@@ -5440,7 +5599,7 @@ async function loadUpdateCheckPrefs(root) {
5440
5599
  }
5441
5600
  }
5442
5601
  function runUpdateCheckJson(root) {
5443
- return new Promise((resolve2) => {
5602
+ return new Promise((resolve3) => {
5444
5603
  const child = spawn5(
5445
5604
  process.execPath,
5446
5605
  [
@@ -5459,20 +5618,20 @@ function runUpdateCheckJson(root) {
5459
5618
  child.stdout?.on("data", (chunk) => {
5460
5619
  out += chunk.toString("utf8");
5461
5620
  });
5462
- child.on("error", () => resolve2(null));
5621
+ child.on("error", () => resolve3(null));
5463
5622
  child.on("close", () => {
5464
5623
  try {
5465
5624
  const parsed = JSON.parse(out.trim());
5466
- resolve2(parsed && typeof parsed === "object" ? parsed : null);
5625
+ resolve3(parsed && typeof parsed === "object" ? parsed : null);
5467
5626
  } catch {
5468
- resolve2(null);
5627
+ resolve3(null);
5469
5628
  }
5470
5629
  });
5471
5630
  });
5472
5631
  }
5473
5632
  async function updateCheckSection(root) {
5474
5633
  if (await loadUpdateCheckPrefs(root) === null) return null;
5475
- const result = await new Promise((resolve2) => {
5634
+ const result = await new Promise((resolve3) => {
5476
5635
  const child = spawn5(
5477
5636
  "agent-kit",
5478
5637
  ["update", "--check", "--json", "--respect-prefs", "--stamp", "--cwd", root],
@@ -5483,17 +5642,17 @@ async function updateCheckSection(root) {
5483
5642
  out += chunk.toString("utf8");
5484
5643
  });
5485
5644
  child.on("error", () => {
5486
- void runUpdateCheckJson(root).then(resolve2);
5645
+ void runUpdateCheckJson(root).then(resolve3);
5487
5646
  });
5488
5647
  child.on("close", (code) => {
5489
5648
  if (code !== 0 && !out.trim()) {
5490
- void runUpdateCheckJson(root).then(resolve2);
5649
+ void runUpdateCheckJson(root).then(resolve3);
5491
5650
  return;
5492
5651
  }
5493
5652
  try {
5494
- resolve2(JSON.parse(out.trim()));
5653
+ resolve3(JSON.parse(out.trim()));
5495
5654
  } catch {
5496
- void runUpdateCheckJson(root).then(resolve2);
5655
+ void runUpdateCheckJson(root).then(resolve3);
5497
5656
  }
5498
5657
  });
5499
5658
  });
@@ -5518,7 +5677,7 @@ async function loadCursorUpdateCheckPrefs(root) {
5518
5677
  }
5519
5678
  }
5520
5679
  function runCursorAwarenessJson(root) {
5521
- return new Promise((resolve2) => {
5680
+ return new Promise((resolve3) => {
5522
5681
  const child = spawn5(
5523
5682
  process.execPath,
5524
5683
  [
@@ -5537,13 +5696,13 @@ function runCursorAwarenessJson(root) {
5537
5696
  child.stdout?.on("data", (chunk) => {
5538
5697
  out += chunk.toString("utf8");
5539
5698
  });
5540
- child.on("error", () => resolve2(null));
5699
+ child.on("error", () => resolve3(null));
5541
5700
  child.on("close", () => {
5542
5701
  try {
5543
5702
  const parsed = JSON.parse(out.trim());
5544
- resolve2(parsed && typeof parsed === "object" ? parsed : null);
5703
+ resolve3(parsed && typeof parsed === "object" ? parsed : null);
5545
5704
  } catch {
5546
- resolve2(null);
5705
+ resolve3(null);
5547
5706
  }
5548
5707
  });
5549
5708
  });
@@ -5560,13 +5719,13 @@ async function cursorAwarenessSection(root, deps = {}) {
5560
5719
  if (await loadCursorUpdateCheckPrefs(root) === null) return null;
5561
5720
  const spawnFn = deps.spawnFn ?? spawn5;
5562
5721
  const runFallback = deps.runFallback ?? runCursorAwarenessJson;
5563
- const result = await new Promise((resolve2) => {
5722
+ const result = await new Promise((resolve3) => {
5564
5723
  let settled = false;
5565
5724
  let fallbackStarted = false;
5566
5725
  const finish = (value) => {
5567
5726
  if (settled) return;
5568
5727
  settled = true;
5569
- resolve2(value);
5728
+ resolve3(value);
5570
5729
  };
5571
5730
  const startFallback = () => {
5572
5731
  if (settled || fallbackStarted) return;
@@ -5608,7 +5767,7 @@ async function cursorAwarenessSection(root, deps = {}) {
5608
5767
  var AUDIT_SESSION_NS_PREFIX = "agent-kit-audit-";
5609
5768
  var AUDIT_SESSION_LIST_TIMEOUT_MS = 2e3;
5610
5769
  function runAuditSessionCommand(cmd, args) {
5611
- return new Promise((resolve2) => {
5770
+ return new Promise((resolve3) => {
5612
5771
  const child = spawn5(cmd, args, {
5613
5772
  stdio: ["ignore", "pipe", "ignore"],
5614
5773
  timeout: AUDIT_SESSION_LIST_TIMEOUT_MS,
@@ -5618,8 +5777,8 @@ function runAuditSessionCommand(cmd, args) {
5618
5777
  child.stdout?.on("data", (chunk) => {
5619
5778
  out += chunk.toString("utf8");
5620
5779
  });
5621
- child.on("error", () => resolve2(null));
5622
- child.on("close", () => resolve2(out));
5780
+ child.on("error", () => resolve3(null));
5781
+ child.on("close", () => resolve3(out));
5623
5782
  });
5624
5783
  }
5625
5784
  function parseTmuxDetachedAuditSessions(out, nowEpochSeconds) {
@@ -6111,6 +6270,10 @@ Mid-session refresh: \`/agent-kit\`.
6111
6270
 
6112
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.
6113
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
+
6114
6277
  ## Non-goals
6115
6278
 
6116
6279
  - Not Action A7 (Windsurf / VS Code generator parity)
@@ -6125,18 +6288,20 @@ description: Load Agent Kit session context (HANDOFF, project-context, commands)
6125
6288
  disable-model-invocation: true
6126
6289
  ---
6127
6290
 
6128
- 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.
6129
6292
 
6130
- 1. \`AGENTS.md\`
6131
- 2. \`.cursor/project-context.md\`
6132
- 3. \`.cursor/HANDOFF.md\`
6133
- 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/\`
6134
6299
 
6135
6300
  If HANDOFF is missing, say so and point at \`/agent-kit-onboard\` or \`/start-project\` rather than inventing a plan.
6136
6301
 
6137
6302
  HITL: numbered-list fallback for Ask questions labels. Never \`/git-prod\` from this skill.
6138
6303
 
6139
- 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.
6140
6305
  `;
6141
6306
  }
6142
6307
  async function writeUnlessExists(rootDir, relativePath, content) {
@@ -7143,21 +7308,416 @@ ${hint.recovery}
7143
7308
  }
7144
7309
  });
7145
7310
 
7146
- // src/commands/monitors.ts
7147
- import path38 from "path";
7311
+ // src/commands/mission-control.ts
7148
7312
  import { defineCommand as defineCommand13 } from "citty";
7149
7313
 
7150
- // 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
7151
7402
  import { execFile as execFile5 } from "child_process";
7152
- import { readFile as readFile20, readdir as readdir8, stat as stat5 } from "fs/promises";
7403
+ import { access as access8 } from "fs/promises";
7153
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";
7154
7714
  import { promisify as promisify5 } from "util";
7155
7715
 
7156
7716
  // src/invariants/triage-heading.ts
7157
7717
  var TRIAGE_HEADING_RE = /^#{2,6}\s+(?:Triage note|Follow-?up plan|Residuals plan)\b/im;
7158
7718
 
7159
7719
  // src/invariants/monitors-untriaged.ts
7160
- var execFileAsync4 = promisify5(execFile5);
7720
+ var execFileAsync4 = promisify5(execFile6);
7161
7721
  var CITE4 = "agent-kit monitors --untriaged (ADR 2026-07-27_plan-review-triage-untriaged-not-mtime; never newest-mtime-wins)";
7162
7722
  function hasOpenGaps(content) {
7163
7723
  if (/###\s+Still open[^\n]*\n+(?:\s*\n)*(?:None\.|none\.|\*None\*)/i.test(content)) {
@@ -7191,7 +7751,7 @@ async function gitFreshMonitorNames(rootDir) {
7191
7751
  for (const line of stdout.split("\n")) {
7192
7752
  if (!line.trim()) continue;
7193
7753
  const file = line.slice(3).trim().replace(/^.* -> /, "");
7194
- const base = path37.basename(file);
7754
+ const base = path38.basename(file);
7195
7755
  if (base.startsWith("plan-monitor-") && base.endsWith(".md")) {
7196
7756
  names.add(base);
7197
7757
  }
@@ -7214,13 +7774,13 @@ function monitorSlugFromName(fileName) {
7214
7774
  return fileName.replace(/^plan-monitor-/, "").replace(/\.md$/, "").toLowerCase();
7215
7775
  }
7216
7776
  async function selectUntriagedMonitors(rootDir) {
7217
- const root = path37.resolve(rootDir);
7218
- const memoryDir = path37.join(root, ".cursor", "memory");
7777
+ const root = path38.resolve(rootDir);
7778
+ const memoryDir = path38.join(root, ".cursor", "memory");
7219
7779
  const allNames = await listMonitorFiles(memoryDir);
7220
7780
  const selectionOrder = ["git-fresh", "handoff-aligned", "untriaged-scan"];
7221
7781
  const byName = /* @__PURE__ */ new Map();
7222
7782
  for (const name of allNames) {
7223
- const abs = path37.join(memoryDir, name);
7783
+ const abs = path38.join(memoryDir, name);
7224
7784
  try {
7225
7785
  const [content, st] = await Promise.all([readFile20(abs, "utf8"), stat5(abs)]);
7226
7786
  byName.set(name, { content, mtimeMs: st.mtimeMs });
@@ -7235,7 +7795,7 @@ async function selectUntriagedMonitors(rootDir) {
7235
7795
  const gitFreshSet = [...gitFresh].filter(untriaged).sort();
7236
7796
  let handoff = "";
7237
7797
  try {
7238
- handoff = await readFile20(path37.join(root, ".cursor", "HANDOFF.md"), "utf8");
7798
+ handoff = await readFile20(path38.join(root, ".cursor", "HANDOFF.md"), "utf8");
7239
7799
  } catch {
7240
7800
  handoff = "";
7241
7801
  }
@@ -7255,8 +7815,8 @@ async function selectUntriagedMonitors(rootDir) {
7255
7815
  const row = byName.get(name);
7256
7816
  if (!row) continue;
7257
7817
  entries.push({
7258
- path: path37.join(memoryDir, name),
7259
- 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("/"),
7260
7820
  mtimeMs: row.mtimeMs,
7261
7821
  hasTriageHeading: false,
7262
7822
  hasOpenGaps: hasOpenGaps(row.content),
@@ -7275,7 +7835,7 @@ async function selectUntriagedMonitors(rootDir) {
7275
7835
  }
7276
7836
 
7277
7837
  // src/commands/monitors.ts
7278
- var monitorsCommand = defineCommand13({
7838
+ var monitorsCommand = defineCommand14({
7279
7839
  meta: {
7280
7840
  name: "monitors",
7281
7841
  description: "Select untriaged plan monitors (--untriaged; SoT for chat triage)."
@@ -7302,7 +7862,7 @@ var monitorsCommand = defineCommand13({
7302
7862
  process.exitCode = 2;
7303
7863
  return;
7304
7864
  }
7305
- const result = await selectUntriagedMonitors(path38.resolve(args.cwd));
7865
+ const result = await selectUntriagedMonitors(path39.resolve(args.cwd));
7306
7866
  if (args.json) {
7307
7867
  console.log(JSON.stringify(result, null, 2));
7308
7868
  return;
@@ -7318,8 +7878,8 @@ var monitorsCommand = defineCommand13({
7318
7878
  });
7319
7879
 
7320
7880
  // src/commands/run-plan.ts
7321
- import path43 from "path";
7322
- import { defineCommand as defineCommand14 } from "citty";
7881
+ import path44 from "path";
7882
+ import { defineCommand as defineCommand15 } from "citty";
7323
7883
 
7324
7884
  // src/plan-loop/backends.ts
7325
7885
  import { execFileSync as execFileSync2, spawn as spawn6 } from "child_process";
@@ -7333,7 +7893,7 @@ async function which(bin) {
7333
7893
  }
7334
7894
  }
7335
7895
  function spawnLogged(command, args, logPath) {
7336
- return new Promise((resolve2, reject) => {
7896
+ return new Promise((resolve3, reject) => {
7337
7897
  const out = createWriteStream(logPath, { flags: "w" });
7338
7898
  const child = spawn6(command, args, {
7339
7899
  stdio: ["ignore", "pipe", "pipe"]
@@ -7349,7 +7909,7 @@ function spawnLogged(command, args, logPath) {
7349
7909
  reject(err);
7350
7910
  });
7351
7911
  child.on("close", (code) => {
7352
- out.end(() => resolve2({ exitCode: code ?? 1 }));
7912
+ out.end(() => resolve3({ exitCode: code ?? 1 }));
7353
7913
  });
7354
7914
  });
7355
7915
  }
@@ -7404,13 +7964,13 @@ function listBackendIds() {
7404
7964
 
7405
7965
  // src/plan-loop/run-loop.ts
7406
7966
  import { mkdir as mkdir6, readFile as readFile23, rm as rm2, unlink as unlink2 } from "fs/promises";
7407
- import path42 from "path";
7967
+ import path43 from "path";
7408
7968
 
7409
7969
  // src/plan-loop/external-review.ts
7410
7970
  import { spawn as spawn7 } from "child_process";
7411
- import path39 from "path";
7412
- var CANONICAL_REL = path39.join(".cursor", "scripts", "plan-external-review.sh");
7413
- 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");
7414
7974
  function isPlanExhaustedReason(reason) {
7415
7975
  const r = reason.trim().toLowerCase();
7416
7976
  if (!r) return false;
@@ -7432,8 +7992,8 @@ async function armExternalPlanReview(root, options = {}) {
7432
7992
  const existsFn = options.existsFn ?? fileExists;
7433
7993
  const log = options.log ?? ((line) => console.log(line));
7434
7994
  const force = options.force === true;
7435
- const canonicalPath = path39.join(root, CANONICAL_REL);
7436
- const fallbackPath = path39.join(root, FALLBACK_REL);
7995
+ const canonicalPath = path40.join(root, CANONICAL_REL);
7996
+ const fallbackPath = path40.join(root, FALLBACK_REL);
7437
7997
  let scriptPath = null;
7438
7998
  let scriptRel = CANONICAL_REL;
7439
7999
  if (await existsFn(canonicalPath)) {
@@ -7451,7 +8011,7 @@ async function armExternalPlanReview(root, options = {}) {
7451
8011
  }
7452
8012
  log("Plan exhausted: arming optional external plan review (opt-in handled by script)...");
7453
8013
  const args = force ? [scriptPath, "--force", "--print"] : [scriptPath, "--print"];
7454
- return new Promise((resolve2) => {
8014
+ return new Promise((resolve3) => {
7455
8015
  const child = spawnFn("bash", args, {
7456
8016
  cwd: root,
7457
8017
  env: { ...process.env, AGENT_KIT_HEADLESS: "1" }
@@ -7472,7 +8032,7 @@ async function armExternalPlanReview(root, options = {}) {
7472
8032
  log(
7473
8033
  `tip: external plan review launcher failed (${err.message}). Manual: ${scriptRel} or /plan-external-review`
7474
8034
  );
7475
- resolve2({ invoked: true, exitCode: null, output });
8035
+ resolve3({ invoked: true, exitCode: null, output });
7476
8036
  });
7477
8037
  child.on("close", (code) => {
7478
8038
  if (code !== 0 && code !== null) {
@@ -7480,17 +8040,17 @@ async function armExternalPlanReview(root, options = {}) {
7480
8040
  `tip: external plan review exited ${code} (ignored; does not fail the loop). Manual: ${scriptRel} or /plan-external-review`
7481
8041
  );
7482
8042
  }
7483
- resolve2({ invoked: true, exitCode: code, output });
8043
+ resolve3({ invoked: true, exitCode: code, output });
7484
8044
  });
7485
8045
  });
7486
8046
  }
7487
8047
 
7488
8048
  // src/plan-loop/persona-banners.ts
7489
- import path40 from "path";
8049
+ import path41 from "path";
7490
8050
  import {
7491
8051
  blue,
7492
8052
  cyan as cyan4,
7493
- gray as gray2,
8053
+ gray as gray3,
7494
8054
  green as green3,
7495
8055
  lightGray,
7496
8056
  lightGreen,
@@ -7503,7 +8063,7 @@ var CLI_RUN_PLAN_MODE = "cli-run-plan";
7503
8063
  var DEFAULT_CLI_PERSONA_ID = "ghost-runner";
7504
8064
  var COLORS = {
7505
8065
  white,
7506
- gray: gray2,
8066
+ gray: gray3,
7507
8067
  green: green3,
7508
8068
  cyan: cyan4,
7509
8069
  magenta,
@@ -7522,7 +8082,7 @@ function resolveColor(name, fallback) {
7522
8082
  async function resolveCliPersonaId(root) {
7523
8083
  try {
7524
8084
  const cfg = await readJson(
7525
- path40.join(root, ".cursor", "context", "config.json")
8085
+ path41.join(root, ".cursor", "context", "config.json")
7526
8086
  );
7527
8087
  const modes = cfg?.agentPersona?.modes ?? cfg?.workspaceSkin?.modes;
7528
8088
  const id = modes?.[CLI_RUN_PLAN_MODE];
@@ -7533,7 +8093,7 @@ async function resolveCliPersonaId(root) {
7533
8093
  }
7534
8094
  async function loadPersonaPack(root, personaId) {
7535
8095
  try {
7536
- const personaPath = path40.join(root, "registry", "personas", "core", personaId, "persona.json");
8096
+ const personaPath = path41.join(root, "registry", "personas", "core", personaId, "persona.json");
7537
8097
  const pack = await readJson(personaPath);
7538
8098
  if (!pack || typeof pack.id !== "string") return null;
7539
8099
  return pack;
@@ -7550,7 +8110,7 @@ function createPersonaBannerPrinter(persona) {
7550
8110
  const banners = persona.cliBanners;
7551
8111
  if (!banners.tickStart && !banners.tickEnd && !banners.phaseComplete) return null;
7552
8112
  const primary = resolveColor(persona.ansiPalette?.primary, white);
7553
- const secondary = resolveColor(persona.ansiPalette?.secondary, gray2);
8113
+ const secondary = resolveColor(persona.ansiPalette?.secondary, gray3);
7554
8114
  const accent = resolveColor(persona.ansiPalette?.accent, green3);
7555
8115
  return {
7556
8116
  tickStart(detail) {
@@ -7583,7 +8143,7 @@ function createPersonaBannerPrinter(persona) {
7583
8143
 
7584
8144
  // src/plan-loop/plan-state.ts
7585
8145
  import { readFile as readFile21, readdir as readdir9 } from "fs/promises";
7586
- import path41 from "path";
8146
+ import path42 from "path";
7587
8147
  function countPendingTodos(raw) {
7588
8148
  const lines = raw.split(/\r?\n/);
7589
8149
  let inFront = 0;
@@ -7611,7 +8171,7 @@ function countPendingTodos(raw) {
7611
8171
  async function findActivePlanFile(plansDir) {
7612
8172
  if (!await fileExists(plansDir)) return null;
7613
8173
  const files = (await readdir9(plansDir)).filter((f) => f.endsWith(".plan.md")).sort();
7614
- return files[0] ? path41.join(plansDir, files[0]) : null;
8174
+ return files[0] ? path42.join(plansDir, files[0]) : null;
7615
8175
  }
7616
8176
  async function readPlan(planPath) {
7617
8177
  return readFile21(planPath, "utf8");
@@ -7688,9 +8248,9 @@ function sleep(ms) {
7688
8248
  return new Promise((r) => setTimeout(r, ms));
7689
8249
  }
7690
8250
  async function runPlanLoop(opts) {
7691
- const plansDir = path42.join(opts.root, ".cursor", "plans");
7692
- const stopFile = path42.join(opts.root, ".cursor", "loop.stop");
7693
- 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");
7694
8254
  const planPath = await findActivePlanFile(plansDir);
7695
8255
  if (!planPath) {
7696
8256
  logger.error("No active plan in .cursor/plans/");
@@ -7711,7 +8271,7 @@ async function runPlanLoop(opts) {
7711
8271
  try {
7712
8272
  const persona = await loadCliRunPlanPersona(opts.root);
7713
8273
  const banners = createPersonaBannerPrinter(persona);
7714
- console.log(`Active plan: ${path42.basename(planPath)}`);
8274
+ console.log(`Active plan: ${path43.basename(planPath)}`);
7715
8275
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
7716
8276
  console.log(`Backend: ${opts.backend.id}`);
7717
8277
  if (persona) {
@@ -7754,8 +8314,8 @@ async function runPlanLoop(opts) {
7754
8314
  planExhausted = true;
7755
8315
  break;
7756
8316
  }
7757
- const logPath = path42.join(logDir, `tick-${stamp()}.log`);
7758
- const relLog = path42.relative(opts.root, logPath);
8317
+ const logPath = path43.join(logDir, `tick-${stamp()}.log`);
8318
+ const relLog = path43.relative(opts.root, logPath);
7759
8319
  console.log("");
7760
8320
  const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
7761
8321
  if (banners) banners.tickStart(tickLine);
@@ -7834,7 +8394,7 @@ async function runPlanLoop(opts) {
7834
8394
  const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
7835
8395
  if (banners) banners.phaseComplete(finishDetail);
7836
8396
  console.log(
7837
- `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)}/`
7838
8398
  );
7839
8399
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
7840
8400
  await armExternalPlanReview(opts.root);
@@ -7846,7 +8406,7 @@ async function runPlanLoop(opts) {
7846
8406
  }
7847
8407
 
7848
8408
  // src/commands/run-plan.ts
7849
- var runPlanCommand = defineCommand14({
8409
+ var runPlanCommand = defineCommand15({
7850
8410
  meta: {
7851
8411
  name: "run-plan",
7852
8412
  description: "Headless continuous plan runner (one fresh agent per tick). Never git-prod."
@@ -7905,7 +8465,7 @@ var runPlanCommand = defineCommand14({
7905
8465
  return;
7906
8466
  }
7907
8467
  const code = await runPlanLoop({
7908
- root: path43.resolve(args.cwd),
8468
+ root: path44.resolve(args.cwd),
7909
8469
  maxTicks,
7910
8470
  sleepSeconds,
7911
8471
  model: args.model ? String(args.model) : void 0,
@@ -7917,8 +8477,8 @@ var runPlanCommand = defineCommand14({
7917
8477
  });
7918
8478
 
7919
8479
  // src/commands/scan.ts
7920
- import { defineCommand as defineCommand15 } from "citty";
7921
- var scanCommand = defineCommand15({
8480
+ import { defineCommand as defineCommand16 } from "citty";
8481
+ var scanCommand = defineCommand16({
7922
8482
  meta: {
7923
8483
  name: "scan",
7924
8484
  description: "Scan the repository and print the detected profile."
@@ -7942,9 +8502,9 @@ var scanCommand = defineCommand15({
7942
8502
  import { spawn as spawn8 } from "child_process";
7943
8503
  import { appendFile, mkdir as mkdir7, readFile as readFile24, writeFile as writeFile12 } from "fs/promises";
7944
8504
  import { homedir as homedir4 } from "os";
7945
- import path44 from "path";
8505
+ import path45 from "path";
7946
8506
  import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
7947
- import { defineCommand as defineCommand16 } from "citty";
8507
+ import { defineCommand as defineCommand17 } from "citty";
7948
8508
  import { cyan as cyan5, green as green4, yellow as yellow3 } from "kolorist";
7949
8509
  var NPM_GLOBAL_DIR_NAME = ".npm-global";
7950
8510
  var SETUP_GLOBAL_MARKER = "# agent-kit setup-global";
@@ -7952,9 +8512,9 @@ var DEFAULT_PACKAGE_SPEC = "@dadado/agent-kit-cli";
7952
8512
  function planSetupGlobalSteps(env, options = {}) {
7953
8513
  const homeDir = options.homeDir ?? homedir4();
7954
8514
  const packageSpec = options.packageSpec ?? DEFAULT_PACKAGE_SPEC;
7955
- const npmGlobalDir = path44.join(homeDir, NPM_GLOBAL_DIR_NAME);
7956
- const npmGlobalBin = path44.join(npmGlobalDir, "bin");
7957
- 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");
7958
8518
  const npmrcPrefixValue = `~/${NPM_GLOBAL_DIR_NAME}`;
7959
8519
  const pathExportLine = `export PATH="${npmGlobalBin}:$PATH"`;
7960
8520
  const shellProfile = env.shellProfile;
@@ -8033,12 +8593,12 @@ async function safeReadFile(fs, filePath) {
8033
8593
  return "";
8034
8594
  }
8035
8595
  }
8036
- var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve2) => {
8596
+ var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve3) => {
8037
8597
  const child = spawn8("npm", ["i", "-g", packageSpec], { stdio: "inherit" });
8038
- child.on("error", (error) => resolve2({ ok: false, error }));
8598
+ child.on("error", (error) => resolve3({ ok: false, error }));
8039
8599
  child.on("close", (code) => {
8040
- if (code === 0) resolve2({ ok: true });
8041
- 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"}`) });
8042
8602
  });
8043
8603
  });
8044
8604
  var defaultConfirmImpl = async (message) => {
@@ -8187,7 +8747,7 @@ ${verifyStep.title}`);
8187
8747
  }
8188
8748
  return { exitCode: 0, mutated, outcome: "completed", env, plan };
8189
8749
  }
8190
- var setupGlobalCommand = defineCommand16({
8750
+ var setupGlobalCommand = defineCommand17({
8191
8751
  meta: {
8192
8752
  name: "setup-global",
8193
8753
  description: "Self-heal a root-owned npm prefix: relocate to ~/.npm-global, fix PATH, reinstall globally."
@@ -8216,8 +8776,8 @@ var setupGlobalCommand = defineCommand16({
8216
8776
  });
8217
8777
 
8218
8778
  // src/commands/status.ts
8219
- import path45 from "path";
8220
- import { defineCommand as defineCommand17 } from "citty";
8779
+ import path46 from "path";
8780
+ import { defineCommand as defineCommand18 } from "citty";
8221
8781
  function profileStatus(profile) {
8222
8782
  if (!profile) return { origin: "none", evidence: [], profile: null };
8223
8783
  if ("detection" in profile && profile.detection && typeof profile.detection === "object") {
@@ -8230,7 +8790,7 @@ function profileStatus(profile) {
8230
8790
  }
8231
8791
  return { origin: "legacy-wizard", evidence: [], profile };
8232
8792
  }
8233
- var statusCommand = defineCommand17({
8793
+ var statusCommand = defineCommand18({
8234
8794
  meta: {
8235
8795
  name: "status",
8236
8796
  description: "Show installed kit version, manifest, and optional profile."
@@ -8247,11 +8807,11 @@ var statusCommand = defineCommand17({
8247
8807
  }
8248
8808
  },
8249
8809
  async run({ args }) {
8250
- const rootDir = path45.resolve(args.cwd);
8810
+ const rootDir = path46.resolve(args.cwd);
8251
8811
  const [manifest, rawProfile, scan] = await Promise.all([
8252
8812
  loadAgentKitManifest(rootDir),
8253
8813
  readJson(
8254
- path45.join(rootDir, ".cursor", "agent-kit.config.json")
8814
+ path46.join(rootDir, ".cursor", "agent-kit.config.json")
8255
8815
  ),
8256
8816
  runScanner(rootDir)
8257
8817
  ]);
@@ -8306,13 +8866,13 @@ var statusCommand = defineCommand17({
8306
8866
  });
8307
8867
 
8308
8868
  // src/commands/update.ts
8309
- import { defineCommand as defineCommand18 } from "citty";
8869
+ import { defineCommand as defineCommand19 } from "citty";
8310
8870
 
8311
8871
  // src/lifecycle/check-updates.ts
8312
- import { execFile as execFile6 } from "child_process";
8313
- import path46 from "path";
8872
+ import { execFile as execFile7 } from "child_process";
8873
+ import path47 from "path";
8314
8874
  import { promisify as promisify6 } from "util";
8315
- var execFileAsync5 = promisify6(execFile6);
8875
+ var execFileAsync5 = promisify6(execFile7);
8316
8876
  var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/i;
8317
8877
  var FACTORY_URL_MARKERS = ["agent-kit-dev"];
8318
8878
  var FACTORY_REFS = /* @__PURE__ */ new Set(["staging", "homologacao", "develop", "dev"]);
@@ -8401,11 +8961,11 @@ function intervalElapsed2(lastCheckedAt, intervalDays) {
8401
8961
  return Date.now() - last >= ms;
8402
8962
  }
8403
8963
  async function loadContextConfig2(cwd) {
8404
- const configPath = path46.join(cwd, ".cursor", "context", "config.json");
8964
+ const configPath = path47.join(cwd, ".cursor", "context", "config.json");
8405
8965
  return readJson(configPath);
8406
8966
  }
8407
8967
  async function stampLastCheckedAt(cwd) {
8408
- const configPath = path46.join(cwd, ".cursor", "context", "config.json");
8968
+ const configPath = path47.join(cwd, ".cursor", "context", "config.json");
8409
8969
  const existing = await loadContextConfig2(cwd) ?? {};
8410
8970
  const prev = existing.updateCheck && typeof existing.updateCheck === "object" ? { ...existing.updateCheck } : {};
8411
8971
  existing.updateCheck = {
@@ -8417,7 +8977,7 @@ async function stampLastCheckedAt(cwd) {
8417
8977
  }
8418
8978
  async function readLocalKitVersion(registryRoot) {
8419
8979
  for (const rel of ["packages/cli/package.json", "package.json"]) {
8420
- const data = await readJson(path46.join(registryRoot, rel));
8980
+ const data = await readJson(path47.join(registryRoot, rel));
8421
8981
  if (data && typeof data.version === "string" && data.version.length > 0) {
8422
8982
  return data.version;
8423
8983
  }
@@ -8438,7 +8998,7 @@ async function checkAgainstLocalRegistry(cwd, manifest, options) {
8438
8998
  status: "error",
8439
8999
  installedVersion: manifest.version,
8440
9000
  latestVersion: null,
8441
- registryUrl: path46.resolve(registryPath),
9001
+ registryUrl: path47.resolve(registryPath),
8442
9002
  registryRef: "local",
8443
9003
  applyRecommended: false,
8444
9004
  message: `Failed to resolve --registry: ${msg}`
@@ -8660,7 +9220,7 @@ async function checkForUpdates(cwd, options = {}) {
8660
9220
  }
8661
9221
 
8662
9222
  // src/commands/update.ts
8663
- var updateCommand = defineCommand18({
9223
+ var updateCommand = defineCommand19({
8664
9224
  meta: {
8665
9225
  name: "update",
8666
9226
  description: "Re-apply L0/packs/skills from the registry (never overwrites L3). --check = notify-only."
@@ -8795,8 +9355,8 @@ ${err.recovery}
8795
9355
 
8796
9356
  // src/commands/validate.ts
8797
9357
  import { readFile as readFile25 } from "fs/promises";
8798
- import path47 from "path";
8799
- import { defineCommand as defineCommand19 } from "citty";
9358
+ import path48 from "path";
9359
+ import { defineCommand as defineCommand20 } from "citty";
8800
9360
 
8801
9361
  // src/invariants/plan-schema.ts
8802
9362
  var CITE5 = "agent-kit validate plan (.cursor/context/templates/plan.md)";
@@ -8842,7 +9402,7 @@ function validatePlanFrontmatterText(text) {
8842
9402
  // src/commands/validate.ts
8843
9403
  async function resolveEditedPath(cwd, explicit) {
8844
9404
  if (explicit) {
8845
- const filePath2 = path47.resolve(cwd, explicit);
9405
+ const filePath2 = path48.resolve(cwd, explicit);
8846
9406
  try {
8847
9407
  return { filePath: filePath2, content: await readFile25(filePath2, "utf8") };
8848
9408
  } catch {
@@ -8852,7 +9412,7 @@ async function resolveEditedPath(cwd, explicit) {
8852
9412
  const payload = await readStdinJson();
8853
9413
  const rel = typeof payload.file_path === "string" && payload.file_path || typeof payload.path === "string" && payload.path || typeof payload.file === "string" && payload.file || "";
8854
9414
  if (!rel) return null;
8855
- const filePath = path47.isAbsolute(rel) ? rel : path47.resolve(cwd, rel);
9415
+ const filePath = path48.isAbsolute(rel) ? rel : path48.resolve(cwd, rel);
8856
9416
  try {
8857
9417
  return { filePath, content: await readFile25(filePath, "utf8") };
8858
9418
  } catch {
@@ -8866,13 +9426,13 @@ function isPlanPath(filePath) {
8866
9426
  const norm = filePath.replace(/\\/g, "/");
8867
9427
  return norm.includes("/.cursor/plans/") && norm.endsWith(".plan.md");
8868
9428
  }
8869
- var validateCommand = defineCommand19({
9429
+ var validateCommand = defineCommand20({
8870
9430
  meta: {
8871
9431
  name: "validate",
8872
9432
  description: "Advisory validators for HANDOFF / plan frontmatter (hook adapter)."
8873
9433
  },
8874
9434
  subCommands: {
8875
- handoff: defineCommand19({
9435
+ handoff: defineCommand20({
8876
9436
  meta: { name: "handoff", description: "Validate HANDOFF machine fields" },
8877
9437
  args: {
8878
9438
  cwd: { type: "string", default: process.cwd() },
@@ -8882,7 +9442,7 @@ var validateCommand = defineCommand19({
8882
9442
  async run({ args }) {
8883
9443
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
8884
9444
  const fileArg = typeof args.file === "string" ? args.file : void 0;
8885
- 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");
8886
9446
  let content = "";
8887
9447
  try {
8888
9448
  content = await readFile25(filePath, "utf8");
@@ -8894,7 +9454,7 @@ var validateCommand = defineCommand19({
8894
9454
  console.log(JSON.stringify({ ok: warnings.length === 0, warnings }));
8895
9455
  }
8896
9456
  }),
8897
- plan: defineCommand19({
9457
+ plan: defineCommand20({
8898
9458
  meta: { name: "plan", description: "Validate plan frontmatter" },
8899
9459
  args: {
8900
9460
  cwd: { type: "string", default: process.cwd() },
@@ -8909,7 +9469,7 @@ var validateCommand = defineCommand19({
8909
9469
  process.exitCode = 2;
8910
9470
  return;
8911
9471
  }
8912
- const filePath = path47.resolve(cwd, fileArg);
9472
+ const filePath = path48.resolve(cwd, fileArg);
8913
9473
  let content = "";
8914
9474
  try {
8915
9475
  content = await readFile25(filePath, "utf8");
@@ -8921,7 +9481,7 @@ var validateCommand = defineCommand19({
8921
9481
  console.log(JSON.stringify({ ok: warnings.length === 0, warnings }));
8922
9482
  }
8923
9483
  }),
8924
- "after-edit": defineCommand19({
9484
+ "after-edit": defineCommand20({
8925
9485
  meta: {
8926
9486
  name: "after-edit",
8927
9487
  description: "Advisory afterFileEdit: annotate HANDOFF/plan issues (never block)"
@@ -8931,7 +9491,7 @@ var validateCommand = defineCommand19({
8931
9491
  },
8932
9492
  async run({ args }) {
8933
9493
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
8934
- const resolved = await resolveEditedPath(path47.resolve(cwd));
9494
+ const resolved = await resolveEditedPath(path48.resolve(cwd));
8935
9495
  if (!resolved) {
8936
9496
  console.log(JSON.stringify({}));
8937
9497
  return;
@@ -8974,19 +9534,10 @@ var validateCommand = defineCommand19({
8974
9534
  });
8975
9535
 
8976
9536
  // src/welcome/help-groups.ts
8977
- import { bold as bold2, gray as gray4, underline } from "kolorist";
9537
+ import { bold as bold2, gray as gray5, underline } from "kolorist";
8978
9538
 
8979
9539
  // src/welcome/screen.ts
8980
- import {
8981
- blue as blue2,
8982
- cyan as cyan6,
8983
- gray as gray3,
8984
- options as koloristOptions3,
8985
- lightCyan,
8986
- trueColor,
8987
- white as white2
8988
- } from "kolorist";
8989
- var KOLORIST_TRUECOLOR = 3;
9540
+ import { blue as blue2, cyan as cyan6, gray as gray4, lightCyan, trueColor as trueColor2, white as white2 } from "kolorist";
8990
9541
  var HELMET_ASCII = [
8991
9542
  " ____",
8992
9543
  " .-' '-.",
@@ -9007,19 +9558,7 @@ function hexToRgb(hex) {
9007
9558
  }
9008
9559
  function outlineAnsi(line) {
9009
9560
  const [r, g, b] = hexToRgb(HELMET_OUTLINE);
9010
- return trueColor(r, g, b)(line);
9011
- }
9012
- function withKoloristColor(fn) {
9013
- const prevEnabled = koloristOptions3.enabled;
9014
- const prevLevel = koloristOptions3.supportLevel;
9015
- koloristOptions3.enabled = true;
9016
- koloristOptions3.supportLevel = KOLORIST_TRUECOLOR;
9017
- try {
9018
- return fn();
9019
- } finally {
9020
- koloristOptions3.enabled = prevEnabled;
9021
- koloristOptions3.supportLevel = prevLevel;
9022
- }
9561
+ return trueColor2(r, g, b)(line);
9023
9562
  }
9024
9563
  function hasCliSubcommand(rawArgs) {
9025
9564
  return Boolean(rawArgs?.some((arg) => !arg.startsWith("-")));
@@ -9039,6 +9578,7 @@ var WELCOME_UTILITY_HINTS = [
9039
9578
  { cmd: "agent-kit doctor", hint: "repository readiness" },
9040
9579
  { cmd: "agent-kit status", hint: "installed kit version" },
9041
9580
  { cmd: "agent-kit dashboard", hint: "Mission Control panel" },
9581
+ { cmd: "agent-kit mission-control", hint: "Mission Control TUI" },
9042
9582
  { cmd: "agent-kit init", hint: "guided install entry" }
9043
9583
  ];
9044
9584
  function renderWelcomeScreen(opts = {}) {
@@ -9046,27 +9586,27 @@ function renderWelcomeScreen(opts = {}) {
9046
9586
  const color = shouldUseWelcomeColor(opts);
9047
9587
  const title = color ? white2("Mission Kit") : "Mission Kit";
9048
9588
  const product = color ? cyan6("agent-kit") : "agent-kit";
9049
- const muted = (s) => color ? gray3(s) : s;
9589
+ const muted2 = (s) => color ? gray4(s) : s;
9050
9590
  const lines = [
9051
9591
  renderHelmetAscii(color),
9052
9592
  "",
9053
9593
  `${title} \xB7 ${product} v${version}`,
9054
- 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"),
9055
9595
  "",
9056
- muted("Try:"),
9596
+ muted2("Try:"),
9057
9597
  ...(() => {
9058
9598
  const width = Math.max(...WELCOME_UTILITY_HINTS.map(({ cmd }) => cmd.length));
9059
9599
  return WELCOME_UTILITY_HINTS.map(({ cmd, hint }) => {
9060
9600
  const pad = " ".repeat(width - cmd.length + 2);
9061
9601
  const left = color ? cyan6(` ${cmd}`) : ` ${cmd}`;
9062
- return `${left}${pad}${muted(hint)}`;
9602
+ return `${left}${pad}${muted2(hint)}`;
9063
9603
  });
9064
9604
  })(),
9065
9605
  "",
9066
- muted(
9606
+ muted2(
9067
9607
  "Chat HITL (start-project, git-staging/prod, run-plan-all) stays in Cursor slash commands."
9068
9608
  ),
9069
- muted(
9609
+ muted2(
9070
9610
  `${shouldUseVisualMotion(opts) ? SPACE_MARKS.star : SPACE_MARKS.tick} ${tipAt(
9071
9611
  [...version].reduce((n, c) => n + c.charCodeAt(0), 0)
9072
9612
  )}`
@@ -9094,7 +9634,7 @@ var CLI_HELP_GROUPS = [
9094
9634
  {
9095
9635
  id: "dashboard",
9096
9636
  title: "DASHBOARD",
9097
- commands: ["dashboard", "dashboard-broadcast", "monitors"]
9637
+ commands: ["dashboard", "dashboard-broadcast", "mission-control", "monitors"]
9098
9638
  },
9099
9639
  {
9100
9640
  id: "integrity",
@@ -9120,7 +9660,7 @@ async function resolveSubMeta(subCommands) {
9120
9660
  async function renderGroupedRootHelp(cmd) {
9121
9661
  const color = shouldUseWelcomeColor();
9122
9662
  const u = (s) => color ? underline(bold2(s)) : s;
9123
- const g = (s) => color ? gray4(s) : s;
9663
+ const g = (s) => color ? gray5(s) : s;
9124
9664
  const meta = await resolveCommandMeta(cmd.meta);
9125
9665
  const name = meta?.name ?? "agent-kit";
9126
9666
  const version = meta?.version ?? KIT_VERSION;
@@ -9164,7 +9704,7 @@ async function renderGroupedRootHelp(cmd) {
9164
9704
  }
9165
9705
 
9166
9706
  // src/index.ts
9167
- var main = defineCommand20({
9707
+ var main = defineCommand21({
9168
9708
  meta: {
9169
9709
  name: "agent-kit",
9170
9710
  description: "HITL framework for AI-assisted IDEs (Mission Kit family)",
@@ -9186,6 +9726,7 @@ var main = defineCommand20({
9186
9726
  "run-plan": runPlanCommand,
9187
9727
  dashboard: dashboardCommand,
9188
9728
  "dashboard-broadcast": dashboardBroadcastCommand,
9729
+ "mission-control": missionControlCommand,
9189
9730
  hook: hookCommand,
9190
9731
  guard: guardCommand,
9191
9732
  monitors: monitorsCommand,