@frostbridge/imdl 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +161 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1351,6 +1351,7 @@ async function initCommand(options) {
1351
1351
  installShellWrapper(agent.name, agent.dir);
1352
1352
  }
1353
1353
  }
1354
+ installDaemon();
1354
1355
  let apiConnected = false;
1355
1356
  try {
1356
1357
  const healthRes = await fetch(`${config.apiUrl}/health`, { signal: AbortSignal.timeout(3e3) });
@@ -1471,6 +1472,60 @@ function installShellWrapper(agentName, agentDir) {
1471
1472
  console.log(pc2.dim(` \u2022 Shell wrapper: couldn't configure for ${agentName} (configure manually)`));
1472
1473
  }
1473
1474
  }
1475
+ function installDaemon() {
1476
+ if (process.platform !== "darwin") {
1477
+ console.log(pc2.dim(" \u2022 Background daemon: only auto-installed on macOS (run `imdl daemon` manually)"));
1478
+ return;
1479
+ }
1480
+ const plistName = "com.frostbridge.imdl-daemon.plist";
1481
+ const plistDir = join6(homedir4(), "Library", "LaunchAgents");
1482
+ const plistPath = join6(plistDir, plistName);
1483
+ if (existsSync7(plistPath)) {
1484
+ console.log(pc2.dim(" \u2022 Background daemon already installed"));
1485
+ return;
1486
+ }
1487
+ const { execSync: execSync2 } = __require("child_process");
1488
+ let imdlBin = "";
1489
+ try {
1490
+ imdlBin = execSync2("which imdl", { encoding: "utf-8" }).trim();
1491
+ } catch {
1492
+ imdlBin = "/usr/local/bin/imdl";
1493
+ }
1494
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
1495
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1496
+ <plist version="1.0">
1497
+ <dict>
1498
+ <key>Label</key>
1499
+ <string>com.frostbridge.imdl-daemon</string>
1500
+ <key>ProgramArguments</key>
1501
+ <array>
1502
+ <string>${imdlBin}</string>
1503
+ <string>daemon</string>
1504
+ </array>
1505
+ <key>RunAtLoad</key>
1506
+ <true/>
1507
+ <key>KeepAlive</key>
1508
+ <true/>
1509
+ <key>StandardOutPath</key>
1510
+ <string>${join6(homedir4(), ".imdl", "daemon.log")}</string>
1511
+ <key>StandardErrorPath</key>
1512
+ <string>${join6(homedir4(), ".imdl", "daemon.log")}</string>
1513
+ <key>EnvironmentVariables</key>
1514
+ <dict>
1515
+ <key>PATH</key>
1516
+ <string>/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin</string>
1517
+ </dict>
1518
+ </dict>
1519
+ </plist>`;
1520
+ try {
1521
+ if (!existsSync7(plistDir)) mkdirSync2(plistDir, { recursive: true });
1522
+ writeFileSync4(plistPath, plist);
1523
+ execSync2(`launchctl load ${plistPath}`, { stdio: "ignore" });
1524
+ console.log(pc2.green(" \u2713 Background daemon installed (auto-starts on login)"));
1525
+ } catch {
1526
+ console.log(pc2.yellow(" \u26A0 Could not install daemon service (run `imdl daemon` manually)"));
1527
+ }
1528
+ }
1474
1529
  function installMCPProxy(mcpConfigPath, agentName) {
1475
1530
  let existing = {};
1476
1531
  const dir = join6(mcpConfigPath, "..");
@@ -3577,6 +3632,8 @@ async function collectCommand() {
3577
3632
 
3578
3633
  // src/commands/daemon.ts
3579
3634
  import pc7 from "picocolors";
3635
+ import { existsSync as existsSync19, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
3636
+ import { join as join18 } from "path";
3580
3637
  var INTERVAL_MS = 3e4;
3581
3638
  async function daemonCommand() {
3582
3639
  console.log(pc7.cyan("imdl daemon started \u2014 collecting every 30s"));
@@ -3584,9 +3641,12 @@ async function daemonCommand() {
3584
3641
  const tick = async () => {
3585
3642
  try {
3586
3643
  const count = await collectPrompts();
3587
- if (count > 0) {
3588
- console.log(pc7.green(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Collected ${count} new event${count !== 1 ? "s" : ""}`));
3644
+ const shellCount = await ingestShellEvents();
3645
+ const total = count + shellCount;
3646
+ if (total > 0) {
3647
+ console.log(pc7.green(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Collected ${total} event${total !== 1 ? "s" : ""} (prompts: ${count}, shell: ${shellCount})`));
3589
3648
  }
3649
+ await tryFlush();
3590
3650
  } catch (err) {
3591
3651
  console.error(pc7.red(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] Error: ${err.message}`));
3592
3652
  }
@@ -3594,6 +3654,50 @@ async function daemonCommand() {
3594
3654
  await tick();
3595
3655
  setInterval(tick, INTERVAL_MS);
3596
3656
  }
3657
+ async function ingestShellEvents() {
3658
+ const shellLog = join18(getBufferDir(), "shell-events.ndjson");
3659
+ if (!existsSync19(shellLog)) return 0;
3660
+ const content = readFileSync13(shellLog, "utf-8").trim();
3661
+ if (!content) return 0;
3662
+ const config = loadConfig();
3663
+ const lines = content.split("\n");
3664
+ const events = lines.map((line) => {
3665
+ try {
3666
+ return JSON.parse(line);
3667
+ } catch {
3668
+ return null;
3669
+ }
3670
+ }).filter(Boolean);
3671
+ if (events.length === 0) return 0;
3672
+ const headers = { "Content-Type": "application/json" };
3673
+ if (config.authToken) headers["X-IMDL-Key"] = config.authToken;
3674
+ const sessionId = `shell_${config.developerId}_${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
3675
+ const apiEvents = events.map((e) => ({
3676
+ type: "pre_tool_use",
3677
+ toolName: "shell_command",
3678
+ toolInput: { command: e.command, agent: e.agent, decision: e.decision, reason: e.reason },
3679
+ timestamp: e.timestamp,
3680
+ violation: e.decision === "block" ? { action: "block", reason: e.reason, policyName: e.policyName } : void 0
3681
+ }));
3682
+ let sent = 0;
3683
+ for (let i = 0; i < apiEvents.length; i += 50) {
3684
+ const batch = apiEvents.slice(i, i + 50);
3685
+ try {
3686
+ const res = await fetch(`${config.apiUrl}/api/sessions/${sessionId}/events`, {
3687
+ method: "POST",
3688
+ headers,
3689
+ body: JSON.stringify({ events: batch, developerId: config.developerId }),
3690
+ signal: AbortSignal.timeout(1e4)
3691
+ });
3692
+ if (res.ok) sent += batch.length;
3693
+ } catch {
3694
+ }
3695
+ }
3696
+ if (sent === apiEvents.length) {
3697
+ writeFileSync7(shellLog, "", { mode: 384 });
3698
+ }
3699
+ return sent;
3700
+ }
3597
3701
 
3598
3702
  // src/commands/request.ts
3599
3703
  import pc8 from "picocolors";
@@ -3658,8 +3762,8 @@ async function requestCommand(options) {
3658
3762
  // src/commands/lock.ts
3659
3763
  import pc9 from "picocolors";
3660
3764
  import { createHash as createHash2 } from "crypto";
3661
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync19 } from "fs";
3662
- import { join as join18, resolve as resolve3 } from "path";
3765
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync8, existsSync as existsSync20 } from "fs";
3766
+ import { join as join19, resolve as resolve3 } from "path";
3663
3767
  var LOCKFILE_NAME = "mcp-lock.json";
3664
3768
  function computeIntegrity(server, identity) {
3665
3769
  const payload = JSON.stringify({
@@ -3674,7 +3778,7 @@ function computeIntegrity(server, identity) {
3674
3778
  }
3675
3779
  function getLockfilePath(customPath) {
3676
3780
  if (customPath) return resolve3(customPath);
3677
- return join18(process.cwd(), LOCKFILE_NAME);
3781
+ return join19(process.cwd(), LOCKFILE_NAME);
3678
3782
  }
3679
3783
  async function lockCommand(options) {
3680
3784
  const detection = await detectMCPConfigs(options.path);
@@ -3721,7 +3825,7 @@ async function lockCommand(options) {
3721
3825
  servers: entries
3722
3826
  };
3723
3827
  const lockPath = getLockfilePath(options.output);
3724
- writeFileSync7(lockPath, JSON.stringify(lockfile, null, 2), { mode: 420 });
3828
+ writeFileSync8(lockPath, JSON.stringify(lockfile, null, 2), { mode: 420 });
3725
3829
  if (options.json) {
3726
3830
  console.log(JSON.stringify(lockfile, null, 2));
3727
3831
  } else {
@@ -3744,7 +3848,7 @@ async function lockCommand(options) {
3744
3848
  }
3745
3849
  async function verifyCommand(options) {
3746
3850
  const lockPath = getLockfilePath(options.path);
3747
- if (!existsSync19(lockPath)) {
3851
+ if (!existsSync20(lockPath)) {
3748
3852
  if (options.json) {
3749
3853
  console.log(JSON.stringify({ error: "No lockfile found. Run `imdl lock` first.", path: lockPath }));
3750
3854
  } else {
@@ -3756,7 +3860,7 @@ async function verifyCommand(options) {
3756
3860
  }
3757
3861
  let lockfile;
3758
3862
  try {
3759
- lockfile = JSON.parse(readFileSync13(lockPath, "utf-8"));
3863
+ lockfile = JSON.parse(readFileSync14(lockPath, "utf-8"));
3760
3864
  } catch {
3761
3865
  console.log(pc9.red("Failed to parse lockfile."));
3762
3866
  process.exit(1);
@@ -4165,8 +4269,8 @@ async function checkCompliance(developerId) {
4165
4269
  }
4166
4270
 
4167
4271
  // src/permissions/fixer.ts
4168
- import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
4169
- import { join as join19 } from "path";
4272
+ import { existsSync as existsSync21, readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "fs";
4273
+ import { join as join20 } from "path";
4170
4274
  import { homedir as homedir14 } from "os";
4171
4275
  function buildFixesFromChanges(changes) {
4172
4276
  const fixes = [];
@@ -4180,10 +4284,10 @@ function buildFixesFromChanges(changes) {
4180
4284
  function buildFixForAgent(change, home) {
4181
4285
  const { agentType, category, action, targetGrant } = change;
4182
4286
  if (agentType === "claude-code") {
4183
- const configPath = join19(home, ".claude", "settings.json");
4184
- if (!existsSync20(configPath)) return null;
4287
+ const configPath = join20(home, ".claude", "settings.json");
4288
+ if (!existsSync21(configPath)) return null;
4185
4289
  try {
4186
- const settings = JSON.parse(readFileSync14(configPath, "utf-8"));
4290
+ const settings = JSON.parse(readFileSync15(configPath, "utf-8"));
4187
4291
  const tools = settings.allowedTools || [];
4188
4292
  if (category === "shell") {
4189
4293
  if (!tools.includes("Bash") && !tools.some((t) => t.startsWith("Bash("))) return null;
@@ -4211,10 +4315,10 @@ function buildFixForAgent(change, home) {
4211
4315
  }
4212
4316
  }
4213
4317
  if (agentType === "cursor") {
4214
- const configPath = join19(home, ".cursor", "settings.json");
4215
- if (!existsSync20(configPath)) return null;
4318
+ const configPath = join20(home, ".cursor", "settings.json");
4319
+ if (!existsSync21(configPath)) return null;
4216
4320
  try {
4217
- const settings = JSON.parse(readFileSync14(configPath, "utf-8"));
4321
+ const settings = JSON.parse(readFileSync15(configPath, "utf-8"));
4218
4322
  if ((category === "agentic_mode" || category === "shell") && settings["cursor.composer.yoloMode"] === true) {
4219
4323
  return { agentType, category: "agentic_mode", currentGrant: "unrestricted", newGrant: "confirmation", configPath, description: "Disable YOLO mode" };
4220
4324
  }
@@ -4223,10 +4327,10 @@ function buildFixForAgent(change, home) {
4223
4327
  }
4224
4328
  }
4225
4329
  if (agentType === "codex") {
4226
- const configPath = join19(home, ".codex", "config.json");
4227
- if (!existsSync20(configPath)) return null;
4330
+ const configPath = join20(home, ".codex", "config.json");
4331
+ if (!existsSync21(configPath)) return null;
4228
4332
  try {
4229
- const config = JSON.parse(readFileSync14(configPath, "utf-8"));
4333
+ const config = JSON.parse(readFileSync15(configPath, "utf-8"));
4230
4334
  if ((category === "agentic_mode" || category === "shell") && config.sandbox_mode === "full_auto") {
4231
4335
  return { agentType, category: "agentic_mode", currentGrant: "unrestricted", newGrant: "confirmation", configPath, description: "Switch to supervised mode" };
4232
4336
  }
@@ -4235,10 +4339,10 @@ function buildFixForAgent(change, home) {
4235
4339
  }
4236
4340
  }
4237
4341
  if (agentType === "copilot") {
4238
- const configPath = join19(home, "Library", "Application Support", "Code", "User", "settings.json");
4239
- if (!existsSync20(configPath)) return null;
4342
+ const configPath = join20(home, "Library", "Application Support", "Code", "User", "settings.json");
4343
+ if (!existsSync21(configPath)) return null;
4240
4344
  try {
4241
- const settings = JSON.parse(readFileSync14(configPath, "utf-8"));
4345
+ const settings = JSON.parse(readFileSync15(configPath, "utf-8"));
4242
4346
  if ((category === "agentic_mode" || category === "shell") && (settings["github.copilot.chat.agent.autoApprove"] || settings["chat.agent.autoApprove"])) {
4243
4347
  return { agentType, category: "agentic_mode", currentGrant: "unrestricted", newGrant: "confirmation", configPath, description: "Disable autoApprove" };
4244
4348
  }
@@ -4248,10 +4352,10 @@ function buildFixForAgent(change, home) {
4248
4352
  }
4249
4353
  if (agentType === "windsurf") {
4250
4354
  if (category === "mcp_tools") {
4251
- const configPath = join19(home, ".windsurf", "mcp.json");
4252
- if (!existsSync20(configPath)) return null;
4355
+ const configPath = join20(home, ".windsurf", "mcp.json");
4356
+ if (!existsSync21(configPath)) return null;
4253
4357
  try {
4254
- const config = JSON.parse(readFileSync14(configPath, "utf-8"));
4358
+ const config = JSON.parse(readFileSync15(configPath, "utf-8"));
4255
4359
  const servers = Object.keys(config.mcpServers || {});
4256
4360
  if (servers.length === 0) return null;
4257
4361
  return { agentType, category, currentGrant: "unrestricted", newGrant: "denied", configPath, description: `Remove MCP servers (${servers.join(", ")})` };
@@ -4264,7 +4368,7 @@ function buildFixForAgent(change, home) {
4264
4368
  }
4265
4369
  function applyFix(fix) {
4266
4370
  try {
4267
- const content = readFileSync14(fix.configPath, "utf-8");
4371
+ const content = readFileSync15(fix.configPath, "utf-8");
4268
4372
  const config = JSON.parse(content);
4269
4373
  let modified = false;
4270
4374
  if (fix.agentType === "claude-code") {
@@ -4318,7 +4422,7 @@ function applyFix(fix) {
4318
4422
  }
4319
4423
  }
4320
4424
  if (modified) {
4321
- writeFileSync8(fix.configPath, JSON.stringify(config, null, 2) + "\n");
4425
+ writeFileSync9(fix.configPath, JSON.stringify(config, null, 2) + "\n");
4322
4426
  return { fix, applied: true };
4323
4427
  }
4324
4428
  return { fix, applied: false, error: "No changes needed" };
@@ -4555,13 +4659,13 @@ function grantLevel(grant) {
4555
4659
 
4556
4660
  // src/commands/gateway.ts
4557
4661
  import pc12 from "picocolors";
4558
- import { existsSync as existsSync21, readFileSync as readFileSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync3 } from "fs";
4559
- import { join as join20 } from "path";
4662
+ import { existsSync as existsSync22, readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync3 } from "fs";
4663
+ import { join as join21 } from "path";
4560
4664
  import { homedir as homedir15 } from "os";
4561
4665
  import { execSync, spawn } from "child_process";
4562
- var IMDL_DIR3 = join20(homedir15(), ".imdl");
4563
- var GATEWAY_CONFIG = join20(IMDL_DIR3, "gateway.toml");
4564
- var GATEWAY_PID_FILE = join20(IMDL_DIR3, "gateway.pid");
4666
+ var IMDL_DIR3 = join21(homedir15(), ".imdl");
4667
+ var GATEWAY_CONFIG = join21(IMDL_DIR3, "gateway.toml");
4668
+ var GATEWAY_PID_FILE = join21(IMDL_DIR3, "gateway.pid");
4565
4669
  var DEFAULT_PORT = 9443;
4566
4670
  async function gatewayCommand(opts) {
4567
4671
  const status = await getGatewayStatus();
@@ -4636,8 +4740,8 @@ async function gatewayStartCommand(opts) {
4636
4740
  });
4637
4741
  child.unref();
4638
4742
  if (child.pid) {
4639
- if (!existsSync21(IMDL_DIR3)) mkdirSync3(IMDL_DIR3, { recursive: true });
4640
- writeFileSync9(GATEWAY_PID_FILE, String(child.pid));
4743
+ if (!existsSync22(IMDL_DIR3)) mkdirSync3(IMDL_DIR3, { recursive: true });
4744
+ writeFileSync10(GATEWAY_PID_FILE, String(child.pid));
4641
4745
  console.log(pc12.green(`Gateway started (PID ${child.pid}, port ${port})`));
4642
4746
  console.log(pc12.dim(` Config: ${GATEWAY_CONFIG}`));
4643
4747
  console.log(pc12.dim(` Set ANTHROPIC_BASE_URL=http://127.0.0.1:${port} to intercept traffic`));
@@ -4696,12 +4800,12 @@ async function gatewayDisableCommand(opts) {
4696
4800
  console.log(pc12.dim("Restart gateway for changes to take effect."));
4697
4801
  }
4698
4802
  async function gatewayAlertsCommand(opts) {
4699
- const logPath = join20(IMDL_DIR3, "gateway-alerts.jsonl");
4700
- if (!existsSync21(logPath)) {
4803
+ const logPath = join21(IMDL_DIR3, "gateway-alerts.jsonl");
4804
+ if (!existsSync22(logPath)) {
4701
4805
  console.log(pc12.dim("No alerts logged yet."));
4702
4806
  return;
4703
4807
  }
4704
- const lines = readFileSync15(logPath, "utf-8").split("\n").filter(Boolean);
4808
+ const lines = readFileSync16(logPath, "utf-8").split("\n").filter(Boolean);
4705
4809
  const limit = opts.limit ? parseInt(opts.limit, 10) : 20;
4706
4810
  const recent = lines.slice(-limit);
4707
4811
  if (opts.json) {
@@ -4803,9 +4907,9 @@ async function getGatewayStatus() {
4803
4907
  return { running: true, pid, port, stats, config };
4804
4908
  }
4805
4909
  function getRunningPid() {
4806
- if (!existsSync21(GATEWAY_PID_FILE)) return null;
4910
+ if (!existsSync22(GATEWAY_PID_FILE)) return null;
4807
4911
  try {
4808
- const pid = parseInt(readFileSync15(GATEWAY_PID_FILE, "utf-8").trim(), 10);
4912
+ const pid = parseInt(readFileSync16(GATEWAY_PID_FILE, "utf-8").trim(), 10);
4809
4913
  return isNaN(pid) ? null : pid;
4810
4914
  } catch {
4811
4915
  return null;
@@ -4820,9 +4924,9 @@ function isProcessAlive(pid) {
4820
4924
  }
4821
4925
  }
4822
4926
  function getConfiguredPort() {
4823
- if (!existsSync21(GATEWAY_CONFIG)) return DEFAULT_PORT;
4927
+ if (!existsSync22(GATEWAY_CONFIG)) return DEFAULT_PORT;
4824
4928
  try {
4825
- const content = readFileSync15(GATEWAY_CONFIG, "utf-8");
4929
+ const content = readFileSync16(GATEWAY_CONFIG, "utf-8");
4826
4930
  const match = content.match(/listen_port\s*=\s*(\d+)/);
4827
4931
  return match ? parseInt(match[1], 10) : DEFAULT_PORT;
4828
4932
  } catch {
@@ -4831,12 +4935,12 @@ function getConfiguredPort() {
4831
4935
  }
4832
4936
  function findGatewayBinary() {
4833
4937
  const candidates = [
4834
- join20(process.cwd(), "target", "release", "imdl-gateway"),
4835
- join20(process.cwd(), "..", "ai-gateway", "target", "release", "imdl-gateway"),
4836
- join20(homedir15(), ".imdl", "bin", "imdl-gateway")
4938
+ join21(process.cwd(), "target", "release", "imdl-gateway"),
4939
+ join21(process.cwd(), "..", "ai-gateway", "target", "release", "imdl-gateway"),
4940
+ join21(homedir15(), ".imdl", "bin", "imdl-gateway")
4837
4941
  ];
4838
4942
  for (const path of candidates) {
4839
- if (existsSync21(path)) return path;
4943
+ if (existsSync22(path)) return path;
4840
4944
  }
4841
4945
  try {
4842
4946
  const result = execSync("which imdl-gateway", { encoding: "utf-8" }).trim();
@@ -4846,8 +4950,8 @@ function findGatewayBinary() {
4846
4950
  return null;
4847
4951
  }
4848
4952
  function ensureConfig(port) {
4849
- if (existsSync21(GATEWAY_CONFIG)) return;
4850
- if (!existsSync21(IMDL_DIR3)) mkdirSync3(IMDL_DIR3, { recursive: true });
4953
+ if (existsSync22(GATEWAY_CONFIG)) return;
4954
+ if (!existsSync22(IMDL_DIR3)) mkdirSync3(IMDL_DIR3, { recursive: true });
4851
4955
  const defaultToml = `# IMDL AI Gateway configuration
4852
4956
  listen_host = "127.0.0.1"
4853
4957
  listen_port = ${port}
@@ -4874,7 +4978,7 @@ openai_url = "https://api.openai.com"
4874
4978
  [audit]
4875
4979
  enabled = true
4876
4980
  `;
4877
- writeFileSync9(GATEWAY_CONFIG, defaultToml, { mode: 384 });
4981
+ writeFileSync10(GATEWAY_CONFIG, defaultToml, { mode: 384 });
4878
4982
  }
4879
4983
  function normalizeModule(input) {
4880
4984
  const map = {
@@ -4891,13 +4995,13 @@ function normalizeModule(input) {
4891
4995
  return map[input.toLowerCase()] ?? null;
4892
4996
  }
4893
4997
  function loadGatewayToml() {
4894
- if (!existsSync21(GATEWAY_CONFIG)) {
4998
+ if (!existsSync22(GATEWAY_CONFIG)) {
4895
4999
  ensureConfig(DEFAULT_PORT);
4896
5000
  }
4897
- return readFileSync15(GATEWAY_CONFIG, "utf-8");
5001
+ return readFileSync16(GATEWAY_CONFIG, "utf-8");
4898
5002
  }
4899
5003
  function saveGatewayToml(content) {
4900
- writeFileSync9(GATEWAY_CONFIG, content, { mode: 384 });
5004
+ writeFileSync10(GATEWAY_CONFIG, content, { mode: 384 });
4901
5005
  }
4902
5006
  function setModuleEnabled(content, module, enabled) {
4903
5007
  const sectionRegex = new RegExp(`(\\[${module}\\][^\\[]*?)enabled\\s*=\\s*(true|false)`, "s");
@@ -5227,18 +5331,18 @@ function ruleTypeToCategory(type) {
5227
5331
  }
5228
5332
 
5229
5333
  // src/transport/sync.ts
5230
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync22 } from "fs";
5231
- import { join as join21 } from "path";
5334
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync23 } from "fs";
5335
+ import { join as join22 } from "path";
5232
5336
  var SYNC_INTERVAL = 6e4;
5233
5337
  var SYNC_TIMEOUT = 3e3;
5234
5338
  function getSyncStateFile() {
5235
- return join21(getImdlDir(), "last_sync.json");
5339
+ return join22(getImdlDir(), "last_sync.json");
5236
5340
  }
5237
5341
  function getLastSyncTime() {
5238
5342
  try {
5239
5343
  const file = getSyncStateFile();
5240
- if (existsSync22(file)) {
5241
- const data = JSON.parse(readFileSync16(file, "utf-8"));
5344
+ if (existsSync23(file)) {
5345
+ const data = JSON.parse(readFileSync17(file, "utf-8"));
5242
5346
  return data.lastSync || 0;
5243
5347
  }
5244
5348
  } catch {
@@ -5247,7 +5351,7 @@ function getLastSyncTime() {
5247
5351
  }
5248
5352
  function setLastSyncTime() {
5249
5353
  try {
5250
- writeFileSync10(getSyncStateFile(), JSON.stringify({ lastSync: Date.now() }), { mode: 384 });
5354
+ writeFileSync11(getSyncStateFile(), JSON.stringify({ lastSync: Date.now() }), { mode: 384 });
5251
5355
  } catch {
5252
5356
  }
5253
5357
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "restricted"
5
5
  },
6
- "version": "0.1.3",
6
+ "version": "0.1.4",
7
7
  "description": "IMDL — Intelligent Mediation & Detection Layer. AI agent security CLI.",
8
8
  "files": [
9
9
  "dist"