@jungjaehoon/mama-os 0.32.3 → 0.34.0
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/README.md +15 -17
- package/dist/agent/os-agent-capabilities.md +2 -2
- package/dist/api/graph-api.d.ts +4 -4
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +47 -78
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +9 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/operator-handler.d.ts +1 -1
- package/dist/api/operator-handler.js +1 -1
- package/dist/api/runtime-status-handler.d.ts +41 -0
- package/dist/api/runtime-status-handler.d.ts.map +1 -0
- package/dist/api/runtime-status-handler.js +55 -0
- package/dist/api/runtime-status-handler.js.map +1 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +58 -23
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.d.ts +2 -0
- package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +62 -1
- package/dist/cli/runtime/api-routes-init.js.map +1 -1
- package/dist/cli/runtime/api-server-init.d.ts +12 -1
- package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-server-init.js +54 -0
- package/dist/cli/runtime/api-server-init.js.map +1 -1
- package/dist/cli/runtime/utilities.d.ts +1 -1
- package/dist/cli/runtime/utilities.d.ts.map +1 -1
- package/dist/cli/runtime/utilities.js +3 -1
- package/dist/cli/runtime/utilities.js.map +1 -1
- package/dist/gateways/message-router.d.ts +4 -0
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +62 -13
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/owner-report-inbox.d.ts +40 -0
- package/dist/gateways/owner-report-inbox.d.ts.map +1 -0
- package/dist/gateways/owner-report-inbox.js +128 -0
- package/dist/gateways/owner-report-inbox.js.map +1 -0
- package/dist/gateways/report-projection-v1.d.ts +41 -0
- package/dist/gateways/report-projection-v1.d.ts.map +1 -0
- package/dist/gateways/report-projection-v1.js +160 -0
- package/dist/gateways/report-projection-v1.js.map +1 -0
- package/dist/gateways/session-store.d.ts +22 -0
- package/dist/gateways/session-store.d.ts.map +1 -1
- package/dist/gateways/session-store.js +76 -3
- package/dist/gateways/session-store.js.map +1 -1
- package/dist/gateways/telegram-message-ledger.d.ts +10 -0
- package/dist/gateways/telegram-message-ledger.d.ts.map +1 -1
- package/dist/gateways/telegram-message-ledger.js +23 -2
- package/dist/gateways/telegram-message-ledger.js.map +1 -1
- package/dist/gateways/telegram-report-context-store.d.ts +193 -0
- package/dist/gateways/telegram-report-context-store.d.ts.map +1 -0
- package/dist/gateways/telegram-report-context-store.js +612 -0
- package/dist/gateways/telegram-report-context-store.js.map +1 -0
- package/dist/gateways/telegram.d.ts +9 -0
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +100 -0
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/gateways/types.d.ts +12 -0
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.js +2 -2
- package/dist/operator/board-slot-instructions.d.ts +1 -1
- package/dist/operator/board-slot-instructions.js +1 -1
- package/dist/operator/operator-trigger-loop.d.ts +17 -1
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +87 -23
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/report-delivery-coordinator.d.ts +82 -0
- package/dist/operator/report-delivery-coordinator.d.ts.map +1 -0
- package/dist/operator/report-delivery-coordinator.js +123 -0
- package/dist/operator/report-delivery-coordinator.js.map +1 -0
- package/dist/operator/situation-report.d.ts +7 -0
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +12 -0
- package/dist/operator/situation-report.js.map +1 -1
- package/package.json +1 -2
- package/public/viewer/js/modules/system.js +183 -0
- package/public/viewer/js/utils/ui-commands.js +4 -9
- package/public/viewer/log-viewer.html +2 -192
- package/public/viewer/operator/operator.css +1 -0
- package/public/viewer/operator/operator.js +14830 -0
- package/public/viewer/src/modules/system.ts +242 -0
- package/public/viewer/src/utils/ui-commands.ts +4 -8
- package/public/viewer/sw.js +44 -10
- package/public/viewer/viewer.css +338 -331
- package/public/viewer/viewer.html +388 -1472
- package/public/ui/assets/index-BDXDGEV6.js +0 -62
- package/public/ui/assets/index-po2tN0xq.css +0 -1
- package/public/ui/index.html +0 -14
- package/public/ui/theme-init.js +0 -20
- package/public/viewer/js/modules/agents.js +0 -1153
- package/public/viewer/js/modules/chat.js +0 -1993
- package/public/viewer/js/modules/connector-feed.js +0 -352
- package/public/viewer/js/modules/dashboard.js +0 -456
- package/public/viewer/js/modules/entity-audit.js +0 -106
- package/public/viewer/js/modules/entity-review.js +0 -66
- package/public/viewer/js/modules/settings.js +0 -1257
- package/public/viewer/src/modules/agents.ts +0 -1302
- package/public/viewer/src/modules/chat.ts +0 -2426
- package/public/viewer/src/modules/connector-feed.ts +0 -391
- package/public/viewer/src/modules/dashboard.ts +0 -498
- package/public/viewer/src/modules/entity-audit.ts +0 -154
- package/public/viewer/src/modules/entity-review.ts +0 -175
- package/public/viewer/src/modules/settings.ts +0 -1547
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ npx @jungjaehoon/mama-os init --backend cline # or claude / codex / auto
|
|
|
86
86
|
mama start
|
|
87
87
|
|
|
88
88
|
# 3. Open the operator board
|
|
89
|
-
open http://localhost:3847/
|
|
89
|
+
open http://localhost:3847/viewer
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
**Prerequisites:** Node.js >= 22.13.0, one authenticated backend CLI (Claude, Codex, or Cline), 500MB disk space.
|
|
@@ -157,25 +157,23 @@ Agents delegate via `delegate()` with skill injection and automatic retry. Confi
|
|
|
157
157
|
|
|
158
158
|
## Viewer
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
mobile (add to home screen).
|
|
160
|
+
One web console at `http://localhost:3847/viewer` (`/` redirects there), opening on the
|
|
161
|
+
operator board. PWA-enabled for mobile (add to home screen).
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
action required, decisions, pipeline) rendered live over SSE, plus a Triggers tab showing the
|
|
165
|
-
trigger loop's library with an owner veto tray.
|
|
163
|
+
Three groups:
|
|
166
164
|
|
|
167
|
-
|
|
165
|
+
| Group | View | What it shows |
|
|
166
|
+
| ------------- | ---------- | ------------------------------------------------------------------------------------------------ |
|
|
167
|
+
| **Operator** | Board | Four agent-published report slots (briefing, action required, decisions, pipeline) live over SSE |
|
|
168
|
+
| **Operator** | Tasks | The task board fed from your channels |
|
|
169
|
+
| **Operator** | Triggers | The trigger loop's library with an owner veto tray |
|
|
170
|
+
| **Knowledge** | Memory | Interactive reasoning graph (1000+ nodes), search, export |
|
|
171
|
+
| **Knowledge** | Wiki | Knowledge base (syncs with Obsidian vault) |
|
|
172
|
+
| **System** | Runtime | Read-only runtime truth: backend, model, gateways, health |
|
|
173
|
+
| **System** | Connectors | Connector status and last poll |
|
|
174
|
+
| **System** | Logs | Daemon logs with filtering, pinning, stats, WebSocket and polling |
|
|
168
175
|
|
|
169
|
-
|
|
170
|
-
| ------------- | ---------------------------------------------------------- |
|
|
171
|
-
| **Dashboard** | Agent activity, memory stats, system health |
|
|
172
|
-
| **Feed** | Real-time stream from all connected sources |
|
|
173
|
-
| **Wiki** | Knowledge base (syncs with Obsidian vault) |
|
|
174
|
-
| **Memory** | Interactive reasoning graph (1000+ nodes), search, export |
|
|
175
|
-
| **Logs** | Daemon logs with filtering, pinning, stats, WebSocket mode |
|
|
176
|
-
| **Settings** | Connectors, gateways, agents, cron, token budget |
|
|
177
|
-
|
|
178
|
-
Floating chat panel on every tab — voice input, TTS, slash commands.
|
|
176
|
+
Each view has its own hash route, e.g. `/viewer#operator/tasks?task=42`.
|
|
179
177
|
|
|
180
178
|
## Gateway Integrations
|
|
181
179
|
|
|
@@ -355,7 +355,7 @@ Restart unnecessary. Continue anyway?
|
|
|
355
355
|
|
|
356
356
|
**DO NOT confuse contexts**:
|
|
357
357
|
|
|
358
|
-
❌ **Wrong** (in
|
|
358
|
+
❌ **Wrong** (in a chat gateway conversation):
|
|
359
359
|
|
|
360
360
|
```text
|
|
361
361
|
|
|
@@ -365,7 +365,7 @@ Want me to check the system status?" ← Mentioning OS Agent role in normal Chat
|
|
|
365
365
|
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
-
✅ **Correct** (in
|
|
368
|
+
✅ **Correct** (in a chat gateway conversation):
|
|
369
369
|
|
|
370
370
|
```text
|
|
371
371
|
|
package/dist/api/graph-api.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MAMA Graph API
|
|
3
3
|
*
|
|
4
|
-
* HTTP API endpoints for
|
|
4
|
+
* HTTP API endpoints for the Viewer.
|
|
5
5
|
* Provides /graph endpoint for fetching decisions and edges data.
|
|
6
6
|
* Provides /viewer endpoint for serving HTML viewer.
|
|
7
7
|
*/
|
|
8
8
|
import type { GraphNode, GraphEdge, CheckpointData, GraphHandlerOptions, GraphHandlerFn } from './graph-api-types.js';
|
|
9
|
-
declare const
|
|
10
|
-
declare const
|
|
9
|
+
declare const viewerHtmlPath: () => string;
|
|
10
|
+
declare const viewerCssPath: () => string;
|
|
11
11
|
declare const DEFAULT_GRAPH_LIMIT = 300;
|
|
12
12
|
declare function migrateLegacyManagedBackends<T extends Record<string, unknown>>(config: T): T;
|
|
13
13
|
type GraphDecisionRow = {
|
|
@@ -37,6 +37,6 @@ declare function filterNodesByTopic(nodes: GraphNode[], topic: string): GraphNod
|
|
|
37
37
|
declare function filterEdgesByNodes(edges: GraphEdge[], nodes: GraphNode[]): GraphEdge[];
|
|
38
38
|
declare function createGraphHandler(options?: GraphHandlerOptions): GraphHandlerFn;
|
|
39
39
|
declare function validateConfigUpdate(config: Record<string, any>): string[];
|
|
40
|
-
export { createGraphHandler, DEFAULT_GRAPH_LIMIT, mapDecisionRowToGraphNode, parseGraphLimit, buildGraphMeta, validateConfigUpdate, migrateLegacyManagedBackends, getAllNodes, getAllEdges, getAllCheckpoints, getUniqueTopics, filterNodesByTopic, filterEdgesByNodes,
|
|
40
|
+
export { createGraphHandler, DEFAULT_GRAPH_LIMIT, mapDecisionRowToGraphNode, parseGraphLimit, buildGraphMeta, validateConfigUpdate, migrateLegacyManagedBackends, getAllNodes, getAllEdges, getAllCheckpoints, getUniqueTopics, filterNodesByTopic, filterEdgesByNodes, viewerHtmlPath, viewerCssPath, };
|
|
41
41
|
export type { GraphNode, GraphEdge, SimilarityEdge, CheckpointData, GraphHandlerOptions, } from './graph-api-types.js';
|
|
42
42
|
//# sourceMappingURL=graph-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-api.d.ts","sourceRoot":"","sources":["../../src/api/graph-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA6CH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EAET,cAAc,EACd,mBAAmB,EAGnB,cAAc,EACf,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"graph-api.d.ts","sourceRoot":"","sources":["../../src/api/graph-api.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA6CH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EAET,cAAc,EACd,mBAAmB,EAGnB,cAAc,EACf,MAAM,sBAAsB,CAAC;AA8C9B,QAAA,MAAM,cAAc,QAAO,MAAwD,CAAC;AACpF,QAAA,MAAM,aAAa,QAAO,MAAuD,CAAC;AAclF,QAAA,MAAM,mBAAmB,MAAM,CAAC;AA8DhC,iBAAS,4BAA4B,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CA4ErF;AAqFD,KAAK,gBAAgB,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAUF,iBAAS,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,GAAG,SAAS,CASnE;AAED,iBAAS,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAgB/D;AAED,iBAAS,cAAc,CAAC,KAAK,EAAE;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CASnC;AAED,iBAAe,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAmBtE;AAqDD,iBAAe,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CA0BjD;AAWD,iBAAe,iBAAiB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAiC5D;AAED,iBAAS,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAGrD;AAED,iBAAS,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAE1E;AAED,iBAAS,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAG/E;AAorBD,iBAAS,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,cAAc,CAmxC7E;AAmpBD,iBAAS,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAiGnE;AAm3BD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,4BAA4B,EAC5B,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,CAAC;AAEF,YAAY,EACV,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,EACd,mBAAmB,GACpB,MAAM,sBAAsB,CAAC"}
|
package/dist/api/graph-api.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* MAMA Graph API
|
|
4
4
|
*
|
|
5
|
-
* HTTP API endpoints for
|
|
5
|
+
* HTTP API endpoints for the Viewer.
|
|
6
6
|
* Provides /graph endpoint for fetching decisions and edges data.
|
|
7
7
|
* Provides /viewer endpoint for serving HTML viewer.
|
|
8
8
|
*/
|
|
@@ -10,7 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.
|
|
13
|
+
exports.viewerCssPath = exports.viewerHtmlPath = exports.DEFAULT_GRAPH_LIMIT = void 0;
|
|
14
14
|
exports.createGraphHandler = createGraphHandler;
|
|
15
15
|
exports.mapDecisionRowToGraphNode = mapDecisionRowToGraphNode;
|
|
16
16
|
exports.parseGraphLimit = parseGraphLimit;
|
|
@@ -52,8 +52,15 @@ const mama = require('@jungjaehoon/mama-core/mama-api');
|
|
|
52
52
|
// Config paths
|
|
53
53
|
const MAMA_CONFIG_PATH = path_1.default.join(os_1.default.homedir(), '.mama', 'config.yaml');
|
|
54
54
|
const PACKAGE_ROOT_DIR = path_1.default.resolve(__dirname, '../..');
|
|
55
|
-
// Paths to viewer files (now in public/viewer/)
|
|
55
|
+
// Paths to viewer files (now in public/viewer/). Resolved per request so the
|
|
56
|
+
// MAMA_VIEWER_DIR override works for tests without module-load ordering games.
|
|
56
57
|
function getViewerDirectory() {
|
|
58
|
+
if (process.env.MAMA_VIEWER_DIR) {
|
|
59
|
+
// resolve() drops trailing slashes; without it the `operatorRoot + path.sep`
|
|
60
|
+
// traversal guard in the /viewer/operator route would 404 every request for
|
|
61
|
+
// '/foo/bar/'-style values.
|
|
62
|
+
return path_1.default.resolve(process.env.MAMA_VIEWER_DIR);
|
|
63
|
+
}
|
|
57
64
|
const packagePublicViewer = path_1.default.join(PACKAGE_ROOT_DIR, 'public', 'viewer');
|
|
58
65
|
const candidateDirs = [
|
|
59
66
|
path_1.default.join(process.cwd(), 'public', 'viewer'),
|
|
@@ -70,52 +77,21 @@ function getViewerDirectory() {
|
|
|
70
77
|
// Fallback for unusual launch locations.
|
|
71
78
|
return path_1.default.join(process.cwd(), 'public', 'viewer');
|
|
72
79
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
// Operator
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// resolve() drops trailing slashes; without it the `uiRoot + path.sep`
|
|
87
|
-
// traversal guard below would 404 every request for '/foo/bar/'-style values.
|
|
88
|
-
return path_1.default.resolve(process.env.MAMA_UI_DIR);
|
|
89
|
-
}
|
|
90
|
-
const candidateDirs = [
|
|
91
|
-
path_1.default.join(process.cwd(), 'public', 'ui'),
|
|
92
|
-
path_1.default.join(PACKAGE_ROOT_DIR, 'public', 'ui'),
|
|
93
|
-
path_1.default.join(__dirname, '../../public/ui'),
|
|
94
|
-
path_1.default.join(__dirname, '../../../public/ui'),
|
|
95
|
-
path_1.default.join(process.cwd(), 'packages', 'standalone', 'public', 'ui'),
|
|
96
|
-
];
|
|
97
|
-
for (const candidate of candidateDirs) {
|
|
98
|
-
if (fs_1.default.existsSync(candidate) && fs_1.default.statSync(candidate).isDirectory()) {
|
|
99
|
-
return candidate;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return path_1.default.join(process.cwd(), 'public', 'ui');
|
|
103
|
-
}
|
|
104
|
-
// serveStaticFile requires an explicit content type and only reads bytes (not
|
|
105
|
-
// utf-8) for image/* or octet-stream -- fonts map to octet-stream for integrity.
|
|
106
|
-
const UI_STATIC_MIME = {
|
|
107
|
-
'.html': 'text/html',
|
|
108
|
-
'.js': 'text/javascript',
|
|
80
|
+
const viewerHtmlPath = () => path_1.default.join(getViewerDirectory(), 'viewer.html');
|
|
81
|
+
exports.viewerHtmlPath = viewerHtmlPath;
|
|
82
|
+
const viewerCssPath = () => path_1.default.join(getViewerDirectory(), 'viewer.css');
|
|
83
|
+
exports.viewerCssPath = viewerCssPath;
|
|
84
|
+
const swJsPath = () => path_1.default.join(getViewerDirectory(), 'sw.js');
|
|
85
|
+
const manifestJsonPath = () => path_1.default.join(getViewerDirectory(), 'manifest.json');
|
|
86
|
+
const viewerIconDir = () => path_1.default.join(getViewerDirectory(), 'icons');
|
|
87
|
+
const viewerFaviconPath = () => path_1.default.join(getViewerDirectory(), '..', 'favicon.ico');
|
|
88
|
+
const viewerOperatorDir = () => path_1.default.join(getViewerDirectory(), 'operator');
|
|
89
|
+
// Operator bundle assets live under public/viewer/operator/ and are the only
|
|
90
|
+
// extensions that route serves.
|
|
91
|
+
const VIEWER_OPERATOR_MIME = {
|
|
92
|
+
'.js': 'application/javascript',
|
|
109
93
|
'.css': 'text/css',
|
|
110
|
-
'.json': 'application/json',
|
|
111
|
-
'.svg': 'image/svg+xml',
|
|
112
|
-
'.png': 'image/png',
|
|
113
|
-
'.ico': 'image/x-icon',
|
|
114
|
-
'.woff2': 'application/octet-stream',
|
|
115
94
|
};
|
|
116
|
-
// Agent-authored slot HTML renders inside this SPA. Two independent XSS layers:
|
|
117
|
-
// DOMPurify at render (ui/src/api/report.ts) + this CSP on the document.
|
|
118
|
-
const UI_CSP = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'";
|
|
119
95
|
const DEFAULT_GRAPH_LIMIT = 300;
|
|
120
96
|
exports.DEFAULT_GRAPH_LIMIT = DEFAULT_GRAPH_LIMIT;
|
|
121
97
|
const MAX_GRAPH_LIMIT = 2000;
|
|
@@ -494,10 +470,10 @@ function serveStaticFile(res, filePath, contentType, extraHeaders = {}) {
|
|
|
494
470
|
}
|
|
495
471
|
}
|
|
496
472
|
function handleViewerRequest(_req, res) {
|
|
497
|
-
serveStaticFile(res,
|
|
473
|
+
serveStaticFile(res, viewerHtmlPath(), 'text/html');
|
|
498
474
|
}
|
|
499
475
|
function handleCssRequest(_req, res) {
|
|
500
|
-
serveStaticFile(res,
|
|
476
|
+
serveStaticFile(res, viewerCssPath(), 'text/css');
|
|
501
477
|
}
|
|
502
478
|
async function handleGraphRequest(_req, res, params) {
|
|
503
479
|
const startTime = Date.now();
|
|
@@ -1047,11 +1023,11 @@ function createGraphHandler(options = {}) {
|
|
|
1047
1023
|
res.end();
|
|
1048
1024
|
return true;
|
|
1049
1025
|
}
|
|
1050
|
-
// Route: GET / - redirect to the
|
|
1051
|
-
//
|
|
1026
|
+
// Route: GET / - redirect to /viewer, the ONE public shell. The temporary
|
|
1027
|
+
// /ui SPA route was retired; there is no second face to fall back to.
|
|
1052
1028
|
if (pathname === '/' && req.method === 'GET') {
|
|
1053
|
-
console.log('[GraphHandler] Redirecting / to /
|
|
1054
|
-
res.writeHead(302, { Location: '/
|
|
1029
|
+
console.log('[GraphHandler] Redirecting / to /viewer');
|
|
1030
|
+
res.writeHead(302, { Location: '/viewer' });
|
|
1055
1031
|
res.end();
|
|
1056
1032
|
return true;
|
|
1057
1033
|
}
|
|
@@ -1069,45 +1045,38 @@ function createGraphHandler(options = {}) {
|
|
|
1069
1045
|
}
|
|
1070
1046
|
// Route: GET/HEAD /sw.js - serve Service Worker
|
|
1071
1047
|
if (pathname === '/sw.js' && (req.method === 'GET' || req.method === 'HEAD')) {
|
|
1072
|
-
serveStaticFile(res,
|
|
1048
|
+
serveStaticFile(res, swJsPath(), 'application/javascript');
|
|
1073
1049
|
return true;
|
|
1074
1050
|
}
|
|
1075
1051
|
// Route: GET/HEAD /viewer/sw.js - serve Service Worker (alternative path)
|
|
1076
1052
|
if (pathname === '/viewer/sw.js' && (req.method === 'GET' || req.method === 'HEAD')) {
|
|
1077
|
-
serveStaticFile(res,
|
|
1053
|
+
serveStaticFile(res, swJsPath(), 'application/javascript');
|
|
1078
1054
|
return true;
|
|
1079
1055
|
}
|
|
1080
1056
|
// Route: GET/HEAD /viewer/manifest.json - serve PWA manifest
|
|
1081
1057
|
if (pathname === '/viewer/manifest.json' && (req.method === 'GET' || req.method === 'HEAD')) {
|
|
1082
|
-
serveStaticFile(res,
|
|
1058
|
+
serveStaticFile(res, manifestJsonPath(), 'application/json');
|
|
1083
1059
|
return true;
|
|
1084
1060
|
}
|
|
1085
1061
|
// Route: GET/HEAD /favicon.ico - serve favicon
|
|
1086
1062
|
if (pathname === '/favicon.ico' && (req.method === 'GET' || req.method === 'HEAD')) {
|
|
1087
|
-
serveStaticFile(res,
|
|
1063
|
+
serveStaticFile(res, viewerFaviconPath(), 'image/x-icon');
|
|
1088
1064
|
return true;
|
|
1089
1065
|
}
|
|
1090
|
-
// Route: GET/HEAD /
|
|
1091
|
-
|
|
1066
|
+
// Route: GET/HEAD /viewer/operator/*.{js,css} - operator bundle assets.
|
|
1067
|
+
// Traversal-safe and extension-allowlisted: this route must never become a
|
|
1068
|
+
// generic file server rooted at the viewer directory.
|
|
1069
|
+
if (pathname.startsWith('/viewer/operator/') &&
|
|
1092
1070
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
const resolved = path_1.default.resolve(uiRoot, rel);
|
|
1098
|
-
if (!resolved.startsWith(uiRoot + path_1.default.sep)) {
|
|
1071
|
+
const operatorRoot = viewerOperatorDir();
|
|
1072
|
+
const resolved = path_1.default.resolve(operatorRoot, pathname.slice('/viewer/operator/'.length));
|
|
1073
|
+
const contentType = VIEWER_OPERATOR_MIME[path_1.default.extname(resolved)];
|
|
1074
|
+
if (!resolved.startsWith(operatorRoot + path_1.default.sep) || !contentType) {
|
|
1099
1075
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
1100
1076
|
res.end('Not found');
|
|
1101
1077
|
return true;
|
|
1102
1078
|
}
|
|
1103
|
-
|
|
1104
|
-
const exists = fs_1.default.existsSync(resolved) && fs_1.default.statSync(resolved).isFile();
|
|
1105
|
-
// Missing hashed assets must 404 (via serveStaticFile's ENOENT path) -- an
|
|
1106
|
-
// index.html fallback would mask them as 200 text/html.
|
|
1107
|
-
const target = exists || isAsset ? resolved : path_1.default.join(uiRoot, 'index.html');
|
|
1108
|
-
const contentType = UI_STATIC_MIME[path_1.default.extname(target)] ?? 'application/octet-stream';
|
|
1109
|
-
const extraHeaders = contentType === 'text/html' ? { 'Content-Security-Policy': UI_CSP } : {};
|
|
1110
|
-
serveStaticFile(res, target, contentType, extraHeaders);
|
|
1079
|
+
serveStaticFile(res, resolved, contentType);
|
|
1111
1080
|
return true;
|
|
1112
1081
|
}
|
|
1113
1082
|
// Route: GET/HEAD /viewer/icons/*.png - serve PWA icons
|
|
@@ -1115,7 +1084,7 @@ function createGraphHandler(options = {}) {
|
|
|
1115
1084
|
pathname.endsWith('.png') &&
|
|
1116
1085
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1117
1086
|
const fileName = path_1.default.basename(pathname.split('/').pop() || '');
|
|
1118
|
-
const filePath = path_1.default.join(
|
|
1087
|
+
const filePath = path_1.default.join(viewerIconDir(), fileName);
|
|
1119
1088
|
serveStaticFile(res, filePath, 'image/png');
|
|
1120
1089
|
return true;
|
|
1121
1090
|
}
|
|
@@ -1124,7 +1093,7 @@ function createGraphHandler(options = {}) {
|
|
|
1124
1093
|
pathname.endsWith('.svg') &&
|
|
1125
1094
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1126
1095
|
const fileName = path_1.default.basename(pathname.split('/').pop() || '');
|
|
1127
|
-
const filePath = path_1.default.join(
|
|
1096
|
+
const filePath = path_1.default.join(viewerIconDir(), fileName);
|
|
1128
1097
|
serveStaticFile(res, filePath, 'image/svg+xml');
|
|
1129
1098
|
return true;
|
|
1130
1099
|
}
|
|
@@ -1133,7 +1102,7 @@ function createGraphHandler(options = {}) {
|
|
|
1133
1102
|
pathname.endsWith('.js') &&
|
|
1134
1103
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1135
1104
|
const fileName = pathname.split('/').pop();
|
|
1136
|
-
const filePath = path_1.default.join(
|
|
1105
|
+
const filePath = path_1.default.join(getViewerDirectory(), 'js', 'utils', fileName);
|
|
1137
1106
|
serveStaticFile(res, filePath, 'application/javascript');
|
|
1138
1107
|
return true;
|
|
1139
1108
|
}
|
|
@@ -1144,7 +1113,7 @@ function createGraphHandler(options = {}) {
|
|
|
1144
1113
|
pathname.endsWith('.js') &&
|
|
1145
1114
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1146
1115
|
const fileName = pathname.split('/').pop();
|
|
1147
|
-
const filePath = path_1.default.join(
|
|
1116
|
+
const filePath = path_1.default.join(getViewerDirectory(), 'js', fileName);
|
|
1148
1117
|
serveStaticFile(res, filePath, 'application/javascript');
|
|
1149
1118
|
return true;
|
|
1150
1119
|
}
|
|
@@ -1153,7 +1122,7 @@ function createGraphHandler(options = {}) {
|
|
|
1153
1122
|
pathname.endsWith('.js') &&
|
|
1154
1123
|
(req.method === 'GET' || req.method === 'HEAD')) {
|
|
1155
1124
|
const fileName = pathname.split('/').pop();
|
|
1156
|
-
const filePath = path_1.default.join(
|
|
1125
|
+
const filePath = path_1.default.join(getViewerDirectory(), 'js', 'modules', fileName);
|
|
1157
1126
|
serveStaticFile(res, filePath, 'application/javascript');
|
|
1158
1127
|
return true;
|
|
1159
1128
|
}
|