@madh-io/alfred-ai 0.3.0 → 0.3.2

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 +109 -57
  2. package/package.json +1 -1
package/bundle/index.js CHANGED
@@ -2239,8 +2239,8 @@ var init_system_info = __esm({
2239
2239
  properties: {
2240
2240
  category: {
2241
2241
  type: "string",
2242
- enum: ["general", "memory", "uptime"],
2243
- description: "Category of system info"
2242
+ enum: ["general", "memory", "uptime", "datetime"],
2243
+ description: "Category of system info (use datetime for current date/time)"
2244
2244
  }
2245
2245
  },
2246
2246
  required: ["category"]
@@ -2255,6 +2255,8 @@ var init_system_info = __esm({
2255
2255
  return this.getMemoryInfo();
2256
2256
  case "uptime":
2257
2257
  return this.getUptimeInfo();
2258
+ case "datetime":
2259
+ return this.getDateTimeInfo();
2258
2260
  default:
2259
2261
  return {
2260
2262
  success: false,
@@ -2304,6 +2306,21 @@ var init_system_info = __esm({
2304
2306
  display: `Uptime: ${info.formatted}`
2305
2307
  };
2306
2308
  }
2309
+ getDateTimeInfo() {
2310
+ const now = /* @__PURE__ */ new Date();
2311
+ const info = {
2312
+ iso: now.toISOString(),
2313
+ date: now.toLocaleDateString("de-DE", { weekday: "long", year: "numeric", month: "long", day: "numeric" }),
2314
+ time: now.toLocaleTimeString("de-DE"),
2315
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
2316
+ timestamp: now.getTime()
2317
+ };
2318
+ return {
2319
+ success: true,
2320
+ data: info,
2321
+ display: `${info.date}, ${info.time} (${info.timezone})`
2322
+ };
2323
+ }
2307
2324
  };
2308
2325
  }
2309
2326
  });
@@ -3906,6 +3923,7 @@ var init_message_pipeline = __esm({
3906
3923
  const result = await this.executeToolCall(toolCall, {
3907
3924
  userId: user.id,
3908
3925
  chatId: message.chatId,
3926
+ chatType: message.chatType,
3909
3927
  platform: message.platform,
3910
3928
  conversationId: conversation.id
3911
3929
  });
@@ -3940,7 +3958,8 @@ var init_message_pipeline = __esm({
3940
3958
  action: toolCall.name,
3941
3959
  riskLevel: skill.metadata.riskLevel,
3942
3960
  platform: context.platform,
3943
- chatId: context.chatId
3961
+ chatId: context.chatId,
3962
+ chatType: context.chatType
3944
3963
  });
3945
3964
  if (!evaluation.allowed) {
3946
3965
  this.logger.warn({ tool: toolCall.name, reason: evaluation.reason, rule: evaluation.matchedRule?.id }, "Skill execution denied by security rules");
@@ -4554,6 +4573,9 @@ var init_dist7 = __esm({
4554
4573
  });
4555
4574
 
4556
4575
  // ../core/dist/alfred.js
4576
+ import fs4 from "node:fs";
4577
+ import path4 from "node:path";
4578
+ import yaml2 from "js-yaml";
4557
4579
  var Alfred;
4558
4580
  var init_alfred = __esm({
4559
4581
  "../core/dist/alfred.js"() {
@@ -4588,8 +4610,10 @@ var init_alfred = __esm({
4588
4610
  const reminderRepo = new ReminderRepository(db);
4589
4611
  this.logger.info("Storage initialized");
4590
4612
  const ruleEngine = new RuleEngine();
4613
+ const rules = this.loadSecurityRules();
4614
+ ruleEngine.loadRules(rules);
4591
4615
  const securityManager = new SecurityManager(ruleEngine, auditRepo, this.logger.child({ component: "security" }));
4592
- this.logger.info("Security engine initialized");
4616
+ this.logger.info({ ruleCount: rules.length }, "Security engine initialized");
4593
4617
  const llmProvider = createLLMProvider(this.config.llm);
4594
4618
  await llmProvider.initialize();
4595
4619
  this.logger.info({ provider: this.config.llm.provider, model: this.config.llm.model }, "LLM provider initialized");
@@ -4708,6 +4732,34 @@ var init_alfred = __esm({
4708
4732
  this.logger.warn({ platform }, "Adapter disconnected");
4709
4733
  });
4710
4734
  }
4735
+ loadSecurityRules() {
4736
+ const rulesPath = path4.resolve(this.config.security.rulesPath);
4737
+ const rules = [];
4738
+ if (!fs4.existsSync(rulesPath)) {
4739
+ this.logger.warn({ rulesPath }, "Security rules directory not found, using default deny");
4740
+ return rules;
4741
+ }
4742
+ const stat = fs4.statSync(rulesPath);
4743
+ if (!stat.isDirectory()) {
4744
+ this.logger.warn({ rulesPath }, "Security rules path is not a directory");
4745
+ return rules;
4746
+ }
4747
+ const files = fs4.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
4748
+ for (const file of files) {
4749
+ try {
4750
+ const filePath = path4.join(rulesPath, file);
4751
+ const content = fs4.readFileSync(filePath, "utf-8");
4752
+ const parsed = yaml2.load(content);
4753
+ if (parsed?.rules && Array.isArray(parsed.rules)) {
4754
+ rules.push(...parsed.rules);
4755
+ this.logger.info({ file, count: parsed.rules.length }, "Loaded security rules");
4756
+ }
4757
+ } catch (err) {
4758
+ this.logger.error({ err, file }, "Failed to load security rules file");
4759
+ }
4760
+ }
4761
+ return rules;
4762
+ }
4711
4763
  };
4712
4764
  }
4713
4765
  });
@@ -4790,9 +4842,9 @@ __export(setup_exports, {
4790
4842
  });
4791
4843
  import { createInterface } from "node:readline/promises";
4792
4844
  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";
4845
+ import fs5 from "node:fs";
4846
+ import path5 from "node:path";
4847
+ import yaml3 from "js-yaml";
4796
4848
  function green(s) {
4797
4849
  return `${GREEN}${s}${RESET}`;
4798
4850
  }
@@ -4822,20 +4874,20 @@ function loadExistingConfig(projectRoot) {
4822
4874
  let shellEnabled = false;
4823
4875
  let writeInGroups = false;
4824
4876
  let rateLimit = 30;
4825
- const configPath = path4.join(projectRoot, "config", "default.yml");
4826
- if (fs4.existsSync(configPath)) {
4877
+ const configPath = path5.join(projectRoot, "config", "default.yml");
4878
+ if (fs5.existsSync(configPath)) {
4827
4879
  try {
4828
- const parsed = yaml2.load(fs4.readFileSync(configPath, "utf-8"));
4880
+ const parsed = yaml3.load(fs5.readFileSync(configPath, "utf-8"));
4829
4881
  if (parsed && typeof parsed === "object") {
4830
4882
  Object.assign(config, parsed);
4831
4883
  }
4832
4884
  } catch {
4833
4885
  }
4834
4886
  }
4835
- const envPath = path4.join(projectRoot, ".env");
4836
- if (fs4.existsSync(envPath)) {
4887
+ const envPath = path5.join(projectRoot, ".env");
4888
+ if (fs5.existsSync(envPath)) {
4837
4889
  try {
4838
- const lines = fs4.readFileSync(envPath, "utf-8").split("\n");
4890
+ const lines = fs5.readFileSync(envPath, "utf-8").split("\n");
4839
4891
  for (const line of lines) {
4840
4892
  const trimmed = line.trim();
4841
4893
  if (!trimmed || trimmed.startsWith("#"))
@@ -4848,10 +4900,10 @@ function loadExistingConfig(projectRoot) {
4848
4900
  } catch {
4849
4901
  }
4850
4902
  }
4851
- const rulesPath = path4.join(projectRoot, "config", "rules", "default-rules.yml");
4852
- if (fs4.existsSync(rulesPath)) {
4903
+ const rulesPath = path5.join(projectRoot, "config", "rules", "default-rules.yml");
4904
+ if (fs5.existsSync(rulesPath)) {
4853
4905
  try {
4854
- const rulesContent = yaml2.load(fs4.readFileSync(rulesPath, "utf-8"));
4906
+ const rulesContent = yaml3.load(fs5.readFileSync(rulesPath, "utf-8"));
4855
4907
  if (rulesContent?.rules) {
4856
4908
  shellEnabled = rulesContent.rules.some((r) => r.id === "allow-owner-admin" && r.effect === "allow");
4857
4909
  const writeDmRule = rulesContent.rules.find((r) => r.id === "allow-write-for-dm" || r.id === "allow-write-all");
@@ -5209,12 +5261,12 @@ ${bold("Writing configuration files...")}`);
5209
5261
  envLines.push("# ALFRED_OWNER_USER_ID=");
5210
5262
  }
5211
5263
  envLines.push("");
5212
- const envPath = path4.join(projectRoot, ".env");
5213
- fs4.writeFileSync(envPath, envLines.join("\n"), "utf-8");
5264
+ const envPath = path5.join(projectRoot, ".env");
5265
+ fs5.writeFileSync(envPath, envLines.join("\n"), "utf-8");
5214
5266
  console.log(` ${green("+")} ${dim(".env")} written`);
5215
- const configDir = path4.join(projectRoot, "config");
5216
- if (!fs4.existsSync(configDir)) {
5217
- fs4.mkdirSync(configDir, { recursive: true });
5267
+ const configDir = path5.join(projectRoot, "config");
5268
+ if (!fs5.existsSync(configDir)) {
5269
+ fs5.mkdirSync(configDir, { recursive: true });
5218
5270
  }
5219
5271
  const config = {
5220
5272
  name: botName,
@@ -5278,13 +5330,13 @@ ${bold("Writing configuration files...")}`);
5278
5330
  if (ownerUserId) {
5279
5331
  config.security.ownerUserId = ownerUserId;
5280
5332
  }
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");
5333
+ 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 });
5334
+ const configPath = path5.join(configDir, "default.yml");
5335
+ fs5.writeFileSync(configPath, yamlStr, "utf-8");
5284
5336
  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 });
5337
+ const rulesDir = path5.join(configDir, "rules");
5338
+ if (!fs5.existsSync(rulesDir)) {
5339
+ fs5.mkdirSync(rulesDir, { recursive: true });
5288
5340
  }
5289
5341
  const ownerAdminRule = enableShell && ownerUserId ? `
5290
5342
  # Allow admin actions (shell, etc.) for the owner only
@@ -5365,12 +5417,12 @@ ${ownerAdminRule}
5365
5417
  actions: ["*"]
5366
5418
  riskLevels: [read, write, destructive, admin]
5367
5419
  `;
5368
- const rulesPath = path4.join(rulesDir, "default-rules.yml");
5369
- fs4.writeFileSync(rulesPath, rulesYaml, "utf-8");
5420
+ const rulesPath = path5.join(rulesDir, "default-rules.yml");
5421
+ fs5.writeFileSync(rulesPath, rulesYaml, "utf-8");
5370
5422
  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 });
5423
+ const dataDir = path5.join(projectRoot, "data");
5424
+ if (!fs5.existsSync(dataDir)) {
5425
+ fs5.mkdirSync(dataDir, { recursive: true });
5374
5426
  console.log(` ${green("+")} ${dim("data/")} directory created`);
5375
5427
  }
5376
5428
  console.log("");
@@ -5643,9 +5695,9 @@ var rules_exports = {};
5643
5695
  __export(rules_exports, {
5644
5696
  rulesCommand: () => rulesCommand
5645
5697
  });
5646
- import fs5 from "node:fs";
5647
- import path5 from "node:path";
5648
- import yaml3 from "js-yaml";
5698
+ import fs6 from "node:fs";
5699
+ import path6 from "node:path";
5700
+ import yaml4 from "js-yaml";
5649
5701
  async function rulesCommand() {
5650
5702
  const configLoader = new ConfigLoader();
5651
5703
  let config;
@@ -5655,18 +5707,18 @@ async function rulesCommand() {
5655
5707
  console.error("Failed to load configuration:", error.message);
5656
5708
  process.exit(1);
5657
5709
  }
5658
- const rulesPath = path5.resolve(config.security.rulesPath);
5659
- if (!fs5.existsSync(rulesPath)) {
5710
+ const rulesPath = path6.resolve(config.security.rulesPath);
5711
+ if (!fs6.existsSync(rulesPath)) {
5660
5712
  console.log(`Rules directory not found: ${rulesPath}`);
5661
5713
  console.log("No security rules loaded.");
5662
5714
  return;
5663
5715
  }
5664
- const stat = fs5.statSync(rulesPath);
5716
+ const stat = fs6.statSync(rulesPath);
5665
5717
  if (!stat.isDirectory()) {
5666
5718
  console.error(`Rules path is not a directory: ${rulesPath}`);
5667
5719
  process.exit(1);
5668
5720
  }
5669
- const files = fs5.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5721
+ const files = fs6.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5670
5722
  if (files.length === 0) {
5671
5723
  console.log(`No YAML rule files found in: ${rulesPath}`);
5672
5724
  return;
@@ -5675,10 +5727,10 @@ async function rulesCommand() {
5675
5727
  const allRules = [];
5676
5728
  const errors = [];
5677
5729
  for (const file of files) {
5678
- const filePath = path5.join(rulesPath, file);
5730
+ const filePath = path6.join(rulesPath, file);
5679
5731
  try {
5680
- const raw = fs5.readFileSync(filePath, "utf-8");
5681
- const parsed = yaml3.load(raw);
5732
+ const raw = fs6.readFileSync(filePath, "utf-8");
5733
+ const parsed = yaml4.load(raw);
5682
5734
  const rules = ruleLoader.loadFromObject(parsed);
5683
5735
  allRules.push(...rules);
5684
5736
  } catch (error) {
@@ -5729,9 +5781,9 @@ var status_exports = {};
5729
5781
  __export(status_exports, {
5730
5782
  statusCommand: () => statusCommand
5731
5783
  });
5732
- import fs6 from "node:fs";
5733
- import path6 from "node:path";
5734
- import yaml4 from "js-yaml";
5784
+ import fs7 from "node:fs";
5785
+ import path7 from "node:path";
5786
+ import yaml5 from "js-yaml";
5735
5787
  async function statusCommand() {
5736
5788
  const configLoader = new ConfigLoader();
5737
5789
  let config;
@@ -5787,23 +5839,23 @@ async function statusCommand() {
5787
5839
  }
5788
5840
  console.log("");
5789
5841
  console.log("Storage:");
5790
- const dbPath = path6.resolve(config.storage.path);
5791
- const dbExists = fs6.existsSync(dbPath);
5842
+ const dbPath = path7.resolve(config.storage.path);
5843
+ const dbExists = fs7.existsSync(dbPath);
5792
5844
  console.log(` Database: ${dbPath}`);
5793
5845
  console.log(` Status: ${dbExists ? "exists" : "not yet created"}`);
5794
5846
  console.log("");
5795
- const rulesPath = path6.resolve(config.security.rulesPath);
5847
+ const rulesPath = path7.resolve(config.security.rulesPath);
5796
5848
  let ruleCount = 0;
5797
5849
  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"));
5850
+ if (fs7.existsSync(rulesPath) && fs7.statSync(rulesPath).isDirectory()) {
5851
+ const files = fs7.readdirSync(rulesPath).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
5800
5852
  ruleFileCount = files.length;
5801
5853
  const ruleLoader = new RuleLoader();
5802
5854
  for (const file of files) {
5803
- const filePath = path6.join(rulesPath, file);
5855
+ const filePath = path7.join(rulesPath, file);
5804
5856
  try {
5805
- const raw = fs6.readFileSync(filePath, "utf-8");
5806
- const parsed = yaml4.load(raw);
5857
+ const raw = fs7.readFileSync(filePath, "utf-8");
5858
+ const parsed = yaml5.load(raw);
5807
5859
  const rules = ruleLoader.loadFromObject(parsed);
5808
5860
  ruleCount += rules.length;
5809
5861
  } catch {
@@ -5836,8 +5888,8 @@ var logs_exports = {};
5836
5888
  __export(logs_exports, {
5837
5889
  logsCommand: () => logsCommand
5838
5890
  });
5839
- import fs7 from "node:fs";
5840
- import path7 from "node:path";
5891
+ import fs8 from "node:fs";
5892
+ import path8 from "node:path";
5841
5893
  async function logsCommand(tail) {
5842
5894
  const configLoader = new ConfigLoader();
5843
5895
  let config;
@@ -5847,8 +5899,8 @@ async function logsCommand(tail) {
5847
5899
  console.error("Failed to load configuration:", error.message);
5848
5900
  process.exit(1);
5849
5901
  }
5850
- const dbPath = path7.resolve(config.storage.path);
5851
- if (!fs7.existsSync(dbPath)) {
5902
+ const dbPath = path8.resolve(config.storage.path);
5903
+ if (!fs8.existsSync(dbPath)) {
5852
5904
  console.log(`Database not found at: ${dbPath}`);
5853
5905
  console.log("No audit log entries. Alfred has not been run yet, or the database path is incorrect.");
5854
5906
  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.2",
4
4
  "description": "Alfred — Personal AI Assistant across Telegram, Discord, WhatsApp, Matrix & Signal",
5
5
  "type": "module",
6
6
  "bin": {