@dadado/agent-kit-cli 4.6.0 → 4.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.
Files changed (2) hide show
  1. package/dist/index.js +201 -133
  2. 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 defineCommand12, runMain } from "citty";
4
+ import { defineCommand as defineCommand13, runMain } from "citty";
5
5
 
6
6
  // src/commands/add.ts
7
7
  import { defineCommand } from "citty";
@@ -997,6 +997,10 @@ var L0_ARTIFACTS = [
997
997
  },
998
998
  { source: ".cursor/commands/handoff.md", target: ".cursor/commands/handoff.md" },
999
999
  { source: ".cursor/commands/summary.md", target: ".cursor/commands/summary.md" },
1000
+ {
1001
+ source: ".cursor/commands/dashboard.md",
1002
+ target: ".cursor/commands/dashboard.md"
1003
+ },
1000
1004
  {
1001
1005
  source: ".cursor/commands/git-staging.md",
1002
1006
  target: ".cursor/commands/git-staging.md"
@@ -1350,12 +1354,75 @@ var contributeCommand = defineCommand2({
1350
1354
  }
1351
1355
  });
1352
1356
 
1353
- // src/commands/diff.ts
1357
+ // src/commands/dashboard.ts
1358
+ import { spawn } from "child_process";
1359
+ import { access as access2 } from "fs/promises";
1360
+ import path9 from "path";
1354
1361
  import { defineCommand as defineCommand3 } from "citty";
1362
+ async function findDashboardStart(cwd) {
1363
+ let dir = path9.resolve(cwd);
1364
+ for (; ; ) {
1365
+ const candidate2 = path9.join(dir, "dashboard", "start.mjs");
1366
+ try {
1367
+ await access2(candidate2);
1368
+ return candidate2;
1369
+ } catch {
1370
+ }
1371
+ const parent = path9.dirname(dir);
1372
+ if (parent === dir) return null;
1373
+ dir = parent;
1374
+ }
1375
+ }
1376
+ function runStartScript(startPath, env) {
1377
+ return new Promise((resolve, reject) => {
1378
+ const child = spawn(process.execPath, [startPath], {
1379
+ cwd: path9.dirname(path9.dirname(startPath)),
1380
+ env,
1381
+ stdio: "inherit"
1382
+ });
1383
+ child.on("error", reject);
1384
+ child.on("close", (code) => resolve(code ?? 1));
1385
+ });
1386
+ }
1387
+ var dashboardCommand = defineCommand3({
1388
+ meta: {
1389
+ name: "dashboard",
1390
+ description: "Start Mission Control if needed and open http://localhost:3333 (terminal counterpart to /dashboard)."
1391
+ },
1392
+ args: {
1393
+ cwd: {
1394
+ type: "string",
1395
+ default: process.cwd(),
1396
+ description: "Directory to search upward for dashboard/start.mjs"
1397
+ },
1398
+ "no-open": {
1399
+ type: "boolean",
1400
+ default: false,
1401
+ description: "Do not open a browser; only ensure the server is up and print the URL"
1402
+ }
1403
+ },
1404
+ async run({ args }) {
1405
+ const startPath = await findDashboardStart(args.cwd);
1406
+ if (!startPath) {
1407
+ logger.error(
1408
+ "No dashboard/start.mjs found. Mission Control ships with the agent-kit repo; run from that tree, or use npm run dashboard there."
1409
+ );
1410
+ process.exitCode = 1;
1411
+ return;
1412
+ }
1413
+ const env = { ...process.env };
1414
+ if (args["no-open"]) env.MISSION_CONTROL_NO_OPEN = "1";
1415
+ const code = await runStartScript(startPath, env);
1416
+ if (code !== 0) process.exitCode = code;
1417
+ }
1418
+ });
1419
+
1420
+ // src/commands/diff.ts
1421
+ import { defineCommand as defineCommand4 } from "citty";
1355
1422
 
1356
1423
  // src/lifecycle/diff.ts
1357
1424
  import { readFile as readFile5 } from "fs/promises";
1358
- import path9 from "path";
1425
+ import path10 from "path";
1359
1426
  async function readIfExists(abs) {
1360
1427
  try {
1361
1428
  return await readFile5(abs, "utf8");
@@ -1364,7 +1431,7 @@ async function readIfExists(abs) {
1364
1431
  }
1365
1432
  }
1366
1433
  async function comparePair(registryRoot, projectRoot, sourceRel, targetRel, protectedGlobs) {
1367
- const posixTarget = targetRel.split(path9.sep).join("/");
1434
+ const posixTarget = targetRel.split(path10.sep).join("/");
1368
1435
  if (isProtectedPath(posixTarget, protectedGlobs)) {
1369
1436
  return { path: posixTarget, status: "protected" };
1370
1437
  }
@@ -1394,7 +1461,7 @@ async function diffAgainstRegistry(registryRoot, projectRoot, manifest) {
1394
1461
  const entries = [];
1395
1462
  const seen = /* @__PURE__ */ new Set();
1396
1463
  const pushUnique = async (sourceRel, targetRel) => {
1397
- const key = targetRel.split(path9.sep).join("/");
1464
+ const key = targetRel.split(path10.sep).join("/");
1398
1465
  if (seen.has(key)) return;
1399
1466
  seen.add(key);
1400
1467
  entries.push(
@@ -1421,8 +1488,8 @@ async function diffAgainstRegistry(registryRoot, projectRoot, manifest) {
1421
1488
  continue;
1422
1489
  }
1423
1490
  const category = skill.path.includes("/core/") ? "core" : "community";
1424
- const sourceRel = path9.posix.join(skill.path, "SKILL.md");
1425
- const targetRel = path9.posix.join(".cursor", "skills", category, skill.id, "SKILL.md");
1491
+ const sourceRel = path10.posix.join(skill.path, "SKILL.md");
1492
+ const targetRel = path10.posix.join(".cursor", "skills", category, skill.id, "SKILL.md");
1426
1493
  await pushUnique(sourceRel, targetRel);
1427
1494
  }
1428
1495
  }
@@ -1441,7 +1508,7 @@ function summarizeDiff(entries) {
1441
1508
  }
1442
1509
 
1443
1510
  // src/commands/diff.ts
1444
- var diffCommand = defineCommand3({
1511
+ var diffCommand = defineCommand4({
1445
1512
  meta: {
1446
1513
  name: "diff",
1447
1514
  description: "Compare installed kit artifacts to the registry (respects L3 protected)."
@@ -1490,8 +1557,8 @@ var diffCommand = defineCommand3({
1490
1557
  });
1491
1558
 
1492
1559
  // src/commands/doctor.ts
1493
- import path19 from "path";
1494
- import { defineCommand as defineCommand4 } from "citty";
1560
+ import path20 from "path";
1561
+ import { defineCommand as defineCommand5 } from "citty";
1495
1562
 
1496
1563
  // src/scanner/readiness.ts
1497
1564
  import { createHash as createHash2 } from "crypto";
@@ -1741,11 +1808,11 @@ function createReadinessReport(scan, options) {
1741
1808
 
1742
1809
  // src/scanner/safe-fixes.ts
1743
1810
  import { readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
1744
- import path17 from "path";
1811
+ import path18 from "path";
1745
1812
 
1746
1813
  // src/scanner/detect-repository.ts
1747
1814
  import { readFile as readFile6 } from "fs/promises";
1748
- import path10 from "path";
1815
+ import path11 from "path";
1749
1816
  var CONTEXT_PATHS = [
1750
1817
  ["README.md", "README"],
1751
1818
  ["README", "README"],
@@ -1764,7 +1831,7 @@ var CONTEXT_PATHS = [
1764
1831
  async function existingEvidence(rootDir, candidates) {
1765
1832
  const evidence = await Promise.all(
1766
1833
  candidates.map(
1767
- async ([relativePath, label]) => await fileExists(path10.join(rootDir, relativePath)) ? { source: "file", value: `${relativePath}:${label}` } : void 0
1834
+ async ([relativePath, label]) => await fileExists(path11.join(rootDir, relativePath)) ? { source: "file", value: `${relativePath}:${label}` } : void 0
1768
1835
  )
1769
1836
  );
1770
1837
  return evidence.flatMap((item) => item ? [item] : []);
@@ -1785,7 +1852,7 @@ async function detectContext(rootDir) {
1785
1852
  async function detectPurpose(rootDir, stack) {
1786
1853
  const entries = await listDirectory(rootDir);
1787
1854
  const lowerEntries = entries.map((entry) => entry.toLowerCase());
1788
- const packageJson = await readJson(path10.join(rootDir, "package.json"));
1855
+ const packageJson = await readJson(path11.join(rootDir, "package.json"));
1789
1856
  const categories = [];
1790
1857
  const evidence = [];
1791
1858
  const add = (category, value2) => {
@@ -1825,16 +1892,16 @@ async function detectPurpose(rootDir, stack) {
1825
1892
  }
1826
1893
  async function detectAgentKit(rootDir) {
1827
1894
  const manifestRelativePath = ".cursor/agent-kit.json";
1828
- const manifestPath = path10.join(rootDir, manifestRelativePath);
1895
+ const manifestPath = path11.join(rootDir, manifestRelativePath);
1829
1896
  const installed = await fileExists(manifestPath);
1830
1897
  const manifest = installed ? await readJson(manifestPath) : null;
1831
1898
  return {
1832
1899
  installed,
1833
1900
  manifestPath: installed ? manifestRelativePath : void 0,
1834
1901
  version: manifest?.version,
1835
- hasPlans: await fileExists(path10.join(rootDir, ".cursor/plans")),
1836
- hasHandoff: await fileExists(path10.join(rootDir, ".cursor/HANDOFF.md")),
1837
- hasMemory: await fileExists(path10.join(rootDir, ".cursor/memory"))
1902
+ hasPlans: await fileExists(path11.join(rootDir, ".cursor/plans")),
1903
+ hasHandoff: await fileExists(path11.join(rootDir, ".cursor/HANDOFF.md")),
1904
+ hasMemory: await fileExists(path11.join(rootDir, ".cursor/memory"))
1838
1905
  };
1839
1906
  }
1840
1907
  var REQUIRED_SECRET_PATTERNS = [
@@ -1848,7 +1915,7 @@ var REQUIRED_SECRET_PATTERNS = [
1848
1915
  "*service-account*.json"
1849
1916
  ];
1850
1917
  async function detectSafety(rootDir, trackedFiles) {
1851
- const gitignorePath = path10.join(rootDir, ".gitignore");
1918
+ const gitignorePath = path11.join(rootDir, ".gitignore");
1852
1919
  const hasGitignore = await fileExists(gitignorePath);
1853
1920
  const gitignore = hasGitignore ? await readFile6(gitignorePath, "utf8") : "";
1854
1921
  const lines = gitignore.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
@@ -1859,7 +1926,7 @@ async function detectSafety(rootDir, trackedFiles) {
1859
1926
  (file) => /(^|\/)(\.env(\..+)?|.*\.(key|pem|p12|pfx)|.*credentials.*\.json)$/i.test(file)
1860
1927
  );
1861
1928
  const hookPaths = [".husky", ".git/hooks/pre-commit", "git-hooks/pre-commit"];
1862
- const hasHooks = (await Promise.all(hookPaths.map((item) => fileExists(path10.join(rootDir, item))))).some(Boolean);
1929
+ const hasHooks = (await Promise.all(hookPaths.map((item) => fileExists(path11.join(rootDir, item))))).some(Boolean);
1863
1930
  const guardCandidates = [
1864
1931
  ".husky/pre-commit",
1865
1932
  ".husky/pre-push",
@@ -1868,7 +1935,7 @@ async function detectSafety(rootDir, trackedFiles) {
1868
1935
  ];
1869
1936
  const guardContents = await Promise.all(
1870
1937
  guardCandidates.map(
1871
- async (item) => await fileExists(path10.join(rootDir, item)) ? readFile6(path10.join(rootDir, item), "utf8") : ""
1938
+ async (item) => await fileExists(path11.join(rootDir, item)) ? readFile6(path11.join(rootDir, item), "utf8") : ""
1872
1939
  )
1873
1940
  );
1874
1941
  return {
@@ -1886,11 +1953,11 @@ async function detectSafety(rootDir, trackedFiles) {
1886
1953
  }
1887
1954
 
1888
1955
  // src/scanner/scan.ts
1889
- import path16 from "path";
1956
+ import path17 from "path";
1890
1957
 
1891
1958
  // src/scanner/detect-git.ts
1892
1959
  import { execFile as execFile2 } from "child_process";
1893
- import path11 from "path";
1960
+ import path12 from "path";
1894
1961
  import { promisify as promisify2 } from "util";
1895
1962
  var exec = promisify2(execFile2);
1896
1963
  function remoteHostname(remoteUrl) {
@@ -1914,7 +1981,7 @@ function sanitizeRemoteUrl(remoteUrl) {
1914
1981
  }
1915
1982
  async function detectProvider(rootDir, remoteUrl) {
1916
1983
  const configuration = await readJson(
1917
- path11.join(rootDir, ".cursor", "agent-kit.config.json")
1984
+ path12.join(rootDir, ".cursor", "agent-kit.config.json")
1918
1985
  );
1919
1986
  const configuredProvider = configuration?.git?.provider;
1920
1987
  if (configuredProvider) {
@@ -1971,7 +2038,7 @@ async function detectProvider(rootDir, remoteUrl) {
1971
2038
  evidence: remoteEvidence
1972
2039
  };
1973
2040
  }
1974
- if (await fileExists(path11.join(rootDir, ".gitlab-ci.yml"))) {
2041
+ if (await fileExists(path12.join(rootDir, ".gitlab-ci.yml"))) {
1975
2042
  return {
1976
2043
  provider: "gitlab",
1977
2044
  providerKind: "gitlab-self-hosted",
@@ -2060,11 +2127,11 @@ async function detectGit(rootDir) {
2060
2127
  }
2061
2128
 
2062
2129
  // src/scanner/detect-ide.ts
2063
- import path12 from "path";
2130
+ import path13 from "path";
2064
2131
  async function detectIde(rootDir) {
2065
- const hasCursor = await fileExists(path12.join(rootDir, ".cursor"));
2066
- const hasVSCode = await fileExists(path12.join(rootDir, ".vscode"));
2067
- const hasWindsurf = await fileExists(path12.join(rootDir, ".windsurfrules"));
2132
+ const hasCursor = await fileExists(path13.join(rootDir, ".cursor"));
2133
+ const hasVSCode = await fileExists(path13.join(rootDir, ".vscode"));
2134
+ const hasWindsurf = await fileExists(path13.join(rootDir, ".windsurfrules"));
2068
2135
  if (hasCursor) return { ide: "cursor", plan: "cursor-pro" };
2069
2136
  if (hasVSCode) return { ide: "vscode", plan: "vscode-pro" };
2070
2137
  if (hasWindsurf) return { ide: "windsurf", plan: "windsurf" };
@@ -2072,7 +2139,7 @@ async function detectIde(rootDir) {
2072
2139
  }
2073
2140
 
2074
2141
  // src/scanner/detect-infra.ts
2075
- import path13 from "path";
2142
+ import path14 from "path";
2076
2143
 
2077
2144
  // src/types.ts
2078
2145
  var CI_PLATFORM_FILES = {
@@ -2101,12 +2168,12 @@ var PM_TOOL_LABELS = {
2101
2168
 
2102
2169
  // src/scanner/detect-infra.ts
2103
2170
  async function detectInfra(rootDir) {
2104
- const docker = await fileExists(path13.join(rootDir, "Dockerfile")) || await fileExists(path13.join(rootDir, "docker-compose.yml")) || await fileExists(path13.join(rootDir, "docker-compose.yaml"));
2105
- const kubernetes = await fileExists(path13.join(rootDir, "k8s")) || await fileExists(path13.join(rootDir, "kubernetes"));
2171
+ const docker = await fileExists(path14.join(rootDir, "Dockerfile")) || await fileExists(path14.join(rootDir, "docker-compose.yml")) || await fileExists(path14.join(rootDir, "docker-compose.yaml"));
2172
+ const kubernetes = await fileExists(path14.join(rootDir, "k8s")) || await fileExists(path14.join(rootDir, "kubernetes"));
2106
2173
  let ci = "none";
2107
2174
  const ciFiles = [];
2108
2175
  for (const [platform, filePath] of Object.entries(CI_PLATFORM_FILES)) {
2109
- if (await fileExists(path13.join(rootDir, filePath))) {
2176
+ if (await fileExists(path14.join(rootDir, filePath))) {
2110
2177
  if (ci === "none") ci = platform;
2111
2178
  ciFiles.push(filePath);
2112
2179
  }
@@ -2131,12 +2198,12 @@ async function detectInfra(rootDir) {
2131
2198
  ];
2132
2199
  const infrastructureFiles = (await Promise.all(
2133
2200
  infrastructureCandidates.map(
2134
- async (file) => await fileExists(path13.join(rootDir, file)) ? file : void 0
2201
+ async (file) => await fileExists(path14.join(rootDir, file)) ? file : void 0
2135
2202
  )
2136
2203
  )).filter((file) => file !== void 0);
2137
2204
  const deploymentFiles = (await Promise.all(
2138
2205
  deploymentCandidates.map(
2139
- async (file) => await fileExists(path13.join(rootDir, file)) ? file : void 0
2206
+ async (file) => await fileExists(path14.join(rootDir, file)) ? file : void 0
2140
2207
  )
2141
2208
  )).filter((file) => file !== void 0);
2142
2209
  return { docker, kubernetes, ci, ciFiles, infrastructureFiles, deploymentFiles };
@@ -2144,12 +2211,12 @@ async function detectInfra(rootDir) {
2144
2211
 
2145
2212
  // src/scanner/detect-services.ts
2146
2213
  import { readFile as readFile7 } from "fs/promises";
2147
- import path14 from "path";
2214
+ import path15 from "path";
2148
2215
  async function detectProjectManagement(rootDir) {
2149
2216
  const tools = [];
2150
2217
  const mcpConfigPaths = [
2151
- path14.join(rootDir, ".cursor", "mcp.json"),
2152
- path14.join(rootDir, "mcp.json")
2218
+ path15.join(rootDir, ".cursor", "mcp.json"),
2219
+ path15.join(rootDir, "mcp.json")
2153
2220
  ];
2154
2221
  for (const configPath of mcpConfigPaths) {
2155
2222
  if (!await fileExists(configPath)) continue;
@@ -2165,20 +2232,20 @@ async function detectProjectManagement(rootDir) {
2165
2232
  } catch {
2166
2233
  }
2167
2234
  }
2168
- if (await fileExists(path14.join(rootDir, ".github", "ISSUE_TEMPLATE"))) {
2235
+ if (await fileExists(path15.join(rootDir, ".github", "ISSUE_TEMPLATE"))) {
2169
2236
  tools.push("github-issues");
2170
2237
  }
2171
- if (await fileExists(path14.join(rootDir, ".github", "projects"))) {
2238
+ if (await fileExists(path15.join(rootDir, ".github", "projects"))) {
2172
2239
  tools.push("github-projects");
2173
2240
  }
2174
2241
  return [...new Set(tools)];
2175
2242
  }
2176
2243
  async function detectServices(rootDir) {
2177
- const hasPrisma = await fileExists(path14.join(rootDir, "prisma/schema.prisma"));
2178
- const hasSequelize = await fileExists(path14.join(rootDir, "sequelize"));
2179
- const hasDrizzle = await fileExists(path14.join(rootDir, "drizzle.config.ts"));
2180
- const hasKnex = await fileExists(path14.join(rootDir, "knexfile.ts"));
2181
- const hasTypeorm = await fileExists(path14.join(rootDir, "ormconfig.json"));
2244
+ const hasPrisma = await fileExists(path15.join(rootDir, "prisma/schema.prisma"));
2245
+ const hasSequelize = await fileExists(path15.join(rootDir, "sequelize"));
2246
+ const hasDrizzle = await fileExists(path15.join(rootDir, "drizzle.config.ts"));
2247
+ const hasKnex = await fileExists(path15.join(rootDir, "knexfile.ts"));
2248
+ const hasTypeorm = await fileExists(path15.join(rootDir, "ormconfig.json"));
2182
2249
  const database = hasPrisma || hasSequelize || hasDrizzle || hasKnex || hasTypeorm ? "postgresql" : void 0;
2183
2250
  const orm = hasPrisma ? "prisma" : hasDrizzle ? "drizzle" : hasSequelize ? "sequelize" : hasKnex ? "knex" : hasTypeorm ? "typeorm" : void 0;
2184
2251
  const projectManagement = await detectProjectManagement(rootDir);
@@ -2190,7 +2257,7 @@ async function detectServices(rootDir) {
2190
2257
  }
2191
2258
 
2192
2259
  // src/scanner/detect-stack.ts
2193
- import path15 from "path";
2260
+ import path16 from "path";
2194
2261
  var PROJECT_MARKERS = [
2195
2262
  "package.json",
2196
2263
  "requirements.txt",
@@ -2219,7 +2286,7 @@ async function detectPackageManager(rootDir, packageJson) {
2219
2286
  };
2220
2287
  }
2221
2288
  for (const [lockfile, packageManager] of LOCKFILES) {
2222
- if (await fileExists(path15.join(rootDir, lockfile))) {
2289
+ if (await fileExists(path16.join(rootDir, lockfile))) {
2223
2290
  return {
2224
2291
  packageManager,
2225
2292
  evidence: [{ source: "file", value: lockfile }]
@@ -2236,27 +2303,27 @@ function commandsForScripts(scripts, packageManager) {
2236
2303
  return { testCommands, validationCommands };
2237
2304
  }
2238
2305
  async function detectStack(rootDir) {
2239
- const hasAnyProjectMarker = (await Promise.all(PROJECT_MARKERS.map((item) => fileExists(path15.join(rootDir, item))))).some(Boolean);
2240
- const hasPackageJson = await fileExists(path15.join(rootDir, "package.json"));
2306
+ const hasAnyProjectMarker = (await Promise.all(PROJECT_MARKERS.map((item) => fileExists(path16.join(rootDir, item))))).some(Boolean);
2307
+ const hasPackageJson = await fileExists(path16.join(rootDir, "package.json"));
2241
2308
  if (hasPackageJson) {
2242
- const packageJson = await readJson(path15.join(rootDir, "package.json")) ?? {};
2309
+ const packageJson = await readJson(path16.join(rootDir, "package.json")) ?? {};
2243
2310
  const scripts = packageJson.scripts ?? {};
2244
2311
  const packageManager = await detectPackageManager(rootDir, packageJson);
2245
2312
  const commands = commandsForScripts(scripts, packageManager.packageManager);
2246
- const hasNextConfig = await fileExists(path15.join(rootDir, "next.config.js")) || await fileExists(path15.join(rootDir, "next.config.mjs")) || await fileExists(path15.join(rootDir, "next.config.ts"));
2247
- const hasNestConfig = await fileExists(path15.join(rootDir, "nest-cli.json"));
2313
+ const hasNextConfig = await fileExists(path16.join(rootDir, "next.config.js")) || await fileExists(path16.join(rootDir, "next.config.mjs")) || await fileExists(path16.join(rootDir, "next.config.ts"));
2314
+ const hasNestConfig = await fileExists(path16.join(rootDir, "nest-cli.json"));
2248
2315
  return {
2249
2316
  language: "node",
2250
2317
  framework: hasNextConfig ? "nextjs" : hasNestConfig ? "nestjs" : "node",
2251
2318
  packageManager: packageManager.packageManager,
2252
2319
  packageManagerEvidence: packageManager.evidence,
2253
2320
  scripts,
2254
- workspaces: packageJson.workspaces !== void 0 || await fileExists(path15.join(rootDir, "pnpm-workspace.yaml")),
2321
+ workspaces: packageJson.workspaces !== void 0 || await fileExists(path16.join(rootDir, "pnpm-workspace.yaml")),
2255
2322
  ...commands,
2256
2323
  hasProjectFiles: hasAnyProjectMarker
2257
2324
  };
2258
2325
  }
2259
- if (await fileExists(path15.join(rootDir, "pyproject.toml"))) {
2326
+ if (await fileExists(path16.join(rootDir, "pyproject.toml"))) {
2260
2327
  return {
2261
2328
  language: "python",
2262
2329
  framework: "python",
@@ -2266,7 +2333,7 @@ async function detectStack(rootDir) {
2266
2333
  hasProjectFiles: hasAnyProjectMarker
2267
2334
  };
2268
2335
  }
2269
- if (await fileExists(path15.join(rootDir, "go.mod"))) {
2336
+ if (await fileExists(path16.join(rootDir, "go.mod"))) {
2270
2337
  return {
2271
2338
  language: "go",
2272
2339
  framework: "go",
@@ -2276,7 +2343,7 @@ async function detectStack(rootDir) {
2276
2343
  hasProjectFiles: hasAnyProjectMarker
2277
2344
  };
2278
2345
  }
2279
- if (await fileExists(path15.join(rootDir, "Cargo.toml"))) {
2346
+ if (await fileExists(path16.join(rootDir, "Cargo.toml"))) {
2280
2347
  return {
2281
2348
  language: "rust",
2282
2349
  framework: "rust",
@@ -2286,7 +2353,7 @@ async function detectStack(rootDir) {
2286
2353
  hasProjectFiles: hasAnyProjectMarker
2287
2354
  };
2288
2355
  }
2289
- if (await fileExists(path15.join(rootDir, "composer.json"))) {
2356
+ if (await fileExists(path16.join(rootDir, "composer.json"))) {
2290
2357
  return {
2291
2358
  language: "php",
2292
2359
  framework: "php",
@@ -2319,7 +2386,7 @@ function isGreenfieldByEntries(entries) {
2319
2386
  return meaningful.length === 0;
2320
2387
  }
2321
2388
  async function runScanner(rootDir) {
2322
- const normalizedRoot = path16.resolve(rootDir);
2389
+ const normalizedRoot = path17.resolve(rootDir);
2323
2390
  const entries = await listDirectory(normalizedRoot);
2324
2391
  const stack = await detectStack(normalizedRoot);
2325
2392
  const purpose = await detectPurpose(normalizedRoot, stack);
@@ -2520,7 +2587,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
2520
2587
  });
2521
2588
  const changes = [];
2522
2589
  for (const relativePath of ESSENTIAL_DIRECTORIES) {
2523
- const absolutePath = path17.join(beforeScan.rootDir, relativePath);
2590
+ const absolutePath = path18.join(beforeScan.rootDir, relativePath);
2524
2591
  const exists = await fileExists(absolutePath);
2525
2592
  if (!exists && !dryRun) await ensureDir(absolutePath);
2526
2593
  recordChange(
@@ -2533,7 +2600,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
2533
2600
  );
2534
2601
  }
2535
2602
  const gitignoreRelativePath = ".gitignore";
2536
- const gitignorePath = path17.join(beforeScan.rootDir, gitignoreRelativePath);
2603
+ const gitignorePath = path18.join(beforeScan.rootDir, gitignoreRelativePath);
2537
2604
  const existingGitignore = await fileExists(gitignorePath) ? await readFile8(gitignorePath, "utf8") : "";
2538
2605
  const mergedGitignore = mergeSecretIgnores(existingGitignore);
2539
2606
  const gitignoreChanged = mergedGitignore !== existingGitignore;
@@ -2549,7 +2616,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
2549
2616
  gitignoreChanged ? "required secret patterns are missing" : "required patterns are present"
2550
2617
  )
2551
2618
  );
2552
- const profilePath = path17.join(beforeScan.rootDir, PROFILE_RELATIVE_PATH);
2619
+ const profilePath = path18.join(beforeScan.rootDir, PROFILE_RELATIVE_PATH);
2553
2620
  const existingProfile = await readJson(profilePath) ?? {};
2554
2621
  const desiredProfile = createProfile(beforeScan, before, generatedAt);
2555
2622
  const mergedProfile = mergeMissing(existingProfile, desiredProfile);
@@ -2571,7 +2638,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
2571
2638
  generatorVersion: options.generatorVersion,
2572
2639
  generatedAt
2573
2640
  });
2574
- const contextConfigPath = path17.join(beforeScan.rootDir, CONTEXT_CONFIG_RELATIVE_PATH);
2641
+ const contextConfigPath = path18.join(beforeScan.rootDir, CONTEXT_CONFIG_RELATIVE_PATH);
2575
2642
  const existingContextConfig = await readJson(contextConfigPath) ?? {};
2576
2643
  const onboarding = reconcileOnboardingState(evidenceReport, existingContextConfig, generatedAt);
2577
2644
  const defaults = preferenceDefaults(onboarding, existingContextConfig.onboarded);
@@ -2600,17 +2667,17 @@ async function executeSafeReadinessFixes(rootDir, options) {
2600
2667
  }
2601
2668
 
2602
2669
  // src/scanner/snapshot.ts
2603
- import path18 from "path";
2670
+ import path19 from "path";
2604
2671
  var READINESS_SNAPSHOT_RELATIVE_PATH = ".cursor/context/readiness.json";
2605
2672
  async function writeReadinessSnapshot(rootDir, report) {
2606
- const snapshotPath = path18.join(rootDir, READINESS_SNAPSHOT_RELATIVE_PATH);
2673
+ const snapshotPath = path19.join(rootDir, READINESS_SNAPSHOT_RELATIVE_PATH);
2607
2674
  await writeJson(snapshotPath, report);
2608
2675
  return snapshotPath;
2609
2676
  }
2610
2677
 
2611
2678
  // src/commands/doctor.ts
2612
2679
  async function runDoctor(cwd, options = {}) {
2613
- const rootDir = path19.resolve(cwd);
2680
+ const rootDir = path20.resolve(cwd);
2614
2681
  if (options.fixSafe) {
2615
2682
  const execution = await executeSafeReadinessFixes(rootDir, {
2616
2683
  generatorVersion: KIT_VERSION,
@@ -2641,7 +2708,7 @@ function printDoctorSummary(result) {
2641
2708
  nextAction ? `Next: ${nextAction.recommendation}` : "Next: repository readiness checks are complete"
2642
2709
  );
2643
2710
  }
2644
- var doctorCommand = defineCommand4({
2711
+ var doctorCommand = defineCommand5({
2645
2712
  meta: {
2646
2713
  name: "doctor",
2647
2714
  description: "Diagnose repository readiness and optionally apply safe local fixes."
@@ -2673,10 +2740,10 @@ var doctorCommand = defineCommand4({
2673
2740
  });
2674
2741
 
2675
2742
  // src/commands/handoff.ts
2676
- import { spawn } from "child_process";
2743
+ import { spawn as spawn2 } from "child_process";
2677
2744
  import { readFile as readFile9, readdir as readdir2, writeFile as writeFile4 } from "fs/promises";
2678
- import path20 from "path";
2679
- import { defineCommand as defineCommand5 } from "citty";
2745
+ import path21 from "path";
2746
+ import { defineCommand as defineCommand6 } from "citty";
2680
2747
  function parsePlanFrontmatter(raw) {
2681
2748
  const match = raw.match(/^---\n([\s\S]*?)\n---/);
2682
2749
  if (!match?.[1]) return null;
@@ -2695,19 +2762,19 @@ async function findActivePlan(plansDir) {
2695
2762
  if (!await fileExists(plansDir)) return null;
2696
2763
  const files = (await readdir2(plansDir)).filter((f) => f.endsWith(".plan.md")).sort().reverse();
2697
2764
  for (const file of files) {
2698
- const raw = await readFile9(path20.join(plansDir, file), "utf8");
2765
+ const raw = await readFile9(path21.join(plansDir, file), "utf8");
2699
2766
  const fm = parsePlanFrontmatter(raw);
2700
2767
  if (fm?.todos?.some((t) => t.status !== "completed" && t.status !== "cancelled")) {
2701
2768
  return { file, raw };
2702
2769
  }
2703
2770
  }
2704
- return files[0] ? { file: files[0], raw: await readFile9(path20.join(plansDir, files[0]), "utf8") } : null;
2771
+ return files[0] ? { file: files[0], raw: await readFile9(path21.join(plansDir, files[0]), "utf8") } : null;
2705
2772
  }
2706
2773
  function now() {
2707
2774
  return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 16);
2708
2775
  }
2709
2776
  async function loadProfile(rootDir) {
2710
- const configPath = path20.join(rootDir, ".cursor", "agent-kit.config.json");
2777
+ const configPath = path21.join(rootDir, ".cursor", "agent-kit.config.json");
2711
2778
  try {
2712
2779
  return await readJson(configPath);
2713
2780
  } catch {
@@ -2785,7 +2852,7 @@ function printV3Guidance() {
2785
2852
  }
2786
2853
  function runCursorHandoff(scriptPath, cwd) {
2787
2854
  return new Promise((resolve, reject) => {
2788
- const child = spawn("sh", [scriptPath, "handoff"], {
2855
+ const child = spawn2("sh", [scriptPath, "handoff"], {
2789
2856
  cwd,
2790
2857
  stdio: "inherit"
2791
2858
  });
@@ -2793,7 +2860,7 @@ function runCursorHandoff(scriptPath, cwd) {
2793
2860
  child.on("close", (code) => resolve(code ?? 1));
2794
2861
  });
2795
2862
  }
2796
- var handoffCommand = defineCommand5({
2863
+ var handoffCommand = defineCommand6({
2797
2864
  meta: {
2798
2865
  name: "handoff",
2799
2866
  description: "Write .cursor/HANDOFF.md from the active Cursor plan, or run ./cursor-handoff handoff when no plan exists."
@@ -2807,13 +2874,13 @@ var handoffCommand = defineCommand5({
2807
2874
  },
2808
2875
  async run({ args }) {
2809
2876
  const profile = await loadProfile(args.cwd);
2810
- const plansDir = path20.join(args.cwd, ".cursor", "plans");
2811
- const handoffPath = path20.join(args.cwd, ".cursor", "HANDOFF.md");
2877
+ const plansDir = path21.join(args.cwd, ".cursor", "plans");
2878
+ const handoffPath = path21.join(args.cwd, ".cursor", "HANDOFF.md");
2812
2879
  const plan = await findActivePlan(plansDir);
2813
2880
  if (plan) {
2814
2881
  const fm = parsePlanFrontmatter(plan.raw);
2815
2882
  if (fm) {
2816
- await ensureDir(path20.join(args.cwd, ".cursor"));
2883
+ await ensureDir(path21.join(args.cwd, ".cursor"));
2817
2884
  const content = buildHandoff(plan.file, fm, profile);
2818
2885
  await writeFile4(handoffPath, content, "utf8");
2819
2886
  logger.success("HANDOFF.md updated: .cursor/HANDOFF.md");
@@ -2833,7 +2900,7 @@ var handoffCommand = defineCommand5({
2833
2900
  }
2834
2901
  logger.warn(`Plan ${plan.file} without valid frontmatter; trying legacy flow.`);
2835
2902
  }
2836
- const scriptPath = path20.join(args.cwd, "cursor-handoff");
2903
+ const scriptPath = path21.join(args.cwd, "cursor-handoff");
2837
2904
  if (!await fileExists(scriptPath)) {
2838
2905
  printV3Guidance();
2839
2906
  return;
@@ -2859,15 +2926,15 @@ var handoffCommand = defineCommand5({
2859
2926
 
2860
2927
  // src/commands/init.ts
2861
2928
  import { intro, outro } from "@clack/prompts";
2862
- import { defineCommand as defineCommand7 } from "citty";
2929
+ import { defineCommand as defineCommand8 } from "citty";
2863
2930
 
2864
2931
  // src/commands/install.ts
2865
- import path23 from "path";
2866
- import { defineCommand as defineCommand6 } from "citty";
2932
+ import path24 from "path";
2933
+ import { defineCommand as defineCommand7 } from "citty";
2867
2934
 
2868
2935
  // src/generator/personalization.ts
2869
2936
  import { readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
2870
- import path21 from "path";
2937
+ import path22 from "path";
2871
2938
  var PERSONALIZATION_CONTRACT_VERSION = 1;
2872
2939
  var CONTEXT_PATH = ".cursor/project-context.md";
2873
2940
  var AGENTS_PATH = "AGENTS.md";
@@ -3018,7 +3085,7 @@ function renderProjectContext(profile) {
3018
3085
  `;
3019
3086
  }
3020
3087
  async function createOwnedFile(rootDir, relativePath, content, evidence) {
3021
- const target = path21.join(rootDir, relativePath);
3088
+ const target = path22.join(rootDir, relativePath);
3022
3089
  if (await fileExists(target)) {
3023
3090
  return {
3024
3091
  kind: "file",
@@ -3028,7 +3095,7 @@ async function createOwnedFile(rootDir, relativePath, content, evidence) {
3028
3095
  evidence
3029
3096
  };
3030
3097
  }
3031
- await ensureDir(path21.dirname(target));
3098
+ await ensureDir(path22.dirname(target));
3032
3099
  await writeFile5(target, content, "utf8");
3033
3100
  return {
3034
3101
  kind: "file",
@@ -3045,7 +3112,7 @@ async function packTargets(registryRoot, packId) {
3045
3112
  async function existingTargets(projectRoot, targets) {
3046
3113
  const checks = await Promise.all(
3047
3114
  targets.map(
3048
- async (target) => await fileExists(path21.join(projectRoot, target)) ? target : null
3115
+ async (target) => await fileExists(path22.join(projectRoot, target)) ? target : null
3049
3116
  )
3050
3117
  );
3051
3118
  return checks.filter((target) => target !== null);
@@ -3067,14 +3134,14 @@ async function applyPersonalization(input) {
3067
3134
  componentResults.push({ ...item, status: "unavailable" });
3068
3135
  continue;
3069
3136
  }
3070
- const target = path21.posix.join(
3137
+ const target = path22.posix.join(
3071
3138
  ".cursor",
3072
3139
  "skills",
3073
3140
  skill.path.includes("/core/") ? "core" : "community",
3074
3141
  skill.id,
3075
3142
  "SKILL.md"
3076
3143
  );
3077
- if (await fileExists(path21.join(input.rootDir, target))) {
3144
+ if (await fileExists(path22.join(input.rootDir, target))) {
3078
3145
  componentResults.push({ ...item, status: "skipped-customized", path: target });
3079
3146
  protectedPaths.add(target);
3080
3147
  continue;
@@ -3129,7 +3196,7 @@ async function applyPersonalization(input) {
3129
3196
  items: [...fileResults, ...componentResults],
3130
3197
  protectedPaths: [...protectedPaths].sort()
3131
3198
  };
3132
- await writeJson(path21.join(input.rootDir, RESULT_PATH), result);
3199
+ await writeJson(path22.join(input.rootDir, RESULT_PATH), result);
3133
3200
  return {
3134
3201
  result,
3135
3202
  manifest: {
@@ -3147,7 +3214,7 @@ async function applyPersonalization(input) {
3147
3214
  };
3148
3215
  }
3149
3216
  async function readRepositoryProfile(rootDir) {
3150
- const target = path21.join(rootDir, ".cursor/agent-kit.config.json");
3217
+ const target = path22.join(rootDir, ".cursor/agent-kit.config.json");
3151
3218
  if (!await fileExists(target)) return null;
3152
3219
  return JSON.parse(await readFile10(target, "utf8"));
3153
3220
  }
@@ -3155,16 +3222,16 @@ async function readRepositoryProfile(rootDir) {
3155
3222
  // src/lifecycle/onboard-migration.ts
3156
3223
  import { createHash as createHash3 } from "crypto";
3157
3224
  import { readFile as readFile11, unlink } from "fs/promises";
3158
- import path22 from "path";
3225
+ import path23 from "path";
3159
3226
  var LEGACY_ONBOARD_PATH = ".cursor/commands/onboard.md";
3160
3227
  var NAMESPACED_ONBOARD_PATH = ".cursor/commands/agent-kit-onboard.md";
3161
3228
  var MANAGED_LEGACY_HASHES = /* @__PURE__ */ new Set([
3162
3229
  "b274a68941813f19b185893cb7c5561dff027f53270890029992f208e24992fe"
3163
3230
  ]);
3164
3231
  async function migrateLegacyOnboardCommand(projectRoot, managedHashes = MANAGED_LEGACY_HASHES) {
3165
- const legacyPath = path22.join(projectRoot, LEGACY_ONBOARD_PATH);
3232
+ const legacyPath = path23.join(projectRoot, LEGACY_ONBOARD_PATH);
3166
3233
  if (!await fileExists(legacyPath)) return "absent";
3167
- const namespacedPath = path22.join(projectRoot, NAMESPACED_ONBOARD_PATH);
3234
+ const namespacedPath = path23.join(projectRoot, NAMESPACED_ONBOARD_PATH);
3168
3235
  if (!await fileExists(namespacedPath)) return "preserved-customized";
3169
3236
  const content = await readFile11(legacyPath);
3170
3237
  const hash = createHash3("sha256").update(content).digest("hex");
@@ -3235,7 +3302,7 @@ function printReadinessNarrative(result) {
3235
3302
  );
3236
3303
  }
3237
3304
  async function performInstall(options) {
3238
- const projectRoot = path23.resolve(options.cwd);
3305
+ const projectRoot = path24.resolve(options.cwd);
3239
3306
  const packs = parsePackList(options.pack);
3240
3307
  const existing = await loadAgentKitManifest(projectRoot);
3241
3308
  const registry = await resolveRegistryFromCli({
@@ -3289,7 +3356,7 @@ async function performInstall(options) {
3289
3356
  safeChanges: readinessExecution.changes
3290
3357
  };
3291
3358
  }
3292
- var installCommand = defineCommand6({
3359
+ var installCommand = defineCommand7({
3293
3360
  meta: {
3294
3361
  name: "install",
3295
3362
  description: "Bootstrap L0 (+ optional packs) from the registry and write agent-kit.json."
@@ -3311,7 +3378,7 @@ var installCommand = defineCommand6({
3311
3378
  ...REGISTRY_CLI_ARGS
3312
3379
  },
3313
3380
  async run({ args }) {
3314
- const projectRoot = path23.resolve(args.cwd);
3381
+ const projectRoot = path24.resolve(args.cwd);
3315
3382
  logger.info(`Installing into: ${projectRoot}`);
3316
3383
  const packs = parsePackList(args.pack);
3317
3384
  for (const id of packs) {
@@ -3339,7 +3406,7 @@ var installCommand = defineCommand6({
3339
3406
  async function runInitCompatibility(cwd, installer = performInstall) {
3340
3407
  return installer({ cwd });
3341
3408
  }
3342
- var initCommand = defineCommand7({
3409
+ var initCommand = defineCommand8({
3343
3410
  meta: {
3344
3411
  name: "init",
3345
3412
  description: "Guided compatibility entry point for install and repository readiness."
@@ -3364,11 +3431,11 @@ var initCommand = defineCommand7({
3364
3431
  });
3365
3432
 
3366
3433
  // src/commands/run-plan.ts
3367
- import path28 from "path";
3368
- import { defineCommand as defineCommand8 } from "citty";
3434
+ import path29 from "path";
3435
+ import { defineCommand as defineCommand9 } from "citty";
3369
3436
 
3370
3437
  // src/plan-loop/backends.ts
3371
- import { execFileSync, spawn as spawn2 } from "child_process";
3438
+ import { execFileSync, spawn as spawn3 } from "child_process";
3372
3439
  import { createWriteStream } from "fs";
3373
3440
  async function which(bin) {
3374
3441
  try {
@@ -3381,7 +3448,7 @@ async function which(bin) {
3381
3448
  function spawnLogged(command, args, logPath) {
3382
3449
  return new Promise((resolve, reject) => {
3383
3450
  const out = createWriteStream(logPath, { flags: "w" });
3384
- const child = spawn2(command, args, {
3451
+ const child = spawn3(command, args, {
3385
3452
  stdio: ["ignore", "pipe", "pipe"]
3386
3453
  });
3387
3454
  const onData = (chunk) => {
@@ -3450,13 +3517,13 @@ function listBackendIds() {
3450
3517
 
3451
3518
  // src/plan-loop/run-loop.ts
3452
3519
  import { mkdir as mkdir4, readFile as readFile14, rm, unlink as unlink2 } from "fs/promises";
3453
- import path27 from "path";
3520
+ import path28 from "path";
3454
3521
 
3455
3522
  // src/plan-loop/external-review.ts
3456
- import { spawn as spawn3 } from "child_process";
3457
- import path24 from "path";
3458
- var CANONICAL_REL = path24.join(".cursor", "scripts", "plan-external-review.sh");
3459
- var FALLBACK_REL = path24.join("scripts", "plan-external-review.sh");
3523
+ import { spawn as spawn4 } from "child_process";
3524
+ import path25 from "path";
3525
+ var CANONICAL_REL = path25.join(".cursor", "scripts", "plan-external-review.sh");
3526
+ var FALLBACK_REL = path25.join("scripts", "plan-external-review.sh");
3460
3527
  function isPlanExhaustedReason(reason) {
3461
3528
  const r = reason.trim().toLowerCase();
3462
3529
  if (!r) return false;
@@ -3474,12 +3541,12 @@ function shouldArmExternalPlanReview(input) {
3474
3541
  return false;
3475
3542
  }
3476
3543
  async function armExternalPlanReview(root, options = {}) {
3477
- const spawnFn = options.spawnFn ?? spawn3;
3544
+ const spawnFn = options.spawnFn ?? spawn4;
3478
3545
  const existsFn = options.existsFn ?? fileExists;
3479
3546
  const log = options.log ?? ((line) => console.log(line));
3480
3547
  const force = options.force === true;
3481
- const canonicalPath = path24.join(root, CANONICAL_REL);
3482
- const fallbackPath = path24.join(root, FALLBACK_REL);
3548
+ const canonicalPath = path25.join(root, CANONICAL_REL);
3549
+ const fallbackPath = path25.join(root, FALLBACK_REL);
3483
3550
  let scriptPath = null;
3484
3551
  let scriptRel = CANONICAL_REL;
3485
3552
  if (await existsFn(canonicalPath)) {
@@ -3533,7 +3600,7 @@ async function armExternalPlanReview(root, options = {}) {
3533
3600
 
3534
3601
  // src/plan-loop/plan-state.ts
3535
3602
  import { readFile as readFile12, readdir as readdir3 } from "fs/promises";
3536
- import path25 from "path";
3603
+ import path26 from "path";
3537
3604
  function countPendingTodos(raw) {
3538
3605
  const lines = raw.split(/\r?\n/);
3539
3606
  let inFront = 0;
@@ -3561,7 +3628,7 @@ function countPendingTodos(raw) {
3561
3628
  async function findActivePlanFile(plansDir) {
3562
3629
  if (!await fileExists(plansDir)) return null;
3563
3630
  const files = (await readdir3(plansDir)).filter((f) => f.endsWith(".plan.md")).sort();
3564
- return files[0] ? path25.join(plansDir, files[0]) : null;
3631
+ return files[0] ? path26.join(plansDir, files[0]) : null;
3565
3632
  }
3566
3633
  async function readPlan(planPath) {
3567
3634
  return readFile12(planPath, "utf8");
@@ -3628,7 +3695,7 @@ function formatSentinelLine(sentinel) {
3628
3695
  }
3629
3696
 
3630
3697
  // src/plan-loop/skin-banners.ts
3631
- import path26 from "path";
3698
+ import path27 from "path";
3632
3699
  import {
3633
3700
  blue,
3634
3701
  cyan as cyan2,
@@ -3664,7 +3731,7 @@ function resolveColor(name, fallback) {
3664
3731
  async function resolveCliSkinId(root) {
3665
3732
  try {
3666
3733
  const cfg = await readJson(
3667
- path26.join(root, ".cursor", "context", "config.json")
3734
+ path27.join(root, ".cursor", "context", "config.json")
3668
3735
  );
3669
3736
  const id = cfg?.workspaceSkin?.modes?.[CLI_RUN_PLAN_MODE];
3670
3737
  if (typeof id === "string" && id.trim()) return id.trim();
@@ -3674,7 +3741,7 @@ async function resolveCliSkinId(root) {
3674
3741
  }
3675
3742
  async function loadSkinPack(root, skinId) {
3676
3743
  try {
3677
- const skinPath = path26.join(root, "registry", "skins", "core", skinId, "skin.json");
3744
+ const skinPath = path27.join(root, "registry", "skins", "core", skinId, "skin.json");
3678
3745
  const pack = await readJson(skinPath);
3679
3746
  if (!pack || typeof pack.id !== "string") return null;
3680
3747
  return pack;
@@ -3733,9 +3800,9 @@ function sleep(ms) {
3733
3800
  return new Promise((r) => setTimeout(r, ms));
3734
3801
  }
3735
3802
  async function runPlanLoop(opts) {
3736
- const plansDir = path27.join(opts.root, ".cursor", "plans");
3737
- const stopFile = path27.join(opts.root, ".cursor", "loop.stop");
3738
- const logDir = path27.join(opts.root, ".cursor", "loop-logs");
3803
+ const plansDir = path28.join(opts.root, ".cursor", "plans");
3804
+ const stopFile = path28.join(opts.root, ".cursor", "loop.stop");
3805
+ const logDir = path28.join(opts.root, ".cursor", "loop-logs");
3739
3806
  const planPath = await findActivePlanFile(plansDir);
3740
3807
  if (!planPath) {
3741
3808
  logger.error("No active plan in .cursor/plans/");
@@ -3756,7 +3823,7 @@ async function runPlanLoop(opts) {
3756
3823
  try {
3757
3824
  const skin = await loadCliRunPlanSkin(opts.root);
3758
3825
  const banners = createSkinBannerPrinter(skin);
3759
- console.log(`Active plan: ${path27.basename(planPath)}`);
3826
+ console.log(`Active plan: ${path28.basename(planPath)}`);
3760
3827
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
3761
3828
  console.log(`Backend: ${opts.backend.id}`);
3762
3829
  if (skin) {
@@ -3799,8 +3866,8 @@ async function runPlanLoop(opts) {
3799
3866
  planExhausted = true;
3800
3867
  break;
3801
3868
  }
3802
- const logPath = path27.join(logDir, `tick-${stamp()}.log`);
3803
- const relLog = path27.relative(opts.root, logPath);
3869
+ const logPath = path28.join(logDir, `tick-${stamp()}.log`);
3870
+ const relLog = path28.relative(opts.root, logPath);
3804
3871
  console.log("");
3805
3872
  const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
3806
3873
  if (banners) banners.tickStart(tickLine);
@@ -3876,7 +3943,7 @@ async function runPlanLoop(opts) {
3876
3943
  const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
3877
3944
  if (banners) banners.phaseComplete(finishDetail);
3878
3945
  console.log(
3879
- `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path27.relative(opts.root, logDir)}/`
3946
+ `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path28.relative(opts.root, logDir)}/`
3880
3947
  );
3881
3948
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
3882
3949
  await armExternalPlanReview(opts.root);
@@ -3888,7 +3955,7 @@ async function runPlanLoop(opts) {
3888
3955
  }
3889
3956
 
3890
3957
  // src/commands/run-plan.ts
3891
- var runPlanCommand = defineCommand8({
3958
+ var runPlanCommand = defineCommand9({
3892
3959
  meta: {
3893
3960
  name: "run-plan",
3894
3961
  description: "Headless continuous plan runner: one fresh agent per tick (LOOP_TICK_RESULT contract). Never git-prod."
@@ -3947,7 +4014,7 @@ var runPlanCommand = defineCommand8({
3947
4014
  return;
3948
4015
  }
3949
4016
  const code = await runPlanLoop({
3950
- root: path28.resolve(args.cwd),
4017
+ root: path29.resolve(args.cwd),
3951
4018
  maxTicks,
3952
4019
  sleepSeconds,
3953
4020
  model: args.model ? String(args.model) : void 0,
@@ -3959,8 +4026,8 @@ var runPlanCommand = defineCommand8({
3959
4026
  });
3960
4027
 
3961
4028
  // src/commands/scan.ts
3962
- import { defineCommand as defineCommand9 } from "citty";
3963
- var scanCommand = defineCommand9({
4029
+ import { defineCommand as defineCommand10 } from "citty";
4030
+ var scanCommand = defineCommand10({
3964
4031
  meta: {
3965
4032
  name: "scan",
3966
4033
  description: "Scan the current repository and print detected profile."
@@ -3981,8 +4048,8 @@ var scanCommand = defineCommand9({
3981
4048
  });
3982
4049
 
3983
4050
  // src/commands/status.ts
3984
- import path29 from "path";
3985
- import { defineCommand as defineCommand10 } from "citty";
4051
+ import path30 from "path";
4052
+ import { defineCommand as defineCommand11 } from "citty";
3986
4053
  function profileStatus(profile) {
3987
4054
  if (!profile) return { origin: "none", evidence: [], profile: null };
3988
4055
  if ("detection" in profile && profile.detection && typeof profile.detection === "object") {
@@ -3995,7 +4062,7 @@ function profileStatus(profile) {
3995
4062
  }
3996
4063
  return { origin: "legacy-wizard", evidence: [], profile };
3997
4064
  }
3998
- var statusCommand = defineCommand10({
4065
+ var statusCommand = defineCommand11({
3999
4066
  meta: {
4000
4067
  name: "status",
4001
4068
  description: "Show Agent Kit distribution status (manifest + optional wizard profile)."
@@ -4012,11 +4079,11 @@ var statusCommand = defineCommand10({
4012
4079
  }
4013
4080
  },
4014
4081
  async run({ args }) {
4015
- const rootDir = path29.resolve(args.cwd);
4082
+ const rootDir = path30.resolve(args.cwd);
4016
4083
  const [manifest, rawProfile, scan] = await Promise.all([
4017
4084
  loadAgentKitManifest(rootDir),
4018
4085
  readJson(
4019
- path29.join(rootDir, ".cursor", "agent-kit.config.json")
4086
+ path30.join(rootDir, ".cursor", "agent-kit.config.json")
4020
4087
  ),
4021
4088
  runScanner(rootDir)
4022
4089
  ]);
@@ -4071,8 +4138,8 @@ var statusCommand = defineCommand10({
4071
4138
  });
4072
4139
 
4073
4140
  // src/commands/update.ts
4074
- import { defineCommand as defineCommand11 } from "citty";
4075
- var updateCommand = defineCommand11({
4141
+ import { defineCommand as defineCommand12 } from "citty";
4142
+ var updateCommand = defineCommand12({
4076
4143
  meta: {
4077
4144
  name: "update",
4078
4145
  description: "Re-apply L0/packs/skills from the registry; never overwrites L3 protected paths."
@@ -4117,7 +4184,7 @@ var updateCommand = defineCommand11({
4117
4184
  });
4118
4185
 
4119
4186
  // src/index.ts
4120
- var main = defineCommand12({
4187
+ var main = defineCommand13({
4121
4188
  meta: {
4122
4189
  name: "agent-kit",
4123
4190
  description: "HITL framework for AI-assisted IDEs"
@@ -4133,7 +4200,8 @@ var main = defineCommand12({
4133
4200
  diff: diffCommand,
4134
4201
  contribute: contributeCommand,
4135
4202
  handoff: handoffCommand,
4136
- "run-plan": runPlanCommand
4203
+ "run-plan": runPlanCommand,
4204
+ dashboard: dashboardCommand
4137
4205
  }
4138
4206
  });
4139
4207
  runMain(main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dadado/agent-kit-cli",
3
- "version": "4.6.0",
3
+ "version": "4.7.0",
4
4
  "description": "Agent Kit CLI: HITL framework install and tooling for AI-assisted IDEs (rules, skills, plan/handoff, context).",
5
5
  "type": "module",
6
6
  "bin": {