@ouro.bot/cli 0.1.0-alpha.284 → 0.1.0-alpha.285

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/changelog.json CHANGED
@@ -1,6 +1,14 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.285",
6
+ "changes": [
7
+ "feat(daemon): wire startPeriodicReconciliation() after scheduler.start() in daemon-entry.ts — prevents silent habit death when OS cron fails by giving the daemon a self-healing reconciliation loop.",
8
+ "feat(guardrails): protect agent.json from agent self-modification — closes a vector where prompt injection could alter the agent's own identity, provider, or model settings.",
9
+ "feat(habits): add tools field to HabitFile interface and habit-parser — habits can now declare tools: [read, web_fetch] in frontmatter. Schema-only; runtime enforcement ships in a follow-up PR."
10
+ ]
11
+ },
4
12
  {
5
13
  "version": "0.1.0-alpha.284",
6
14
  "changes": [
@@ -195,6 +195,7 @@ void daemon.start().then(() => {
195
195
  },
196
196
  });
197
197
  scheduler.start();
198
+ scheduler.startPeriodicReconciliation();
198
199
  scheduler.watchForChanges();
199
200
  habitSchedulers.push(scheduler);
200
201
  }
@@ -41,6 +41,22 @@ const runtime_1 = require("../../nerves/runtime");
41
41
  function isHabitStatus(value) {
42
42
  return value === "active" || value === "paused";
43
43
  }
44
+ function parseToolsField(raw) {
45
+ if (raw === undefined || raw === null)
46
+ return undefined;
47
+ // YAML dash-list: parseFrontmatter returns unknown[]
48
+ if (Array.isArray(raw)) {
49
+ return raw.filter((item) => typeof item === "string");
50
+ }
51
+ // Inline bracket format: parseFrontmatter returns string like "[a, b, c]"
52
+ if (typeof raw === "string" && raw.startsWith("[") && raw.endsWith("]")) {
53
+ const inner = raw.slice(1, -1);
54
+ if (inner.trim().length === 0)
55
+ return [];
56
+ return inner.split(",").map((s) => s.trim()).filter(Boolean);
57
+ }
58
+ return undefined;
59
+ }
44
60
  function extractFrontmatterAndBody(content) {
45
61
  const lines = content.split(/\r?\n/);
46
62
  if (lines[0]?.trim() !== "---") {
@@ -71,6 +87,7 @@ function parseHabitFile(content, filePath) {
71
87
  status: "active",
72
88
  lastRun: null,
73
89
  created: null,
90
+ tools: undefined,
74
91
  body: content.trim(),
75
92
  };
76
93
  }
@@ -85,6 +102,7 @@ function parseHabitFile(content, filePath) {
85
102
  const lastRun = typeof rawLastRun === "string" && rawLastRun.length > 0 ? rawLastRun : null;
86
103
  const rawCreated = frontmatter.created;
87
104
  const created = typeof rawCreated === "string" && rawCreated.length > 0 ? rawCreated : null;
105
+ const tools = parseToolsField(frontmatter.tools);
88
106
  return {
89
107
  name: stem,
90
108
  title,
@@ -92,12 +110,15 @@ function parseHabitFile(content, filePath) {
92
110
  status,
93
111
  lastRun,
94
112
  created,
113
+ tools,
95
114
  body,
96
115
  };
97
116
  }
98
117
  function formatFrontmatterValue(value) {
99
118
  if (value === null || value === undefined)
100
119
  return "null";
120
+ if (Array.isArray(value))
121
+ return `[${value.join(", ")}]`;
101
122
  return String(value);
102
123
  }
103
124
  function renderHabitFile(frontmatter, body) {
@@ -37,6 +37,7 @@ exports.OURO_CLI_TRUST_MANIFEST = void 0;
37
37
  exports.guardInvocation = guardInvocation;
38
38
  const fs = __importStar(require("node:fs"));
39
39
  const os = __importStar(require("node:os"));
40
+ const path = __importStar(require("node:path"));
40
41
  const types_1 = require("../mind/friends/types");
41
42
  const runtime_1 = require("../nerves/runtime");
42
43
  const deny = (reason) => ({ allowed: false, reason });
@@ -56,6 +57,7 @@ const REASONS = {
56
57
  const READ_ONLY_TOOLS = new Set(["read_file", "glob", "grep"]);
57
58
  // --- protected path detection ---
58
59
  const PROTECTED_PATH_SEGMENTS = [".git/"];
60
+ const PROTECTED_FILENAMES = ["agent.json"];
59
61
  function getProtectedAbsolutePrefixes() {
60
62
  return [`${os.homedir()}/.agentsecrets/`];
61
63
  }
@@ -68,6 +70,10 @@ function isProtectedPath(filePath) {
68
70
  if (filePath.startsWith(prefix))
69
71
  return true;
70
72
  }
73
+ for (const name of PROTECTED_FILENAMES) {
74
+ if (path.basename(filePath) === name)
75
+ return true;
76
+ }
71
77
  return false;
72
78
  }
73
79
  // --- destructive shell patterns ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.284",
3
+ "version": "0.1.0-alpha.285",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",