@ouro.bot/cli 0.1.0-alpha.891 → 0.1.0-alpha.893
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 +12 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/cmux-config.js +102 -0
- package/dist/heart/daemon/runtime-logging.js +1 -1
- package/dist/heart/daemon/sense-manager.js +23 -6
- package/dist/heart/identity.js +4 -1
- package/dist/heart/private-runtime/policy.js +8 -0
- package/dist/heart/sense-truth.js +2 -0
- package/dist/heart/turn-context.js +7 -0
- package/dist/mind/prompt.js +7 -0
- package/dist/repertoire/guardrails.js +6 -0
- package/dist/repertoire/tools-cmux.js +277 -0
- package/dist/repertoire/tools.js +4 -1
- package/dist/senses/cmux/attention.js +263 -0
- package/dist/senses/cmux/client.js +196 -0
- package/dist/senses/cmux/redact.js +37 -0
- package/dist/senses/cmux/sense.js +248 -0
- package/dist/senses/cmux-entry.js +77 -0
- package/dist/senses/voice/local-audio-devices.js +52 -7
- package/dist/senses/voice/local-audio-transport.js +22 -1
- package/dist/senses/voice/twilio-phone.js +17 -4
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
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.893",
|
|
6
|
+
"changes": [
|
|
7
|
+
"New cmux sense: an agent with senses.cmux.enabled watches the coding agents running in cmux on this Mac. It follows cmux's event stream, keeps what each terminal's agent last did, and brings each permission request, question or plan approval that cmux is holding for the human to the agent once, the way the mail sense does: a pending message in the agent's private runtime plus a private-turn wake that the daemon's policy now allows for the cmux sense (never including the request's tool input; every Feed field is flattened to one line, capped and marked untrusted, and a burst of requests costs one wake). This works for an agent with no tool-profiles.json. Three family-only tools: cmux_overview (who needs the human and what each session did), cmux_read (a terminal's text, redacted and bounded) and cmux_signal (a one-line workspace status or a desktop notification). The socket credential is a cmux capability token stored per machine with 'ouro vault config set --scope machine --key cmux.socketCapability'. After a gap in cmux's event stream or a cmux restart it starts its picture of the terminals afresh; a request that cannot be queued is retried on the next check while the others carry on; a failed state write no longer stops the Feed checks; it records the cmux version it is attached to (a prerelease such as 0.65.0-beta counts as older than 0.65.0); and the cmux tools are denied whenever the caller's trust level is unknown. See docs/cmux-sense.md."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.892",
|
|
12
|
+
"changes": [
|
|
13
|
+
"Local audio joins play the agent's voice through ffmpeg instead of sox, because sox's CoreAudio output can deadlock and stay silent when the process runs at lowered priority. An outbound call is treated as the job's friend only when the dialed number is on that friend's record. Phone greetings now name the agent: they had introduced themselves as ChatGPT in half of the live test calls."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.891",
|
|
6
18
|
"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.893</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -0,0 +1,102 @@
|
|
|
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.cmuxRepairHint = cmuxRepairHint;
|
|
37
|
+
exports.cmuxConfigFacts = cmuxConfigFacts;
|
|
38
|
+
exports.cmuxSenseStatus = cmuxSenseStatus;
|
|
39
|
+
exports.defaultCmuxSocketPath = defaultCmuxSocketPath;
|
|
40
|
+
exports.resolveCmuxConnection = resolveCmuxConnection;
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const os = __importStar(require("node:os"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const runtime_1 = require("../nerves/runtime");
|
|
45
|
+
function cmuxRepairHint(agent) {
|
|
46
|
+
return `human-required: in a cmux terminal run 'ouro vault config set --agent ${agent} --scope machine --key cmux.socketCapability --value "$CMUX_SOCKET_CAPABILITY"' (or set cmux.socketPassword when cmux is in password mode), then 'ouro up'.`;
|
|
47
|
+
}
|
|
48
|
+
function text(record, key) {
|
|
49
|
+
const value = record?.[key];
|
|
50
|
+
return typeof value === "string" ? value.trim() : "";
|
|
51
|
+
}
|
|
52
|
+
function cmuxRecord(machinePayload) {
|
|
53
|
+
const value = machinePayload.cmux;
|
|
54
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
55
|
+
}
|
|
56
|
+
function authFrom(cmux) {
|
|
57
|
+
const token = text(cmux, "socketCapability");
|
|
58
|
+
if (token)
|
|
59
|
+
return { kind: "capability", token };
|
|
60
|
+
const password = text(cmux, "socketPassword");
|
|
61
|
+
if (password)
|
|
62
|
+
return { kind: "password", password };
|
|
63
|
+
if (text(cmux, "socketMode") === "automation")
|
|
64
|
+
return { kind: "none" };
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function cmuxConfigFacts(machinePayload) {
|
|
68
|
+
const cmux = cmuxRecord(machinePayload);
|
|
69
|
+
const auth = authFrom(cmux);
|
|
70
|
+
if (!auth)
|
|
71
|
+
return cmux ? { configured: false, detail: "missing cmux.socketCapability" } : { configured: false, optional: true, detail: "not attached on this machine" };
|
|
72
|
+
return { configured: true, detail: `socket auth: ${auth.kind === "none" ? "automation mode" : auth.kind}` };
|
|
73
|
+
}
|
|
74
|
+
/** The one-word status the prompt and turn context show for the cmux sense, matching the daemon's sense rows. */
|
|
75
|
+
function cmuxSenseStatus(enabled, machinePayload) {
|
|
76
|
+
if (!enabled)
|
|
77
|
+
return "disabled";
|
|
78
|
+
const facts = cmuxConfigFacts(machinePayload);
|
|
79
|
+
if (facts.configured)
|
|
80
|
+
return "ready";
|
|
81
|
+
return facts.optional ? "not_attached" : "needs_config";
|
|
82
|
+
}
|
|
83
|
+
/** cmux's own default: `~/.local/state/cmux/cmux-<uid>.sock`, then the older unscoped `cmux.sock`. */
|
|
84
|
+
function defaultCmuxSocketPath(homeDir = os.homedir(), uid = process.getuid?.() ?? 0, exists = fs.existsSync) {
|
|
85
|
+
const dir = path.join(homeDir, ".local", "state", "cmux");
|
|
86
|
+
const scoped = path.join(dir, `cmux-${uid}.sock`);
|
|
87
|
+
const unscoped = path.join(dir, "cmux.sock");
|
|
88
|
+
return !exists(scoped) && exists(unscoped) ? unscoped : scoped;
|
|
89
|
+
}
|
|
90
|
+
function resolveCmuxConnection(agent, machinePayload, defaultSocketPath = defaultCmuxSocketPath) {
|
|
91
|
+
const cmux = cmuxRecord(machinePayload);
|
|
92
|
+
const auth = authFrom(cmux);
|
|
93
|
+
(0, runtime_1.emitNervesEvent)({
|
|
94
|
+
component: "senses",
|
|
95
|
+
event: "senses.cmux_connection_resolved",
|
|
96
|
+
message: "resolved cmux socket connection settings",
|
|
97
|
+
meta: { agent, auth: auth?.kind ?? "missing" },
|
|
98
|
+
});
|
|
99
|
+
if (!auth)
|
|
100
|
+
return { ok: false, error: `cmux socket auth is not configured on this machine; ${cmuxRepairHint(agent)}` };
|
|
101
|
+
return { ok: true, connection: { socketPath: text(cmux, "socketPath") || defaultSocketPath(), auth } };
|
|
102
|
+
}
|
|
@@ -58,7 +58,7 @@ function defaultLoggingForProcess(processName) {
|
|
|
58
58
|
sinks: ["terminal", "ndjson"],
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
if (processName === "bluebubbles" || processName === "mail" || processName === "voice" || processName === "a2a") {
|
|
61
|
+
if (processName === "bluebubbles" || processName === "mail" || processName === "voice" || processName === "a2a" || processName === "cmux") {
|
|
62
62
|
return {
|
|
63
63
|
level: "warn",
|
|
64
64
|
sinks: ["terminal", "ndjson"],
|
|
@@ -43,6 +43,7 @@ const runtime_credentials_1 = require("../runtime-credentials");
|
|
|
43
43
|
const provider_credentials_1 = require("../provider-credentials");
|
|
44
44
|
const sense_truth_1 = require("../sense-truth");
|
|
45
45
|
const machine_identity_1 = require("../machine-identity");
|
|
46
|
+
const cmux_config_1 = require("../cmux-config");
|
|
46
47
|
const process_manager_1 = require("./process-manager");
|
|
47
48
|
const config_1 = require("../../a2a/config");
|
|
48
49
|
const DEFAULT_TEAMS_PORT = 3978;
|
|
@@ -62,6 +63,7 @@ function defaultSenses() {
|
|
|
62
63
|
a2a: { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
|
|
63
64
|
telegram: { ...identity_1.DEFAULT_AGENT_SENSES.telegram },
|
|
64
65
|
workbench: { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
|
|
66
|
+
cmux: { ...identity_1.DEFAULT_AGENT_SENSES.cmux },
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
69
|
function readAgentSenses(agentJsonPath) {
|
|
@@ -101,7 +103,7 @@ function readAgentSenses(agentJsonPath) {
|
|
|
101
103
|
&& !Array.isArray(rawMcpServers)
|
|
102
104
|
&& Object.prototype.hasOwnProperty.call(rawMcpServers, "ouro_workbench");
|
|
103
105
|
const workbenchHasStaleBundleEntry = workbenchSensePresent || workbenchMcpPresent;
|
|
104
|
-
for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench"]) {
|
|
106
|
+
for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "cmux"]) {
|
|
105
107
|
const rawSense = rawSenses[sense];
|
|
106
108
|
if (!rawSense || typeof rawSense !== "object" || Array.isArray(rawSense)) {
|
|
107
109
|
continue;
|
|
@@ -162,7 +164,7 @@ function runtimeConfigUnavailableDetail(agent, runtimeConfig) {
|
|
|
162
164
|
return `vault ${itemName} unavailable (${compactRuntimeConfigError(agent, runtimeConfig.error)})`;
|
|
163
165
|
}
|
|
164
166
|
function needsMachineRuntimeConfig(agent, sense) {
|
|
165
|
-
return sense === "bluebubbles" || sense === "voice" || sense === "a2a" || (agent === "sanctuary" && sense === "telegram");
|
|
167
|
+
return sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "cmux" || (agent === "sanctuary" && sense === "telegram");
|
|
166
168
|
}
|
|
167
169
|
function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntimeConfig = (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent), workbenchHasStaleBundleEntry = false) {
|
|
168
170
|
const base = {
|
|
@@ -174,6 +176,7 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
|
|
|
174
176
|
a2a: { configured: false, detail: "not enabled in agent.json" },
|
|
175
177
|
telegram: { configured: false, detail: "not enabled in agent.json" },
|
|
176
178
|
workbench: { configured: false, detail: "not enabled in agent.json" },
|
|
179
|
+
cmux: { configured: false, detail: "not enabled in agent.json" },
|
|
177
180
|
};
|
|
178
181
|
const payload = runtimeConfig.ok ? runtimeConfig.config : {};
|
|
179
182
|
const unavailableDetail = runtimeConfigUnavailableDetail(agent, runtimeConfig);
|
|
@@ -342,6 +345,11 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
|
|
|
342
345
|
detail: publicUrl ? `${publicUrl}${endpointPath}` : `:${port} ${endpointPath}`,
|
|
343
346
|
};
|
|
344
347
|
}
|
|
348
|
+
if (senses.cmux.enabled) {
|
|
349
|
+
base.cmux = !machineRuntimeConfig.ok && machineRuntimeConfig.reason !== "missing"
|
|
350
|
+
? { configured: false, detail: runtimeConfigUnavailableDetail(agent, machineRuntimeConfig) }
|
|
351
|
+
: (0, cmux_config_1.cmuxConfigFacts)(machinePayload);
|
|
352
|
+
}
|
|
345
353
|
if (workbenchHasStaleBundleEntry || senses.workbench.enabled) {
|
|
346
354
|
base.workbench = {
|
|
347
355
|
configured: false,
|
|
@@ -369,6 +377,8 @@ function senseRepairHint(agent, sense) {
|
|
|
369
377
|
? "Agent-runnable: complete or recover the root authority migration; do not restore a resident Telegram token."
|
|
370
378
|
: `Agent-runnable: store Telegram bot/user/chat coordinates with 'ouro connect telegram --agent ${agent}', then restart with 'ouro up'.`;
|
|
371
379
|
}
|
|
380
|
+
if (sense === "cmux")
|
|
381
|
+
return (0, cmux_config_1.cmuxRepairHint)(agent);
|
|
372
382
|
/* v8 ignore next -- Workbench is deliberately not daemon-managed, so getSenseInventory never asks the daemon manager for a repair hint @preserve */
|
|
373
383
|
if (sense === "workbench") {
|
|
374
384
|
return `Agent-runnable: install Ouro Workbench.app, then launch the boss through Workbench or run 'ouro acp-serve --agent ${agent} --workbench-mcp'; 'ouro connect workbench --agent ${agent}' only cleans stale bundle entries.`;
|
|
@@ -383,7 +393,7 @@ function parseSenseSnapshotName(name) {
|
|
|
383
393
|
if (parts.length !== 2)
|
|
384
394
|
return null;
|
|
385
395
|
const [agent, sense] = parts;
|
|
386
|
-
if (sense !== "teams" && sense !== "bluebubbles" && sense !== "mail" && sense !== "voice" && sense !== "a2a" && sense !== "telegram")
|
|
396
|
+
if (sense !== "teams" && sense !== "bluebubbles" && sense !== "mail" && sense !== "voice" && sense !== "a2a" && sense !== "telegram" && sense !== "cmux")
|
|
387
397
|
return null;
|
|
388
398
|
return { agent, sense };
|
|
389
399
|
}
|
|
@@ -403,11 +413,13 @@ function managedSenseEntry(sense) {
|
|
|
403
413
|
return "senses/a2a-entry.js";
|
|
404
414
|
if (sense === "telegram")
|
|
405
415
|
return "senses/telegram-entry.js";
|
|
416
|
+
if (sense === "cmux")
|
|
417
|
+
return "senses/cmux-entry.js";
|
|
406
418
|
return "senses/mail-entry.js";
|
|
407
419
|
}
|
|
408
420
|
function runtimeCredentialBootstrapFor(agent, sense) {
|
|
409
421
|
const runtime = (0, runtime_credentials_1.readRuntimeCredentialConfig)(agent);
|
|
410
|
-
const usesMachineConfig = sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "telegram";
|
|
422
|
+
const usesMachineConfig = sense === "bluebubbles" || sense === "voice" || sense === "a2a" || sense === "telegram" || sense === "cmux";
|
|
411
423
|
const machineId = usesMachineConfig ? currentMachineId() : undefined;
|
|
412
424
|
const machine = usesMachineConfig ? (0, runtime_credentials_1.readMachineRuntimeCredentialConfig)(agent) : null;
|
|
413
425
|
const providerPool = (0, provider_credentials_1.readProviderCredentialPool)(agent);
|
|
@@ -578,7 +590,7 @@ class DaemonSenseManager {
|
|
|
578
590
|
return [agent, { senses, workbenchHasStaleBundleEntry, facts }];
|
|
579
591
|
}));
|
|
580
592
|
const managedSenseAgents = [...this.contexts.entries()].flatMap(([agent, context]) => {
|
|
581
|
-
return ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram"]
|
|
593
|
+
return ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "cmux"]
|
|
582
594
|
.filter((sense) => context.senses[sense].enabled)
|
|
583
595
|
.map((sense) => ({
|
|
584
596
|
name: `${agent}:${sense}`,
|
|
@@ -730,7 +742,7 @@ class DaemonSenseManager {
|
|
|
730
742
|
}
|
|
731
743
|
async refreshEnabledSenseConfigs() {
|
|
732
744
|
const refreshes = [...this.contexts.entries()].map(async ([agent, context]) => {
|
|
733
|
-
const enabledManagedSenses = ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram"]
|
|
745
|
+
const enabledManagedSenses = ["teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "cmux"]
|
|
734
746
|
.filter((sense) => context.senses[sense].enabled);
|
|
735
747
|
/* v8 ignore next -- periodic refresh work only exists when a managed background sense is enabled @preserve */
|
|
736
748
|
if (enabledManagedSenses.length === 0)
|
|
@@ -904,6 +916,11 @@ class DaemonSenseManager {
|
|
|
904
916
|
workbench: {
|
|
905
917
|
configured: context.facts.workbench.configured,
|
|
906
918
|
},
|
|
919
|
+
cmux: {
|
|
920
|
+
configured: context.facts.cmux.configured,
|
|
921
|
+
optional: context.facts.cmux.optional,
|
|
922
|
+
...(runtime.get(agent)?.cmux ?? {}),
|
|
923
|
+
},
|
|
907
924
|
};
|
|
908
925
|
const inventory = (0, sense_truth_1.getSenseInventory)({ senses: context.senses }, runtimeInfo);
|
|
909
926
|
return inventory.map((entry) => ({
|
package/dist/heart/identity.js
CHANGED
|
@@ -145,6 +145,7 @@ exports.DEFAULT_AGENT_SENSES = {
|
|
|
145
145
|
a2a: { enabled: false },
|
|
146
146
|
telegram: { enabled: false },
|
|
147
147
|
workbench: { enabled: false },
|
|
148
|
+
cmux: { enabled: false },
|
|
148
149
|
};
|
|
149
150
|
function normalizeSenses(value, configFile) {
|
|
150
151
|
const defaults = {
|
|
@@ -156,6 +157,7 @@ function normalizeSenses(value, configFile) {
|
|
|
156
157
|
a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
|
|
157
158
|
telegram: { ...exports.DEFAULT_AGENT_SENSES.telegram },
|
|
158
159
|
workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
|
|
160
|
+
cmux: { ...exports.DEFAULT_AGENT_SENSES.cmux },
|
|
159
161
|
};
|
|
160
162
|
if (value === undefined) {
|
|
161
163
|
return defaults;
|
|
@@ -171,7 +173,7 @@ function normalizeSenses(value, configFile) {
|
|
|
171
173
|
throw new Error(`agent.json at ${configFile} must include senses as an object when present.`);
|
|
172
174
|
}
|
|
173
175
|
const raw = value;
|
|
174
|
-
const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench"];
|
|
176
|
+
const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "telegram", "workbench", "cmux"];
|
|
175
177
|
for (const senseName of senseNames) {
|
|
176
178
|
const rawSense = raw[senseName];
|
|
177
179
|
if (rawSense === undefined) {
|
|
@@ -219,6 +221,7 @@ function buildDefaultAgentTemplate(_agentName) {
|
|
|
219
221
|
a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
|
|
220
222
|
telegram: { ...exports.DEFAULT_AGENT_SENSES.telegram },
|
|
221
223
|
workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
|
|
224
|
+
cmux: { ...exports.DEFAULT_AGENT_SENSES.cmux },
|
|
222
225
|
},
|
|
223
226
|
phrases: {
|
|
224
227
|
thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
|
|
@@ -150,6 +150,14 @@ async function evaluatePolicy(request, context, deps) {
|
|
|
150
150
|
reason: "verified daemon external event",
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
|
+
if (request.triggerSource === "cmux-feed"
|
|
154
|
+
&& hasNonEmptyOriginRef(originRefs, "cmux-feed")
|
|
155
|
+
&& hasOriginRef(originRefs, "sense", "cmux")) {
|
|
156
|
+
return {
|
|
157
|
+
result: "allow",
|
|
158
|
+
reason: "cmux sense escalation",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
153
161
|
if (request.triggerSource === "operator-cli"
|
|
154
162
|
&& hasOriginRef(originRefs, "cli-command", "ouro msg")
|
|
155
163
|
&& hasNonEmptyOriginRef(originRefs, "daemon-receipt")) {
|
|
@@ -12,6 +12,7 @@ const SENSES = [
|
|
|
12
12
|
{ sense: "a2a", label: "A2A", daemonManaged: true },
|
|
13
13
|
{ sense: "telegram", label: "Telegram", daemonManaged: true },
|
|
14
14
|
{ sense: "workbench", label: "Workbench", daemonManaged: false },
|
|
15
|
+
{ sense: "cmux", label: "cmux", daemonManaged: true },
|
|
15
16
|
];
|
|
16
17
|
function configuredSenses(senses) {
|
|
17
18
|
const configured = senses ?? {};
|
|
@@ -25,6 +26,7 @@ function configuredSenses(senses) {
|
|
|
25
26
|
a2a: configured.a2a ?? { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
|
|
26
27
|
telegram: configured.telegram ?? { ...identity_1.DEFAULT_AGENT_SENSES.telegram },
|
|
27
28
|
workbench: configured.workbench ?? { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
|
|
29
|
+
cmux: configured.cmux ?? { ...identity_1.DEFAULT_AGENT_SENSES.cmux },
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
32
|
function resolveStatus(enabled, daemonManaged, runtimeInfo) {
|
|
@@ -63,6 +63,7 @@ const provider_visibility_1 = require("./provider-visibility");
|
|
|
63
63
|
const mail_import_discovery_1 = require("./mail-import-discovery");
|
|
64
64
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
65
65
|
const context_loss_sentinel_1 = require("./context-loss-sentinel");
|
|
66
|
+
const cmux_config_1 = require("./cmux-config");
|
|
66
67
|
// ── Helpers ─────────────────────────────────────────────────────────
|
|
67
68
|
const DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
|
|
68
69
|
function isLiveCodingSessionStatus(status) {
|
|
@@ -167,6 +168,7 @@ function readSenseStatusLines() {
|
|
|
167
168
|
a2a: configuredSenses.a2a ?? { enabled: false },
|
|
168
169
|
telegram: configuredSenses.telegram ?? { enabled: false },
|
|
169
170
|
workbench: configuredSenses.workbench ?? { enabled: false },
|
|
171
|
+
cmux: configuredSenses.cmux ?? { enabled: false },
|
|
170
172
|
};
|
|
171
173
|
const payload = (0, config_1.loadConfig)();
|
|
172
174
|
const agentName = (0, identity_1.getAgentName)();
|
|
@@ -221,6 +223,7 @@ function readSenseStatusLines() {
|
|
|
221
223
|
&& hasTextField(runtimePayload, "telegramAuthorizedUserId")
|
|
222
224
|
&& hasTextField(runtimePayload, "telegramAuthorizedChatId"),
|
|
223
225
|
workbench: false,
|
|
226
|
+
cmux: (0, cmux_config_1.cmuxSenseStatus)(true, machinePayload) === "ready",
|
|
224
227
|
};
|
|
225
228
|
const rows = [
|
|
226
229
|
{ label: "CLI", status: "interactive" },
|
|
@@ -248,6 +251,10 @@ function readSenseStatusLines() {
|
|
|
248
251
|
label: "Telegram",
|
|
249
252
|
status: !senses.telegram.enabled ? "disabled" : configured.telegram ? "ready" : "needs_config",
|
|
250
253
|
},
|
|
254
|
+
{
|
|
255
|
+
label: "cmux",
|
|
256
|
+
status: (0, cmux_config_1.cmuxSenseStatus)(senses.cmux.enabled, machinePayload),
|
|
257
|
+
},
|
|
251
258
|
{
|
|
252
259
|
label: "Workbench",
|
|
253
260
|
// Workbench can be injected at runtime (the Workbench app spawns
|
package/dist/mind/prompt.js
CHANGED
|
@@ -86,6 +86,7 @@ const daemon_health_1 = require("../heart/daemon/daemon-health");
|
|
|
86
86
|
const scrutiny_1 = require("./scrutiny");
|
|
87
87
|
const pulse_1 = require("../heart/daemon/pulse");
|
|
88
88
|
const provider_visibility_1 = require("../heart/provider-visibility");
|
|
89
|
+
const cmux_config_1 = require("../heart/cmux-config");
|
|
89
90
|
const store_1 = require("../trips/store");
|
|
90
91
|
const orientation_frame_1 = require("../heart/orientation-frame");
|
|
91
92
|
const flight_recorder_1 = require("../arc/flight-recorder");
|
|
@@ -478,6 +479,7 @@ function localSenseStatusLines() {
|
|
|
478
479
|
a2a: configuredSenses.a2a ?? { enabled: false },
|
|
479
480
|
telegram: configuredSenses.telegram ?? { enabled: false },
|
|
480
481
|
workbench: configuredSenses.workbench ?? { enabled: false },
|
|
482
|
+
cmux: configuredSenses.cmux ?? { enabled: false },
|
|
481
483
|
};
|
|
482
484
|
const payload = (0, config_1.loadConfig)();
|
|
483
485
|
const runtimeConfig = (0, runtime_credentials_1.readRuntimeCredentialConfig)((0, identity_1.getAgentName)());
|
|
@@ -506,6 +508,7 @@ function localSenseStatusLines() {
|
|
|
506
508
|
&& hasTextField(runtimePayload, "telegramAuthorizedUserId")
|
|
507
509
|
&& hasTextField(runtimePayload, "telegramAuthorizedChatId"),
|
|
508
510
|
workbench: false,
|
|
511
|
+
cmux: (0, cmux_config_1.cmuxSenseStatus)(true, machinePayload) === "ready",
|
|
509
512
|
};
|
|
510
513
|
const rows = [
|
|
511
514
|
{ label: "CLI", status: "interactive" },
|
|
@@ -533,6 +536,10 @@ function localSenseStatusLines() {
|
|
|
533
536
|
label: "Telegram",
|
|
534
537
|
status: !senses.telegram.enabled ? "disabled" : configured.telegram ? "ready" : "needs_config",
|
|
535
538
|
},
|
|
539
|
+
{
|
|
540
|
+
label: "cmux",
|
|
541
|
+
status: (0, cmux_config_1.cmuxSenseStatus)(senses.cmux.enabled, machinePayload),
|
|
542
|
+
},
|
|
536
543
|
{
|
|
537
544
|
label: "Workbench",
|
|
538
545
|
// Workbench can be injected at runtime (the Workbench app spawns
|
|
@@ -441,6 +441,9 @@ const TRAVEL_TRUSTED_TOOLS = new Set(["weather_lookup", "travel_advisory", "geoc
|
|
|
441
441
|
const A2A_TRUSTED_TOOLS = new Set(["a2a_list_peers", "a2a_send_message", "a2a_get_task"]);
|
|
442
442
|
const COMMERCE_FAMILY_TOOLS = new Set(["commerce_checkout_preview", "commerce_checkout_commit", "commerce_receipt_get", "commerce_access_log"]);
|
|
443
443
|
const COMMERCE_AUTHORITY_TOOLS = new Set(["stripe_create_card", "flight_hold", "flight_book"]);
|
|
444
|
+
// The cmux tools read the owner's terminals and speak to them through their desktop, so only family may use them.
|
|
445
|
+
// A call with no known trust level fails closed.
|
|
446
|
+
const CMUX_FAMILY_TOOLS = new Set(["cmux_overview", "cmux_read", "cmux_signal"]);
|
|
444
447
|
const MAIL_FAMILY_TOOLS = new Set(["mail_screener", "mail_decide", "mail_access_log", "mail_send", "mail_index_refresh"]);
|
|
445
448
|
const MAIL_DELEGATED_READ_TOOLS = new Set(["mail_recent", "mail_search"]);
|
|
446
449
|
function opaqueAnsiShellAtoms(command) {
|
|
@@ -1181,6 +1184,9 @@ function checkTrustLevelGuardrails(toolName, args, context) {
|
|
|
1181
1184
|
const mailResult = mailTrustGuardrail(toolName, args, context);
|
|
1182
1185
|
if (!mailResult.allowed)
|
|
1183
1186
|
return mailResult;
|
|
1187
|
+
if (CMUX_FAMILY_TOOLS.has(toolName) && context.trustLevel !== "family") {
|
|
1188
|
+
return deny("the owner's cmux terminals require family trust.");
|
|
1189
|
+
}
|
|
1184
1190
|
// Credential tools have their own trust rules that apply at all levels
|
|
1185
1191
|
const credentialResult = checkCredentialTrustGuardrails(toolName, context);
|
|
1186
1192
|
if (!credentialResult.allowed)
|