@ouro.bot/cli 0.1.0-alpha.325 → 0.1.0-alpha.326
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 +7 -0
- package/dist/heart/outlook/outlook-http-hooks.js +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +17 -357
- package/dist/nerves/coverage/file-completeness.js +7 -0
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
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.326",
|
|
6
|
+
"changes": [
|
|
7
|
+
"refactor(outlook): split the Outlook HTTP server boundary into focused transport, static/path, default-hook, route-dispatch, and JSON-response helpers while preserving the public `startOutlookHttpServer()` API and existing HTTP behavior.",
|
|
8
|
+
"test(outlook): add direct seam coverage for Outlook HTTP helper modules, route/static/SSE/default-hook behavior, and nerves file-completeness exemptions for the new helper-module pattern."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.325",
|
|
6
13
|
"changes": [
|
|
@@ -0,0 +1,64 @@
|
|
|
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.createOutlookHttpReadHooks = createOutlookHttpReadHooks;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const outlook_read_1 = require("./outlook-read");
|
|
39
|
+
function createOutlookHttpReadHooks(options) {
|
|
40
|
+
const bundlesRoot = options.bundlesRoot;
|
|
41
|
+
const readOptions = bundlesRoot ? { bundlesRoot } : undefined;
|
|
42
|
+
const agentRoot = (agentName) => path.join(bundlesRoot ?? "", `${agentName}.ouro`);
|
|
43
|
+
return {
|
|
44
|
+
agentRoot,
|
|
45
|
+
readAgentSessions: options.readAgentSessions ?? ((agentName) => (0, outlook_read_1.readSessionInventory)(agentName, readOptions)),
|
|
46
|
+
readAgentTranscript: options.readAgentTranscript ?? ((agentName, friendId, channel, key) => (0, outlook_read_1.readSessionTranscript)(agentName, friendId, channel, key, readOptions)),
|
|
47
|
+
readAgentCoding: options.readAgentCoding ?? ((agentName) => (0, outlook_read_1.readCodingDeep)(agentRoot(agentName))),
|
|
48
|
+
readAgentAttention: options.readAgentAttention ?? ((agentName) => (0, outlook_read_1.readAttentionView)(agentName, readOptions)),
|
|
49
|
+
readAgentBridges: options.readAgentBridges ?? ((agentName) => (0, outlook_read_1.readBridgeInventory)(agentRoot(agentName))),
|
|
50
|
+
readAgentMemory: options.readAgentMemory ?? ((agentName) => (0, outlook_read_1.readMemoryView)(agentRoot(agentName))),
|
|
51
|
+
readAgentFriends: options.readAgentFriends ?? ((agentName) => (0, outlook_read_1.readFriendView)(agentName, readOptions)),
|
|
52
|
+
readAgentContinuity: options.readAgentContinuity ?? ((agentName) => (0, outlook_read_1.readOutlookContinuity)(agentRoot(agentName), agentName)),
|
|
53
|
+
readAgentOrientation: options.readAgentOrientation ?? ((agentName) => (0, outlook_read_1.readOrientationView)(agentRoot(agentName), agentName)),
|
|
54
|
+
readAgentObligations: options.readAgentObligations ?? ((agentName) => (0, outlook_read_1.readObligationDetailView)(agentRoot(agentName))),
|
|
55
|
+
readAgentChanges: options.readAgentChanges ?? ((agentName) => (0, outlook_read_1.readChangesView)(agentRoot(agentName))),
|
|
56
|
+
readAgentSelfFix: options.readAgentSelfFix ?? ((agentName) => (0, outlook_read_1.readSelfFixView)(agentRoot(agentName))),
|
|
57
|
+
readAgentMemoryDecisions: options.readAgentMemoryDecisions ?? ((agentName) => (0, outlook_read_1.readMemoryDecisionView)(agentRoot(agentName))),
|
|
58
|
+
readAgentHabits: options.readAgentHabits ?? ((agentName) => (0, outlook_read_1.readHabitView)(agentRoot(agentName))),
|
|
59
|
+
readDaemonHealth: options.readDaemonHealth ?? (() => (0, outlook_read_1.readDaemonHealthDeep)(options.healthPath)),
|
|
60
|
+
readLogs: options.readLogs ?? (() => (0, outlook_read_1.readLogView)(options.logPath ?? null)),
|
|
61
|
+
readDeskPrefs: (agentName) => (0, outlook_read_1.readDeskPrefs)(agentRoot(agentName)),
|
|
62
|
+
readNeedsMe: (agentName) => (0, outlook_read_1.readNeedsMeView)(agentName, readOptions),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeJson = writeJson;
|
|
4
|
+
function writeJson(response, statusCode, payload) {
|
|
5
|
+
response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8" });
|
|
6
|
+
response.end(`${JSON.stringify(payload, null, 2)}\n`);
|
|
7
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
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.createOutlookHttpRequestHandler = createOutlookHttpRequestHandler;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const outlook_http_response_1 = require("./outlook-http-response");
|
|
40
|
+
const outlook_http_static_1 = require("./outlook-http-static");
|
|
41
|
+
function createOutlookHttpRequestHandler(options) {
|
|
42
|
+
const staticFiles = options.staticFiles ?? { resolveSpaDistDir: outlook_http_static_1.resolveSpaDistDir, serveStaticFile: outlook_http_static_1.serveStaticFile };
|
|
43
|
+
return (request, response) => {
|
|
44
|
+
let pathname = (0, outlook_http_static_1.normalizeOutlookRequestPath)(request.url);
|
|
45
|
+
const origin = `http://${options.host}:${options.getPort()}`;
|
|
46
|
+
if (pathname.startsWith("/assets/")) {
|
|
47
|
+
const spaDir = staticFiles.resolveSpaDistDir();
|
|
48
|
+
if (spaDir) {
|
|
49
|
+
const assetPath = path.join(spaDir, pathname);
|
|
50
|
+
if (staticFiles.serveStaticFile(response, assetPath))
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
(0, outlook_http_response_1.writeJson)(response, 404, { ok: false, error: "asset not found" });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (pathname === "/outlook") {
|
|
57
|
+
response.writeHead(301, { location: "/" });
|
|
58
|
+
response.end();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
pathname = (0, outlook_http_static_1.normalizeLegacyOutlookApiPath)(pathname);
|
|
62
|
+
if (pathname === "/api/events") {
|
|
63
|
+
response.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", "connection": "keep-alive", "access-control-allow-origin": "*" });
|
|
64
|
+
response.write(":ok\n\n");
|
|
65
|
+
options.sse.add(response);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (pathname === "/api/machine") {
|
|
69
|
+
const machine = options.readMachineState();
|
|
70
|
+
const machineView = options.readMachineView?.({ origin, machine });
|
|
71
|
+
(0, outlook_http_response_1.writeJson)(response, 200, machineView ?? machine);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (pathname === "/api/machine/health") {
|
|
75
|
+
const health = options.hooks.readDaemonHealth();
|
|
76
|
+
(0, outlook_http_response_1.writeJson)(response, 200, health ?? { status: "unavailable" });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (pathname === "/api/machine/logs") {
|
|
80
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readLogs());
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const agentMatch = /^\/api\/agents\/([^/]+)(?:\/(.+))?$/.exec(pathname);
|
|
84
|
+
if (agentMatch) {
|
|
85
|
+
handleAgentRoute(request, response, {
|
|
86
|
+
agent: decodeURIComponent(agentMatch[1]),
|
|
87
|
+
surface: agentMatch[2] ?? null,
|
|
88
|
+
options,
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const spaDir = staticFiles.resolveSpaDistDir();
|
|
93
|
+
if (spaDir) {
|
|
94
|
+
if (staticFiles.serveStaticFile(response, path.join(spaDir, "index.html")))
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
(0, outlook_http_response_1.writeJson)(response, 404, { ok: false, error: `not found: ${pathname}` });
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function handleAgentRoute(request, response, context) {
|
|
101
|
+
const { agent, surface, options } = context;
|
|
102
|
+
if (!surface) {
|
|
103
|
+
const view = options.readAgentView?.(agent);
|
|
104
|
+
if (view) {
|
|
105
|
+
(0, outlook_http_response_1.writeJson)(response, 200, view);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const state = options.readAgentState(agent);
|
|
109
|
+
if (!state) {
|
|
110
|
+
(0, outlook_http_response_1.writeJson)(response, 404, { ok: false, error: `unknown agent: ${agent}` });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
(0, outlook_http_response_1.writeJson)(response, 200, state);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (surface === "sessions") {
|
|
117
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentSessions(agent));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const transcriptMatch = /^sessions\/([^/]+)\/([^/]+)\/([^/]+)$/.exec(surface);
|
|
121
|
+
if (transcriptMatch) {
|
|
122
|
+
const friendId = decodeURIComponent(transcriptMatch[1]);
|
|
123
|
+
const channel = decodeURIComponent(transcriptMatch[2]);
|
|
124
|
+
const key = decodeURIComponent(transcriptMatch[3]);
|
|
125
|
+
const transcript = options.hooks.readAgentTranscript(agent, friendId, channel, key);
|
|
126
|
+
if (!transcript) {
|
|
127
|
+
(0, outlook_http_response_1.writeJson)(response, 404, { ok: false, error: "session not found" });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
(0, outlook_http_response_1.writeJson)(response, 200, transcript);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (surface === "coding") {
|
|
134
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentCoding(agent));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (surface === "attention") {
|
|
138
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentAttention(agent));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (surface === "bridges") {
|
|
142
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentBridges(agent));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (surface === "memory") {
|
|
146
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentMemory(agent));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (surface === "friends") {
|
|
150
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentFriends(agent));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (surface === "continuity") {
|
|
154
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentContinuity(agent));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (surface === "orientation") {
|
|
158
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentOrientation(agent));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (surface === "obligations") {
|
|
162
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentObligations(agent));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (surface === "changes") {
|
|
166
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentChanges(agent));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (surface === "self-fix") {
|
|
170
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentSelfFix(agent));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (surface === "memory-decisions") {
|
|
174
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentMemoryDecisions(agent));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (surface === "dismiss-obligation" && request.method === "POST") {
|
|
178
|
+
handleDismissObligation(request, response, options.hooks.agentRoot(agent));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (surface === "desk-prefs") {
|
|
182
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readDeskPrefs(agent));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (surface === "needs-me") {
|
|
186
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readNeedsMe(agent));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (surface === "habits") {
|
|
190
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentHabits(agent));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (surface === "inner-transcript") {
|
|
194
|
+
const transcript = options.hooks.readAgentTranscript(agent, "self", "inner", "dialog");
|
|
195
|
+
(0, outlook_http_response_1.writeJson)(response, 200, transcript ?? { messageCount: 0, messages: [] });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
(0, outlook_http_response_1.writeJson)(response, 404, { ok: false, error: `unknown agent surface: ${surface}` });
|
|
199
|
+
}
|
|
200
|
+
function handleDismissObligation(request, response, agentRoot) {
|
|
201
|
+
let body = "";
|
|
202
|
+
request.on("data", (chunk) => {
|
|
203
|
+
body += chunk;
|
|
204
|
+
});
|
|
205
|
+
request.on("end", () => {
|
|
206
|
+
try {
|
|
207
|
+
const { obligationId } = JSON.parse(body);
|
|
208
|
+
if (!obligationId) {
|
|
209
|
+
(0, outlook_http_response_1.writeJson)(response, 400, { ok: false, error: "obligationId required" });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const prefsPath = path.join(agentRoot, "state", "outlook-prefs.json");
|
|
213
|
+
let prefs = {};
|
|
214
|
+
try {
|
|
215
|
+
prefs = JSON.parse(fs.readFileSync(prefsPath, "utf-8"));
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Missing or malformed prefs start from a clean preference object.
|
|
219
|
+
}
|
|
220
|
+
const dismissed = Array.isArray(prefs.dismissedObligations) ? prefs.dismissedObligations : [];
|
|
221
|
+
if (!dismissed.includes(obligationId))
|
|
222
|
+
dismissed.push(obligationId);
|
|
223
|
+
prefs.dismissedObligations = dismissed;
|
|
224
|
+
fs.mkdirSync(path.dirname(prefsPath), { recursive: true });
|
|
225
|
+
fs.writeFileSync(prefsPath, `${JSON.stringify(prefs, null, 2)}\n`, "utf-8");
|
|
226
|
+
(0, outlook_http_response_1.writeJson)(response, 200, { ok: true, dismissed: dismissed.length });
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
(0, outlook_http_response_1.writeJson)(response, 500, { ok: false, error: String(error) });
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
@@ -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.normalizeOutlookRequestPath = normalizeOutlookRequestPath;
|
|
37
|
+
exports.normalizeLegacyOutlookApiPath = normalizeLegacyOutlookApiPath;
|
|
38
|
+
exports.resolveSpaDistDir = resolveSpaDistDir;
|
|
39
|
+
exports.serveStaticFile = serveStaticFile;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const MIME_TYPES = {
|
|
43
|
+
".html": "text/html",
|
|
44
|
+
".js": "application/javascript",
|
|
45
|
+
".css": "text/css",
|
|
46
|
+
".json": "application/json",
|
|
47
|
+
".svg": "image/svg+xml",
|
|
48
|
+
".png": "image/png",
|
|
49
|
+
".ico": "image/x-icon",
|
|
50
|
+
".woff2": "font/woff2",
|
|
51
|
+
};
|
|
52
|
+
function normalizeOutlookRequestPath(urlValue = "/") {
|
|
53
|
+
const parsed = new URL(urlValue, "http://127.0.0.1");
|
|
54
|
+
const normalizedPath = parsed.pathname.replace(/\/+$/, "");
|
|
55
|
+
if (normalizedPath.length === 0)
|
|
56
|
+
return "/";
|
|
57
|
+
return normalizedPath;
|
|
58
|
+
}
|
|
59
|
+
function normalizeLegacyOutlookApiPath(pathname) {
|
|
60
|
+
if (pathname.startsWith("/outlook/api/"))
|
|
61
|
+
return pathname.slice("/outlook".length);
|
|
62
|
+
if (pathname === "/outlook/api")
|
|
63
|
+
return "/api";
|
|
64
|
+
return pathname;
|
|
65
|
+
}
|
|
66
|
+
function defaultSpaDistCandidates() {
|
|
67
|
+
return [
|
|
68
|
+
path.resolve(__dirname, "..", "..", "..", "packages", "outlook-ui", "dist"),
|
|
69
|
+
path.resolve(__dirname, "..", "..", "packages", "outlook-ui", "dist"),
|
|
70
|
+
path.resolve(__dirname, "..", "..", "..", "..", "packages", "outlook-ui", "dist"),
|
|
71
|
+
path.resolve(__dirname, "..", "..", "outlook-ui"),
|
|
72
|
+
path.resolve(__dirname, "..", "outlook-ui"),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
function resolveSpaDistDir(candidates = defaultSpaDistCandidates()) {
|
|
76
|
+
for (const candidate of candidates) {
|
|
77
|
+
if (fs.existsSync(path.join(candidate, "index.html")))
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function serveStaticFile(response, filePath) {
|
|
83
|
+
try {
|
|
84
|
+
if (!fs.existsSync(filePath))
|
|
85
|
+
return false;
|
|
86
|
+
const ext = path.extname(filePath);
|
|
87
|
+
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
88
|
+
const content = fs.readFileSync(filePath);
|
|
89
|
+
response.writeHead(200, {
|
|
90
|
+
"content-type": contentType,
|
|
91
|
+
"cache-control": ext === ".html" ? "no-cache" : "public, max-age=31536000, immutable",
|
|
92
|
+
});
|
|
93
|
+
response.end(content);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
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.createSseBroadcaster = createSseBroadcaster;
|
|
37
|
+
exports.createStateChangedBroadcast = createStateChangedBroadcast;
|
|
38
|
+
exports.createBundleWatcher = createBundleWatcher;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const DEFAULT_BUNDLE_WATCHER_DEPS = {
|
|
41
|
+
existsSync: fs.existsSync,
|
|
42
|
+
watch: fs.watch,
|
|
43
|
+
setTimeout,
|
|
44
|
+
clearTimeout,
|
|
45
|
+
};
|
|
46
|
+
function createSseBroadcaster() {
|
|
47
|
+
let nextId = 1;
|
|
48
|
+
const clients = new Set();
|
|
49
|
+
function add(response) {
|
|
50
|
+
const client = { id: nextId++, response };
|
|
51
|
+
clients.add(client);
|
|
52
|
+
response.on("close", () => clients.delete(client));
|
|
53
|
+
return client;
|
|
54
|
+
}
|
|
55
|
+
function broadcast(event, data = {}) {
|
|
56
|
+
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
57
|
+
for (const client of clients) {
|
|
58
|
+
try {
|
|
59
|
+
client.response.write(payload);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
clients.delete(client);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function disconnectAll() {
|
|
67
|
+
for (const client of clients) {
|
|
68
|
+
try {
|
|
69
|
+
client.response.end();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// The client may already have closed between the loop snapshot and end.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
clients.clear();
|
|
76
|
+
}
|
|
77
|
+
return { add, broadcast, disconnectAll };
|
|
78
|
+
}
|
|
79
|
+
function createStateChangedBroadcast(sse) {
|
|
80
|
+
return () => {
|
|
81
|
+
sse.broadcast("state-changed", { at: new Date().toISOString() });
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function createBundleWatcher(bundlesRoot, onChange, deps = DEFAULT_BUNDLE_WATCHER_DEPS) {
|
|
85
|
+
const watchers = [];
|
|
86
|
+
let debounceTimer = null;
|
|
87
|
+
const debounceMs = 500;
|
|
88
|
+
function debouncedOnChange() {
|
|
89
|
+
if (debounceTimer)
|
|
90
|
+
deps.clearTimeout(debounceTimer);
|
|
91
|
+
debounceTimer = deps.setTimeout(onChange, debounceMs);
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
if (deps.existsSync(bundlesRoot)) {
|
|
95
|
+
watchers.push(deps.watch(bundlesRoot, { recursive: true }, debouncedOnChange));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Watching is best-effort; manual broadcasts still keep Outlook usable.
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
stop() {
|
|
103
|
+
if (debounceTimer)
|
|
104
|
+
deps.clearTimeout(debounceTimer);
|
|
105
|
+
for (const watcher of watchers) {
|
|
106
|
+
try {
|
|
107
|
+
watcher.close();
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Already closed.
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
watchers.length = 0;
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -34,140 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.startOutlookHttpServer = startOutlookHttpServer;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
37
|
const http = __importStar(require("http"));
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
38
|
const runtime_1 = require("../../nerves/runtime");
|
|
41
39
|
const outlook_read_1 = require("./outlook-read");
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
function add(response) {
|
|
46
|
-
const client = { id: nextId++, response };
|
|
47
|
-
clients.add(client);
|
|
48
|
-
response.on("close", () => clients.delete(client));
|
|
49
|
-
return client;
|
|
50
|
-
}
|
|
51
|
-
function broadcast(event, data = {}) {
|
|
52
|
-
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
53
|
-
for (const client of clients) {
|
|
54
|
-
try {
|
|
55
|
-
client.response.write(payload);
|
|
56
|
-
/* v8 ignore start */
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
clients.delete(client);
|
|
60
|
-
}
|
|
61
|
-
/* v8 ignore stop */
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function disconnectAll() {
|
|
65
|
-
for (const client of clients) {
|
|
66
|
-
try {
|
|
67
|
-
client.response.end();
|
|
68
|
-
/* v8 ignore start */
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
/* already closed */
|
|
72
|
-
}
|
|
73
|
-
/* v8 ignore stop */
|
|
74
|
-
}
|
|
75
|
-
clients.clear();
|
|
76
|
-
}
|
|
77
|
-
return { add, broadcast, disconnectAll };
|
|
78
|
-
}
|
|
79
|
-
/* v8 ignore start — filesystem watcher, tested via integration */
|
|
80
|
-
function createBundleWatcher(bundlesRoot, onChange) {
|
|
81
|
-
const watchers = [];
|
|
82
|
-
let debounceTimer = null;
|
|
83
|
-
const DEBOUNCE_MS = 500;
|
|
84
|
-
function debouncedOnChange() {
|
|
85
|
-
if (debounceTimer)
|
|
86
|
-
clearTimeout(debounceTimer);
|
|
87
|
-
debounceTimer = setTimeout(onChange, DEBOUNCE_MS);
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
if (fs.existsSync(bundlesRoot)) {
|
|
91
|
-
const watcher = fs.watch(bundlesRoot, { recursive: true }, debouncedOnChange);
|
|
92
|
-
watchers.push(watcher);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// watch not available — SSE will rely on manual broadcast
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
stop() {
|
|
100
|
-
if (debounceTimer)
|
|
101
|
-
clearTimeout(debounceTimer);
|
|
102
|
-
for (const w of watchers)
|
|
103
|
-
try {
|
|
104
|
-
w.close();
|
|
105
|
-
}
|
|
106
|
-
catch { /* ignore */ }
|
|
107
|
-
watchers.length = 0;
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
/* v8 ignore stop */
|
|
112
|
-
function writeJson(response, statusCode, payload) {
|
|
113
|
-
response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8" });
|
|
114
|
-
response.end(`${JSON.stringify(payload, null, 2)}\n`);
|
|
115
|
-
}
|
|
116
|
-
/* v8 ignore start — SPA static file serving infrastructure */
|
|
117
|
-
const MIME_TYPES = {
|
|
118
|
-
".html": "text/html",
|
|
119
|
-
".js": "application/javascript",
|
|
120
|
-
".css": "text/css",
|
|
121
|
-
".json": "application/json",
|
|
122
|
-
".svg": "image/svg+xml",
|
|
123
|
-
".png": "image/png",
|
|
124
|
-
".ico": "image/x-icon",
|
|
125
|
-
".woff2": "font/woff2",
|
|
126
|
-
};
|
|
127
|
-
function resolveSpaDistDir() {
|
|
128
|
-
// Look for the built SPA relative to this file's location
|
|
129
|
-
// In production: dist/heart/daemon/outlook-http.js -> ../../packages/outlook-ui/dist/
|
|
130
|
-
// In dev: packages/outlook-ui/dist/
|
|
131
|
-
const candidates = [
|
|
132
|
-
path.resolve(__dirname, "..", "..", "..", "packages", "outlook-ui", "dist"),
|
|
133
|
-
path.resolve(__dirname, "..", "..", "packages", "outlook-ui", "dist"),
|
|
134
|
-
path.resolve(__dirname, "..", "..", "..", "..", "packages", "outlook-ui", "dist"),
|
|
135
|
-
// npm-published layout: the SPA dist is copied to dist/outlook-ui/
|
|
136
|
-
path.resolve(__dirname, "..", "..", "outlook-ui"),
|
|
137
|
-
path.resolve(__dirname, "..", "outlook-ui"),
|
|
138
|
-
];
|
|
139
|
-
for (const candidate of candidates) {
|
|
140
|
-
if (fs.existsSync(path.join(candidate, "index.html")))
|
|
141
|
-
return candidate;
|
|
142
|
-
}
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
function serveStaticFile(response, filePath) {
|
|
146
|
-
try {
|
|
147
|
-
if (!fs.existsSync(filePath))
|
|
148
|
-
return false;
|
|
149
|
-
const ext = path.extname(filePath);
|
|
150
|
-
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
151
|
-
const content = fs.readFileSync(filePath);
|
|
152
|
-
response.writeHead(200, {
|
|
153
|
-
"content-type": contentType,
|
|
154
|
-
"cache-control": ext === ".html" ? "no-cache" : "public, max-age=31536000, immutable",
|
|
155
|
-
});
|
|
156
|
-
response.end(content);
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
catch {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/* v8 ignore stop */
|
|
164
|
-
function normalizePath(urlValue = "/") {
|
|
165
|
-
const parsed = new URL(urlValue, "http://127.0.0.1");
|
|
166
|
-
const normalizedPath = parsed.pathname.replace(/\/+$/, "");
|
|
167
|
-
if (normalizedPath.length === 0)
|
|
168
|
-
return "/";
|
|
169
|
-
return normalizedPath;
|
|
170
|
-
}
|
|
40
|
+
const outlook_http_hooks_1 = require("./outlook-http-hooks");
|
|
41
|
+
const outlook_http_routes_1 = require("./outlook-http-routes");
|
|
42
|
+
const outlook_http_transport_1 = require("./outlook-http-transport");
|
|
171
43
|
async function startOutlookHttpServer(options = {}) {
|
|
172
44
|
const host = options.host ?? "127.0.0.1";
|
|
173
45
|
const port = options.port ?? 0;
|
|
@@ -175,238 +47,26 @@ async function startOutlookHttpServer(options = {}) {
|
|
|
175
47
|
const opts = bundlesRoot ? { bundlesRoot } : undefined;
|
|
176
48
|
const readMachineState = options.readMachineState ?? (() => (0, outlook_read_1.readOutlookMachineState)(opts));
|
|
177
49
|
const readMachineView = options.readMachineView;
|
|
178
|
-
/* v8 ignore start */
|
|
179
50
|
const readAgentState = options.readAgentState ?? ((agentName) => {
|
|
180
51
|
if (opts)
|
|
181
52
|
return (0, outlook_read_1.readOutlookAgentState)(agentName, opts);
|
|
182
53
|
return (0, outlook_read_1.readOutlookAgentState)(agentName);
|
|
183
54
|
});
|
|
184
|
-
/* v8 ignore stop */
|
|
185
55
|
const readAgentView = options.readAgentView;
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
readAgentOrientation: options.readAgentOrientation ?? ((agentName) => (0, outlook_read_1.readOrientationView)(agentRoot(agentName), agentName)),
|
|
201
|
-
readAgentObligations: options.readAgentObligations ?? ((agentName) => (0, outlook_read_1.readObligationDetailView)(agentRoot(agentName))),
|
|
202
|
-
readAgentChanges: options.readAgentChanges ?? ((agentName) => (0, outlook_read_1.readChangesView)(agentRoot(agentName))),
|
|
203
|
-
readAgentSelfFix: options.readAgentSelfFix ?? ((agentName) => (0, outlook_read_1.readSelfFixView)(agentRoot(agentName))),
|
|
204
|
-
readAgentMemoryDecisions: options.readAgentMemoryDecisions ?? ((agentName) => (0, outlook_read_1.readMemoryDecisionView)(agentRoot(agentName))),
|
|
205
|
-
readAgentHabits: options.readAgentHabits ?? ((agentName) => (0, outlook_read_1.readHabitView)(agentRoot(agentName))),
|
|
206
|
-
readDaemonHealth: options.readDaemonHealth ?? (() => (0, outlook_read_1.readDaemonHealthDeep)(options.healthPath)),
|
|
207
|
-
readLogs: options.readLogs ?? (() => (0, outlook_read_1.readLogView)(options.logPath ?? null)),
|
|
208
|
-
};
|
|
209
|
-
/* v8 ignore stop */
|
|
210
|
-
const sse = createSseBroadcaster();
|
|
211
|
-
/* v8 ignore start — watcher callback fires on filesystem changes */
|
|
212
|
-
const bundleWatcher = bundlesRoot ? createBundleWatcher(bundlesRoot, () => {
|
|
213
|
-
sse.broadcast("state-changed", { at: new Date().toISOString() });
|
|
214
|
-
}) : null;
|
|
215
|
-
/* v8 ignore stop */
|
|
216
|
-
const server = http.createServer((request, response) => {
|
|
217
|
-
let pathname = normalizePath(request.url);
|
|
218
|
-
const origin = `http://${host}:${server.address().port}`;
|
|
219
|
-
/* v8 ignore start — SPA static asset serving */
|
|
220
|
-
// Serve built SPA static assets: /assets/*
|
|
221
|
-
if (pathname.startsWith("/assets/")) {
|
|
222
|
-
const spaDir = resolveSpaDistDir();
|
|
223
|
-
if (spaDir) {
|
|
224
|
-
const assetPath = path.join(spaDir, pathname);
|
|
225
|
-
if (serveStaticFile(response, assetPath))
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
writeJson(response, 404, { ok: false, error: "asset not found" });
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
/* v8 ignore stop */
|
|
232
|
-
// Legacy /outlook route — redirect to root
|
|
233
|
-
if (pathname === "/outlook") {
|
|
234
|
-
response.writeHead(301, { location: "/" });
|
|
235
|
-
response.end();
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
// Compatibility alias: /outlook/api/* → /api/*
|
|
239
|
-
/* v8 ignore start -- legacy compat path: tested via integration @preserve */
|
|
240
|
-
if (pathname.startsWith("/outlook/api/")) {
|
|
241
|
-
pathname = pathname.slice("/outlook".length);
|
|
242
|
-
}
|
|
243
|
-
else if (pathname === "/outlook/api") {
|
|
244
|
-
pathname = "/api";
|
|
245
|
-
}
|
|
246
|
-
/* v8 ignore stop */
|
|
247
|
-
// SSE event stream
|
|
248
|
-
if (pathname === "/api/events") {
|
|
249
|
-
response.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", "connection": "keep-alive", "access-control-allow-origin": "*" });
|
|
250
|
-
response.write(":ok\n\n");
|
|
251
|
-
sse.add(response);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
if (pathname === "/api/machine") {
|
|
255
|
-
const machine = readMachineState();
|
|
256
|
-
const machineView = readMachineView?.({ origin, machine });
|
|
257
|
-
writeJson(response, 200, machineView ?? machine);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
if (pathname === "/api/machine/health") {
|
|
261
|
-
const health = hooks.readDaemonHealth();
|
|
262
|
-
writeJson(response, 200, health ?? { status: "unavailable" });
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
if (pathname === "/api/machine/logs") {
|
|
266
|
-
writeJson(response, 200, hooks.readLogs());
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
// Agent-level endpoints: /api/agents/:agent[/:surface[/:params...]]
|
|
270
|
-
const agentMatch = /^\/api\/agents\/([^/]+)(?:\/(.+))?$/.exec(pathname);
|
|
271
|
-
if (agentMatch) {
|
|
272
|
-
const agent = decodeURIComponent(agentMatch[1]);
|
|
273
|
-
const surface = agentMatch[2] ?? null;
|
|
274
|
-
if (!surface) {
|
|
275
|
-
const view = readAgentView?.(agent);
|
|
276
|
-
if (view) {
|
|
277
|
-
writeJson(response, 200, view);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
const state = readAgentState(agent);
|
|
281
|
-
if (!state) {
|
|
282
|
-
writeJson(response, 404, { ok: false, error: `unknown agent: ${agent}` });
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
writeJson(response, 200, state);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
if (surface === "sessions") {
|
|
289
|
-
writeJson(response, 200, hooks.readAgentSessions(agent));
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
const transcriptMatch = /^sessions\/([^/]+)\/([^/]+)\/([^/]+)$/.exec(surface);
|
|
293
|
-
if (transcriptMatch) {
|
|
294
|
-
const friendId = decodeURIComponent(transcriptMatch[1]);
|
|
295
|
-
const channel = decodeURIComponent(transcriptMatch[2]);
|
|
296
|
-
const key = decodeURIComponent(transcriptMatch[3]);
|
|
297
|
-
const transcript = hooks.readAgentTranscript(agent, friendId, channel, key);
|
|
298
|
-
if (!transcript) {
|
|
299
|
-
writeJson(response, 404, { ok: false, error: "session not found" });
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
writeJson(response, 200, transcript);
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
if (surface === "coding") {
|
|
306
|
-
writeJson(response, 200, hooks.readAgentCoding(agent));
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
if (surface === "attention") {
|
|
310
|
-
writeJson(response, 200, hooks.readAgentAttention(agent));
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
if (surface === "bridges") {
|
|
314
|
-
writeJson(response, 200, hooks.readAgentBridges(agent));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
if (surface === "memory") {
|
|
318
|
-
writeJson(response, 200, hooks.readAgentMemory(agent));
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
if (surface === "friends") {
|
|
322
|
-
writeJson(response, 200, hooks.readAgentFriends(agent));
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
if (surface === "continuity") {
|
|
326
|
-
writeJson(response, 200, hooks.readAgentContinuity(agent));
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
if (surface === "orientation") {
|
|
330
|
-
writeJson(response, 200, hooks.readAgentOrientation(agent));
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
if (surface === "obligations") {
|
|
334
|
-
writeJson(response, 200, hooks.readAgentObligations(agent));
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
if (surface === "changes") {
|
|
338
|
-
writeJson(response, 200, hooks.readAgentChanges(agent));
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
if (surface === "self-fix") {
|
|
342
|
-
writeJson(response, 200, hooks.readAgentSelfFix(agent));
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (surface === "memory-decisions") {
|
|
346
|
-
writeJson(response, 200, hooks.readAgentMemoryDecisions(agent));
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
/* v8 ignore start — desk prefs write + reads */
|
|
350
|
-
if (surface === "dismiss-obligation" && request.method === "POST") {
|
|
351
|
-
let body = "";
|
|
352
|
-
request.on("data", (chunk) => { body += chunk; });
|
|
353
|
-
request.on("end", () => {
|
|
354
|
-
try {
|
|
355
|
-
const { obligationId } = JSON.parse(body);
|
|
356
|
-
if (!obligationId) {
|
|
357
|
-
writeJson(response, 400, { ok: false, error: "obligationId required" });
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
const prefsPath = path.join(agentRoot(agent), "state", "outlook-prefs.json");
|
|
361
|
-
let prefs = {};
|
|
362
|
-
try {
|
|
363
|
-
prefs = JSON.parse(fs.readFileSync(prefsPath, "utf-8"));
|
|
364
|
-
}
|
|
365
|
-
catch { /* new file */ }
|
|
366
|
-
const dismissed = Array.isArray(prefs.dismissedObligations) ? prefs.dismissedObligations : [];
|
|
367
|
-
if (!dismissed.includes(obligationId))
|
|
368
|
-
dismissed.push(obligationId);
|
|
369
|
-
prefs.dismissedObligations = dismissed;
|
|
370
|
-
fs.mkdirSync(path.dirname(prefsPath), { recursive: true });
|
|
371
|
-
fs.writeFileSync(prefsPath, JSON.stringify(prefs, null, 2) + "\n", "utf-8");
|
|
372
|
-
writeJson(response, 200, { ok: true, dismissed: dismissed.length });
|
|
373
|
-
}
|
|
374
|
-
catch (error) {
|
|
375
|
-
writeJson(response, 500, { ok: false, error: String(error) });
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (surface === "desk-prefs") {
|
|
381
|
-
writeJson(response, 200, (0, outlook_read_1.readDeskPrefs)(agentRoot(agent)));
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
if (surface === "needs-me") {
|
|
385
|
-
writeJson(response, 200, (0, outlook_read_1.readNeedsMeView)(agent, opts));
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
/* v8 ignore stop */
|
|
389
|
-
if (surface === "habits") {
|
|
390
|
-
writeJson(response, 200, hooks.readAgentHabits(agent));
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
if (surface === "inner-transcript") {
|
|
394
|
-
const transcript = hooks.readAgentTranscript(agent, "self", "inner", "dialog");
|
|
395
|
-
writeJson(response, 200, transcript ?? { messageCount: 0, messages: [] });
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
writeJson(response, 404, { ok: false, error: `unknown agent surface: ${surface}` });
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
/* v8 ignore start — SPA fallback for client-side routing @preserve */
|
|
402
|
-
const spaDir = resolveSpaDistDir();
|
|
403
|
-
if (spaDir) {
|
|
404
|
-
if (serveStaticFile(response, path.join(spaDir, "index.html")))
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
writeJson(response, 404, { ok: false, error: `not found: ${pathname}` });
|
|
408
|
-
/* v8 ignore stop */
|
|
409
|
-
});
|
|
56
|
+
const hooks = (0, outlook_http_hooks_1.createOutlookHttpReadHooks)(options);
|
|
57
|
+
const sse = (0, outlook_http_transport_1.createSseBroadcaster)();
|
|
58
|
+
const bundleWatcher = bundlesRoot ? (0, outlook_http_transport_1.createBundleWatcher)(bundlesRoot, (0, outlook_http_transport_1.createStateChangedBroadcast)(sse)) : null;
|
|
59
|
+
let server;
|
|
60
|
+
server = http.createServer((0, outlook_http_routes_1.createOutlookHttpRequestHandler)({
|
|
61
|
+
host,
|
|
62
|
+
getPort: () => server.address().port,
|
|
63
|
+
readMachineState,
|
|
64
|
+
readMachineView,
|
|
65
|
+
readAgentState,
|
|
66
|
+
readAgentView,
|
|
67
|
+
hooks,
|
|
68
|
+
sse,
|
|
69
|
+
}));
|
|
410
70
|
await new Promise((resolve, reject) => {
|
|
411
71
|
server.once("error", reject);
|
|
412
72
|
server.listen(port, host, () => resolve());
|
|
@@ -95,6 +95,13 @@ const DISPATCH_EXEMPT_PATTERNS = [
|
|
|
95
95
|
// consumed by server readers and the UI. Outlook read/render modules own
|
|
96
96
|
// the observability for these projections.
|
|
97
97
|
"heart/outlook/outlook-types",
|
|
98
|
+
// Outlook HTTP helper modules: route/static/transport/hook seams are
|
|
99
|
+
// dispatched by outlook-http.ts, whose server lifecycle owns observability.
|
|
100
|
+
"heart/outlook/outlook-http-transport",
|
|
101
|
+
"heart/outlook/outlook-http-static",
|
|
102
|
+
"heart/outlook/outlook-http-hooks",
|
|
103
|
+
"heart/outlook/outlook-http-routes",
|
|
104
|
+
"heart/outlook/outlook-http-response",
|
|
98
105
|
];
|
|
99
106
|
function isDispatchExempt(filePath) {
|
|
100
107
|
return DISPATCH_EXEMPT_PATTERNS.some((pattern) => filePath.includes(pattern));
|