@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/README.md +11 -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/dashboard/social-preview.png +0 -0
- package/dashboard/social-preview.svg +18 -0
- package/dist/index.js +702 -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";
|
|
@@ -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((
|
|
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) =>
|
|
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((
|
|
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) =>
|
|
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.
|
|
3410
|
+
scan.stack.language !== "unknown" || scan.stack.hasProjectFiles ? "ready" : "needs_choice",
|
|
3389
3411
|
true,
|
|
3390
|
-
scan.stack.packageManagerEvidence ??
|
|
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
|
|
3794
|
-
hasRemoteStaging
|
|
3795
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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, {
|
|
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((
|
|
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) =>
|
|
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
|
|
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((
|
|
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", () =>
|
|
5621
|
+
child.on("error", () => resolve3(null));
|
|
5463
5622
|
child.on("close", () => {
|
|
5464
5623
|
try {
|
|
5465
5624
|
const parsed = JSON.parse(out.trim());
|
|
5466
|
-
|
|
5625
|
+
resolve3(parsed && typeof parsed === "object" ? parsed : null);
|
|
5467
5626
|
} catch {
|
|
5468
|
-
|
|
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((
|
|
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(
|
|
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(
|
|
5649
|
+
void runUpdateCheckJson(root).then(resolve3);
|
|
5491
5650
|
return;
|
|
5492
5651
|
}
|
|
5493
5652
|
try {
|
|
5494
|
-
|
|
5653
|
+
resolve3(JSON.parse(out.trim()));
|
|
5495
5654
|
} catch {
|
|
5496
|
-
void runUpdateCheckJson(root).then(
|
|
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((
|
|
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", () =>
|
|
5699
|
+
child.on("error", () => resolve3(null));
|
|
5541
5700
|
child.on("close", () => {
|
|
5542
5701
|
try {
|
|
5543
5702
|
const parsed = JSON.parse(out.trim());
|
|
5544
|
-
|
|
5703
|
+
resolve3(parsed && typeof parsed === "object" ? parsed : null);
|
|
5545
5704
|
} catch {
|
|
5546
|
-
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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", () =>
|
|
5622
|
-
child.on("close", () =>
|
|
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
|
|
6291
|
+
Read these files if they exist. Prefer a one-shot ASCII Mission Control snapshot over a plain HANDOFF paraphrase.
|
|
6129
6292
|
|
|
6130
|
-
1. \`
|
|
6131
|
-
2.
|
|
6132
|
-
|
|
6133
|
-
|
|
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/
|
|
7147
|
-
import path38 from "path";
|
|
7311
|
+
// src/commands/mission-control.ts
|
|
7148
7312
|
import { defineCommand as defineCommand13 } from "citty";
|
|
7149
7313
|
|
|
7150
|
-
// 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
|
|
7151
7402
|
import { execFile as execFile5 } from "child_process";
|
|
7152
|
-
import {
|
|
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(
|
|
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 =
|
|
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 =
|
|
7218
|
-
const memoryDir =
|
|
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 =
|
|
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(
|
|
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:
|
|
7259
|
-
relativePath:
|
|
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 =
|
|
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(
|
|
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
|
|
7322
|
-
import { defineCommand as
|
|
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((
|
|
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(() =>
|
|
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
|
|
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
|
|
7412
|
-
var CANONICAL_REL =
|
|
7413
|
-
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");
|
|
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 =
|
|
7436
|
-
const fallbackPath =
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
8049
|
+
import path41 from "path";
|
|
7490
8050
|
import {
|
|
7491
8051
|
blue,
|
|
7492
8052
|
cyan as cyan4,
|
|
7493
|
-
gray as
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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
|
|
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] ?
|
|
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 =
|
|
7692
|
-
const stopFile =
|
|
7693
|
-
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");
|
|
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: ${
|
|
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 =
|
|
7758
|
-
const relLog =
|
|
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 ${
|
|
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 =
|
|
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:
|
|
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
|
|
7921
|
-
var scanCommand =
|
|
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
|
|
8505
|
+
import path45 from "path";
|
|
7946
8506
|
import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
|
|
7947
|
-
import { defineCommand as
|
|
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 =
|
|
7956
|
-
const npmGlobalBin =
|
|
7957
|
-
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");
|
|
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((
|
|
8596
|
+
var defaultNpmInstallImpl = (packageSpec) => new Promise((resolve3) => {
|
|
8037
8597
|
const child = spawn8("npm", ["i", "-g", packageSpec], { stdio: "inherit" });
|
|
8038
|
-
child.on("error", (error) =>
|
|
8598
|
+
child.on("error", (error) => resolve3({ ok: false, error }));
|
|
8039
8599
|
child.on("close", (code) => {
|
|
8040
|
-
if (code === 0)
|
|
8041
|
-
else
|
|
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 =
|
|
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
|
|
8220
|
-
import { defineCommand as
|
|
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 =
|
|
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 =
|
|
8810
|
+
const rootDir = path46.resolve(args.cwd);
|
|
8251
8811
|
const [manifest, rawProfile, scan] = await Promise.all([
|
|
8252
8812
|
loadAgentKitManifest(rootDir),
|
|
8253
8813
|
readJson(
|
|
8254
|
-
|
|
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
|
|
8869
|
+
import { defineCommand as defineCommand19 } from "citty";
|
|
8310
8870
|
|
|
8311
8871
|
// src/lifecycle/check-updates.ts
|
|
8312
|
-
import { execFile as
|
|
8313
|
-
import
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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:
|
|
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 =
|
|
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
|
|
8799
|
-
import { defineCommand as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 ?
|
|
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:
|
|
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 =
|
|
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":
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
9594
|
+
muted2("HITL framework for AI-assisted IDEs \xB7 @dadado/agent-kit-cli"),
|
|
9055
9595
|
"",
|
|
9056
|
-
|
|
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}${
|
|
9602
|
+
return `${left}${pad}${muted2(hint)}`;
|
|
9063
9603
|
});
|
|
9064
9604
|
})(),
|
|
9065
9605
|
"",
|
|
9066
|
-
|
|
9606
|
+
muted2(
|
|
9067
9607
|
"Chat HITL (start-project, git-staging/prod, run-plan-all) stays in Cursor slash commands."
|
|
9068
9608
|
),
|
|
9069
|
-
|
|
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 ?
|
|
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 =
|
|
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,
|