@h-rig/server 0.0.6-alpha.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.
Files changed (60) hide show
  1. package/README.md +14 -0
  2. package/dist/src/bootstrap.js +161 -0
  3. package/dist/src/index.js +13153 -0
  4. package/dist/src/inspector/agent-runtime.js +1077 -0
  5. package/dist/src/inspector/analysis.js +41 -0
  6. package/dist/src/inspector/discovery.js +137 -0
  7. package/dist/src/inspector/journal.js +518 -0
  8. package/dist/src/inspector/mission.js +562 -0
  9. package/dist/src/inspector/prompt.js +97 -0
  10. package/dist/src/inspector/provider-session.js +65 -0
  11. package/dist/src/inspector/reconcile.js +118 -0
  12. package/dist/src/inspector/review.js +13 -0
  13. package/dist/src/inspector/service.js +1759 -0
  14. package/dist/src/inspector/skills.js +155 -0
  15. package/dist/src/inspector/tools.js +1592 -0
  16. package/dist/src/inspector/types.js +1 -0
  17. package/dist/src/inspector/upstream-sync.js +479 -0
  18. package/dist/src/orchestration.js +402 -0
  19. package/dist/src/remote.js +123 -0
  20. package/dist/src/scheduler.js +84 -0
  21. package/dist/src/server-helpers/broadcasters.js +161 -0
  22. package/dist/src/server-helpers/conversation-snapshot.js +382 -0
  23. package/dist/src/server-helpers/event-emitter.js +41 -0
  24. package/dist/src/server-helpers/github-auth-store.js +155 -0
  25. package/dist/src/server-helpers/github-credentials.js +38 -0
  26. package/dist/src/server-helpers/github-project-status-sync.js +196 -0
  27. package/dist/src/server-helpers/github-projects.js +147 -0
  28. package/dist/src/server-helpers/github-reconciler.js +89 -0
  29. package/dist/src/server-helpers/http-router.js +3781 -0
  30. package/dist/src/server-helpers/http-utils.js +135 -0
  31. package/dist/src/server-helpers/inspector-agent-lifecycle.js +104 -0
  32. package/dist/src/server-helpers/inspector-jobs.js +4145 -0
  33. package/dist/src/server-helpers/issue-analysis.js +362 -0
  34. package/dist/src/server-helpers/normalizers.js +31 -0
  35. package/dist/src/server-helpers/notifications.js +96 -0
  36. package/dist/src/server-helpers/orchestration-ops.js +287 -0
  37. package/dist/src/server-helpers/orchestration.js +39 -0
  38. package/dist/src/server-helpers/plugin-host-cache.js +86 -0
  39. package/dist/src/server-helpers/project-fs-ops.js +194 -0
  40. package/dist/src/server-helpers/project-registry.js +124 -0
  41. package/dist/src/server-helpers/queue-state.js +78 -0
  42. package/dist/src/server-helpers/remote-checkout.js +140 -0
  43. package/dist/src/server-helpers/remote-snapshots.js +119 -0
  44. package/dist/src/server-helpers/run-io.js +262 -0
  45. package/dist/src/server-helpers/run-mutations.js +1784 -0
  46. package/dist/src/server-helpers/run-steering.js +176 -0
  47. package/dist/src/server-helpers/run-writers.js +75 -0
  48. package/dist/src/server-helpers/server-paths.js +27 -0
  49. package/dist/src/server-helpers/snapshot-orchestrator.js +832 -0
  50. package/dist/src/server-helpers/snapshot-service.js +1143 -0
  51. package/dist/src/server-helpers/summaries.js +126 -0
  52. package/dist/src/server-helpers/task-config.js +50 -0
  53. package/dist/src/server-helpers/task-projection.js +98 -0
  54. package/dist/src/server-helpers/terminal-runtime.js +156 -0
  55. package/dist/src/server-helpers/terminal-sessions.js +22 -0
  56. package/dist/src/server-helpers/validation-failure.js +31 -0
  57. package/dist/src/server-helpers/ws-router.js +1308 -0
  58. package/dist/src/server.js +12628 -0
  59. package/dist/src/websocket.js +63 -0
  60. package/package.json +33 -0
@@ -0,0 +1,135 @@
1
+ // @bun
2
+ // packages/server/src/server-helpers/http-utils.ts
3
+ async function readJsonBody(req) {
4
+ const body = await req.text();
5
+ if (!body.trim()) {
6
+ return {};
7
+ }
8
+ try {
9
+ const parsed = JSON.parse(body);
10
+ return parsed && typeof parsed === "object" ? parsed : {};
11
+ } catch {
12
+ throw new Error("Invalid JSON body");
13
+ }
14
+ }
15
+ function jsonResponse(payload, status = 200) {
16
+ return Response.json(payload, { status });
17
+ }
18
+ function normalizePositiveIntQuery(value, fallback) {
19
+ if (!value) {
20
+ return fallback;
21
+ }
22
+ const parsed = Number.parseInt(value, 10);
23
+ if (!Number.isFinite(parsed) || parsed <= 0) {
24
+ return fallback;
25
+ }
26
+ return parsed;
27
+ }
28
+ function isTruthyQuery(value) {
29
+ if (!value) {
30
+ return false;
31
+ }
32
+ const normalized = value.trim().toLowerCase();
33
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
34
+ }
35
+ function formatSseEvent(event, data) {
36
+ return `event: ${event}
37
+ data: ${JSON.stringify(data)}
38
+
39
+ `;
40
+ }
41
+ function notFound() {
42
+ return jsonResponse({ ok: false, error: "Not found" }, 404);
43
+ }
44
+ function badRequest(message) {
45
+ return jsonResponse({ ok: false, error: message }, 400);
46
+ }
47
+ function htmlResponse(html, status = 200) {
48
+ return new Response(html, {
49
+ status,
50
+ headers: {
51
+ "Content-Type": "text/html;charset=utf-8"
52
+ }
53
+ });
54
+ }
55
+ function escapeHtml(value) {
56
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
57
+ }
58
+ function isAuthorizedHttpRequest(req, authToken) {
59
+ if (!authToken)
60
+ return true;
61
+ const header = req.headers.get("authorization");
62
+ if (!header)
63
+ return false;
64
+ const match = header.match(/^Bearer\s+(.+)$/i);
65
+ return Boolean(match && match[1] === authToken);
66
+ }
67
+ function resolveAllowedBrowserOrigin(req) {
68
+ const originHeader = req.headers.get("origin");
69
+ if (!originHeader)
70
+ return null;
71
+ try {
72
+ const requestUrl = new URL(req.url);
73
+ const originUrl = new URL(originHeader);
74
+ if (!["http:", "https:"].includes(originUrl.protocol)) {
75
+ return null;
76
+ }
77
+ const sameHost = originUrl.hostname === requestUrl.hostname;
78
+ const equivalentLoopback = ["127.0.0.1", "localhost"].includes(originUrl.hostname) && ["127.0.0.1", "localhost"].includes(requestUrl.hostname);
79
+ if (!sameHost && !equivalentLoopback) {
80
+ return null;
81
+ }
82
+ return originUrl.origin;
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+ function buildCorsHeaders(req, origin) {
88
+ const headers = new Headers;
89
+ headers.set("Access-Control-Allow-Origin", origin);
90
+ headers.set("Vary", "Origin");
91
+ headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
92
+ headers.set("Access-Control-Allow-Headers", req.headers.get("access-control-request-headers") ?? "Authorization, Content-Type");
93
+ headers.set("Access-Control-Max-Age", "600");
94
+ if (req.headers.get("access-control-request-private-network") === "true") {
95
+ headers.set("Access-Control-Allow-Private-Network", "true");
96
+ }
97
+ return headers;
98
+ }
99
+ function withCorsHeaders(response, req, origin) {
100
+ if (!origin)
101
+ return response;
102
+ const headers = new Headers(response.headers);
103
+ const corsHeaders = buildCorsHeaders(req, origin);
104
+ for (const [key, value] of corsHeaders.entries()) {
105
+ headers.set(key, value);
106
+ }
107
+ return new Response(response.body, {
108
+ status: response.status,
109
+ statusText: response.statusText,
110
+ headers
111
+ });
112
+ }
113
+ function isAuthorizedLinearWebhookRequest(req) {
114
+ const secret = process.env.LINEAR_WEBHOOK_SECRET?.trim();
115
+ if (!secret) {
116
+ return false;
117
+ }
118
+ return req.headers.get("x-linear-webhook-secret") === secret;
119
+ }
120
+ export {
121
+ withCorsHeaders,
122
+ resolveAllowedBrowserOrigin,
123
+ readJsonBody,
124
+ notFound,
125
+ normalizePositiveIntQuery,
126
+ jsonResponse,
127
+ isTruthyQuery,
128
+ isAuthorizedLinearWebhookRequest,
129
+ isAuthorizedHttpRequest,
130
+ htmlResponse,
131
+ formatSseEvent,
132
+ escapeHtml,
133
+ buildCorsHeaders,
134
+ badRequest
135
+ };
@@ -0,0 +1,104 @@
1
+ // @bun
2
+ // packages/server/src/server-helpers/inspector-agent-lifecycle.ts
3
+ function createInspectorAgentLifecycleController(options) {
4
+ const initialDelayMs = Math.max(1, options.initialDelayMs ?? 5000);
5
+ const maxDelayMs = Math.max(initialDelayMs, options.maxDelayMs ?? 5 * 60000);
6
+ const backoffFactor = Math.max(1, options.backoffFactor ?? 2);
7
+ const now = options.now ?? Date.now;
8
+ const setTimer = options.setTimer ?? ((callback, delayMs) => setTimeout(callback, delayMs));
9
+ const clearTimer = options.clearTimer ?? clearTimeout;
10
+ const logError = options.logError ?? ((error, retryDelayMs2) => {
11
+ const message = error instanceof Error ? error.message : String(error);
12
+ console.error(`[server] inspector agent start failed: ${message} (next retry in ${Math.round(retryDelayMs2 / 1000)}s)`);
13
+ });
14
+ let retryDelayMs = initialDelayMs;
15
+ let nextAttemptAt = now();
16
+ let timer = null;
17
+ let stopped = false;
18
+ let lastError = null;
19
+ let lastLoggedError = null;
20
+ let failureCount = 0;
21
+ const snapshot = () => ({
22
+ disabled: options.disabled,
23
+ retryDelayMs: options.disabled || !options.agent ? null : retryDelayMs,
24
+ nextAttemptAt: options.disabled || !options.agent ? null : new Date(nextAttemptAt).toISOString(),
25
+ lastError,
26
+ failureCount
27
+ });
28
+ const scheduleNext = () => {
29
+ if (stopped || options.disabled || !options.agent || timer !== null)
30
+ return;
31
+ const delay = Math.max(0, nextAttemptAt - now());
32
+ timer = setTimer(() => {
33
+ timer = null;
34
+ attemptNow();
35
+ }, delay);
36
+ };
37
+ const resetHealthyBackoff = () => {
38
+ lastLoggedError = null;
39
+ lastError = null;
40
+ retryDelayMs = initialDelayMs;
41
+ failureCount = 0;
42
+ };
43
+ const attemptNow = async () => {
44
+ if (stopped || options.disabled || !options.agent)
45
+ return;
46
+ const status = options.agent.snapshot().status;
47
+ if (status === "starting" || status === "idle" || status === "running") {
48
+ resetHealthyBackoff();
49
+ nextAttemptAt = now() + retryDelayMs;
50
+ scheduleNext();
51
+ return;
52
+ }
53
+ try {
54
+ await options.agent.start();
55
+ resetHealthyBackoff();
56
+ } catch (error) {
57
+ const message = error instanceof Error ? error.message : String(error);
58
+ lastError = message;
59
+ failureCount += 1;
60
+ retryDelayMs = Math.min(Math.round(retryDelayMs * backoffFactor), maxDelayMs);
61
+ if (message !== lastLoggedError) {
62
+ lastLoggedError = message;
63
+ logError(error, retryDelayMs);
64
+ }
65
+ }
66
+ nextAttemptAt = now() + retryDelayMs;
67
+ scheduleNext();
68
+ };
69
+ return {
70
+ start() {
71
+ if (!options.disabled) {
72
+ attemptNow();
73
+ }
74
+ },
75
+ attemptNow,
76
+ stop() {
77
+ stopped = true;
78
+ if (timer !== null) {
79
+ clearTimer(timer);
80
+ timer = null;
81
+ }
82
+ options.agent?.stop();
83
+ },
84
+ snapshot
85
+ };
86
+ }
87
+ function inspectorAgentLifecycleSnapshot(input) {
88
+ const agentSnapshot = input.agent?.snapshot() ?? null;
89
+ return {
90
+ service: {
91
+ available: input.inspector !== null,
92
+ running: input.inspector?.isRunning() ?? false
93
+ },
94
+ agent: {
95
+ available: input.agent !== null,
96
+ status: input.retry?.disabled ? "disabled" : agentSnapshot?.status ?? "unavailable",
97
+ retry: input.retry
98
+ }
99
+ };
100
+ }
101
+ export {
102
+ inspectorAgentLifecycleSnapshot,
103
+ createInspectorAgentLifecycleController
104
+ };