@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.
Files changed (86) hide show
  1. package/README.md +34 -18
  2. package/assets/skill/SKILL.md +25 -6
  3. package/assets/skill/mcp-reference.md +21 -0
  4. package/package.json +2 -2
  5. package/src/app/context-agent-projection.ts +303 -0
  6. package/src/app/context-format.ts +249 -0
  7. package/src/app/context-runtime-contract.ts +325 -0
  8. package/src/app/context-runtime-input.ts +362 -0
  9. package/src/app/context-runtime-types.ts +65 -0
  10. package/src/app/context-runtime.ts +170 -0
  11. package/src/app/context-surface.ts +145 -0
  12. package/src/cli/commands/context-build.ts +149 -0
  13. package/src/cli/commands/context-verify.ts +90 -0
  14. package/src/cli/commands/daemon.ts +69 -2
  15. package/src/cli/commands/models/pull.ts +13 -3
  16. package/src/cli/commands/status.ts +2 -0
  17. package/src/cli/detach.ts +37 -20
  18. package/src/cli/options.ts +4 -0
  19. package/src/cli/program.ts +252 -27
  20. package/src/config/index.ts +3 -0
  21. package/src/config/types.ts +37 -0
  22. package/src/core/context-budget.ts +461 -0
  23. package/src/core/context-capsule-index-schema.ts +15 -0
  24. package/src/core/context-capsule-retrieval-schema.ts +81 -0
  25. package/src/core/context-capsule-schema.ts +473 -0
  26. package/src/core/context-capsule-validation.ts +416 -0
  27. package/src/core/context-capsule-verification.ts +218 -0
  28. package/src/core/context-capsule.ts +439 -0
  29. package/src/core/context-compiler.ts +513 -0
  30. package/src/core/context-evidence-metadata.ts +33 -0
  31. package/src/core/context-evidence.ts +495 -0
  32. package/src/core/context-facets.ts +163 -0
  33. package/src/core/context-guidance.ts +69 -0
  34. package/src/core/context-scope.ts +32 -0
  35. package/src/core/context-verifier-canonical.ts +90 -0
  36. package/src/core/context-verifier-input.ts +66 -0
  37. package/src/core/context-verifier.ts +447 -0
  38. package/src/core/job-manager.ts +19 -0
  39. package/src/core/mutation-generations.ts +33 -0
  40. package/src/core/sections.ts +63 -0
  41. package/src/llm/cache.ts +13 -3
  42. package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
  43. package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
  44. package/src/mcp/context.ts +161 -0
  45. package/src/mcp/http-security.ts +477 -0
  46. package/src/mcp/http-session.ts +272 -0
  47. package/src/mcp/http-transport.ts +370 -0
  48. package/src/mcp/resources/index.ts +141 -134
  49. package/src/mcp/server.ts +28 -82
  50. package/src/mcp/tools/add-collection.ts +3 -1
  51. package/src/mcp/tools/capture.ts +3 -0
  52. package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
  53. package/src/mcp/tools/context.ts +230 -0
  54. package/src/mcp/tools/embed.ts +62 -52
  55. package/src/mcp/tools/index-cmd.ts +88 -74
  56. package/src/mcp/tools/index.ts +49 -2
  57. package/src/mcp/tools/remove-collection.ts +2 -0
  58. package/src/mcp/tools/status.ts +11 -0
  59. package/src/mcp/tools/sync.ts +16 -14
  60. package/src/mcp/tools/workspace-write.ts +7 -3
  61. package/src/pipeline/chunk-lookup.ts +33 -0
  62. package/src/pipeline/hybrid.ts +79 -57
  63. package/src/pipeline/types.ts +14 -0
  64. package/src/sdk/client.ts +68 -6
  65. package/src/sdk/index.ts +21 -0
  66. package/src/sdk/types.ts +24 -0
  67. package/src/serve/background-runtime.ts +12 -211
  68. package/src/serve/context-capsule.ts +136 -0
  69. package/src/serve/context.ts +10 -1
  70. package/src/serve/embed-scheduler.ts +74 -43
  71. package/src/serve/index.ts +9 -0
  72. package/src/serve/jobs.ts +78 -80
  73. package/src/serve/public/components/HealthCenter.tsx +74 -1
  74. package/src/serve/public/globals.built.css +1 -1
  75. package/src/serve/public/pages/Dashboard.tsx +1 -0
  76. package/src/serve/resident-admission.ts +159 -0
  77. package/src/serve/resident-background-work.ts +39 -0
  78. package/src/serve/resident-request.ts +55 -0
  79. package/src/serve/resident-runtime.ts +490 -0
  80. package/src/serve/resident-status.ts +96 -0
  81. package/src/serve/routes/api.ts +265 -167
  82. package/src/serve/routes/mcp.ts +69 -0
  83. package/src/serve/server.ts +212 -35
  84. package/src/serve/status-model.ts +51 -0
  85. package/src/serve/status.ts +5 -0
  86. package/src/store/sqlite/adapter.ts +64 -29
@@ -513,6 +513,7 @@ export default function Dashboard({ navigate }: PageProps) {
513
513
  busyAction={busyAction}
514
514
  health={status.health}
515
515
  onAction={handleHealthAction}
516
+ resident={status.resident}
516
517
  />
517
518
  </div>
518
519
  )}
@@ -0,0 +1,159 @@
1
+ /** Resident request admission and bounded reader concurrency primitives. */
2
+
3
+ import type { ResidentRequestHandle } from "./resident-runtime";
4
+
5
+ const DEFAULT_READER_LIMIT = 8;
6
+ const DEFAULT_READER_QUEUE_LIMIT = 64;
7
+
8
+ export class ReaderGate {
9
+ readonly #limit: number;
10
+ readonly #maxQueued: number;
11
+ #active = 0;
12
+ readonly #queue: Array<{
13
+ resolve: () => void;
14
+ reject: (error: Error) => void;
15
+ signal?: AbortSignal;
16
+ onAbort?: () => void;
17
+ }> = [];
18
+
19
+ constructor(
20
+ limit = DEFAULT_READER_LIMIT,
21
+ maxQueued = DEFAULT_READER_QUEUE_LIMIT
22
+ ) {
23
+ this.#limit = Math.max(1, Math.floor(limit));
24
+ this.#maxQueued = Math.max(0, Math.floor(maxQueued));
25
+ }
26
+
27
+ get active(): number {
28
+ return this.#active;
29
+ }
30
+
31
+ get queued(): number {
32
+ return this.#queue.length;
33
+ }
34
+
35
+ get limit(): number {
36
+ return this.#limit;
37
+ }
38
+
39
+ get maxQueued(): number {
40
+ return this.#maxQueued;
41
+ }
42
+
43
+ async acquire(signal?: AbortSignal): Promise<() => void> {
44
+ if (signal?.aborted) {
45
+ throw new Error("Resident request aborted");
46
+ }
47
+ if (this.#active >= this.#limit) {
48
+ if (this.#queue.length >= this.#maxQueued) {
49
+ throw new Error("Resident reader queue is full");
50
+ }
51
+ await new Promise<void>((resolve, reject) => {
52
+ const entry = {
53
+ resolve,
54
+ reject,
55
+ signal,
56
+ onAbort: undefined as (() => void) | undefined,
57
+ };
58
+ entry.onAbort = () => {
59
+ const index = this.#queue.indexOf(entry);
60
+ if (index >= 0) this.#queue.splice(index, 1);
61
+ reject(new Error("Resident request aborted"));
62
+ };
63
+ signal?.addEventListener("abort", entry.onAbort, { once: true });
64
+ this.#queue.push(entry);
65
+ });
66
+ }
67
+ if (signal?.aborted) throw new Error("Resident request aborted");
68
+ this.#active += 1;
69
+ let released = false;
70
+ return () => {
71
+ if (released) return;
72
+ released = true;
73
+ this.#active -= 1;
74
+ const next = this.#queue.shift();
75
+ if (next) {
76
+ next.signal?.removeEventListener("abort", next.onAbort!);
77
+ next.resolve();
78
+ }
79
+ };
80
+ }
81
+ }
82
+
83
+ export class AdmissionController {
84
+ #accepting = true;
85
+ readonly #requests = new Map<string, AbortController>();
86
+ readonly #drainWaiters = new Set<() => void>();
87
+
88
+ get active(): number {
89
+ return this.#requests.size;
90
+ }
91
+
92
+ get accepting(): boolean {
93
+ return this.#accepting;
94
+ }
95
+
96
+ admit(parentSignal?: AbortSignal): ResidentRequestHandle | null {
97
+ if (!this.#accepting) return null;
98
+ const id = crypto.randomUUID();
99
+ const controller = new AbortController();
100
+ const abortFromParent = (): void => controller.abort(parentSignal?.reason);
101
+ parentSignal?.addEventListener("abort", abortFromParent, { once: true });
102
+ if (parentSignal?.aborted) abortFromParent();
103
+ this.#requests.set(id, controller);
104
+ let finished = false;
105
+ return {
106
+ id,
107
+ signal: controller.signal,
108
+ finish: () => {
109
+ if (finished) return;
110
+ finished = true;
111
+ parentSignal?.removeEventListener("abort", abortFromParent);
112
+ this.#requests.delete(id);
113
+ if (this.#requests.size === 0) {
114
+ for (const waiter of this.#drainWaiters) waiter();
115
+ this.#drainWaiters.clear();
116
+ }
117
+ },
118
+ };
119
+ }
120
+
121
+ async closeAndDrain(
122
+ deadlineMs: number,
123
+ abortSettleMs = deadlineMs
124
+ ): Promise<boolean> {
125
+ this.#accepting = false;
126
+ if (this.#requests.size === 0) return false;
127
+
128
+ let timeout: ReturnType<typeof setTimeout> | undefined;
129
+ let deadlineReached = false;
130
+ await Promise.race([
131
+ new Promise<void>((resolve) => this.#drainWaiters.add(resolve)),
132
+ new Promise<void>((resolve) => {
133
+ timeout = setTimeout(
134
+ () => {
135
+ deadlineReached = true;
136
+ resolve();
137
+ },
138
+ Math.max(0, deadlineMs)
139
+ );
140
+ }),
141
+ ]);
142
+ if (timeout) clearTimeout(timeout);
143
+
144
+ if (!deadlineReached) return false;
145
+
146
+ for (const controller of this.#requests.values())
147
+ controller.abort(new Error("Resident runtime is shutting down"));
148
+
149
+ if (this.#requests.size > 0) {
150
+ await Promise.race([
151
+ new Promise<void>((resolve) => this.#drainWaiters.add(resolve)),
152
+ new Promise<void>((resolve) =>
153
+ setTimeout(resolve, Math.max(0, abortSettleMs))
154
+ ),
155
+ ]);
156
+ }
157
+ return deadlineReached;
158
+ }
159
+ }
@@ -0,0 +1,39 @@
1
+ /** Tracks cancellable work that intentionally outlives its initiating request. */
2
+
3
+ interface BackgroundWorkEntry {
4
+ controller: AbortController;
5
+ promise: Promise<void>;
6
+ }
7
+
8
+ export class ResidentBackgroundWork {
9
+ readonly #entries = new Set<BackgroundWorkEntry>();
10
+ readonly #isAccepting: () => boolean;
11
+
12
+ constructor(isAccepting: () => boolean) {
13
+ this.#isAccepting = isAccepting;
14
+ }
15
+
16
+ start(operation: (signal: AbortSignal) => Promise<void>): boolean {
17
+ if (!this.#isAccepting()) return false;
18
+ const controller = new AbortController();
19
+ const entry: BackgroundWorkEntry = {
20
+ controller,
21
+ promise: Promise.resolve(),
22
+ };
23
+ entry.promise = Promise.resolve()
24
+ .then(() => operation(controller.signal))
25
+ .catch(() => undefined)
26
+ .finally(() => this.#entries.delete(entry));
27
+ this.#entries.add(entry);
28
+ return true;
29
+ }
30
+
31
+ async cancelAndDrain(): Promise<void> {
32
+ for (const entry of this.#entries) {
33
+ entry.controller.abort(new Error("Resident runtime is shutting down"));
34
+ }
35
+ await Promise.allSettled(
36
+ Array.from(this.#entries, (entry) => entry.promise)
37
+ );
38
+ }
39
+ }
@@ -0,0 +1,55 @@
1
+ /** Admission, bounded-reader, and model-lease boundary for resident REST reads. */
2
+
3
+ import type { ResidentRuntime } from "./resident-runtime";
4
+
5
+ function unavailableResponse(): Response {
6
+ return Response.json(
7
+ { error: { code: "UNAVAILABLE", message: "Resident runtime unavailable" } },
8
+ { status: 503 }
9
+ );
10
+ }
11
+
12
+ function saturatedResponse(): Response {
13
+ return Response.json(
14
+ {
15
+ error: { code: "RATE_LIMITED", message: "Resident reader queue is full" },
16
+ },
17
+ { status: 429 }
18
+ );
19
+ }
20
+
21
+ export async function handleResidentRead(
22
+ runtime: ResidentRuntime,
23
+ request: Request | undefined,
24
+ operation: (signal: AbortSignal) => Promise<Response> | Response
25
+ ): Promise<Response> {
26
+ const admitted = runtime.admitRequest(request?.signal);
27
+ if (!admitted) return unavailableResponse();
28
+
29
+ let releaseReader: (() => void) | undefined;
30
+ try {
31
+ releaseReader = await runtime.readerGate.acquire(admitted.signal);
32
+ if (admitted.signal.aborted) return unavailableResponse();
33
+ const response = await runtime.withModelLease(() =>
34
+ Promise.resolve(operation(admitted.signal))
35
+ );
36
+ return admitted.signal.aborted ? unavailableResponse() : response;
37
+ } catch (error) {
38
+ if (
39
+ admitted.signal.aborted ||
40
+ (error instanceof Error && error.message === "Resident request aborted")
41
+ ) {
42
+ return unavailableResponse();
43
+ }
44
+ if (
45
+ error instanceof Error &&
46
+ error.message === "Resident reader queue is full"
47
+ ) {
48
+ return saturatedResponse();
49
+ }
50
+ throw error;
51
+ } finally {
52
+ releaseReader?.();
53
+ admitted.finish();
54
+ }
55
+ }