@ouro.bot/cli 0.1.0-alpha.288 → 0.1.0-alpha.289

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,12 @@
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.289",
6
+ "changes": [
7
+ "feat(senses): enforce per-habit tool restrictions during inner dialog turns. When a habit file declares a `tools` field in its frontmatter (e.g., `tools: [read, web_fetch, send_message]`), the inner dialog adapter now filters the full tool repertoire to only those declared tools before passing them to the turn runner. Habits without a `tools` field retain the full repertoire (backwards compatible). Fail-closed design: unknown tool names in the `tools` array are silently excluded rather than causing errors. Two nerves events provide observability: `habit.tools_restricted` (emitted with declared vs resolved tool lists) and `habit.tools_unrestricted` (emitted when a successfully-parsed habit runs with full repertoire). Existing guardrails (protected paths, destructive command blocking) still apply at execution time. 6 new test cases cover restriction, unknown tool exclusion, unrestricted event emission, no event on parse failure, tools passthrough to turn runner, and empty tools array behavior."
8
+ ]
9
+ },
4
10
  {
5
11
  "version": "0.1.0-alpha.288",
6
12
  "changes": [
@@ -53,6 +53,7 @@ const identity_1 = require("../heart/identity");
53
53
  const context_1 = require("../mind/context");
54
54
  const prompt_1 = require("../mind/prompt");
55
55
  const mcp_manager_1 = require("../repertoire/mcp-manager");
56
+ const tools_1 = require("../repertoire/tools");
56
57
  const bundle_manifest_1 = require("../mind/bundle-manifest");
57
58
  const pending_1 = require("../mind/pending");
58
59
  const obligations_1 = require("../arc/obligations");
@@ -535,6 +536,8 @@ async function runInnerDialogTurn(options) {
535
536
  };
536
537
  // ── Adapter concern: build user message ──────────────────────────
537
538
  let userContent;
539
+ let habitTools;
540
+ let habitParsedSuccessfully = false;
538
541
  if (existingMessages.length === 0) {
539
542
  // Fresh session: bootstrap message with non-canonical cleanup nudge
540
543
  const aspirations = readAspirations((0, identity_1.getAgentRoot)());
@@ -568,6 +571,7 @@ async function runInnerDialogTurn(options) {
568
571
  habitBody = parsed.body || undefined;
569
572
  habitTitle = parsed.title || habitName;
570
573
  habitLastRun = parsed.lastRun;
574
+ habitTools = parsed.tools;
571
575
  }
572
576
  catch {
573
577
  // Habit file missing or unreadable
@@ -577,6 +581,7 @@ async function runInnerDialogTurn(options) {
577
581
  userContent = `habit "${habitName}" could not be read (file not found or unreadable). check habits/${habitName}.md exists.`;
578
582
  }
579
583
  else {
584
+ habitParsedSuccessfully = true;
580
585
  // Unified path: gather context for ALL habits (heartbeat included)
581
586
  const obligations = (0, obligations_1.listActiveReturnObligations)(agentName);
582
587
  const nowMs = now().getTime();
@@ -631,6 +636,30 @@ async function runInnerDialogTurn(options) {
631
636
  const selfFriend = createSelfFriend(agentName);
632
637
  const selfContext = { friend: selfFriend, channel: innerCapabilities };
633
638
  const mcpManager = await (0, mcp_manager_1.getSharedMcpManager)() ?? undefined;
639
+ // ── Habit tool enforcement ───────────────────────────────────────
640
+ let habitToolsResolved;
641
+ if (habitTools !== undefined) {
642
+ const fullTools = (0, tools_1.getToolsForChannel)(innerCapabilities);
643
+ habitToolsResolved = fullTools.filter((t) => habitTools.includes(t.function.name));
644
+ (0, runtime_1.emitNervesEvent)({
645
+ event: "habit.tools_restricted",
646
+ component: "senses",
647
+ message: "habit running with restricted tools",
648
+ meta: {
649
+ habitName: options?.habitName,
650
+ declared: habitTools,
651
+ resolved: habitToolsResolved.map((t) => t.function.name),
652
+ },
653
+ });
654
+ }
655
+ else if (reason === "habit" && options?.habitName && habitParsedSuccessfully) {
656
+ (0, runtime_1.emitNervesEvent)({
657
+ event: "habit.tools_unrestricted",
658
+ component: "senses",
659
+ message: "habit running with full tool repertoire",
660
+ meta: { habitName: options.habitName },
661
+ });
662
+ }
634
663
  const sessionLoader = {
635
664
  loadOrCreate: async () => {
636
665
  if (existingMessages.length > 0) {
@@ -694,6 +723,7 @@ async function runInnerDialogTurn(options) {
694
723
  traceId,
695
724
  toolChoiceRequired: true,
696
725
  mcpManager,
726
+ ...(habitToolsResolved !== undefined && { tools: habitToolsResolved }),
697
727
  toolContext: {
698
728
  signin: async () => undefined,
699
729
  delegatedOrigins: attentionQueue,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.288",
3
+ "version": "0.1.0-alpha.289",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",