humanish 0.16.0 → 0.18.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 +54 -3
- package/dist/actor-contract.d.ts +1 -1
- package/dist/actor-contract.js.map +1 -1
- package/dist/computer-use.js +33 -5
- package/dist/computer-use.js.map +1 -1
- package/dist/cua-actor-lab.d.ts +1 -1
- package/dist/cua-actor-lab.js.map +1 -1
- package/dist/observer-library.d.ts +19 -0
- package/dist/observer-library.js +184 -0
- package/dist/observer-library.js.map +1 -0
- package/dist/observer-serve.d.ts +99 -0
- package/dist/observer-serve.js +289 -0
- package/dist/observer-serve.js.map +1 -0
- package/dist/observer.d.ts +34 -0
- package/dist/observer.js +57 -5
- package/dist/observer.js.map +1 -1
- package/dist/program.js +433 -19
- package/dist/program.js.map +1 -1
- package/dist/serve-exposure.d.ts +62 -0
- package/dist/serve-exposure.js +129 -0
- package/dist/serve-exposure.js.map +1 -0
- package/dist/serve-http.d.ts +8 -0
- package/dist/serve-http.js +37 -0
- package/dist/serve-http.js.map +1 -0
- package/dist/serve-tunnel.d.ts +20 -0
- package/dist/serve-tunnel.js +113 -0
- package/dist/serve-tunnel.js.map +1 -0
- package/docs/architecture/actor-contract.md +29 -3
- package/docs/architecture/observer.md +37 -0
- package/docs/architecture/serve.md +196 -0
- package/docs/contracts/schemas.md +33 -2
- package/docs/goals/current.md +2 -1
- package/docs/principles/invariants-and-defaults.md +2 -0
- package/docs/ramp/README.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const STATUS_TONES = {
|
|
2
|
+
passed: "#3fb970",
|
|
3
|
+
running: "#4f8ff7",
|
|
4
|
+
failed: "#e5534b",
|
|
5
|
+
blocked: "#d29922",
|
|
6
|
+
timed_out: "#d29922"
|
|
7
|
+
};
|
|
8
|
+
export function renderLibraryHtml(history, opts) {
|
|
9
|
+
const emptyState = opts.safe
|
|
10
|
+
? "No share_ready runs yet — run `humanish verify` to see why."
|
|
11
|
+
: "No runs yet — run `humanish watch` to create one.";
|
|
12
|
+
return `<!doctype html>
|
|
13
|
+
<html lang="en" data-theme="dark">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="utf-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
17
|
+
<title>Humanish Library</title>
|
|
18
|
+
<style>${libraryCss()}</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<header class="bar">
|
|
22
|
+
<span class="mark">humanish</span>
|
|
23
|
+
<span class="title">Run Library</span>
|
|
24
|
+
<span class="mode">${escapeHtml(modeLabel(opts))}</span>
|
|
25
|
+
</header>
|
|
26
|
+
<main>
|
|
27
|
+
<p class="note" id="note" hidden></p>
|
|
28
|
+
<ul class="runs" id="runs"></ul>
|
|
29
|
+
<p class="empty" id="empty" hidden>${escapeHtml(emptyState)}</p>
|
|
30
|
+
</main>
|
|
31
|
+
<script type="application/json" id="serve-capabilities">${escapeJsonScript(opts.capabilities)}</script>
|
|
32
|
+
<script type="application/json" id="library-data">${escapeJsonScript(history)}</script>
|
|
33
|
+
<script>${libraryClientJs()}</script>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
function modeLabel(opts) {
|
|
39
|
+
const auth = opts.mode === "exposed" ? "edge-authed" : opts.mode === "share-safe-open" ? "open" : "loopback";
|
|
40
|
+
return opts.safe ? `${auth} · share_ready only` : auth;
|
|
41
|
+
}
|
|
42
|
+
function libraryCss() {
|
|
43
|
+
return `
|
|
44
|
+
:root { color-scheme: dark; }
|
|
45
|
+
* { box-sizing: border-box; margin: 0; }
|
|
46
|
+
body {
|
|
47
|
+
background: #0c0e12; color: #e6e8ec; min-height: 100vh;
|
|
48
|
+
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
49
|
+
}
|
|
50
|
+
.bar {
|
|
51
|
+
display: flex; align-items: baseline; gap: 0.6rem;
|
|
52
|
+
padding: 1rem 1.1rem; border-bottom: 1px solid #1e222b;
|
|
53
|
+
position: sticky; top: 0; background: rgba(12,14,18,0.95); backdrop-filter: blur(6px);
|
|
54
|
+
}
|
|
55
|
+
.mark { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-weight: 600; color: #9aa3b2; }
|
|
56
|
+
.title { font-weight: 600; }
|
|
57
|
+
.mode { margin-left: auto; font-size: 0.75rem; color: #9aa3b2; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
|
|
58
|
+
main { padding: 1rem 1.1rem 3rem; max-width: 44rem; margin: 0 auto; }
|
|
59
|
+
.note { font-size: 0.8rem; color: #d29922; padding: 0.5rem 0; }
|
|
60
|
+
.runs { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
|
|
61
|
+
.runs a {
|
|
62
|
+
display: block; text-decoration: none; color: inherit;
|
|
63
|
+
border: 1px solid #1e222b; border-radius: 10px; padding: 0.8rem 0.9rem; background: #11141a;
|
|
64
|
+
}
|
|
65
|
+
.runs a:active { background: #171b23; }
|
|
66
|
+
.run-top { display: flex; align-items: center; gap: 0.5rem; }
|
|
67
|
+
.pip { width: 9px; height: 9px; border-radius: 50%; flex: none; }
|
|
68
|
+
.pip.running { animation: pulse 1.6s ease-in-out infinite; }
|
|
69
|
+
@keyframes pulse { 50% { opacity: 0.35; } }
|
|
70
|
+
.run-id {
|
|
71
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 0.8rem;
|
|
72
|
+
overflow-wrap: anywhere;
|
|
73
|
+
}
|
|
74
|
+
.badge {
|
|
75
|
+
margin-left: auto; flex: none; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.06em;
|
|
76
|
+
border: 1px solid #2c5f8a; color: #7cb8ec; border-radius: 999px; padding: 0.1rem 0.5rem;
|
|
77
|
+
}
|
|
78
|
+
.badge.latest { border-color: #3fb970; color: #7ee2a8; }
|
|
79
|
+
.run-meta { margin-top: 0.35rem; font-size: 0.75rem; color: #9aa3b2; }
|
|
80
|
+
.empty { color: #9aa3b2; font-size: 0.85rem; padding: 2rem 0; text-align: center; }
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
function libraryClientJs() {
|
|
84
|
+
const tones = JSON.stringify(STATUS_TONES);
|
|
85
|
+
return `
|
|
86
|
+
(function () {
|
|
87
|
+
var TONES = ${tones};
|
|
88
|
+
var POLL_MS = 15000;
|
|
89
|
+
var stopped = false;
|
|
90
|
+
|
|
91
|
+
function render(history) {
|
|
92
|
+
var list = document.getElementById("runs");
|
|
93
|
+
var empty = document.getElementById("empty");
|
|
94
|
+
list.textContent = "";
|
|
95
|
+
var runs = history.runs || [];
|
|
96
|
+
empty.hidden = runs.length !== 0;
|
|
97
|
+
for (var i = 0; i < runs.length; i += 1) {
|
|
98
|
+
var run = runs[i];
|
|
99
|
+
var item = document.createElement("li");
|
|
100
|
+
var link = document.createElement("a");
|
|
101
|
+
link.href = run.href;
|
|
102
|
+
var top = document.createElement("div");
|
|
103
|
+
top.className = "run-top";
|
|
104
|
+
var pip = document.createElement("span");
|
|
105
|
+
pip.className = run.status === "running" ? "pip running" : "pip";
|
|
106
|
+
pip.style.background = TONES[run.status] || "#57606f";
|
|
107
|
+
var id = document.createElement("span");
|
|
108
|
+
id.className = "run-id";
|
|
109
|
+
id.textContent = run.runId;
|
|
110
|
+
top.appendChild(pip);
|
|
111
|
+
top.appendChild(id);
|
|
112
|
+
if (run.runId === history.latestRunId) {
|
|
113
|
+
var latest = document.createElement("span");
|
|
114
|
+
latest.className = "badge latest";
|
|
115
|
+
latest.textContent = "latest";
|
|
116
|
+
top.appendChild(latest);
|
|
117
|
+
} else if (run.status === "running") {
|
|
118
|
+
var live = document.createElement("span");
|
|
119
|
+
live.className = "badge";
|
|
120
|
+
live.textContent = "live";
|
|
121
|
+
top.appendChild(live);
|
|
122
|
+
}
|
|
123
|
+
var meta = document.createElement("div");
|
|
124
|
+
meta.className = "run-meta";
|
|
125
|
+
meta.textContent = [run.mode || "unknown", run.streamCount + " lanes", run.createdAt || ""].filter(Boolean).join(" \\u00b7 ");
|
|
126
|
+
link.appendChild(top);
|
|
127
|
+
link.appendChild(meta);
|
|
128
|
+
item.appendChild(link);
|
|
129
|
+
list.appendChild(item);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function note(text) {
|
|
134
|
+
var element = document.getElementById("note");
|
|
135
|
+
element.hidden = !text;
|
|
136
|
+
element.textContent = text || "";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function poll() {
|
|
140
|
+
if (stopped) return;
|
|
141
|
+
fetch("/_humanish/history.json", { cache: "no-store" }).then(function (response) {
|
|
142
|
+
return response.json();
|
|
143
|
+
}).then(function (history) {
|
|
144
|
+
if (history) {
|
|
145
|
+
note("");
|
|
146
|
+
render(history);
|
|
147
|
+
}
|
|
148
|
+
}).catch(function () {
|
|
149
|
+
note("connection lost \\u2014 retrying");
|
|
150
|
+
}).then(function () {
|
|
151
|
+
if (!stopped) setTimeout(poll, POLL_MS);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
render(JSON.parse(document.getElementById("library-data").textContent));
|
|
156
|
+
setTimeout(poll, POLL_MS);
|
|
157
|
+
})();
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
function escapeHtml(value) {
|
|
161
|
+
return value.replace(/[&<>"']/g, (char) => {
|
|
162
|
+
switch (char) {
|
|
163
|
+
case "&":
|
|
164
|
+
return "&";
|
|
165
|
+
case "<":
|
|
166
|
+
return "<";
|
|
167
|
+
case ">":
|
|
168
|
+
return ">";
|
|
169
|
+
case "\"":
|
|
170
|
+
return """;
|
|
171
|
+
default:
|
|
172
|
+
return "'";
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
function escapeJsonScript(value) {
|
|
177
|
+
return JSON.stringify(value)
|
|
178
|
+
.replace(/</g, "\\u003c")
|
|
179
|
+
.replace(/>/g, "\\u003e")
|
|
180
|
+
.replace(/&/g, "\\u0026")
|
|
181
|
+
.replace(/\u2028/g, "\\u2028")
|
|
182
|
+
.replace(/\u2029/g, "\\u2029");
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=observer-library.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-library.js","sourceRoot":"","sources":["../src/observer-library.ts"],"names":[],"mappings":"AAkBA,MAAM,YAAY,GAA2B;IAC3C,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,SAAS;CACrB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,OAAuB,EAAE,IAA0B;IACnF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI;QAC1B,CAAC,CAAC,6DAA6D;QAC/D,CAAC,CAAC,mDAAmD,CAAC;IAExD,OAAO;;;;;;SAMA,UAAU,EAAE;;;;;;uBAME,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;;;;;uCAKX,UAAU,CAAC,UAAU,CAAC;;0DAEH,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC;oDACzC,gBAAgB,CAAC,OAAO,CAAC;UACnE,eAAe,EAAE;;;CAG1B,CAAC;AACF,CAAC;AAED,SAAS,SAAS,CAAC,IAA0B;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7G,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,CAAC;AAED,SAAS,UAAU;IACjB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCR,CAAC;AACF,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC3C,OAAO;;gBAEO,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuEpB,CAAC;AACF,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;QACxC,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,GAAG;gBACN,OAAO,OAAO,CAAC;YACjB,KAAK,GAAG;gBACN,OAAO,MAAM,CAAC;YAChB,KAAK,GAAG;gBACN,OAAO,MAAM,CAAC;YAChB,KAAK,IAAI;gBACP,OAAO,QAAQ,CAAC;YAClB;gBACE,OAAO,OAAO,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SACzB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC;SAC7B,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { PinnedDirectory } from "./observer.js";
|
|
3
|
+
import type { LibraryHistory } from "./observer-library.js";
|
|
4
|
+
import { buildServeSecurityHeaders, hostAllowed, parsePublicOrigin, type ServeMode } from "./serve-http.js";
|
|
5
|
+
import type { ExposureErrorCode } from "./serve-exposure.js";
|
|
6
|
+
import { verifyRun } from "./run.js";
|
|
7
|
+
export declare const SERVE_SCHEMA = "humanish.serve-result.v1";
|
|
8
|
+
export { buildServeSecurityHeaders, hostAllowed, parsePublicOrigin };
|
|
9
|
+
export type { ServeMode };
|
|
10
|
+
export type ServeErrorCode = "HUMANISH_INVALID_PORT" | "HUMANISH_SERVE_TUNNEL_NOT_FOUND" | "HUMANISH_SERVE_TUNNEL_START_FAILED" | "HUMANISH_RUN_NOT_FOUND" | "HUMANISH_SERVE_RUN_NOT_SHAREABLE" | ExposureErrorCode;
|
|
11
|
+
export interface ServeResult {
|
|
12
|
+
schema: typeof SERVE_SCHEMA;
|
|
13
|
+
ok: boolean;
|
|
14
|
+
cwd: string;
|
|
15
|
+
mode: ServeMode;
|
|
16
|
+
safe: boolean;
|
|
17
|
+
host: "127.0.0.1";
|
|
18
|
+
port?: number;
|
|
19
|
+
url?: string;
|
|
20
|
+
publicUrl?: string;
|
|
21
|
+
tunnel?: {
|
|
22
|
+
provider: "ngrok";
|
|
23
|
+
url: string;
|
|
24
|
+
};
|
|
25
|
+
oauth?: {
|
|
26
|
+
provider: "google";
|
|
27
|
+
allowEmails: string[];
|
|
28
|
+
allowDomains: string[];
|
|
29
|
+
};
|
|
30
|
+
runsListed: number;
|
|
31
|
+
shareReadyCount?: number;
|
|
32
|
+
entryRunId?: string;
|
|
33
|
+
opened?: boolean;
|
|
34
|
+
openCommand?: string;
|
|
35
|
+
warnings: string[];
|
|
36
|
+
error?: {
|
|
37
|
+
code: ServeErrorCode;
|
|
38
|
+
message: string;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface ServeControlPlane {
|
|
42
|
+
startRun?(request: {
|
|
43
|
+
labId: string;
|
|
44
|
+
dryRun: boolean;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
accepted: boolean;
|
|
47
|
+
runId?: string;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export interface ShareSafetyAdmission {
|
|
51
|
+
admit(runId: string): Promise<boolean>;
|
|
52
|
+
}
|
|
53
|
+
export declare function createShareSafetyAdmission(cwd: string, options?: {
|
|
54
|
+
verifyImpl?: typeof verifyRun;
|
|
55
|
+
ttlMs?: number;
|
|
56
|
+
now?: () => number;
|
|
57
|
+
}): ShareSafetyAdmission;
|
|
58
|
+
export interface ServeRequestHandlerOptions {
|
|
59
|
+
proofRoot: PinnedDirectory;
|
|
60
|
+
safe: boolean;
|
|
61
|
+
admit: (runId: string) => Promise<boolean>;
|
|
62
|
+
hostAllowlist: ReadonlySet<string>;
|
|
63
|
+
entryRunId?: string;
|
|
64
|
+
renderLibrary: (history: LibraryHistory) => string;
|
|
65
|
+
controlPlane?: ServeControlPlane;
|
|
66
|
+
}
|
|
67
|
+
export declare function createServeRequestHandler(options: ServeRequestHandlerOptions): (request: IncomingMessage, response: ServerResponse) => Promise<void>;
|
|
68
|
+
export interface ServeLibraryOptions {
|
|
69
|
+
port: number;
|
|
70
|
+
safe: boolean;
|
|
71
|
+
expose: boolean;
|
|
72
|
+
edgeAuthed: boolean;
|
|
73
|
+
publicOrigin?: string;
|
|
74
|
+
entryRunId?: string;
|
|
75
|
+
controlPlane?: ServeControlPlane;
|
|
76
|
+
verifyImpl?: typeof verifyRun;
|
|
77
|
+
now?: () => number;
|
|
78
|
+
}
|
|
79
|
+
export interface ServeLibraryServer {
|
|
80
|
+
url: string;
|
|
81
|
+
port: number;
|
|
82
|
+
mode: ServeMode;
|
|
83
|
+
runsListed: number;
|
|
84
|
+
shareReadyCount?: number;
|
|
85
|
+
entryRunId?: string;
|
|
86
|
+
addPublicOrigin(origin: string): void;
|
|
87
|
+
close(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
export type ServeLibraryStart = {
|
|
90
|
+
ok: true;
|
|
91
|
+
server: ServeLibraryServer;
|
|
92
|
+
} | {
|
|
93
|
+
ok: false;
|
|
94
|
+
error: {
|
|
95
|
+
code: ServeErrorCode;
|
|
96
|
+
message: string;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
export declare function serveObserverLibrary(cwdInput: string, options: ServeLibraryOptions): Promise<ServeLibraryStart>;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { lstat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { buildHistoryIndex, matchRunRoute, pinDirectChildDirectory, pinDirectory, serveRunPath } from "./observer.js";
|
|
5
|
+
import { renderLibraryHtml } from "./observer-library.js";
|
|
6
|
+
import { buildServeSecurityHeaders, hostAllowed, parsePublicOrigin } from "./serve-http.js";
|
|
7
|
+
import { listRuns, verifyRun } from "./run.js";
|
|
8
|
+
export const SERVE_SCHEMA = "humanish.serve-result.v1";
|
|
9
|
+
// Re-exported for compat: these hardening primitives now live in serve-http.js so the live Observer
|
|
10
|
+
// server can share them without a module cycle.
|
|
11
|
+
export { buildServeSecurityHeaders, hostAllowed, parsePublicOrigin };
|
|
12
|
+
export function createShareSafetyAdmission(cwd, options = {}) {
|
|
13
|
+
const verifyImpl = options.verifyImpl ?? verifyRun;
|
|
14
|
+
const now = options.now ?? (() => Date.now());
|
|
15
|
+
// verifyRun scans the ENTIRE run tree, but the cache key is run.json's stat
|
|
16
|
+
// identity, so an out-of-band edit to a scanned artifact that leaves run.json
|
|
17
|
+
// untouched would otherwise keep a stale share_ready verdict. A short TTL
|
|
18
|
+
// bounds that window: any mutation is re-scanned within ttlMs even when
|
|
19
|
+
// run.json never changes. Defense in depth on top of pre-persist redaction.
|
|
20
|
+
const ttlMs = options.ttlMs ?? 30_000;
|
|
21
|
+
const cache = new Map();
|
|
22
|
+
const bundleIdentity = async (runId) => {
|
|
23
|
+
try {
|
|
24
|
+
const stats = await lstat(path.join(cwd, ".humanish", "runs", runId, "run.json"), { bigint: true });
|
|
25
|
+
if (!stats.isFile()) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return `${stats.dev}:${stats.ino}:${stats.mtimeNs}:${stats.size}`;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
async admit(runId) {
|
|
36
|
+
const identity = await bundleIdentity(runId);
|
|
37
|
+
if (!identity) {
|
|
38
|
+
cache.delete(runId);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const cached = cache.get(runId);
|
|
42
|
+
if (cached && cached.identity === identity && now() - cached.verifiedAt < ttlMs) {
|
|
43
|
+
return cached.admitted;
|
|
44
|
+
}
|
|
45
|
+
const admitted = verifyImpl(cwd, runId)
|
|
46
|
+
.then((verified) => verified.ok === true && verified.shareSafety.status === "share_ready")
|
|
47
|
+
.catch(() => false);
|
|
48
|
+
cache.set(runId, { identity, verifiedAt: now(), admitted });
|
|
49
|
+
return admitted;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function createServeRequestHandler(options) {
|
|
54
|
+
return async (request, response) => {
|
|
55
|
+
try {
|
|
56
|
+
for (const [name, value] of Object.entries(buildServeSecurityHeaders())) {
|
|
57
|
+
response.setHeader(name, value);
|
|
58
|
+
}
|
|
59
|
+
const method = request.method ?? "GET";
|
|
60
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
61
|
+
writeText(response, 405, "Method Not Allowed");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!hostAllowed(request.headers.host, options.hostAllowlist)) {
|
|
65
|
+
writeText(response, 421, "Misdirected Request");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "127.0.0.1"}`);
|
|
69
|
+
if (url.pathname === "/_humanish/api" || url.pathname.startsWith("/_humanish/api/")) {
|
|
70
|
+
writeText(response, 501, `${JSON.stringify({
|
|
71
|
+
error: {
|
|
72
|
+
code: "HUMANISH_SERVE_CONTROL_PLANE_DISABLED",
|
|
73
|
+
message: "control plane not enabled in this version"
|
|
74
|
+
}
|
|
75
|
+
}, null, 2)}\n`, "application/json; charset=utf-8");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (url.pathname === "/") {
|
|
79
|
+
if (options.entryRunId) {
|
|
80
|
+
response.writeHead(302, {
|
|
81
|
+
location: `/_humanish/runs/${encodeURIComponent(options.entryRunId)}/observer/index.html`
|
|
82
|
+
});
|
|
83
|
+
response.end();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const history = await loadFilteredHistory(options);
|
|
87
|
+
writeText(response, 200, options.renderLibrary(history), "text/html; charset=utf-8");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (url.pathname === "/_humanish/history.json") {
|
|
91
|
+
const history = await loadFilteredHistory(options);
|
|
92
|
+
writeText(response, 200, JSON.stringify(history, null, 2), "application/json; charset=utf-8");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (url.pathname.startsWith("/_humanish/runs/")) {
|
|
96
|
+
const runRoute = matchRunRoute(url.pathname);
|
|
97
|
+
if (!runRoute) {
|
|
98
|
+
writeText(response, 404, "Run not found");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (options.safe && !(await options.admit(runRoute.runId))) {
|
|
102
|
+
// Byte-identical to the nonexistent-run 404: no existence oracle.
|
|
103
|
+
writeText(response, 404, "Run not found");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const targetRoot = await pinDirectChildDirectory(options.proofRoot, runRoute.runId);
|
|
107
|
+
if (!targetRoot) {
|
|
108
|
+
writeText(response, 404, "Run not found");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// The explicit empty runtimeStreamUrls keeps a future refactor from
|
|
112
|
+
// reintroducing auth-keyed stream injection on the serve surface.
|
|
113
|
+
await serveRunPath(targetRoot, runRoute.relativePath || "observer/index.html", response, []);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
writeText(response, 404, "Not found");
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
writeText(response, 500, "Observer request failed");
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async function loadFilteredHistory(options) {
|
|
124
|
+
const history = await buildHistoryIndex(options.proofRoot);
|
|
125
|
+
if (!options.safe) {
|
|
126
|
+
return history;
|
|
127
|
+
}
|
|
128
|
+
const admissions = await Promise.all(history.runs.map(async (run) => ((await options.admit(run.runId)) === true ? run : null)));
|
|
129
|
+
const runs = admissions.filter((run) => run !== null);
|
|
130
|
+
const latestRunId = runs.some((run) => run.runId === history.latestRunId)
|
|
131
|
+
? history.latestRunId
|
|
132
|
+
: runs[0]?.runId ?? null;
|
|
133
|
+
return { latestRunId, runs };
|
|
134
|
+
}
|
|
135
|
+
export async function serveObserverLibrary(cwdInput, options) {
|
|
136
|
+
const cwd = path.resolve(cwdInput);
|
|
137
|
+
const verifyImpl = options.verifyImpl ?? verifyRun;
|
|
138
|
+
let proofRoot;
|
|
139
|
+
try {
|
|
140
|
+
proofRoot = await pinDirectory(path.join(cwd, ".humanish", "runs"));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
error: {
|
|
146
|
+
code: "HUMANISH_RUN_NOT_FOUND",
|
|
147
|
+
message: "No run library found under .humanish/runs. Run `humanish watch` to create the first run."
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const admission = createShareSafetyAdmission(cwd, {
|
|
152
|
+
verifyImpl,
|
|
153
|
+
...(options.now ? { now: options.now } : {})
|
|
154
|
+
});
|
|
155
|
+
// Exposure auth is tunnel-edge only. Under --expose, an edge-authed surface (ngrok --oauth or an
|
|
156
|
+
// operator --public-url) serves every run (mode "exposed"); an un-authed surface is admissible
|
|
157
|
+
// only because --safe narrows it to share_ready runs (mode "share-safe-open").
|
|
158
|
+
const mode = options.expose
|
|
159
|
+
? options.edgeAuthed ? "exposed" : "share-safe-open"
|
|
160
|
+
: "loopback";
|
|
161
|
+
let entryRunId;
|
|
162
|
+
if (options.entryRunId) {
|
|
163
|
+
const resolved = options.entryRunId === "latest"
|
|
164
|
+
? (await listRuns(cwd)).latest ?? null
|
|
165
|
+
: options.entryRunId;
|
|
166
|
+
const pinned = resolved ? await pinDirectChildDirectory(proofRoot, resolved) : null;
|
|
167
|
+
if (!resolved || !pinned) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: { code: "HUMANISH_RUN_NOT_FOUND", message: `Run not found: ${options.entryRunId}` }
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (options.safe && !(await admission.admit(resolved))) {
|
|
174
|
+
const verified = await verifyImpl(cwd, resolved).catch(() => null);
|
|
175
|
+
const status = verified?.shareSafety.status ?? "unverifiable";
|
|
176
|
+
const reasons = verified?.shareSafety.reasons.map((reason) => reason.code).join(", ") || "VERIFY_FAILED";
|
|
177
|
+
return {
|
|
178
|
+
ok: false,
|
|
179
|
+
error: {
|
|
180
|
+
code: "HUMANISH_SERVE_RUN_NOT_SHAREABLE",
|
|
181
|
+
message: `Run ${resolved} is not share_ready (shareSafety: ${status}; reasons: ${reasons}); --safe refuses to serve it.`
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
entryRunId = resolved;
|
|
186
|
+
}
|
|
187
|
+
// Counts are computed over the UNCAPPED run list, not the 80-item history
|
|
188
|
+
// index: an edge-authed surface (non-safe) grants access to every run by direct
|
|
189
|
+
// URL, and share-safe modes admit every share_ready run per request, so a
|
|
190
|
+
// count capped at 80 would understate exactly what the exposure warning
|
|
191
|
+
// claims. runsListed feeds the operator's declared-friction warning.
|
|
192
|
+
const allRuns = (await listRuns(cwd)).runs;
|
|
193
|
+
let runsListed;
|
|
194
|
+
let shareReadyCount;
|
|
195
|
+
if (options.safe) {
|
|
196
|
+
const admitted = await Promise.all(allRuns.map((run) => admission.admit(run.runId)));
|
|
197
|
+
shareReadyCount = admitted.filter(Boolean).length;
|
|
198
|
+
runsListed = shareReadyCount;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
runsListed = allRuns.length;
|
|
202
|
+
}
|
|
203
|
+
const declaredOrigin = options.publicOrigin ? parsePublicOrigin(options.publicOrigin) : null;
|
|
204
|
+
const hostAllowlist = new Set();
|
|
205
|
+
const handler = createServeRequestHandler({
|
|
206
|
+
proofRoot,
|
|
207
|
+
safe: options.safe,
|
|
208
|
+
admit: (runId) => admission.admit(runId),
|
|
209
|
+
hostAllowlist,
|
|
210
|
+
...(entryRunId ? { entryRunId } : {}),
|
|
211
|
+
renderLibrary: (history) => renderLibraryHtml(history, {
|
|
212
|
+
mode,
|
|
213
|
+
safe: options.safe,
|
|
214
|
+
capabilities: { actions: false }
|
|
215
|
+
}),
|
|
216
|
+
...(options.controlPlane ? { controlPlane: options.controlPlane } : {})
|
|
217
|
+
});
|
|
218
|
+
const server = createServer((request, response) => {
|
|
219
|
+
void handler(request, response);
|
|
220
|
+
});
|
|
221
|
+
const port = await listen(server, options.port);
|
|
222
|
+
hostAllowlist.add(`127.0.0.1:${port}`);
|
|
223
|
+
hostAllowlist.add(`localhost:${port}`);
|
|
224
|
+
hostAllowlist.add(`[::1]:${port}`);
|
|
225
|
+
if (declaredOrigin) {
|
|
226
|
+
hostAllowlist.add(declaredOrigin.host);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
ok: true,
|
|
230
|
+
server: {
|
|
231
|
+
url: `http://127.0.0.1:${port}/`,
|
|
232
|
+
port,
|
|
233
|
+
mode,
|
|
234
|
+
runsListed,
|
|
235
|
+
...(shareReadyCount !== undefined ? { shareReadyCount } : {}),
|
|
236
|
+
...(entryRunId ? { entryRunId } : {}),
|
|
237
|
+
// A tunnel's public origin is only known after the tunnel starts (post bind); this lets the
|
|
238
|
+
// caller declare it, extending the Host allowlist so the authenticated edge forwarding under
|
|
239
|
+
// that Host is admitted. Never flips any in-process auth flag (there is none).
|
|
240
|
+
addPublicOrigin(origin) {
|
|
241
|
+
const parsed = parsePublicOrigin(origin);
|
|
242
|
+
if (!parsed) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
hostAllowlist.add(parsed.host);
|
|
246
|
+
},
|
|
247
|
+
close: async () => {
|
|
248
|
+
const closed = closeServer(server);
|
|
249
|
+
// Keep-alive sockets would otherwise keep close() pending past the point
|
|
250
|
+
// the operator believes Ctrl-C tore the server down.
|
|
251
|
+
server.closeAllConnections?.();
|
|
252
|
+
await closed;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function writeText(response, status, body, contentType = "text/plain; charset=utf-8") {
|
|
258
|
+
response.writeHead(status, { "content-type": contentType });
|
|
259
|
+
response.end(body);
|
|
260
|
+
}
|
|
261
|
+
function listen(server, port) {
|
|
262
|
+
return new Promise((resolve, reject) => {
|
|
263
|
+
server.once("error", reject);
|
|
264
|
+
// The serve surface never binds beyond loopback; exposure only ever happens
|
|
265
|
+
// through a tunnel or proxy forwarding to this port.
|
|
266
|
+
server.listen(port, "127.0.0.1", () => {
|
|
267
|
+
server.off("error", reject);
|
|
268
|
+
const address = server.address();
|
|
269
|
+
if (!address || typeof address === "string") {
|
|
270
|
+
reject(new Error("Serve library server did not bind to a TCP port."));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
resolve(address.port);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function closeServer(server) {
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
server.close((error) => {
|
|
280
|
+
if (error) {
|
|
281
|
+
reject(error);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
resolve();
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=observer-serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-serve.js","sourceRoot":"","sources":["../src/observer-serve.ts"],"names":[],"mappings":"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"}
|
package/dist/observer.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ServerResponse } from "node:http";
|
|
1
2
|
export declare const OBSERVER_SCHEMA = "humanish.observer-result.v1";
|
|
2
3
|
export interface ObserverResult {
|
|
3
4
|
schema: typeof OBSERVER_SCHEMA;
|
|
@@ -24,21 +25,54 @@ export interface ObserverOptions {
|
|
|
24
25
|
export interface ObserverServeOptions {
|
|
25
26
|
open?: boolean;
|
|
26
27
|
port?: number;
|
|
28
|
+
exposed?: boolean;
|
|
27
29
|
}
|
|
28
30
|
export interface ObserverServer {
|
|
29
31
|
url: string;
|
|
32
|
+
port: number;
|
|
30
33
|
opened: boolean;
|
|
31
34
|
openCommand?: string;
|
|
32
35
|
warning?: string;
|
|
36
|
+
addPublicOrigin(origin: string): void;
|
|
33
37
|
close(): Promise<void>;
|
|
34
38
|
}
|
|
35
39
|
export interface ObserverRuntimeStreamUrl {
|
|
36
40
|
streamId: string;
|
|
37
41
|
url: string;
|
|
38
42
|
}
|
|
43
|
+
/** internal: consumed by observer-serve */
|
|
44
|
+
export interface PinnedDirectory {
|
|
45
|
+
readonly birthtimeNs: bigint;
|
|
46
|
+
readonly dev: bigint;
|
|
47
|
+
readonly ino: bigint;
|
|
48
|
+
readonly physicalPath: string;
|
|
49
|
+
}
|
|
39
50
|
export declare function attachObserverRuntimeStreamUrls(result: ObserverResult, streams: ObserverRuntimeStreamUrl[]): void;
|
|
40
51
|
export declare function renderObserver(cwdInput: string, runInput: string, options?: ObserverOptions): Promise<ObserverResult>;
|
|
41
52
|
export declare function serveObserver(result: ObserverResult, options?: ObserverServeOptions): Promise<ObserverServer>;
|
|
53
|
+
/** internal: consumed by observer-serve */
|
|
54
|
+
export declare function serveRunPath(runRoot: PinnedDirectory, relativePath: string, response: ServerResponse, runtimeStreamUrls?: ObserverRuntimeStreamUrl[]): Promise<void>;
|
|
55
|
+
/** internal: consumed by observer-serve */
|
|
56
|
+
export declare function buildHistoryIndex(proofRoot: PinnedDirectory): Promise<{
|
|
57
|
+
latestRunId: string | null;
|
|
58
|
+
runs: Array<{
|
|
59
|
+
runId: string;
|
|
60
|
+
createdAt: string | null;
|
|
61
|
+
mode: string | null;
|
|
62
|
+
href: string;
|
|
63
|
+
status: string;
|
|
64
|
+
streamCount: number;
|
|
65
|
+
}>;
|
|
66
|
+
}>;
|
|
67
|
+
/** internal: consumed by observer-serve */
|
|
68
|
+
export declare function matchRunRoute(pathname: string): {
|
|
69
|
+
runId: string;
|
|
70
|
+
relativePath: string;
|
|
71
|
+
} | null;
|
|
72
|
+
/** internal: consumed by observer-serve */
|
|
73
|
+
export declare function pinDirectory(directoryInput: string): Promise<PinnedDirectory>;
|
|
74
|
+
/** internal: consumed by observer-serve */
|
|
75
|
+
export declare function pinDirectChildDirectory(root: PinnedDirectory, name: string): Promise<PinnedDirectory | null>;
|
|
42
76
|
export declare function openTarget(target: string): {
|
|
43
77
|
opened: boolean;
|
|
44
78
|
command?: string;
|