@gmickel/gno 1.16.0 → 1.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 +34 -18
- package/assets/skill/SKILL.md +25 -6
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +2 -2
- package/src/app/context-agent-projection.ts +303 -0
- package/src/app/context-format.ts +249 -0
- package/src/app/context-runtime-contract.ts +325 -0
- package/src/app/context-runtime-input.ts +362 -0
- package/src/app/context-runtime-types.ts +65 -0
- package/src/app/context-runtime.ts +170 -0
- package/src/app/context-surface.ts +145 -0
- package/src/cli/commands/context-build.ts +149 -0
- package/src/cli/commands/context-verify.ts +90 -0
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/models/pull.ts +13 -3
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/detach.ts +37 -20
- package/src/cli/options.ts +4 -0
- package/src/cli/program.ts +252 -27
- package/src/config/index.ts +3 -0
- package/src/config/types.ts +37 -0
- package/src/core/context-budget.ts +461 -0
- package/src/core/context-capsule-index-schema.ts +15 -0
- package/src/core/context-capsule-retrieval-schema.ts +81 -0
- package/src/core/context-capsule-schema.ts +473 -0
- package/src/core/context-capsule-validation.ts +416 -0
- package/src/core/context-capsule-verification.ts +218 -0
- package/src/core/context-capsule.ts +439 -0
- package/src/core/context-compiler.ts +513 -0
- package/src/core/context-evidence-metadata.ts +33 -0
- package/src/core/context-evidence.ts +495 -0
- package/src/core/context-facets.ts +163 -0
- package/src/core/context-guidance.ts +69 -0
- package/src/core/context-scope.ts +32 -0
- package/src/core/context-verifier-canonical.ts +90 -0
- package/src/core/context-verifier-input.ts +66 -0
- package/src/core/context-verifier.ts +447 -0
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -0
- package/src/core/sections.ts +63 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +28 -82
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +230 -0
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +49 -2
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/pipeline/chunk-lookup.ts +33 -0
- package/src/pipeline/hybrid.ts +79 -57
- package/src/pipeline/types.ts +14 -0
- package/src/sdk/client.ts +68 -6
- package/src/sdk/index.ts +21 -0
- package/src/sdk/types.ts +24 -0
- package/src/serve/background-runtime.ts +12 -211
- package/src/serve/context-capsule.ts +136 -0
- package/src/serve/context.ts +10 -1
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Dashboard.tsx +1 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/routes/api.ts +265 -167
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/server.ts +212 -35
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- package/src/store/sqlite/adapter.ts +64 -29
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Production route adapter for the secured resident MCP endpoint. */
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
HttpMcpPeerServer,
|
|
5
|
+
ResolvedHttpGatewayConfig,
|
|
6
|
+
} from "../../mcp/http-security";
|
|
7
|
+
import type { ResidentRuntime } from "../resident-runtime";
|
|
8
|
+
|
|
9
|
+
import { HttpMcpSecurity } from "../../mcp/http-security";
|
|
10
|
+
import { HttpMcpTransport } from "../../mcp/http-transport";
|
|
11
|
+
|
|
12
|
+
export type McpHttpRoute = (
|
|
13
|
+
request: Request,
|
|
14
|
+
server: HttpMcpPeerServer
|
|
15
|
+
) => Promise<Response>;
|
|
16
|
+
|
|
17
|
+
export interface McpHttpGateway {
|
|
18
|
+
readonly route: McpHttpRoute;
|
|
19
|
+
readonly security: HttpMcpSecurity;
|
|
20
|
+
readonly transport: HttpMcpTransport;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build the route only after startup policy and token-file checks succeed.
|
|
26
|
+
* Every method passes through the external boundary before transport dispatch.
|
|
27
|
+
*/
|
|
28
|
+
export async function createMcpHttpGateway(
|
|
29
|
+
runtime: ResidentRuntime,
|
|
30
|
+
config: ResolvedHttpGatewayConfig
|
|
31
|
+
): Promise<McpHttpGateway> {
|
|
32
|
+
runtime.mcpContext.enableWrite = config.enableWrite;
|
|
33
|
+
const transport = new HttpMcpTransport(runtime, {
|
|
34
|
+
enableWrite: config.enableWrite,
|
|
35
|
+
idleTimeoutMs: config.limits.sessionIdleTimeoutMs,
|
|
36
|
+
maxConcurrentRequests: config.limits.maxConcurrentRequests,
|
|
37
|
+
maxQueuedRequests: config.limits.maxQueuedRequests,
|
|
38
|
+
maxSessions: config.limits.maxSessions,
|
|
39
|
+
});
|
|
40
|
+
const security = new HttpMcpSecurity(config, {
|
|
41
|
+
onCredentialsChanged: () => transport.invalidateAuthenticatedSessions(),
|
|
42
|
+
});
|
|
43
|
+
await security.initialize();
|
|
44
|
+
(runtime as Partial<ResidentRuntime>).setTransportStatusProvider?.(() =>
|
|
45
|
+
transport.getStatus()
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const route: McpHttpRoute = async (request, server) => {
|
|
49
|
+
const authorization = await security.authorize(request, server);
|
|
50
|
+
if (!authorization.ok) return authorization.response;
|
|
51
|
+
|
|
52
|
+
// POST responses and GET streams may both be long-lived SSE responses.
|
|
53
|
+
server.timeout(request, 0);
|
|
54
|
+
return transport.handleRequest(authorization.value.request, {
|
|
55
|
+
identity: authorization.value.identity,
|
|
56
|
+
parsedBody: authorization.value.parsedBody,
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
route,
|
|
62
|
+
security,
|
|
63
|
+
transport,
|
|
64
|
+
close: async () => {
|
|
65
|
+
await transport.close();
|
|
66
|
+
(runtime as Partial<ResidentRuntime>).setTransportStatusProvider?.(null);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
package/src/serve/server.ts
CHANGED
|
@@ -6,12 +6,20 @@
|
|
|
6
6
|
* @module src/serve/server
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { HttpGatewayOverrides } from "../mcp/http-security";
|
|
10
|
+
import type { ResidentRuntime } from "./resident-runtime";
|
|
9
11
|
import type { ContextHolder } from "./routes/api";
|
|
10
12
|
|
|
13
|
+
import {
|
|
14
|
+
isHttpGatewayLoopbackBind,
|
|
15
|
+
resolveHttpGatewayConfig,
|
|
16
|
+
} from "../mcp/http-security";
|
|
11
17
|
import { startBackgroundRuntime } from "./background-runtime";
|
|
18
|
+
import { handleContextBuild, handleContextVerify } from "./context-capsule";
|
|
12
19
|
import { DocumentEventBus } from "./doc-events";
|
|
13
20
|
// HTML import - Bun handles bundling TSX/CSS automatically via routes
|
|
14
21
|
import homepage from "./public/index.html";
|
|
22
|
+
import { handleResidentRead } from "./resident-request";
|
|
15
23
|
import {
|
|
16
24
|
handleActiveJob,
|
|
17
25
|
handleAsk,
|
|
@@ -48,6 +56,7 @@ import {
|
|
|
48
56
|
handleQuery,
|
|
49
57
|
handleQueryDiagnose,
|
|
50
58
|
handleRefactorPlan,
|
|
59
|
+
handleResidentStatus,
|
|
51
60
|
handleRenameDoc,
|
|
52
61
|
handleRevealDoc,
|
|
53
62
|
handleSearch,
|
|
@@ -66,9 +75,10 @@ import {
|
|
|
66
75
|
handleDocLinks,
|
|
67
76
|
handleDocSimilar,
|
|
68
77
|
} from "./routes/links";
|
|
78
|
+
import { createMcpHttpGateway } from "./routes/mcp";
|
|
69
79
|
import { forbiddenResponse, isRequestAllowed } from "./security";
|
|
70
80
|
|
|
71
|
-
export interface ServeOptions {
|
|
81
|
+
export interface ServeOptions extends HttpGatewayOverrides {
|
|
72
82
|
/** Port to listen on (default: 3000) */
|
|
73
83
|
port?: number;
|
|
74
84
|
/** Config path override */
|
|
@@ -84,8 +94,14 @@ export interface ServeResult {
|
|
|
84
94
|
|
|
85
95
|
interface StartServerDependencies {
|
|
86
96
|
startBackgroundRuntime?: typeof startBackgroundRuntime;
|
|
97
|
+
createMcpHttpGateway?: typeof createMcpHttpGateway;
|
|
87
98
|
serve?: typeof Bun.serve;
|
|
88
99
|
handleInstallConnector?: typeof handleInstallConnector;
|
|
100
|
+
handleDocs?: typeof handleDocs;
|
|
101
|
+
handleVerifyConnector?: typeof handleVerifyConnector;
|
|
102
|
+
handleImportPreview?: typeof handleImportPreview;
|
|
103
|
+
handlePublishExport?: typeof handlePublishExport;
|
|
104
|
+
handleRefactorPlan?: typeof handleRefactorPlan;
|
|
89
105
|
waitForShutdown?: (signal: AbortSignal) => Promise<void>;
|
|
90
106
|
}
|
|
91
107
|
|
|
@@ -151,6 +167,7 @@ export async function startServer(
|
|
|
151
167
|
const runtimeResult = await (
|
|
152
168
|
dependencies.startBackgroundRuntime ?? startBackgroundRuntime
|
|
153
169
|
)({
|
|
170
|
+
mode: "serve",
|
|
154
171
|
configPath: options.configPath,
|
|
155
172
|
index: options.index,
|
|
156
173
|
requireCollections: false,
|
|
@@ -162,6 +179,35 @@ export async function startServer(
|
|
|
162
179
|
const runtime = runtimeResult.runtime;
|
|
163
180
|
const store = runtime.store;
|
|
164
181
|
const ctxHolder: ContextHolder = runtime.ctxHolder;
|
|
182
|
+
const gatewayConfig = resolveHttpGatewayConfig(runtime.config.gateway, {
|
|
183
|
+
host: options.host,
|
|
184
|
+
port,
|
|
185
|
+
tokenFile: options.tokenFile,
|
|
186
|
+
allowedHosts: options.allowedHosts,
|
|
187
|
+
allowedOrigins: options.allowedOrigins,
|
|
188
|
+
enableWrite: options.enableWrite,
|
|
189
|
+
});
|
|
190
|
+
if (!isHttpGatewayLoopbackBind(gatewayConfig.host)) {
|
|
191
|
+
await runtime.dispose();
|
|
192
|
+
return {
|
|
193
|
+
success: false,
|
|
194
|
+
error:
|
|
195
|
+
"gno serve remains loopback-only because Web and REST share its listener; use gno daemon for authenticated non-loopback MCP",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let gateway: Awaited<ReturnType<typeof createMcpHttpGateway>>;
|
|
199
|
+
try {
|
|
200
|
+
gateway = await (dependencies.createMcpHttpGateway ?? createMcpHttpGateway)(
|
|
201
|
+
runtime as ResidentRuntime,
|
|
202
|
+
gatewayConfig
|
|
203
|
+
);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
await runtime.dispose();
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
error: error instanceof Error ? error.message : String(error),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
165
211
|
|
|
166
212
|
// Shutdown controller for clean lifecycle
|
|
167
213
|
const shutdownController = new AbortController();
|
|
@@ -184,13 +230,14 @@ export async function startServer(
|
|
|
184
230
|
try {
|
|
185
231
|
server = (dependencies.serve ?? Bun.serve)({
|
|
186
232
|
port,
|
|
187
|
-
hostname:
|
|
233
|
+
hostname: gatewayConfig.host,
|
|
188
234
|
|
|
189
235
|
// Enable development mode for HMR and console logging
|
|
190
236
|
development: isDev,
|
|
191
237
|
|
|
192
238
|
// Static routes - Bun handles HTML bundling and /_bun/* assets automatically
|
|
193
239
|
routes: {
|
|
240
|
+
"/mcp": gateway.route,
|
|
194
241
|
// SPA routes - all serve the same React app
|
|
195
242
|
"/": homepage,
|
|
196
243
|
"/search": homepage,
|
|
@@ -207,8 +254,25 @@ export async function startServer(
|
|
|
207
254
|
GET: () => withSecurityHeaders(handleHealth(), isDev),
|
|
208
255
|
},
|
|
209
256
|
"/api/status": {
|
|
210
|
-
GET: async () =>
|
|
211
|
-
withSecurityHeaders(
|
|
257
|
+
GET: async (req: Request) =>
|
|
258
|
+
withSecurityHeaders(
|
|
259
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
260
|
+
handleStatus(ctxHolder.current, {
|
|
261
|
+
getResidentStatus: () =>
|
|
262
|
+
(runtime as ResidentRuntime).getStatus(),
|
|
263
|
+
})
|
|
264
|
+
),
|
|
265
|
+
isDev
|
|
266
|
+
),
|
|
267
|
+
},
|
|
268
|
+
"/api/resident/status": {
|
|
269
|
+
GET: () =>
|
|
270
|
+
withSecurityHeaders(
|
|
271
|
+
handleResidentStatus(() =>
|
|
272
|
+
(runtime as ResidentRuntime).getStatus()
|
|
273
|
+
),
|
|
274
|
+
isDev
|
|
275
|
+
),
|
|
212
276
|
},
|
|
213
277
|
"/api/collections": {
|
|
214
278
|
GET: async () =>
|
|
@@ -227,9 +291,11 @@ export async function startServer(
|
|
|
227
291
|
},
|
|
228
292
|
},
|
|
229
293
|
"/api/connectors": {
|
|
230
|
-
GET: async () =>
|
|
294
|
+
GET: async (req: Request) =>
|
|
231
295
|
withSecurityHeaders(
|
|
232
|
-
await
|
|
296
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
297
|
+
handleConnectors(ctxHolder.config)
|
|
298
|
+
),
|
|
233
299
|
isDev
|
|
234
300
|
),
|
|
235
301
|
},
|
|
@@ -255,7 +321,13 @@ export async function startServer(
|
|
|
255
321
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
256
322
|
}
|
|
257
323
|
return withSecurityHeaders(
|
|
258
|
-
await
|
|
324
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
325
|
+
(dependencies.handleVerifyConnector ?? handleVerifyConnector)(
|
|
326
|
+
ctxHolder.config,
|
|
327
|
+
store,
|
|
328
|
+
req
|
|
329
|
+
)
|
|
330
|
+
),
|
|
259
331
|
isDev
|
|
260
332
|
);
|
|
261
333
|
},
|
|
@@ -266,7 +338,12 @@ export async function startServer(
|
|
|
266
338
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
267
339
|
}
|
|
268
340
|
return withSecurityHeaders(
|
|
269
|
-
await
|
|
341
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
342
|
+
(dependencies.handleImportPreview ?? handleImportPreview)(
|
|
343
|
+
ctxHolder,
|
|
344
|
+
req
|
|
345
|
+
)
|
|
346
|
+
),
|
|
270
347
|
isDev
|
|
271
348
|
);
|
|
272
349
|
},
|
|
@@ -277,7 +354,13 @@ export async function startServer(
|
|
|
277
354
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
278
355
|
}
|
|
279
356
|
return withSecurityHeaders(
|
|
280
|
-
await
|
|
357
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
358
|
+
(dependencies.handlePublishExport ?? handlePublishExport)(
|
|
359
|
+
ctxHolder.config,
|
|
360
|
+
store,
|
|
361
|
+
req
|
|
362
|
+
)
|
|
363
|
+
),
|
|
281
364
|
isDev
|
|
282
365
|
);
|
|
283
366
|
},
|
|
@@ -307,7 +390,12 @@ export async function startServer(
|
|
|
307
390
|
"/api/docs": {
|
|
308
391
|
GET: async (req: Request) => {
|
|
309
392
|
const url = new URL(req.url);
|
|
310
|
-
return withSecurityHeaders(
|
|
393
|
+
return withSecurityHeaders(
|
|
394
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
395
|
+
(dependencies.handleDocs ?? handleDocs)(store, url)
|
|
396
|
+
),
|
|
397
|
+
isDev
|
|
398
|
+
);
|
|
311
399
|
},
|
|
312
400
|
POST: async (req: Request) => {
|
|
313
401
|
if (!isRequestAllowed(req, port)) {
|
|
@@ -323,7 +411,9 @@ export async function startServer(
|
|
|
323
411
|
GET: async (req: Request) => {
|
|
324
412
|
const url = new URL(req.url);
|
|
325
413
|
return withSecurityHeaders(
|
|
326
|
-
await
|
|
414
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
415
|
+
handleDocsAutocomplete(store, url)
|
|
416
|
+
),
|
|
327
417
|
isDev
|
|
328
418
|
);
|
|
329
419
|
},
|
|
@@ -344,8 +434,13 @@ export async function startServer(
|
|
|
344
434
|
},
|
|
345
435
|
},
|
|
346
436
|
"/api/browse/tree": {
|
|
347
|
-
GET: async () =>
|
|
348
|
-
withSecurityHeaders(
|
|
437
|
+
GET: async (req: Request) =>
|
|
438
|
+
withSecurityHeaders(
|
|
439
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
440
|
+
handleBrowseTree(store)
|
|
441
|
+
),
|
|
442
|
+
isDev
|
|
443
|
+
),
|
|
349
444
|
},
|
|
350
445
|
"/api/docs/:id/deactivate": {
|
|
351
446
|
POST: async (req: Request) => {
|
|
@@ -357,7 +452,7 @@ export async function startServer(
|
|
|
357
452
|
const parts = url.pathname.split("/");
|
|
358
453
|
const id = decodeURIComponent(parts[3] || "");
|
|
359
454
|
return withSecurityHeaders(
|
|
360
|
-
await handleDeactivateDoc(store, id, req),
|
|
455
|
+
await handleDeactivateDoc(ctxHolder, store, id, req),
|
|
361
456
|
isDev
|
|
362
457
|
);
|
|
363
458
|
},
|
|
@@ -413,7 +508,14 @@ export async function startServer(
|
|
|
413
508
|
const parts = url.pathname.split("/");
|
|
414
509
|
const id = decodeURIComponent(parts[3] || "");
|
|
415
510
|
return withSecurityHeaders(
|
|
416
|
-
await
|
|
511
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
512
|
+
(dependencies.handleRefactorPlan ?? handleRefactorPlan)(
|
|
513
|
+
ctxHolder,
|
|
514
|
+
store,
|
|
515
|
+
id,
|
|
516
|
+
req
|
|
517
|
+
)
|
|
518
|
+
),
|
|
417
519
|
isDev
|
|
418
520
|
);
|
|
419
521
|
},
|
|
@@ -478,7 +580,9 @@ export async function startServer(
|
|
|
478
580
|
GET: async (req: Request) => {
|
|
479
581
|
const url = new URL(req.url);
|
|
480
582
|
return withSecurityHeaders(
|
|
481
|
-
await
|
|
583
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
584
|
+
handleDoc(store, ctxHolder.config, url)
|
|
585
|
+
),
|
|
482
586
|
isDev
|
|
483
587
|
);
|
|
484
588
|
},
|
|
@@ -487,7 +591,9 @@ export async function startServer(
|
|
|
487
591
|
GET: async (req: Request) => {
|
|
488
592
|
const url = new URL(req.url);
|
|
489
593
|
return withSecurityHeaders(
|
|
490
|
-
await
|
|
594
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
595
|
+
handleDocAsset(store, ctxHolder.config, url)
|
|
596
|
+
),
|
|
491
597
|
isDev
|
|
492
598
|
);
|
|
493
599
|
},
|
|
@@ -503,7 +609,12 @@ export async function startServer(
|
|
|
503
609
|
"/api/tags": {
|
|
504
610
|
GET: async (req: Request) => {
|
|
505
611
|
const url = new URL(req.url);
|
|
506
|
-
return withSecurityHeaders(
|
|
612
|
+
return withSecurityHeaders(
|
|
613
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
614
|
+
handleTags(store, url)
|
|
615
|
+
),
|
|
616
|
+
isDev
|
|
617
|
+
);
|
|
507
618
|
},
|
|
508
619
|
},
|
|
509
620
|
"/api/search": {
|
|
@@ -511,7 +622,12 @@ export async function startServer(
|
|
|
511
622
|
if (!isRequestAllowed(req, port)) {
|
|
512
623
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
513
624
|
}
|
|
514
|
-
return withSecurityHeaders(
|
|
625
|
+
return withSecurityHeaders(
|
|
626
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
627
|
+
handleSearch(store, req)
|
|
628
|
+
),
|
|
629
|
+
isDev
|
|
630
|
+
);
|
|
515
631
|
},
|
|
516
632
|
},
|
|
517
633
|
"/api/query": {
|
|
@@ -520,7 +636,35 @@ export async function startServer(
|
|
|
520
636
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
521
637
|
}
|
|
522
638
|
return withSecurityHeaders(
|
|
523
|
-
await
|
|
639
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
640
|
+
handleQuery(ctxHolder.current, req)
|
|
641
|
+
),
|
|
642
|
+
isDev
|
|
643
|
+
);
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
"/api/context": {
|
|
647
|
+
POST: async (req: Request) => {
|
|
648
|
+
if (!isRequestAllowed(req, port)) {
|
|
649
|
+
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
650
|
+
}
|
|
651
|
+
return withSecurityHeaders(
|
|
652
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
653
|
+
handleContextBuild(ctxHolder.current, req)
|
|
654
|
+
),
|
|
655
|
+
isDev
|
|
656
|
+
);
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
"/api/context/verify": {
|
|
660
|
+
POST: async (req: Request) => {
|
|
661
|
+
if (!isRequestAllowed(req, port)) {
|
|
662
|
+
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
663
|
+
}
|
|
664
|
+
return withSecurityHeaders(
|
|
665
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
666
|
+
handleContextVerify(ctxHolder.current, req)
|
|
667
|
+
),
|
|
524
668
|
isDev
|
|
525
669
|
);
|
|
526
670
|
},
|
|
@@ -531,7 +675,9 @@ export async function startServer(
|
|
|
531
675
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
532
676
|
}
|
|
533
677
|
return withSecurityHeaders(
|
|
534
|
-
await
|
|
678
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
679
|
+
handleQueryDiagnose(ctxHolder.current, req)
|
|
680
|
+
),
|
|
535
681
|
isDev
|
|
536
682
|
);
|
|
537
683
|
},
|
|
@@ -542,7 +688,9 @@ export async function startServer(
|
|
|
542
688
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
543
689
|
}
|
|
544
690
|
return withSecurityHeaders(
|
|
545
|
-
await
|
|
691
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
692
|
+
handleAsk(ctxHolder.current, req)
|
|
693
|
+
),
|
|
546
694
|
isDev
|
|
547
695
|
);
|
|
548
696
|
},
|
|
@@ -568,21 +716,30 @@ export async function startServer(
|
|
|
568
716
|
GET: () => withSecurityHeaders(handleModelStatus(), isDev),
|
|
569
717
|
},
|
|
570
718
|
"/api/models/pull": {
|
|
571
|
-
POST: (req: Request) => {
|
|
719
|
+
POST: async (req: Request) => {
|
|
572
720
|
if (!isRequestAllowed(req, port)) {
|
|
573
721
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
574
722
|
}
|
|
575
|
-
return withSecurityHeaders(
|
|
723
|
+
return withSecurityHeaders(
|
|
724
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
725
|
+
handleModelPull(ctxHolder)
|
|
726
|
+
),
|
|
727
|
+
isDev
|
|
728
|
+
);
|
|
576
729
|
},
|
|
577
730
|
},
|
|
578
731
|
"/api/jobs/active": {
|
|
579
|
-
GET: () =>
|
|
732
|
+
GET: () =>
|
|
733
|
+
withSecurityHeaders(handleActiveJob(ctxHolder.jobManager), isDev),
|
|
580
734
|
},
|
|
581
735
|
"/api/jobs/:id": {
|
|
582
736
|
GET: (req: Request) => {
|
|
583
737
|
const url = new URL(req.url);
|
|
584
738
|
const id = decodeURIComponent(url.pathname.split("/").pop() || "");
|
|
585
|
-
return withSecurityHeaders(
|
|
739
|
+
return withSecurityHeaders(
|
|
740
|
+
handleJob(id, ctxHolder.jobManager),
|
|
741
|
+
isDev
|
|
742
|
+
);
|
|
586
743
|
},
|
|
587
744
|
},
|
|
588
745
|
"/api/embed": {
|
|
@@ -654,7 +811,9 @@ export async function startServer(
|
|
|
654
811
|
const parts = url.pathname.split("/");
|
|
655
812
|
const id = decodeURIComponent(parts[3] || "");
|
|
656
813
|
return withSecurityHeaders(
|
|
657
|
-
await
|
|
814
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
815
|
+
handleDocLinks(store, id, url)
|
|
816
|
+
),
|
|
658
817
|
isDev
|
|
659
818
|
);
|
|
660
819
|
},
|
|
@@ -665,7 +824,9 @@ export async function startServer(
|
|
|
665
824
|
const parts = url.pathname.split("/");
|
|
666
825
|
const id = decodeURIComponent(parts[3] || "");
|
|
667
826
|
return withSecurityHeaders(
|
|
668
|
-
await
|
|
827
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
828
|
+
handleDocSections(store, id, req)
|
|
829
|
+
),
|
|
669
830
|
isDev
|
|
670
831
|
);
|
|
671
832
|
},
|
|
@@ -677,7 +838,9 @@ export async function startServer(
|
|
|
677
838
|
const parts = url.pathname.split("/");
|
|
678
839
|
const id = decodeURIComponent(parts[3] || "");
|
|
679
840
|
return withSecurityHeaders(
|
|
680
|
-
await
|
|
841
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
842
|
+
handleDocBacklinks(store, id)
|
|
843
|
+
),
|
|
681
844
|
isDev
|
|
682
845
|
);
|
|
683
846
|
},
|
|
@@ -689,7 +852,9 @@ export async function startServer(
|
|
|
689
852
|
const parts = url.pathname.split("/");
|
|
690
853
|
const id = decodeURIComponent(parts[3] || "");
|
|
691
854
|
return withSecurityHeaders(
|
|
692
|
-
await
|
|
855
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
856
|
+
handleDocSimilar(ctxHolder.current, id, url)
|
|
857
|
+
),
|
|
693
858
|
isDev
|
|
694
859
|
);
|
|
695
860
|
},
|
|
@@ -697,7 +862,12 @@ export async function startServer(
|
|
|
697
862
|
"/api/graph": {
|
|
698
863
|
GET: async (req: Request) => {
|
|
699
864
|
const url = new URL(req.url);
|
|
700
|
-
return withSecurityHeaders(
|
|
865
|
+
return withSecurityHeaders(
|
|
866
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
867
|
+
handleGraph(store, url)
|
|
868
|
+
),
|
|
869
|
+
isDev
|
|
870
|
+
);
|
|
701
871
|
},
|
|
702
872
|
},
|
|
703
873
|
"/api/graph/query": {
|
|
@@ -706,7 +876,9 @@ export async function startServer(
|
|
|
706
876
|
return withSecurityHeaders(forbiddenResponse(), isDev);
|
|
707
877
|
}
|
|
708
878
|
return withSecurityHeaders(
|
|
709
|
-
await
|
|
879
|
+
await handleResidentRead(runtime as ResidentRuntime, req, () =>
|
|
880
|
+
handleGraphQuery(store, ctxHolder.config, req)
|
|
881
|
+
),
|
|
710
882
|
isDev
|
|
711
883
|
);
|
|
712
884
|
},
|
|
@@ -715,14 +887,18 @@ export async function startServer(
|
|
|
715
887
|
});
|
|
716
888
|
} catch (e) {
|
|
717
889
|
removeShutdownHandlers();
|
|
718
|
-
await
|
|
890
|
+
await Promise.allSettled([gateway.close()]);
|
|
891
|
+
await Promise.allSettled([runtime.dispose()]);
|
|
719
892
|
return {
|
|
720
893
|
success: false,
|
|
721
894
|
error: e instanceof Error ? e.message : String(e),
|
|
722
895
|
};
|
|
723
896
|
}
|
|
897
|
+
(runtime as Partial<ResidentRuntime>).setListenerPort?.(server.port ?? port);
|
|
724
898
|
|
|
725
|
-
console.log(
|
|
899
|
+
console.log(
|
|
900
|
+
`GNO server running at http://${gatewayConfig.host}:${server.port}`
|
|
901
|
+
);
|
|
726
902
|
console.log("Press Ctrl+C to stop");
|
|
727
903
|
|
|
728
904
|
// Block until shutdown signal
|
|
@@ -740,7 +916,8 @@ export async function startServer(
|
|
|
740
916
|
try {
|
|
741
917
|
await server.stop(true);
|
|
742
918
|
} finally {
|
|
743
|
-
await
|
|
919
|
+
await Promise.allSettled([gateway.close()]);
|
|
920
|
+
await Promise.allSettled([runtime.dispose()]);
|
|
744
921
|
}
|
|
745
922
|
return { success: true };
|
|
746
923
|
}
|
|
@@ -59,6 +59,56 @@ export interface HealthCenterState {
|
|
|
59
59
|
checks: HealthCheck[];
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export type RuntimeMode = "serve" | "daemon" | "stdio" | "direct-cli";
|
|
63
|
+
|
|
64
|
+
export interface ResidentStatus {
|
|
65
|
+
schemaVersion: "1.0";
|
|
66
|
+
mode: RuntimeMode;
|
|
67
|
+
resident: boolean;
|
|
68
|
+
uptimeSeconds: number | null;
|
|
69
|
+
listenerPort: number | null;
|
|
70
|
+
admission: {
|
|
71
|
+
state: "accepting" | "draining" | "closed";
|
|
72
|
+
activeRequests: number;
|
|
73
|
+
};
|
|
74
|
+
shutdown: {
|
|
75
|
+
state: "none" | "graceful" | "deadline";
|
|
76
|
+
};
|
|
77
|
+
transport: {
|
|
78
|
+
activeRequests: number;
|
|
79
|
+
activeSessions: number;
|
|
80
|
+
queuedRequests: number;
|
|
81
|
+
maxConcurrentRequests: number;
|
|
82
|
+
maxQueuedRequests: number;
|
|
83
|
+
maxSessions: number;
|
|
84
|
+
};
|
|
85
|
+
readers: {
|
|
86
|
+
active: number;
|
|
87
|
+
queued: number;
|
|
88
|
+
limit: number;
|
|
89
|
+
maxQueued: number;
|
|
90
|
+
};
|
|
91
|
+
models: {
|
|
92
|
+
activeLeases: number;
|
|
93
|
+
leaseAcquisitions: number;
|
|
94
|
+
leaseReleases: number;
|
|
95
|
+
loadedModels: number;
|
|
96
|
+
loadAttempts: number;
|
|
97
|
+
loadSuccesses: number;
|
|
98
|
+
loadFailures: number;
|
|
99
|
+
inflightLoads: number;
|
|
100
|
+
};
|
|
101
|
+
jobs: {
|
|
102
|
+
active: number;
|
|
103
|
+
recent: number;
|
|
104
|
+
failed: number;
|
|
105
|
+
};
|
|
106
|
+
generations: {
|
|
107
|
+
content: number;
|
|
108
|
+
index: number;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
62
112
|
export interface BackgroundServiceState {
|
|
63
113
|
watcher: {
|
|
64
114
|
expectedCollections: string[];
|
|
@@ -125,6 +175,7 @@ export interface BootstrapState {
|
|
|
125
175
|
}
|
|
126
176
|
|
|
127
177
|
export interface AppStatusResponse {
|
|
178
|
+
resident: ResidentStatus;
|
|
128
179
|
indexName: string;
|
|
129
180
|
configPath: string;
|
|
130
181
|
dbPath: string;
|
package/src/serve/status.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "./activation-health";
|
|
27
27
|
import { getConnectorVerificationTargets } from "./connectors";
|
|
28
28
|
import { downloadState, type ServerContext } from "./context";
|
|
29
|
+
import { createStandaloneResidentStatus } from "./resident-status";
|
|
29
30
|
|
|
30
31
|
const GIGABYTE = 1024 * 1024 * 1024;
|
|
31
32
|
const DISK_WARN_BYTES = 4 * GIGABYTE;
|
|
@@ -71,6 +72,7 @@ export interface StatusBuildDeps {
|
|
|
71
72
|
listSuggestedCollections?: () => Promise<SuggestedCollection[]>;
|
|
72
73
|
buildActivation?: typeof buildActivationStatus;
|
|
73
74
|
listConnectorTargets?: typeof getConnectorVerificationTargets;
|
|
75
|
+
getResidentStatus?: () => AppStatusResponse["resident"];
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
function formatBytes(bytes: number): string {
|
|
@@ -714,6 +716,9 @@ export async function buildAppStatus(
|
|
|
714
716
|
: "GNO works, but a few issues still need attention before it feels reliable.";
|
|
715
717
|
|
|
716
718
|
return {
|
|
719
|
+
resident:
|
|
720
|
+
deps.getResidentStatus?.() ??
|
|
721
|
+
createStandaloneResidentStatus("direct-cli"),
|
|
717
722
|
indexName: status.indexName,
|
|
718
723
|
configPath: status.configPath,
|
|
719
724
|
dbPath: status.dbPath,
|