@dadado/agent-kit-cli 5.11.0 → 5.12.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 CHANGED
@@ -10,12 +10,15 @@ import { defineCommand } from "citty";
10
10
  import { copyFile, mkdir as mkdir3, readFile as readFile3 } from "fs/promises";
11
11
  import path4 from "path";
12
12
 
13
+ // src/utils/kit-paths.ts
14
+ var HANDOFF_REL = ".cursor/HANDOFF.md";
15
+
13
16
  // src/manifest/types.ts
14
17
  var MANIFEST_FILENAME = "agent-kit.json";
15
18
  var MANIFEST_RELATIVE_PATH = `.cursor/${MANIFEST_FILENAME}`;
16
19
  var MANIFEST_SCHEMA_VERSION = 1;
17
20
  var DEFAULT_PROTECTED_PATHS = [
18
- ".cursor/HANDOFF.md",
21
+ HANDOFF_REL,
19
22
  ".cursor/plans/**",
20
23
  ".cursor/memory/**",
21
24
  ".cursor/context/config.json",
@@ -347,7 +350,11 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
347
350
  "73e3ca429cb522b0877f0d6d46bedbaf270f94bc63bb87f4e0fc7c512bf36e9c",
348
351
  "9a61f7432cf66be53d42b5d6f3c67ea71dd5efa1cc18d77d996f08ffea873373",
349
352
  "fd2a8867de62f83c89ae11295cae5b5699360b5205f9726c2c47c064318bd7a4",
350
- "364126473e089ed09a71e3f9eed80b1d602b35b4baa669b0a4f4be0519a787f8"
353
+ "364126473e089ed09a71e3f9eed80b1d602b35b4baa669b0a4f4be0519a787f8",
354
+ "cb14c0162e66ac565679089a566a725b26989db3536b7dba89bff77cb6010969",
355
+ "ebf490086ea45a7b342b3ec7408c9a82b22031daaefddf4425b6e6e931f6d6c8",
356
+ "3077e013297c7dd1e32eb2fa86e1ffa1de7d8740058652782bb8d391782eed71",
357
+ "7e0fa1bb73c8b6f1358cae19477304d85edfb7d4d9a7faf37c00e0578ed79edf"
351
358
  ]);
352
359
 
353
360
  // src/lifecycle/paths.ts
@@ -718,6 +725,11 @@ import { mkdir as mkdir4, readFile as readFile4, rename, rm, stat, writeFile as
718
725
  import { homedir } from "os";
719
726
  import path5 from "path";
720
727
  import { promisify } from "util";
728
+
729
+ // src/registry/paths.ts
730
+ var REGISTRY_INDEX_REL = "registry/registry.json";
731
+
732
+ // src/registry/resolve.ts
721
733
  var execFileAsync = promisify(execFile);
722
734
  var LOCK_TIMEOUT_MS = 6e4;
723
735
  var LOCK_RETRY_MS = 200;
@@ -876,7 +888,7 @@ function cacheKey(url, ref) {
876
888
  return createHash2("sha256").update(`${url}@${ref}`).digest("hex").slice(0, 16);
877
889
  }
878
890
  async function hasRegistryIndex(root) {
879
- return fileExists(path5.join(root, "registry", "registry.json"));
891
+ return fileExists(path5.join(root, REGISTRY_INDEX_REL));
880
892
  }
881
893
  async function cloneRegistry(url, ref, dest) {
882
894
  const { mkdir: mkdir9 } = await import("fs/promises");
@@ -924,7 +936,7 @@ async function resolveRegistryRoot(options) {
924
936
  if (options.registryPath) {
925
937
  const root = path5.resolve(options.registryPath);
926
938
  if (!await hasRegistryIndex(root)) {
927
- throw new Error(`No registry/registry.json under --registry ${root}`);
939
+ throw new Error(`No ${REGISTRY_INDEX_REL} under --registry ${root}`);
928
940
  }
929
941
  return { root, source: "flag" };
930
942
  }
@@ -932,7 +944,7 @@ async function resolveRegistryRoot(options) {
932
944
  if (envPath) {
933
945
  const root = path5.resolve(envPath);
934
946
  if (!await hasRegistryIndex(root)) {
935
- throw new Error(`No registry/registry.json under AGENT_KIT_REGISTRY=${root}`);
947
+ throw new Error(`No ${REGISTRY_INDEX_REL} under AGENT_KIT_REGISTRY=${root}`);
936
948
  }
937
949
  return { root, source: "env", url: options.registryUrl, ref: options.registryRef };
938
950
  }
@@ -956,7 +968,7 @@ async function resolveRegistryRoot(options) {
956
968
  } else {
957
969
  await cloneRegistry(url, ref, dest);
958
970
  if (!await hasRegistryIndex(dest)) {
959
- throw new Error(`Cloned ${url}@${ref} but registry/registry.json is missing`);
971
+ throw new Error(`Cloned ${url}@${ref} but ${REGISTRY_INDEX_REL} is missing`);
960
972
  }
961
973
  }
962
974
  ownershipTransferred = true;
@@ -1206,7 +1218,7 @@ async function loadAgentKitManifest(cwd) {
1206
1218
  // src/registry/client.ts
1207
1219
  import path7 from "path";
1208
1220
  async function loadRegistry(rootDir) {
1209
- const indexPath = path7.join(rootDir, "registry", "registry.json");
1221
+ const indexPath = path7.join(rootDir, REGISTRY_INDEX_REL);
1210
1222
  const index = await readJson(indexPath);
1211
1223
  if (!index) throw new Error(`Registry not found at ${indexPath}`);
1212
1224
  return index;
@@ -1323,7 +1335,7 @@ async function installSkill(registryRoot, projectRoot, skill, options = {}) {
1323
1335
  return stats;
1324
1336
  }
1325
1337
  async function installSkillsByIds(registryRoot, projectRoot, skillIds, options = {}) {
1326
- const index = await readJson(path8.join(registryRoot, "registry", "registry.json"));
1338
+ const index = await readJson(path8.join(registryRoot, REGISTRY_INDEX_REL));
1327
1339
  const stats = emptyStats();
1328
1340
  if (!index) return stats;
1329
1341
  const pool = allSkills(index);
@@ -2122,22 +2134,40 @@ import { defineCommand as defineCommand3 } from "citty";
2122
2134
 
2123
2135
  // src/lifecycle/cursor-update-awareness.ts
2124
2136
  import { access as access2, readFile as readFile7 } from "fs/promises";
2137
+ import path11 from "path";
2138
+
2139
+ // src/lifecycle/context-config.ts
2125
2140
  import path10 from "path";
2141
+ var CONTEXT_CONFIG_REL = path10.join(".cursor", "context", "config.json");
2142
+ function contextConfigPath(cwd) {
2143
+ return path10.join(cwd, CONTEXT_CONFIG_REL);
2144
+ }
2145
+ async function loadContextConfig(cwd) {
2146
+ return readJson(contextConfigPath(cwd));
2147
+ }
2148
+ function intervalElapsed(lastCheckedAt, intervalDays) {
2149
+ if (!lastCheckedAt) return true;
2150
+ const last = Date.parse(lastCheckedAt);
2151
+ if (Number.isNaN(last)) return true;
2152
+ return Date.now() - last >= intervalDays * 24 * 60 * 60 * 1e3;
2153
+ }
2154
+
2155
+ // src/lifecycle/cursor-update-awareness.ts
2126
2156
  var DEFAULT_CURSOR_CHANGELOG_URL = "https://cursor.com/changelog";
2127
2157
  var CHANGELOG_FETCH_TIMEOUT_MS = 15e3;
2128
2158
  var CURSOR_VERSION_MAJOR_MAX = 20;
2129
- var INVENTORY_REL = path10.join("docs", "cursor-native-audit.md");
2130
- var FEATURES_REL = path10.join("docs", "cursor-3-features.md");
2159
+ var INVENTORY_REL = path11.join("docs", "cursor-native-audit.md");
2160
+ var FEATURES_REL = path11.join("docs", "cursor-3-features.md");
2131
2161
  async function resolveInventoryRoot(cwd) {
2132
- let dir = path10.resolve(cwd);
2162
+ let dir = path11.resolve(cwd);
2133
2163
  for (; ; ) {
2134
2164
  try {
2135
- await access2(path10.join(dir, INVENTORY_REL));
2165
+ await access2(path11.join(dir, INVENTORY_REL));
2136
2166
  return dir;
2137
2167
  } catch {
2138
2168
  }
2139
- if (await fileExists(path10.join(dir, ".git"))) break;
2140
- const parent = path10.dirname(dir);
2169
+ if (await fileExists(path11.join(dir, ".git"))) break;
2170
+ const parent = path11.dirname(dir);
2141
2171
  if (parent === dir) break;
2142
2172
  dir = parent;
2143
2173
  }
@@ -2173,18 +2203,7 @@ function readCursorUpdateCheckPrefs(config) {
2173
2203
  changelogUrl
2174
2204
  };
2175
2205
  }
2176
- function intervalElapsed(lastCheckedAt, intervalDays) {
2177
- if (!lastCheckedAt) return true;
2178
- const last = Date.parse(lastCheckedAt);
2179
- if (Number.isNaN(last)) return true;
2180
- return Date.now() - last >= intervalDays * 24 * 60 * 60 * 1e3;
2181
- }
2182
- async function loadContextConfig(cwd) {
2183
- const configPath = path10.join(cwd, ".cursor", "context", "config.json");
2184
- return readJson(configPath);
2185
- }
2186
2206
  async function stampCursorUpdateCheck(cwd, patch) {
2187
- const configPath = path10.join(cwd, ".cursor", "context", "config.json");
2188
2207
  const existing = await loadContextConfig(cwd) ?? {};
2189
2208
  const prev = existing.cursorUpdateCheck && typeof existing.cursorUpdateCheck === "object" ? { ...existing.cursorUpdateCheck } : {};
2190
2209
  const nextSeen = patch.lastSeenCursorVersion !== void 0 ? patch.lastSeenCursorVersion : void 0;
@@ -2194,7 +2213,7 @@ async function stampCursorUpdateCheck(cwd, patch) {
2194
2213
  ...prev,
2195
2214
  lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString()
2196
2215
  };
2197
- await writeJson(configPath, existing);
2216
+ await writeJson(contextConfigPath(cwd), existing);
2198
2217
  return;
2199
2218
  }
2200
2219
  existing.cursorUpdateCheck = {
@@ -2203,7 +2222,7 @@ async function stampCursorUpdateCheck(cwd, patch) {
2203
2222
  lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
2204
2223
  ...nextSeen !== void 0 ? { lastSeenCursorVersion: nextSeen } : {}
2205
2224
  };
2206
- await writeJson(configPath, existing);
2225
+ await writeJson(contextConfigPath(cwd), existing);
2207
2226
  }
2208
2227
  function isPlausibleCursorVersion(version) {
2209
2228
  const parts = String(version).split(".");
@@ -2453,8 +2472,8 @@ async function checkCursorUpdateAwareness(cwd, options = {}) {
2453
2472
  message: missingInventoryMessage()
2454
2473
  });
2455
2474
  }
2456
- const inventoryPath = path10.join(inventoryRoot, INVENTORY_REL);
2457
- const featuresPath = path10.join(inventoryRoot, FEATURES_REL);
2475
+ const inventoryPath = path11.join(inventoryRoot, INVENTORY_REL);
2476
+ const featuresPath = path11.join(inventoryRoot, FEATURES_REL);
2458
2477
  let inventoryMd;
2459
2478
  try {
2460
2479
  inventoryMd = await readFile7(inventoryPath, "utf8");
@@ -2667,14 +2686,14 @@ var cursorAwarenessCommand = defineCommand3({
2667
2686
  // src/commands/dashboard-broadcast.ts
2668
2687
  import { spawn as spawn3 } from "child_process";
2669
2688
  import { access as access4 } from "fs/promises";
2670
- import path12 from "path";
2689
+ import path13 from "path";
2671
2690
  import { defineCommand as defineCommand5 } from "citty";
2672
2691
 
2673
2692
  // src/commands/dashboard.ts
2674
2693
  import { execFileSync, spawn as spawn2 } from "child_process";
2675
2694
  import { existsSync, readFileSync as readFileSync2, realpathSync } from "fs";
2676
2695
  import { access as access3 } from "fs/promises";
2677
- import path11 from "path";
2696
+ import path12 from "path";
2678
2697
  import { fileURLToPath } from "url";
2679
2698
  import { defineCommand as defineCommand4 } from "citty";
2680
2699
 
@@ -2684,7 +2703,7 @@ import { networkInterfaces } from "os";
2684
2703
  import { resolve } from "path";
2685
2704
  var REPO_ROOT_ENV = "MISSION_CONTROL_REPO_ROOT";
2686
2705
  var KIT_ROOT_ENV_KEYS = Object.freeze(["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]);
2687
- var CONTEXT_CONFIG_REL = ".cursor/context/config.json";
2706
+ var CONTEXT_CONFIG_REL2 = ".cursor/context/config.json";
2688
2707
  var CONFIG_PERSONA_IDS = Object.freeze(["autopilot", "night-shift", "ghost-runner"]);
2689
2708
  var CONFIG_PERSONA_MODES = Object.freeze(["continue-plan", "run-plan", "cli-run-plan"]);
2690
2709
  var CONFIG_REVIEW_BACKENDS = Object.freeze(["auto", "claude", "cursor"]);
@@ -2697,7 +2716,7 @@ function resolveContextConfigPath(repoRoot, fsHooks = {}) {
2697
2716
  if (typeof repoRoot !== "string" || !repoRoot) {
2698
2717
  return { ok: false, error: "invalid repo root" };
2699
2718
  }
2700
- const abs = resolve(repoRoot, CONTEXT_CONFIG_REL);
2719
+ const abs = resolve(repoRoot, CONTEXT_CONFIG_REL2);
2701
2720
  const contextDir = resolve(repoRoot, ".cursor", "context");
2702
2721
  const absNorm = abs.replace(/\\/g, "/");
2703
2722
  if (!absNorm.endsWith("/.cursor/context/config.json")) {
@@ -2763,7 +2782,7 @@ function readPreferredBrowserFromConfig(configPath, fsHooks = {}) {
2763
2782
 
2764
2783
  // src/commands/dashboard.ts
2765
2784
  function readPreferredBrowserFromWorkspace(cwd, readFile31 = readFileSync2) {
2766
- const resolved = resolveContextConfigPath(path11.resolve(cwd), {
2785
+ const resolved = resolveContextConfigPath(path12.resolve(cwd), {
2767
2786
  existsSync,
2768
2787
  realpathSync
2769
2788
  });
@@ -2785,61 +2804,61 @@ function applyDashboardOpenEnv(env, opts) {
2785
2804
  return next;
2786
2805
  }
2787
2806
  function dashboardSpawnEnv(env, snapshotRoot, opts) {
2788
- const root = path11.resolve(snapshotRoot);
2807
+ const root = path12.resolve(snapshotRoot);
2789
2808
  return applyDashboardOpenEnv({ ...env, MISSION_CONTROL_REPO_ROOT: root }, { ...opts, cwd: root });
2790
2809
  }
2791
2810
  function dashboardProcessTitle(snapshotRoot) {
2792
- const base = path11.basename(path11.resolve(snapshotRoot)) || "workspace";
2811
+ const base = path12.basename(path12.resolve(snapshotRoot)) || "workspace";
2793
2812
  return `Mission Control \xB7 ${base}`;
2794
2813
  }
2795
2814
  function bundledDashboardCandidates(filename, moduleUrl = import.meta.url) {
2796
- const here = path11.dirname(fileURLToPath(moduleUrl));
2815
+ const here = path12.dirname(fileURLToPath(moduleUrl));
2797
2816
  return [
2798
2817
  // Published / built: <pkg>/dist/index.js -> <pkg>/dashboard/
2799
- path11.join(here, "..", "dashboard", filename),
2818
+ path12.join(here, "..", "dashboard", filename),
2800
2819
  // Dev source: packages/cli/src/commands/*.ts -> packages/cli/dashboard/ (sync copy)
2801
- path11.join(here, "..", "..", "dashboard", filename),
2820
+ path12.join(here, "..", "..", "dashboard", filename),
2802
2821
  // From src/commands: packages/dashboard/ (unused layout); from dist: two levels above package
2803
- path11.join(here, "..", "..", "..", "dashboard", filename)
2822
+ path12.join(here, "..", "..", "..", "dashboard", filename)
2804
2823
  ];
2805
2824
  }
2806
2825
  async function firstExisting(candidates) {
2807
2826
  for (const candidate2 of candidates) {
2808
2827
  try {
2809
2828
  await access3(candidate2);
2810
- return path11.resolve(candidate2);
2829
+ return path12.resolve(candidate2);
2811
2830
  } catch {
2812
2831
  }
2813
2832
  }
2814
2833
  return null;
2815
2834
  }
2816
2835
  async function findDashboardStart(cwd, env = process.env, options = {}) {
2817
- let dir = path11.resolve(cwd);
2836
+ let dir = path12.resolve(cwd);
2818
2837
  for (; ; ) {
2819
- const candidate2 = path11.join(dir, "dashboard", "start.mjs");
2838
+ const candidate2 = path12.join(dir, "dashboard", "start.mjs");
2820
2839
  try {
2821
2840
  await access3(candidate2);
2822
2841
  return candidate2;
2823
2842
  } catch {
2824
2843
  }
2825
- const parent = path11.dirname(dir);
2844
+ const parent = path12.dirname(dir);
2826
2845
  if (parent === dir) break;
2827
2846
  dir = parent;
2828
2847
  }
2829
2848
  for (const key of ["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]) {
2830
2849
  const base = env[key];
2831
2850
  if (!base || typeof base !== "string" || !base.trim()) continue;
2832
- const candidate2 = path11.join(path11.resolve(base.trim()), "dashboard", "start.mjs");
2851
+ const candidate2 = path12.join(path12.resolve(base.trim()), "dashboard", "start.mjs");
2833
2852
  try {
2834
2853
  await access3(candidate2);
2835
2854
  return candidate2;
2836
2855
  } catch {
2837
2856
  }
2838
2857
  }
2839
- const sibling = path11.join(path11.resolve(cwd), "..", "agent-kit", "dashboard", "start.mjs");
2858
+ const sibling = path12.join(path12.resolve(cwd), "..", "agent-kit", "dashboard", "start.mjs");
2840
2859
  try {
2841
2860
  await access3(sibling);
2842
- return path11.resolve(sibling);
2861
+ return path12.resolve(sibling);
2843
2862
  } catch {
2844
2863
  }
2845
2864
  return firstExisting(
@@ -2847,13 +2866,13 @@ async function findDashboardStart(cwd, env = process.env, options = {}) {
2847
2866
  );
2848
2867
  }
2849
2868
  function resolveDashboardSnapshotRoot(cwd) {
2850
- const abs = path11.resolve(cwd);
2869
+ const abs = path12.resolve(cwd);
2851
2870
  let dir = abs;
2852
2871
  for (; ; ) {
2853
- if (existsSync(path11.join(dir, ".cursor", "agent-kit.json"))) {
2872
+ if (existsSync(path12.join(dir, ".cursor", "agent-kit.json"))) {
2854
2873
  return dir;
2855
2874
  }
2856
- const parent = path11.dirname(dir);
2875
+ const parent = path12.dirname(dir);
2857
2876
  if (parent === dir) break;
2858
2877
  dir = parent;
2859
2878
  }
@@ -2863,7 +2882,7 @@ function resolveDashboardSnapshotRoot(cwd) {
2863
2882
  timeout: 5e3,
2864
2883
  stdio: ["ignore", "pipe", "ignore"]
2865
2884
  }).trim();
2866
- if (top) return path11.resolve(top);
2885
+ if (top) return path12.resolve(top);
2867
2886
  } catch {
2868
2887
  }
2869
2888
  return abs;
@@ -2871,7 +2890,7 @@ function resolveDashboardSnapshotRoot(cwd) {
2871
2890
  function runStartScript(startPath, env) {
2872
2891
  return new Promise((resolve3, reject) => {
2873
2892
  const child = spawn2(process.execPath, [startPath], {
2874
- cwd: path11.dirname(path11.dirname(startPath)),
2893
+ cwd: path12.dirname(path12.dirname(startPath)),
2875
2894
  env,
2876
2895
  stdio: "inherit"
2877
2896
  });
@@ -2939,30 +2958,30 @@ var dashboardCommand = defineCommand4({
2939
2958
 
2940
2959
  // src/commands/dashboard-broadcast.ts
2941
2960
  async function findDashboardBroadcastStart(cwd, env = process.env, options = {}) {
2942
- let dir = path12.resolve(cwd);
2961
+ let dir = path13.resolve(cwd);
2943
2962
  for (; ; ) {
2944
- const candidate2 = path12.join(dir, "dashboard", "start-broadcast.mjs");
2963
+ const candidate2 = path13.join(dir, "dashboard", "start-broadcast.mjs");
2945
2964
  try {
2946
2965
  await access4(candidate2);
2947
2966
  return candidate2;
2948
2967
  } catch {
2949
2968
  }
2950
- const parent = path12.dirname(dir);
2969
+ const parent = path13.dirname(dir);
2951
2970
  if (parent === dir) break;
2952
2971
  dir = parent;
2953
2972
  }
2954
2973
  for (const key of ["MISSION_CONTROL_KIT_ROOT", "AGENT_KIT_HOME"]) {
2955
2974
  const base = env[key];
2956
2975
  if (!base || typeof base !== "string" || !base.trim()) continue;
2957
- const candidate2 = path12.join(path12.resolve(base.trim()), "dashboard", "start-broadcast.mjs");
2976
+ const candidate2 = path13.join(path13.resolve(base.trim()), "dashboard", "start-broadcast.mjs");
2958
2977
  try {
2959
2978
  await access4(candidate2);
2960
2979
  return candidate2;
2961
2980
  } catch {
2962
2981
  }
2963
2982
  }
2964
- const sibling = path12.join(
2965
- path12.resolve(cwd),
2983
+ const sibling = path13.join(
2984
+ path13.resolve(cwd),
2966
2985
  "..",
2967
2986
  "agent-kit",
2968
2987
  "dashboard",
@@ -2970,7 +2989,7 @@ async function findDashboardBroadcastStart(cwd, env = process.env, options = {})
2970
2989
  );
2971
2990
  try {
2972
2991
  await access4(sibling);
2973
- return path12.resolve(sibling);
2992
+ return path13.resolve(sibling);
2974
2993
  } catch {
2975
2994
  }
2976
2995
  for (const candidate2 of bundledDashboardCandidates(
@@ -2979,7 +2998,7 @@ async function findDashboardBroadcastStart(cwd, env = process.env, options = {})
2979
2998
  )) {
2980
2999
  try {
2981
3000
  await access4(candidate2);
2982
- return path12.resolve(candidate2);
3001
+ return path13.resolve(candidate2);
2983
3002
  } catch {
2984
3003
  }
2985
3004
  }
@@ -2988,7 +3007,7 @@ async function findDashboardBroadcastStart(cwd, env = process.env, options = {})
2988
3007
  function runStartScript2(startPath, env) {
2989
3008
  return new Promise((resolve3, reject) => {
2990
3009
  const child = spawn3(process.execPath, [startPath], {
2991
- cwd: path12.dirname(path12.dirname(startPath)),
3010
+ cwd: path13.dirname(path13.dirname(startPath)),
2992
3011
  env,
2993
3012
  stdio: "inherit"
2994
3013
  });
@@ -3043,7 +3062,7 @@ import { defineCommand as defineCommand6 } from "citty";
3043
3062
 
3044
3063
  // src/lifecycle/diff.ts
3045
3064
  import { readFile as readFile8 } from "fs/promises";
3046
- import path13 from "path";
3065
+ import path14 from "path";
3047
3066
  async function readIfExists(abs) {
3048
3067
  try {
3049
3068
  return await readFile8(abs, "utf8");
@@ -3052,7 +3071,7 @@ async function readIfExists(abs) {
3052
3071
  }
3053
3072
  }
3054
3073
  async function comparePair(registryRoot, projectRoot, sourceRel, targetRel, protectedGlobs) {
3055
- const posixTarget = targetRel.split(path13.sep).join("/");
3074
+ const posixTarget = targetRel.split(path14.sep).join("/");
3056
3075
  if (isProtectedPath(posixTarget, protectedGlobs)) {
3057
3076
  return { path: posixTarget, status: "protected" };
3058
3077
  }
@@ -3082,7 +3101,7 @@ async function diffAgainstRegistry(registryRoot, projectRoot, manifest) {
3082
3101
  const entries = [];
3083
3102
  const seen = /* @__PURE__ */ new Set();
3084
3103
  const pushUnique = async (sourceRel, targetRel) => {
3085
- const key = targetRel.split(path13.sep).join("/");
3104
+ const key = targetRel.split(path14.sep).join("/");
3086
3105
  if (seen.has(key)) return;
3087
3106
  seen.add(key);
3088
3107
  entries.push(
@@ -3187,14 +3206,116 @@ var diffCommand = defineCommand6({
3187
3206
  });
3188
3207
 
3189
3208
  // src/commands/doctor.ts
3190
- import path26 from "path";
3209
+ import path28 from "path";
3191
3210
  import { defineCommand as defineCommand7 } from "citty";
3192
3211
 
3193
3212
  // src/invariants/hooks-health.ts
3194
3213
  import { execFile as execFile2 } from "child_process";
3195
- import { constants as constants2, access as access5, readFile as readFile9, readdir as readdir4, stat as stat2 } from "fs/promises";
3196
- import path14 from "path";
3214
+ import { constants as constants2, access as access5, readFile as readFile10, readdir as readdir4, stat as stat2 } from "fs/promises";
3215
+ import path16 from "path";
3197
3216
  import { promisify as promisify2 } from "util";
3217
+
3218
+ // src/generator/claude-session-start-hook.ts
3219
+ import { readFile as readFile9, writeFile as writeFile5 } from "fs/promises";
3220
+ import path15 from "path";
3221
+ var CLAUDE_SETTINGS_REL = ".claude/settings.json";
3222
+ var RESOLVE_AGENT_KIT_REL = ".cursor/hooks/agent/resolve-agent-kit.sh";
3223
+ var SESSION_START_HOOK_MARKER = "hook session-start --format claude";
3224
+ var SESSION_START_DEGRADED_TEXT = "Agent Kit hooks are running in degraded fail-open mode: the agent-kit CLI could not be resolved (checked AGENT_KIT_HOOK_BIN, PATH, node_modules/.bin/agent-kit). Slash command adapters still work; session-context injection is inactive. Fix: install the CLI (npm i -D @dadado/agent-kit-cli) or set AGENT_KIT_HOOK_BIN.";
3225
+ function buildSessionStartHookCommand() {
3226
+ return `. "\${CLAUDE_PROJECT_DIR}/${RESOLVE_AGENT_KIT_REL}" 2>/dev/null && resolve_agent_kit && exec $AGENT_KIT_RESOLVED hook session-start --format claude; printf '%s' ${shellSingleQuote(SESSION_START_DEGRADED_TEXT)}`;
3227
+ }
3228
+ function shellSingleQuote(text) {
3229
+ return `'${text.replace(/'/g, "'\\''")}'`;
3230
+ }
3231
+ function buildSessionStartHookEntry() {
3232
+ return {
3233
+ type: "command",
3234
+ command: buildSessionStartHookCommand(),
3235
+ timeout: 15,
3236
+ statusMessage: "Loading Agent Kit session context"
3237
+ };
3238
+ }
3239
+ function isPlainObject2(value) {
3240
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3241
+ }
3242
+ function groupHasMarker(group) {
3243
+ if (!isPlainObject2(group) || !Array.isArray(group.hooks)) return false;
3244
+ return group.hooks.some(
3245
+ (h) => isPlainObject2(h) && typeof h.command === "string" && h.command.includes(SESSION_START_HOOK_MARKER)
3246
+ );
3247
+ }
3248
+ function mergeSessionStartHookIntoSettings(existingRaw) {
3249
+ const entry = buildSessionStartHookEntry();
3250
+ const newGroup = { hooks: [entry] };
3251
+ let root = {};
3252
+ if (existingRaw !== null && existingRaw.trim() !== "") {
3253
+ try {
3254
+ const parsed = JSON.parse(existingRaw);
3255
+ if (!isPlainObject2(parsed)) throw new Error("root is not an object");
3256
+ root = parsed;
3257
+ } catch {
3258
+ return {
3259
+ content: null,
3260
+ status: "unavailable",
3261
+ instructions: instructionsBlock(entry)
3262
+ };
3263
+ }
3264
+ }
3265
+ const hooks = isPlainObject2(root.hooks) ? { ...root.hooks } : {};
3266
+ const sessionStart = Array.isArray(hooks.SessionStart) ? [...hooks.SessionStart] : [];
3267
+ const existingIndex = sessionStart.findIndex((g) => groupHasMarker(g));
3268
+ let status;
3269
+ if (existingIndex === -1) {
3270
+ sessionStart.push(newGroup);
3271
+ status = "applied";
3272
+ } else {
3273
+ const current = sessionStart[existingIndex];
3274
+ if (JSON.stringify(current) === JSON.stringify(newGroup)) {
3275
+ status = "unchanged";
3276
+ } else {
3277
+ sessionStart[existingIndex] = newGroup;
3278
+ status = "refreshed";
3279
+ }
3280
+ }
3281
+ hooks.SessionStart = sessionStart;
3282
+ root.hooks = hooks;
3283
+ return { content: `${JSON.stringify(root, null, 2)}
3284
+ `, status };
3285
+ }
3286
+ function instructionsBlock(entry) {
3287
+ return [
3288
+ `Could not parse the existing ${CLAUDE_SETTINGS_REL} as JSON, so Agent Kit did not touch it.`,
3289
+ "Add this hook by hand under hooks.SessionStart (create the arrays if they do not exist):",
3290
+ "",
3291
+ JSON.stringify(entry, null, 2)
3292
+ ].join("\n");
3293
+ }
3294
+ async function writeClaudeSessionStartHook(rootDir) {
3295
+ const abs = path15.join(rootDir, CLAUDE_SETTINGS_REL);
3296
+ let existing = null;
3297
+ try {
3298
+ existing = await readFile9(abs, "utf8");
3299
+ } catch {
3300
+ existing = null;
3301
+ }
3302
+ const merged = mergeSessionStartHookIntoSettings(existing);
3303
+ if (merged.status === "unavailable" || merged.content === null) {
3304
+ return {
3305
+ relativePath: CLAUDE_SETTINGS_REL,
3306
+ status: "unavailable",
3307
+ instructions: merged.instructions
3308
+ };
3309
+ }
3310
+ if (merged.status === "unchanged") {
3311
+ return { relativePath: CLAUDE_SETTINGS_REL, status: "unchanged" };
3312
+ }
3313
+ await ensureDir(path15.dirname(abs));
3314
+ await writeFile5(abs, merged.content, "utf8");
3315
+ return { relativePath: CLAUDE_SETTINGS_REL, status: merged.status };
3316
+ }
3317
+
3318
+ // src/invariants/hooks-health.ts
3198
3319
  var execFileAsync2 = promisify2(execFile2);
3199
3320
  var GIT_HOOK_CANONICAL_NAMES = ["pre-commit", "pre-push", "prepare-commit-msg"];
3200
3321
  var EXPECTED_EVENTS = [
@@ -3221,10 +3342,10 @@ async function isExecutable(p) {
3221
3342
  }
3222
3343
  }
3223
3344
  async function resolveAgentKitCli(rootDir) {
3224
- const root = path14.resolve(rootDir);
3345
+ const root = path16.resolve(rootDir);
3225
3346
  const candidates = [
3226
- path14.join(root, "node_modules", ".bin", "agent-kit"),
3227
- path14.join(root, "packages", "cli", "dist", "index.js")
3347
+ path16.join(root, "node_modules", ".bin", "agent-kit"),
3348
+ path16.join(root, "packages", "cli", "dist", "index.js")
3228
3349
  ];
3229
3350
  for (const c of candidates) {
3230
3351
  if (await exists(c)) return c;
@@ -3244,8 +3365,8 @@ function commandLooksLikeAdapter(command) {
3244
3365
  return m?.[1] ?? null;
3245
3366
  }
3246
3367
  async function assessGitHooksInstallDrift(rootDir) {
3247
- const root = path14.resolve(rootDir);
3248
- const canonicalDir = path14.join(root, "git-hooks");
3368
+ const root = path16.resolve(rootDir);
3369
+ const canonicalDir = path16.join(root, "git-hooks");
3249
3370
  if (!await exists(canonicalDir)) return [];
3250
3371
  let hooksPathCfg = "";
3251
3372
  try {
@@ -3258,12 +3379,12 @@ async function assessGitHooksInstallDrift(rootDir) {
3258
3379
  } catch {
3259
3380
  }
3260
3381
  if (hooksPathCfg) {
3261
- const resolved = path14.isAbsolute(hooksPathCfg) ? path14.normalize(hooksPathCfg) : path14.normalize(path14.join(root, hooksPathCfg));
3262
- if (resolved === path14.normalize(canonicalDir)) {
3382
+ const resolved = path16.isAbsolute(hooksPathCfg) ? path16.normalize(hooksPathCfg) : path16.normalize(path16.join(root, hooksPathCfg));
3383
+ if (resolved === path16.normalize(canonicalDir)) {
3263
3384
  return [];
3264
3385
  }
3265
3386
  }
3266
- const gitDir = path14.join(root, ".git");
3387
+ const gitDir = path16.join(root, ".git");
3267
3388
  if (!await exists(gitDir)) return [];
3268
3389
  try {
3269
3390
  const st = await stat2(gitDir);
@@ -3271,7 +3392,7 @@ async function assessGitHooksInstallDrift(rootDir) {
3271
3392
  } catch {
3272
3393
  return [];
3273
3394
  }
3274
- const installedDir = path14.join(gitDir, "hooks");
3395
+ const installedDir = path16.join(gitDir, "hooks");
3275
3396
  const advisories = [];
3276
3397
  const installHint = "Install or refresh with: `cp git-hooks/<name> .git/hooks/<name> && chmod +x .git/hooks/<name>` (see git-hooks/README.md)";
3277
3398
  let names = [...GIT_HOOK_CANONICAL_NAMES];
@@ -3284,8 +3405,8 @@ async function assessGitHooksInstallDrift(rootDir) {
3284
3405
  } catch {
3285
3406
  }
3286
3407
  for (const name of names) {
3287
- const canonical = path14.join(canonicalDir, name);
3288
- const installed = path14.join(installedDir, name);
3408
+ const canonical = path16.join(canonicalDir, name);
3409
+ const installed = path16.join(installedDir, name);
3289
3410
  if (!await exists(canonical)) continue;
3290
3411
  if (!await exists(installed)) {
3291
3412
  advisories.push(
@@ -3294,7 +3415,7 @@ async function assessGitHooksInstallDrift(rootDir) {
3294
3415
  continue;
3295
3416
  }
3296
3417
  try {
3297
- const [a, b] = await Promise.all([readFile9(canonical, "utf8"), readFile9(installed, "utf8")]);
3418
+ const [a, b] = await Promise.all([readFile10(canonical, "utf8"), readFile10(installed, "utf8")]);
3298
3419
  if (a !== b) {
3299
3420
  advisories.push(
3300
3421
  `git-hooks drift: \`.git/hooks/${name}\` differs from \`git-hooks/${name}\`. ${installHint}`
@@ -3309,9 +3430,9 @@ async function assessGitHooksInstallDrift(rootDir) {
3309
3430
  return advisories;
3310
3431
  }
3311
3432
  async function assessHooksHealth(rootDir) {
3312
- const root = path14.resolve(rootDir);
3433
+ const root = path16.resolve(rootDir);
3313
3434
  const hooksJsonPath = ".cursor/hooks.json";
3314
- const hooksJsonAbs = path14.join(root, hooksJsonPath);
3435
+ const hooksJsonAbs = path16.join(root, hooksJsonPath);
3315
3436
  const reasons = [];
3316
3437
  const wiredEvents = [];
3317
3438
  const advisories = await assessGitHooksInstallDrift(root);
@@ -3327,7 +3448,7 @@ async function assessHooksHealth(rootDir) {
3327
3448
  }
3328
3449
  let parsed;
3329
3450
  try {
3330
- parsed = JSON.parse(await readFile9(hooksJsonAbs, "utf8"));
3451
+ parsed = JSON.parse(await readFile10(hooksJsonAbs, "utf8"));
3331
3452
  } catch {
3332
3453
  return {
3333
3454
  status: "degraded",
@@ -3357,14 +3478,14 @@ async function assessHooksHealth(rootDir) {
3357
3478
  reasons.push(`missing hook event: ${event}`);
3358
3479
  }
3359
3480
  }
3360
- const resolveLib = path14.join(root, ".cursor", "hooks", "agent", "resolve-agent-kit.sh");
3481
+ const resolveLib = path16.join(root, RESOLVE_AGENT_KIT_REL);
3361
3482
  if (!await exists(resolveLib)) {
3362
- reasons.push("missing `.cursor/hooks/agent/resolve-agent-kit.sh` (thin adapter resolver)");
3483
+ reasons.push(`missing \`${RESOLVE_AGENT_KIT_REL}\` (thin adapter resolver)`);
3363
3484
  } else if (!await isExecutable(resolveLib)) {
3364
- reasons.push("`.cursor/hooks/agent/resolve-agent-kit.sh` is not executable (chmod +x)");
3485
+ reasons.push(`\`${RESOLVE_AGENT_KIT_REL}\` is not executable (chmod +x)`);
3365
3486
  }
3366
3487
  for (const rel of adapterRels) {
3367
- const abs = path14.join(root, rel);
3488
+ const abs = path16.join(root, rel);
3368
3489
  if (!await exists(abs)) {
3369
3490
  reasons.push(`missing adapter script: \`${rel}\``);
3370
3491
  continue;
@@ -3405,7 +3526,7 @@ async function assessHooksHealth(rootDir) {
3405
3526
 
3406
3527
  // src/lifecycle/check-updates.ts
3407
3528
  import { execFile as execFile3 } from "child_process";
3408
- import path15 from "path";
3529
+ import path17 from "path";
3409
3530
  import { promisify as promisify3 } from "util";
3410
3531
  var execFileAsync3 = promisify3(execFile3);
3411
3532
  var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/i;
@@ -3505,31 +3626,19 @@ function readUpdateCheckPrefs(config) {
3505
3626
  lastCheckedAt: typeof uc.lastCheckedAt === "string" ? uc.lastCheckedAt : null
3506
3627
  };
3507
3628
  }
3508
- function intervalElapsed2(lastCheckedAt, intervalDays) {
3509
- if (!lastCheckedAt) return true;
3510
- const last = Date.parse(lastCheckedAt);
3511
- if (Number.isNaN(last)) return true;
3512
- const ms = intervalDays * 24 * 60 * 60 * 1e3;
3513
- return Date.now() - last >= ms;
3514
- }
3515
- async function loadContextConfig2(cwd) {
3516
- const configPath = path15.join(cwd, ".cursor", "context", "config.json");
3517
- return readJson(configPath);
3518
- }
3519
3629
  async function stampLastCheckedAt(cwd) {
3520
- const configPath = path15.join(cwd, ".cursor", "context", "config.json");
3521
- const existing = await loadContextConfig2(cwd) ?? {};
3630
+ const existing = await loadContextConfig(cwd) ?? {};
3522
3631
  const prev = existing.updateCheck && typeof existing.updateCheck === "object" ? { ...existing.updateCheck } : {};
3523
3632
  existing.updateCheck = {
3524
3633
  ...DEFAULT_UPDATE_CHECK,
3525
3634
  ...prev,
3526
3635
  lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString()
3527
3636
  };
3528
- await writeJson(configPath, existing);
3637
+ await writeJson(contextConfigPath(cwd), existing);
3529
3638
  }
3530
3639
  async function readLocalKitVersion(registryRoot) {
3531
3640
  for (const rel of ["packages/cli/package.json", "package.json"]) {
3532
- const data = await readJson(path15.join(registryRoot, rel));
3641
+ const data = await readJson(path17.join(registryRoot, rel));
3533
3642
  if (data && typeof data.version === "string" && data.version.length > 0) {
3534
3643
  return data.version;
3535
3644
  }
@@ -3550,7 +3659,7 @@ async function checkAgainstLocalRegistry(cwd, manifest, options) {
3550
3659
  status: "error",
3551
3660
  installedVersion: manifest.version,
3552
3661
  latestVersion: null,
3553
- registryUrl: path15.resolve(registryPath),
3662
+ registryUrl: path17.resolve(registryPath),
3554
3663
  registryRef: "local",
3555
3664
  applyRecommended: false,
3556
3665
  message: `Failed to resolve --registry: ${msg}`
@@ -3668,7 +3777,7 @@ async function checkForUpdates(cwd, options = {}) {
3668
3777
  };
3669
3778
  }
3670
3779
  if (options.respectPrefs) {
3671
- const config = await loadContextConfig2(cwd);
3780
+ const config = await loadContextConfig(cwd);
3672
3781
  const prefs = readUpdateCheckPrefs(config);
3673
3782
  if (!prefs.enabled) {
3674
3783
  return {
@@ -3681,7 +3790,7 @@ async function checkForUpdates(cwd, options = {}) {
3681
3790
  message: "updateCheck.enabled is false (opt-in). Set true in .cursor/context/config.json to nudge."
3682
3791
  };
3683
3792
  }
3684
- if (!intervalElapsed2(prefs.lastCheckedAt, prefs.intervalDays)) {
3793
+ if (!intervalElapsed(prefs.lastCheckedAt, prefs.intervalDays)) {
3685
3794
  return {
3686
3795
  status: "skipped-interval",
3687
3796
  installedVersion: manifest.version,
@@ -3778,7 +3887,7 @@ function runningCliBehindMessage(running, latest) {
3778
3887
  async function checkRunningCliVsNpmLatest(cwd, options = {}) {
3779
3888
  const running = normalizeSemver(KIT_VERSION) ?? KIT_VERSION;
3780
3889
  if (options.respectPrefs) {
3781
- const config = await loadContextConfig2(cwd);
3890
+ const config = await loadContextConfig(cwd);
3782
3891
  const prefs = readUpdateCheckPrefs(config);
3783
3892
  if (!prefs.enabled) {
3784
3893
  return {
@@ -3788,7 +3897,7 @@ async function checkRunningCliVsNpmLatest(cwd, options = {}) {
3788
3897
  message: "updateCheck.enabled is false (opt-in). Set true in .cursor/context/config.json to nudge."
3789
3898
  };
3790
3899
  }
3791
- if (!intervalElapsed2(prefs.lastCheckedAt, prefs.intervalDays)) {
3900
+ if (!intervalElapsed(prefs.lastCheckedAt, prefs.intervalDays)) {
3792
3901
  return {
3793
3902
  status: "skipped-interval",
3794
3903
  runningVersion: running,
@@ -3887,11 +3996,11 @@ async function warnIfRunningCliBehindNpm(cwd, options = {}) {
3887
3996
  }
3888
3997
 
3889
3998
  // src/readiness/env-checks.ts
3890
- import { constants as constants3, access as access6, readFile as readFile10, stat as stat3 } from "fs/promises";
3999
+ import { constants as constants3, access as access6, readFile as readFile11, stat as stat3 } from "fs/promises";
3891
4000
  import { homedir as homedir2 } from "os";
3892
- import path16 from "path";
4001
+ import path18 from "path";
3893
4002
  var MIN_NODE_MAJOR = 20;
3894
- var CLI_PACKAGE_JSON_REL = path16.join(
4003
+ var CLI_PACKAGE_JSON_REL = path18.join(
3895
4004
  "lib",
3896
4005
  "node_modules",
3897
4006
  "@dadado",
@@ -3912,7 +4021,7 @@ function expandBinDirVars(raw, binDir) {
3912
4021
  return raw.replace(/\$\{basedir\}/g, binDir).replace(/\$basedir/g, binDir);
3913
4022
  }
3914
4023
  function packageJsonFromDistIndex(distIndex) {
3915
- return path16.join(path16.dirname(distIndex), "..", "package.json");
4024
+ return path18.join(path18.dirname(distIndex), "..", "package.json");
3916
4025
  }
3917
4026
  function parsePackageVersion(contents) {
3918
4027
  try {
@@ -3923,23 +4032,23 @@ function parsePackageVersion(contents) {
3923
4032
  }
3924
4033
  }
3925
4034
  async function readBinVersion(binPath, options = {}) {
3926
- const readFileImpl = options.readFileImpl ?? ((filePath) => readFile10(filePath, "utf8"));
3927
- const binDir = path16.dirname(binPath);
4035
+ const readFileImpl = options.readFileImpl ?? ((filePath) => readFile11(filePath, "utf8"));
4036
+ const binDir = path18.dirname(binPath);
3928
4037
  const candidates = [
3929
- path16.join(binDir, "..", CLI_PACKAGE_JSON_REL),
3930
- path16.join(binDir, "..", "node_modules", "@dadado", "agent-kit-cli", "package.json")
4038
+ path18.join(binDir, "..", CLI_PACKAGE_JSON_REL),
4039
+ path18.join(binDir, "..", "node_modules", "@dadado", "agent-kit-cli", "package.json")
3931
4040
  ];
3932
4041
  try {
3933
4042
  const contents = await readFileImpl(binPath);
3934
4043
  for (const raw of extractDistIndexFromBinScript(contents)) {
3935
- const distIndex = path16.resolve(binDir, expandBinDirVars(raw, binDir));
4044
+ const distIndex = path18.resolve(binDir, expandBinDirVars(raw, binDir));
3936
4045
  candidates.push(packageJsonFromDistIndex(distIndex));
3937
4046
  }
3938
4047
  } catch {
3939
4048
  }
3940
4049
  const seen = /* @__PURE__ */ new Set();
3941
4050
  for (const candidate2 of candidates) {
3942
- const resolved = path16.resolve(candidate2);
4051
+ const resolved = path18.resolve(candidate2);
3943
4052
  if (seen.has(resolved)) continue;
3944
4053
  seen.add(resolved);
3945
4054
  try {
@@ -3953,11 +4062,11 @@ async function readBinVersion(binPath, options = {}) {
3953
4062
  async function resolveBinOnPath(binName, env, platform) {
3954
4063
  const pathVar = env.PATH ?? env.Path ?? "";
3955
4064
  if (!pathVar) return null;
3956
- const dirs = pathVar.split(path16.delimiter).filter(Boolean);
4065
+ const dirs = pathVar.split(path18.delimiter).filter(Boolean);
3957
4066
  const candidates = platform === "win32" ? [binName, `${binName}.cmd`, `${binName}.exe`, `${binName}.bat`] : [binName];
3958
4067
  for (const dir of dirs) {
3959
4068
  for (const candidate2 of candidates) {
3960
- const abs = path16.join(dir, candidate2);
4069
+ const abs = path18.join(dir, candidate2);
3961
4070
  try {
3962
4071
  await access6(abs, platform === "win32" ? void 0 : constants3.X_OK);
3963
4072
  return abs;
@@ -3981,13 +4090,13 @@ function detectShellName(env, platform) {
3981
4090
  }
3982
4091
  const shellPath = env.SHELL;
3983
4092
  if (!shellPath) return null;
3984
- const base = path16.basename(shellPath).trim();
4093
+ const base = path18.basename(shellPath).trim();
3985
4094
  return base || null;
3986
4095
  }
3987
4096
  function detectShellProfile(env, platform, homeDir) {
3988
4097
  const shellName = detectShellName(env, platform);
3989
- if (shellName === "zsh") return path16.join(homeDir, ".zshrc");
3990
- if (shellName === "bash") return path16.join(homeDir, ".bashrc");
4098
+ if (shellName === "zsh") return path18.join(homeDir, ".zshrc");
4099
+ if (shellName === "bash") return path18.join(homeDir, ".bashrc");
3991
4100
  return null;
3992
4101
  }
3993
4102
  function parseNpmrcPrefix(content, homeDir) {
@@ -3996,12 +4105,12 @@ function parseNpmrcPrefix(content, homeDir) {
3996
4105
  if (!captured) return null;
3997
4106
  let value = captured.trim().replace(/^["']|["']$/g, "");
3998
4107
  if (value.startsWith("~")) {
3999
- value = path16.join(homeDir, value.slice(1));
4108
+ value = path18.join(homeDir, value.slice(1));
4000
4109
  }
4001
4110
  return value || null;
4002
4111
  }
4003
4112
  function heuristicPrefixFromExecPath(execPath, platform) {
4004
- const p = platform === "win32" ? path16.win32 : path16.posix;
4113
+ const p = platform === "win32" ? path18.win32 : path18.posix;
4005
4114
  return platform === "win32" ? p.dirname(execPath) : p.dirname(p.dirname(execPath));
4006
4115
  }
4007
4116
  async function detectNpmPrefix(options = {}) {
@@ -4009,12 +4118,12 @@ async function detectNpmPrefix(options = {}) {
4009
4118
  const platform = options.platform ?? process.platform;
4010
4119
  const homeDir = options.homeDir ?? homedir2();
4011
4120
  const execPath = options.execPath ?? process.execPath;
4012
- const readFileImpl = options.readFileImpl ?? ((filePath) => readFile10(filePath, "utf8"));
4121
+ const readFileImpl = options.readFileImpl ?? ((filePath) => readFile11(filePath, "utf8"));
4013
4122
  const envPrefix = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
4014
4123
  if (envPrefix?.trim()) {
4015
4124
  return { prefix: envPrefix.trim(), source: "env" };
4016
4125
  }
4017
- const userconfigPath = env.NPM_CONFIG_USERCONFIG ?? path16.join(homeDir, ".npmrc");
4126
+ const userconfigPath = env.NPM_CONFIG_USERCONFIG ?? path18.join(homeDir, ".npmrc");
4018
4127
  try {
4019
4128
  const content = await readFileImpl(userconfigPath);
4020
4129
  const npmrcPrefix = parseNpmrcPrefix(content, homeDir);
@@ -4341,12 +4450,17 @@ function createReadinessReport(scan, options) {
4341
4450
  }
4342
4451
 
4343
4452
  // src/scanner/safe-fixes.ts
4344
- import { readFile as readFile15, writeFile as writeFile5 } from "fs/promises";
4345
- import path24 from "path";
4453
+ import { readFile as readFile16, writeFile as writeFile6 } from "fs/promises";
4454
+ import path26 from "path";
4455
+
4456
+ // src/scanner/detect-repository.ts
4457
+ import { readFile as readFile12 } from "fs/promises";
4458
+ import path19 from "path";
4459
+
4460
+ // src/scanner/paths.ts
4461
+ var REPOSITORY_PROFILE_REL = ".cursor/agent-kit.config.json";
4346
4462
 
4347
4463
  // src/scanner/detect-repository.ts
4348
- import { readFile as readFile11 } from "fs/promises";
4349
- import path17 from "path";
4350
4464
  var CONTEXT_PATHS = [
4351
4465
  ["README.md", "README"],
4352
4466
  ["README", "README"],
@@ -4365,7 +4479,7 @@ var CONTEXT_PATHS = [
4365
4479
  async function existingEvidence(rootDir, candidates) {
4366
4480
  const evidence = await Promise.all(
4367
4481
  candidates.map(
4368
- async ([relativePath, label]) => await fileExists(path17.join(rootDir, relativePath)) ? { source: "file", value: `${relativePath}:${label}` } : void 0
4482
+ async ([relativePath, label]) => await fileExists(path19.join(rootDir, relativePath)) ? { source: "file", value: `${relativePath}:${label}` } : void 0
4369
4483
  )
4370
4484
  );
4371
4485
  return evidence.flatMap((item) => item ? [item] : []);
@@ -4399,7 +4513,7 @@ function isRepositoryPurpose(value) {
4399
4513
  }
4400
4514
  async function readConfirmedPurpose(rootDir) {
4401
4515
  const configuration = await readJson(
4402
- path17.join(rootDir, ".cursor", "agent-kit.config.json")
4516
+ path19.join(rootDir, REPOSITORY_PROFILE_REL)
4403
4517
  );
4404
4518
  const configuredPurpose = configuration?.purpose;
4405
4519
  if (!configuredPurpose || !isRepositoryPurpose(configuredPurpose.value) || configuredPurpose.value === "unknown") {
@@ -4411,7 +4525,7 @@ async function readConfirmedPurpose(rootDir) {
4411
4525
  value: configuredPurpose.value,
4412
4526
  categories: categories.length > 0 ? categories : [configuredPurpose.value],
4413
4527
  confidence: "high",
4414
- evidence: evidence.length > 0 ? evidence : [{ source: "configuration", value: ".cursor/agent-kit.config.json#purpose.value" }]
4528
+ evidence: evidence.length > 0 ? evidence : [{ source: "configuration", value: `${REPOSITORY_PROFILE_REL}#purpose.value` }]
4415
4529
  };
4416
4530
  }
4417
4531
  async function detectPurpose(rootDir, stack) {
@@ -4419,7 +4533,7 @@ async function detectPurpose(rootDir, stack) {
4419
4533
  if (confirmed) return confirmed;
4420
4534
  const entries = await listDirectory(rootDir);
4421
4535
  const lowerEntries = entries.map((entry) => entry.toLowerCase());
4422
- const packageJson = await readJson(path17.join(rootDir, "package.json"));
4536
+ const packageJson = await readJson(path19.join(rootDir, "package.json"));
4423
4537
  const categories = [];
4424
4538
  const evidence = [];
4425
4539
  const add = (category, value2) => {
@@ -4459,16 +4573,16 @@ async function detectPurpose(rootDir, stack) {
4459
4573
  }
4460
4574
  async function detectAgentKit(rootDir) {
4461
4575
  const manifestRelativePath = ".cursor/agent-kit.json";
4462
- const manifestPath = path17.join(rootDir, manifestRelativePath);
4576
+ const manifestPath = path19.join(rootDir, manifestRelativePath);
4463
4577
  const installed = await fileExists(manifestPath);
4464
4578
  const manifest = installed ? await readJson(manifestPath) : null;
4465
4579
  return {
4466
4580
  installed,
4467
4581
  manifestPath: installed ? manifestRelativePath : void 0,
4468
4582
  version: manifest?.version,
4469
- hasPlans: await fileExists(path17.join(rootDir, ".cursor/plans")),
4470
- hasHandoff: await fileExists(path17.join(rootDir, ".cursor/HANDOFF.md")),
4471
- hasMemory: await fileExists(path17.join(rootDir, ".cursor/memory"))
4583
+ hasPlans: await fileExists(path19.join(rootDir, ".cursor/plans")),
4584
+ hasHandoff: await fileExists(path19.join(rootDir, ".cursor/HANDOFF.md")),
4585
+ hasMemory: await fileExists(path19.join(rootDir, ".cursor/memory"))
4472
4586
  };
4473
4587
  }
4474
4588
  var REQUIRED_SECRET_PATTERNS = [
@@ -4489,9 +4603,9 @@ var KIT_OWNED_IGNORE_PATTERNS = [
4489
4603
  ".cursor/context/mission-timing.json"
4490
4604
  ];
4491
4605
  async function detectSafety(rootDir, trackedFiles) {
4492
- const gitignorePath = path17.join(rootDir, ".gitignore");
4606
+ const gitignorePath = path19.join(rootDir, ".gitignore");
4493
4607
  const hasGitignore = await fileExists(gitignorePath);
4494
- const gitignore = hasGitignore ? await readFile11(gitignorePath, "utf8") : "";
4608
+ const gitignore = hasGitignore ? await readFile12(gitignorePath, "utf8") : "";
4495
4609
  const lines = gitignore.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
4496
4610
  const ignoredSecretPatterns = REQUIRED_SECRET_PATTERNS.filter(
4497
4611
  (pattern) => lines.includes(pattern)
@@ -4500,7 +4614,7 @@ async function detectSafety(rootDir, trackedFiles) {
4500
4614
  (file) => /(^|\/)(\.env(\..+)?|.*\.(key|pem|p12|pfx)|.*credentials.*\.json)$/i.test(file)
4501
4615
  );
4502
4616
  const hookPaths = [".husky", ".git/hooks/pre-commit", "git-hooks/pre-commit"];
4503
- const hasHooks = (await Promise.all(hookPaths.map((item) => fileExists(path17.join(rootDir, item))))).some(Boolean);
4617
+ const hasHooks = (await Promise.all(hookPaths.map((item) => fileExists(path19.join(rootDir, item))))).some(Boolean);
4504
4618
  const guardCandidates = [
4505
4619
  ".husky/pre-commit",
4506
4620
  ".husky/pre-push",
@@ -4509,7 +4623,7 @@ async function detectSafety(rootDir, trackedFiles) {
4509
4623
  ];
4510
4624
  const guardContents = await Promise.all(
4511
4625
  guardCandidates.map(
4512
- async (item) => await fileExists(path17.join(rootDir, item)) ? readFile11(path17.join(rootDir, item), "utf8") : ""
4626
+ async (item) => await fileExists(path19.join(rootDir, item)) ? readFile12(path19.join(rootDir, item), "utf8") : ""
4513
4627
  )
4514
4628
  );
4515
4629
  return {
@@ -4527,11 +4641,11 @@ async function detectSafety(rootDir, trackedFiles) {
4527
4641
  }
4528
4642
 
4529
4643
  // src/scanner/scan.ts
4530
- import path23 from "path";
4644
+ import path25 from "path";
4531
4645
 
4532
4646
  // src/scanner/detect-git.ts
4533
4647
  import { execFile as execFile4 } from "child_process";
4534
- import path18 from "path";
4648
+ import path20 from "path";
4535
4649
  import { promisify as promisify4 } from "util";
4536
4650
  var exec = promisify4(execFile4);
4537
4651
  function remoteHostname(remoteUrl) {
@@ -4555,7 +4669,7 @@ function sanitizeRemoteUrl(remoteUrl) {
4555
4669
  }
4556
4670
  async function detectProvider(rootDir, remoteUrl) {
4557
4671
  const configuration = await readJson(
4558
- path18.join(rootDir, ".cursor", "agent-kit.config.json")
4672
+ path20.join(rootDir, REPOSITORY_PROFILE_REL)
4559
4673
  );
4560
4674
  const configuredProvider = configuration?.git?.provider;
4561
4675
  if (configuredProvider) {
@@ -4564,7 +4678,7 @@ async function detectProvider(rootDir, remoteUrl) {
4564
4678
  provider: configuredProvider,
4565
4679
  providerKind: configuredKind,
4566
4680
  confidence: "high",
4567
- evidence: [{ source: "configuration", value: ".cursor/agent-kit.config.json#git.provider" }]
4681
+ evidence: [{ source: "configuration", value: `${REPOSITORY_PROFILE_REL}#git.provider` }]
4568
4682
  };
4569
4683
  }
4570
4684
  if (!remoteUrl) {
@@ -4612,7 +4726,7 @@ async function detectProvider(rootDir, remoteUrl) {
4612
4726
  evidence: remoteEvidence
4613
4727
  };
4614
4728
  }
4615
- if (await fileExists(path18.join(rootDir, ".gitlab-ci.yml"))) {
4729
+ if (await fileExists(path20.join(rootDir, ".gitlab-ci.yml"))) {
4616
4730
  return {
4617
4731
  provider: "gitlab",
4618
4732
  providerKind: "gitlab-self-hosted",
@@ -4702,11 +4816,11 @@ async function detectGit(rootDir) {
4702
4816
  }
4703
4817
 
4704
4818
  // src/scanner/detect-ide.ts
4705
- import path19 from "path";
4819
+ import path21 from "path";
4706
4820
  async function detectIde(rootDir) {
4707
- const hasCursor = await fileExists(path19.join(rootDir, ".cursor"));
4708
- const hasVSCode = await fileExists(path19.join(rootDir, ".vscode"));
4709
- const hasWindsurf = await fileExists(path19.join(rootDir, ".windsurfrules"));
4821
+ const hasCursor = await fileExists(path21.join(rootDir, ".cursor"));
4822
+ const hasVSCode = await fileExists(path21.join(rootDir, ".vscode"));
4823
+ const hasWindsurf = await fileExists(path21.join(rootDir, ".windsurfrules"));
4710
4824
  if (hasCursor) return { ide: "cursor", plan: "cursor-pro" };
4711
4825
  if (hasVSCode) return { ide: "vscode", plan: "vscode-pro" };
4712
4826
  if (hasWindsurf) return { ide: "windsurf", plan: "windsurf" };
@@ -4714,8 +4828,8 @@ async function detectIde(rootDir) {
4714
4828
  }
4715
4829
 
4716
4830
  // src/scanner/detect-infra.ts
4717
- import { readFile as readFile12, readdir as readdir5 } from "fs/promises";
4718
- import path20 from "path";
4831
+ import { readFile as readFile13, readdir as readdir5 } from "fs/promises";
4832
+ import path22 from "path";
4719
4833
 
4720
4834
  // src/types.ts
4721
4835
  var GIT_PLATFORM_META = {
@@ -4795,7 +4909,7 @@ function extractRunCommands(yaml) {
4795
4909
  return Array.from(new Set(commands));
4796
4910
  }
4797
4911
  async function detectCiRunCommands(rootDir) {
4798
- const workflowsDir = path20.join(rootDir, ".github", "workflows");
4912
+ const workflowsDir = path22.join(rootDir, ".github", "workflows");
4799
4913
  if (!await fileExists(workflowsDir)) return [];
4800
4914
  let entries;
4801
4915
  try {
@@ -4807,7 +4921,7 @@ async function detectCiRunCommands(rootDir) {
4807
4921
  const perFile = await Promise.all(
4808
4922
  workflowFiles.map(async (name) => {
4809
4923
  try {
4810
- return extractRunCommands(await readFile12(path20.join(workflowsDir, name), "utf8"));
4924
+ return extractRunCommands(await readFile13(path22.join(workflowsDir, name), "utf8"));
4811
4925
  } catch {
4812
4926
  return [];
4813
4927
  }
@@ -4816,12 +4930,12 @@ async function detectCiRunCommands(rootDir) {
4816
4930
  return Array.from(new Set(perFile.flat()));
4817
4931
  }
4818
4932
  async function detectInfra(rootDir) {
4819
- const docker = await fileExists(path20.join(rootDir, "Dockerfile")) || await fileExists(path20.join(rootDir, "docker-compose.yml")) || await fileExists(path20.join(rootDir, "docker-compose.yaml"));
4820
- const kubernetes = await fileExists(path20.join(rootDir, "k8s")) || await fileExists(path20.join(rootDir, "kubernetes"));
4933
+ const docker = await fileExists(path22.join(rootDir, "Dockerfile")) || await fileExists(path22.join(rootDir, "docker-compose.yml")) || await fileExists(path22.join(rootDir, "docker-compose.yaml"));
4934
+ const kubernetes = await fileExists(path22.join(rootDir, "k8s")) || await fileExists(path22.join(rootDir, "kubernetes"));
4821
4935
  let ci = "none";
4822
4936
  const ciFiles = [];
4823
4937
  for (const [platform, filePath] of Object.entries(CI_PLATFORM_FILES)) {
4824
- if (await fileExists(path20.join(rootDir, filePath))) {
4938
+ if (await fileExists(path22.join(rootDir, filePath))) {
4825
4939
  if (ci === "none") ci = platform;
4826
4940
  ciFiles.push(filePath);
4827
4941
  }
@@ -4846,12 +4960,12 @@ async function detectInfra(rootDir) {
4846
4960
  ];
4847
4961
  const infrastructureFiles = (await Promise.all(
4848
4962
  infrastructureCandidates.map(
4849
- async (file) => await fileExists(path20.join(rootDir, file)) ? file : void 0
4963
+ async (file) => await fileExists(path22.join(rootDir, file)) ? file : void 0
4850
4964
  )
4851
4965
  )).filter((file) => file !== void 0);
4852
4966
  const deploymentFiles = (await Promise.all(
4853
4967
  deploymentCandidates.map(
4854
- async (file) => await fileExists(path20.join(rootDir, file)) ? file : void 0
4968
+ async (file) => await fileExists(path22.join(rootDir, file)) ? file : void 0
4855
4969
  )
4856
4970
  )).filter((file) => file !== void 0);
4857
4971
  const ciRunCommands = ci === "github-actions" ? await detectCiRunCommands(rootDir) : [];
@@ -4859,18 +4973,18 @@ async function detectInfra(rootDir) {
4859
4973
  }
4860
4974
 
4861
4975
  // src/scanner/detect-services.ts
4862
- import { readFile as readFile13 } from "fs/promises";
4863
- import path21 from "path";
4976
+ import { readFile as readFile14 } from "fs/promises";
4977
+ import path23 from "path";
4864
4978
  async function detectProjectManagement(rootDir) {
4865
4979
  const tools = [];
4866
4980
  const mcpConfigPaths = [
4867
- path21.join(rootDir, ".cursor", "mcp.json"),
4868
- path21.join(rootDir, "mcp.json")
4981
+ path23.join(rootDir, ".cursor", "mcp.json"),
4982
+ path23.join(rootDir, "mcp.json")
4869
4983
  ];
4870
4984
  for (const configPath of mcpConfigPaths) {
4871
4985
  if (!await fileExists(configPath)) continue;
4872
4986
  try {
4873
- const raw = await readFile13(configPath, "utf8");
4987
+ const raw = await readFile14(configPath, "utf8");
4874
4988
  const lower = raw.toLowerCase();
4875
4989
  if (lower.includes("clickup")) tools.push("clickup");
4876
4990
  if (lower.includes("jira") || lower.includes("atlassian")) tools.push("jira");
@@ -4881,20 +4995,20 @@ async function detectProjectManagement(rootDir) {
4881
4995
  } catch {
4882
4996
  }
4883
4997
  }
4884
- if (await fileExists(path21.join(rootDir, ".github", "ISSUE_TEMPLATE"))) {
4998
+ if (await fileExists(path23.join(rootDir, ".github", "ISSUE_TEMPLATE"))) {
4885
4999
  tools.push("github-issues");
4886
5000
  }
4887
- if (await fileExists(path21.join(rootDir, ".github", "projects"))) {
5001
+ if (await fileExists(path23.join(rootDir, ".github", "projects"))) {
4888
5002
  tools.push("github-projects");
4889
5003
  }
4890
5004
  return [...new Set(tools)];
4891
5005
  }
4892
5006
  async function detectServices(rootDir) {
4893
- const hasPrisma = await fileExists(path21.join(rootDir, "prisma/schema.prisma"));
4894
- const hasSequelize = await fileExists(path21.join(rootDir, "sequelize"));
4895
- const hasDrizzle = await fileExists(path21.join(rootDir, "drizzle.config.ts"));
4896
- const hasKnex = await fileExists(path21.join(rootDir, "knexfile.ts"));
4897
- const hasTypeorm = await fileExists(path21.join(rootDir, "ormconfig.json"));
5007
+ const hasPrisma = await fileExists(path23.join(rootDir, "prisma/schema.prisma"));
5008
+ const hasSequelize = await fileExists(path23.join(rootDir, "sequelize"));
5009
+ const hasDrizzle = await fileExists(path23.join(rootDir, "drizzle.config.ts"));
5010
+ const hasKnex = await fileExists(path23.join(rootDir, "knexfile.ts"));
5011
+ const hasTypeorm = await fileExists(path23.join(rootDir, "ormconfig.json"));
4898
5012
  const database = hasPrisma || hasSequelize || hasDrizzle || hasKnex || hasTypeorm ? "postgresql" : void 0;
4899
5013
  const orm = hasPrisma ? "prisma" : hasDrizzle ? "drizzle" : hasSequelize ? "sequelize" : hasKnex ? "knex" : hasTypeorm ? "typeorm" : void 0;
4900
5014
  const projectManagement = await detectProjectManagement(rootDir);
@@ -4906,8 +5020,8 @@ async function detectServices(rootDir) {
4906
5020
  }
4907
5021
 
4908
5022
  // src/scanner/detect-stack.ts
4909
- import { readFile as readFile14, readdir as readdir6 } from "fs/promises";
4910
- import path22 from "path";
5023
+ import { readFile as readFile15, readdir as readdir6 } from "fs/promises";
5024
+ import path24 from "path";
4911
5025
  var PROJECT_MARKERS = [
4912
5026
  "package.json",
4913
5027
  "requirements.txt",
@@ -4933,7 +5047,7 @@ async function scanSubdirectoryMarkers(rootDir) {
4933
5047
  const candidates = dirs.flatMap((dir) => PROJECT_MARKERS.map((marker) => ({ dir, marker })));
4934
5048
  const found = await Promise.all(
4935
5049
  candidates.map(async (candidate2) => {
4936
- const exists2 = await fileExists(path22.join(rootDir, candidate2.dir, candidate2.marker));
5050
+ const exists2 = await fileExists(path24.join(rootDir, candidate2.dir, candidate2.marker));
4937
5051
  return exists2 ? candidate2 : null;
4938
5052
  })
4939
5053
  );
@@ -4949,7 +5063,7 @@ var DART_VALIDATION_COMMANDS = [
4949
5063
  async function detectDartFlavor(pubspecDir) {
4950
5064
  let content = "";
4951
5065
  try {
4952
- content = await readFile14(path22.join(pubspecDir, "pubspec.yaml"), "utf8");
5066
+ content = await readFile15(path24.join(pubspecDir, "pubspec.yaml"), "utf8");
4953
5067
  } catch {
4954
5068
  }
4955
5069
  return { isFlutter: isFlutterPubspec(content) };
@@ -4962,7 +5076,7 @@ async function detectStackFromSubdirHits(rootDir, hits) {
4962
5076
  const dartHits = hits.filter((hit) => hit.marker === "pubspec.yaml");
4963
5077
  if (dartHits.length > 0) {
4964
5078
  const flavors = await Promise.all(
4965
- dartHits.map((hit) => detectDartFlavor(path22.join(rootDir, hit.dir)))
5079
+ dartHits.map((hit) => detectDartFlavor(path24.join(rootDir, hit.dir)))
4966
5080
  );
4967
5081
  const testCommands = Array.from(
4968
5082
  new Set(flavors.map((flavor) => flavor.isFlutter ? "flutter test" : "dart test"))
@@ -4979,8 +5093,8 @@ async function detectStackFromSubdirHits(rootDir, hits) {
4979
5093
  }
4980
5094
  const nodeHit = hits.find((hit) => hit.marker === "package.json");
4981
5095
  if (nodeHit) {
4982
- const subRoot = path22.join(rootDir, nodeHit.dir);
4983
- const packageJson = await readJson(path22.join(subRoot, "package.json")) ?? {};
5096
+ const subRoot = path24.join(rootDir, nodeHit.dir);
5097
+ const packageJson = await readJson(path24.join(subRoot, "package.json")) ?? {};
4984
5098
  const scripts = packageJson.scripts ?? {};
4985
5099
  const packageManager = await detectPackageManager(subRoot, packageJson);
4986
5100
  const commands = commandsForScripts(scripts, packageManager.packageManager);
@@ -5037,7 +5151,7 @@ function isDetectionEvidenceArray(value) {
5037
5151
  }
5038
5152
  async function readConfirmedStack(rootDir) {
5039
5153
  const configuration = await readJson(
5040
- path22.join(rootDir, ".cursor", "agent-kit.config.json")
5154
+ path24.join(rootDir, REPOSITORY_PROFILE_REL)
5041
5155
  );
5042
5156
  const configured = configuration?.stack;
5043
5157
  const language = configured?.language;
@@ -5051,7 +5165,7 @@ async function readConfirmedStack(rootDir) {
5051
5165
  const scripts = configured.scripts && typeof configured.scripts === "object" && !Array.isArray(configured.scripts) ? configured.scripts : void 0;
5052
5166
  const packageManagerEvidence = isDetectionEvidenceArray(
5053
5167
  configured.packageManagerEvidence
5054
- ) ? configured.packageManagerEvidence : [{ source: "configuration", value: ".cursor/agent-kit.config.json#stack.language" }];
5168
+ ) ? configured.packageManagerEvidence : [{ source: "configuration", value: `${REPOSITORY_PROFILE_REL}#stack.language` }];
5055
5169
  return {
5056
5170
  language,
5057
5171
  framework: typeof configured.framework === "string" ? configured.framework : void 0,
@@ -5080,7 +5194,7 @@ async function detectPackageManager(rootDir, packageJson) {
5080
5194
  };
5081
5195
  }
5082
5196
  for (const [lockfile, packageManager] of LOCKFILES) {
5083
- if (await fileExists(path22.join(rootDir, lockfile))) {
5197
+ if (await fileExists(path24.join(rootDir, lockfile))) {
5084
5198
  return {
5085
5199
  packageManager,
5086
5200
  evidence: [{ source: "file", value: lockfile }]
@@ -5099,33 +5213,33 @@ function commandsForScripts(scripts, packageManager) {
5099
5213
  async function detectStack(rootDir) {
5100
5214
  const confirmed = await readConfirmedStack(rootDir);
5101
5215
  if (confirmed) return confirmed;
5102
- const hasAnyProjectMarker = (await Promise.all(PROJECT_MARKERS.map((item) => fileExists(path22.join(rootDir, item))))).some(Boolean);
5216
+ const hasAnyProjectMarker = (await Promise.all(PROJECT_MARKERS.map((item) => fileExists(path24.join(rootDir, item))))).some(Boolean);
5103
5217
  if (!hasAnyProjectMarker) {
5104
5218
  const subdirHits = await scanSubdirectoryMarkers(rootDir);
5105
5219
  if (subdirHits.length > 0) {
5106
5220
  return detectStackFromSubdirHits(rootDir, subdirHits);
5107
5221
  }
5108
5222
  }
5109
- const hasPackageJson = await fileExists(path22.join(rootDir, "package.json"));
5223
+ const hasPackageJson = await fileExists(path24.join(rootDir, "package.json"));
5110
5224
  if (hasPackageJson) {
5111
- const packageJson = await readJson(path22.join(rootDir, "package.json")) ?? {};
5225
+ const packageJson = await readJson(path24.join(rootDir, "package.json")) ?? {};
5112
5226
  const scripts = packageJson.scripts ?? {};
5113
5227
  const packageManager = await detectPackageManager(rootDir, packageJson);
5114
5228
  const commands = commandsForScripts(scripts, packageManager.packageManager);
5115
- const hasNextConfig = await fileExists(path22.join(rootDir, "next.config.js")) || await fileExists(path22.join(rootDir, "next.config.mjs")) || await fileExists(path22.join(rootDir, "next.config.ts"));
5116
- const hasNestConfig = await fileExists(path22.join(rootDir, "nest-cli.json"));
5229
+ const hasNextConfig = await fileExists(path24.join(rootDir, "next.config.js")) || await fileExists(path24.join(rootDir, "next.config.mjs")) || await fileExists(path24.join(rootDir, "next.config.ts"));
5230
+ const hasNestConfig = await fileExists(path24.join(rootDir, "nest-cli.json"));
5117
5231
  return {
5118
5232
  language: "node",
5119
5233
  framework: hasNextConfig ? "nextjs" : hasNestConfig ? "nestjs" : "node",
5120
5234
  packageManager: packageManager.packageManager,
5121
5235
  packageManagerEvidence: packageManager.evidence,
5122
5236
  scripts,
5123
- workspaces: packageJson.workspaces !== void 0 || await fileExists(path22.join(rootDir, "pnpm-workspace.yaml")),
5237
+ workspaces: packageJson.workspaces !== void 0 || await fileExists(path24.join(rootDir, "pnpm-workspace.yaml")),
5124
5238
  ...commands,
5125
5239
  hasProjectFiles: hasAnyProjectMarker
5126
5240
  };
5127
5241
  }
5128
- if (await fileExists(path22.join(rootDir, "pyproject.toml"))) {
5242
+ if (await fileExists(path24.join(rootDir, "pyproject.toml"))) {
5129
5243
  return {
5130
5244
  language: "python",
5131
5245
  framework: "python",
@@ -5135,7 +5249,7 @@ async function detectStack(rootDir) {
5135
5249
  hasProjectFiles: hasAnyProjectMarker
5136
5250
  };
5137
5251
  }
5138
- if (await fileExists(path22.join(rootDir, "go.mod"))) {
5252
+ if (await fileExists(path24.join(rootDir, "go.mod"))) {
5139
5253
  return {
5140
5254
  language: "go",
5141
5255
  framework: "go",
@@ -5145,7 +5259,7 @@ async function detectStack(rootDir) {
5145
5259
  hasProjectFiles: hasAnyProjectMarker
5146
5260
  };
5147
5261
  }
5148
- if (await fileExists(path22.join(rootDir, "Cargo.toml"))) {
5262
+ if (await fileExists(path24.join(rootDir, "Cargo.toml"))) {
5149
5263
  return {
5150
5264
  language: "rust",
5151
5265
  framework: "rust",
@@ -5155,7 +5269,7 @@ async function detectStack(rootDir) {
5155
5269
  hasProjectFiles: hasAnyProjectMarker
5156
5270
  };
5157
5271
  }
5158
- if (await fileExists(path22.join(rootDir, "composer.json"))) {
5272
+ if (await fileExists(path24.join(rootDir, "composer.json"))) {
5159
5273
  return {
5160
5274
  language: "php",
5161
5275
  framework: "php",
@@ -5165,7 +5279,7 @@ async function detectStack(rootDir) {
5165
5279
  hasProjectFiles: hasAnyProjectMarker
5166
5280
  };
5167
5281
  }
5168
- if (await fileExists(path22.join(rootDir, "pubspec.yaml"))) {
5282
+ if (await fileExists(path24.join(rootDir, "pubspec.yaml"))) {
5169
5283
  const { isFlutter } = await detectDartFlavor(rootDir);
5170
5284
  return {
5171
5285
  language: "dart",
@@ -5199,7 +5313,7 @@ function isGreenfieldByEntries(entries) {
5199
5313
  return meaningful.length === 0;
5200
5314
  }
5201
5315
  async function runScanner(rootDir) {
5202
- const normalizedRoot = path23.resolve(rootDir);
5316
+ const normalizedRoot = path25.resolve(rootDir);
5203
5317
  const entries = await listDirectory(normalizedRoot);
5204
5318
  const stack = await detectStack(normalizedRoot);
5205
5319
  const purpose = await detectPurpose(normalizedRoot, stack);
@@ -5237,8 +5351,7 @@ async function runScanner(rootDir) {
5237
5351
  }
5238
5352
 
5239
5353
  // src/scanner/safe-fixes.ts
5240
- var PROFILE_RELATIVE_PATH = ".cursor/agent-kit.config.json";
5241
- var CONTEXT_CONFIG_RELATIVE_PATH = ".cursor/context/config.json";
5354
+ var CONTEXT_CONFIG_REL_POSIX = CONTEXT_CONFIG_REL.replace(/\\/g, "/");
5242
5355
  var ESSENTIAL_DIRECTORIES = [
5243
5356
  ".cursor",
5244
5357
  ".cursor/context",
@@ -5423,7 +5536,7 @@ async function refreshRepositoryProfile(rootDir, options) {
5423
5536
  generatedAt
5424
5537
  });
5425
5538
  const desiredProfile = createProfile(scan, report, generatedAt);
5426
- const profilePath = path24.join(scan.rootDir, PROFILE_RELATIVE_PATH);
5539
+ const profilePath = path26.join(scan.rootDir, REPOSITORY_PROFILE_REL);
5427
5540
  const existingProfile = await readJson(profilePath) ?? {};
5428
5541
  const reconciled = reconcileFreshOverExisting(desiredProfile, existingProfile);
5429
5542
  const meaningfulChange = !jsonEqual(
@@ -5446,7 +5559,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
5446
5559
  });
5447
5560
  const changes = [];
5448
5561
  for (const relativePath of ESSENTIAL_DIRECTORIES) {
5449
- const absolutePath = path24.join(beforeScan.rootDir, relativePath);
5562
+ const absolutePath = path26.join(beforeScan.rootDir, relativePath);
5450
5563
  const exists2 = await fileExists(absolutePath);
5451
5564
  if (!exists2 && !dryRun) await ensureDir(absolutePath);
5452
5565
  recordChange(
@@ -5459,14 +5572,14 @@ async function executeSafeReadinessFixes(rootDir, options) {
5459
5572
  );
5460
5573
  }
5461
5574
  const gitignoreRelativePath = ".gitignore";
5462
- const gitignorePath = path24.join(beforeScan.rootDir, gitignoreRelativePath);
5463
- const existingGitignore = await fileExists(gitignorePath) ? await readFile15(gitignorePath, "utf8") : "";
5575
+ const gitignorePath = path26.join(beforeScan.rootDir, gitignoreRelativePath);
5576
+ const existingGitignore = await fileExists(gitignorePath) ? await readFile16(gitignorePath, "utf8") : "";
5464
5577
  const gitignoreAfterSecrets = mergeSecretIgnores(existingGitignore);
5465
5578
  const secretsChanged = gitignoreAfterSecrets !== existingGitignore;
5466
5579
  const mergedGitignore = mergeKitOwnedIgnores(gitignoreAfterSecrets);
5467
5580
  const gitignoreChanged = mergedGitignore !== existingGitignore;
5468
5581
  const kitOwnedChanged = mergedGitignore !== gitignoreAfterSecrets;
5469
- if (gitignoreChanged && !dryRun) await writeFile5(gitignorePath, mergedGitignore, "utf8");
5582
+ if (gitignoreChanged && !dryRun) await writeFile6(gitignorePath, mergedGitignore, "utf8");
5470
5583
  recordChange(
5471
5584
  changes,
5472
5585
  "merge-secret-ignores",
@@ -5489,7 +5602,7 @@ async function executeSafeReadinessFixes(rootDir, options) {
5489
5602
  kitOwnedChanged ? "kit-owned session/derived paths are missing" : "kit-owned session/derived paths are present"
5490
5603
  )
5491
5604
  );
5492
- const profilePath = path24.join(beforeScan.rootDir, PROFILE_RELATIVE_PATH);
5605
+ const profilePath = path26.join(beforeScan.rootDir, REPOSITORY_PROFILE_REL);
5493
5606
  const existingProfile = await readJson(profilePath) ?? {};
5494
5607
  const desiredProfile = createProfile(beforeScan, before, generatedAt);
5495
5608
  const mergedProfile = mergeMissing(existingProfile, desiredProfile);
@@ -5498,11 +5611,11 @@ async function executeSafeReadinessFixes(rootDir, options) {
5498
5611
  recordChange(
5499
5612
  changes,
5500
5613
  "merge-repository-profile",
5501
- PROFILE_RELATIVE_PATH,
5614
+ REPOSITORY_PROFILE_REL,
5502
5615
  profileChanged,
5503
5616
  dryRun,
5504
5617
  relativeEvidence(
5505
- PROFILE_RELATIVE_PATH,
5618
+ REPOSITORY_PROFILE_REL,
5506
5619
  profileChanged ? "missing scanner-derived facts" : "existing facts preserved"
5507
5620
  )
5508
5621
  );
@@ -5511,22 +5624,22 @@ async function executeSafeReadinessFixes(rootDir, options) {
5511
5624
  generatorVersion: options.generatorVersion,
5512
5625
  generatedAt
5513
5626
  });
5514
- const contextConfigPath = path24.join(beforeScan.rootDir, CONTEXT_CONFIG_RELATIVE_PATH);
5515
- const existingContextConfig = await readJson(contextConfigPath) ?? {};
5627
+ const configPath = contextConfigPath(beforeScan.rootDir);
5628
+ const existingContextConfig = await readJson(configPath) ?? {};
5516
5629
  const onboarding = reconcileOnboardingState(evidenceReport, existingContextConfig, generatedAt);
5517
5630
  const defaults = preferenceDefaults(onboarding, existingContextConfig.onboarded);
5518
5631
  const mergedContextConfig = mergeMissing(existingContextConfig, defaults);
5519
5632
  mergedContextConfig.onboarding = onboarding;
5520
5633
  const contextConfigChanged = !jsonEqual(existingContextConfig, mergedContextConfig);
5521
- if (contextConfigChanged && !dryRun) await writeJson(contextConfigPath, mergedContextConfig);
5634
+ if (contextConfigChanged && !dryRun) await writeJson(configPath, mergedContextConfig);
5522
5635
  recordChange(
5523
5636
  changes,
5524
5637
  "merge-onboarding-state",
5525
- CONTEXT_CONFIG_RELATIVE_PATH,
5638
+ CONTEXT_CONFIG_REL_POSIX,
5526
5639
  contextConfigChanged,
5527
5640
  dryRun,
5528
5641
  relativeEvidence(
5529
- CONTEXT_CONFIG_RELATIVE_PATH,
5642
+ CONTEXT_CONFIG_REL_POSIX,
5530
5643
  contextConfigChanged ? "missing preferences or onboarding state" : "state already merged"
5531
5644
  )
5532
5645
  );
@@ -5540,10 +5653,10 @@ async function executeSafeReadinessFixes(rootDir, options) {
5540
5653
  }
5541
5654
 
5542
5655
  // src/scanner/snapshot.ts
5543
- import path25 from "path";
5656
+ import path27 from "path";
5544
5657
  var READINESS_SNAPSHOT_RELATIVE_PATH = ".cursor/context/readiness.json";
5545
5658
  async function writeReadinessSnapshot(rootDir, report) {
5546
- const snapshotPath = path25.join(rootDir, READINESS_SNAPSHOT_RELATIVE_PATH);
5659
+ const snapshotPath = path27.join(rootDir, READINESS_SNAPSHOT_RELATIVE_PATH);
5547
5660
  await writeJson(snapshotPath, report);
5548
5661
  return snapshotPath;
5549
5662
  }
@@ -5735,7 +5848,7 @@ async function withCliProgress(label, fn, opts) {
5735
5848
  // src/commands/doctor.ts
5736
5849
  async function readDeferredEssentials(rootDir, report) {
5737
5850
  const config = await readJson(
5738
- path26.join(rootDir, ".cursor", "context", "config.json")
5851
+ path28.join(rootDir, ".cursor", "context", "config.json")
5739
5852
  );
5740
5853
  const deferredItems = config?.onboarding?.deferredItems;
5741
5854
  if (!Array.isArray(deferredItems)) return [];
@@ -5747,7 +5860,7 @@ async function readDeferredEssentials(rootDir, report) {
5747
5860
  ).map((item) => ({ checkId: item.checkId, reason: item.reason }));
5748
5861
  }
5749
5862
  async function runDoctor(cwd, options = {}) {
5750
- const rootDir = path26.resolve(cwd);
5863
+ const rootDir = path28.resolve(cwd);
5751
5864
  const hooks = await assessHooksHealth(rootDir);
5752
5865
  const env = await assessEnvironment();
5753
5866
  if (options.fixSafe) {
@@ -6275,8 +6388,8 @@ var guardCommand = defineCommand8({
6275
6388
 
6276
6389
  // src/commands/handoff.ts
6277
6390
  import { spawn as spawn4 } from "child_process";
6278
- import { appendFile, readFile as readFile16, readdir as readdir7, writeFile as writeFile6 } from "fs/promises";
6279
- import path27 from "path";
6391
+ import { appendFile, readFile as readFile17, readdir as readdir7, writeFile as writeFile7 } from "fs/promises";
6392
+ import path29 from "path";
6280
6393
  import { defineCommand as defineCommand9 } from "citty";
6281
6394
 
6282
6395
  // src/invariants/handoff-prune.ts
@@ -6417,12 +6530,12 @@ function pruneArchiveTimestamp(now2 = /* @__PURE__ */ new Date()) {
6417
6530
  return `${now2.getFullYear()}-${pad(now2.getMonth() + 1)}-${pad(now2.getDate())}-${pad(now2.getHours())}${pad(now2.getMinutes())}`;
6418
6531
  }
6419
6532
  async function runPrune(cwd, keep) {
6420
- const handoffPath = path27.join(cwd, ".cursor", "HANDOFF.md");
6533
+ const handoffPath = path29.join(cwd, ".cursor", "HANDOFF.md");
6421
6534
  if (!await fileExists(handoffPath)) {
6422
6535
  logger.warn("No .cursor/HANDOFF.md to prune.");
6423
6536
  return;
6424
6537
  }
6425
- const original = await readFile16(handoffPath, "utf8");
6538
+ const original = await readFile17(handoffPath, "utf8");
6426
6539
  const result = pruneHandoffText(original, keep);
6427
6540
  if (!result.ok) {
6428
6541
  logger.warn(`Refusing to prune: ${result.reason}`);
@@ -6435,9 +6548,9 @@ async function runPrune(cwd, keep) {
6435
6548
  );
6436
6549
  return;
6437
6550
  }
6438
- const archiveDir = path27.join(cwd, ".cursor", "context", "archive");
6551
+ const archiveDir = path29.join(cwd, ".cursor", "context", "archive");
6439
6552
  await ensureDir(archiveDir);
6440
- const archivePath = path27.join(archiveDir, `handoff-${pruneArchiveTimestamp()}.md`);
6553
+ const archivePath = path29.join(archiveDir, `handoff-${pruneArchiveTimestamp()}.md`);
6441
6554
  const header = [
6442
6555
  `<!-- Pruned from .cursor/HANDOFF.md at ${(/* @__PURE__ */ new Date()).toISOString()} -->`,
6443
6556
  `<!-- ${result.archived.length} narrative ${result.archived.length === 1 ? "entry" : "entries"} archived, keep=${keep} -->`,
@@ -6449,11 +6562,11 @@ async function runPrune(cwd, keep) {
6449
6562
  await appendFile(archivePath, `
6450
6563
  ${header}${body}`, "utf8");
6451
6564
  } else {
6452
- await writeFile6(archivePath, `${header}${body}`, "utf8");
6565
+ await writeFile7(archivePath, `${header}${body}`, "utf8");
6453
6566
  }
6454
- await writeFile6(handoffPath, result.text ?? original, "utf8");
6567
+ await writeFile7(handoffPath, result.text ?? original, "utf8");
6455
6568
  logger.success(
6456
- `HANDOFF.md pruned: kept ${result.keptCount} narrative ${result.keptCount === 1 ? "entry" : "entries"}, archived ${result.archived.length} to ${path27.relative(cwd, archivePath)}.`
6569
+ `HANDOFF.md pruned: kept ${result.keptCount} narrative ${result.keptCount === 1 ? "entry" : "entries"}, archived ${result.archived.length} to ${path29.relative(cwd, archivePath)}.`
6457
6570
  );
6458
6571
  }
6459
6572
  function parsePlanFrontmatter(raw) {
@@ -6474,19 +6587,19 @@ async function findActivePlan(plansDir) {
6474
6587
  if (!await fileExists(plansDir)) return null;
6475
6588
  const files = (await readdir7(plansDir)).filter((f) => f.endsWith(".plan.md")).sort().reverse();
6476
6589
  for (const file of files) {
6477
- const raw = await readFile16(path27.join(plansDir, file), "utf8");
6590
+ const raw = await readFile17(path29.join(plansDir, file), "utf8");
6478
6591
  const fm = parsePlanFrontmatter(raw);
6479
6592
  if (fm?.todos?.some((t) => t.status !== "completed" && t.status !== "cancelled")) {
6480
6593
  return { file, raw };
6481
6594
  }
6482
6595
  }
6483
- return files[0] ? { file: files[0], raw: await readFile16(path27.join(plansDir, files[0]), "utf8") } : null;
6596
+ return files[0] ? { file: files[0], raw: await readFile17(path29.join(plansDir, files[0]), "utf8") } : null;
6484
6597
  }
6485
6598
  function now() {
6486
6599
  return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 16);
6487
6600
  }
6488
6601
  async function loadProfile(rootDir) {
6489
- const configPath = path27.join(rootDir, ".cursor", "agent-kit.config.json");
6602
+ const configPath = path29.join(rootDir, ".cursor", "agent-kit.config.json");
6490
6603
  try {
6491
6604
  return await readJson(configPath);
6492
6605
  } catch {
@@ -6601,15 +6714,15 @@ var handoffCommand = defineCommand9({
6601
6714
  return;
6602
6715
  }
6603
6716
  const profile = await loadProfile(args.cwd);
6604
- const plansDir = path27.join(args.cwd, ".cursor", "plans");
6605
- const handoffPath = path27.join(args.cwd, ".cursor", "HANDOFF.md");
6717
+ const plansDir = path29.join(args.cwd, ".cursor", "plans");
6718
+ const handoffPath = path29.join(args.cwd, ".cursor", "HANDOFF.md");
6606
6719
  const plan = await findActivePlan(plansDir);
6607
6720
  if (plan) {
6608
6721
  const fm = parsePlanFrontmatter(plan.raw);
6609
6722
  if (fm) {
6610
- await ensureDir(path27.join(args.cwd, ".cursor"));
6723
+ await ensureDir(path29.join(args.cwd, ".cursor"));
6611
6724
  const content = buildHandoff(plan.file, fm, profile);
6612
- await writeFile6(handoffPath, content, "utf8");
6725
+ await writeFile7(handoffPath, content, "utf8");
6613
6726
  logger.success("HANDOFF.md updated: .cursor/HANDOFF.md");
6614
6727
  logger.info(
6615
6728
  `Plan: ${plan.file} (${fm.todos?.filter((t) => t.status === "completed").length}/${fm.todos?.length} completed)`
@@ -6627,7 +6740,7 @@ var handoffCommand = defineCommand9({
6627
6740
  }
6628
6741
  logger.warn(`Plan ${plan.file} without valid frontmatter; trying legacy flow.`);
6629
6742
  }
6630
- const scriptPath = path27.join(args.cwd, "cursor-handoff");
6743
+ const scriptPath = path29.join(args.cwd, "cursor-handoff");
6631
6744
  if (!await fileExists(scriptPath)) {
6632
6745
  printV3Guidance();
6633
6746
  return;
@@ -6652,7 +6765,7 @@ var handoffCommand = defineCommand9({
6652
6765
  });
6653
6766
 
6654
6767
  // src/commands/hook.ts
6655
- import path30 from "path";
6768
+ import path32 from "path";
6656
6769
  import { defineCommand as defineCommand10 } from "citty";
6657
6770
 
6658
6771
  // src/hooks/format-session-start.ts
@@ -6678,8 +6791,8 @@ function buildPreCompactUserMessage(payload = {}) {
6678
6791
 
6679
6792
  // src/hooks/session-start.ts
6680
6793
  import { spawn as spawn5 } from "child_process";
6681
- import { access as access7, readFile as readFile18, stat as stat4 } from "fs/promises";
6682
- import path29 from "path";
6794
+ import { readFile as readFile19, stat as stat4 } from "fs/promises";
6795
+ import path31 from "path";
6683
6796
 
6684
6797
  // src/invariants/handoff-schema.ts
6685
6798
  var MACHINE_LIST_CHECKS = [
@@ -6721,8 +6834,8 @@ function validateHandoffText(text) {
6721
6834
  }
6722
6835
 
6723
6836
  // src/plan-index/plan-index.ts
6724
- import { readFile as readFile17, writeFile as writeFile7 } from "fs/promises";
6725
- import path28 from "path";
6837
+ import { readFile as readFile18, writeFile as writeFile8 } from "fs/promises";
6838
+ import path30 from "path";
6726
6839
  var PLAN_INDEX_REL = ".cursor/context/plan-index.json";
6727
6840
  var NONE = /^(none|n\/a|empty|nil)$/i;
6728
6841
  var OPEN_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress"]);
@@ -6730,14 +6843,14 @@ function defaultPlanIndexIo() {
6730
6843
  return {
6731
6844
  async readFile(absPath) {
6732
6845
  try {
6733
- return await readFile17(absPath, "utf8");
6846
+ return await readFile18(absPath, "utf8");
6734
6847
  } catch {
6735
6848
  return null;
6736
6849
  }
6737
6850
  },
6738
6851
  async writeFile(absPath, body) {
6739
- await ensureDir(path28.dirname(absPath));
6740
- await writeFile7(absPath, body, "utf8");
6852
+ await ensureDir(path30.dirname(absPath));
6853
+ await writeFile8(absPath, body, "utf8");
6741
6854
  }
6742
6855
  };
6743
6856
  }
@@ -6762,11 +6875,11 @@ function collectNamedPlanBasenames(named) {
6762
6875
  return out;
6763
6876
  }
6764
6877
  function namedPlanCandidatePaths(root, basename) {
6765
- const safe = path28.basename(basename);
6878
+ const safe = path30.basename(basename);
6766
6879
  if (!/^[A-Za-z0-9._-]+\.plan\.md$/i.test(safe)) return [];
6767
6880
  return [
6768
- path28.join(root, ".cursor", "plans", safe),
6769
- path28.join(root, ".cursor", "plans", "archive", safe)
6881
+ path30.join(root, ".cursor", "plans", safe),
6882
+ path30.join(root, ".cursor", "plans", "archive", safe)
6770
6883
  ];
6771
6884
  }
6772
6885
  function classifyPlanRole(file, named, openTodos) {
@@ -6798,7 +6911,7 @@ function parsePlanFrontmatter2(raw) {
6798
6911
  return { name, todos };
6799
6912
  }
6800
6913
  async function buildPlanIndex(root, io = defaultPlanIndexIo(), now2 = () => /* @__PURE__ */ new Date()) {
6801
- const handoffPath = path28.join(root, ".cursor", "HANDOFF.md");
6914
+ const handoffPath = path30.join(root, HANDOFF_REL);
6802
6915
  const handoffText = await io.readFile(handoffPath) ?? "";
6803
6916
  const named = extractHandoffNamedPlans(handoffText);
6804
6917
  const plans = [];
@@ -6827,7 +6940,7 @@ async function buildPlanIndex(root, io = defaultPlanIndexIo(), now2 = () => /* @
6827
6940
  }
6828
6941
  async function writePlanIndex(root, io = defaultPlanIndexIo(), now2 = () => /* @__PURE__ */ new Date()) {
6829
6942
  const index = await buildPlanIndex(root, io, now2);
6830
- const dest = path28.join(root, PLAN_INDEX_REL);
6943
+ const dest = path30.join(root, PLAN_INDEX_REL);
6831
6944
  const write = io.writeFile ?? defaultPlanIndexIo().writeFile;
6832
6945
  if (write) {
6833
6946
  await write(dest, `${JSON.stringify(index, null, 2)}
@@ -7066,19 +7179,11 @@ var NONE_PLACEHOLDERS = /* @__PURE__ */ new Set(["none", "n/a", "empty", "nil"])
7066
7179
  var CURSOR_AWARENESS_SPAWN_TIMEOUT_MS = CHANGELOG_FETCH_TIMEOUT_MS + 3e3;
7067
7180
  async function readFull(filePath) {
7068
7181
  try {
7069
- return await readFile18(filePath, "utf8");
7182
+ return await readFile19(filePath, "utf8");
7070
7183
  } catch {
7071
7184
  return "";
7072
7185
  }
7073
7186
  }
7074
- async function fileExists2(p) {
7075
- try {
7076
- await access7(p);
7077
- return true;
7078
- } catch {
7079
- return false;
7080
- }
7081
- }
7082
7187
  function isMarkdownTableSeparator(line) {
7083
7188
  const stripped = line.trim();
7084
7189
  if (!stripped.startsWith("|")) return false;
@@ -7140,8 +7245,7 @@ function extractUnprocessedDogfoodLine(line) {
7140
7245
  return raw;
7141
7246
  }
7142
7247
  async function l0Present(root) {
7143
- const cursor = path29.join(root, ".cursor");
7144
- return await fileExists2(path29.join(cursor, "agent-kit.json")) || await fileExists2(path29.join(cursor, "commands", "agent-kit-onboard.md")) || await fileExists2(path29.join(cursor, "commands", "start-project.md"));
7248
+ return await fileExists(path31.join(root, MANIFEST_RELATIVE_PATH)) || await fileExists(path31.join(root, ".cursor", "commands", "agent-kit-onboard.md")) || await fileExists(path31.join(root, ".cursor", "commands", "start-project.md"));
7145
7249
  }
7146
7250
  function checkLabelAndRecommendation(check2) {
7147
7251
  const checkId = check2.id;
@@ -7180,10 +7284,10 @@ function unresolvedReadinessChecks(data) {
7180
7284
  return { essential, nonessential };
7181
7285
  }
7182
7286
  async function readinessSection(root) {
7183
- const snapshotPath = path29.join(root, ".cursor", "context", "readiness.json");
7287
+ const snapshotPath = path31.join(root, READINESS_SNAPSHOT_RELATIVE_PATH);
7184
7288
  let data;
7185
7289
  try {
7186
- data = JSON.parse(await readFile18(snapshotPath, "utf8"));
7290
+ data = JSON.parse(await readFile19(snapshotPath, "utf8"));
7187
7291
  } catch {
7188
7292
  return null;
7189
7293
  }
@@ -7214,13 +7318,13 @@ Optional readiness item: \`${first.id}\`. ${first.recommendation} This does not
7214
7318
  }
7215
7319
  async function dogfoodInboxSection(root) {
7216
7320
  const candidateReadmes = [
7217
- path29.join(root, "dogfood", "README.md"),
7218
- path29.join(root, ".cursor", "dogfood", "README.md")
7321
+ path31.join(root, "dogfood", "README.md"),
7322
+ path31.join(root, ".cursor", "dogfood", "README.md")
7219
7323
  ];
7220
7324
  for (const readme of candidateReadmes) {
7221
- if (!await fileExists2(readme)) continue;
7325
+ if (!await fileExists(readme)) continue;
7222
7326
  try {
7223
- const text = await readFile18(readme, "utf8");
7327
+ const text = await readFile19(readme, "utf8");
7224
7328
  if (parseUnprocessedDogfoodItems(text).length) return DOGFOOD_INBOX_HINT;
7225
7329
  } catch {
7226
7330
  }
@@ -7228,18 +7332,13 @@ async function dogfoodInboxSection(root) {
7228
7332
  return null;
7229
7333
  }
7230
7334
  async function loadUpdateCheckPrefs(root) {
7231
- try {
7232
- const data = JSON.parse(
7233
- await readFile18(path29.join(root, ".cursor", "context", "config.json"), "utf8")
7234
- );
7235
- const uc = data.updateCheck;
7236
- if (!uc || typeof uc !== "object" || uc.enabled !== true) {
7237
- return null;
7238
- }
7239
- return uc;
7240
- } catch {
7335
+ const data = await loadContextConfig(root);
7336
+ if (!data) return null;
7337
+ const uc = data.updateCheck;
7338
+ if (!uc || typeof uc !== "object" || uc.enabled !== true) {
7241
7339
  return null;
7242
7340
  }
7341
+ return uc;
7243
7342
  }
7244
7343
  function runUpdateCheckJson(root) {
7245
7344
  return new Promise((resolve3) => {
@@ -7306,18 +7405,13 @@ async function updateCheckSection(root) {
7306
7405
  return UPDATE_CHECK_NUDGE.replace("{installed}", installed).replace("{latest}", latest);
7307
7406
  }
7308
7407
  async function loadCursorUpdateCheckPrefs(root) {
7309
- try {
7310
- const data = JSON.parse(
7311
- await readFile18(path29.join(root, ".cursor", "context", "config.json"), "utf8")
7312
- );
7313
- const uc = data.cursorUpdateCheck;
7314
- if (!uc || typeof uc !== "object" || uc.enabled !== true) {
7315
- return null;
7316
- }
7317
- return uc;
7318
- } catch {
7408
+ const data = await loadContextConfig(root);
7409
+ if (!data) return null;
7410
+ const uc = data.cursorUpdateCheck;
7411
+ if (!uc || typeof uc !== "object" || uc.enabled !== true) {
7319
7412
  return null;
7320
7413
  }
7414
+ return uc;
7321
7415
  }
7322
7416
  function runCursorAwarenessJson(root) {
7323
7417
  return new Promise((resolve3) => {
@@ -7452,7 +7546,7 @@ function parseScreenDetachedAuditSessions(listing) {
7452
7546
  const [, pid, name, marker] = m;
7453
7547
  if (!name || !name.startsWith(AUDIT_SESSION_NS_PREFIX)) continue;
7454
7548
  if (marker && /[Aa]ttached/.test(marker)) continue;
7455
- entries.push({ name, socketPath: sockdir ? path29.join(sockdir, `${pid}.${name}`) : null });
7549
+ entries.push({ name, socketPath: sockdir ? path31.join(sockdir, `${pid}.${name}`) : null });
7456
7550
  }
7457
7551
  return entries;
7458
7552
  }
@@ -7500,8 +7594,8 @@ ${sessions.length} detached \`agent-kit-audit-*\` PTY ${noun} on this host (${ol
7500
7594
  }
7501
7595
  }
7502
7596
  async function buildSessionStartAdditionalContext(rootDir, _payload = {}) {
7503
- const root = path29.resolve(rootDir);
7504
- const handoffPath = path29.join(root, ".cursor", "HANDOFF.md");
7597
+ const root = path31.resolve(rootDir);
7598
+ const handoffPath = path31.join(root, HANDOFF_REL);
7505
7599
  const handoffFull = await readFull(handoffPath);
7506
7600
  const handoff = capHandoffExcerpt(handoffFull);
7507
7601
  const parts = [HARD_RULES];
@@ -7568,7 +7662,7 @@ async function runSessionStartHook(cwd, formatArg, deps = {}) {
7568
7662
  const readStdin = deps.readStdin ?? readStdinJson;
7569
7663
  const buildContext = deps.buildContext ?? buildSessionStartAdditionalContext;
7570
7664
  const payload = await readStdin();
7571
- const root = resolveSessionRoot(payload, path30.resolve(cwd));
7665
+ const root = resolveSessionRoot(payload, path32.resolve(cwd));
7572
7666
  const out = await buildContext(root, payload);
7573
7667
  return formatSessionStartOutput(out.additional_context, format);
7574
7668
  } catch {
@@ -7621,12 +7715,12 @@ import { defineCommand as defineCommand12 } from "citty";
7621
7715
 
7622
7716
  // src/lifecycle/path-cli.ts
7623
7717
  import { spawn as spawn6 } from "child_process";
7624
- import path32 from "path";
7718
+ import path34 from "path";
7625
7719
 
7626
7720
  // src/utils/terminal.ts
7627
7721
  import { readdir as readdir8 } from "fs/promises";
7628
7722
  import { homedir as homedir3 } from "os";
7629
- import path31 from "path";
7723
+ import path33 from "path";
7630
7724
  import { confirm, isCancel } from "@clack/prompts";
7631
7725
  function isNonInteractive() {
7632
7726
  if (process.env.CI === "true" || process.env.CI === "1") return true;
@@ -7650,14 +7744,14 @@ async function findNestedRepoChildren(resolved) {
7650
7744
  if (!entry.isDirectory()) continue;
7651
7745
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
7652
7746
  scanned += 1;
7653
- if (await fileExists(path31.join(resolved, entry.name, ".git"))) {
7747
+ if (await fileExists(path33.join(resolved, entry.name, ".git"))) {
7654
7748
  nested.push(entry.name);
7655
7749
  }
7656
7750
  }
7657
7751
  return nested;
7658
7752
  }
7659
7753
  async function validateProjectRoot(resolved) {
7660
- const home = path31.resolve(homedir3());
7754
+ const home = path33.resolve(homedir3());
7661
7755
  if (resolved === "/" || resolved === home) {
7662
7756
  return {
7663
7757
  ok: false,
@@ -7665,12 +7759,12 @@ async function validateProjectRoot(resolved) {
7665
7759
  recovery: "Change into a project directory and re-run. Agent Kit installs per project."
7666
7760
  };
7667
7761
  }
7668
- const hasGit = await fileExists(path31.join(resolved, ".git"));
7669
- const hasManifest = await fileExists(path31.join(resolved, ".cursor", "agent-kit.json"));
7762
+ const hasGit = await fileExists(path33.join(resolved, ".git"));
7763
+ const hasManifest = await fileExists(path33.join(resolved, MANIFEST_RELATIVE_PATH));
7670
7764
  if (!hasGit && !hasManifest) {
7671
7765
  return {
7672
7766
  ok: false,
7673
- reason: `Refused ${resolved}: no .git and no .cursor/agent-kit.json.`,
7767
+ reason: `Refused ${resolved}: no .git and no ${MANIFEST_RELATIVE_PATH}.`,
7674
7768
  recovery: [
7675
7769
  "Starting from an empty folder? Pick one of these:",
7676
7770
  " 1. git init - then re-run. Recommended: readiness and the",
@@ -7699,7 +7793,7 @@ async function validateProjectRoot(resolved) {
7699
7793
  return { ok: true };
7700
7794
  }
7701
7795
  async function confirmProjectRoot(cwd, opts) {
7702
- const resolved = path31.resolve(cwd);
7796
+ const resolved = path33.resolve(cwd);
7703
7797
  if (opts.forceRoot) {
7704
7798
  return resolved;
7705
7799
  }
@@ -7813,9 +7907,9 @@ function npxPinned(runtimeVersion, subcommand) {
7813
7907
  return `npx -y ${pinnedCliSpec(runtimeVersion)} ${subcommand}`;
7814
7908
  }
7815
7909
  function isBinUnderPrefix(binPath, prefix) {
7816
- const bin = path32.resolve(binPath);
7817
- const root = path32.resolve(prefix);
7818
- return bin === root || bin.startsWith(`${root}${path32.sep}`);
7910
+ const bin = path34.resolve(binPath);
7911
+ const root = path34.resolve(prefix);
7912
+ return bin === root || bin.startsWith(`${root}${path34.sep}`);
7819
7913
  }
7820
7914
  function pathCliStatus(env, runtimeVersion) {
7821
7915
  if (!env.binOnPath || !env.binPath) return "missing";
@@ -7913,17 +8007,17 @@ async function syncPathCliToRuntime(options = {}) {
7913
8007
  }
7914
8008
 
7915
8009
  // src/commands/install.ts
7916
- import path39 from "path";
8010
+ import path40 from "path";
7917
8011
  import { defineCommand as defineCommand11 } from "citty";
7918
8012
  import { bold, cyan as cyan3, green as green2, options as koloristOptions2 } from "kolorist";
7919
8013
 
7920
8014
  // src/generator/personalization.ts
7921
8015
  import { readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
7922
- import path37 from "path";
8016
+ import path38 from "path";
7923
8017
 
7924
8018
  // src/generator/claude-command-adapters.ts
7925
- import { readFile as readFile19, readdir as readdir9, writeFile as writeFile8 } from "fs/promises";
7926
- import path33 from "path";
8019
+ import { readFile as readFile20, readdir as readdir9, writeFile as writeFile9 } from "fs/promises";
8020
+ import path35 from "path";
7927
8021
  var CURSOR_COMMANDS_DIR_REL = ".cursor/commands";
7928
8022
  var CLAUDE_COMMANDS_DIR_REL = ".claude/commands";
7929
8023
  var RESERVED_ADAPTER_NAMES = /* @__PURE__ */ new Set(["agent-kit"]);
@@ -7952,7 +8046,7 @@ Adapter rules (Claude Code CLI):
7952
8046
  `;
7953
8047
  }
7954
8048
  async function discoverInstalledCommands(rootDir) {
7955
- const dir = path33.join(rootDir, CURSOR_COMMANDS_DIR_REL);
8049
+ const dir = path35.join(rootDir, CURSOR_COMMANDS_DIR_REL);
7956
8050
  let entries;
7957
8051
  try {
7958
8052
  entries = (await readdir9(dir)).filter((f) => f.endsWith(".md"));
@@ -7964,7 +8058,7 @@ async function discoverInstalledCommands(rootDir) {
7964
8058
  const name = file.slice(0, -3);
7965
8059
  if (RESERVED_ADAPTER_NAMES.has(name)) continue;
7966
8060
  try {
7967
- const raw = await readFile19(path33.join(dir, file), "utf8");
8061
+ const raw = await readFile20(path35.join(dir, file), "utf8");
7968
8062
  const parsed = parseCommandFrontmatter(name, raw);
7969
8063
  if (parsed) commands.push(parsed);
7970
8064
  } catch {
@@ -7979,18 +8073,18 @@ async function generateClaudeCommandAdapters(rootDir) {
7979
8073
  const results = [];
7980
8074
  let ledgerDirty = false;
7981
8075
  for (const command of commands) {
7982
- const relPath = path33.posix.join(CLAUDE_COMMANDS_DIR_REL, `${command.name}.md`);
8076
+ const relPath = path35.posix.join(CLAUDE_COMMANDS_DIR_REL, `${command.name}.md`);
7983
8077
  const rendered = renderClaudeCommandAdapter(command);
7984
- const abs = path33.join(rootDir, relPath);
8078
+ const abs = path35.join(rootDir, relPath);
7985
8079
  if (!await fileExists(abs)) {
7986
- await ensureDir(path33.dirname(abs));
7987
- await writeFile8(abs, rendered, "utf8");
8080
+ await ensureDir(path35.dirname(abs));
8081
+ await writeFile9(abs, rendered, "utf8");
7988
8082
  ledger.hashes[relPath] = contentHash(rendered);
7989
8083
  ledgerDirty = true;
7990
8084
  results.push({ relativePath: relPath, status: "applied" });
7991
8085
  continue;
7992
8086
  }
7993
- const localContent = await readFile19(abs, "utf8");
8087
+ const localContent = await readFile20(abs, "utf8");
7994
8088
  if (localContent === rendered) {
7995
8089
  if (ledger.hashes[relPath] !== contentHash(rendered)) {
7996
8090
  ledger.hashes[relPath] = contentHash(rendered);
@@ -8003,7 +8097,7 @@ async function generateClaudeCommandAdapters(rootDir) {
8003
8097
  results.push({ relativePath: relPath, status: "preserved-customized" });
8004
8098
  continue;
8005
8099
  }
8006
- await writeFile8(abs, rendered, "utf8");
8100
+ await writeFile9(abs, rendered, "utf8");
8007
8101
  ledger.hashes[relPath] = contentHash(rendered);
8008
8102
  ledgerDirty = true;
8009
8103
  results.push({ relativePath: relPath, status: "refreshed" });
@@ -8013,8 +8107,8 @@ async function generateClaudeCommandAdapters(rootDir) {
8013
8107
  }
8014
8108
 
8015
8109
  // src/generator/claude-kit-load.ts
8016
- import { writeFile as writeFile9 } from "fs/promises";
8017
- import path34 from "path";
8110
+ import { writeFile as writeFile10 } from "fs/promises";
8111
+ import path36 from "path";
8018
8112
  var CLAUDE_MD_REL = "CLAUDE.md";
8019
8113
  var AGENT_KIT_COMMAND_REL = ".claude/commands/agent-kit.md";
8020
8114
  function renderClaudeMd() {
@@ -8070,12 +8164,12 @@ Non-goals: not audits / \`/plan-external-review\`, not a second tick dialect (\`
8070
8164
  `;
8071
8165
  }
8072
8166
  async function writeUnlessExists(rootDir, relativePath, content) {
8073
- const target = path34.join(rootDir, relativePath);
8167
+ const target = path36.join(rootDir, relativePath);
8074
8168
  if (await fileExists(target)) {
8075
8169
  return { relativePath, status: "skipped-customized" };
8076
8170
  }
8077
- await ensureDir(path34.dirname(target));
8078
- await writeFile9(target, content, "utf8");
8171
+ await ensureDir(path36.dirname(target));
8172
+ await writeFile10(target, content, "utf8");
8079
8173
  return { relativePath, status: "applied" };
8080
8174
  }
8081
8175
  async function generateClaudeKitLoadArtifacts(rootDir) {
@@ -8085,109 +8179,9 @@ async function generateClaudeKitLoadArtifacts(rootDir) {
8085
8179
  ]);
8086
8180
  }
8087
8181
 
8088
- // src/generator/claude-session-start-hook.ts
8089
- import { readFile as readFile20, writeFile as writeFile10 } from "fs/promises";
8090
- import path35 from "path";
8091
- var CLAUDE_SETTINGS_REL = ".claude/settings.json";
8092
- var RESOLVE_AGENT_KIT_REL = ".cursor/hooks/agent/resolve-agent-kit.sh";
8093
- var SESSION_START_HOOK_MARKER = "hook session-start --format claude";
8094
- var SESSION_START_DEGRADED_TEXT = "Agent Kit hooks are running in degraded fail-open mode: the agent-kit CLI could not be resolved (checked AGENT_KIT_HOOK_BIN, PATH, node_modules/.bin/agent-kit). Slash command adapters still work; session-context injection is inactive. Fix: install the CLI (npm i -D @dadado/agent-kit-cli) or set AGENT_KIT_HOOK_BIN.";
8095
- function buildSessionStartHookCommand() {
8096
- return `. "\${CLAUDE_PROJECT_DIR}/${RESOLVE_AGENT_KIT_REL}" 2>/dev/null && resolve_agent_kit && exec $AGENT_KIT_RESOLVED hook session-start --format claude; printf '%s' ${shellSingleQuote(SESSION_START_DEGRADED_TEXT)}`;
8097
- }
8098
- function shellSingleQuote(text) {
8099
- return `'${text.replace(/'/g, "'\\''")}'`;
8100
- }
8101
- function buildSessionStartHookEntry() {
8102
- return {
8103
- type: "command",
8104
- command: buildSessionStartHookCommand(),
8105
- timeout: 15,
8106
- statusMessage: "Loading Agent Kit session context"
8107
- };
8108
- }
8109
- function isPlainObject2(value) {
8110
- return typeof value === "object" && value !== null && !Array.isArray(value);
8111
- }
8112
- function groupHasMarker(group) {
8113
- if (!isPlainObject2(group) || !Array.isArray(group.hooks)) return false;
8114
- return group.hooks.some(
8115
- (h) => isPlainObject2(h) && typeof h.command === "string" && h.command.includes(SESSION_START_HOOK_MARKER)
8116
- );
8117
- }
8118
- function mergeSessionStartHookIntoSettings(existingRaw) {
8119
- const entry = buildSessionStartHookEntry();
8120
- const newGroup = { hooks: [entry] };
8121
- let root = {};
8122
- if (existingRaw !== null && existingRaw.trim() !== "") {
8123
- try {
8124
- const parsed = JSON.parse(existingRaw);
8125
- if (!isPlainObject2(parsed)) throw new Error("root is not an object");
8126
- root = parsed;
8127
- } catch {
8128
- return {
8129
- content: null,
8130
- status: "unavailable",
8131
- instructions: instructionsBlock(entry)
8132
- };
8133
- }
8134
- }
8135
- const hooks = isPlainObject2(root.hooks) ? { ...root.hooks } : {};
8136
- const sessionStart = Array.isArray(hooks.SessionStart) ? [...hooks.SessionStart] : [];
8137
- const existingIndex = sessionStart.findIndex((g) => groupHasMarker(g));
8138
- let status;
8139
- if (existingIndex === -1) {
8140
- sessionStart.push(newGroup);
8141
- status = "applied";
8142
- } else {
8143
- const current = sessionStart[existingIndex];
8144
- if (JSON.stringify(current) === JSON.stringify(newGroup)) {
8145
- status = "unchanged";
8146
- } else {
8147
- sessionStart[existingIndex] = newGroup;
8148
- status = "refreshed";
8149
- }
8150
- }
8151
- hooks.SessionStart = sessionStart;
8152
- root.hooks = hooks;
8153
- return { content: `${JSON.stringify(root, null, 2)}
8154
- `, status };
8155
- }
8156
- function instructionsBlock(entry) {
8157
- return [
8158
- `Could not parse the existing ${CLAUDE_SETTINGS_REL} as JSON, so Agent Kit did not touch it.`,
8159
- "Add this hook by hand under hooks.SessionStart (create the arrays if they do not exist):",
8160
- "",
8161
- JSON.stringify(entry, null, 2)
8162
- ].join("\n");
8163
- }
8164
- async function writeClaudeSessionStartHook(rootDir) {
8165
- const abs = path35.join(rootDir, CLAUDE_SETTINGS_REL);
8166
- let existing = null;
8167
- try {
8168
- existing = await readFile20(abs, "utf8");
8169
- } catch {
8170
- existing = null;
8171
- }
8172
- const merged = mergeSessionStartHookIntoSettings(existing);
8173
- if (merged.status === "unavailable" || merged.content === null) {
8174
- return {
8175
- relativePath: CLAUDE_SETTINGS_REL,
8176
- status: "unavailable",
8177
- instructions: merged.instructions
8178
- };
8179
- }
8180
- if (merged.status === "unchanged") {
8181
- return { relativePath: CLAUDE_SETTINGS_REL, status: "unchanged" };
8182
- }
8183
- await ensureDir(path35.dirname(abs));
8184
- await writeFile10(abs, merged.content, "utf8");
8185
- return { relativePath: CLAUDE_SETTINGS_REL, status: merged.status };
8186
- }
8187
-
8188
8182
  // src/generator/vscode.ts
8189
8183
  import { writeFile as writeFile11 } from "fs/promises";
8190
- import path36 from "path";
8184
+ import path37 from "path";
8191
8185
 
8192
8186
  // src/generator/platform.ts
8193
8187
  function gitProviderLabel(profile) {
@@ -8211,10 +8205,10 @@ function prTerminology(profile) {
8211
8205
  // src/generator/vscode.ts
8212
8206
  async function generateVSCodeArtifacts(profile) {
8213
8207
  const results = [];
8214
- const vscodeDir = path36.join(profile.rootDir, ".vscode");
8215
- const githubDir = path36.join(profile.rootDir, ".github");
8208
+ const vscodeDir = path37.join(profile.rootDir, ".vscode");
8209
+ const githubDir = path37.join(profile.rootDir, ".github");
8216
8210
  await Promise.all([ensureDir(vscodeDir), ensureDir(githubDir)]);
8217
- const settingsPath = path36.join(vscodeDir, "settings.json");
8211
+ const settingsPath = path37.join(vscodeDir, "settings.json");
8218
8212
  if (await fileExists(settingsPath)) {
8219
8213
  results.push({ relativePath: ".vscode/settings.json", status: "skipped-customized" });
8220
8214
  } else {
@@ -8238,7 +8232,7 @@ async function generateVSCodeArtifacts(profile) {
8238
8232
  }
8239
8233
  const provider = gitProviderLabel(profile);
8240
8234
  const prTerm = prTerminology(profile);
8241
- const copilotPath = path36.join(githubDir, "copilot-instructions.md");
8235
+ const copilotPath = path37.join(githubDir, "copilot-instructions.md");
8242
8236
  if (await fileExists(copilotPath)) {
8243
8237
  results.push({ relativePath: ".github/copilot-instructions.md", status: "skipped-customized" });
8244
8238
  } else {
@@ -8256,7 +8250,7 @@ async function generateVSCodeArtifacts(profile) {
8256
8250
  results.push({ relativePath: ".github/copilot-instructions.md", status: "applied" });
8257
8251
  }
8258
8252
  if (profile.ide.plan === "vscode-pro") {
8259
- const securityPath = path36.join(vscodeDir, "security-review.agent.md");
8253
+ const securityPath = path37.join(vscodeDir, "security-review.agent.md");
8260
8254
  if (await fileExists(securityPath)) {
8261
8255
  results.push({
8262
8256
  relativePath: ".vscode/security-review.agent.md",
@@ -8468,7 +8462,7 @@ function renderProjectContext(profile, skillItems = []) {
8468
8462
  `;
8469
8463
  }
8470
8464
  async function createOwnedFile(rootDir, relativePath, content, evidence) {
8471
- const target = path37.join(rootDir, relativePath);
8465
+ const target = path38.join(rootDir, relativePath);
8472
8466
  if (await fileExists(target)) {
8473
8467
  return {
8474
8468
  kind: "file",
@@ -8478,7 +8472,7 @@ async function createOwnedFile(rootDir, relativePath, content, evidence) {
8478
8472
  evidence
8479
8473
  };
8480
8474
  }
8481
- await ensureDir(path37.dirname(target));
8475
+ await ensureDir(path38.dirname(target));
8482
8476
  await writeFile12(target, content, "utf8");
8483
8477
  return {
8484
8478
  kind: "file",
@@ -8495,7 +8489,7 @@ async function packTargets(registryRoot, packId) {
8495
8489
  async function existingTargets(projectRoot, targets) {
8496
8490
  const checks = await Promise.all(
8497
8491
  targets.map(
8498
- async (target) => await fileExists(path37.join(projectRoot, target)) ? target : null
8492
+ async (target) => await fileExists(path38.join(projectRoot, target)) ? target : null
8499
8493
  )
8500
8494
  );
8501
8495
  return checks.filter((target) => target !== null);
@@ -8517,14 +8511,14 @@ async function applyPersonalization(input) {
8517
8511
  componentResults.push({ ...item, status: "unavailable" });
8518
8512
  continue;
8519
8513
  }
8520
- const target = path37.posix.join(
8514
+ const target = path38.posix.join(
8521
8515
  ".cursor",
8522
8516
  "skills",
8523
8517
  skill.path.includes("/core/") ? "core" : "community",
8524
8518
  skill.id,
8525
8519
  "SKILL.md"
8526
8520
  );
8527
- if (await fileExists(path37.join(input.rootDir, target))) {
8521
+ if (await fileExists(path38.join(input.rootDir, target))) {
8528
8522
  componentResults.push({ ...item, status: "skipped-customized", path: target });
8529
8523
  protectedPaths.add(target);
8530
8524
  continue;
@@ -8669,7 +8663,7 @@ async function applyPersonalization(input) {
8669
8663
  protectedPaths: [...protectedPaths].sort(),
8670
8664
  ...claudeSessionStartInstructions ? { claudeSessionStartInstructions } : {}
8671
8665
  };
8672
- await writeJson(path37.join(input.rootDir, RESULT_PATH), result);
8666
+ await writeJson(path38.join(input.rootDir, RESULT_PATH), result);
8673
8667
  return {
8674
8668
  result,
8675
8669
  manifest: {
@@ -8687,7 +8681,7 @@ async function applyPersonalization(input) {
8687
8681
  };
8688
8682
  }
8689
8683
  async function readRepositoryProfile(rootDir) {
8690
- const target = path37.join(rootDir, ".cursor/agent-kit.config.json");
8684
+ const target = path38.join(rootDir, REPOSITORY_PROFILE_REL);
8691
8685
  if (!await fileExists(target)) return null;
8692
8686
  return JSON.parse(await readFile21(target, "utf8"));
8693
8687
  }
@@ -8695,16 +8689,16 @@ async function readRepositoryProfile(rootDir) {
8695
8689
  // src/lifecycle/onboard-migration.ts
8696
8690
  import { createHash as createHash4 } from "crypto";
8697
8691
  import { readFile as readFile22, unlink } from "fs/promises";
8698
- import path38 from "path";
8692
+ import path39 from "path";
8699
8693
  var LEGACY_ONBOARD_PATH = ".cursor/commands/onboard.md";
8700
8694
  var NAMESPACED_ONBOARD_PATH = ".cursor/commands/agent-kit-onboard.md";
8701
8695
  var MANAGED_LEGACY_HASHES = /* @__PURE__ */ new Set([
8702
8696
  "b274a68941813f19b185893cb7c5561dff027f53270890029992f208e24992fe"
8703
8697
  ]);
8704
8698
  async function migrateLegacyOnboardCommand(projectRoot, managedHashes = MANAGED_LEGACY_HASHES) {
8705
- const legacyPath = path38.join(projectRoot, LEGACY_ONBOARD_PATH);
8699
+ const legacyPath = path39.join(projectRoot, LEGACY_ONBOARD_PATH);
8706
8700
  if (!await fileExists(legacyPath)) return "absent";
8707
- const namespacedPath = path38.join(projectRoot, NAMESPACED_ONBOARD_PATH);
8701
+ const namespacedPath = path39.join(projectRoot, NAMESPACED_ONBOARD_PATH);
8708
8702
  if (!await fileExists(namespacedPath)) return "preserved-customized";
8709
8703
  const content = await readFile22(legacyPath);
8710
8704
  const hash = createHash4("sha256").update(content).digest("hex");
@@ -8756,6 +8750,21 @@ async function syncFromManifest(registryRoot, projectRoot, manifest) {
8756
8750
  return stats;
8757
8751
  }
8758
8752
 
8753
+ // src/commands/shared-args.ts
8754
+ var NON_INTERACTIVE_ROOT_ARGS = {
8755
+ yes: {
8756
+ type: "boolean",
8757
+ alias: "y",
8758
+ description: "Skip interactive prompts; use defaults (IDE-agnostic non-interactive mode)",
8759
+ default: false
8760
+ },
8761
+ "force-root": {
8762
+ type: "boolean",
8763
+ description: "Bypass the ambiguous-root guard (use with caution)",
8764
+ default: false
8765
+ }
8766
+ };
8767
+
8759
8768
  // src/commands/install.ts
8760
8769
  function parsePackList(raw) {
8761
8770
  if (!raw?.trim()) return [];
@@ -8840,7 +8849,7 @@ async function printPostInstallSummary(result) {
8840
8849
  printInstallEpilogue(sync.env, { runtimeVersion: KIT_VERSION });
8841
8850
  }
8842
8851
  async function performInstall(options) {
8843
- const projectRoot = path39.resolve(options.cwd);
8852
+ const projectRoot = path40.resolve(options.cwd);
8844
8853
  const packs = parsePackList(options.pack);
8845
8854
  const existing = await loadAgentKitManifest(projectRoot);
8846
8855
  const registry = await resolveRegistryFromCli({
@@ -8917,17 +8926,7 @@ var installCommand = defineCommand11({
8917
8926
  type: "string",
8918
8927
  description: `Comma-separated L1 pack ids (e.g. cybersec,devops). Known: ${DOMAIN_PACK_IDS.join(", ")}`
8919
8928
  },
8920
- yes: {
8921
- type: "boolean",
8922
- alias: "y",
8923
- description: "Skip interactive prompts; use defaults (IDE-agnostic non-interactive mode)",
8924
- default: false
8925
- },
8926
- "force-root": {
8927
- type: "boolean",
8928
- description: "Bypass the ambiguous-root guard (use with caution)",
8929
- default: false
8930
- },
8929
+ ...NON_INTERACTIVE_ROOT_ARGS,
8931
8930
  claude: {
8932
8931
  type: "boolean",
8933
8932
  description: "Opt-in: generate .claude/commands/*.md thin pointer adapters for the installed .cursor/commands set, and merge a SessionStart context hook into .claude/settings.json (default install behavior is unchanged without this flag)",
@@ -9022,17 +9021,7 @@ var initCommand = defineCommand12({
9022
9021
  description: "Project root directory",
9023
9022
  default: process.cwd()
9024
9023
  },
9025
- yes: {
9026
- type: "boolean",
9027
- alias: "y",
9028
- description: "Skip interactive prompts; use defaults (IDE-agnostic non-interactive mode)",
9029
- default: false
9030
- },
9031
- "force-root": {
9032
- type: "boolean",
9033
- description: "Bypass the ambiguous-root guard (use with caution)",
9034
- default: false
9035
- }
9024
+ ...NON_INTERACTIVE_ROOT_ARGS
9036
9025
  },
9037
9026
  async run({ args }) {
9038
9027
  const nonInteractive = args.yes || isNonInteractive();
@@ -9566,8 +9555,8 @@ function renderMcLive(view, opts = {}) {
9566
9555
 
9567
9556
  // src/mission-control/snapshot.ts
9568
9557
  import { execFile as execFile6 } from "child_process";
9569
- import { access as access8 } from "fs/promises";
9570
- import path40 from "path";
9558
+ import { access as access7 } from "fs/promises";
9559
+ import path41 from "path";
9571
9560
 
9572
9561
  // ../../dashboard/lib/live-refresh.mjs
9573
9562
  import { join, resolve as resolve2 } from "path";
@@ -9599,8 +9588,8 @@ function dataScriptTimeoutMs(env = process.env) {
9599
9588
  async function firstExisting2(candidates) {
9600
9589
  for (const candidate2 of candidates) {
9601
9590
  try {
9602
- await access8(candidate2);
9603
- return path40.resolve(candidate2);
9591
+ await access7(candidate2);
9592
+ return path41.resolve(candidate2);
9604
9593
  } catch {
9605
9594
  }
9606
9595
  }
@@ -9609,9 +9598,9 @@ async function firstExisting2(candidates) {
9609
9598
  async function findDashboardDataScript(cwd, env = process.env, options = {}) {
9610
9599
  const startPath = await findDashboardStart(cwd, env, options);
9611
9600
  if (startPath) {
9612
- const sibling = path40.join(path40.dirname(startPath), "dashboard-data.mjs");
9601
+ const sibling = path41.join(path41.dirname(startPath), "dashboard-data.mjs");
9613
9602
  try {
9614
- await access8(sibling);
9603
+ await access7(sibling);
9615
9604
  return sibling;
9616
9605
  } catch {
9617
9606
  }
@@ -9624,7 +9613,7 @@ async function loadDashboardSnapshot(opts) {
9624
9613
  const env = opts.env ?? process.env;
9625
9614
  const timeout = dataScriptTimeoutMs(env);
9626
9615
  const run = opts.execFileFn ?? execFile6;
9627
- const snapshotRoot = path40.resolve(opts.snapshotRoot);
9616
+ const snapshotRoot = path41.resolve(opts.snapshotRoot);
9628
9617
  return new Promise((resolve3) => {
9629
9618
  run(
9630
9619
  process.execPath,
@@ -9947,13 +9936,13 @@ var missionControlCommand = defineCommand13({
9947
9936
  });
9948
9937
 
9949
9938
  // src/commands/monitors.ts
9950
- import path42 from "path";
9939
+ import path43 from "path";
9951
9940
  import { defineCommand as defineCommand14 } from "citty";
9952
9941
 
9953
9942
  // src/invariants/monitors-untriaged.ts
9954
9943
  import { execFile as execFile7 } from "child_process";
9955
9944
  import { readFile as readFile23, readdir as readdir10, stat as stat5 } from "fs/promises";
9956
- import path41 from "path";
9945
+ import path42 from "path";
9957
9946
  import { promisify as promisify6 } from "util";
9958
9947
 
9959
9948
  // src/invariants/triage-heading.ts
@@ -9994,7 +9983,7 @@ async function gitFreshMonitorNames(rootDir) {
9994
9983
  for (const line of stdout.split("\n")) {
9995
9984
  if (!line.trim()) continue;
9996
9985
  const file = line.slice(3).trim().replace(/^.* -> /, "");
9997
- const base = path41.basename(file);
9986
+ const base = path42.basename(file);
9998
9987
  if (base.startsWith("plan-monitor-") && base.endsWith(".md")) {
9999
9988
  names.add(base);
10000
9989
  }
@@ -10017,13 +10006,13 @@ function monitorSlugFromName(fileName) {
10017
10006
  return fileName.replace(/^plan-monitor-/, "").replace(/\.md$/, "").toLowerCase();
10018
10007
  }
10019
10008
  async function selectUntriagedMonitors(rootDir) {
10020
- const root = path41.resolve(rootDir);
10021
- const memoryDir = path41.join(root, ".cursor", "memory");
10009
+ const root = path42.resolve(rootDir);
10010
+ const memoryDir = path42.join(root, ".cursor", "memory");
10022
10011
  const allNames = await listMonitorFiles(memoryDir);
10023
10012
  const selectionOrder = ["git-fresh", "handoff-aligned", "untriaged-scan"];
10024
10013
  const byName = /* @__PURE__ */ new Map();
10025
10014
  for (const name of allNames) {
10026
- const abs = path41.join(memoryDir, name);
10015
+ const abs = path42.join(memoryDir, name);
10027
10016
  try {
10028
10017
  const [content, st] = await Promise.all([readFile23(abs, "utf8"), stat5(abs)]);
10029
10018
  byName.set(name, { content, mtimeMs: st.mtimeMs });
@@ -10038,7 +10027,7 @@ async function selectUntriagedMonitors(rootDir) {
10038
10027
  const gitFreshSet = [...gitFresh].filter(untriaged).sort();
10039
10028
  let handoff = "";
10040
10029
  try {
10041
- handoff = await readFile23(path41.join(root, ".cursor", "HANDOFF.md"), "utf8");
10030
+ handoff = await readFile23(path42.join(root, ".cursor", "HANDOFF.md"), "utf8");
10042
10031
  } catch {
10043
10032
  handoff = "";
10044
10033
  }
@@ -10058,8 +10047,8 @@ async function selectUntriagedMonitors(rootDir) {
10058
10047
  const row = byName.get(name);
10059
10048
  if (!row) continue;
10060
10049
  entries.push({
10061
- path: path41.join(memoryDir, name),
10062
- relativePath: path41.relative(root, path41.join(memoryDir, name)).split(path41.sep).join("/"),
10050
+ path: path42.join(memoryDir, name),
10051
+ relativePath: path42.relative(root, path42.join(memoryDir, name)).split(path42.sep).join("/"),
10063
10052
  mtimeMs: row.mtimeMs,
10064
10053
  hasTriageHeading: false,
10065
10054
  hasOpenGaps: hasOpenGaps(row.content),
@@ -10105,7 +10094,7 @@ var monitorsCommand = defineCommand14({
10105
10094
  process.exitCode = 2;
10106
10095
  return;
10107
10096
  }
10108
- const result = await selectUntriagedMonitors(path42.resolve(args.cwd));
10097
+ const result = await selectUntriagedMonitors(path43.resolve(args.cwd));
10109
10098
  if (args.json) {
10110
10099
  console.log(JSON.stringify(result, null, 2));
10111
10100
  return;
@@ -10121,7 +10110,7 @@ var monitorsCommand = defineCommand14({
10121
10110
  });
10122
10111
 
10123
10112
  // src/commands/plan-index.ts
10124
- import path43 from "path";
10113
+ import path44 from "path";
10125
10114
  import { defineCommand as defineCommand15 } from "citty";
10126
10115
  var planIndexCommand = defineCommand15({
10127
10116
  meta: {
@@ -10140,7 +10129,7 @@ var planIndexCommand = defineCommand15({
10140
10129
  }
10141
10130
  },
10142
10131
  async run({ args }) {
10143
- const root = path43.resolve(args.cwd);
10132
+ const root = path44.resolve(args.cwd);
10144
10133
  const index = await writePlanIndex(root);
10145
10134
  if (args.json) {
10146
10135
  console.log(JSON.stringify(index, null, 2));
@@ -10156,14 +10145,14 @@ var planIndexCommand = defineCommand15({
10156
10145
  });
10157
10146
 
10158
10147
  // src/commands/run-plan.ts
10159
- import path50 from "path";
10148
+ import path51 from "path";
10160
10149
  import { defineCommand as defineCommand16 } from "citty";
10161
10150
 
10162
10151
  // src/plan-loop/backends.ts
10163
10152
  import { execFileSync as execFileSync2, spawn as spawn7 } from "child_process";
10164
10153
  import { createWriteStream } from "fs";
10165
- import { access as access9 } from "fs/promises";
10166
- import path44 from "path";
10154
+ import { access as access8 } from "fs/promises";
10155
+ import path45 from "path";
10167
10156
  import { StringDecoder as StringDecoder3 } from "string_decoder";
10168
10157
 
10169
10158
  // src/plan-loop/hitl-relay.ts
@@ -11191,26 +11180,32 @@ function createRelay(hitl, child, redactedError) {
11191
11180
  }
11192
11181
  };
11193
11182
  }
11183
+ function cursorAgentHeadlessArgs(opts) {
11184
+ const args = [
11185
+ "-p",
11186
+ "--force",
11187
+ "--sandbox",
11188
+ "disabled",
11189
+ "--output-format",
11190
+ "stream-json",
11191
+ "--workspace",
11192
+ opts.workspace
11193
+ ];
11194
+ if (opts.model) args.push("--model", opts.model);
11195
+ args.push(opts.prompt);
11196
+ return args;
11197
+ }
11194
11198
  var cursorAgentBackend = {
11195
11199
  id: "cursor-agent",
11196
11200
  async resolve() {
11197
11201
  return whichBinary("cursor-agent");
11198
11202
  },
11199
11203
  async run(opts) {
11200
- const args = [
11201
- "-p",
11202
- "--force",
11203
- "--sandbox",
11204
- "disabled",
11205
- "--output-format",
11206
- "stream-json",
11207
- "--workspace",
11208
- opts.workspace
11209
- ];
11210
- if (opts.model) {
11211
- args.push("--model", opts.model);
11212
- }
11213
- args.push(opts.prompt);
11204
+ const args = cursorAgentHeadlessArgs({
11205
+ workspace: opts.workspace,
11206
+ prompt: opts.prompt,
11207
+ model: opts.model
11208
+ });
11214
11209
  const env = opts.env ? mergeChildEnv(opts.env) : void 0;
11215
11210
  return spawnLogged("cursor-agent", args, opts.logPath, {
11216
11211
  spawnFn: opts.spawnFn,
@@ -11297,9 +11292,9 @@ function claudeHeadlessArgs(opts = {}) {
11297
11292
  async function missingClaudeAdapter(workspace, prompt) {
11298
11293
  const m = /^\/([A-Za-z0-9][A-Za-z0-9_-]*)/.exec(prompt.trimStart());
11299
11294
  if (!m?.[1]) return null;
11300
- const rel = path44.join(".claude", "commands", `${m[1]}.md`);
11295
+ const rel = path45.join(".claude", "commands", `${m[1]}.md`);
11301
11296
  try {
11302
- await access9(path44.join(workspace, rel));
11297
+ await access8(path45.join(workspace, rel));
11303
11298
  return null;
11304
11299
  } catch {
11305
11300
  return rel;
@@ -11422,15 +11417,15 @@ async function detectAgentBackend(requested, whichFn = whichBinary) {
11422
11417
 
11423
11418
  // src/plan-loop/run-loop.ts
11424
11419
  import { mkdir as mkdir6, readFile as readFile27, rm as rm2, unlink as unlink2 } from "fs/promises";
11425
- import path49 from "path";
11420
+ import path50 from "path";
11426
11421
 
11427
11422
  // src/mission-control/live-run.ts
11428
11423
  import { readFile as readFile25 } from "fs/promises";
11429
- import path46 from "path";
11424
+ import path47 from "path";
11430
11425
 
11431
11426
  // src/plan-loop/plan-state.ts
11432
11427
  import { readFile as readFile24, readdir as readdir11 } from "fs/promises";
11433
- import path45 from "path";
11428
+ import path46 from "path";
11434
11429
  function countPendingTodos(raw) {
11435
11430
  const lines = raw.split(/\r?\n/);
11436
11431
  let inFront = 0;
@@ -11458,7 +11453,7 @@ function countPendingTodos(raw) {
11458
11453
  async function findActivePlanFile(plansDir) {
11459
11454
  if (!await fileExists(plansDir)) return null;
11460
11455
  const files = (await readdir11(plansDir)).filter((f) => f.endsWith(".plan.md")).sort();
11461
- return files[0] ? path45.join(plansDir, files[0]) : null;
11456
+ return files[0] ? path46.join(plansDir, files[0]) : null;
11462
11457
  }
11463
11458
  async function readPlan(planPath) {
11464
11459
  return readFile24(planPath, "utf8");
@@ -11646,7 +11641,7 @@ function firstWord(raw) {
11646
11641
  }
11647
11642
  async function readLiveMission(root, io = defaultMissionIo()) {
11648
11643
  const mission = emptyLiveMission();
11649
- const handoff = await io.readFile(path46.join(root, ".cursor", "HANDOFF.md")) ?? "";
11644
+ const handoff = await io.readFile(path47.join(root, ".cursor", "HANDOFF.md")) ?? "";
11650
11645
  const named = extractHandoffNamedPlans(handoff);
11651
11646
  mission.mode = firstWord(MODE_RE.exec(handoff)?.[1]);
11652
11647
  let cursorIndex = null;
@@ -11682,13 +11677,13 @@ async function readLiveMission(root, io = defaultMissionIo()) {
11682
11677
  state: finished || cursor !== null && i < cursor ? "done" : i === cursor ? "current" : "pending"
11683
11678
  }));
11684
11679
  }
11685
- const plansDir = path46.join(root, ".cursor", "plans");
11680
+ const plansDir = path47.join(root, ".cursor", "plans");
11686
11681
  const planBase = (mission.queue && !finished ? mission.queue.current : null) ?? named.active;
11687
- const planPath = planBase ? path46.join(plansDir, planBase) : await io.findActivePlan(plansDir);
11682
+ const planPath = planBase ? path47.join(plansDir, planBase) : await io.findActivePlan(plansDir);
11688
11683
  if (planPath) {
11689
11684
  const raw = await io.readFile(planPath);
11690
11685
  if (raw !== null) {
11691
- mission.planFile = path46.basename(planPath);
11686
+ mission.planFile = path47.basename(planPath);
11692
11687
  const { todos } = parsePlanFrontmatter2(raw);
11693
11688
  const open = todos.filter((t) => t.status !== "cancelled");
11694
11689
  mission.todos = {
@@ -11739,7 +11734,7 @@ async function withLiveTui(opts, run) {
11739
11734
  columns,
11740
11735
  now: now2,
11741
11736
  backend: opts.backend,
11742
- logPath: path46.relative(opts.root, opts.logPath) || opts.logPath
11737
+ logPath: path47.relative(opts.root, opts.logPath) || opts.logPath
11743
11738
  });
11744
11739
  opts.onFeed?.(feed);
11745
11740
  const missionLoader = opts.missionLoader ?? createLiveMissionLoader(opts.root, { now: now2 });
@@ -11876,9 +11871,9 @@ async function withLiveTui(opts, run) {
11876
11871
 
11877
11872
  // src/plan-loop/external-review.ts
11878
11873
  import { spawn as spawn8 } from "child_process";
11879
- import path47 from "path";
11880
- var CANONICAL_REL = path47.join(".cursor", "scripts", "plan-external-review.sh");
11881
- var FALLBACK_REL = path47.join("scripts", "plan-external-review.sh");
11874
+ import path48 from "path";
11875
+ var CANONICAL_REL = path48.join(".cursor", "scripts", "plan-external-review.sh");
11876
+ var FALLBACK_REL = path48.join("scripts", "plan-external-review.sh");
11882
11877
  function isPlanExhaustedReason(reason) {
11883
11878
  const r = reason.trim().toLowerCase();
11884
11879
  if (!r) return false;
@@ -11900,8 +11895,8 @@ async function armExternalPlanReview(root, options = {}) {
11900
11895
  const existsFn = options.existsFn ?? fileExists;
11901
11896
  const log = options.log ?? ((line) => console.log(line));
11902
11897
  const force = options.force === true;
11903
- const canonicalPath = path47.join(root, CANONICAL_REL);
11904
- const fallbackPath = path47.join(root, FALLBACK_REL);
11898
+ const canonicalPath = path48.join(root, CANONICAL_REL);
11899
+ const fallbackPath = path48.join(root, FALLBACK_REL);
11905
11900
  let scriptPath = null;
11906
11901
  let scriptRel = CANONICAL_REL;
11907
11902
  if (await existsFn(canonicalPath)) {
@@ -11954,7 +11949,7 @@ async function armExternalPlanReview(root, options = {}) {
11954
11949
  }
11955
11950
 
11956
11951
  // src/plan-loop/persona-banners.ts
11957
- import path48 from "path";
11952
+ import path49 from "path";
11958
11953
  import {
11959
11954
  blue,
11960
11955
  cyan as cyan4,
@@ -11990,7 +11985,7 @@ function resolveColor(name, fallback) {
11990
11985
  async function resolveCliPersonaId(root) {
11991
11986
  try {
11992
11987
  const cfg = await readJson(
11993
- path48.join(root, ".cursor", "context", "config.json")
11988
+ path49.join(root, ".cursor", "context", "config.json")
11994
11989
  );
11995
11990
  const modes = cfg?.agentPersona?.modes ?? cfg?.workspaceSkin?.modes;
11996
11991
  const id = modes?.[CLI_RUN_PLAN_MODE];
@@ -12001,7 +11996,7 @@ async function resolveCliPersonaId(root) {
12001
11996
  }
12002
11997
  async function loadPersonaPack(root, personaId) {
12003
11998
  try {
12004
- const personaPath = path48.join(root, "registry", "personas", "core", personaId, "persona.json");
11999
+ const personaPath = path49.join(root, "registry", "personas", "core", personaId, "persona.json");
12005
12000
  const pack = await readJson(personaPath);
12006
12001
  if (!pack || typeof pack.id !== "string") return null;
12007
12002
  return pack;
@@ -12180,9 +12175,9 @@ function sleep(ms) {
12180
12175
  return new Promise((r) => setTimeout(r, ms));
12181
12176
  }
12182
12177
  async function runPlanLoop(opts) {
12183
- const plansDir = path49.join(opts.root, ".cursor", "plans");
12184
- const stopFile = path49.join(opts.root, ".cursor", "loop.stop");
12185
- const logDir = path49.join(opts.root, ".cursor", "loop-logs");
12178
+ const plansDir = path50.join(opts.root, ".cursor", "plans");
12179
+ const stopFile = path50.join(opts.root, ".cursor", "loop.stop");
12180
+ const logDir = path50.join(opts.root, ".cursor", "loop-logs");
12186
12181
  const planPath = await findActivePlanFile(plansDir);
12187
12182
  if (!planPath) {
12188
12183
  logger.error("No active plan in .cursor/plans/");
@@ -12203,7 +12198,7 @@ async function runPlanLoop(opts) {
12203
12198
  try {
12204
12199
  const persona = await loadCliRunPlanPersona(opts.root);
12205
12200
  const banners = createPersonaBannerPrinter(persona);
12206
- console.log(`Active plan: ${path49.basename(planPath)}`);
12201
+ console.log(`Active plan: ${path50.basename(planPath)}`);
12207
12202
  console.log(`Pending to-dos: ${await pending()} | max ticks: ${opts.maxTicks}`);
12208
12203
  console.log(`Backend: ${opts.backend.id}`);
12209
12204
  if (persona) {
@@ -12247,8 +12242,8 @@ async function runPlanLoop(opts) {
12247
12242
  planExhausted = true;
12248
12243
  break;
12249
12244
  }
12250
- const logPath = path49.join(logDir, `tick-${stamp()}.log`);
12251
- const relLog = path49.relative(opts.root, logPath);
12245
+ const logPath = path50.join(logDir, `tick-${stamp()}.log`);
12246
+ const relLog = path50.relative(opts.root, logPath);
12252
12247
  console.log("");
12253
12248
  const tickLine = `=== tick ${tick}/${opts.maxTicks} - pending: ${before} - log: ${relLog} ===`;
12254
12249
  if (banners) banners.tickStart(tickLine);
@@ -12356,7 +12351,7 @@ async function runPlanLoop(opts) {
12356
12351
  const finishDetail = `after ${tick} tick(s); pending: ${pendingNow}`;
12357
12352
  if (banners) banners.phaseComplete(finishDetail);
12358
12353
  console.log(
12359
- `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path49.relative(opts.root, logDir)}/`
12354
+ `Loop finished after ${tick} tick(s). Pending now: ${pendingNow}. Logs in ${path50.relative(opts.root, logDir)}/`
12360
12355
  );
12361
12356
  if (planExhausted || shouldArmExternalPlanReview({ pending: pendingNow, stopReason })) {
12362
12357
  await armExternalPlanReview(opts.root);
@@ -12448,7 +12443,7 @@ var runPlanCommand = defineCommand16({
12448
12443
  return;
12449
12444
  }
12450
12445
  const code = await runPlanLoop({
12451
- root: path50.resolve(args.cwd),
12446
+ root: path51.resolve(args.cwd),
12452
12447
  maxTicks,
12453
12448
  sleepSeconds,
12454
12449
  model: args.model ? String(args.model) : void 0,
@@ -12463,12 +12458,12 @@ var runPlanCommand = defineCommand16({
12463
12458
 
12464
12459
  // src/commands/run.ts
12465
12460
  import { homedir as homedir4 } from "os";
12466
- import path52 from "path";
12461
+ import path53 from "path";
12467
12462
  import { defineCommand as defineCommand17 } from "citty";
12468
12463
 
12469
12464
  // src/plan-loop/dispatch.ts
12470
12465
  import { mkdir as mkdir7, readFile as readFile28 } from "fs/promises";
12471
- import path51 from "path";
12466
+ import path52 from "path";
12472
12467
  var RUN_CATALOG = [
12473
12468
  "run-plan",
12474
12469
  "run-plan-all",
@@ -12482,7 +12477,7 @@ var RUN_CATALOG = [
12482
12477
  "kit-staging"
12483
12478
  ];
12484
12479
  var FIRST_CLASS_SLASH_COMMANDS = ["run-plan", "run-plan-all"];
12485
- var RUN_PROMOTE_BLOCKED = ["git-prod", "kit-prod"];
12480
+ var RUN_PROMOTE_BLOCKED = RESERVED_GATE_IDS;
12486
12481
  function normalizeSlashName(raw) {
12487
12482
  return raw.replace(/^\//, "").replace(/\.md$/i, "").trim();
12488
12483
  }
@@ -12512,7 +12507,7 @@ function rewriteRootArgvToRun(argv) {
12512
12507
  return next;
12513
12508
  }
12514
12509
  function commandMarkdownPath(root, name) {
12515
- return path51.join(root, ".cursor", "commands", `${normalizeSlashName(name)}.md`);
12510
+ return path52.join(root, ".cursor", "commands", `${normalizeSlashName(name)}.md`);
12516
12511
  }
12517
12512
  function buildDispatchPrompt(commandBody) {
12518
12513
  return [
@@ -12546,19 +12541,7 @@ function stamp2() {
12546
12541
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}${p(d.getMilliseconds(), 3)}`;
12547
12542
  }
12548
12543
  function cursorAgentDispatchArgs(opts) {
12549
- const args = [
12550
- "-p",
12551
- "--force",
12552
- "--sandbox",
12553
- "disabled",
12554
- "--output-format",
12555
- "stream-json",
12556
- "--workspace",
12557
- opts.workspace
12558
- ];
12559
- if (opts.model) args.push("--model", opts.model);
12560
- args.push(opts.prompt);
12561
- return args;
12544
+ return cursorAgentHeadlessArgs(opts);
12562
12545
  }
12563
12546
  function claudeDispatchArgs(opts = {}) {
12564
12547
  return claudeHeadlessArgs(opts);
@@ -12612,20 +12595,20 @@ async function runHeadlessDispatch(opts) {
12612
12595
  });
12613
12596
  }
12614
12597
  async function ensureDispatchLogPath(root) {
12615
- const logDir = path51.join(root, ".cursor", "loop-logs");
12598
+ const logDir = path52.join(root, ".cursor", "loop-logs");
12616
12599
  await mkdir7(logDir, { recursive: true });
12617
- return path51.join(logDir, `run-${stamp2()}.log`);
12600
+ return path52.join(logDir, `run-${stamp2()}.log`);
12618
12601
  }
12619
12602
 
12620
12603
  // src/commands/run.ts
12621
12604
  function displayPath(target, home = homedir4()) {
12622
- const resolvedHome = path52.resolve(home);
12605
+ const resolvedHome = path53.resolve(home);
12623
12606
  if (target === resolvedHome) return "~";
12624
- const prefix = resolvedHome.endsWith(path52.sep) ? resolvedHome : `${resolvedHome}${path52.sep}`;
12625
- return target.startsWith(prefix) ? `~${path52.sep}${target.slice(prefix.length)}` : target;
12607
+ const prefix = resolvedHome.endsWith(path53.sep) ? resolvedHome : `${resolvedHome}${path53.sep}`;
12608
+ return target.startsWith(prefix) ? `~${path53.sep}${target.slice(prefix.length)}` : target;
12626
12609
  }
12627
12610
  async function executeRun(input) {
12628
- const root = path52.resolve(input.cwd);
12611
+ const root = path53.resolve(input.cwd);
12629
12612
  const slash = normalizeSlashName(input.slash);
12630
12613
  if (!slash) {
12631
12614
  return { exitCode: 1, error: "Provide a slash: agent-kit run <slash>" };
@@ -12676,7 +12659,7 @@ async function executeRun(input) {
12676
12659
  const stdout = [
12677
12660
  "--dry-run: no agent will be started.",
12678
12661
  `Slash: ${slash}`,
12679
- `Command file: ${path52.relative(root, file.path)}`,
12662
+ `Command file: ${path53.relative(root, file.path)}`,
12680
12663
  `Backend: ${detected.id} (${displayPath(detected.bin)})`,
12681
12664
  "Prompt:",
12682
12665
  prompt
@@ -12685,8 +12668,8 @@ async function executeRun(input) {
12685
12668
  }
12686
12669
  const logPath = await ensureDispatchLogPath(root);
12687
12670
  console.log(`Dispatch: ${slash} via ${detected.id}`);
12688
- console.log(`Command file: ${path52.relative(root, file.path)}`);
12689
- console.log(`Log: ${path52.relative(root, logPath)}`);
12671
+ console.log(`Command file: ${path53.relative(root, file.path)}`);
12672
+ console.log(`Log: ${path53.relative(root, logPath)}`);
12690
12673
  try {
12691
12674
  const dispatch = {
12692
12675
  backendId: detected.id,
@@ -12843,7 +12826,7 @@ var scanCommand = defineCommand18({
12843
12826
  import { spawn as spawn9 } from "child_process";
12844
12827
  import { appendFile as appendFile2, mkdir as mkdir8, readFile as readFile29, writeFile as writeFile13 } from "fs/promises";
12845
12828
  import { homedir as homedir5 } from "os";
12846
- import path53 from "path";
12829
+ import path54 from "path";
12847
12830
  import { confirm as confirm2, isCancel as isCancel2 } from "@clack/prompts";
12848
12831
  import { defineCommand as defineCommand19 } from "citty";
12849
12832
  import { cyan as cyan5, green as green4, yellow as yellow3 } from "kolorist";
@@ -12852,9 +12835,9 @@ var SETUP_GLOBAL_MARKER = "# agent-kit setup-global";
12852
12835
  function planSetupGlobalSteps(env, options = {}) {
12853
12836
  const homeDir = options.homeDir ?? homedir5();
12854
12837
  const packageSpec = options.packageSpec ?? pinnedCliSpec();
12855
- const npmGlobalDir = path53.join(homeDir, NPM_GLOBAL_DIR_NAME);
12856
- const npmGlobalBin = path53.join(npmGlobalDir, "bin");
12857
- const npmrcPath = path53.join(homeDir, ".npmrc");
12838
+ const npmGlobalDir = path54.join(homeDir, NPM_GLOBAL_DIR_NAME);
12839
+ const npmGlobalBin = path54.join(npmGlobalDir, "bin");
12840
+ const npmrcPath = path54.join(homeDir, ".npmrc");
12858
12841
  const npmrcPrefixValue = `~/${NPM_GLOBAL_DIR_NAME}`;
12859
12842
  const pathExportLine = `export PATH="${npmGlobalBin}:$PATH"`;
12860
12843
  const shellProfile = env.shellProfile;
@@ -13153,7 +13136,7 @@ var setupGlobalCommand = defineCommand19({
13153
13136
  });
13154
13137
 
13155
13138
  // src/commands/status.ts
13156
- import path54 from "path";
13139
+ import path55 from "path";
13157
13140
  import { defineCommand as defineCommand20 } from "citty";
13158
13141
  function profileStatus(profile) {
13159
13142
  if (!profile) return { origin: "none", evidence: [], profile: null };
@@ -13184,11 +13167,11 @@ var statusCommand = defineCommand20({
13184
13167
  }
13185
13168
  },
13186
13169
  async run({ args }) {
13187
- const rootDir = path54.resolve(args.cwd);
13170
+ const rootDir = path55.resolve(args.cwd);
13188
13171
  const [manifest, rawProfile, scan, env] = await Promise.all([
13189
13172
  loadAgentKitManifest(rootDir),
13190
13173
  readJson(
13191
- path54.join(rootDir, ".cursor", "agent-kit.config.json")
13174
+ path55.join(rootDir, ".cursor", "agent-kit.config.json")
13192
13175
  ),
13193
13176
  runScanner(rootDir),
13194
13177
  assessEnvironment()
@@ -13296,17 +13279,7 @@ var updateCommand = defineCommand21({
13296
13279
  description: "Apply even when this CLI is older than the registry it is syncing from; the manifest is then stamped with this CLI's version, not the registry's (factory/dev only)",
13297
13280
  default: false
13298
13281
  },
13299
- yes: {
13300
- type: "boolean",
13301
- alias: "y",
13302
- description: "Skip interactive prompts; use defaults (IDE-agnostic non-interactive mode)",
13303
- default: false
13304
- },
13305
- "force-root": {
13306
- type: "boolean",
13307
- description: "Bypass the ambiguous-root guard (use with caution)",
13308
- default: false
13309
- },
13282
+ ...NON_INTERACTIVE_ROOT_ARGS,
13310
13283
  ...REGISTRY_CLI_ARGS
13311
13284
  },
13312
13285
  async run({ args }) {
@@ -13434,7 +13407,7 @@ ${err.recovery}
13434
13407
 
13435
13408
  // src/commands/validate.ts
13436
13409
  import { readFile as readFile30 } from "fs/promises";
13437
- import path55 from "path";
13410
+ import path56 from "path";
13438
13411
  import { defineCommand as defineCommand22 } from "citty";
13439
13412
 
13440
13413
  // src/invariants/plan-schema.ts
@@ -13481,7 +13454,7 @@ function validatePlanFrontmatterText(text) {
13481
13454
  // src/commands/validate.ts
13482
13455
  async function resolveEditedPath(cwd, explicit) {
13483
13456
  if (explicit) {
13484
- const filePath2 = path55.resolve(cwd, explicit);
13457
+ const filePath2 = path56.resolve(cwd, explicit);
13485
13458
  try {
13486
13459
  return { filePath: filePath2, content: await readFile30(filePath2, "utf8") };
13487
13460
  } catch {
@@ -13491,7 +13464,7 @@ async function resolveEditedPath(cwd, explicit) {
13491
13464
  const payload = await readStdinJson();
13492
13465
  const rel = typeof payload.file_path === "string" && payload.file_path || typeof payload.path === "string" && payload.path || typeof payload.file === "string" && payload.file || "";
13493
13466
  if (!rel) return null;
13494
- const filePath = path55.isAbsolute(rel) ? rel : path55.resolve(cwd, rel);
13467
+ const filePath = path56.isAbsolute(rel) ? rel : path56.resolve(cwd, rel);
13495
13468
  try {
13496
13469
  return { filePath, content: await readFile30(filePath, "utf8") };
13497
13470
  } catch {
@@ -13521,7 +13494,7 @@ var validateCommand = defineCommand22({
13521
13494
  async run({ args }) {
13522
13495
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
13523
13496
  const fileArg = typeof args.file === "string" ? args.file : void 0;
13524
- const filePath = fileArg ? path55.resolve(cwd, fileArg) : path55.join(path55.resolve(cwd), ".cursor", "HANDOFF.md");
13497
+ const filePath = fileArg ? path56.resolve(cwd, fileArg) : path56.join(path56.resolve(cwd), ".cursor", "HANDOFF.md");
13525
13498
  let content = "";
13526
13499
  try {
13527
13500
  content = await readFile30(filePath, "utf8");
@@ -13554,7 +13527,7 @@ var validateCommand = defineCommand22({
13554
13527
  process.exitCode = 2;
13555
13528
  return;
13556
13529
  }
13557
- const filePath = path55.resolve(cwd, fileArg);
13530
+ const filePath = path56.resolve(cwd, fileArg);
13558
13531
  let content = "";
13559
13532
  try {
13560
13533
  content = await readFile30(filePath, "utf8");
@@ -13576,7 +13549,7 @@ var validateCommand = defineCommand22({
13576
13549
  },
13577
13550
  async run({ args }) {
13578
13551
  const cwd = typeof args.cwd === "string" ? args.cwd : process.cwd();
13579
- const resolved = await resolveEditedPath(path55.resolve(cwd));
13552
+ const resolved = await resolveEditedPath(path56.resolve(cwd));
13580
13553
  if (!resolved) {
13581
13554
  console.log(JSON.stringify({}));
13582
13555
  return;