@gmickel/gno 1.46.0 → 2.1.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 (235) hide show
  1. package/README.md +17 -5
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/spa-production.json.gz +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip.sha256 +1 -0
  7. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  8. package/browser-extension/dist/manifest.json +1 -1
  9. package/browser-extension/dist/preview.html +1 -1
  10. package/browser-extension/dist/service-worker.js +32 -33
  11. package/bunfig.toml +2 -0
  12. package/package.json +40 -26
  13. package/spec/cli.md +29 -4
  14. package/spec/db/schema.sql +146 -1
  15. package/spec/mcp.md +26 -0
  16. package/src/app/context-runtime-types.ts +3 -0
  17. package/src/app/context-runtime.ts +2 -0
  18. package/src/cli/commands/ask.ts +6 -1
  19. package/src/cli/commands/daemon.ts +21 -8
  20. package/src/cli/commands/embed.ts +77 -41
  21. package/src/cli/detach.ts +3 -2
  22. package/src/config/types.ts +3 -3
  23. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  24. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  25. package/src/converters/versions.ts +6 -8
  26. package/src/core/context-evidence.ts +8 -4
  27. package/src/core/job-manager.ts +95 -13
  28. package/src/core/network-boundary-inventory.ts +10 -0
  29. package/src/core/shutdown-budget.ts +45 -0
  30. package/src/embed/backlog.ts +107 -4
  31. package/src/embed/batch.ts +42 -2
  32. package/src/embed/fingerprint.ts +16 -0
  33. package/src/embed/retry.ts +113 -5
  34. package/src/embed/variant-backlog.ts +105 -0
  35. package/src/embed/variant-plan.ts +62 -0
  36. package/src/embed/variant-retry.ts +113 -0
  37. package/src/ingestion/graph-reconciliation.ts +327 -0
  38. package/src/ingestion/sync.ts +9 -272
  39. package/src/llm/http-inference.ts +6 -0
  40. package/src/llm/httpEmbedding.ts +37 -6
  41. package/src/llm/httpGeneration.ts +18 -3
  42. package/src/llm/httpRerank.ts +23 -5
  43. package/src/llm/inference-cancellation.ts +168 -0
  44. package/src/llm/inference-scope.ts +202 -0
  45. package/src/llm/lazy-ports.ts +115 -0
  46. package/src/llm/native-worker/client.ts +541 -0
  47. package/src/llm/native-worker/dispatcher.ts +228 -0
  48. package/src/llm/native-worker/embedding-identity.ts +33 -0
  49. package/src/llm/native-worker/entry.ts +173 -0
  50. package/src/llm/native-worker/errors.ts +32 -0
  51. package/src/llm/native-worker/evaluation.ts +16 -0
  52. package/src/llm/native-worker/owned-exit.ts +108 -0
  53. package/src/llm/native-worker/owner.ts +141 -0
  54. package/src/llm/native-worker/ports.ts +317 -0
  55. package/src/llm/native-worker/protocol.ts +442 -0
  56. package/src/llm/native-worker/runtime-config.ts +92 -0
  57. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  58. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  59. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  60. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  61. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  62. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  63. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  64. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  65. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  66. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  67. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  68. package/src/llm/types.ts +35 -5
  69. package/src/mcp/context.ts +27 -0
  70. package/src/mcp/http-transport.ts +12 -10
  71. package/src/mcp/server.ts +3 -0
  72. package/src/mcp/tool-profile.ts +30 -8
  73. package/src/mcp/tools/context.ts +8 -11
  74. package/src/mcp/tools/embed.ts +1 -1
  75. package/src/mcp/tools/index-cmd.ts +1 -1
  76. package/src/mcp/tools/index.ts +10 -8
  77. package/src/mcp/tools/query.ts +14 -30
  78. package/src/mcp/tools/vsearch.ts +1 -1
  79. package/src/pipeline/answer.ts +23 -3
  80. package/src/pipeline/claim-verifier.ts +6 -0
  81. package/src/pipeline/expansion.ts +43 -40
  82. package/src/pipeline/explain.ts +6 -2
  83. package/src/pipeline/filters.ts +63 -0
  84. package/src/pipeline/fusion.ts +29 -9
  85. package/src/pipeline/graph-retrieval.ts +29 -9
  86. package/src/pipeline/hybrid.ts +198 -55
  87. package/src/pipeline/hydration.ts +161 -0
  88. package/src/pipeline/owner-fusion.ts +87 -0
  89. package/src/pipeline/rerank.ts +35 -11
  90. package/src/pipeline/search.ts +13 -2
  91. package/src/pipeline/types.ts +5 -3
  92. package/src/pipeline/vsearch.ts +87 -7
  93. package/src/sdk/client.ts +47 -3
  94. package/src/sdk/embed.ts +63 -39
  95. package/src/serve/background-runtime.ts +1 -1
  96. package/src/serve/context.ts +41 -56
  97. package/src/serve/embed-scheduler.ts +58 -35
  98. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  99. package/src/serve/public/components/PublishExportDialog.tsx +266 -0
  100. package/src/serve/public/globals.built.css +1 -1
  101. package/src/serve/public/globals.css +35 -0
  102. package/src/serve/public/lib/publish-export.ts +81 -1
  103. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  104. package/src/serve/public/pages/Collections.tsx +12 -46
  105. package/src/serve/public/pages/DocView.tsx +14 -52
  106. package/src/serve/resident-admission.ts +36 -36
  107. package/src/serve/resident-background-work.ts +20 -2
  108. package/src/serve/resident-request.ts +11 -5
  109. package/src/serve/resident-runtime.ts +97 -61
  110. package/src/serve/resident-shutdown.ts +153 -0
  111. package/src/serve/routes/api.ts +3 -1
  112. package/src/serve/server.ts +47 -26
  113. package/src/store/migrations/028-vector-variants.ts +54 -0
  114. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  115. package/src/store/migrations/index.ts +4 -0
  116. package/src/store/sqlite/adapter.ts +251 -183
  117. package/src/store/sqlite/eligibility.ts +174 -0
  118. package/src/store/sqlite/graph-edge-application.ts +66 -0
  119. package/src/store/sqlite/graph-reference-state.ts +194 -0
  120. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  121. package/src/store/types.ts +80 -12
  122. package/src/store/vector/eligibility.ts +36 -0
  123. package/src/store/vector/freshness.ts +33 -6
  124. package/src/store/vector/lazy.ts +81 -0
  125. package/src/store/vector/sqlite-vec.ts +106 -54
  126. package/src/store/vector/stats.ts +14 -3
  127. package/src/store/vector/types.ts +35 -2
  128. package/src/store/vector/variant-search.ts +192 -0
  129. package/src/store/vector/variants.ts +451 -0
  130. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  131. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  132. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  136. package/vendor/converters/markitdown-ts/package.json +77 -0
  137. package/vendor/converters/officeparser/LICENSE +21 -0
  138. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  140. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  142. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  144. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  145. package/vendor/converters/officeparser/dist/cli.js +381 -0
  146. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  147. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  148. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  150. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  152. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  154. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  156. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  158. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  160. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  162. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  164. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  166. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  167. package/vendor/converters/officeparser/dist/index.js +72 -0
  168. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  175. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  177. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  179. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  181. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  183. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  185. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  187. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  189. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  191. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  193. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  195. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  196. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  197. package/vendor/converters/officeparser/dist/types.js +107 -0
  198. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  200. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  202. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  204. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  206. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  208. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  210. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  212. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  214. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  216. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  218. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  220. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  222. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  224. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  226. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  228. package/vendor/converters/officeparser/package.json +147 -0
  229. package/vendor/converters/upstream-manifest.json +124 -0
  230. package/vendor/dependency-fixes/README.md +77 -0
  231. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  232. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  234. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  235. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -568,3 +568,38 @@ mark {
568
568
  animation: none;
569
569
  }
570
570
  }
571
+
572
+ /* Keep the review and actions inside the viewport, including short windows and
573
+ mobile keyboards. Only the form body scrolls; the close/export controls stay put. */
574
+ .publish-export-dialog {
575
+ display: flex;
576
+ flex-direction: column;
577
+ width: min(36rem, calc(100vw - 2rem));
578
+ max-width: 36rem;
579
+ max-height: calc(100dvh - 2rem);
580
+ gap: 0;
581
+ overflow: hidden;
582
+ padding: 0;
583
+ }
584
+
585
+ .publish-export-dialog-header {
586
+ flex-shrink: 0;
587
+ padding: 1.25rem 2.5rem 1rem 1.5rem;
588
+ overflow-wrap: anywhere;
589
+ }
590
+
591
+ .publish-export-dialog-body {
592
+ display: flex;
593
+ min-height: 0;
594
+ flex-direction: column;
595
+ gap: 1rem;
596
+ overflow-y: auto;
597
+ overscroll-behavior: contain;
598
+ padding: 0.25rem 1.5rem 1.25rem;
599
+ }
600
+
601
+ .publish-export-dialog-footer {
602
+ flex-shrink: 0;
603
+ border-top: 1px solid hsl(var(--border));
604
+ padding: 1rem 1.5rem;
605
+ }
@@ -1,4 +1,7 @@
1
- import type { PublishArtifact } from "../../../publish/artifact";
1
+ import type {
2
+ PublishArtifact,
3
+ PublishVisibility,
4
+ } from "../../../publish/artifact";
2
5
 
3
6
  export interface PublishExportResponse {
4
7
  artifact: PublishArtifact;
@@ -19,3 +22,80 @@ export function downloadPublishArtifactFile(
19
22
  anchor.click();
20
23
  URL.revokeObjectURL(href);
21
24
  }
25
+
26
+ /**
27
+ * Local help metadata, checked against gno.sh src/lib/server/{billing,entitlements}.ts
28
+ * on 2026-09-05. Keep in sync when hosted plan capabilities change. These labels
29
+ * explain availability; only the hosted entitlement service authorizes publishing.
30
+ */
31
+ export const PUBLISH_ACCESS_OPTIONS: ReadonlyArray<{
32
+ value: PublishVisibility;
33
+ label: string;
34
+ audience: string;
35
+ availability: string;
36
+ }> = [
37
+ {
38
+ value: "public",
39
+ label: "Public",
40
+ audience:
41
+ "Anyone can read, discover, and download the published content, including search engines and agents.",
42
+ availability: "Free and paid plans",
43
+ },
44
+ {
45
+ value: "secret-link",
46
+ label: "Secret link",
47
+ audience:
48
+ "Anyone with the link can read and forward it. Readers do not need an invitation.",
49
+ availability: "Paid plans with private publishing",
50
+ },
51
+ {
52
+ value: "invite-only",
53
+ label: "Invite only",
54
+ audience:
55
+ "Personal shares start with owner access only. Choose recipients or the intended organization audience in Studio before publishing.",
56
+ availability: "Paid plans with private publishing",
57
+ },
58
+ {
59
+ value: "encrypted",
60
+ label: "Encrypted",
61
+ audience:
62
+ "Anyone with both the link and passphrase can decrypt the content in their browser. Share the passphrase separately.",
63
+ availability: "Paid plans with encrypted publishing",
64
+ },
65
+ ];
66
+
67
+ export function buildPublishExportRequest(input: {
68
+ target: string;
69
+ visibility: string | null;
70
+ passphrase: string;
71
+ passphraseConfirmation: string;
72
+ audienceConfirmed: boolean;
73
+ }): {
74
+ target: string;
75
+ visibility: PublishVisibility;
76
+ encryptionPassphrase?: string;
77
+ } {
78
+ const option = PUBLISH_ACCESS_OPTIONS.find(
79
+ ({ value }) => value === input.visibility
80
+ );
81
+ if (!option) {
82
+ throw new Error("Choose who can read this export.");
83
+ }
84
+ if (!input.audienceConfirmed) {
85
+ throw new Error("Review and confirm the audience before exporting.");
86
+ }
87
+ if (option.value === "encrypted") {
88
+ if (!input.passphrase.trim()) {
89
+ throw new Error("Enter a passphrase for the encrypted export.");
90
+ }
91
+ if (input.passphrase !== input.passphraseConfirmation) {
92
+ throw new Error("The passphrases do not match.");
93
+ }
94
+ return {
95
+ target: input.target,
96
+ visibility: option.value,
97
+ encryptionPassphrase: input.passphrase,
98
+ };
99
+ }
100
+ return { target: input.target, visibility: option.value };
101
+ }
@@ -3,9 +3,13 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
3
3
  "1c",
4
4
  "1c-query",
5
5
  "abap",
6
+ "actionscript",
6
7
  "actionscript-3",
7
8
  "ada",
8
9
  "adoc",
10
+ "ahk",
11
+ "ahk1",
12
+ "ahk2",
9
13
  "angular-html",
10
14
  "angular-ts",
11
15
  "apache",
@@ -13,6 +17,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
13
17
  "apl",
14
18
  "applescript",
15
19
  "ara",
20
+ "as3",
16
21
  "asciidoc",
17
22
  "asm",
18
23
  "astro",
@@ -37,6 +42,8 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
37
42
  "cadence",
38
43
  "cairo",
39
44
  "cdc",
45
+ "chapel",
46
+ "chpl",
40
47
  "cjs",
41
48
  "clarity",
42
49
  "clj",
@@ -151,6 +158,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
151
158
  "jsx",
152
159
  "julia",
153
160
  "just",
161
+ "justfile",
154
162
  "kdl",
155
163
  "kotlin",
156
164
  "kql",
@@ -197,6 +205,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
197
205
  "nginx",
198
206
  "nim",
199
207
  "nix",
208
+ "nsis",
200
209
  "nu",
201
210
  "nushell",
202
211
  "objc",
@@ -205,6 +214,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
205
214
  "ocaml",
206
215
  "odin",
207
216
  "openscad",
217
+ "org",
208
218
  "pascal",
209
219
  "perl",
210
220
  "perl6",
@@ -228,6 +238,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
228
238
  "pug",
229
239
  "puppet",
230
240
  "purescript",
241
+ "pwsh",
231
242
  "py",
232
243
  "python",
233
244
  "ql",
@@ -239,6 +250,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
239
250
  "raku",
240
251
  "razor",
241
252
  "rb",
253
+ "rbs",
242
254
  "reg",
243
255
  "regex",
244
256
  "regexp",
@@ -249,6 +261,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
249
261
  "rs",
250
262
  "rst",
251
263
  "ruby",
264
+ "ruby-signature",
252
265
  "rust",
253
266
  "sas",
254
267
  "sass",
@@ -264,6 +277,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
264
277
  "shellscript",
265
278
  "shellsession",
266
279
  "smalltalk",
280
+ "smithy",
267
281
  "solidity",
268
282
  "soy",
269
283
  "sparql",
@@ -37,6 +37,7 @@ import {
37
37
  } from "../components/CollectionModelDialog";
38
38
  import { CollectionsEmptyState } from "../components/CollectionsEmptyState";
39
39
  import { IndexingProgress } from "../components/IndexingProgress";
40
+ import { PublishExportDialog } from "../components/PublishExportDialog";
40
41
  import { Badge } from "../components/ui/badge";
41
42
  import { Button } from "../components/ui/button";
42
43
  import {
@@ -67,10 +68,6 @@ import {
67
68
  TooltipTrigger,
68
69
  } from "../components/ui/tooltip";
69
70
  import { apiFetch } from "../hooks/use-api";
70
- import {
71
- downloadPublishArtifactFile,
72
- type PublishExportResponse,
73
- } from "../lib/publish-export";
74
71
 
75
72
  interface PageProps {
76
73
  navigate: (to: string | number) => void;
@@ -129,7 +126,6 @@ interface CollectionCardProps {
129
126
  onModelSettings: () => void;
130
127
  onReindex: () => void;
131
128
  onRemove: () => void;
132
- isExporting: boolean;
133
129
  isReindexing: boolean;
134
130
  }
135
131
 
@@ -161,7 +157,6 @@ function CollectionCard({
161
157
  onModelSettings,
162
158
  onReindex,
163
159
  onRemove,
164
- isExporting,
165
160
  isReindexing,
166
161
  }: CollectionCardProps) {
167
162
  const embedPercent =
@@ -227,17 +222,13 @@ function CollectionCard({
227
222
  Embedding cleanup
228
223
  </DropdownMenuItem>
229
224
  <DropdownMenuItem
230
- disabled={actionsDisabled || isExporting}
225
+ disabled={actionsDisabled}
231
226
  onClick={(event) => {
232
227
  event.stopPropagation();
233
228
  onExport();
234
229
  }}
235
230
  >
236
- {isExporting ? (
237
- <Loader2Icon className="mr-2 size-4 animate-spin" />
238
- ) : (
239
- <Share2Icon className="mr-2 size-4" />
240
- )}
231
+ <Share2Icon className="mr-2 size-4" />
241
232
  Export for gno.sh
242
233
  </DropdownMenuItem>
243
234
  <DropdownMenuSeparator />
@@ -361,8 +352,7 @@ export default function Collections({ navigate }: PageProps) {
361
352
  const [syncJobId, setSyncJobId] = useState<string | null>(null);
362
353
  const [syncTarget, setSyncTarget] = useState<SyncTarget>(null);
363
354
  const [syncError, setSyncError] = useState<string | null>(null);
364
- const [exportError, setExportError] = useState<string | null>(null);
365
- const [exportingCollectionName, setExportingCollectionName] = useState<
355
+ const [exportCollectionName, setExportCollectionName] = useState<
366
356
  string | null
367
357
  >(null);
368
358
  const [removeDialog, setRemoveDialog] = useState<CollectionStats | null>(
@@ -499,30 +489,6 @@ export default function Collections({ navigate }: PageProps) {
499
489
  await loadCollections();
500
490
  };
501
491
 
502
- const handleExport = async (name: string) => {
503
- setExportError(null);
504
- setExportingCollectionName(name);
505
-
506
- const { data, error: err } = await apiFetch<PublishExportResponse>(
507
- "/api/publish/export",
508
- {
509
- body: JSON.stringify({ target: name }),
510
- method: "POST",
511
- }
512
- );
513
-
514
- setExportingCollectionName(null);
515
-
516
- if (err) {
517
- setExportError(err);
518
- return;
519
- }
520
-
521
- if (data) {
522
- downloadPublishArtifactFile(data);
523
- }
524
- };
525
-
526
492
  // Loading state
527
493
  if (loading) {
528
494
  return (
@@ -643,12 +609,13 @@ export default function Collections({ navigate }: PageProps) {
643
609
  </Card>
644
610
  )}
645
611
 
646
- {exportError && (
647
- <Card className="mx-auto mb-6 max-w-3xl border-destructive bg-destructive/10">
648
- <CardContent className="py-4">
649
- <p className="text-destructive text-sm">{exportError}</p>
650
- </CardContent>
651
- </Card>
612
+ {exportCollectionName !== null && (
613
+ <PublishExportDialog
614
+ key={exportCollectionName}
615
+ onClose={() => setExportCollectionName(null)}
616
+ target={exportCollectionName}
617
+ title={exportCollectionName}
618
+ />
652
619
  )}
653
620
 
654
621
  {/* Error */}
@@ -687,7 +654,6 @@ export default function Collections({ navigate }: PageProps) {
687
654
  <CollectionCard
688
655
  actionsDisabled={Boolean(syncJobId)}
689
656
  collection={collection}
690
- isExporting={exportingCollectionName === collection.name}
691
657
  isReindexing={
692
658
  Boolean(syncJobId) &&
693
659
  syncTarget?.kind === "collection" &&
@@ -704,7 +670,7 @@ export default function Collections({ navigate }: PageProps) {
704
670
  setEmbeddingCleanupNote(null);
705
671
  }}
706
672
  onExport={() => {
707
- void handleExport(collection.name);
673
+ setExportCollectionName(collection.name);
708
674
  }}
709
675
  onModelSettings={() => setModelDialogCollection(collection)}
710
676
  onReindex={() => void handleReindex(collection.name)}
@@ -47,6 +47,7 @@ import {
47
47
  OutgoingLinksPanel,
48
48
  type OutgoingLink,
49
49
  } from "../components/OutgoingLinksPanel";
50
+ import { PublishExportDialog } from "../components/PublishExportDialog";
50
51
  import { RefactorImpactPreview } from "../components/RefactorImpactPreview";
51
52
  import { RelatedNotesSidebar } from "../components/RelatedNotesSidebar";
52
53
  import { TagInput } from "../components/TagInput";
@@ -81,10 +82,6 @@ import {
81
82
  isPdfDocument,
82
83
  } from "../lib/doc-asset-url";
83
84
  import { waitForDocumentAvailability } from "../lib/document-availability";
84
- import {
85
- downloadPublishArtifactFile,
86
- type PublishExportResponse,
87
- } from "../lib/publish-export";
88
85
  import {
89
86
  buildReadableSectionUrl,
90
87
  createCitationSectionUrl,
@@ -411,11 +408,7 @@ export default function DocView({ navigate }: PageProps) {
411
408
  const [externalChangeNotice, setExternalChangeNotice] = useState<
412
409
  string | null
413
410
  >(null);
414
- const [exportingPublishArtifact, setExportingPublishArtifact] =
415
- useState(false);
416
- const [publishExportError, setPublishExportError] = useState<string | null>(
417
- null
418
- );
411
+ const [publishExportOpen, setPublishExportOpen] = useState(false);
419
412
 
420
413
  // Tag editing state
421
414
  const [editingTags, setEditingTags] = useState(false);
@@ -879,32 +872,6 @@ export default function DocView({ navigate }: PageProps) {
879
872
  }
880
873
  }, [doc, navigate]);
881
874
 
882
- const handlePublishExport = useCallback(async () => {
883
- if (!doc) {
884
- return;
885
- }
886
-
887
- setPublishExportError(null);
888
- setExportingPublishArtifact(true);
889
- const { data, error: err } = await apiFetch<PublishExportResponse>(
890
- "/api/publish/export",
891
- {
892
- body: JSON.stringify({ target: doc.uri }),
893
- method: "POST",
894
- }
895
- );
896
- setExportingPublishArtifact(false);
897
-
898
- if (err) {
899
- setPublishExportError(err);
900
- return;
901
- }
902
-
903
- if (data) {
904
- downloadPublishArtifactFile(data);
905
- }
906
- }, [doc]);
907
-
908
875
  const handleDelete = async () => {
909
876
  if (!doc) return;
910
877
 
@@ -1784,18 +1751,13 @@ export default function DocView({ navigate }: PageProps) {
1784
1751
  </Button>
1785
1752
  <Button
1786
1753
  className="gap-1.5"
1787
- disabled={exportingPublishArtifact}
1788
1754
  onClick={() => {
1789
- void handlePublishExport();
1755
+ setPublishExportOpen(true);
1790
1756
  }}
1791
1757
  size="sm"
1792
1758
  variant="outline"
1793
1759
  >
1794
- {exportingPublishArtifact ? (
1795
- <Loader2Icon className="size-4 animate-spin" />
1796
- ) : (
1797
- <Share2Icon className="size-4" />
1798
- )}
1760
+ <Share2Icon className="size-4" />
1799
1761
  Export for gno.sh
1800
1762
  </Button>
1801
1763
  <Button
@@ -1847,18 +1809,13 @@ export default function DocView({ navigate }: PageProps) {
1847
1809
  )}
1848
1810
  <Button
1849
1811
  className="gap-1.5"
1850
- disabled={exportingPublishArtifact}
1851
1812
  onClick={() => {
1852
- void handlePublishExport();
1813
+ setPublishExportOpen(true);
1853
1814
  }}
1854
1815
  size="sm"
1855
1816
  variant="outline"
1856
1817
  >
1857
- {exportingPublishArtifact ? (
1858
- <Loader2Icon className="size-4 animate-spin" />
1859
- ) : (
1860
- <Share2Icon className="size-4" />
1861
- )}
1818
+ <Share2Icon className="size-4" />
1862
1819
  Export for gno.sh
1863
1820
  </Button>
1864
1821
  {localClient && doc.source.absPath && (
@@ -1945,11 +1902,16 @@ export default function DocView({ navigate }: PageProps) {
1945
1902
  </>
1946
1903
  )}
1947
1904
  </div>
1948
- {publishExportError && (
1949
- <p className="pt-2 text-destructive text-sm">{publishExportError}</p>
1950
- )}
1951
1905
  </header>
1952
1906
 
1907
+ {publishExportOpen && doc && (
1908
+ <PublishExportDialog
1909
+ key={doc.uri}
1910
+ onClose={() => setPublishExportOpen(false)}
1911
+ target={doc.uri}
1912
+ title={doc.title ?? doc.uri}
1913
+ />
1914
+ )}
1953
1915
  <div className="mx-auto flex max-w-[1800px] gap-5 px-6 xl:px-8">
1954
1916
  {/* Left rail — metadata + outline */}
1955
1917
  {doc && (
@@ -2,6 +2,8 @@
2
2
 
3
3
  import type { ResidentRequestHandle } from "./resident-runtime";
4
4
 
5
+ import { settlesBy } from "../core/shutdown-budget";
6
+
5
7
  const DEFAULT_READER_LIMIT = 8;
6
8
  const DEFAULT_READER_QUEUE_LIMIT = 64;
7
9
 
@@ -63,21 +65,32 @@ export class ReaderGate {
63
65
  signal?.addEventListener("abort", entry.onAbort, { once: true });
64
66
  this.#queue.push(entry);
65
67
  });
68
+ // Release reserved capacity if cancellation won the handoff race.
69
+ if (signal?.aborted) {
70
+ this.#releaseSlot();
71
+ throw new Error("Resident request aborted");
72
+ }
73
+ } else {
74
+ this.#active += 1;
66
75
  }
67
- if (signal?.aborted) throw new Error("Resident request aborted");
68
- this.#active += 1;
69
76
  let released = false;
70
77
  return () => {
71
78
  if (released) return;
72
79
  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
- }
80
+ this.#releaseSlot();
79
81
  };
80
82
  }
83
+
84
+ #releaseSlot(): void {
85
+ const next = this.#queue.shift();
86
+ if (next) {
87
+ // Transfer ownership synchronously, before any fresh acquire can run.
88
+ next.signal?.removeEventListener("abort", next.onAbort!);
89
+ next.resolve();
90
+ } else {
91
+ this.#active -= 1;
92
+ }
93
+ }
81
94
  }
82
95
 
83
96
  export class AdmissionController {
@@ -122,38 +135,25 @@ export class AdmissionController {
122
135
  deadlineMs: number,
123
136
  abortSettleMs = deadlineMs
124
137
  ): Promise<boolean> {
138
+ this.stop();
139
+ const deadline = performance.now() + deadlineMs;
140
+ if (await settlesBy(this.drain(), deadline)) return false;
141
+ this.cancel();
142
+ await settlesBy(this.drain(), deadline + abortSettleMs);
143
+ return true;
144
+ }
145
+
146
+ stop(): void {
125
147
  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;
148
+ }
145
149
 
150
+ cancel(): void {
146
151
  for (const controller of this.#requests.values())
147
152
  controller.abort(new Error("Resident runtime is shutting down"));
153
+ }
148
154
 
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;
155
+ drain(): Promise<void> {
156
+ if (!this.#requests.size) return Promise.resolve();
157
+ return new Promise<void>((resolve) => this.#drainWaiters.add(resolve));
158
158
  }
159
159
  }
@@ -1,4 +1,8 @@
1
1
  /** Tracks cancellable work that intentionally outlives its initiating request. */
2
+ import {
3
+ withBackgroundInference,
4
+ withOwnedInferenceScope,
5
+ } from "../llm/inference-scope";
2
6
 
3
7
  interface BackgroundWorkEntry {
4
8
  controller: AbortController;
@@ -21,19 +25,33 @@ export class ResidentBackgroundWork {
21
25
  promise: Promise.resolve(),
22
26
  };
23
27
  entry.promise = Promise.resolve()
24
- .then(() => operation(controller.signal))
28
+ .then(() =>
29
+ withBackgroundInference(() =>
30
+ withOwnedInferenceScope({ signal: controller.signal }, () =>
31
+ operation(controller.signal)
32
+ )
33
+ )
34
+ )
25
35
  .catch(() => undefined)
26
36
  .finally(() => this.#entries.delete(entry));
27
37
  this.#entries.add(entry);
28
38
  return true;
29
39
  }
30
40
 
31
- async cancelAndDrain(): Promise<void> {
41
+ cancel(): void {
32
42
  for (const entry of this.#entries) {
33
43
  entry.controller.abort(new Error("Resident runtime is shutting down"));
34
44
  }
45
+ }
46
+
47
+ async drain(): Promise<void> {
35
48
  await Promise.allSettled(
36
49
  Array.from(this.#entries, (entry) => entry.promise)
37
50
  );
38
51
  }
52
+
53
+ async cancelAndDrain(): Promise<void> {
54
+ this.cancel();
55
+ await this.drain();
56
+ }
39
57
  }
@@ -1,6 +1,7 @@
1
- /** Admission, bounded-reader, and model-lease boundary for resident REST reads. */
2
-
3
1
  import type { ResidentRuntime } from "./resident-runtime";
2
+ /** Admission and bounded-reader boundary for resident REST reads. */
3
+
4
+ import { withInferenceScope } from "../llm/inference-scope";
4
5
 
5
6
  function unavailableResponse(): Response {
6
7
  return Response.json(
@@ -100,8 +101,9 @@ export async function handleResidentRead(
100
101
  try {
101
102
  releaseReader = await runtime.readerGate.acquire(admitted.signal);
102
103
  if (admitted.signal.aborted) return unavailableResponse();
103
- const response = await runtime.withModelLease(() =>
104
- Promise.resolve(operation(admitted.signal))
104
+ const response = await withInferenceScope(
105
+ { signal: admitted.signal },
106
+ async () => operation(admitted.signal)
105
107
  );
106
108
  if (admitted.signal.aborted) return unavailableResponse();
107
109
  if (!isAuthorizationEpochCurrent()) {
@@ -109,7 +111,11 @@ export async function handleResidentRead(
109
111
  }
110
112
  if (response.headers.get("content-type")?.includes("text/event-stream")) {
111
113
  deferredFinish = true;
112
- return wrapResidentStream(response, isAuthorizationEpochCurrent, finish);
114
+ return wrapResidentStream(
115
+ response,
116
+ () => !admitted.signal.aborted && isAuthorizationEpochCurrent(),
117
+ finish
118
+ );
113
119
  }
114
120
  return response;
115
121
  } catch (error) {