@cleocode/adapters 2026.9.19 → 2026.9.20

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
@@ -43274,7 +43274,53 @@ var init_spawn = __esm({
43274
43274
  // packages/adapters/src/providers/claude-code/paths.ts
43275
43275
  import { homedir as homedir3 } from "node:os";
43276
43276
  import { join as join3 } from "node:path";
43277
- var ClaudeCodePathProvider;
43277
+ function claudeSettingsPath() {
43278
+ return new ClaudeCodePathProvider().getSettingsPath() ?? join3(homedir3(), ".claude", "settings.json");
43279
+ }
43280
+ function isPlainObject2(value) {
43281
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43282
+ }
43283
+ function isCleoHookEntry(entry, commandIncludes) {
43284
+ if (!isPlainObject2(entry) || !Array.isArray(entry.hooks)) return false;
43285
+ return entry.hooks.some(
43286
+ (hook) => isPlainObject2(hook) && typeof hook.command === "string" && hook.command.includes(CLEO_HOOK_MARKER) && (commandIncludes === void 0 || hook.command.includes(commandIncludes))
43287
+ );
43288
+ }
43289
+ function hasCleoHook(entries, commandIncludes) {
43290
+ return Array.isArray(entries) && entries.some((e) => isCleoHookEntry(e, commandIncludes));
43291
+ }
43292
+ function hookMap(settings) {
43293
+ const existing = settings.hooks;
43294
+ if (existing === void 0) {
43295
+ const created = {};
43296
+ settings.hooks = created;
43297
+ return created;
43298
+ }
43299
+ if (!isPlainObject2(existing)) {
43300
+ throw new Error('settings.json "hooks" is not an object; not modifying it');
43301
+ }
43302
+ return existing;
43303
+ }
43304
+ function appendHookEntry(hooks, event, entry) {
43305
+ const existing = hooks[event];
43306
+ if (existing !== void 0 && !Array.isArray(existing)) {
43307
+ throw new Error(`settings.json "hooks.${event}" is not an array; not modifying it`);
43308
+ }
43309
+ hooks[event] = [...existing ?? [], entry];
43310
+ }
43311
+ function removeCleoHookEntries(hooks) {
43312
+ let changed = false;
43313
+ for (const [event, entries] of Object.entries(hooks)) {
43314
+ if (!Array.isArray(entries)) continue;
43315
+ const kept = entries.filter((e) => !isCleoHookEntry(e));
43316
+ if (kept.length !== entries.length) {
43317
+ hooks[event] = kept;
43318
+ changed = true;
43319
+ }
43320
+ }
43321
+ return changed;
43322
+ }
43323
+ var ClaudeCodePathProvider, CLEO_HOOK_MARKER;
43278
43324
  var init_paths = __esm({
43279
43325
  "packages/adapters/src/providers/claude-code/paths.ts"() {
43280
43326
  "use strict";
@@ -43296,6 +43342,7 @@ var init_paths = __esm({
43296
43342
  return process.env["CLAUDE_MEM_DB"] ?? join3(homedir3(), ".claude-mem", "claude-mem.db");
43297
43343
  }
43298
43344
  };
43345
+ CLEO_HOOK_MARKER = "# cleo-hook";
43299
43346
  }
43300
43347
  });
43301
43348
 
@@ -43427,14 +43474,15 @@ var init_context_monitor = __esm({
43427
43474
  });
43428
43475
 
43429
43476
  // packages/adapters/src/providers/claude-code/hooks.ts
43430
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
43477
+ import { existsSync as existsSync4 } from "node:fs";
43431
43478
  import { readdir, readFile } from "node:fs/promises";
43432
- import { homedir as homedir5 } from "node:os";
43433
43479
  import { join as join5 } from "node:path";
43480
+ import { updateJsonConfigFile } from "@cleocode/caamp";
43434
43481
  var PROVIDER_ID, CLAUDE_CODE_EVENT_MAP, ClaudeCodeHookProvider;
43435
43482
  var init_hooks = __esm({
43436
43483
  "packages/adapters/src/providers/claude-code/hooks.ts"() {
43437
43484
  "use strict";
43485
+ init_paths();
43438
43486
  PROVIDER_ID = "claude-code";
43439
43487
  CLAUDE_CODE_EVENT_MAP = {
43440
43488
  // CAAMP: toNative('SessionStart', 'claude-code') = 'SessionStart'
@@ -43506,39 +43554,16 @@ var init_hooks = __esm({
43506
43554
  async registerNativeHooks(projectDir) {
43507
43555
  this.projectDir = projectDir;
43508
43556
  this.registered = true;
43509
- try {
43510
- const home = homedir5();
43511
- const settingsPath = join5(home, ".claude", "settings.json");
43512
- let settings = {};
43513
- if (existsSync4(settingsPath)) {
43514
- try {
43515
- settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
43516
- } catch {
43517
- }
43518
- }
43519
- const hooks = settings.hooks ?? {};
43520
- const alreadyRegistered = Object.values(hooks).some(
43521
- (entries) => Array.isArray(entries) && entries.some(
43522
- (e) => typeof e === "object" && e !== null && Array.isArray(e.hooks) && e.hooks.some(
43523
- (h) => typeof h.command === "string" && h.command.includes("# cleo-hook")
43524
- )
43525
- )
43526
- );
43527
- if (alreadyRegistered) {
43528
- return;
43557
+ await this.updateSettings((settings) => {
43558
+ const hooks = hookMap(settings);
43559
+ if (Object.values(hooks).some((entries) => hasCleoHook(entries))) {
43560
+ return false;
43529
43561
  }
43530
- if (!hooks.Stop) hooks.Stop = [];
43531
- hooks.Stop.push({
43562
+ appendHookEntry(hooks, "Stop", {
43532
43563
  matcher: "",
43533
- hooks: [
43534
- {
43535
- type: "command",
43536
- command: `cleo session end --quiet # cleo-hook`
43537
- }
43538
- ]
43564
+ hooks: [{ type: "command", command: `cleo session end --quiet # cleo-hook` }]
43539
43565
  });
43540
- if (!hooks.PostToolUse) hooks.PostToolUse = [];
43541
- hooks.PostToolUse.push({
43566
+ appendHookEntry(hooks, "PostToolUse", {
43542
43567
  matcher: "Write|Edit",
43543
43568
  hooks: [
43544
43569
  {
@@ -43553,48 +43578,54 @@ var init_hooks = __esm({
43553
43578
  }
43554
43579
  ]
43555
43580
  });
43556
- settings.hooks = hooks;
43557
- mkdirSync(join5(home, ".claude"), { recursive: true });
43558
- writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
43559
- } catch {
43560
- }
43581
+ return true;
43582
+ });
43561
43583
  }
43562
43584
  /**
43563
43585
  * Unregister native hooks.
43564
43586
  *
43565
- * Removes CLEO hook entries from `~/.claude/settings.json` by filtering out
43566
- * entries containing the `# cleo-hook` marker.
43587
+ * Removes CLEO hook entries from Claude Code's `settings.json` by filtering
43588
+ * out entries containing the `# cleo-hook` marker. Same locking, atomicity
43589
+ * and parse-error rules as {@link registerNativeHooks}.
43567
43590
  *
43568
43591
  * @task T164 @task T555
43569
43592
  */
43570
43593
  async unregisterNativeHooks() {
43571
43594
  this.registered = false;
43572
43595
  this.projectDir = null;
43596
+ if (!existsSync4(claudeSettingsPath())) return;
43597
+ await this.updateSettings((settings) => {
43598
+ if (settings.hooks === void 0) return false;
43599
+ return removeCleoHookEntries(hookMap(settings));
43600
+ });
43601
+ }
43602
+ /** The last settings.json failure, or `null` when the last update succeeded. */
43603
+ settingsError = null;
43604
+ /**
43605
+ * Why the last settings.json update did not happen, or `null`.
43606
+ *
43607
+ * @remarks
43608
+ * Hook registration stays non-fatal for adapter initialisation, so a
43609
+ * refused write (malformed settings.json, lock timeout) is surfaced here and
43610
+ * on stderr instead of being swallowed (T12385).
43611
+ *
43612
+ * @returns The failure message, or `null`
43613
+ */
43614
+ getSettingsError() {
43615
+ return this.settingsError;
43616
+ }
43617
+ /** Apply `mutate` to settings.json via CAAMP's locked, atomic JSON writer. */
43618
+ async updateSettings(mutate) {
43619
+ const settingsPath = claudeSettingsPath();
43573
43620
  try {
43574
- const home = homedir5();
43575
- const settingsPath = join5(home, ".claude", "settings.json");
43576
- if (!existsSync4(settingsPath)) return;
43577
- const settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
43578
- const hooks = settings.hooks;
43579
- if (!hooks) return;
43580
- let changed = false;
43581
- for (const [event, entries] of Object.entries(hooks)) {
43582
- if (!Array.isArray(entries)) continue;
43583
- const filtered = entries.filter(
43584
- (e) => !(typeof e === "object" && e !== null && Array.isArray(e.hooks) && e.hooks.some(
43585
- (h) => typeof h.command === "string" && h.command.includes("# cleo-hook")
43586
- ))
43587
- );
43588
- if (filtered.length !== entries.length) {
43589
- hooks[event] = filtered;
43590
- changed = true;
43591
- }
43592
- }
43593
- if (changed) {
43594
- settings.hooks = hooks;
43595
- writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
43596
- }
43597
- } catch {
43621
+ await updateJsonConfigFile(settingsPath, mutate);
43622
+ this.settingsError = null;
43623
+ } catch (err) {
43624
+ this.settingsError = err instanceof Error ? err.message : String(err);
43625
+ process.stderr.write(
43626
+ `[cleo:claude-code] hooks not written to ${settingsPath}: ${this.settingsError}
43627
+ `
43628
+ );
43598
43629
  }
43599
43630
  }
43600
43631
  /**
@@ -43773,7 +43804,7 @@ var init_hooks = __esm({
43773
43804
  });
43774
43805
 
43775
43806
  // packages/adapters/src/providers/shared/hook-template-installer.ts
43776
- import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, statSync } from "node:fs";
43807
+ import { copyFileSync, existsSync as existsSync5, mkdirSync, statSync } from "node:fs";
43777
43808
  import { dirname as dirname2, join as join6 } from "node:path";
43778
43809
  import { fileURLToPath } from "node:url";
43779
43810
  function resolveProviderCandidates() {
@@ -43807,7 +43838,7 @@ function copyTemplate(src, dest, force) {
43807
43838
  return { wrote: false };
43808
43839
  }
43809
43840
  }
43810
- mkdirSync2(dirname2(dest), { recursive: true });
43841
+ mkdirSync(dirname2(dest), { recursive: true });
43811
43842
  copyFileSync(src, dest);
43812
43843
  return { wrote: true };
43813
43844
  }
@@ -43819,7 +43850,7 @@ function installProviderHookTemplates(options) {
43819
43850
  installedFiles: [],
43820
43851
  skipped: []
43821
43852
  };
43822
- mkdirSync2(targetDir, { recursive: true });
43853
+ mkdirSync(targetDir, { recursive: true });
43823
43854
  const coreDest = join6(targetDir, SHARED_CORE_FILE);
43824
43855
  const coreOutcome = copyTemplate(sharedCoreSource(), coreDest, force);
43825
43856
  if (coreOutcome.wrote) result.installedFiles.push(coreDest);
@@ -43852,20 +43883,13 @@ var init_hook_template_installer = __esm({
43852
43883
  });
43853
43884
 
43854
43885
  // packages/adapters/src/providers/claude-code/install.ts
43855
- import {
43856
- copyFileSync as copyFileSync2,
43857
- existsSync as existsSync6,
43858
- mkdirSync as mkdirSync3,
43859
- readdirSync as readdirSync2,
43860
- readFileSync as readFileSync5,
43861
- writeFileSync as writeFileSync3
43862
- } from "node:fs";
43863
- import { homedir as homedir6 } from "node:os";
43886
+ import { copyFileSync as copyFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "node:fs";
43887
+ import { homedir as homedir5 } from "node:os";
43864
43888
  import { dirname as dirname3, join as join7 } from "node:path";
43865
43889
  import { fileURLToPath as fileURLToPath2 } from "node:url";
43866
- import { ensureProviderInstructionFile } from "@cleocode/caamp";
43890
+ import { ensureProviderInstructionFile, updateJsonConfigFile as updateJsonConfigFile2 } from "@cleocode/caamp";
43867
43891
  function getClaudeConfigDir() {
43868
- return process.env["CLAUDE_HOME"] ?? join7(homedir6(), ".claude");
43892
+ return process.env["CLAUDE_HOME"] ?? join7(homedir5(), ".claude");
43869
43893
  }
43870
43894
  function getAdapterCommandsDir() {
43871
43895
  const thisDir = dirname3(fileURLToPath2(import.meta.url));
@@ -43876,6 +43900,7 @@ var init_install = __esm({
43876
43900
  "packages/adapters/src/providers/claude-code/install.ts"() {
43877
43901
  "use strict";
43878
43902
  init_hook_template_installer();
43903
+ init_paths();
43879
43904
  ClaudeCodeInstallProvider = class {
43880
43905
  /**
43881
43906
  * Install CLEO into a Claude Code project.
@@ -43897,16 +43922,28 @@ var init_install = __esm({
43897
43922
  if (commandsInstalled.length > 0) {
43898
43923
  details.commands = commandsInstalled;
43899
43924
  }
43900
- const pluginResult = this.registerPlugin();
43901
- if (pluginResult) {
43902
- details.plugin = pluginResult;
43925
+ const settingsErrors = [];
43926
+ try {
43927
+ const pluginResult = await this.registerPlugin();
43928
+ if (pluginResult) {
43929
+ details.plugin = pluginResult;
43930
+ }
43931
+ } catch (err) {
43932
+ settingsErrors.push(err instanceof Error ? err.message : String(err));
43903
43933
  }
43904
- const hookResult = this.installHookTemplates();
43905
- if (hookResult) {
43906
- details.hookTemplates = hookResult;
43934
+ try {
43935
+ const hookResult = await this.installHookTemplates();
43936
+ if (hookResult) {
43937
+ details.hookTemplates = hookResult;
43938
+ }
43939
+ } catch (err) {
43940
+ settingsErrors.push(err instanceof Error ? err.message : String(err));
43941
+ }
43942
+ if (settingsErrors.length > 0) {
43943
+ details.settingsErrors = settingsErrors;
43907
43944
  }
43908
43945
  return {
43909
- success: true,
43946
+ success: settingsErrors.length === 0,
43910
43947
  installedAt,
43911
43948
  instructionFileUpdated,
43912
43949
  details
@@ -43925,10 +43962,10 @@ var init_install = __esm({
43925
43962
  * Checks for plugin enabled in ~/.claude/settings.json.
43926
43963
  */
43927
43964
  async isInstalled() {
43928
- const settingsPath = join7(getClaudeConfigDir(), "settings.json");
43965
+ const settingsPath = claudeSettingsPath();
43929
43966
  if (existsSync6(settingsPath)) {
43930
43967
  try {
43931
- const settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
43968
+ const settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
43932
43969
  const plugins = settings.enabledPlugins;
43933
43970
  if (plugins && plugins["cleo@cleocode"] === true) {
43934
43971
  return true;
@@ -43964,7 +44001,7 @@ var init_install = __esm({
43964
44001
  return [];
43965
44002
  }
43966
44003
  const targetDir = join7(projectDir, ".claude", "commands");
43967
- mkdirSync3(targetDir, { recursive: true });
44004
+ mkdirSync2(targetDir, { recursive: true });
43968
44005
  const installed = [];
43969
44006
  const files = readdirSync2(adapterCommandsDir).filter((f) => f.endsWith(".md"));
43970
44007
  for (const file2 of files) {
@@ -43980,29 +44017,24 @@ var init_install = __esm({
43980
44017
  *
43981
44018
  * @returns Description of what was registered, or null if no change needed
43982
44019
  */
43983
- registerPlugin() {
43984
- const claudeDir = getClaudeConfigDir();
43985
- const settingsPath = join7(claudeDir, "settings.json");
43986
- let settings = {};
43987
- if (existsSync6(settingsPath)) {
43988
- try {
43989
- settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
43990
- } catch {
43991
- }
43992
- }
43993
- const enabledPlugins = settings.enabledPlugins ?? {};
44020
+ async registerPlugin() {
43994
44021
  const pluginKey = "cleo@cleocode";
43995
- if (enabledPlugins[pluginKey] === true) {
43996
- return null;
43997
- }
43998
- if (enabledPlugins["claude-mem@thedotmack"] === true) {
43999
- enabledPlugins["claude-mem@thedotmack"] = false;
44000
- }
44001
- enabledPlugins[pluginKey] = true;
44002
- settings.enabledPlugins = enabledPlugins;
44003
- mkdirSync3(claudeDir, { recursive: true });
44004
- writeFileSync3(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
44005
- return `Enabled ${pluginKey} in ~/.claude/settings.json`;
44022
+ const wrote = await updateJsonConfigFile2(claudeSettingsPath(), (settings) => {
44023
+ const enabledPlugins = settings.enabledPlugins ?? {};
44024
+ if (!isPlainObject2(enabledPlugins)) {
44025
+ throw new Error('settings.json "enabledPlugins" is not an object; not modifying it');
44026
+ }
44027
+ if (enabledPlugins[pluginKey] === true) {
44028
+ return false;
44029
+ }
44030
+ if (enabledPlugins["claude-mem@thedotmack"] === true) {
44031
+ enabledPlugins["claude-mem@thedotmack"] = false;
44032
+ }
44033
+ enabledPlugins[pluginKey] = true;
44034
+ settings.enabledPlugins = enabledPlugins;
44035
+ return true;
44036
+ });
44037
+ return wrote ? `Enabled ${pluginKey} in ~/.claude/settings.json` : null;
44006
44038
  }
44007
44039
  /**
44008
44040
  * Install the CLEO PreCompact hook templates for Claude Code (T1013).
@@ -44024,7 +44056,7 @@ var init_install = __esm({
44024
44056
  *
44025
44057
  * @task T1013
44026
44058
  */
44027
- installHookTemplates() {
44059
+ async installHookTemplates() {
44028
44060
  const claudeDir = getClaudeConfigDir();
44029
44061
  const hooksDir = join7(claudeDir, "hooks");
44030
44062
  let templates;
@@ -44036,7 +44068,7 @@ var init_install = __esm({
44036
44068
  } catch {
44037
44069
  return null;
44038
44070
  }
44039
- const settingsEntryAdded = this.registerPreCompactHook(
44071
+ const settingsEntryAdded = await this.registerPreCompactHook(
44040
44072
  join7(hooksDir, "precompact-safestop.sh")
44041
44073
  );
44042
44074
  if (templates.installedFiles.length === 0 && !settingsEntryAdded) {
@@ -44058,41 +44090,24 @@ var init_install = __esm({
44058
44090
  *
44059
44091
  * @task T1013
44060
44092
  */
44061
- registerPreCompactHook(shimPath) {
44062
- const claudeDir = getClaudeConfigDir();
44063
- const settingsPath = join7(claudeDir, "settings.json");
44064
- let settings = {};
44065
- if (existsSync6(settingsPath)) {
44066
- try {
44067
- settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
44068
- } catch {
44093
+ async registerPreCompactHook(shimPath) {
44094
+ return updateJsonConfigFile2(claudeSettingsPath(), (settings) => {
44095
+ const hooks = hookMap(settings);
44096
+ if (hasCleoHook(hooks.PreCompact, "precompact-safestop.sh")) {
44097
+ return false;
44069
44098
  }
44070
- }
44071
- const hooks = settings.hooks ?? {};
44072
- const preCompactEntries = hooks.PreCompact ?? [];
44073
- const alreadyWired = preCompactEntries.some(
44074
- (entry) => typeof entry === "object" && entry !== null && Array.isArray(entry.hooks) && entry.hooks.some(
44075
- (h) => typeof h.command === "string" && h.command.includes("# cleo-hook") && h.command.includes("precompact-safestop.sh")
44076
- )
44077
- );
44078
- if (alreadyWired) {
44079
- return false;
44080
- }
44081
- preCompactEntries.push({
44082
- matcher: "",
44083
- hooks: [
44084
- {
44085
- type: "command",
44086
- command: `"${shimPath}" # cleo-hook`,
44087
- timeout: 30
44088
- }
44089
- ]
44099
+ appendHookEntry(hooks, "PreCompact", {
44100
+ matcher: "",
44101
+ hooks: [
44102
+ {
44103
+ type: "command",
44104
+ command: `"${shimPath}" # cleo-hook`,
44105
+ timeout: 30
44106
+ }
44107
+ ]
44108
+ });
44109
+ return true;
44090
44110
  });
44091
- hooks.PreCompact = preCompactEntries;
44092
- settings.hooks = hooks;
44093
- mkdirSync3(claudeDir, { recursive: true });
44094
- writeFileSync3(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
44095
- return true;
44096
44111
  }
44097
44112
  };
44098
44113
  }
@@ -44100,7 +44115,7 @@ var init_install = __esm({
44100
44115
 
44101
44116
  // packages/adapters/src/providers/shared/agent-spawn-wrapper.ts
44102
44117
  import { spawnSync } from "node:child_process";
44103
- import { readFileSync as readFileSync6 } from "node:fs";
44118
+ import { readFileSync as readFileSync5 } from "node:fs";
44104
44119
  function hasSystemdRun() {
44105
44120
  if (_systemdRunAvailable !== void 0) return _systemdRunAvailable;
44106
44121
  if (process.platform !== "linux") {
@@ -44114,7 +44129,7 @@ function hasSystemdRun() {
44114
44129
  function readMemTotalBytes() {
44115
44130
  if (process.platform !== "linux") return 32 * 1024 * 1024 * 1024;
44116
44131
  try {
44117
- const raw = readFileSync6("/proc/meminfo", "utf8");
44132
+ const raw = readFileSync5("/proc/meminfo", "utf8");
44118
44133
  const m = raw.match(/^MemTotal:\s+(\d+)\s+kB/m);
44119
44134
  if (m?.[1]) return parseInt(m[1], 10) * 1024;
44120
44135
  } catch {
@@ -44576,7 +44591,7 @@ var init_transport = __esm({
44576
44591
  // packages/adapters/src/providers/claude-code/adapter.ts
44577
44592
  import { exec as exec2 } from "node:child_process";
44578
44593
  import { existsSync as existsSync7 } from "node:fs";
44579
- import { homedir as homedir7 } from "node:os";
44594
+ import { homedir as homedir6 } from "node:os";
44580
44595
  import { join as join9 } from "node:path";
44581
44596
  import { promisify as promisify3 } from "node:util";
44582
44597
  var execAsync2, ClaudeCodeAdapter;
@@ -44734,7 +44749,7 @@ var init_adapter = __esm({
44734
44749
  } catch {
44735
44750
  details.cliAvailable = false;
44736
44751
  }
44737
- const claudeConfigDir = join9(homedir7(), ".claude");
44752
+ const claudeConfigDir = join9(homedir6(), ".claude");
44738
44753
  const configExists = existsSync7(claudeConfigDir);
44739
44754
  details.configDirExists = configExists;
44740
44755
  const entrypointSet = process.env.CLAUDE_CODE_ENTRYPOINT !== void 0;
@@ -44764,17 +44779,17 @@ var init_adapter = __esm({
44764
44779
  });
44765
44780
 
44766
44781
  // packages/adapters/src/providers/claude-code/statusline.ts
44767
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
44768
- import { homedir as homedir8 } from "node:os";
44782
+ import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
44783
+ import { homedir as homedir7 } from "node:os";
44769
44784
  import { join as join10 } from "node:path";
44770
44785
  function getClaudeSettingsPath() {
44771
- return process.env["CLAUDE_SETTINGS"] ?? join10(process.env["CLAUDE_HOME"] ?? join10(homedir8(), ".claude"), "settings.json");
44786
+ return process.env["CLAUDE_SETTINGS"] ?? join10(process.env["CLAUDE_HOME"] ?? join10(homedir7(), ".claude"), "settings.json");
44772
44787
  }
44773
44788
  function checkStatuslineIntegration() {
44774
44789
  const settingsPath = getClaudeSettingsPath();
44775
44790
  if (!existsSync8(settingsPath)) return "no_settings";
44776
44791
  try {
44777
- const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
44792
+ const settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
44778
44793
  const statusLine = settings.statusLine;
44779
44794
  if (!statusLine?.type) return "not_configured";
44780
44795
  if (statusLine.type !== "command") return "custom_no_cleo";
@@ -44782,10 +44797,10 @@ function checkStatuslineIntegration() {
44782
44797
  if (cmd.includes("context-monitor.sh") || cmd.includes("cleo-statusline") || cmd.includes(".context-state.json") || cmd.includes("context-states")) {
44783
44798
  return "configured";
44784
44799
  }
44785
- const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir8()) : cmd;
44800
+ const scriptPath = cmd.startsWith("~") ? cmd.replace("~", homedir7()) : cmd;
44786
44801
  if (existsSync8(scriptPath)) {
44787
44802
  try {
44788
- const content = readFileSync7(scriptPath, "utf-8");
44803
+ const content = readFileSync6(scriptPath, "utf-8");
44789
44804
  if (content.includes("context-state.json")) return "configured";
44790
44805
  } catch {
44791
44806
  }
@@ -45018,15 +45033,30 @@ var init_hooks2 = __esm({
45018
45033
  });
45019
45034
 
45020
45035
  // packages/adapters/src/providers/cursor/install.ts
45021
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
45036
+ import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
45022
45037
  import { join as join16 } from "node:path";
45023
- import { ensureProviderInstructionFile as ensureProviderInstructionFile3 } from "@cleocode/caamp";
45024
- var CursorInstallProvider;
45038
+ import {
45039
+ ensureProviderInstructionFile as ensureProviderInstructionFile3,
45040
+ ensureProviderRuleFile,
45041
+ updateJsonConfigFile as updateJsonConfigFile3
45042
+ } from "@cleocode/caamp";
45043
+ function isRecord(value) {
45044
+ return typeof value === "object" && value !== null && !Array.isArray(value);
45045
+ }
45046
+ var CLEO_MDC_FRONTMATTER, CursorInstallProvider;
45025
45047
  var init_install2 = __esm({
45026
45048
  "packages/adapters/src/providers/cursor/install.ts"() {
45027
45049
  "use strict";
45028
45050
  init_hook_template_installer();
45029
45051
  init_paths2();
45052
+ CLEO_MDC_FRONTMATTER = [
45053
+ "---",
45054
+ "description: CLEO task management protocol references",
45055
+ 'globs: "**/*"',
45056
+ "alwaysApply: true",
45057
+ "---",
45058
+ ""
45059
+ ].join("\n");
45030
45060
  CursorInstallProvider = class {
45031
45061
  /**
45032
45062
  * Install CLEO into a Cursor project.
@@ -45040,17 +45070,23 @@ var init_install2 = __esm({
45040
45070
  let instructionFileUpdated = false;
45041
45071
  const details = {};
45042
45072
  const instructionResult = await ensureProviderInstructionFile3("cursor", projectDir, {});
45043
- const cursorFilesUpdated = this.updateInstructionFiles(projectDir);
45073
+ const cursorFilesUpdated = await this.updateInstructionFiles(projectDir);
45044
45074
  instructionFileUpdated = instructionResult.action !== "intact" || cursorFilesUpdated;
45045
45075
  if (instructionFileUpdated) {
45046
45076
  details.instructionFiles = this.getUpdatedFileList(projectDir);
45047
45077
  }
45048
- const hookResult = this.installHookTemplates(projectDir);
45049
- if (hookResult) {
45050
- details.hookTemplates = hookResult;
45078
+ let hooksError = null;
45079
+ try {
45080
+ const hookResult = await this.installHookTemplates(projectDir);
45081
+ if (hookResult) {
45082
+ details.hookTemplates = hookResult;
45083
+ }
45084
+ } catch (err) {
45085
+ hooksError = err instanceof Error ? err.message : String(err);
45086
+ details.hooksError = hooksError;
45051
45087
  }
45052
45088
  return {
45053
- success: true,
45089
+ success: hooksError === null,
45054
45090
  installedAt,
45055
45091
  instructionFileUpdated,
45056
45092
  details
@@ -45076,7 +45112,7 @@ var init_install2 = __esm({
45076
45112
  const rulesPath = join16(process.cwd(), ".cursorrules");
45077
45113
  if (existsSync11(rulesPath)) {
45078
45114
  try {
45079
- const content = readFileSync8(rulesPath, "utf-8");
45115
+ const content = readFileSync7(rulesPath, "utf-8");
45080
45116
  const injectionRef = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
45081
45117
  if (content.includes(injectionRef) || content.includes("@.cleo/memory-bridge.md")) {
45082
45118
  return true;
@@ -45096,88 +45132,36 @@ var init_install2 = __esm({
45096
45132
  */
45097
45133
  async ensureInstructionReferences(projectDir) {
45098
45134
  await ensureProviderInstructionFile3("cursor", projectDir, {});
45099
- this.updateInstructionFiles(projectDir);
45135
+ await this.updateInstructionFiles(projectDir);
45100
45136
  }
45101
45137
  /**
45102
- * Update instruction files with CLEO @-references.
45103
- *
45104
- * Handles both legacy (.cursorrules) and modern (.cursor/rules/cleo.mdc) formats.
45138
+ * Update Cursor's auxiliary rule files through the CAAMP writer.
45105
45139
  *
45106
- * @returns true if any file was created or modified
45107
- */
45108
- updateInstructionFiles(projectDir) {
45109
- let updated = false;
45110
- if (this.updateLegacyRules(projectDir)) {
45111
- updated = true;
45112
- }
45113
- if (this.updateModernRules(projectDir)) {
45114
- updated = true;
45115
- }
45116
- return updated;
45117
- }
45118
- /**
45119
- * Update legacy .cursorrules file with @-references.
45140
+ * @remarks
45141
+ * ADR-064 / T12385: both files are written by CAAMP's
45142
+ * `ensureProviderRuleFile` — locked, atomic, with references taken from the
45143
+ * provider registry — instead of raw `writeFileSync` with a local copy of
45144
+ * the references.
45120
45145
  *
45121
- * References are sourced from the CAAMP provider registry (T1919) rather than
45122
- * a local constant, keeping this adapter in sync with the single source of truth.
45123
- * Only modifies the file if it already exists (does not create it).
45146
+ * - Legacy `.cursorrules` is only updated when it already exists; CLEO's
45147
+ * references live in a CAAMP block and user text is preserved.
45148
+ * - Modern `.cursor/rules/cleo.mdc` is CLEO-owned: MDC frontmatter followed
45149
+ * by the CAAMP block.
45124
45150
  *
45125
- * @returns true if the file was modified
45126
- */
45127
- updateLegacyRules(projectDir) {
45128
- const rulesPath = join16(projectDir, ".cursorrules");
45129
- if (!existsSync11(rulesPath)) {
45130
- return false;
45131
- }
45132
- let content = readFileSync8(rulesPath, "utf-8");
45133
- const cursorRefs = [
45134
- `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`,
45135
- "@.cleo/memory-bridge.md"
45136
- ];
45137
- const missingRefs = cursorRefs.filter((ref) => !content.includes(ref));
45138
- if (missingRefs.length === 0) {
45139
- return false;
45140
- }
45141
- const separator = content.endsWith("\n") ? "" : "\n";
45142
- content = content + separator + missingRefs.join("\n") + "\n";
45143
- writeFileSync4(rulesPath, content, "utf-8");
45144
- return true;
45145
- }
45146
- /**
45147
- * Create or update .cursor/rules/cleo.mdc with CLEO references.
45148
- *
45149
- * MDC (Markdown Component) format is Cursor's modern rule file format.
45150
- * Each .mdc file in .cursor/rules/ is loaded as a rule set.
45151
- * References are sourced from the CAAMP provider registry (T1919).
45152
- *
45153
- * @returns true if the file was created or modified
45151
+ * @returns true if any file was created or modified
45154
45152
  */
45155
- updateModernRules(projectDir) {
45156
- const rulesDir = join16(projectDir, ".cursor", "rules");
45157
- const mdcPath = join16(rulesDir, "cleo.mdc");
45158
- const cursorRefs = [
45159
- `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`,
45160
- "@.cleo/memory-bridge.md"
45153
+ async updateInstructionFiles(projectDir) {
45154
+ const results = [
45155
+ await ensureProviderRuleFile("cursor", projectDir, {
45156
+ relativePath: ".cursorrules",
45157
+ onlyIfExists: true
45158
+ }),
45159
+ await ensureProviderRuleFile("cursor", projectDir, {
45160
+ relativePath: join16(".cursor", "rules", "cleo.mdc"),
45161
+ preamble: CLEO_MDC_FRONTMATTER
45162
+ })
45161
45163
  ];
45162
- const expectedContent = [
45163
- "---",
45164
- "description: CLEO task management protocol references",
45165
- 'globs: "**/*"',
45166
- "alwaysApply: true",
45167
- "---",
45168
- "",
45169
- ...cursorRefs,
45170
- ""
45171
- ].join("\n");
45172
- if (existsSync11(mdcPath)) {
45173
- const existing = readFileSync8(mdcPath, "utf-8");
45174
- if (existing === expectedContent) {
45175
- return false;
45176
- }
45177
- }
45178
- mkdirSync4(rulesDir, { recursive: true });
45179
- writeFileSync4(mdcPath, expectedContent, "utf-8");
45180
- return true;
45164
+ return results.some((r) => r !== null && r.action !== "intact");
45181
45165
  }
45182
45166
  /**
45183
45167
  * Get list of instruction files that were updated.
@@ -45208,7 +45192,7 @@ var init_install2 = __esm({
45208
45192
  *
45209
45193
  * @task T1013
45210
45194
  */
45211
- installHookTemplates(projectDir) {
45195
+ async installHookTemplates(projectDir) {
45212
45196
  const hooksDir = join16(projectDir, ".cursor", "hooks");
45213
45197
  let templates;
45214
45198
  try {
@@ -45219,7 +45203,7 @@ var init_install2 = __esm({
45219
45203
  } catch {
45220
45204
  return null;
45221
45205
  }
45222
- const hooksJsonEntryAdded = this.registerPreCompactHook(
45206
+ const hooksJsonEntryAdded = await this.registerPreCompactHook(
45223
45207
  projectDir,
45224
45208
  join16(hooksDir, "precompact.sh")
45225
45209
  );
@@ -45241,33 +45225,30 @@ var init_install2 = __esm({
45241
45225
  *
45242
45226
  * @task T1013
45243
45227
  */
45244
- registerPreCompactHook(projectDir, shimPath) {
45228
+ async registerPreCompactHook(projectDir, shimPath) {
45245
45229
  const hooksJsonPath = join16(projectDir, ".cursor", "hooks.json");
45246
- let config2 = {};
45247
- if (existsSync11(hooksJsonPath)) {
45248
- try {
45249
- config2 = JSON.parse(readFileSync8(hooksJsonPath, "utf-8"));
45250
- } catch {
45230
+ return updateJsonConfigFile3(hooksJsonPath, (config2) => {
45231
+ const hooks = config2.hooks ?? {};
45232
+ if (!isRecord(hooks)) {
45233
+ throw new Error('.cursor/hooks.json "hooks" is not an object; not modifying it');
45251
45234
  }
45252
- }
45253
- const hooks = config2.hooks ?? {};
45254
- const entries = hooks.preCompact ?? [];
45255
- const alreadyWired = entries.some(
45256
- (entry) => typeof entry === "object" && entry !== null && typeof entry.command === "string" && entry.command.includes("# cleo-hook") && entry.command.includes("precompact.sh")
45257
- );
45258
- if (alreadyWired) {
45259
- return false;
45260
- }
45261
- entries.push({
45262
- type: "command",
45263
- command: `"${shimPath}" # cleo-hook`,
45264
- timeout: 30
45235
+ const entries = hooks.preCompact ?? [];
45236
+ if (!Array.isArray(entries)) {
45237
+ throw new Error('.cursor/hooks.json "hooks.preCompact" is not an array; not modifying it');
45238
+ }
45239
+ const alreadyWired = entries.some(
45240
+ (entry) => isRecord(entry) && typeof entry.command === "string" && entry.command.includes("# cleo-hook") && entry.command.includes("precompact.sh")
45241
+ );
45242
+ if (alreadyWired) {
45243
+ return false;
45244
+ }
45245
+ hooks.preCompact = [
45246
+ ...entries,
45247
+ { type: "command", command: `"${shimPath}" # cleo-hook`, timeout: 30 }
45248
+ ];
45249
+ config2.hooks = hooks;
45250
+ return true;
45265
45251
  });
45266
- hooks.preCompact = entries;
45267
- config2.hooks = hooks;
45268
- mkdirSync4(join16(projectDir, ".cursor"), { recursive: true });
45269
- writeFileSync4(hooksJsonPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
45270
- return true;
45271
45252
  }
45272
45253
  };
45273
45254
  }
@@ -45580,7 +45561,7 @@ var init_hooks3 = __esm({
45580
45561
  });
45581
45562
 
45582
45563
  // packages/adapters/src/providers/opencode/install.ts
45583
- import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
45564
+ import { existsSync as existsSync17, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
45584
45565
  import { join as join23 } from "node:path";
45585
45566
  import { ensureProviderInstructionFile as ensureProviderInstructionFile6 } from "@cleocode/caamp";
45586
45567
  var OpenCodeInstallProvider;
@@ -45744,14 +45725,14 @@ var init_install3 = __esm({
45744
45725
  ].join("\n");
45745
45726
  if (existsSync17(pluginPath)) {
45746
45727
  try {
45747
- if (readFileSync11(pluginPath, "utf-8") === generated) {
45728
+ if (readFileSync10(pluginPath, "utf-8") === generated) {
45748
45729
  return false;
45749
45730
  }
45750
45731
  } catch {
45751
45732
  }
45752
45733
  }
45753
- mkdirSync5(pluginsDir, { recursive: true });
45754
- writeFileSync5(pluginPath, generated, "utf-8");
45734
+ mkdirSync3(pluginsDir, { recursive: true });
45735
+ writeFileSync2(pluginPath, generated, "utf-8");
45755
45736
  return true;
45756
45737
  }
45757
45738
  };
@@ -46526,21 +46507,21 @@ var init_spawn4 = __esm({
46526
46507
  // packages/adapters/src/providers/pi/adapter.ts
46527
46508
  import { exec as exec12 } from "node:child_process";
46528
46509
  import { existsSync as existsSync19 } from "node:fs";
46529
- import { homedir as homedir14 } from "node:os";
46510
+ import { homedir as homedir13 } from "node:os";
46530
46511
  import { join as join27 } from "node:path";
46531
46512
  import { promisify as promisify13 } from "node:util";
46532
46513
  function getPiAgentDir() {
46533
46514
  const env = process.env["PI_CODING_AGENT_DIR"];
46534
46515
  if (env !== void 0 && env.length > 0) {
46535
- if (env === "~") return homedir14();
46536
- if (env.startsWith("~/")) return join27(homedir14(), env.slice(2));
46516
+ if (env === "~") return homedir13();
46517
+ if (env.startsWith("~/")) return join27(homedir13(), env.slice(2));
46537
46518
  return env;
46538
46519
  }
46539
46520
  const piHome = process.env["PI_HOME"];
46540
46521
  if (piHome !== void 0 && piHome.length > 0) {
46541
46522
  return join27(piHome, "agent");
46542
46523
  }
46543
- return join27(homedir14(), ".pi", "agent");
46524
+ return join27(homedir13(), ".pi", "agent");
46544
46525
  }
46545
46526
  var execAsync12, PiAdapter;
46546
46527
  var init_adapter4 = __esm({
@@ -46876,12 +46857,12 @@ function createAdapter2() {
46876
46857
  // packages/adapters/src/providers/codex/adapter.ts
46877
46858
  import { exec as exec3 } from "node:child_process";
46878
46859
  import { existsSync as existsSync10 } from "node:fs";
46879
- import { homedir as homedir10 } from "node:os";
46860
+ import { homedir as homedir9 } from "node:os";
46880
46861
  import { join as join15 } from "node:path";
46881
46862
  import { promisify as promisify4 } from "node:util";
46882
46863
 
46883
46864
  // packages/adapters/src/providers/codex/hooks.ts
46884
- import { homedir as homedir9 } from "node:os";
46865
+ import { homedir as homedir8 } from "node:os";
46885
46866
  import { join as join13 } from "node:path";
46886
46867
 
46887
46868
  // packages/adapters/src/providers/shared/transcript-reader.ts
@@ -47001,7 +46982,7 @@ var CodexHookProvider = class {
47001
46982
  * @task T162 @epic T134
47002
46983
  */
47003
46984
  async getTranscript(_sessionId, _projectDir) {
47004
- return readLatestTranscript(join13(homedir9(), ".codex"));
46985
+ return readLatestTranscript(join13(homedir8(), ".codex"));
47005
46986
  }
47006
46987
  };
47007
46988
 
@@ -47165,7 +47146,7 @@ var CodexAdapter = class {
47165
47146
  } catch {
47166
47147
  details.cliAvailable = false;
47167
47148
  }
47168
- const codexConfigDir = join15(homedir10(), ".codex");
47149
+ const codexConfigDir = join15(homedir9(), ".codex");
47169
47150
  const configExists = existsSync10(codexConfigDir);
47170
47151
  details.configDirExists = configExists;
47171
47152
  const healthy = cliAvailable;
@@ -47209,12 +47190,12 @@ init_cursor();
47209
47190
  // packages/adapters/src/providers/gemini-cli/adapter.ts
47210
47191
  import { exec as exec5 } from "node:child_process";
47211
47192
  import { existsSync as existsSync14 } from "node:fs";
47212
- import { homedir as homedir12 } from "node:os";
47193
+ import { homedir as homedir11 } from "node:os";
47213
47194
  import { join as join20 } from "node:path";
47214
47195
  import { promisify as promisify6 } from "node:util";
47215
47196
 
47216
47197
  // packages/adapters/src/providers/gemini-cli/hooks.ts
47217
- import { homedir as homedir11 } from "node:os";
47198
+ import { homedir as homedir10 } from "node:os";
47218
47199
  import { join as join18 } from "node:path";
47219
47200
  var GEMINI_CLI_EVENT_MAP = {
47220
47201
  SessionStart: "SessionStart",
@@ -47293,13 +47274,13 @@ var GeminiCliHookProvider = class {
47293
47274
  * @task T161 @epic T134
47294
47275
  */
47295
47276
  async getTranscript(_sessionId, _projectDir) {
47296
- return readLatestTranscript(join18(homedir11(), ".gemini"));
47277
+ return readLatestTranscript(join18(homedir10(), ".gemini"));
47297
47278
  }
47298
47279
  };
47299
47280
 
47300
47281
  // packages/adapters/src/providers/gemini-cli/install.ts
47301
47282
  init_paths2();
47302
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "node:fs";
47283
+ import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
47303
47284
  import { join as join19 } from "node:path";
47304
47285
  import { ensureProviderInstructionFile as ensureProviderInstructionFile4 } from "@cleocode/caamp";
47305
47286
  var GeminiCliInstallProvider = class {
@@ -47348,7 +47329,7 @@ var GeminiCliInstallProvider = class {
47348
47329
  const geminiMdPath = join19(process.cwd(), "GEMINI.md");
47349
47330
  if (existsSync13(geminiMdPath)) {
47350
47331
  try {
47351
- const content = readFileSync9(geminiMdPath, "utf-8");
47332
+ const content = readFileSync8(geminiMdPath, "utf-8");
47352
47333
  if (content.includes(instructionRef)) {
47353
47334
  return true;
47354
47335
  }
@@ -47469,7 +47450,7 @@ var GeminiCliAdapter = class {
47469
47450
  } catch {
47470
47451
  details.cliAvailable = false;
47471
47452
  }
47472
- const geminiConfigDir = join20(homedir12(), ".gemini");
47453
+ const geminiConfigDir = join20(homedir11(), ".gemini");
47473
47454
  const configExists = existsSync14(geminiConfigDir);
47474
47455
  details.configDirExists = configExists;
47475
47456
  const healthy = cliAvailable;
@@ -47510,7 +47491,7 @@ function createAdapter5() {
47510
47491
  // packages/adapters/src/providers/kimi/adapter.ts
47511
47492
  import { exec as exec7 } from "node:child_process";
47512
47493
  import { existsSync as existsSync16 } from "node:fs";
47513
- import { homedir as homedir13 } from "node:os";
47494
+ import { homedir as homedir12 } from "node:os";
47514
47495
  import { join as join22 } from "node:path";
47515
47496
  import { promisify as promisify8 } from "node:util";
47516
47497
 
@@ -47571,7 +47552,7 @@ var KimiHookProvider = class {
47571
47552
 
47572
47553
  // packages/adapters/src/providers/kimi/install.ts
47573
47554
  init_paths2();
47574
- import { existsSync as existsSync15, readFileSync as readFileSync10 } from "node:fs";
47555
+ import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
47575
47556
  import { join as join21 } from "node:path";
47576
47557
  import { ensureProviderInstructionFile as ensureProviderInstructionFile5 } from "@cleocode/caamp";
47577
47558
  var KimiInstallProvider = class {
@@ -47620,7 +47601,7 @@ var KimiInstallProvider = class {
47620
47601
  const agentsMdPath = join21(process.cwd(), "AGENTS.md");
47621
47602
  if (existsSync15(agentsMdPath)) {
47622
47603
  try {
47623
- const content = readFileSync10(agentsMdPath, "utf-8");
47604
+ const content = readFileSync9(agentsMdPath, "utf-8");
47624
47605
  if (content.includes(instructionRef)) {
47625
47606
  return true;
47626
47607
  }
@@ -47728,7 +47709,7 @@ var KimiAdapter = class {
47728
47709
  } catch {
47729
47710
  details.cliAvailable = false;
47730
47711
  }
47731
- const kimiConfigDir = join22(homedir13(), ".kimi");
47712
+ const kimiConfigDir = join22(homedir12(), ".kimi");
47732
47713
  const configExists = existsSync16(kimiConfigDir);
47733
47714
  details.configDirExists = configExists;
47734
47715
  const healthy = cliAvailable;
@@ -47771,7 +47752,7 @@ init_opencode();
47771
47752
  init_hook_template_installer();
47772
47753
 
47773
47754
  // packages/adapters/src/registry.ts
47774
- import { readFileSync as readFileSync12 } from "node:fs";
47755
+ import { readFileSync as readFileSync11 } from "node:fs";
47775
47756
  import { dirname as dirname4, join as join28, resolve as resolve2 } from "node:path";
47776
47757
  import { fileURLToPath as fileURLToPath3 } from "node:url";
47777
47758
  var PROVIDER_IDS = ["claude-code", "opencode", "cursor", "pi"];
@@ -47781,7 +47762,7 @@ function getProviderManifests() {
47781
47762
  for (const providerId of PROVIDER_IDS) {
47782
47763
  try {
47783
47764
  const manifestPath = join28(baseDir, providerId, "manifest.json");
47784
- const raw = readFileSync12(manifestPath, "utf-8");
47765
+ const raw = readFileSync11(manifestPath, "utf-8");
47785
47766
  manifests.push(JSON.parse(raw));
47786
47767
  } catch {
47787
47768
  }