@ouro.bot/cli 0.1.0-alpha.920 → 0.1.0-alpha.922
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 +13 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/daemon/sense-manager.js +6 -6
- package/dist/repertoire/tools-shepherd.js +27 -6
- package/dist/senses/shepherd/cmux.js +12 -4
- package/dist/senses/shepherd/owner-notice.js +13 -7
- package/dist/senses/shepherd/sense.js +1 -0
- package/dist/senses/shepherd/terminal-process.js +99 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
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.922",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Make Shepherd overview read fresh bounded screens for every terminal, separate historical returns, and report individual read failures."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.921",
|
|
12
|
+
"changes": [
|
|
13
|
+
"Make Teams chat tools share Shepherd’s machine attachment and identify cmux agents by foreground process, folder, workspace and tab title.",
|
|
14
|
+
"Initialize foreground process execution only when attached terminals need it, keeping unrelated prompt and daemon consumers free of lookup startup side effects."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
4
17
|
{
|
|
5
18
|
"version": "0.1.0-alpha.920",
|
|
6
19
|
"changes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0"?>
|
|
2
2
|
<Container version="2">
|
|
3
3
|
<Name>ouro-butler</Name>
|
|
4
|
-
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.
|
|
4
|
+
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.922</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -429,11 +429,11 @@ function managedSenseEntry(sense) {
|
|
|
429
429
|
return "senses/shepherd-entry.js";
|
|
430
430
|
return "senses/mail-entry.js";
|
|
431
431
|
}
|
|
432
|
-
function runtimeCredentialBootstrapFor(agent
|
|
432
|
+
function runtimeCredentialBootstrapFor(agent) {
|
|
433
433
|
const runtime = (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent);
|
|
434
|
-
|
|
435
|
-
const machineId =
|
|
436
|
-
const machine =
|
|
434
|
+
// Every sense can run chat-turn tools against this machine's attachments.
|
|
435
|
+
const machineId = currentMachineId();
|
|
436
|
+
const machine = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent);
|
|
437
437
|
const providerPool = (0, provider_credentials_1.readProviderCredentialPool)(agent);
|
|
438
438
|
const providerCredentialRecords = providerPool.ok
|
|
439
439
|
? Object.values(providerPool.pool.providers).filter((record) => !!record)
|
|
@@ -441,7 +441,7 @@ function runtimeCredentialBootstrapFor(agent, sense) {
|
|
|
441
441
|
const bootstrap = {
|
|
442
442
|
agentName: agent,
|
|
443
443
|
runtimeConfig: runtime.ok ? runtime.config : undefined,
|
|
444
|
-
machineRuntimeConfig: machine
|
|
444
|
+
machineRuntimeConfig: machine.ok ? machine.config : undefined,
|
|
445
445
|
machineId,
|
|
446
446
|
providerCredentialRecords: providerCredentialRecords.length > 0 ? providerCredentialRecords : undefined,
|
|
447
447
|
};
|
|
@@ -611,7 +611,7 @@ class DaemonSenseManager {
|
|
|
611
611
|
channel: sense,
|
|
612
612
|
autoStart: true,
|
|
613
613
|
...(sense === "a2a" ? { args: managedA2AArgs(agent), getArgs: () => managedA2AArgs(agent) } : {}),
|
|
614
|
-
getRuntimeCredentialBootstrap: () => runtimeCredentialBootstrapFor(agent
|
|
614
|
+
getRuntimeCredentialBootstrap: () => runtimeCredentialBootstrapFor(agent),
|
|
615
615
|
}));
|
|
616
616
|
});
|
|
617
617
|
this.processManager = options.processManager ?? new process_manager_1.DaemonProcessManager({
|
|
@@ -45,13 +45,16 @@ const redact_1 = require("../senses/shepherd/redact");
|
|
|
45
45
|
const returns_1 = require("../senses/shepherd/returns");
|
|
46
46
|
const tools_base_1 = require("./tools-base");
|
|
47
47
|
/**
|
|
48
|
-
* Shepherd's tools: every coding-agent session on this machine's terminal host with
|
|
49
|
-
* last decided about it (`shepherd_overview`),
|
|
48
|
+
* Shepherd's tools: every coding-agent session on this machine's terminal host with a current screen
|
|
49
|
+
* and what Shepherd last decided about it (`shepherd_overview`), a deeper read (`shepherd_read`), a status
|
|
50
50
|
* line or notification for the human (`shepherd_signal`), and a line or key typed for the human
|
|
51
51
|
* who asked for it (`shepherd_send`).
|
|
52
52
|
*/
|
|
53
53
|
const STATUS_MAX_CHARS = 120;
|
|
54
54
|
const READ_MAX_CHARS = 16_000;
|
|
55
|
+
const OVERVIEW_READ_LINES = 80;
|
|
56
|
+
const OVERVIEW_SCREEN_MAX_CHARS = 4_000;
|
|
57
|
+
const OVERVIEW_TOTAL_SCREEN_MAX_CHARS = 64_000;
|
|
55
58
|
exports.SEND_TEXT_MAX_CHARS = 2_000;
|
|
56
59
|
exports.SEND_KEYS = ["enter", "escape", "up", "down", "tab", "ctrl-c", "1", "2", "3", "4", "5", "6", "7", "8", "9", "y", "n"];
|
|
57
60
|
/** Keys that can approve or choose something on a prompt: pressed only on the screen the caller last read. */
|
|
@@ -91,12 +94,27 @@ async function withHost(tool, ctx, run) {
|
|
|
91
94
|
return JSON.stringify({ error: error.message });
|
|
92
95
|
}
|
|
93
96
|
}
|
|
97
|
+
async function currentScreen(host, session, maxChars) {
|
|
98
|
+
try {
|
|
99
|
+
const raw = await host.read(session, OVERVIEW_READ_LINES);
|
|
100
|
+
// Frame glyphs and padded empty rows otherwise crowd actual work out of a multi-terminal snapshot.
|
|
101
|
+
const content = (0, redact_1.redactSecrets)(raw).split("\n")
|
|
102
|
+
.map(line => line.replace(/[\u2500-\u259f]/g, "").trimEnd())
|
|
103
|
+
.filter(line => line.trim().length > 0).join("\n");
|
|
104
|
+
return { at: new Date().toISOString(), text: content.slice(Math.max(0, content.length - maxChars)), truncated: content.length > maxChars };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const message = (0, redact_1.redactSecrets)(error instanceof Error ? error.message : String(error));
|
|
108
|
+
(0, runtime_1.emitNervesEvent)({ level: "warn", component: "repertoire", event: "repertoire.shepherd_overview_read_error", message: "could not read one terminal in the live Shepherd overview", meta: { session, error: message } });
|
|
109
|
+
return { at: new Date().toISOString(), error: message };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
94
112
|
exports.shepherdOverviewToolDefinition = {
|
|
95
113
|
tool: {
|
|
96
114
|
type: "function",
|
|
97
115
|
function: {
|
|
98
116
|
name: "shepherd_overview",
|
|
99
|
-
description: "
|
|
117
|
+
description: "A live, read-only snapshot of every terminal on this machine's host (cmux): agent, folder, workspace and tab, plus a freshly read, redacted, bounded currentScreen with its observation time. Use currentScreen to answer what agents are doing now in one reply; lastReturn is historical and must not be presented as current status. A currentScreen.error explicitly identifies a terminal that could not be read; explain it inline with the other sessions, not by asking for another turn. For deeper details use shepherd_read. terminalCount is authoritative; derive any category counts from the actual listed sessions. Historical lastReturn includes the prior judgment time, kind, action and reason.",
|
|
100
118
|
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
101
119
|
},
|
|
102
120
|
},
|
|
@@ -104,12 +122,15 @@ exports.shepherdOverviewToolDefinition = {
|
|
|
104
122
|
const last = new Map();
|
|
105
123
|
for (const record of (0, returns_1.readReturns)(ctx.agentRoot))
|
|
106
124
|
last.set(record.session, record);
|
|
125
|
+
const sessions = await host.list();
|
|
126
|
+
const screenLimit = Math.min(OVERVIEW_SCREEN_MAX_CHARS, Math.floor(OVERVIEW_TOTAL_SCREEN_MAX_CHARS / Math.max(1, sessions.length)));
|
|
107
127
|
return {
|
|
108
128
|
host: host.name,
|
|
109
|
-
|
|
129
|
+
terminalCount: sessions.length,
|
|
130
|
+
sessions: await Promise.all(sessions.map(async (session) => {
|
|
110
131
|
const record = last.get(session.id);
|
|
111
|
-
return { ...session, ...(record ? { lastReturn: { at: record.at, kind: record.kind, action: record.action, reason: record.reason, reply: record.reply, task: record.task } } : {}) };
|
|
112
|
-
}),
|
|
132
|
+
return { ...session, currentScreen: await currentScreen(host, session.id, screenLimit), ...(record ? { lastReturn: { at: record.at, kind: record.kind, action: record.action, reason: record.reason, reply: record.reply, task: record.task } } : {}) };
|
|
133
|
+
})),
|
|
113
134
|
};
|
|
114
135
|
}),
|
|
115
136
|
summaryKeys: [],
|
|
@@ -42,6 +42,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
42
42
|
const os = __importStar(require("node:os"));
|
|
43
43
|
const path = __importStar(require("node:path"));
|
|
44
44
|
const runtime_1 = require("../../nerves/runtime");
|
|
45
|
+
const terminal_process_1 = require("./terminal-process");
|
|
45
46
|
/**
|
|
46
47
|
* The cmux host (0.64.22 or later). A return is cmux's own "agent stopped" signal: an
|
|
47
48
|
* `agent.hook.Stop` event, which cmux publishes for every agent its hooks cover (Claude Code,
|
|
@@ -128,17 +129,25 @@ function createCmuxHost(client, options = {}) {
|
|
|
128
129
|
};
|
|
129
130
|
async function surfaces() {
|
|
130
131
|
const tree = await client.call("system.tree", { all_windows: true });
|
|
131
|
-
|
|
132
|
+
const entries = list(tree.windows).flatMap((window) => list(window.workspaces).map((workspace) => ({ window, workspace }))).flatMap(({ window, workspace }) => list(workspace.panes).flatMap((pane) => list(pane.surfaces)).map((surface) => ({
|
|
132
133
|
id: str(surface.id) ?? "",
|
|
133
134
|
ref: str(surface.ref) ?? "",
|
|
134
135
|
workspace: str(workspace.ref),
|
|
136
|
+
workspaceTitle: str(workspace.title),
|
|
135
137
|
workspaceId: str(workspace.id) ?? "",
|
|
136
138
|
title: str(surface.title) ?? "",
|
|
139
|
+
tty: str(surface.tty),
|
|
137
140
|
type: str(surface.type) ?? "",
|
|
138
141
|
agent: hooked.get(str(surface.id) ?? "")?.agent ?? null,
|
|
142
|
+
cwd: hooked.get(str(surface.id) ?? "")?.cwd ?? null,
|
|
139
143
|
// The human's terminal: the focused surface of the selected workspace in a visible window.
|
|
140
144
|
focused: surface.focused === true && workspace.selected === true && window.visible !== false,
|
|
141
145
|
})));
|
|
146
|
+
const identities = await (options.identifyTerminals ?? terminal_process_1.identifyTerminalProcesses)(entries.filter((entry) => entry.type === "terminal" && entry.tty).map((entry) => entry.tty));
|
|
147
|
+
return entries.map((entry) => {
|
|
148
|
+
const identity = entry.tty ? identities.get(entry.tty) : undefined;
|
|
149
|
+
return { ...entry, agent: identity?.agent ?? entry.agent, cwd: identity?.cwd ?? entry.cwd };
|
|
150
|
+
});
|
|
142
151
|
}
|
|
143
152
|
async function locate(sessionId) {
|
|
144
153
|
const surface = (await surfaces()).find((entry) => entry.id === sessionId || entry.ref === sessionId);
|
|
@@ -153,7 +162,7 @@ function createCmuxHost(client, options = {}) {
|
|
|
153
162
|
return {
|
|
154
163
|
name: "cmux",
|
|
155
164
|
async list() {
|
|
156
|
-
return (await surfaces()).filter((surface) => surface.type === "terminal").map(({
|
|
165
|
+
return (await surfaces()).filter((surface) => surface.type === "terminal").map(({ workspaceId: _workspaceId, type: _type, ...session }) => session);
|
|
157
166
|
},
|
|
158
167
|
read,
|
|
159
168
|
async prompt(sessionId, line) {
|
|
@@ -316,8 +325,7 @@ function createCmuxHost(client, options = {}) {
|
|
|
316
325
|
}
|
|
317
326
|
else if (last.active && at - last.changedAt >= Math.max(quietMs.get(surface.id) ?? exports.QUIET_MS, hooked.has(surface.id) ? exports.HOOKED_QUIET_MS : 0)) {
|
|
318
327
|
last.active = false;
|
|
319
|
-
|
|
320
|
-
handlers.returned({ sessionId: surface.id, transitionId: `cmux:quiet:${surface.id}:${last.changedAt}`, agent: hook?.agent ?? null, cwd: hook?.cwd ?? null, lastBody: null, backgroundWork: null });
|
|
328
|
+
handlers.returned({ sessionId: surface.id, transitionId: `cmux:quiet:${surface.id}:${last.changedAt}`, agent: surface.agent, cwd: surface.cwd ?? null, title: surface.title, workspaceTitle: surface.workspaceTitle, lastBody: null, backgroundWork: null });
|
|
321
329
|
}
|
|
322
330
|
}
|
|
323
331
|
}
|
|
@@ -78,15 +78,21 @@ function plain(value, max) {
|
|
|
78
78
|
.trim();
|
|
79
79
|
return flat.length <= max ? flat : `${flat.slice(0, max - 1).trimEnd()}…`;
|
|
80
80
|
}
|
|
81
|
-
function who(record,
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
81
|
+
function who(record, location) {
|
|
82
|
+
const session = typeof location === "object" ? location : undefined;
|
|
83
|
+
const agentName = record.agent ?? session?.agent;
|
|
84
|
+
const cwd = record.cwd ?? session?.cwd;
|
|
85
|
+
const agent = agentName ? plain(agentName, NAME_MAX) : "";
|
|
86
|
+
const folder = cwd ? plain(path.basename(cwd), NAME_MAX) : "";
|
|
87
|
+
const ref = typeof location === "string" ? location : session?.ref;
|
|
88
|
+
const handle = plain(ref ?? record.session.slice(0, 8), NAME_MAX);
|
|
89
|
+
const labels = [record.workspaceTitle ?? session?.workspaceTitle, record.title ?? session?.title].filter((label) => !!label).map((label) => plain(label, NAME_MAX));
|
|
90
|
+
const where = labels.length ? `${labels.join(" / ")}; ${handle}` : handle;
|
|
85
91
|
return `${agent || "A coding agent"}${folder ? ` in ${folder}` : ""}${where ? ` (${where})` : ""}`;
|
|
86
92
|
}
|
|
87
93
|
/** One return as one sentence pair: who returned, what Shepherd did, and why. */
|
|
88
|
-
function noticeLine(record,
|
|
89
|
-
const subject = who(record,
|
|
94
|
+
function noticeLine(record, location) {
|
|
95
|
+
const subject = who(record, location);
|
|
90
96
|
const why = `Why: ${plain(record.reason, REASON_MAX) || "no reason given"}`;
|
|
91
97
|
switch (record.kind) {
|
|
92
98
|
case "premature":
|
|
@@ -198,7 +204,7 @@ function createOwnerNotifier(options) {
|
|
|
198
204
|
const refs = new Map();
|
|
199
205
|
try {
|
|
200
206
|
for (const session of await options.listSessions())
|
|
201
|
-
refs.set(session.id, session
|
|
207
|
+
refs.set(session.id, session);
|
|
202
208
|
}
|
|
203
209
|
catch {
|
|
204
210
|
// Without the host's handles, each notice names a short session id instead.
|
|
@@ -204,6 +204,7 @@ async function startShepherdSenseApp(options) {
|
|
|
204
204
|
const record = {
|
|
205
205
|
at: new Date(now()).toISOString(), host: host.name, session: event.sessionId, transition: event.transitionId,
|
|
206
206
|
agent: event.agent, cwd: event.cwd, task: null, kind: "unclear", action: "let_through", reason: "", reply: null, latencyMs: null, inputTokens: null,
|
|
207
|
+
...(event.title !== undefined ? { title: event.title, workspaceTitle: event.workspaceTitle } : {}),
|
|
207
208
|
};
|
|
208
209
|
const state = guardFor(event.sessionId);
|
|
209
210
|
/** False for a return nothing new was decided about: the loop guard still holds, or the same background wait. */
|
|
@@ -0,0 +1,99 @@
|
|
|
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.identifyTerminalProcesses = identifyTerminalProcesses;
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const node_util_1 = require("node:util");
|
|
39
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
40
|
+
async function runCommand(command, args) {
|
|
41
|
+
const { execFile } = await Promise.resolve().then(() => __importStar(require("node:child_process")));
|
|
42
|
+
const exec = (0, node_util_1.promisify)(execFile);
|
|
43
|
+
const { stdout } = await exec(command, args, { timeout: 3_000, maxBuffer: 4 * 1024 * 1024 });
|
|
44
|
+
return stdout;
|
|
45
|
+
}
|
|
46
|
+
/** One process snapshot and one cwd lookup for all terminals, not a subprocess per polling surface. */
|
|
47
|
+
async function identifyTerminalProcesses(ttys, run = runCommand) {
|
|
48
|
+
const result = new Map();
|
|
49
|
+
if (ttys.length === 0)
|
|
50
|
+
return result;
|
|
51
|
+
const wanted = new Set(ttys.map((tty) => tty.replace(/^\/dev\//, "")));
|
|
52
|
+
const agents = new Map();
|
|
53
|
+
try {
|
|
54
|
+
for (const line of (await run("ps", ["-axo", "pid=,ppid=,pgid=,tpgid=,tty=,comm="])).split("\n")) {
|
|
55
|
+
const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\d+)\s+(-?\d+)\s+(\S+)\s+(.+)$/);
|
|
56
|
+
if (!match)
|
|
57
|
+
continue;
|
|
58
|
+
const [, pid, parent, group, foreground, tty, command] = match;
|
|
59
|
+
if (!wanted.has(tty) || group !== foreground)
|
|
60
|
+
continue;
|
|
61
|
+
const executable = path.basename(command);
|
|
62
|
+
const agent = executable === "claude" ? "Claude Code" : executable === "copilot" ? "Copilot" : executable === "codex" ? "Codex" : null;
|
|
63
|
+
if (!agent)
|
|
64
|
+
continue;
|
|
65
|
+
const candidates = agents.get(tty) ?? [];
|
|
66
|
+
candidates.push({ pid: Number(pid), parent: Number(parent), agent });
|
|
67
|
+
agents.set(tty, candidates);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
(0, runtime_1.emitNervesEvent)({ level: "warn", component: "senses", event: "senses.shepherd_process_lookup_error", message: "could not identify terminal foreground agents", meta: { error: String(error) } });
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
const selected = new Map();
|
|
75
|
+
for (const [tty, candidates] of agents) {
|
|
76
|
+
const outer = candidates.find((candidate) => !candidates.some((parent) => parent.pid === candidate.parent));
|
|
77
|
+
selected.set(tty, outer);
|
|
78
|
+
result.set(tty, { agent: outer.agent, cwd: null });
|
|
79
|
+
}
|
|
80
|
+
if (selected.size === 0)
|
|
81
|
+
return result;
|
|
82
|
+
try {
|
|
83
|
+
const cwdByPid = new Map();
|
|
84
|
+
let pid = 0;
|
|
85
|
+
const output = await run("lsof", ["-a", "-p", [...selected.values()].map((agent) => agent.pid).join(","), "-d", "cwd", "-Fn"]);
|
|
86
|
+
for (const line of output.split("\n")) {
|
|
87
|
+
if (line.startsWith("p"))
|
|
88
|
+
pid = Number(line.slice(1));
|
|
89
|
+
else if (line.startsWith("n") && pid)
|
|
90
|
+
cwdByPid.set(pid, line.slice(1));
|
|
91
|
+
}
|
|
92
|
+
for (const [tty, agent] of selected)
|
|
93
|
+
result.set(tty, { agent: agent.agent, cwd: cwdByPid.get(agent.pid) ?? null });
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
(0, runtime_1.emitNervesEvent)({ level: "warn", component: "senses", event: "senses.shepherd_cwd_lookup_error", message: "could not read foreground agent folders", meta: { error: String(error) } });
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.922",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.922",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|