@ouro.bot/cli 0.1.0-alpha.159 → 0.1.0-alpha.160
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 -2
- package/dist/heart/daemon/daemon-cli.js +44 -1
- package/dist/heart/daemon/daemon.js +64 -18
- package/dist/heart/daemon/outlook-http.js +307 -0
- package/dist/heart/daemon/outlook-read.js +1281 -0
- package/dist/heart/daemon/outlook-render.js +1032 -0
- package/dist/heart/daemon/outlook-types.js +7 -0
- package/dist/heart/daemon/outlook-view.js +194 -0
- package/dist/heart/session-activity.js +5 -6
- package/dist/nerves/observation.js +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OUTLOOK_DEFAULT_PORT = exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = exports.OUTLOOK_RELEASE_INTERACTION_MODEL = exports.OUTLOOK_PRODUCT_NAME = void 0;
|
|
4
|
+
exports.OUTLOOK_PRODUCT_NAME = "Ouro Outlook";
|
|
5
|
+
exports.OUTLOOK_RELEASE_INTERACTION_MODEL = "read-only";
|
|
6
|
+
exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = "summary";
|
|
7
|
+
exports.OUTLOOK_DEFAULT_PORT = 6876;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildOutlookMachineView = buildOutlookMachineView;
|
|
4
|
+
exports.buildOutlookAgentView = buildOutlookAgentView;
|
|
5
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
6
|
+
const outlook_types_1 = require("./outlook-types");
|
|
7
|
+
function deriveAttention(agent) {
|
|
8
|
+
if (agent.degraded.status === "degraded") {
|
|
9
|
+
return { level: "degraded", label: "Degraded" };
|
|
10
|
+
}
|
|
11
|
+
if (agent.freshness.status === "stale") {
|
|
12
|
+
return { level: "stale", label: "Stale" };
|
|
13
|
+
}
|
|
14
|
+
if (agent.tasks.blockedCount > 0 || agent.coding.blockedCount > 0) {
|
|
15
|
+
return { level: "blocked", label: "Blocked" };
|
|
16
|
+
}
|
|
17
|
+
if (agent.tasks.liveCount > 0 || agent.coding.activeCount > 0 || agent.obligations.openCount > 0) {
|
|
18
|
+
return { level: "active", label: "Active" };
|
|
19
|
+
}
|
|
20
|
+
return { level: "idle", label: "Idle" };
|
|
21
|
+
}
|
|
22
|
+
function deriveAgentAttention(agent) {
|
|
23
|
+
return deriveAttention({
|
|
24
|
+
agentName: agent.agentName,
|
|
25
|
+
enabled: agent.enabled,
|
|
26
|
+
freshness: agent.freshness,
|
|
27
|
+
degraded: agent.degraded,
|
|
28
|
+
tasks: {
|
|
29
|
+
liveCount: agent.tasks.liveCount,
|
|
30
|
+
blockedCount: agent.tasks.blockedCount,
|
|
31
|
+
},
|
|
32
|
+
obligations: {
|
|
33
|
+
openCount: agent.obligations.openCount,
|
|
34
|
+
},
|
|
35
|
+
coding: {
|
|
36
|
+
activeCount: agent.coding.activeCount,
|
|
37
|
+
blockedCount: agent.coding.blockedCount,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function buildTotals(machine) {
|
|
42
|
+
return machine.agents.reduce((totals, agent) => ({
|
|
43
|
+
agents: totals.agents + 1,
|
|
44
|
+
enabledAgents: totals.enabledAgents + (agent.enabled ? 1 : 0),
|
|
45
|
+
degradedAgents: totals.degradedAgents + (agent.degraded.status === "degraded" ? 1 : 0),
|
|
46
|
+
staleAgents: totals.staleAgents + (agent.freshness.status === "stale" ? 1 : 0),
|
|
47
|
+
liveTasks: totals.liveTasks + agent.tasks.liveCount,
|
|
48
|
+
blockedTasks: totals.blockedTasks + agent.tasks.blockedCount,
|
|
49
|
+
openObligations: totals.openObligations + agent.obligations.openCount,
|
|
50
|
+
activeCodingAgents: totals.activeCodingAgents + (agent.coding.activeCount > 0 ? 1 : 0),
|
|
51
|
+
blockedCodingAgents: totals.blockedCodingAgents + (agent.coding.blockedCount > 0 ? 1 : 0),
|
|
52
|
+
}), {
|
|
53
|
+
agents: 0,
|
|
54
|
+
enabledAgents: 0,
|
|
55
|
+
degradedAgents: 0,
|
|
56
|
+
staleAgents: 0,
|
|
57
|
+
liveTasks: 0,
|
|
58
|
+
blockedTasks: 0,
|
|
59
|
+
openObligations: 0,
|
|
60
|
+
activeCodingAgents: 0,
|
|
61
|
+
blockedCodingAgents: 0,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function deriveMood(machine, daemon) {
|
|
65
|
+
if (machine.degraded.status === "degraded" || daemon.health === "warn") {
|
|
66
|
+
return "strained";
|
|
67
|
+
}
|
|
68
|
+
if (machine.freshness.status === "stale") {
|
|
69
|
+
return "watchful";
|
|
70
|
+
}
|
|
71
|
+
return "calm";
|
|
72
|
+
}
|
|
73
|
+
function buildOutlookMachineView(input) {
|
|
74
|
+
const totals = buildTotals(input.machine);
|
|
75
|
+
const agents = input.machine.agents
|
|
76
|
+
.map((agent) => ({
|
|
77
|
+
...agent,
|
|
78
|
+
attention: deriveAttention(agent),
|
|
79
|
+
}))
|
|
80
|
+
.sort((left, right) => {
|
|
81
|
+
const leftAt = left.freshness.latestActivityAt ?? "";
|
|
82
|
+
const rightAt = right.freshness.latestActivityAt ?? "";
|
|
83
|
+
return rightAt.localeCompare(leftAt);
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
overview: {
|
|
87
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
88
|
+
observedAt: input.machine.observedAt,
|
|
89
|
+
primaryEntryPoint: input.daemon.outlookUrl,
|
|
90
|
+
daemon: input.daemon,
|
|
91
|
+
runtime: input.machine.runtime,
|
|
92
|
+
freshness: input.machine.freshness,
|
|
93
|
+
degraded: input.machine.degraded,
|
|
94
|
+
totals,
|
|
95
|
+
mood: deriveMood(input.machine, input.daemon),
|
|
96
|
+
entrypoints: [
|
|
97
|
+
{ kind: "web", label: "Open Outlook", target: input.daemon.outlookUrl },
|
|
98
|
+
{ kind: "cli", label: "CLI JSON", target: "ouro outlook --json" },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
agents,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function normalizeViewer(viewer) {
|
|
105
|
+
return {
|
|
106
|
+
kind: viewer?.kind ?? "human",
|
|
107
|
+
agentName: viewer?.agentName,
|
|
108
|
+
innerDetail: viewer?.innerDetail ?? "summary",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function buildInnerView(inner, viewer) {
|
|
112
|
+
if (viewer.innerDetail === "deep") {
|
|
113
|
+
return {
|
|
114
|
+
mode: "deep",
|
|
115
|
+
status: inner.status,
|
|
116
|
+
summary: inner.surfacedSummary,
|
|
117
|
+
hasPending: inner.hasPending,
|
|
118
|
+
origin: inner.origin,
|
|
119
|
+
obligationStatus: inner.obligationStatus,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
mode: "summary",
|
|
124
|
+
status: inner.status,
|
|
125
|
+
summary: inner.surfacedSummary,
|
|
126
|
+
hasPending: inner.hasPending,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function buildRecentActivity(agent) {
|
|
130
|
+
const items = [
|
|
131
|
+
...agent.coding.items.map((item) => ({
|
|
132
|
+
kind: "coding",
|
|
133
|
+
at: item.lastActivityAt,
|
|
134
|
+
label: item.checkpoint ?? `${item.runner} ${item.status}`,
|
|
135
|
+
detail: item.workdir,
|
|
136
|
+
})),
|
|
137
|
+
...agent.sessions.items.map((item) => ({
|
|
138
|
+
kind: "session",
|
|
139
|
+
at: item.lastActivityAt,
|
|
140
|
+
label: `${item.friendName} via ${item.channel}`,
|
|
141
|
+
detail: item.key,
|
|
142
|
+
})),
|
|
143
|
+
...agent.obligations.items.map((item) => ({
|
|
144
|
+
kind: "obligation",
|
|
145
|
+
at: item.updatedAt,
|
|
146
|
+
label: item.content,
|
|
147
|
+
detail: item.nextAction ?? item.status,
|
|
148
|
+
})),
|
|
149
|
+
];
|
|
150
|
+
if (agent.inner.latestActivityAt) {
|
|
151
|
+
items.push({
|
|
152
|
+
kind: "inner",
|
|
153
|
+
at: agent.inner.latestActivityAt,
|
|
154
|
+
label: agent.inner.surfacedSummary ?? agent.inner.status,
|
|
155
|
+
detail: agent.inner.hasPending ? "pending inner work" : agent.inner.obligationStatus ?? "no linked obligation",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return items
|
|
159
|
+
.filter((item) => Number.isFinite(Date.parse(item.at)))
|
|
160
|
+
.sort((left, right) => right.at.localeCompare(left.at))
|
|
161
|
+
.slice(0, 4);
|
|
162
|
+
}
|
|
163
|
+
function buildOutlookAgentView(input) {
|
|
164
|
+
/* v8 ignore next */
|
|
165
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_view_agent", message: `building outlook view for ${input.agent.agentName}`, meta: { agent: input.agent.agentName } });
|
|
166
|
+
const viewer = normalizeViewer(input.viewer);
|
|
167
|
+
return {
|
|
168
|
+
productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
|
|
169
|
+
interactionModel: outlook_types_1.OUTLOOK_RELEASE_INTERACTION_MODEL,
|
|
170
|
+
viewer,
|
|
171
|
+
agent: {
|
|
172
|
+
agentName: input.agent.agentName,
|
|
173
|
+
agentRoot: input.agent.agentRoot,
|
|
174
|
+
enabled: input.agent.enabled,
|
|
175
|
+
provider: input.agent.provider,
|
|
176
|
+
senses: input.agent.senses,
|
|
177
|
+
freshness: input.agent.freshness,
|
|
178
|
+
degraded: input.agent.degraded,
|
|
179
|
+
attention: deriveAgentAttention(input.agent),
|
|
180
|
+
},
|
|
181
|
+
work: {
|
|
182
|
+
tasks: input.agent.tasks,
|
|
183
|
+
obligations: input.agent.obligations,
|
|
184
|
+
sessions: input.agent.sessions,
|
|
185
|
+
coding: input.agent.coding,
|
|
186
|
+
bridges: input.agent.tasks.activeBridges,
|
|
187
|
+
},
|
|
188
|
+
inner: buildInnerView(input.agent.inner, viewer),
|
|
189
|
+
activity: {
|
|
190
|
+
freshness: input.agent.freshness,
|
|
191
|
+
recent: buildRecentActivity(input.agent),
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -88,7 +88,7 @@ function parseFriendActivity(sessionPath) {
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
function listSessionActivity(query) {
|
|
91
|
-
const { sessionsDir, friendsDir, agentName, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, currentSession = null, } = query;
|
|
91
|
+
const { sessionsDir, friendsDir, agentName, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, nowMs = Date.now(), currentSession = null, } = query;
|
|
92
92
|
(0, runtime_1.emitNervesEvent)({
|
|
93
93
|
component: "daemon",
|
|
94
94
|
event: "daemon.session_activity_scan",
|
|
@@ -100,7 +100,6 @@ function listSessionActivity(query) {
|
|
|
100
100
|
});
|
|
101
101
|
if (!fs.existsSync(sessionsDir))
|
|
102
102
|
return [];
|
|
103
|
-
const now = Date.now();
|
|
104
103
|
const results = [];
|
|
105
104
|
let friendDirs;
|
|
106
105
|
try {
|
|
@@ -141,7 +140,7 @@ function listSessionActivity(query) {
|
|
|
141
140
|
const activity = parseFriendActivity(sessionPath);
|
|
142
141
|
if (!activity)
|
|
143
142
|
continue;
|
|
144
|
-
if (
|
|
143
|
+
if (nowMs - activity.lastActivityMs > activeThresholdMs)
|
|
145
144
|
continue;
|
|
146
145
|
results.push({
|
|
147
146
|
friendId,
|
|
@@ -164,10 +163,10 @@ function listSessionActivity(query) {
|
|
|
164
163
|
});
|
|
165
164
|
}
|
|
166
165
|
function findFreshestFriendSession(query) {
|
|
167
|
-
const { activeOnly = false, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, ...rest } = query;
|
|
166
|
+
const { activeOnly = false, activeThresholdMs = DEFAULT_ACTIVE_THRESHOLD_MS, nowMs, ...rest } = query;
|
|
168
167
|
const currentSession = rest.currentSession ?? null;
|
|
169
168
|
const all = activeOnly
|
|
170
|
-
? listSessionActivity({ ...rest, activeThresholdMs, currentSession })
|
|
171
|
-
: listSessionActivity({ ...rest, activeThresholdMs: Number.MAX_SAFE_INTEGER, currentSession });
|
|
169
|
+
? listSessionActivity({ ...rest, activeThresholdMs, nowMs, currentSession })
|
|
170
|
+
: listSessionActivity({ ...rest, activeThresholdMs: Number.MAX_SAFE_INTEGER, nowMs, currentSession });
|
|
172
171
|
return all.find((entry) => entry.friendId === query.friendId) ?? null;
|
|
173
172
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Nerves observation layer — shared typed readers for runtime state.
|
|
4
|
+
*
|
|
5
|
+
* This module re-exports domain types that multiple consumers need
|
|
6
|
+
* (Outlook, CLI, agent tools) so they don't maintain parallel type universes.
|
|
7
|
+
*
|
|
8
|
+
* The Outlook UI consumes these through the HTTP API, but the same
|
|
9
|
+
* observation functions back CLI commands and future native clients.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
/* v8 ignore start — module-level observability event */
|
|
13
|
+
const runtime_1 = require("./runtime");
|
|
14
|
+
(0, runtime_1.emitNervesEvent)({
|
|
15
|
+
component: "nerves",
|
|
16
|
+
event: "nerves.observation_loaded",
|
|
17
|
+
message: "observation layer loaded",
|
|
18
|
+
meta: {},
|
|
19
|
+
});
|
|
20
|
+
/* v8 ignore stop */
|