@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": [
|
|
@@ -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 ---
|