@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/README.md +4 -1
- package/dashboard/README.md +17 -0
- package/dashboard/dashboard-data.mjs +215 -5
- package/dashboard/dashboard.html +285 -1
- package/dashboard/lib/live-refresh.d.mts +23 -0
- package/dashboard/lib/semantic-model.mjs +12 -5
- package/dist/index.js +693 -161
- package/package.json +1 -1
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
|
|
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((
|
|
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) =>
|
|
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((
|
|
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) =>
|
|
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.
|
|
3410
|
+
scan.stack.language !== "unknown" || scan.stack.hasProjectFiles ? "ready" : "needs_choice",
|
|
3398
3411
|
true,
|
|
3399
|
-
scan.stack.packageManagerEvidence ??
|
|
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
|
|
3803
|
-
hasRemoteStaging
|
|
3804
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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, {
|
|
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((
|
|
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) =>
|
|
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
|
|
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((
|
|
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", () =>
|
|
5621
|
+
child.on("error", () => resolve3(null));
|
|
5472
5622
|
child.on("close", () => {
|
|
5473
5623
|
try {
|
|
5474
5624
|
const parsed = JSON.parse(out.trim());
|
|
5475
|
-
|
|
5625
|
+
resolve3(parsed && typeof parsed === "object" ? parsed : null);
|
|
5476
5626
|
} catch {
|
|
5477
|
-
|
|
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((
|
|
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(
|
|
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(
|
|
5649
|
+
void runUpdateCheckJson(root).then(resolve3);
|
|
5500
5650
|
return;
|
|
5501
5651
|
}
|
|
5502
5652
|
try {
|
|
5503
|
-
|
|
5653
|
+
resolve3(JSON.parse(out.trim()));
|
|
5504
5654
|
} catch {
|
|
5505
|
-
void runUpdateCheckJson(root).then(
|
|
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((
|
|
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", () =>
|
|
5699
|
+
child.on("error", () => resolve3(null));
|
|
5550
5700
|
child.on("close", () => {
|
|
5551
5701
|
try {
|
|
5552
5702
|
const parsed = JSON.parse(out.trim());
|
|
5553
|
-
|
|
5703
|
+
resolve3(parsed && typeof parsed === "object" ? parsed : null);
|
|
5554
5704
|
} catch {
|
|
5555
|
-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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", () =>
|
|
5631
|
-
child.on("close", () =>
|
|
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
|
|
6291
|
+
Read these files if they exist. Prefer a one-shot ASCII Mission Control snapshot over a plain HANDOFF paraphrase.
|
|
6138
6292
|
|
|
6139
|
-
1. \`
|
|
6140
|
-
2.
|
|
6141
|
-
|
|
6142
|
-
|
|
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/
|
|
7156
|
-
import path38 from "path";
|
|
7311
|
+
// src/commands/mission-control.ts
|
|
7157
7312
|
import { defineCommand as defineCommand13 } from "citty";
|
|
7158
7313
|
|
|
7159
|
-
// src/
|
|
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 {
|
|
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(
|
|
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 =
|
|
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 =
|
|
7227
|
-
const memoryDir =
|
|
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 =
|
|
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(
|
|
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:
|
|
7268
|
-
relativePath:
|
|
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 =
|
|
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(
|
|
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
|
|
7331
|
-
import { defineCommand as
|
|
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((
|
|
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(() =>
|
|
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
|
|
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
|
|
7421
|
-
var CANONICAL_REL =
|
|
7422
|
-
var FALLBACK_REL =
|
|
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 =
|
|
7445
|
-
const fallbackPath =
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
8049
|
+
import path41 from "path";
|
|
7499
8050
|
import {
|
|
7500
8051
|
blue,
|
|
7501
8052
|
cyan as cyan4,
|
|
7502
|
-
gray as
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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
|
|
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] ?
|
|
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 =
|
|
7701
|
-
const stopFile =
|
|
7702
|
-
const logDir =
|
|
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: ${
|
|
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 =
|
|
7767
|
-
const relLog =
|
|
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 ${
|
|
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 =
|
|
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:
|
|
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
|
|
7930
|
-
var scanCommand =
|
|
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
|
|
8505
|
+
import path45 from "path";
|
|
7955
8506
|
import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
|
|
7956
|
-
import { defineCommand as
|
|
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 =
|
|
7965
|
-
const npmGlobalBin =
|
|
7966
|
-
const npmrcPath =
|
|
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((
|
|
8596
|
+
var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve3) => {
|
|
8046
8597
|
const child = spawn8("npm", ["i", "-g", packageSpec], { stdio: "inherit" });
|
|
8047
|
-
child.on("error", (error) =>
|
|
8598
|
+
child.on("error", (error) => resolve3({ ok: false, error }));
|
|
8048
8599
|
child.on("close", (code) => {
|
|
8049
|
-
if (code === 0)
|
|
8050
|
-
else
|
|
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 =
|
|
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
|
|
8229
|
-
import { defineCommand as
|
|
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 =
|
|
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 =
|
|
8810
|
+
const rootDir = path46.resolve(args.cwd);
|
|
8260
8811
|
const [manifest, rawProfile, scan] = await Promise.all([
|
|
8261
8812
|
loadAgentKitManifest(rootDir),
|
|
8262
8813
|
readJson(
|
|
8263
|
-
|
|
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
|
|
8869
|
+
import { defineCommand as defineCommand19 } from "citty";
|
|
8319
8870
|
|
|
8320
8871
|
// src/lifecycle/check-updates.ts
|
|
8321
|
-
import { execFile as
|
|
8322
|
-
import
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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:
|
|
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 =
|
|
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
|
|
8808
|
-
import { defineCommand as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 ?
|
|
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:
|
|
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 =
|
|
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":
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
9594
|
+
muted2("HITL framework for AI-assisted IDEs \xB7 @dadado/agent-kit-cli"),
|
|
9064
9595
|
"",
|
|
9065
|
-
|
|
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}${
|
|
9602
|
+
return `${left}${pad}${muted2(hint)}`;
|
|
9072
9603
|
});
|
|
9073
9604
|
})(),
|
|
9074
9605
|
"",
|
|
9075
|
-
|
|
9606
|
+
muted2(
|
|
9076
9607
|
"Chat HITL (start-project, git-staging/prod, run-plan-all) stays in Cursor slash commands."
|
|
9077
9608
|
),
|
|
9078
|
-
|
|
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 ?
|
|
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 =
|
|
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,
|