@ouro.bot/cli 0.1.0-alpha.205 → 0.1.0-alpha.207

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.
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shellToolDefinitions = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const shell_sessions_1 = require("./shell-sessions");
6
+ const identity_1 = require("../heart/identity");
7
+ const runtime_1 = require("../nerves/runtime");
8
+ exports.shellToolDefinitions = [
9
+ {
10
+ tool: {
11
+ type: "function",
12
+ function: {
13
+ name: "shell",
14
+ description: "Run a shell command and return stdout/stderr. Working directory persists between calls. Use dedicated tools instead of shell when available: read_file instead of cat, edit_file instead of sed, glob instead of find, grep instead of grep/rg. Reserve shell for operations that genuinely need the shell: installing packages, running builds/tests, git operations, process management. Be careful with destructive commands -- consider reversibility before running. If a command fails, read the error output before retrying with a different approach.",
15
+ parameters: {
16
+ type: "object",
17
+ properties: {
18
+ command: { type: "string" },
19
+ timeout_ms: {
20
+ type: "number",
21
+ description: "Timeout in milliseconds. Default: 30000. Max: 600000.",
22
+ },
23
+ background: {
24
+ type: "boolean",
25
+ description: "Run in background. Returns immediately with a process ID. Use shell_status/shell_tail to monitor.",
26
+ },
27
+ },
28
+ required: ["command"],
29
+ },
30
+ },
31
+ },
32
+ handler: (a) => {
33
+ // Destructive pattern detection (friction, not a block)
34
+ const destructivePatterns = (0, shell_sessions_1.detectDestructivePatterns)(a.command);
35
+ if (destructivePatterns.length > 0) {
36
+ (0, runtime_1.emitNervesEvent)({
37
+ level: "warn",
38
+ event: "tool.shell.destructive_detected",
39
+ component: "tools",
40
+ message: `destructive pattern detected: ${destructivePatterns.join(", ")}`,
41
+ meta: { command: a.command, patterns: destructivePatterns },
42
+ });
43
+ }
44
+ // Background mode: spawn and return immediately
45
+ if (a.background === "true") {
46
+ const session = (0, shell_sessions_1.spawnBackgroundShell)(a.command);
47
+ return JSON.stringify({ id: session.id, command: session.command, status: session.status });
48
+ }
49
+ const MAX_TIMEOUT = 600000;
50
+ const requestedTimeout = Number(a.timeout_ms) || 0;
51
+ let configDefault = 30000;
52
+ try {
53
+ configDefault = (0, identity_1.loadAgentConfig)().shell?.defaultTimeout ?? 30000;
54
+ }
55
+ catch { /* test env: no --agent flag */ }
56
+ const baseTimeout = requestedTimeout > 0 ? requestedTimeout : configDefault;
57
+ const timeout = Math.min(baseTimeout, MAX_TIMEOUT);
58
+ const output = (0, child_process_1.execSync)(a.command, {
59
+ encoding: "utf-8",
60
+ timeout,
61
+ });
62
+ if (destructivePatterns.length > 0) {
63
+ return `${output}\n\n--- destructive pattern detected: ${destructivePatterns.join(", ")} ---`;
64
+ }
65
+ return output;
66
+ },
67
+ summaryKeys: ["command"],
68
+ },
69
+ {
70
+ tool: {
71
+ type: "function",
72
+ function: {
73
+ name: "shell_status",
74
+ description: "Check status of background shell processes. Omit id to list all.",
75
+ parameters: {
76
+ type: "object",
77
+ properties: {
78
+ id: { type: "string", description: "Background shell process ID" },
79
+ },
80
+ },
81
+ },
82
+ },
83
+ handler: (a) => {
84
+ if (!a.id) {
85
+ return JSON.stringify((0, shell_sessions_1.listShellSessions)());
86
+ }
87
+ const session = (0, shell_sessions_1.getShellSession)(a.id);
88
+ if (!session)
89
+ return `process not found: ${a.id}`;
90
+ return JSON.stringify(session);
91
+ },
92
+ summaryKeys: ["id"],
93
+ },
94
+ {
95
+ tool: {
96
+ type: "function",
97
+ function: {
98
+ name: "shell_tail",
99
+ description: "Show recent output from a background shell process.",
100
+ parameters: {
101
+ type: "object",
102
+ properties: {
103
+ id: { type: "string", description: "Background shell process ID" },
104
+ },
105
+ required: ["id"],
106
+ },
107
+ },
108
+ },
109
+ handler: (a) => {
110
+ /* v8 ignore next -- schema requires id, defensive guard @preserve */
111
+ if (!a.id)
112
+ return "id is required";
113
+ const output = (0, shell_sessions_1.tailShellSession)(a.id);
114
+ if (output === undefined)
115
+ return `process not found: ${a.id}`;
116
+ return output || "(no output yet)";
117
+ },
118
+ summaryKeys: ["id"],
119
+ },
120
+ ];
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.surfaceToolDefinition = exports.surfaceToolDef = void 0;
37
+ const identity_1 = require("../heart/identity");
38
+ const surface_tool_1 = require("../senses/surface-tool");
39
+ const obligations_1 = require("../heart/obligations");
40
+ const session_activity_1 = require("../heart/session-activity");
41
+ const path = __importStar(require("path"));
42
+ // Surface tool schema — canonical home. Handler lives in senses/surface-tool.ts.
43
+ exports.surfaceToolDef = {
44
+ type: "function",
45
+ function: {
46
+ name: "surface",
47
+ description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
48
+ parameters: {
49
+ type: "object",
50
+ properties: {
51
+ content: {
52
+ type: "string",
53
+ description: "the message to deliver",
54
+ },
55
+ delegationId: {
56
+ type: "string",
57
+ description: "ID from your attention queue — addresses a specific held thought",
58
+ },
59
+ friendId: {
60
+ type: "string",
61
+ description: "friend to reach out to spontaneously (when not addressing a held thought)",
62
+ },
63
+ },
64
+ required: ["content"],
65
+ },
66
+ },
67
+ };
68
+ // Surface tool handler: routes content to friend's freshest session
69
+ /* v8 ignore start -- surface handler wiring: core logic tested via surface-tool.test.ts; this wires identity/routing deps @preserve */
70
+ exports.surfaceToolDefinition = {
71
+ tool: exports.surfaceToolDef,
72
+ handler: async (args, ctx) => {
73
+ const queue = ctx?.delegatedOrigins ?? [];
74
+ const agentName = (() => { try {
75
+ return (0, identity_1.getAgentName)();
76
+ }
77
+ catch {
78
+ return "unknown";
79
+ } })();
80
+ const routeToFriend = async (friendId, content, queueItem) => {
81
+ /* v8 ignore start -- routing: integration path tested via inner-dialog routing tests @preserve */
82
+ try {
83
+ const agentRoot = (0, identity_1.getAgentRoot)();
84
+ const sessionsDir = path.join(agentRoot, "state", "sessions");
85
+ const friendsDir = path.join(agentRoot, "friends");
86
+ // Priority 1: Bridge-preferred session (if queue item has a bridgeId)
87
+ if (queueItem?.bridgeId) {
88
+ const { createBridgeManager } = await Promise.resolve().then(() => __importStar(require("../heart/bridges/manager")));
89
+ const bridge = createBridgeManager().getBridge(queueItem.bridgeId);
90
+ if (bridge && bridge.lifecycle !== "completed" && bridge.lifecycle !== "cancelled") {
91
+ const allSessions = (0, session_activity_1.listSessionActivity)({ sessionsDir, friendsDir, agentName });
92
+ const bridgeTarget = allSessions.find((activity) => activity.friendId === friendId
93
+ && activity.channel !== "inner"
94
+ && bridge.attachedSessions.some((s) => s.friendId === activity.friendId && s.channel === activity.channel && s.key === activity.key));
95
+ if (bridgeTarget) {
96
+ // Attempt proactive BB delivery for bridge target
97
+ if (bridgeTarget.channel === "bluebubbles") {
98
+ const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
99
+ const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
100
+ friendId: bridgeTarget.friendId,
101
+ sessionKey: bridgeTarget.key,
102
+ text: content,
103
+ });
104
+ if (proactiveResult.delivered) {
105
+ // Inject surfaced content into the target session so it knows what was delivered
106
+ const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
107
+ const sessionFilePath = path.join(sessionsDir, bridgeTarget.friendId, bridgeTarget.channel, `${bridgeTarget.key}.json`);
108
+ appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
109
+ return { status: "delivered", detail: "via iMessage" };
110
+ }
111
+ }
112
+ // Fall back to pending queue for bridge target
113
+ const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
114
+ const pendingDir = getPendingDir(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key);
115
+ queuePendingMessage(pendingDir, {
116
+ from: agentName,
117
+ friendId: bridgeTarget.friendId,
118
+ channel: bridgeTarget.channel,
119
+ key: bridgeTarget.key,
120
+ content,
121
+ timestamp: Date.now(),
122
+ });
123
+ return { status: "queued", detail: `for next interaction via ${bridgeTarget.channel}` };
124
+ }
125
+ }
126
+ }
127
+ // Priority 2: Freshest active friend session
128
+ const freshest = (0, session_activity_1.findFreshestFriendSession)({
129
+ sessionsDir,
130
+ friendsDir,
131
+ agentName,
132
+ friendId,
133
+ activeOnly: true,
134
+ });
135
+ if (freshest && freshest.channel !== "inner") {
136
+ // Attempt proactive BB delivery
137
+ if (freshest.channel === "bluebubbles") {
138
+ const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
139
+ const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
140
+ friendId: freshest.friendId,
141
+ sessionKey: freshest.key,
142
+ text: content,
143
+ });
144
+ if (proactiveResult.delivered) {
145
+ // Inject surfaced content into the target session so it knows what was delivered
146
+ const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
147
+ const sessionFilePath = path.join(sessionsDir, freshest.friendId, freshest.channel, `${freshest.key}.json`);
148
+ appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
149
+ return { status: "delivered", detail: "via iMessage" };
150
+ }
151
+ }
152
+ // Queue as pending for next interaction
153
+ const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
154
+ const pendingDir = getPendingDir(agentName, freshest.friendId, freshest.channel, freshest.key);
155
+ queuePendingMessage(pendingDir, {
156
+ from: agentName,
157
+ friendId: freshest.friendId,
158
+ channel: freshest.channel,
159
+ key: freshest.key,
160
+ content,
161
+ timestamp: Date.now(),
162
+ });
163
+ return { status: "queued", detail: `for next interaction via ${freshest.channel}` };
164
+ }
165
+ // Priority 3: Deferred — no active session found
166
+ const { getDeferredReturnDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
167
+ const { queuePendingMessage: queueDeferred } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
168
+ const deferredDir = getDeferredReturnDir(agentName, friendId);
169
+ queueDeferred(deferredDir, {
170
+ from: agentName,
171
+ friendId,
172
+ channel: "deferred",
173
+ key: "return",
174
+ content,
175
+ timestamp: Date.now(),
176
+ });
177
+ return { status: "deferred", detail: "they'll see it next time" };
178
+ }
179
+ catch {
180
+ return { status: "failed" };
181
+ }
182
+ /* v8 ignore stop */
183
+ };
184
+ return (0, surface_tool_1.handleSurface)({
185
+ content: args.content ?? "",
186
+ delegationId: args.delegationId,
187
+ friendId: args.friendId,
188
+ queue,
189
+ routeToFriend,
190
+ advanceObligation: (obligationId, update) => {
191
+ /* v8 ignore start -- obligation advance: tested via attention-queue tests @preserve */
192
+ try {
193
+ const name = (() => { try {
194
+ return (0, identity_1.getAgentName)();
195
+ }
196
+ catch {
197
+ return "unknown";
198
+ } })();
199
+ (0, obligations_1.advanceReturnObligation)(name, obligationId, {
200
+ status: update.status,
201
+ ...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
202
+ ...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
203
+ });
204
+ }
205
+ catch {
206
+ // swallowed — obligation advance must never break surface delivery
207
+ }
208
+ /* v8 ignore stop */
209
+ },
210
+ fulfillHeartObligation: (origin) => {
211
+ /* v8 ignore start -- heart obligation fulfillment: tested via surface-tool.test.ts @preserve */
212
+ try {
213
+ const agentRoot = (0, identity_1.getAgentRoot)();
214
+ const heartObligation = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, origin);
215
+ if (heartObligation) {
216
+ (0, obligations_1.fulfillObligation)(agentRoot, heartObligation.id);
217
+ }
218
+ }
219
+ catch {
220
+ // swallowed — heart obligation fulfillment must never break surface delivery
221
+ }
222
+ /* v8 ignore stop */
223
+ },
224
+ });
225
+ },
226
+ summaryKeys: ["content", "delegationId"],
227
+ };
228
+ /* v8 ignore stop */
@@ -1,41 +1,9 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.surfaceToolDef = exports.restTool = exports.ponderTool = exports.observeTool = exports.settleTool = exports.tools = void 0;
37
4
  exports.getToolsForChannel = getToolsForChannel;
38
5
  exports.isConfirmationRequired = isConfirmationRequired;
6
+ exports.isConfirmationAlwaysRequired = isConfirmationAlwaysRequired;
39
7
  exports.execTool = execTool;
40
8
  exports.summarizeArgs = summarizeArgs;
41
9
  exports.buildToolResultSummary = buildToolResultSummary;
@@ -47,10 +15,7 @@ const tools_github_1 = require("./tools-github");
47
15
  const runtime_1 = require("../nerves/runtime");
48
16
  const guardrails_1 = require("./guardrails");
49
17
  const identity_1 = require("../heart/identity");
50
- const surface_tool_1 = require("../senses/surface-tool");
51
- const obligations_1 = require("../heart/obligations");
52
- const session_activity_1 = require("../heart/session-activity");
53
- const path = __importStar(require("path"));
18
+ const tools_surface_1 = require("./tools-surface");
54
19
  function safeGetAgentRoot() {
55
20
  try {
56
21
  return (0, identity_1.getAgentRoot)();
@@ -66,195 +31,11 @@ Object.defineProperty(exports, "settleTool", { enumerable: true, get: function (
66
31
  Object.defineProperty(exports, "observeTool", { enumerable: true, get: function () { return tools_base_2.observeTool; } });
67
32
  Object.defineProperty(exports, "ponderTool", { enumerable: true, get: function () { return tools_base_2.ponderTool; } });
68
33
  Object.defineProperty(exports, "restTool", { enumerable: true, get: function () { return tools_base_2.restTool; } });
69
- // Surface tool schema — canonical home. Handler lives in senses/surface-tool.ts.
70
- exports.surfaceToolDef = {
71
- type: "function",
72
- function: {
73
- name: "surface",
74
- description: "share a thought outward — deliver an answer, ask a follow-up, or surface progress to whoever needs to hear it. pass delegationId to address a held thought (see your attention queue above), or friendId for spontaneous outreach. does not end your turn.",
75
- parameters: {
76
- type: "object",
77
- properties: {
78
- content: {
79
- type: "string",
80
- description: "the message to deliver",
81
- },
82
- delegationId: {
83
- type: "string",
84
- description: "ID from your attention queue — addresses a specific held thought",
85
- },
86
- friendId: {
87
- type: "string",
88
- description: "friend to reach out to spontaneously (when not addressing a held thought)",
89
- },
90
- },
91
- required: ["content"],
92
- },
93
- },
94
- };
95
- // Surface tool handler: routes content to friend's freshest session
96
- /* v8 ignore start -- surface handler wiring: core logic tested via surface-tool.test.ts; this wires identity/routing deps @preserve */
97
- const surfaceToolDefinition = {
98
- tool: exports.surfaceToolDef,
99
- handler: async (args, ctx) => {
100
- const queue = ctx?.delegatedOrigins ?? [];
101
- const agentName = (() => { try {
102
- return (0, identity_1.getAgentName)();
103
- }
104
- catch {
105
- return "unknown";
106
- } })();
107
- const routeToFriend = async (friendId, content, queueItem) => {
108
- /* v8 ignore start -- routing: integration path tested via inner-dialog routing tests @preserve */
109
- try {
110
- const agentRoot = (0, identity_1.getAgentRoot)();
111
- const sessionsDir = path.join(agentRoot, "state", "sessions");
112
- const friendsDir = path.join(agentRoot, "friends");
113
- // Priority 1: Bridge-preferred session (if queue item has a bridgeId)
114
- if (queueItem?.bridgeId) {
115
- const { createBridgeManager } = await Promise.resolve().then(() => __importStar(require("../heart/bridges/manager")));
116
- const bridge = createBridgeManager().getBridge(queueItem.bridgeId);
117
- if (bridge && bridge.lifecycle !== "completed" && bridge.lifecycle !== "cancelled") {
118
- const allSessions = (0, session_activity_1.listSessionActivity)({ sessionsDir, friendsDir, agentName });
119
- const bridgeTarget = allSessions.find((activity) => activity.friendId === friendId
120
- && activity.channel !== "inner"
121
- && bridge.attachedSessions.some((s) => s.friendId === activity.friendId && s.channel === activity.channel && s.key === activity.key));
122
- if (bridgeTarget) {
123
- // Attempt proactive BB delivery for bridge target
124
- if (bridgeTarget.channel === "bluebubbles") {
125
- const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
126
- const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
127
- friendId: bridgeTarget.friendId,
128
- sessionKey: bridgeTarget.key,
129
- text: content,
130
- });
131
- if (proactiveResult.delivered) {
132
- // Inject surfaced content into the target session so it knows what was delivered
133
- const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
134
- const sessionFilePath = path.join(sessionsDir, bridgeTarget.friendId, bridgeTarget.channel, `${bridgeTarget.key}.json`);
135
- appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
136
- return { status: "delivered", detail: "via iMessage" };
137
- }
138
- }
139
- // Fall back to pending queue for bridge target
140
- const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
141
- const pendingDir = getPendingDir(agentName, bridgeTarget.friendId, bridgeTarget.channel, bridgeTarget.key);
142
- queuePendingMessage(pendingDir, {
143
- from: agentName,
144
- friendId: bridgeTarget.friendId,
145
- channel: bridgeTarget.channel,
146
- key: bridgeTarget.key,
147
- content,
148
- timestamp: Date.now(),
149
- });
150
- return { status: "queued", detail: `for next interaction via ${bridgeTarget.channel}` };
151
- }
152
- }
153
- }
154
- // Priority 2: Freshest active friend session
155
- const freshest = (0, session_activity_1.findFreshestFriendSession)({
156
- sessionsDir,
157
- friendsDir,
158
- agentName,
159
- friendId,
160
- activeOnly: true,
161
- });
162
- if (freshest && freshest.channel !== "inner") {
163
- // Attempt proactive BB delivery
164
- if (freshest.channel === "bluebubbles") {
165
- const { sendProactiveBlueBubblesMessageToSession } = await Promise.resolve().then(() => __importStar(require("../senses/bluebubbles")));
166
- const proactiveResult = await sendProactiveBlueBubblesMessageToSession({
167
- friendId: freshest.friendId,
168
- sessionKey: freshest.key,
169
- text: content,
170
- });
171
- if (proactiveResult.delivered) {
172
- // Inject surfaced content into the target session so it knows what was delivered
173
- const { appendSyntheticAssistantMessage } = await Promise.resolve().then(() => __importStar(require("../mind/context")));
174
- const sessionFilePath = path.join(sessionsDir, freshest.friendId, freshest.channel, `${freshest.key}.json`);
175
- appendSyntheticAssistantMessage(sessionFilePath, `[surfaced from inner dialog] ${content}`);
176
- return { status: "delivered", detail: "via iMessage" };
177
- }
178
- }
179
- // Queue as pending for next interaction
180
- const { queuePendingMessage, getPendingDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
181
- const pendingDir = getPendingDir(agentName, freshest.friendId, freshest.channel, freshest.key);
182
- queuePendingMessage(pendingDir, {
183
- from: agentName,
184
- friendId: freshest.friendId,
185
- channel: freshest.channel,
186
- key: freshest.key,
187
- content,
188
- timestamp: Date.now(),
189
- });
190
- return { status: "queued", detail: `for next interaction via ${freshest.channel}` };
191
- }
192
- // Priority 3: Deferred — no active session found
193
- const { getDeferredReturnDir } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
194
- const { queuePendingMessage: queueDeferred } = await Promise.resolve().then(() => __importStar(require("../mind/pending")));
195
- const deferredDir = getDeferredReturnDir(agentName, friendId);
196
- queueDeferred(deferredDir, {
197
- from: agentName,
198
- friendId,
199
- channel: "deferred",
200
- key: "return",
201
- content,
202
- timestamp: Date.now(),
203
- });
204
- return { status: "deferred", detail: "they'll see it next time" };
205
- }
206
- catch {
207
- return { status: "failed" };
208
- }
209
- /* v8 ignore stop */
210
- };
211
- return (0, surface_tool_1.handleSurface)({
212
- content: args.content ?? "",
213
- delegationId: args.delegationId,
214
- friendId: args.friendId,
215
- queue,
216
- routeToFriend,
217
- advanceObligation: (obligationId, update) => {
218
- /* v8 ignore start -- obligation advance: tested via attention-queue tests @preserve */
219
- try {
220
- const name = (() => { try {
221
- return (0, identity_1.getAgentName)();
222
- }
223
- catch {
224
- return "unknown";
225
- } })();
226
- (0, obligations_1.advanceReturnObligation)(name, obligationId, {
227
- status: update.status,
228
- ...(update.returnedAt !== undefined ? { returnedAt: update.returnedAt } : {}),
229
- ...(update.returnTarget !== undefined ? { returnTarget: update.returnTarget } : {}),
230
- });
231
- }
232
- catch {
233
- // swallowed — obligation advance must never break surface delivery
234
- }
235
- /* v8 ignore stop */
236
- },
237
- fulfillHeartObligation: (origin) => {
238
- /* v8 ignore start -- heart obligation fulfillment: tested via surface-tool.test.ts @preserve */
239
- try {
240
- const agentRoot = (0, identity_1.getAgentRoot)();
241
- const heartObligation = (0, obligations_1.findPendingObligationForOrigin)(agentRoot, origin);
242
- if (heartObligation) {
243
- (0, obligations_1.fulfillObligation)(agentRoot, heartObligation.id);
244
- }
245
- }
246
- catch {
247
- // swallowed — heart obligation fulfillment must never break surface delivery
248
- }
249
- /* v8 ignore stop */
250
- },
251
- });
252
- },
253
- summaryKeys: ["content", "delegationId"],
254
- };
255
- /* v8 ignore stop */
34
+ // Re-export surface tool schema for consumers (e.g. heart/core.ts)
35
+ var tools_surface_2 = require("./tools-surface");
36
+ Object.defineProperty(exports, "surfaceToolDef", { enumerable: true, get: function () { return tools_surface_2.surfaceToolDef; } });
256
37
  // All tool definitions in a single registry
257
- const allDefinitions = [...tools_base_1.baseToolDefinitions, ...tools_bluebubbles_1.bluebubblesToolDefinitions, ...tools_teams_1.teamsToolDefinitions, ...ado_semantic_1.adoSemanticToolDefinitions, ...tools_github_1.githubToolDefinitions, surfaceToolDefinition];
38
+ const allDefinitions = [...tools_base_1.baseToolDefinitions, ...tools_bluebubbles_1.bluebubblesToolDefinitions, ...tools_teams_1.teamsToolDefinitions, ...ado_semantic_1.adoSemanticToolDefinitions, ...tools_github_1.githubToolDefinitions, tools_surface_1.surfaceToolDefinition];
258
39
  function baseToolsForCapabilities() {
259
40
  // Use baseToolDefinitions at call time so dynamically-added tools are included
260
41
  return tools_base_1.baseToolDefinitions.map((d) => d.tool);
@@ -325,6 +106,12 @@ function isConfirmationRequired(toolName) {
325
106
  const def = allDefinitions.find((d) => d.tool.function.name === toolName);
326
107
  return def?.confirmationRequired === true;
327
108
  }
109
+ // Check whether a tool's confirmation is non-bypassable (cannot be skipped by skipConfirmation).
110
+ // Used for T2 config proposals that must always require operator approval.
111
+ function isConfirmationAlwaysRequired(toolName) {
112
+ const def = allDefinitions.find((d) => d.tool.function.name === toolName);
113
+ return def?.confirmationAlwaysRequired === true;
114
+ }
328
115
  function normalizeGuardArgs(_name, args) {
329
116
  return args;
330
117
  }
@@ -419,6 +206,7 @@ function summarizeArgs(name, args) {
419
206
  * Falls back to arg-based summary for unrecognized tools.
420
207
  */
421
208
  function buildToolResultSummary(name, args, _result, success) {
209
+ /* v8 ignore start -- branches: ?? fallbacks and ternaries in tool summary formatting @preserve */
422
210
  switch (name) {
423
211
  case "edit_file": {
424
212
  if (!success)
@@ -448,4 +236,5 @@ function buildToolResultSummary(name, args, _result, success) {
448
236
  default:
449
237
  return summarizeArgs(name, args);
450
238
  }
239
+ /* v8 ignore stop */
451
240
  }
@@ -390,6 +390,10 @@ async function handleInboundTurn(input) {
390
390
  if (syncFailure) {
391
391
  startOfTurnPacket.syncFailure = syncFailure;
392
392
  }
393
+ const capabilities = (0, start_of_turn_packet_1.buildCapabilitiesSection)(agentRoot);
394
+ if (capabilities) {
395
+ startOfTurnPacket.capabilities = capabilities;
396
+ }
393
397
  renderedStartOfTurnPacket = (0, start_of_turn_packet_1.renderStartOfTurnPacket)(startOfTurnPacket);
394
398
  if (!renderedStartOfTurnPacket)
395
399
  renderedStartOfTurnPacket = undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.205",
3
+ "version": "0.1.0-alpha.207",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",