@madh-io/alfred-ai 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bundle/index.js +87 -54
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -4554,6 +4554,9 @@ var init_dist7 = __esm({
4554
4554
  });
4555
4555
 
4556
4556
  // ../core/dist/alfred.js
4557
+ import fs4 from "node:fs";
4558
+ import path4 from "node:path";
4559
+ import yaml2 from "js-yaml";
4557
4560
  var Alfred;
4558
4561
  var init_alfred = __esm({
4559
4562
  "../core/dist/alfred.js"() {
@@ -4588,8 +4591,10 @@ var init_alfred = __esm({
4588
4591
  const reminderRepo = new ReminderRepository(db);
4589
4592
  this.logger.info("Storage initialized");
4590
4593
  const ruleEngine = new RuleEngine();
4594
+ const rules = this.loadSecurityRules();
4595
+ ruleEngine.loadRules(rules);
4591
4596
  const securityManager = new SecurityManager(ruleEngine, auditRepo, this.logger.child({ component: "security" }));
4592
- this.logger.info("Security engine initialized");
4597
+ this.logger.info({ ruleCount: rules.length }, "Security engine initialized");
4593
4598
  const llmProvider = createLLMProvider(this.config.llm);
4594
4599
  await llmProvider.initialize();
4595
4600
  this.logger.info({ provider: this.config.llm.provider, model: this.config.llm.model }, "LLM provider initialized");
@@ -4708,6 +4713,34 @@ var init_alfred = __esm({
4708
4713
  this.logger.warn({ platform }, "Adapter disconnected");
4709
4714
  });
4710
4715
  }
4716
+ loadSecurityRules() {
4717
+ const rulesPath = path4.resolve(this.config.security.rulesPath);
4718
+ const rules = [];
4719
+ if (!fs4.existsSync(rulesPath)) {
4720
+ this.logger.warn({ rulesPath }, "Security rules directory not found, using default deny");
4721
+ return rules;
4722
+ }
4723
+ const stat = fs4.statSync(rulesPath);
4724
+ if (!stat.isDirectory()) {
4725
+ this.logger.warn({ rulesPath }, "Security rules path is not a directory");
4726
+ return rules;
4727
+ }
4728
+ const files = fs4.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
4729
+ for (const file of files) {
4730
+ try {
4731
+ const filePath = path4.join(rulesPath, file);
4732
+ const content = fs4.readFileSync(filePath, "utf-8");
4733
+ const parsed = yaml2.load(content);
4734
+ if (parsed?.rules && Array.isArray(parsed.rules)) {
4735
+ rules.push(...parsed.rules);
4736
+ this.logger.info({ file, count: parsed.rules.length }, "Loaded security rules");
4737
+ }
4738
+ } catch (err) {
4739
+ this.logger.error({ err, file }, "Failed to load security rules file");
4740
+ }
4741
+ }
4742
+ return rules;
4743
+ }
4711
4744
  };
4712
4745
  }
4713
4746
  });
@@ -4790,9 +4823,9 @@ __export(setup_exports, {
4790
4823
  });
4791
4824
  import { createInterface } from "node:readline/promises";
4792
4825
  import { stdin as input, stdout as output } from "node:process";
4793
- import fs4 from "node:fs";
4794
- import path4 from "node:path";
4795
- import yaml2 from "js-yaml";
4826
+ import fs5 from "node:fs";
4827
+ import path5 from "node:path";
4828
+ import yaml3 from "js-yaml";
4796
4829
  function green(s) {
4797
4830
  return `${GREEN}${s}${RESET}`;
4798
4831
  }
@@ -4822,20 +4855,20 @@ function loadExistingConfig(projectRoot) {
4822
4855
  let shellEnabled = false;
4823
4856
  let writeInGroups = false;
4824
4857
  let rateLimit = 30;
4825
- const configPath = path4.join(projectRoot, "config", "default.yml");
4826
- if (fs4.existsSync(configPath)) {
4858
+ const configPath = path5.join(projectRoot, "config", "default.yml");
4859
+ if (fs5.existsSync(configPath)) {
4827
4860
  try {
4828
- const parsed = yaml2.load(fs4.readFileSync(configPath, "utf-8"));
4861
+ const parsed = yaml3.load(fs5.readFileSync(configPath, "utf-8"));
4829
4862
  if (parsed && typeof parsed === "object") {
4830
4863
  Object.assign(config, parsed);
4831
4864
  }
4832
4865
  } catch {
4833
4866
  }
4834
4867
  }
4835
- const envPath = path4.join(projectRoot, ".env");
4836
- if (fs4.existsSync(envPath)) {
4868
+ const envPath = path5.join(projectRoot, ".env");
4869
+ if (fs5.existsSync(envPath)) {
4837
4870
  try {
4838
- const lines = fs4.readFileSync(envPath, "utf-8").split("\n");
4871
+ const lines = fs5.readFileSync(envPath, "utf-8").split("\n");
4839
4872
  for (const line of lines) {
4840
4873
  const trimmed = line.trim();
4841
4874
  if (!trimmed || trimmed.startsWith("#"))
@@ -4848,10 +4881,10 @@ function loadExistingConfig(projectRoot) {
4848
4881
  } catch {
4849
4882
  }
4850
4883
  }
4851
- const rulesPath = path4.join(projectRoot, "config", "rules", "default-rules.yml");
4852
- if (fs4.existsSync(rulesPath)) {
4884
+ const rulesPath = path5.join(projectRoot, "config", "rules", "default-rules.yml");
4885
+ if (fs5.existsSync(rulesPath)) {
4853
4886
  try {
4854
- const rulesContent = yaml2.load(fs4.readFileSync(rulesPath, "utf-8"));
4887
+ const rulesContent = yaml3.load(fs5.readFileSync(rulesPath, "utf-8"));
4855
4888
  if (rulesContent?.rules) {
4856
4889
  shellEnabled = rulesContent.rules.some((r) => r.id === "allow-owner-admin" && r.effect === "allow");
4857
4890
  const writeDmRule = rulesContent.rules.find((r) => r.id === "allow-write-for-dm" || r.id === "allow-write-all");
@@ -5209,12 +5242,12 @@ ${bold("Writing configuration files...")}`);
5209
5242
  envLines.push("# ALFRED_OWNER_USER_ID=");
5210
5243
  }
5211
5244
  envLines.push("");
5212
- const envPath = path4.join(projectRoot, ".env");
5213
- fs4.writeFileSync(envPath, envLines.join("\n"), "utf-8");
5245
+ const envPath = path5.join(projectRoot, ".env");
5246
+ fs5.writeFileSync(envPath, envLines.join("\n"), "utf-8");
5214
5247
  console.log(` ${green("+")} ${dim(".env")} written`);
5215
- const configDir = path4.join(projectRoot, "config");
5216
- if (!fs4.existsSync(configDir)) {
5217
- fs4.mkdirSync(configDir, { recursive: true });
5248
+ const configDir = path5.join(projectRoot, "config");
5249
+ if (!fs5.existsSync(configDir)) {
5250
+ fs5.mkdirSync(configDir, { recursive: true });
5218
5251
  }
5219
5252
  const config = {
5220
5253
  name: botName,
@@ -5278,13 +5311,13 @@ ${bold("Writing configuration files...")}`);
5278
5311
  if (ownerUserId) {
5279
5312
  config.security.ownerUserId = ownerUserId;
5280
5313
  }
5281
- const yamlStr = "# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n" + yaml2.dump(config, { lineWidth: 120, noRefs: true, sortKeys: false });
5282
- const configPath = path4.join(configDir, "default.yml");
5283
- fs4.writeFileSync(configPath, yamlStr, "utf-8");
5314
+ const yamlStr = "# Alfred \u2014 Configuration\n# Generated by `alfred setup`\n# Edit manually or re-run `alfred setup` to reconfigure.\n\n" + yaml3.dump(config, { lineWidth: 120, noRefs: true, sortKeys: false });
5315
+ const configPath = path5.join(configDir, "default.yml");
5316
+ fs5.writeFileSync(configPath, yamlStr, "utf-8");
5284
5317
  console.log(` ${green("+")} ${dim("config/default.yml")} written`);
5285
- const rulesDir = path4.join(configDir, "rules");
5286
- if (!fs4.existsSync(rulesDir)) {
5287
- fs4.mkdirSync(rulesDir, { recursive: true });
5318
+ const rulesDir = path5.join(configDir, "rules");
5319
+ if (!fs5.existsSync(rulesDir)) {
5320
+ fs5.mkdirSync(rulesDir, { recursive: true });
5288
5321
  }
5289
5322
  const ownerAdminRule = enableShell && ownerUserId ? `
5290
5323
  # Allow admin actions (shell, etc.) for the owner only
@@ -5365,12 +5398,12 @@ ${ownerAdminRule}
5365
5398
  actions: ["*"]
5366
5399
  riskLevels: [read, write, destructive, admin]
5367
5400
  `;
5368
- const rulesPath = path4.join(rulesDir, "default-rules.yml");
5369
- fs4.writeFileSync(rulesPath, rulesYaml, "utf-8");
5401
+ const rulesPath = path5.join(rulesDir, "default-rules.yml");
5402
+ fs5.writeFileSync(rulesPath, rulesYaml, "utf-8");
5370
5403
  console.log(` ${green("+")} ${dim("config/rules/default-rules.yml")} written`);
5371
- const dataDir = path4.join(projectRoot, "data");
5372
- if (!fs4.existsSync(dataDir)) {
5373
- fs4.mkdirSync(dataDir, { recursive: true });
5404
+ const dataDir = path5.join(projectRoot, "data");
5405
+ if (!fs5.existsSync(dataDir)) {
5406
+ fs5.mkdirSync(dataDir, { recursive: true });
5374
5407
  console.log(` ${green("+")} ${dim("data/")} directory created`);
5375
5408
  }
5376
5409
  console.log("");
@@ -5643,9 +5676,9 @@ var rules_exports = {};
5643
5676
  __export(rules_exports, {
5644
5677
  rulesCommand: () => rulesCommand
5645
5678
  });
5646
- import fs5 from "node:fs";
5647
- import path5 from "node:path";
5648
- import yaml3 from "js-yaml";
5679
+ import fs6 from "node:fs";
5680
+ import path6 from "node:path";
5681
+ import yaml4 from "js-yaml";
5649
5682
  async function rulesCommand() {
5650
5683
  const configLoader = new ConfigLoader();
5651
5684
  let config;
@@ -5655,18 +5688,18 @@ async function rulesCommand() {
5655
5688
  console.error("Failed to load configuration:", error.message);
5656
5689
  process.exit(1);
5657
5690
  }
5658
- const rulesPath = path5.resolve(config.security.rulesPath);
5659
- if (!fs5.existsSync(rulesPath)) {
5691
+ const rulesPath = path6.resolve(config.security.rulesPath);
5692
+ if (!fs6.existsSync(rulesPath)) {
5660
5693
  console.log(`Rules directory not found: ${rulesPath}`);
5661
5694
  console.log("No security rules loaded.");
5662
5695
  return;
5663
5696
  }
5664
- const stat = fs5.statSync(rulesPath);
5697
+ const stat = fs6.statSync(rulesPath);
5665
5698
  if (!stat.isDirectory()) {
5666
5699
  console.error(`Rules path is not a directory: ${rulesPath}`);
5667
5700
  process.exit(1);
5668
5701
  }
5669
- const files = fs5.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5702
+ const files = fs6.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5670
5703
  if (files.length === 0) {
5671
5704
  console.log(`No YAML rule files found in: ${rulesPath}`);
5672
5705
  return;
@@ -5675,10 +5708,10 @@ async function rulesCommand() {
5675
5708
  const allRules = [];
5676
5709
  const errors = [];
5677
5710
  for (const file of files) {
5678
- const filePath = path5.join(rulesPath, file);
5711
+ const filePath = path6.join(rulesPath, file);
5679
5712
  try {
5680
- const raw = fs5.readFileSync(filePath, "utf-8");
5681
- const parsed = yaml3.load(raw);
5713
+ const raw = fs6.readFileSync(filePath, "utf-8");
5714
+ const parsed = yaml4.load(raw);
5682
5715
  const rules = ruleLoader.loadFromObject(parsed);
5683
5716
  allRules.push(...rules);
5684
5717
  } catch (error) {
@@ -5729,9 +5762,9 @@ var status_exports = {};
5729
5762
  __export(status_exports, {
5730
5763
  statusCommand: () => statusCommand
5731
5764
  });
5732
- import fs6 from "node:fs";
5733
- import path6 from "node:path";
5734
- import yaml4 from "js-yaml";
5765
+ import fs7 from "node:fs";
5766
+ import path7 from "node:path";
5767
+ import yaml5 from "js-yaml";
5735
5768
  async function statusCommand() {
5736
5769
  const configLoader = new ConfigLoader();
5737
5770
  let config;
@@ -5787,23 +5820,23 @@ async function statusCommand() {
5787
5820
  }
5788
5821
  console.log("");
5789
5822
  console.log("Storage:");
5790
- const dbPath = path6.resolve(config.storage.path);
5791
- const dbExists = fs6.existsSync(dbPath);
5823
+ const dbPath = path7.resolve(config.storage.path);
5824
+ const dbExists = fs7.existsSync(dbPath);
5792
5825
  console.log(` Database: ${dbPath}`);
5793
5826
  console.log(` Status: ${dbExists ? "exists" : "not yet created"}`);
5794
5827
  console.log("");
5795
- const rulesPath = path6.resolve(config.security.rulesPath);
5828
+ const rulesPath = path7.resolve(config.security.rulesPath);
5796
5829
  let ruleCount = 0;
5797
5830
  let ruleFileCount = 0;
5798
- if (fs6.existsSync(rulesPath) && fs6.statSync(rulesPath).isDirectory()) {
5799
- const files = fs6.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5831
+ if (fs7.existsSync(rulesPath) && fs7.statSync(rulesPath).isDirectory()) {
5832
+ const files = fs7.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5800
5833
  ruleFileCount = files.length;
5801
5834
  const ruleLoader = new RuleLoader();
5802
5835
  for (const file of files) {
5803
- const filePath = path6.join(rulesPath, file);
5836
+ const filePath = path7.join(rulesPath, file);
5804
5837
  try {
5805
- const raw = fs6.readFileSync(filePath, "utf-8");
5806
- const parsed = yaml4.load(raw);
5838
+ const raw = fs7.readFileSync(filePath, "utf-8");
5839
+ const parsed = yaml5.load(raw);
5807
5840
  const rules = ruleLoader.loadFromObject(parsed);
5808
5841
  ruleCount += rules.length;
5809
5842
  } catch {
@@ -5836,8 +5869,8 @@ var logs_exports = {};
5836
5869
  __export(logs_exports, {
5837
5870
  logsCommand: () => logsCommand
5838
5871
  });
5839
- import fs7 from "node:fs";
5840
- import path7 from "node:path";
5872
+ import fs8 from "node:fs";
5873
+ import path8 from "node:path";
5841
5874
  async function logsCommand(tail) {
5842
5875
  const configLoader = new ConfigLoader();
5843
5876
  let config;
@@ -5847,8 +5880,8 @@ async function logsCommand(tail) {
5847
5880
  console.error("Failed to load configuration:", error.message);
5848
5881
  process.exit(1);
5849
5882
  }
5850
- const dbPath = path7.resolve(config.storage.path);
5851
- if (!fs7.existsSync(dbPath)) {
5883
+ const dbPath = path8.resolve(config.storage.path);
5884
+ if (!fs8.existsSync(dbPath)) {
5852
5885
  console.log(`Database not found at: ${dbPath}`);
5853
5886
  console.log("No audit log entries. Alfred has not been run yet, or the database path is incorrect.");
5854
5887
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madh-io/alfred-ai",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Alfred — Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",
5
5
  "type": "module",
6
6
  "bin": {