@dadado/agent-kit-cli 4.6.0 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +201 -133
- 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 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/
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
1425
|
-
const targetRel =
|
|
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 =
|
|
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
|
|
1494
|
-
import { defineCommand as
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
1836
|
-
hasHandoff: await fileExists(
|
|
1837
|
-
hasMemory: await fileExists(
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
2130
|
+
import path13 from "path";
|
|
2064
2131
|
async function detectIde(rootDir) {
|
|
2065
|
-
const hasCursor = await fileExists(
|
|
2066
|
-
const hasVSCode = await fileExists(
|
|
2067
|
-
const hasWindsurf = await fileExists(
|
|
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
|
|
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(
|
|
2105
|
-
const kubernetes = await fileExists(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
2214
|
+
import path15 from "path";
|
|
2148
2215
|
async function detectProjectManagement(rootDir) {
|
|
2149
2216
|
const tools = [];
|
|
2150
2217
|
const mcpConfigPaths = [
|
|
2151
|
-
|
|
2152
|
-
|
|
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(
|
|
2235
|
+
if (await fileExists(path15.join(rootDir, ".github", "ISSUE_TEMPLATE"))) {
|
|
2169
2236
|
tools.push("github-issues");
|
|
2170
2237
|
}
|
|
2171
|
-
if (await fileExists(
|
|
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(
|
|
2178
|
-
const hasSequelize = await fileExists(
|
|
2179
|
-
const hasDrizzle = await fileExists(
|
|
2180
|
-
const hasKnex = await fileExists(
|
|
2181
|
-
const hasTypeorm = await fileExists(
|
|
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
|
|
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(
|
|
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(
|
|
2240
|
-
const hasPackageJson = await fileExists(
|
|
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(
|
|
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(
|
|
2247
|
-
const hasNestConfig = await fileExists(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
2679
|
-
import { defineCommand as
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2811
|
-
const handoffPath =
|
|
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(
|
|
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 =
|
|
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
|
|
2929
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2863
2930
|
|
|
2864
2931
|
// src/commands/install.ts
|
|
2865
|
-
import
|
|
2866
|
-
import { defineCommand as
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
3232
|
+
const legacyPath = path23.join(projectRoot, LEGACY_ONBOARD_PATH);
|
|
3166
3233
|
if (!await fileExists(legacyPath)) return "absent";
|
|
3167
|
-
const namespacedPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
3368
|
-
import { defineCommand as
|
|
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
|
|
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 =
|
|
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
|
|
3520
|
+
import path28 from "path";
|
|
3454
3521
|
|
|
3455
3522
|
// src/plan-loop/external-review.ts
|
|
3456
|
-
import { spawn as
|
|
3457
|
-
import
|
|
3458
|
-
var CANONICAL_REL =
|
|
3459
|
-
var FALLBACK_REL =
|
|
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 ??
|
|
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 =
|
|
3482
|
-
const fallbackPath =
|
|
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
|
|
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] ?
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
3737
|
-
const stopFile =
|
|
3738
|
-
const logDir =
|
|
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: ${
|
|
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 =
|
|
3803
|
-
const relLog =
|
|
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 ${
|
|
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 =
|
|
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:
|
|
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
|
|
3963
|
-
var scanCommand =
|
|
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
|
|
3985
|
-
import { defineCommand as
|
|
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 =
|
|
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 =
|
|
4082
|
+
const rootDir = path30.resolve(args.cwd);
|
|
4016
4083
|
const [manifest, rawProfile, scan] = await Promise.all([
|
|
4017
4084
|
loadAgentKitManifest(rootDir),
|
|
4018
4085
|
readJson(
|
|
4019
|
-
|
|
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
|
|
4075
|
-
var updateCommand =
|
|
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 =
|
|
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