ai-ops-cli 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/index.js CHANGED
@@ -1409,12 +1409,12 @@ var buildPermissionProfileBlock = (paths, includeDefaultPermissions) => [
1409
1409
  `${quoteTomlString(paths.personalContextRoot)} = "write"`,
1410
1410
  `${quoteTomlString(join10(paths.userBasePath, ".ai-ops", "context-promotion"))} = "write"`,
1411
1411
  "",
1412
- `[permissions.${SAFE_LOCAL_CODEX_PERMISSION_NAME}.filesystem.":workspace_roots"]`,
1412
+ `[permissions.${SAFE_LOCAL_CODEX_PERMISSION_NAME}.filesystem.":project_roots"]`,
1413
1413
  '"." = "write"',
1414
1414
  '".git" = "read"',
1415
1415
  '".codex" = "read"',
1416
1416
  '".codex/plans" = "write"',
1417
- '"**/*.env" = "deny"',
1417
+ '"**/*.env" = "none"',
1418
1418
  "",
1419
1419
  `[permissions.${SAFE_LOCAL_CODEX_PERMISSION_NAME}.network]`,
1420
1420
  "enabled = false",
@@ -2082,13 +2082,14 @@ var pruneContextPromotionReceipts = (params) => {
2082
2082
  };
2083
2083
 
2084
2084
  // src/features/context-promotion/status.ts
2085
- import { existsSync as existsSync9 } from "fs";
2085
+ import { existsSync as existsSync10 } from "fs";
2086
2086
  import { join as join16, resolve as resolve8 } from "path";
2087
2087
 
2088
2088
  // src/features/project-layer/constants.ts
2089
2089
  import { join as join13 } from "path";
2090
2090
  var PROJECT_LAYER_MANIFEST_RELATIVE_PATH = ".ai-ops/manifest.json";
2091
2091
  var PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH = ".ai-ops/context-layer.json";
2092
+ var CUSTOM_PROJECT_RULES_DIR = "docs/agent/project-rules";
2092
2093
  var CONTEXT_LAYER_DATA_DIR = join13(COMPILER_DATA_DIR, "context-layer");
2093
2094
  var TOOL_ORDER2 = ["codex", "gemini", "claude-code"];
2094
2095
  var DEFAULT_TOOLS = TOOL_ORDER2;
@@ -2125,7 +2126,7 @@ var resolveProjectLayerManifestPath = (basePath) => join14(basePath, PROJECT_LAY
2125
2126
  var resolveProjectLayerContextIndexPath = (basePath) => join14(basePath, PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH);
2126
2127
  var resolveTemplatePath = (relativePath) => join14(CONTEXT_LAYER_DATA_DIR, relativePath);
2127
2128
  var toRelativeDir = (relativePath) => dirname8(relativePath);
2128
- var resolveProjectLayerFilePath2 = (basePath, relativePath) => {
2129
+ var resolveProjectLayerFilePath = (basePath, relativePath) => {
2129
2130
  if (!isSafeProjectLayerPath(relativePath)) {
2130
2131
  throw new Error(`Unsafe project layer path: ${relativePath}`);
2131
2132
  }
@@ -2258,18 +2259,86 @@ var loadProjectLayerTemplateSpecs = (tools) => {
2258
2259
  };
2259
2260
  var computeProjectLayerSourceHash = (specs) => computeHash(specs.map((spec) => `${spec.path}:${spec.content}`));
2260
2261
 
2262
+ // src/features/project-layer/custom-project-rules.ts
2263
+ import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "fs";
2264
+ var isMarkdownPath = (path) => path.endsWith(".md");
2265
+ var hasMarkdownFrontmatter = (content) => content.startsWith("---\n");
2266
+ var assertCustomProjectRuleContract = (params) => {
2267
+ if (params.owner !== "project") {
2268
+ throw new Error(`${params.path} owner\uB294 project\uC5EC\uC57C \uD569\uB2C8\uB2E4. \uD604\uC7AC \uAC12: ${params.owner}`);
2269
+ }
2270
+ if (params.layer !== "agent") {
2271
+ throw new Error(`${params.path} layer\uB294 agent\uC5EC\uC57C \uD569\uB2C8\uB2E4. \uD604\uC7AC \uAC12: ${params.layer}`);
2272
+ }
2273
+ };
2274
+ var isCustomProjectRulePath = (path) => path.startsWith(`${CUSTOM_PROJECT_RULES_DIR}/`) && isMarkdownPath(path);
2275
+ var collectMarkdownPaths = (params) => {
2276
+ const absoluteDir = resolveProjectLayerFilePath(params.basePath, params.relativeDir);
2277
+ if (!existsSync5(absoluteDir)) {
2278
+ return [];
2279
+ }
2280
+ return readdirSync3(absoluteDir, { withFileTypes: true }).flatMap((entry) => {
2281
+ const relativePath = `${params.relativeDir}/${entry.name}`;
2282
+ if (entry.isDirectory()) {
2283
+ return collectMarkdownPaths({ basePath: params.basePath, relativeDir: relativePath });
2284
+ }
2285
+ return entry.isFile() && isMarkdownPath(relativePath) ? [relativePath] : [];
2286
+ });
2287
+ };
2288
+ var discoverCustomProjectRuleFiles = (basePath) => collectMarkdownPaths({ basePath, relativeDir: CUSTOM_PROJECT_RULES_DIR }).sort((left, right) => left.localeCompare(right)).flatMap((path) => {
2289
+ const content = readFileSync9(resolveProjectLayerFilePath(basePath, path), "utf-8");
2290
+ if (!hasMarkdownFrontmatter(content)) {
2291
+ return [];
2292
+ }
2293
+ try {
2294
+ const document = parseProjectLayerDocument(path, content);
2295
+ assertCustomProjectRuleContract({
2296
+ path,
2297
+ owner: document.owner,
2298
+ layer: document.layer
2299
+ });
2300
+ return [
2301
+ {
2302
+ path,
2303
+ templateHash: document.contentHash,
2304
+ created: false
2305
+ }
2306
+ ];
2307
+ } catch (error) {
2308
+ const reason = error instanceof Error ? error.message : "unknown error";
2309
+ throw new Error(`${path} frontmatter \uD30C\uC2F1 \uC2E4\uD328: ${reason}`);
2310
+ }
2311
+ });
2312
+ var syncCustomProjectRuleFiles = (params) => {
2313
+ const customFiles = discoverCustomProjectRuleFiles(params.basePath);
2314
+ const customPathSet = new Set(customFiles.map((file) => file.path));
2315
+ const projectFilesByPath = /* @__PURE__ */ new Map();
2316
+ for (const file of params.manifest.project_files) {
2317
+ if (!isCustomProjectRulePath(file.path) || customPathSet.has(file.path)) {
2318
+ projectFilesByPath.set(file.path, file);
2319
+ }
2320
+ }
2321
+ for (const file of customFiles) {
2322
+ projectFilesByPath.set(file.path, file);
2323
+ }
2324
+ return ProjectLayerManifestSchema.parse({
2325
+ ...params.manifest,
2326
+ project_files: [...projectFilesByPath.values()].sort((left, right) => left.path.localeCompare(right.path))
2327
+ });
2328
+ };
2329
+
2261
2330
  // src/features/project-layer/state-io.ts
2262
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
2331
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "fs";
2263
2332
  import { dirname as dirname9 } from "path";
2264
2333
 
2265
2334
  // src/features/project-layer/docs-status.logic.ts
2266
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
2335
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
2267
2336
  var docsStatusIssue = (code, message) => ({
2268
2337
  level: "error",
2269
2338
  code,
2270
2339
  message
2271
2340
  });
2272
- var computeDocsStatusFileHash = (basePath, relativePath) => computeHash([readFileSync9(resolveProjectLayerFilePath2(basePath, relativePath), "utf-8").trimEnd()]);
2341
+ var computeDocsStatusFileHash = (basePath, relativePath) => computeHash([readFileSync10(resolveProjectLayerFilePath(basePath, relativePath), "utf-8").trimEnd()]);
2273
2342
  var parseMarkdownTableCells = (line) => {
2274
2343
  const trimmed = line.trim();
2275
2344
  if (!trimmed.startsWith("|") || !trimmed.endsWith("|")) {
@@ -2319,7 +2388,7 @@ var parseDocsStatusEntries = (content) => {
2319
2388
  });
2320
2389
  };
2321
2390
  var buildDocsStatusRowsFromDisk = (params) => params.documentPaths.map((path) => {
2322
- const document = parseProjectLayerDocument(path, readFileSync9(resolveProjectLayerFilePath2(params.basePath, path), "utf-8"));
2391
+ const document = parseProjectLayerDocument(path, readFileSync10(resolveProjectLayerFilePath(params.basePath, path), "utf-8"));
2323
2392
  return `| ${document.path} | ${document.status} | ${document.owner} |`;
2324
2393
  });
2325
2394
  var replaceDocsStatusRows = (content, rows) => {
@@ -2332,10 +2401,10 @@ var replaceDocsStatusRows = (content, rows) => {
2332
2401
  };
2333
2402
  var updateDocsStatusTable = (basePath, documentPaths) => {
2334
2403
  const docsStatusPath = "docs/docs-status.md";
2335
- const absolutePath = resolveProjectLayerFilePath2(basePath, docsStatusPath);
2404
+ const absolutePath = resolveProjectLayerFilePath(basePath, docsStatusPath);
2336
2405
  const beforeHash = computeDocsStatusFileHash(basePath, docsStatusPath);
2337
2406
  const rows = buildDocsStatusRowsFromDisk({ basePath, documentPaths });
2338
- const nextContent = replaceDocsStatusRows(readFileSync9(absolutePath, "utf-8"), rows);
2407
+ const nextContent = replaceDocsStatusRows(readFileSync10(absolutePath, "utf-8"), rows);
2339
2408
  writeFileSync6(absolutePath, nextContent, "utf-8");
2340
2409
  return {
2341
2410
  beforeHash,
@@ -2372,7 +2441,7 @@ var compareDocsStatusEntry = (params) => {
2372
2441
  // src/features/project-layer/state-io.ts
2373
2442
  var readProjectLayerManifest = (basePath) => {
2374
2443
  try {
2375
- return parseProjectLayerManifest(readFileSync10(resolveProjectLayerManifestPath(basePath), "utf-8"));
2444
+ return parseProjectLayerManifest(readFileSync11(resolveProjectLayerManifestPath(basePath), "utf-8"));
2376
2445
  } catch (error) {
2377
2446
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2378
2447
  return null;
@@ -2387,7 +2456,7 @@ var writeProjectLayerManifest = (basePath, manifest) => {
2387
2456
  };
2388
2457
  var readProjectLayerContextIndex = (basePath) => {
2389
2458
  try {
2390
- return parseProjectLayerContextIndex(readFileSync10(resolveProjectLayerContextIndexPath(basePath), "utf-8"));
2459
+ return parseProjectLayerContextIndex(readFileSync11(resolveProjectLayerContextIndexPath(basePath), "utf-8"));
2391
2460
  } catch (error) {
2392
2461
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
2393
2462
  return null;
@@ -2402,7 +2471,7 @@ var writeProjectLayerContextIndex = (basePath, contextIndex) => {
2402
2471
  };
2403
2472
  var buildContextIndexFromDisk = (params) => {
2404
2473
  const documents = params.documentPaths.map(
2405
- (path) => parseProjectLayerDocument(path, readFileSync10(resolveProjectLayerFilePath2(params.basePath, path), "utf-8"))
2474
+ (path) => parseProjectLayerDocument(path, readFileSync11(resolveProjectLayerFilePath(params.basePath, path), "utf-8"))
2406
2475
  );
2407
2476
  return ProjectLayerContextIndexSchema.parse({
2408
2477
  schemaVersion: 1,
@@ -2417,10 +2486,14 @@ var collectDocumentPathsFromManifest = (manifest) => [
2417
2486
  ...manifest.packs.flatMap((pack) => pack.documents.map((file) => file.path))
2418
2487
  ].sort();
2419
2488
  var refreshProjectLayerDerivedState = (params) => {
2420
- const documentPaths = collectDocumentPathsFromManifest(params.manifest);
2489
+ const manifestWithCustomRules = syncCustomProjectRuleFiles({
2490
+ basePath: params.basePath,
2491
+ manifest: params.manifest
2492
+ });
2493
+ const documentPaths = collectDocumentPathsFromManifest(manifestWithCustomRules);
2421
2494
  const docsStatusHashes = updateDocsStatusTable(params.basePath, documentPaths);
2422
2495
  const manifest = updateDocsStatusProjectFileRecord({
2423
- manifest: params.manifest,
2496
+ manifest: manifestWithCustomRules,
2424
2497
  beforeHash: docsStatusHashes.beforeHash,
2425
2498
  afterHash: docsStatusHashes.afterHash
2426
2499
  });
@@ -2437,17 +2510,17 @@ var refreshProjectLayerDerivedState = (params) => {
2437
2510
  };
2438
2511
 
2439
2512
  // src/features/project-layer/lifecycle.logic.ts
2440
- import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
2513
+ import { existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
2441
2514
  import { dirname as dirname10 } from "path";
2442
2515
 
2443
2516
  // src/features/project-layer/uninstall.logic.ts
2444
- import { existsSync as existsSync5, readFileSync as readFileSync11, readdirSync as readdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync8 } from "fs";
2517
+ import { existsSync as existsSync6, readFileSync as readFileSync12, readdirSync as readdirSync4, rmSync as rmSync2, writeFileSync as writeFileSync8 } from "fs";
2445
2518
  function removeManagedProjectFile(basePath, relativePath) {
2446
- const absolutePath = resolveProjectLayerFilePath2(basePath, relativePath);
2447
- if (!existsSync5(absolutePath)) {
2519
+ const absolutePath = resolveProjectLayerFilePath(basePath, relativePath);
2520
+ if (!existsSync6(absolutePath)) {
2448
2521
  return { deleted: [], cleaned: [], preserved: [], notFound: [relativePath] };
2449
2522
  }
2450
- const content = readFileSync11(absolutePath, "utf-8");
2523
+ const content = readFileSync12(absolutePath, "utf-8");
2451
2524
  if (!hasAiOpsSection(content)) {
2452
2525
  return { deleted: [], cleaned: [], preserved: [relativePath], notFound: [] };
2453
2526
  }
@@ -2460,11 +2533,11 @@ function removeManagedProjectFile(basePath, relativePath) {
2460
2533
  return { deleted: [], cleaned: [relativePath], preserved: [], notFound: [] };
2461
2534
  }
2462
2535
  var removeCreateOnlyProjectFile = (basePath, file) => {
2463
- const absolutePath = resolveProjectLayerFilePath2(basePath, file.path);
2464
- if (!existsSync5(absolutePath)) {
2536
+ const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
2537
+ if (!existsSync6(absolutePath)) {
2465
2538
  return { deleted: [], cleaned: [], preserved: [], notFound: [file.path] };
2466
2539
  }
2467
- const content = readFileSync11(absolutePath, "utf-8").trimEnd();
2540
+ const content = readFileSync12(absolutePath, "utf-8").trimEnd();
2468
2541
  const currentHash = computeHash([content]);
2469
2542
  if (file.created && currentHash === file.templateHash) {
2470
2543
  rmSync2(absolutePath);
@@ -2473,11 +2546,11 @@ var removeCreateOnlyProjectFile = (basePath, file) => {
2473
2546
  return { deleted: [], cleaned: [], preserved: [file.path], notFound: [] };
2474
2547
  };
2475
2548
  var removePackOwnedFile = (basePath, file) => {
2476
- const absolutePath = resolveProjectLayerFilePath2(basePath, file.path);
2477
- if (!existsSync5(absolutePath)) {
2549
+ const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
2550
+ if (!existsSync6(absolutePath)) {
2478
2551
  return { deleted: [], cleaned: [], preserved: [], notFound: [file.path] };
2479
2552
  }
2480
- const currentHash = computeHash([readFileSync11(absolutePath, "utf-8").trimEnd()]);
2553
+ const currentHash = computeHash([readFileSync12(absolutePath, "utf-8").trimEnd()]);
2481
2554
  if (currentHash === file.sourceHash) {
2482
2555
  rmSync2(absolutePath);
2483
2556
  return { deleted: [file.path], cleaned: [], preserved: [], notFound: [] };
@@ -2495,10 +2568,10 @@ var removeEmptyDirs = (basePath, relativePaths) => {
2495
2568
  (a, b) => b.length - a.length
2496
2569
  );
2497
2570
  for (const dir of [...dirs, ".ai-ops"]) {
2498
- const absoluteDir = resolveProjectLayerFilePath2(basePath, dir);
2499
- if (!existsSync5(absoluteDir)) continue;
2571
+ const absoluteDir = resolveProjectLayerFilePath(basePath, dir);
2572
+ if (!existsSync6(absoluteDir)) continue;
2500
2573
  try {
2501
- if (readdirSync3(absoluteDir).length === 0) {
2574
+ if (readdirSync4(absoluteDir).length === 0) {
2502
2575
  rmSync2(absoluteDir, { recursive: true });
2503
2576
  }
2504
2577
  } catch {
@@ -2513,7 +2586,7 @@ var uninstallProjectLayer = (basePath, manifest) => {
2513
2586
  );
2514
2587
  const stateFiles = [PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH, PROJECT_LAYER_MANIFEST_RELATIVE_PATH];
2515
2588
  for (const stateFile of stateFiles) {
2516
- rmSync2(resolveProjectLayerFilePath2(basePath, stateFile), { force: true });
2589
+ rmSync2(resolveProjectLayerFilePath(basePath, stateFile), { force: true });
2517
2590
  }
2518
2591
  const result = mergeRemoveResults([...managedResults, ...projectResults, ...packResults]);
2519
2592
  removeEmptyDirs(basePath, [...result.deleted, ...stateFiles]);
@@ -2525,15 +2598,15 @@ var installManagedFiles = (basePath, specs, meta) => {
2525
2598
  const written = [];
2526
2599
  const appended = [];
2527
2600
  for (const spec of specs) {
2528
- const absolutePath = resolveProjectLayerFilePath2(basePath, spec.path);
2601
+ const absolutePath = resolveProjectLayerFilePath(basePath, spec.path);
2529
2602
  const wrappedContent = wrapWithSection(spec.content, meta);
2530
- if (!existsSync6(absolutePath)) {
2603
+ if (!existsSync7(absolutePath)) {
2531
2604
  mkdirSync7(dirname10(absolutePath), { recursive: true });
2532
2605
  writeFileSync9(absolutePath, wrappedContent + "\n", "utf-8");
2533
2606
  written.push(spec.path);
2534
2607
  continue;
2535
2608
  }
2536
- const existing = readFileSync12(absolutePath, "utf-8");
2609
+ const existing = readFileSync13(absolutePath, "utf-8");
2537
2610
  if (hasAiOpsSection(existing)) {
2538
2611
  writeFileSync9(absolutePath, replaceAiOpsSection(existing, wrappedContent), "utf-8");
2539
2612
  const stripped = stripAiOpsSection(existing);
@@ -2557,9 +2630,9 @@ var installProjectFiles = (params) => {
2557
2630
  const preserved = [];
2558
2631
  const previousByPath = new Map((params.previousProjectFiles ?? []).map((file) => [file.path, file]));
2559
2632
  for (const spec of params.specs) {
2560
- const absolutePath = resolveProjectLayerFilePath2(params.basePath, spec.path);
2633
+ const absolutePath = resolveProjectLayerFilePath(params.basePath, spec.path);
2561
2634
  const previous = previousByPath.get(spec.path);
2562
- if (!existsSync6(absolutePath)) {
2635
+ if (!existsSync7(absolutePath)) {
2563
2636
  mkdirSync7(dirname10(absolutePath), { recursive: true });
2564
2637
  writeFileSync9(absolutePath, spec.content + "\n", "utf-8");
2565
2638
  created.push(spec.path);
@@ -2570,7 +2643,7 @@ var installProjectFiles = (params) => {
2570
2643
  });
2571
2644
  continue;
2572
2645
  }
2573
- const existingContent = readFileSync12(absolutePath, "utf-8").trimEnd();
2646
+ const existingContent = readFileSync13(absolutePath, "utf-8").trimEnd();
2574
2647
  const existingHash = computeHash([existingContent]);
2575
2648
  if (previous?.created === true && existingHash === previous.templateHash) {
2576
2649
  if (existingHash !== spec.contentHash) {
@@ -2704,7 +2777,7 @@ var updateProjectLayer = (params) => {
2704
2777
  };
2705
2778
 
2706
2779
  // src/features/project-layer/audit.logic.ts
2707
- import { existsSync as existsSync7, readFileSync as readFileSync13 } from "fs";
2780
+ import { existsSync as existsSync8, readFileSync as readFileSync14 } from "fs";
2708
2781
  var issue = (level, code, message) => ({
2709
2782
  level,
2710
2783
  code,
@@ -2712,11 +2785,11 @@ var issue = (level, code, message) => ({
2712
2785
  });
2713
2786
  var readDocumentSafely = (basePath, path) => {
2714
2787
  try {
2715
- const absolutePath = resolveProjectLayerFilePath2(basePath, path);
2716
- if (!existsSync7(absolutePath)) {
2788
+ const absolutePath = resolveProjectLayerFilePath(basePath, path);
2789
+ if (!existsSync8(absolutePath)) {
2717
2790
  return issue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${path}`);
2718
2791
  }
2719
- return parseProjectLayerDocument(path, readFileSync13(absolutePath, "utf-8"));
2792
+ return parseProjectLayerDocument(path, readFileSync14(absolutePath, "utf-8"));
2720
2793
  } catch (error) {
2721
2794
  const reason = error instanceof Error ? error.message : "unknown error";
2722
2795
  return issue("error", "invalid-frontmatter", `${path} frontmatter \uD30C\uC2F1 \uC2E4\uD328: ${reason}`);
@@ -2724,6 +2797,10 @@ var readDocumentSafely = (basePath, path) => {
2724
2797
  };
2725
2798
  var buildContextIndexMap = (contextIndex) => new Map((contextIndex?.documents ?? []).map((document) => [document.path, document]));
2726
2799
  var compareArray = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
2800
+ var compareProjectFileRecords = (left, right) => left.length === right.length && left.every((file, index) => {
2801
+ const other = right[index];
2802
+ return other !== void 0 && file.path === other.path && file.templateHash === other.templateHash && file.created === other.created;
2803
+ });
2727
2804
  var compareContextDocument = (params) => {
2728
2805
  const indexed = params.indexed;
2729
2806
  if (indexed === void 0) {
@@ -2767,6 +2844,13 @@ var diffProjectLayer = (basePath) => {
2767
2844
  const currentSourceHash = computeProjectLayerSourceHash(specs);
2768
2845
  let contextIndex = null;
2769
2846
  const issues = [];
2847
+ let syncedManifest = manifest;
2848
+ try {
2849
+ syncedManifest = syncCustomProjectRuleFiles({ basePath, manifest });
2850
+ } catch (error) {
2851
+ const reason = error instanceof Error ? error.message : "unknown error";
2852
+ issues.push(issue("error", "invalid-custom-project-rule", reason));
2853
+ }
2770
2854
  try {
2771
2855
  contextIndex = readProjectLayerContextIndex(basePath);
2772
2856
  } catch (error) {
@@ -2786,18 +2870,27 @@ var diffProjectLayer = (basePath) => {
2786
2870
  if (contextIndex === null) {
2787
2871
  issues.push(issue("error", "missing-context-index", `${PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH}\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`));
2788
2872
  }
2873
+ if (!compareProjectFileRecords(manifest.project_files, syncedManifest.project_files)) {
2874
+ issues.push(
2875
+ issue(
2876
+ "warning",
2877
+ "custom-project-rules-drift",
2878
+ "`docs/agent/project-rules/**/*.md` discovery \uACB0\uACFC\uAC00 manifest\uC640 \uB2E4\uB985\uB2C8\uB2E4. `ai-ops update`\uB85C \uB3D9\uAE30\uD654\uD558\uC138\uC694."
2879
+ )
2880
+ );
2881
+ }
2789
2882
  for (const expectedPath of expectedManagedPaths) {
2790
2883
  if (!manifestManagedPaths.has(expectedPath)) {
2791
2884
  issues.push(issue("error", "manifest-missing-managed-file", `manifest managed_files \uB204\uB77D: ${expectedPath}`));
2792
2885
  }
2793
2886
  }
2794
2887
  for (const file of manifest.managed_files) {
2795
- const absolutePath = resolveProjectLayerFilePath2(basePath, file.path);
2796
- if (!existsSync7(absolutePath)) {
2888
+ const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
2889
+ if (!existsSync8(absolutePath)) {
2797
2890
  issues.push(issue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
2798
2891
  continue;
2799
2892
  }
2800
- const content = readFileSync13(absolutePath, "utf-8");
2893
+ const content = readFileSync14(absolutePath, "utf-8");
2801
2894
  const meta = parseAiOpsMeta(content);
2802
2895
  if (!meta) {
2803
2896
  issues.push(issue("error", "missing-managed-section", `managed section \uBA54\uD0C0 \uC5C6\uC74C: ${file.path}`));
@@ -2809,19 +2902,19 @@ var diffProjectLayer = (basePath) => {
2809
2902
  );
2810
2903
  }
2811
2904
  }
2812
- for (const file of manifest.project_files) {
2813
- if (!existsSync7(resolveProjectLayerFilePath2(basePath, file.path))) {
2905
+ for (const file of syncedManifest.project_files) {
2906
+ if (!existsSync8(resolveProjectLayerFilePath(basePath, file.path))) {
2814
2907
  issues.push(issue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
2815
2908
  }
2816
2909
  }
2817
- for (const pack of manifest.packs) {
2910
+ for (const pack of syncedManifest.packs) {
2818
2911
  for (const file of [...pack.documents, ...pack.files]) {
2819
- if (!existsSync7(resolveProjectLayerFilePath2(basePath, file.path))) {
2912
+ if (!existsSync8(resolveProjectLayerFilePath(basePath, file.path))) {
2820
2913
  issues.push(issue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
2821
2914
  }
2822
2915
  }
2823
2916
  }
2824
- for (const path of collectDocumentPathsFromManifest(manifest)) {
2917
+ for (const path of collectDocumentPathsFromManifest(syncedManifest)) {
2825
2918
  const document = readDocumentSafely(basePath, path);
2826
2919
  if ("code" in document) {
2827
2920
  issues.push(document);
@@ -2848,18 +2941,24 @@ var auditProjectLayer = (basePath) => {
2848
2941
  } catch {
2849
2942
  contextIndex = null;
2850
2943
  }
2851
- const documentPaths = collectDocumentPathsFromManifest(manifest);
2944
+ let syncedManifest = manifest;
2945
+ try {
2946
+ syncedManifest = syncCustomProjectRuleFiles({ basePath, manifest });
2947
+ } catch {
2948
+ return diffReport;
2949
+ }
2950
+ const documentPaths = collectDocumentPathsFromManifest(syncedManifest);
2852
2951
  const documentPathSet = new Set(documentPaths);
2853
2952
  const contextPathSet = new Set(contextIndex?.documents.map((document) => document.path) ?? []);
2854
2953
  const issues = [...diffReport.issues];
2855
- const docsStatusPath = resolveProjectLayerFilePath2(basePath, "docs/docs-status.md");
2856
- if (!existsSync7(docsStatusPath)) {
2954
+ const docsStatusPath = resolveProjectLayerFilePath(basePath, "docs/docs-status.md");
2955
+ if (!existsSync8(docsStatusPath)) {
2857
2956
  issues.push(issue("error", "missing-docs-status", "docs/docs-status.md\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
2858
2957
  return { currentSourceHash: diffReport.currentSourceHash, issues };
2859
2958
  }
2860
2959
  let docsStatusEntries = [];
2861
2960
  try {
2862
- docsStatusEntries = parseDocsStatusEntries(readFileSync13(docsStatusPath, "utf-8"));
2961
+ docsStatusEntries = parseDocsStatusEntries(readFileSync14(docsStatusPath, "utf-8"));
2863
2962
  } catch (error) {
2864
2963
  const reason = error instanceof Error ? error.message : "unknown error";
2865
2964
  issues.push(issue("error", "invalid-docs-status", `docs/docs-status.md \uD30C\uC2F1 \uC2E4\uD328: ${reason}`));
@@ -2886,11 +2985,11 @@ var auditProjectLayer = (basePath) => {
2886
2985
  };
2887
2986
 
2888
2987
  // src/features/project-layer/pack.logic.ts
2889
- import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync15, readdirSync as readdirSync5, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "fs";
2988
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync16, readdirSync as readdirSync6, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "fs";
2890
2989
  import { dirname as dirname11 } from "path";
2891
2990
 
2892
2991
  // src/features/project-layer/pack-source.logic.ts
2893
- import { readFileSync as readFileSync14, readdirSync as readdirSync4 } from "fs";
2992
+ import { readFileSync as readFileSync15, readdirSync as readdirSync5 } from "fs";
2894
2993
  import { isAbsolute as isAbsolute2, join as join15, relative as relative2, resolve as resolve7 } from "path";
2895
2994
  var PACK_REGISTRY_FILENAME = "pack-registry.json";
2896
2995
  var SPEC_LIFECYCLE_PACK_ID = "spec-lifecycle";
@@ -2901,7 +3000,7 @@ var RESERVED_DOCUMENT_WARNINGS2 = [
2901
3000
  ];
2902
3001
  var DEFAULT_PACKS_DIR = join15(COMPILER_DATA_DIR, "packs");
2903
3002
  var includesReservedDocumentWarning2 = (content) => RESERVED_DOCUMENT_WARNINGS2.some((warning) => content.includes(warning));
2904
- var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(readFileSync14(join15(packsDir, PACK_REGISTRY_FILENAME), "utf-8")));
3003
+ var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(readFileSync15(join15(packsDir, PACK_REGISTRY_FILENAME), "utf-8")));
2905
3004
  var assertPackInstallPath = (path) => {
2906
3005
  if (!isSafeProjectLayerPath(path) || !path.startsWith(PACK_INSTALL_ROOT)) {
2907
3006
  throw new Error(`Unsafe pack path: ${path}`);
@@ -2911,7 +3010,7 @@ var readPackSourceFiles = (packDir) => {
2911
3010
  const files = [];
2912
3011
  const walk = (relativeDir = "") => {
2913
3012
  const absoluteDir = relativeDir.length > 0 ? join15(packDir, relativeDir) : packDir;
2914
- const entries = readdirSync4(absoluteDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
3013
+ const entries = readdirSync5(absoluteDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
2915
3014
  for (const entry of entries) {
2916
3015
  const nextRelativePath = relativeDir.length > 0 ? join15(relativeDir, entry.name) : entry.name;
2917
3016
  if (entry.isDirectory()) {
@@ -2919,7 +3018,7 @@ var readPackSourceFiles = (packDir) => {
2919
3018
  continue;
2920
3019
  }
2921
3020
  assertPackInstallPath(nextRelativePath);
2922
- const content = readFileSync14(join15(packDir, nextRelativePath), "utf-8");
3021
+ const content = readFileSync15(join15(packDir, nextRelativePath), "utf-8");
2923
3022
  files.push({
2924
3023
  path: nextRelativePath,
2925
3024
  content,
@@ -2979,9 +3078,9 @@ var resolvePackById = (packsDir, packId) => {
2979
3078
 
2980
3079
  // src/features/project-layer/pack.logic.ts
2981
3080
  var serializePackFileContent = (content) => content.length === 0 ? "" : content.trimEnd() + "\n";
2982
- var readProjectFileHash = (basePath, relativePath) => computeHash([readFileSync15(resolveProjectLayerFilePath2(basePath, relativePath), "utf-8").trimEnd()]);
3081
+ var readProjectFileHash = (basePath, relativePath) => computeHash([readFileSync16(resolveProjectLayerFilePath(basePath, relativePath), "utf-8").trimEnd()]);
2983
3082
  var writePackFile = (basePath, file) => {
2984
- const absolutePath = resolveProjectLayerFilePath2(basePath, file.path);
3083
+ const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
2985
3084
  mkdirSync8(dirname11(absolutePath), { recursive: true });
2986
3085
  writeFileSync10(absolutePath, serializePackFileContent(file.content), "utf-8");
2987
3086
  };
@@ -3011,9 +3110,9 @@ var applyPackSourceFiles = (params) => {
3011
3110
  ])
3012
3111
  );
3013
3112
  for (const file of sourceFiles) {
3014
- const absolutePath = resolveProjectLayerFilePath2(params.basePath, file.path);
3113
+ const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
3015
3114
  const previous = previousByPath.get(file.path);
3016
- if (!existsSync8(absolutePath)) {
3115
+ if (!existsSync9(absolutePath)) {
3017
3116
  writePackFile(params.basePath, file);
3018
3117
  written.push(file.path);
3019
3118
  continue;
@@ -3036,8 +3135,8 @@ var applyPackSourceFiles = (params) => {
3036
3135
  if (sourceByPath.has(previous.path)) {
3037
3136
  continue;
3038
3137
  }
3039
- const absolutePath = resolveProjectLayerFilePath2(params.basePath, previous.path);
3040
- if (!existsSync8(absolutePath)) {
3138
+ const absolutePath = resolveProjectLayerFilePath(params.basePath, previous.path);
3139
+ if (!existsSync9(absolutePath)) {
3041
3140
  notFound.push(previous.path);
3042
3141
  continue;
3043
3142
  }
@@ -3055,8 +3154,8 @@ var removePackFiles = (basePath, record) => {
3055
3154
  const preserved = [];
3056
3155
  const notFound = [];
3057
3156
  for (const file of [...record.documents, ...record.files]) {
3058
- const absolutePath = resolveProjectLayerFilePath2(basePath, file.path);
3059
- if (!existsSync8(absolutePath)) {
3157
+ const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
3158
+ if (!existsSync9(absolutePath)) {
3060
3159
  notFound.push(file.path);
3061
3160
  continue;
3062
3161
  }
@@ -3074,12 +3173,12 @@ var removeEmptyDirs2 = (basePath, relativePaths) => {
3074
3173
  (a, b) => b.length - a.length
3075
3174
  );
3076
3175
  for (const dir of dirs) {
3077
- const absoluteDir = resolveProjectLayerFilePath2(basePath, dir);
3078
- if (!existsSync8(absoluteDir)) {
3176
+ const absoluteDir = resolveProjectLayerFilePath(basePath, dir);
3177
+ if (!existsSync9(absoluteDir)) {
3079
3178
  continue;
3080
3179
  }
3081
3180
  try {
3082
- if (readdirSync5(absoluteDir).length === 0) {
3181
+ if (readdirSync6(absoluteDir).length === 0) {
3083
3182
  rmSync3(absoluteDir, { recursive: true });
3084
3183
  }
3085
3184
  } catch {
@@ -3190,8 +3289,8 @@ var diffProjectLayerPack = (params) => {
3190
3289
  );
3191
3290
  }
3192
3291
  for (const file of [...record.documents, ...record.files]) {
3193
- const absolutePath = resolveProjectLayerFilePath2(params.basePath, file.path);
3194
- if (!existsSync8(absolutePath)) {
3292
+ const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
3293
+ if (!existsSync9(absolutePath)) {
3195
3294
  issues.push(packIssue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
3196
3295
  }
3197
3296
  }
@@ -3200,7 +3299,7 @@ var diffProjectLayerPack = (params) => {
3200
3299
  };
3201
3300
 
3202
3301
  // src/features/context-promotion/status.ts
3203
- var hasContextPromotionLayer = (gitRoot) => existsSync9(join16(gitRoot, PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH));
3302
+ var hasContextPromotionLayer = (gitRoot) => existsSync10(join16(gitRoot, PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH));
3204
3303
  var getContextPromotionStatus = (params) => {
3205
3304
  const cwd = resolve8(params.cwd);
3206
3305
  const gitRoot = resolveContextPromotionGitRoot(cwd);
@@ -3528,11 +3627,11 @@ import * as p5 from "@clack/prompts";
3528
3627
 
3529
3628
  // src/features/pc/status.ts
3530
3629
  import { execFileSync as execFileSync2 } from "child_process";
3531
- import { existsSync as existsSync10, readdirSync as readdirSync6 } from "fs";
3630
+ import { existsSync as existsSync11, readdirSync as readdirSync7 } from "fs";
3532
3631
  import { join as join17, resolve as resolve10, sep as sep2 } from "path";
3533
3632
 
3534
3633
  // src/features/pc/markdown.ts
3535
- import { readFileSync as readFileSync16 } from "fs";
3634
+ import { readFileSync as readFileSync17 } from "fs";
3536
3635
  import { resolve as resolve9, sep } from "path";
3537
3636
  var normalizePath = (path) => resolve9(path.replace(/^~(?=$|\/)/, process.env.HOME ?? "~"));
3538
3637
  var pathContains = (parentPath, childPath) => {
@@ -3571,7 +3670,7 @@ var parseListField = (content, labels) => {
3571
3670
  };
3572
3671
  var readTextFileOrNull = (filePath) => {
3573
3672
  try {
3574
- return readFileSync16(filePath, "utf-8");
3673
+ return readFileSync17(filePath, "utf-8");
3575
3674
  } catch {
3576
3675
  return null;
3577
3676
  }
@@ -3599,10 +3698,10 @@ var readGitHead2 = (cwd) => {
3599
3698
  };
3600
3699
  var listWorkspaceStatePaths = (contextRoot) => {
3601
3700
  const workspacesDir = join17(contextRoot, "workspaces");
3602
- if (!existsSync10(workspacesDir)) {
3701
+ if (!existsSync11(workspacesDir)) {
3603
3702
  return [];
3604
3703
  }
3605
- return readdirSync6(workspacesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join17(workspacesDir, entry.name, "workspace-state.md")).filter((statePath) => existsSync10(statePath)).sort((a, b) => a.localeCompare(b));
3704
+ return readdirSync7(workspacesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join17(workspacesDir, entry.name, "workspace-state.md")).filter((statePath) => existsSync11(statePath)).sort((a, b) => a.localeCompare(b));
3606
3705
  };
3607
3706
  var parseWorkspaceCandidate = (statePath) => {
3608
3707
  const content = readTextFileOrNull(statePath);
@@ -3646,10 +3745,10 @@ var parseRepoEntry = (entryPath) => {
3646
3745
  };
3647
3746
  var findCurrentEntry = (params) => {
3648
3747
  const reposDir = join17(params.workspaceDir, "repos");
3649
- if (!existsSync10(reposDir)) {
3748
+ if (!existsSync11(reposDir)) {
3650
3749
  return null;
3651
3750
  }
3652
- const entries = readdirSync6(reposDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => parseRepoEntry(join17(reposDir, entry.name))).filter((entry) => entry !== null).filter((entry) => {
3751
+ const entries = readdirSync7(reposDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => parseRepoEntry(join17(reposDir, entry.name))).filter((entry) => entry !== null).filter((entry) => {
3653
3752
  const paths = [entry.path, entry.gitRoot].filter((path) => path !== null);
3654
3753
  return paths.some((path) => pathContains(path, params.cwd));
3655
3754
  }).sort((a, b) => {
@@ -3701,7 +3800,7 @@ var parseLastConfirmedCommitHash = (params) => {
3701
3800
  var getPcHandoffStatus = (params) => {
3702
3801
  const cwd = normalizePath(params.cwd);
3703
3802
  const contextRoot = normalizePath(params.contextRoot);
3704
- if (!existsSync10(contextRoot)) {
3803
+ if (!existsSync11(contextRoot)) {
3705
3804
  return {
3706
3805
  cwd,
3707
3806
  contextRoot,
@@ -3864,7 +3963,7 @@ var evaluatePcPostToolUseHook = (params) => {
3864
3963
  };
3865
3964
 
3866
3965
  // src/features/integrations/manifest-io.ts
3867
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync17, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
3966
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync18, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
3868
3967
  import { dirname as dirname12, join as join18 } from "path";
3869
3968
  var INTEGRATION_MANIFEST_FILENAME = "integrations-manifest.json";
3870
3969
  var parseIntegrationManifest = (json) => IntegrationManifestSchema.parse(JSON.parse(json));
@@ -3873,7 +3972,7 @@ var resolveIntegrationManifestPath = (userBasePath) => join18(userBasePath, ".ai
3873
3972
  var readIntegrationManifest = (manifestPath) => {
3874
3973
  let raw;
3875
3974
  try {
3876
- raw = readFileSync17(manifestPath, "utf-8");
3975
+ raw = readFileSync18(manifestPath, "utf-8");
3877
3976
  } catch {
3878
3977
  return null;
3879
3978
  }
@@ -3906,7 +4005,7 @@ var writeUserIntegrationState = (params) => {
3906
4005
  };
3907
4006
 
3908
4007
  // src/features/integrations/components.ts
3909
- import { existsSync as existsSync11, rmSync as rmSync5 } from "fs";
4008
+ import { existsSync as existsSync12, rmSync as rmSync5 } from "fs";
3910
4009
  import { join as join19 } from "path";
3911
4010
  var readInstalledSkills2 = (basePath) => (readSkillRegistry(resolveSkillRegistryPath(basePath))?.skills ?? []).map((installedSkill) => ({
3912
4011
  ...installedSkill,
@@ -3921,7 +4020,7 @@ var resolveSkillById = (skillId) => {
3921
4020
  };
3922
4021
  var hasInstalledCodexSkill = (params) => {
3923
4022
  const installedSkill = findInstalledSkill(readInstalledSkills2(params.basePath), params.skillId);
3924
- return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true && existsSync11(join19(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
4023
+ return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true && existsSync12(join19(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
3925
4024
  };
3926
4025
  var writeUserSkillState = (params) => {
3927
4026
  const registryPath = resolveSkillRegistryPath(params.basePath);
@@ -3949,7 +4048,7 @@ var ensureSkillComponent = (params) => {
3949
4048
  skill,
3950
4049
  requestedTools
3951
4050
  });
3952
- const alreadyCurrent = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) && existsSync11(join19(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
4051
+ const alreadyCurrent = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) && existsSync12(join19(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
3953
4052
  if (alreadyCurrent) {
3954
4053
  return {
3955
4054
  type: INTEGRATION_COMPONENT_TYPE.SKILL,
@@ -4884,7 +4983,7 @@ var registerSkillCommands = (program) => {
4884
4983
  import { join as join23 } from "path";
4885
4984
 
4886
4985
  // src/features/studio/project-snapshot.ts
4887
- import { existsSync as existsSync12, readFileSync as readFileSync18 } from "fs";
4986
+ import { existsSync as existsSync13, readFileSync as readFileSync19 } from "fs";
4888
4987
  import { resolve as resolve11 } from "path";
4889
4988
  import { z as z14 } from "zod";
4890
4989
 
@@ -4951,7 +5050,9 @@ var AUDIT_ISSUE_SOURCES_BY_CODE = {
4951
5050
  "invalid-frontmatter": "frontmatter",
4952
5051
  "missing-managed-section": "managed-section",
4953
5052
  "source-hash-drift": "source-hash",
4954
- "managed-source-hash-drift": "source-hash"
5053
+ "managed-source-hash-drift": "source-hash",
5054
+ "invalid-custom-project-rule": "frontmatter",
5055
+ "custom-project-rules-drift": "manifest"
4955
5056
  };
4956
5057
  var AUDIT_ISSUE_ACTION_LABELS_BY_SOURCE = {
4957
5058
  manifest: "Review manifest record",
@@ -4998,6 +5099,10 @@ var extractTrailingIssuePath = (message) => {
4998
5099
  const [firstToken] = trailingSegment.trim().split(/\s+/);
4999
5100
  return firstToken === void 0 ? null : parsePathLikeToken(firstToken);
5000
5101
  };
5102
+ var extractLeadingIssuePath = (message) => {
5103
+ const [firstToken] = message.trim().split(/\s+/);
5104
+ return firstToken === void 0 ? null : parsePathLikeToken(firstToken);
5105
+ };
5001
5106
  var resolveIssueSource = (issue2) => AUDIT_ISSUE_SOURCES_BY_CODE[issue2.code] ?? "unknown";
5002
5107
  var resolveIssueAffectedPath = (params) => {
5003
5108
  if (params.issue.code === "missing-manifest" || params.issue.code === "invalid-manifest") {
@@ -5012,6 +5117,9 @@ var resolveIssueAffectedPath = (params) => {
5012
5117
  if (params.issue.code === "source-hash-drift") {
5013
5118
  return null;
5014
5119
  }
5120
+ if (params.issue.code === "invalid-custom-project-rule") {
5121
+ return extractLeadingIssuePath(params.issue.message);
5122
+ }
5015
5123
  const knownPath = findKnownPathInMessage(params.issue.message, params.knownPaths);
5016
5124
  if (knownPath !== null) {
5017
5125
  return knownPath;
@@ -5051,7 +5159,7 @@ var RecoverableContextIndexSchema = z14.object({
5051
5159
  });
5052
5160
  var readProjectManifestSnapshot = (basePath) => {
5053
5161
  const manifestPath = resolveProjectLayerManifestPath(basePath);
5054
- if (!existsSync12(manifestPath)) {
5162
+ if (!existsSync13(manifestPath)) {
5055
5163
  return {
5056
5164
  source: createMissingSourceState(PROJECT_LAYER_MANIFEST_RELATIVE_PATH),
5057
5165
  manifest: null
@@ -5082,14 +5190,14 @@ var readProjectManifestSnapshot = (basePath) => {
5082
5190
  };
5083
5191
  var readProjectContextIndexSnapshot = (basePath) => {
5084
5192
  const contextIndexPath = resolveProjectLayerContextIndexPath(basePath);
5085
- if (!existsSync12(contextIndexPath)) {
5193
+ if (!existsSync13(contextIndexPath)) {
5086
5194
  return {
5087
5195
  source: createMissingSourceState(PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH),
5088
5196
  contextIndex: null
5089
5197
  };
5090
5198
  }
5091
5199
  try {
5092
- const parsedJson = JSON.parse(readFileSync18(contextIndexPath, "utf-8"));
5200
+ const parsedJson = JSON.parse(readFileSync19(contextIndexPath, "utf-8"));
5093
5201
  const strictContextIndex = ProjectLayerContextIndexSchema.safeParse(parsedJson);
5094
5202
  if (strictContextIndex.success) {
5095
5203
  return {
@@ -5146,12 +5254,12 @@ var readProjectContextIndexSnapshot = (basePath) => {
5146
5254
  }
5147
5255
  };
5148
5256
  var readDocsStatusSourceState = (basePath) => {
5149
- const docsStatusPath = resolveProjectLayerFilePath2(basePath, DOCS_STATUS_RELATIVE_PATH);
5150
- if (!existsSync12(docsStatusPath)) {
5257
+ const docsStatusPath = resolveProjectLayerFilePath(basePath, DOCS_STATUS_RELATIVE_PATH);
5258
+ if (!existsSync13(docsStatusPath)) {
5151
5259
  return createMissingSourceState(DOCS_STATUS_RELATIVE_PATH);
5152
5260
  }
5153
5261
  try {
5154
- parseProjectLayerDocument(DOCS_STATUS_RELATIVE_PATH, readFileSync18(docsStatusPath, "utf-8"));
5262
+ parseProjectLayerDocument(DOCS_STATUS_RELATIVE_PATH, readFileSync19(docsStatusPath, "utf-8"));
5155
5263
  return buildSourceState({
5156
5264
  path: DOCS_STATUS_RELATIVE_PATH,
5157
5265
  exists: true,
@@ -5182,7 +5290,7 @@ var buildDocumentReadError = (code, message) => `${code}: ${message}`;
5182
5290
  var buildProjectDocumentSnapshot = (params) => {
5183
5291
  let absolutePath;
5184
5292
  try {
5185
- absolutePath = resolveProjectLayerFilePath2(params.basePath, params.indexed.path);
5293
+ absolutePath = resolveProjectLayerFilePath(params.basePath, params.indexed.path);
5186
5294
  } catch (error) {
5187
5295
  return {
5188
5296
  path: params.indexed.path,
@@ -5200,7 +5308,7 @@ var buildProjectDocumentSnapshot = (params) => {
5200
5308
  readError: buildDocumentReadError("unsafe-path", getErrorMessage(error))
5201
5309
  };
5202
5310
  }
5203
- if (!existsSync12(absolutePath)) {
5311
+ if (!existsSync13(absolutePath)) {
5204
5312
  return {
5205
5313
  path: params.indexed.path,
5206
5314
  status: params.indexed.status,
@@ -5218,7 +5326,7 @@ var buildProjectDocumentSnapshot = (params) => {
5218
5326
  };
5219
5327
  }
5220
5328
  try {
5221
- const document = parseProjectLayerDocument(params.indexed.path, readFileSync18(absolutePath, "utf-8"));
5329
+ const document = parseProjectLayerDocument(params.indexed.path, readFileSync19(absolutePath, "utf-8"));
5222
5330
  return {
5223
5331
  path: params.indexed.path,
5224
5332
  status: params.indexed.status,
@@ -5309,11 +5417,11 @@ var buildProjectSnapshot = (basePath) => {
5309
5417
  };
5310
5418
 
5311
5419
  // src/features/studio/runtime-snapshot.ts
5312
- import { existsSync as existsSync13, readFileSync as readFileSync20 } from "fs";
5420
+ import { existsSync as existsSync14, readFileSync as readFileSync21 } from "fs";
5313
5421
  import { join as join22 } from "path";
5314
5422
 
5315
5423
  // src/features/subagents/manifest-io.ts
5316
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
5424
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync12 } from "fs";
5317
5425
  import { dirname as dirname13, join as join21 } from "path";
5318
5426
  var SUBAGENT_MANIFEST_FILENAME = "subagents-manifest.json";
5319
5427
  var parseSubagentManifest = (json) => SubagentManifestSchema.parse(JSON.parse(json));
@@ -5322,7 +5430,7 @@ var resolveSubagentManifestPath = (userBasePath) => join21(userBasePath, ".ai-op
5322
5430
  var readSubagentManifest = (manifestPath) => {
5323
5431
  let raw;
5324
5432
  try {
5325
- raw = readFileSync19(manifestPath, "utf-8");
5433
+ raw = readFileSync20(manifestPath, "utf-8");
5326
5434
  } catch {
5327
5435
  return null;
5328
5436
  }
@@ -5352,7 +5460,7 @@ var readRuntimeManifest = (params) => {
5352
5460
  value: null
5353
5461
  };
5354
5462
  }
5355
- if (!existsSync13(params.manifestPath)) {
5463
+ if (!existsSync14(params.manifestPath)) {
5356
5464
  return {
5357
5465
  source: createMissingSourceState(params.manifestPath),
5358
5466
  value: null
@@ -5390,11 +5498,11 @@ var readHooksSourceState = (codexHomePath, unavailableReason) => {
5390
5498
  });
5391
5499
  }
5392
5500
  const hooksPath = resolveCodexHooksPath(codexHomePath);
5393
- if (!existsSync13(hooksPath)) {
5501
+ if (!existsSync14(hooksPath)) {
5394
5502
  return createMissingSourceState(hooksPath);
5395
5503
  }
5396
5504
  try {
5397
- const parsed = JSON.parse(readFileSync20(hooksPath, "utf-8"));
5505
+ const parsed = JSON.parse(readFileSync21(hooksPath, "utf-8"));
5398
5506
  if (!isJsonRecord4(parsed)) {
5399
5507
  return buildSourceState({
5400
5508
  path: hooksPath,
@@ -5455,7 +5563,7 @@ var buildInstalledPathStates = (params) => {
5455
5563
  }
5456
5564
  return params.installedPaths.map((path) => ({
5457
5565
  path,
5458
- exists: existsSync13(join22(params.userBasePath ?? "", path))
5566
+ exists: existsSync14(join22(params.userBasePath ?? "", path))
5459
5567
  }));
5460
5568
  };
5461
5569
  var buildInstalledSkillMap = (installedSkills) => new Map(
@@ -5659,7 +5767,7 @@ var registerStudioCommands = (program) => {
5659
5767
 
5660
5768
  // src/features/subagents/commands.ts
5661
5769
  import * as p14 from "@clack/prompts";
5662
- import { existsSync as existsSync15, rmSync as rmSync8 } from "fs";
5770
+ import { existsSync as existsSync16, rmSync as rmSync8 } from "fs";
5663
5771
 
5664
5772
  // src/features/subagents/renderer.ts
5665
5773
  import { resolve as resolve12 } from "path";
@@ -5782,7 +5890,7 @@ var buildSubagentInstallPlan = (params) => {
5782
5890
  };
5783
5891
 
5784
5892
  // src/features/subagents/install-files.ts
5785
- import { existsSync as existsSync14, mkdirSync as mkdirSync11, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
5893
+ import { existsSync as existsSync15, mkdirSync as mkdirSync11, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
5786
5894
  import { dirname as dirname14, isAbsolute as isAbsolute3, relative as relative3, resolve as resolve13 } from "path";
5787
5895
  var resolveInsideBasePath = (basePath, relativePath) => {
5788
5896
  const absBasePath = resolve13(basePath);
@@ -5798,7 +5906,7 @@ var installSubagentPackages = (basePath, packages) => {
5798
5906
  for (const subagentPackage of packages) {
5799
5907
  for (const file of subagentPackage.files) {
5800
5908
  const absPath = resolveInsideBasePath(basePath, file.relativePath);
5801
- if (existsSync14(absPath)) {
5909
+ if (existsSync15(absPath)) {
5802
5910
  rmSync7(absPath, { recursive: true, force: true });
5803
5911
  }
5804
5912
  mkdirSync11(dirname14(absPath), { recursive: true });
@@ -5812,7 +5920,7 @@ var removeSubagentFiles = (basePath, relativePaths) => {
5812
5920
  const removed = [];
5813
5921
  for (const relativePath of relativePaths) {
5814
5922
  const absPath = resolveInsideBasePath(basePath, relativePath);
5815
- if (!existsSync14(absPath)) continue;
5923
+ if (!existsSync15(absPath)) continue;
5816
5924
  rmSync7(absPath, { recursive: true, force: true });
5817
5925
  removed.push(relativePath);
5818
5926
  }
@@ -5874,7 +5982,7 @@ var writeUserSubagentState = (params) => {
5874
5982
  };
5875
5983
  var readInstalledSubagents = (basePath) => readSubagentManifest(resolveSubagentManifestPath(basePath))?.subagents ?? [];
5876
5984
  var warnMissingSkills = (requiredSkills) => {
5877
- const missing = requiredSkills.filter((skill) => !existsSync15(skill.path));
5985
+ const missing = requiredSkills.filter((skill) => !existsSync16(skill.path));
5878
5986
  if (missing.length === 0) {
5879
5987
  return;
5880
5988
  }