@lamplitisles/dsh-nanocodex 0.1.0-beta.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 (276) hide show
  1. package/LICENSE +65 -0
  2. package/NOTICE +2 -0
  3. package/README.md +182 -0
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/cordis.patch.yml +52 -0
  6. package/dist/index.d.ts +435 -0
  7. package/dist/index.js +3405 -0
  8. package/dist/standard-preset.d.ts +7 -0
  9. package/dist/standard-preset.js +25 -0
  10. package/engine-release.json +14 -0
  11. package/package.json +119 -0
  12. package/presets/standard/agent.cordis.yml +6 -0
  13. package/presets/standard/preset.yml +2 -0
  14. package/vendor/nanocodex/README.md +1344 -0
  15. package/vendor/nanocodex/actions/events.d.mts +10 -0
  16. package/vendor/nanocodex/actions/events.mjs +163 -0
  17. package/vendor/nanocodex/actions/index.d.mts +13 -0
  18. package/vendor/nanocodex/actions/index.mjs +35 -0
  19. package/vendor/nanocodex/actions/session.d.mts +66 -0
  20. package/vendor/nanocodex/actions/session.mjs +59 -0
  21. package/vendor/nanocodex/actions/turn.d.mts +59 -0
  22. package/vendor/nanocodex/actions/turn.mjs +37 -0
  23. package/vendor/nanocodex/actions/voice.d.mts +22 -0
  24. package/vendor/nanocodex/actions/voice.mjs +50 -0
  25. package/vendor/nanocodex/browser/Agent.d.mts +55 -0
  26. package/vendor/nanocodex/browser/Agent.mjs +11 -0
  27. package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
  28. package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
  29. package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
  30. package/vendor/nanocodex/browser/Transport.d.mts +74 -0
  31. package/vendor/nanocodex/browser/Transport.mjs +61 -0
  32. package/vendor/nanocodex/browser/Voice.d.mts +71 -0
  33. package/vendor/nanocodex/browser/Voice.mjs +291 -0
  34. package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
  35. package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
  36. package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
  37. package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
  38. package/vendor/nanocodex/browser/config.d.mts +36 -0
  39. package/vendor/nanocodex/browser/config.mjs +439 -0
  40. package/vendor/nanocodex/browser/engine.mjs +13 -0
  41. package/vendor/nanocodex/browser/harness.mjs +55 -0
  42. package/vendor/nanocodex/browser/host.d.mts +83 -0
  43. package/vendor/nanocodex/browser/host.mjs +555 -0
  44. package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
  45. package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
  46. package/vendor/nanocodex/browser/index.d.mts +92 -0
  47. package/vendor/nanocodex/browser/index.mjs +23 -0
  48. package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
  49. package/vendor/nanocodex/browser/workspace.d.mts +16 -0
  50. package/vendor/nanocodex/browser/workspace.mjs +107 -0
  51. package/vendor/nanocodex/cloud/Client.d.mts +83 -0
  52. package/vendor/nanocodex/cloud/Client.mjs +231 -0
  53. package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
  54. package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
  55. package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
  56. package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
  57. package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
  58. package/vendor/nanocodex/cloud/Errors.mjs +39 -0
  59. package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
  60. package/vendor/nanocodex/cloud/Principal.mjs +88 -0
  61. package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
  62. package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
  63. package/vendor/nanocodex/cloud/Transport.mjs +454 -0
  64. package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
  65. package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
  66. package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
  67. package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
  68. package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
  69. package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
  70. package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
  71. package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
  72. package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
  73. package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
  74. package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
  75. package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
  76. package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
  77. package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
  78. package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
  79. package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
  80. package/vendor/nanocodex/cloud/index.d.mts +30 -0
  81. package/vendor/nanocodex/cloud/index.mjs +9 -0
  82. package/vendor/nanocodex/cloud/internal.mjs +533 -0
  83. package/vendor/nanocodex/cloud/mercator.mjs +108 -0
  84. package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
  85. package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
  86. package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
  87. package/vendor/nanocodex/cloud/server/index.mjs +1 -0
  88. package/vendor/nanocodex/cloud/types.d.mts +211 -0
  89. package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
  90. package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
  91. package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
  92. package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
  93. package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
  94. package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
  95. package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
  96. package/vendor/nanocodex/cloudflare/index.mjs +6 -0
  97. package/vendor/nanocodex/host/Agent.d.mts +55 -0
  98. package/vendor/nanocodex/host/Agent.mjs +1 -0
  99. package/vendor/nanocodex/host/index.d.mts +82 -0
  100. package/vendor/nanocodex/host/index.mjs +10 -0
  101. package/vendor/nanocodex/index.d.mts +81 -0
  102. package/vendor/nanocodex/index.mjs +12 -0
  103. package/vendor/nanocodex/internal.mjs +1275 -0
  104. package/vendor/nanocodex/managed/Agent.d.mts +380 -0
  105. package/vendor/nanocodex/managed/Agent.mjs +1694 -0
  106. package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
  107. package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
  108. package/vendor/nanocodex/managed/README.md +241 -0
  109. package/vendor/nanocodex/managed/Voice.mjs +202 -0
  110. package/vendor/nanocodex/managed/index.d.mts +20 -0
  111. package/vendor/nanocodex/managed/index.mjs +2 -0
  112. package/vendor/nanocodex/managed/internal.mjs +119 -0
  113. package/vendor/nanocodex/node/Agent.d.mts +50 -0
  114. package/vendor/nanocodex/node/Agent.mjs +203 -0
  115. package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
  116. package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
  117. package/vendor/nanocodex/node/Transport.d.mts +44 -0
  118. package/vendor/nanocodex/node/Transport.mjs +46 -0
  119. package/vendor/nanocodex/node/host.mjs +731 -0
  120. package/vendor/nanocodex/node/index.d.mts +73 -0
  121. package/vendor/nanocodex/node/index.mjs +17 -0
  122. package/vendor/nanocodex/node/workspace.d.mts +10 -0
  123. package/vendor/nanocodex/node/workspace.mjs +198 -0
  124. package/vendor/nanocodex/package.json +200 -0
  125. package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
  126. package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
  127. package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
  128. package/vendor/nanocodex/pkg-node/package.json +1 -0
  129. package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
  130. package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
  131. package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
  132. package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
  133. package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
  134. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
  135. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
  136. package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
  137. package/vendor/nanocodex/pkg-web/package.json +1 -0
  138. package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
  139. package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
  140. package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
  141. package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
  142. package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
  143. package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
  144. package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
  145. package/vendor/nanocodex/runtime/durability.mjs +153 -0
  146. package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
  147. package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
  148. package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
  149. package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
  150. package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
  151. package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
  152. package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
  153. package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
  154. package/vendor/nanocodex/runtime/subagents.mjs +54 -0
  155. package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
  156. package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
  157. package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
  158. package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
  159. package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
  160. package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
  161. package/vendor/nanocodex/runtime/utf8.mjs +1 -0
  162. package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
  163. package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
  164. package/vendor/nanocodex/runtime/workspace.mjs +1 -0
  165. package/vendor/nanocodex/tools/Tools.d.mts +56 -0
  166. package/vendor/nanocodex/tools/Tools.mjs +136 -0
  167. package/vendor/nanocodex/tools/artifact.d.mts +1 -0
  168. package/vendor/nanocodex/tools/artifact.mjs +1 -0
  169. package/vendor/nanocodex/tools/attachment.mjs +1 -0
  170. package/vendor/nanocodex/tools/bash.d.mts +1 -0
  171. package/vendor/nanocodex/tools/bash.mjs +1 -0
  172. package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
  173. package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
  174. package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
  175. package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
  176. package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
  177. package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
  178. package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
  179. package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
  180. package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
  181. package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
  182. package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
  183. package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
  184. package/vendor/nanocodex/tools/browser/index.mjs +174 -0
  185. package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
  186. package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
  187. package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
  188. package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
  189. package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
  190. package/vendor/nanocodex/tools/dataset.d.mts +1 -0
  191. package/vendor/nanocodex/tools/dataset.mjs +1 -0
  192. package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
  193. package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
  194. package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
  195. package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
  196. package/vendor/nanocodex/tools/index.d.mts +49 -0
  197. package/vendor/nanocodex/tools/index.mjs +19 -0
  198. package/vendor/nanocodex/tools/namedTool.mjs +1 -0
  199. package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
  200. package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
  201. package/vendor/nanocodex/tools/ssh.d.mts +1 -0
  202. package/vendor/nanocodex/tools/ssh.mjs +1 -0
  203. package/vendor/nanocodex/tools/standard.mjs +1 -0
  204. package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
  205. package/vendor/nanocodex/types.d.mts +663 -0
  206. package/vendor/nanocodex/wasm.d.mts +4 -0
  207. package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
  208. package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
  209. package/vendor/nanocodex/worker/index.d.mts +18 -0
  210. package/vendor/nanocodex/worker/index.mjs +5 -0
  211. package/vendor/nanocodex-tools/README.md +65 -0
  212. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
  213. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
  214. package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
  215. package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
  216. package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
  217. package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
  218. package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
  219. package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
  220. package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
  221. package/vendor/nanocodex-tools/dist/index.js +14 -0
  222. package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
  223. package/vendor/nanocodex-tools/dist/memory.js +411 -0
  224. package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
  225. package/vendor/nanocodex-tools/dist/namespace.js +338 -0
  226. package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
  227. package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
  228. package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
  229. package/vendor/nanocodex-tools/dist/runtime.js +37 -0
  230. package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
  231. package/vendor/nanocodex-tools/dist/session.js +286 -0
  232. package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
  233. package/vendor/nanocodex-tools/dist/shell.js +553 -0
  234. package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
  235. package/vendor/nanocodex-tools/dist/ssh.js +66 -0
  236. package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
  237. package/vendor/nanocodex-tools/dist/workspace.js +237 -0
  238. package/vendor/nanocodex-tools/package.json +122 -0
  239. package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
  240. package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
  241. package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
  242. package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
  243. package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
  244. package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
  245. package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
  246. package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
  247. package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
  248. package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
  249. package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
  250. package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
  251. package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
  252. package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
  253. package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
  254. package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
  255. package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
  256. package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
  257. package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
  258. package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
  259. package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
  260. package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
  261. package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
  262. package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
  263. package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
  264. package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
  265. package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
  266. package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
  267. package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
  268. package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
  269. package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
  270. package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
  271. package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
  272. package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
  273. package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
  274. package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
  275. package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
  276. package/vendor/nanocodex-tools/tools/x.mjs +91 -0
@@ -0,0 +1,2 @@
1
+ /** Returns the UTF-8 size of a JavaScript string without allocating encoded bytes. */
2
+ export function utf8ByteLength(value: string): number;
@@ -0,0 +1,25 @@
1
+ /** Returns the UTF-8 size of a JavaScript string without allocating encoded bytes. */
2
+ export function utf8ByteLength(value) {
3
+ let bytes = 0;
4
+ for (let index = 0; index < value.length; index += 1) {
5
+ const codeUnit = value.charCodeAt(index);
6
+ if (codeUnit < 0x80) {
7
+ bytes += 1;
8
+ } else if (codeUnit < 0x800) {
9
+ bytes += 2;
10
+ } else if (
11
+ codeUnit >= 0xd800
12
+ && codeUnit <= 0xdbff
13
+ && index + 1 < value.length
14
+ && value.charCodeAt(index + 1) >= 0xdc00
15
+ && value.charCodeAt(index + 1) <= 0xdfff
16
+ ) {
17
+ bytes += 4;
18
+ index += 1;
19
+ } else {
20
+ // TextEncoder replaces unpaired surrogates with U+FFFD, also three bytes.
21
+ bytes += 3;
22
+ }
23
+ }
24
+ return bytes;
25
+ }
@@ -0,0 +1,69 @@
1
+ import type { NamedTool, Workspace, WorkspaceEntry } from "./types.mjs";
2
+
3
+ export const ARTIFACT_DIRECTORY: "/workspace/.nanocodex/artifacts";
4
+
5
+ export type ArtifactDocument = Readonly<{
6
+ version: 1;
7
+ id: string;
8
+ title: string;
9
+ source: string;
10
+ createdAt: number;
11
+ updatedAt: number;
12
+ }>;
13
+
14
+ export type ArtifactInput = Readonly<{
15
+ id?: string | undefined;
16
+ title: string;
17
+ source: string;
18
+ }>;
19
+
20
+ export type ArtifactWorkspace = Readonly<{
21
+ root: string;
22
+ list(path?: string, options?: { maxEntries?: number }): Promise<readonly WorkspaceEntry[]>;
23
+ readFile(path: string): Promise<Uint8Array>;
24
+ writeFile(path: string, contents: string | ArrayBuffer | ArrayBufferView): Promise<void>;
25
+ remove(path: string): Promise<void>;
26
+ mkdir(path: string): Promise<void>;
27
+ }>;
28
+
29
+ export type ArtifactScan = Readonly<{
30
+ artifacts: readonly ArtifactDocument[];
31
+ rejected: readonly Readonly<{ path: string; error: unknown }>[];
32
+ }>;
33
+
34
+ export type ArtifactStoreOptions = Readonly<{
35
+ directory?: string | undefined;
36
+ validateSource?(source: string): void | Promise<void>;
37
+ }>;
38
+
39
+ export type ArtifactOptions = ArtifactStoreOptions & Readonly<{
40
+ workspace: Pick<Workspace, "root" | "list" | "readFile" | "writeFile" | "remove" | "mkdir">;
41
+ onArtifact?(artifact: ArtifactDocument): void;
42
+ }>;
43
+
44
+ export const artifactToolDefinition: Readonly<{
45
+ description: string;
46
+ parameters: Readonly<Record<string, unknown>>;
47
+ }>;
48
+
49
+ export class ArtifactStore {
50
+ readonly directory: string;
51
+ constructor(workspace: ArtifactWorkspace, options?: ArtifactStoreOptions);
52
+ path(id: string): string;
53
+ read(id: string): Promise<ArtifactDocument>;
54
+ scan(): Promise<ArtifactScan>;
55
+ list(): Promise<readonly ArtifactDocument[]>;
56
+ save(input: unknown): Promise<ArtifactDocument>;
57
+ remove(id: string): Promise<void>;
58
+ tool(onArtifact?: (artifact: ArtifactDocument) => void): NamedTool;
59
+ }
60
+
61
+ /** Creates the named `render_artifact` tool for direct array composition. */
62
+ export function artifact(options: ArtifactOptions): NamedTool;
63
+ export function createArtifactTool(
64
+ workspace: ArtifactWorkspace,
65
+ onArtifact?: (artifact: ArtifactDocument) => void,
66
+ options?: ArtifactStoreOptions,
67
+ ): NamedTool;
68
+ export function artifactPath(id: string, directory?: string): string;
69
+ export function parseArtifactDocument(encoded: string): ArtifactDocument;
@@ -0,0 +1,270 @@
1
+ import { namedTool } from "./namedTool.mjs";
2
+
3
+ export const ARTIFACT_DIRECTORY = "/workspace/.nanocodex/artifacts";
4
+
5
+ export const artifactToolDefinition = Object.freeze({
6
+ description: [
7
+ "Create or update the custom React interface shown to the user.",
8
+ "source must be JavaScript that defines an App component; React, html, and sendPrompt are already in scope.",
9
+ "Use React hooks, html tagged templates instead of JSX, and embedded styles to build a polished responsive interface.",
10
+ "Interactive controls may update local React state or call sendPrompt(prompt) to ask the agent to evolve the interface.",
11
+ "Imports, network access, and access to parent or top are unavailable.",
12
+ "Reuse the same id to replace the displayed interface in place.",
13
+ ].join(" "),
14
+ parameters: {
15
+ type: "object",
16
+ required: ["title", "source"],
17
+ properties: {
18
+ id: {
19
+ type: "string",
20
+ description: "Stable lowercase artifact ID. Reuse it to update an interface.",
21
+ pattern: "^[a-z0-9][a-z0-9_-]*$",
22
+ },
23
+ title: { type: "string", minLength: 1 },
24
+ source: {
25
+ type: "string",
26
+ minLength: 1,
27
+ description: "JavaScript defining App; React, html, and sendPrompt are in scope.",
28
+ },
29
+ },
30
+ additionalProperties: false,
31
+ },
32
+ });
33
+
34
+ export class ArtifactStore {
35
+ #workspace;
36
+ #validateSource;
37
+
38
+ constructor(workspace, options = {}) {
39
+ requireWorkspace(workspace);
40
+ this.#workspace = workspace;
41
+ this.#validateSource = options.validateSource;
42
+ if (this.#validateSource !== undefined && typeof this.#validateSource !== "function") {
43
+ throw new TypeError("validateSource must be a function");
44
+ }
45
+ this.directory = artifactDirectory(options.directory ?? defaultArtifactDirectory(workspace.root));
46
+ }
47
+
48
+ path(id) {
49
+ return joinAbsolutePath(this.directory, `${validateArtifactId(id)}.json`);
50
+ }
51
+
52
+ async read(id) {
53
+ return this.#readPath(this.path(id));
54
+ }
55
+
56
+ async scan() {
57
+ let entries;
58
+ try {
59
+ entries = await this.#workspace.list(this.directory);
60
+ } catch (error) {
61
+ if (isNotFound(error)) return { artifacts: [], rejected: [] };
62
+ throw error;
63
+ }
64
+ const prefix = `${this.directory === "/" ? "" : this.directory}/`;
65
+ const files = entries.filter((entry) => entry.kind === "file"
66
+ && entry.path.startsWith(prefix)
67
+ && !entry.path.slice(prefix.length).includes("/")
68
+ && entry.path.endsWith(".json"));
69
+ const results = await mapConcurrent(files, 8, async (entry) => {
70
+ try {
71
+ return { ok: true, path: entry.path, artifact: await this.#readPath(entry.path) };
72
+ } catch (error) {
73
+ return { ok: false, path: entry.path, error };
74
+ }
75
+ });
76
+ const artifacts = [];
77
+ const rejected = [];
78
+ for (const result of results) {
79
+ if (result.ok) artifacts.push(result.artifact);
80
+ else rejected.push({ path: result.path, error: result.error });
81
+ }
82
+ artifacts.sort((left, right) => right.updatedAt - left.updatedAt);
83
+ return { artifacts, rejected };
84
+ }
85
+
86
+ async list() {
87
+ return (await this.scan()).artifacts;
88
+ }
89
+
90
+ async save(input) {
91
+ const value = exactRecord(input, "artifact input", ["id", "title", "source"]);
92
+ const title = requiredString(value.title, "title").trim();
93
+ const id = value.id === undefined
94
+ ? slugArtifactId(title)
95
+ : validateArtifactId(requiredString(value.id, "id"));
96
+ const source = requiredString(value.source, "source");
97
+ await this.#validateSource?.(source);
98
+ const now = Date.now();
99
+ let previous;
100
+ try {
101
+ previous = await this.read(id);
102
+ } catch (error) {
103
+ if (!isNotFound(error) && !(error instanceof InvalidArtifactDocumentError)) throw error;
104
+ }
105
+ const document = {
106
+ version: 1,
107
+ id,
108
+ title,
109
+ source,
110
+ createdAt: previous?.createdAt ?? now,
111
+ updatedAt: now,
112
+ };
113
+ await this.#workspace.mkdir(this.directory);
114
+ await this.#workspace.writeFile(this.path(id), JSON.stringify(document));
115
+ return document;
116
+ }
117
+
118
+ async remove(id) {
119
+ await this.#workspace.remove(this.path(id));
120
+ }
121
+
122
+ tool(onArtifact = () => {}) {
123
+ if (typeof onArtifact !== "function") throw new TypeError("onArtifact must be a function");
124
+ return namedTool("render_artifact", {
125
+ ...artifactToolDefinition,
126
+ outputSchema: {
127
+ type: "object",
128
+ properties: {
129
+ artifactId: { type: "string" },
130
+ path: { type: "string" },
131
+ title: { type: "string" },
132
+ runtime: { type: "string", const: "react" },
133
+ },
134
+ required: ["artifactId", "path", "title", "runtime"],
135
+ additionalProperties: false,
136
+ },
137
+ handler: async (input) => {
138
+ const document = await this.save(input);
139
+ onArtifact(document);
140
+ return {
141
+ artifactId: document.id,
142
+ path: this.path(document.id),
143
+ title: document.title,
144
+ runtime: "react",
145
+ };
146
+ },
147
+ });
148
+ }
149
+
150
+ async #readPath(path) {
151
+ const bytes = await this.#workspace.readFile(path);
152
+ try {
153
+ const document = parseArtifactDocument(new TextDecoder().decode(bytes));
154
+ if (this.path(document.id) !== path) throw new TypeError("artifact id does not match its filename");
155
+ return document;
156
+ } catch (error) {
157
+ throw new InvalidArtifactDocumentError(path, error);
158
+ }
159
+ }
160
+ }
161
+
162
+ class InvalidArtifactDocumentError extends Error {
163
+ constructor(path, cause) {
164
+ super(`invalid artifact document at ${path}: ${errorMessage(cause)}`, { cause });
165
+ this.name = "InvalidArtifactDocumentError";
166
+ }
167
+ }
168
+
169
+ /** Viem-style factory returning a named tool ready for array composition. */
170
+ export function artifact(options) {
171
+ const value = exactRecord(options, "artifact options", [
172
+ "workspace", "onArtifact", "directory", "validateSource",
173
+ ]);
174
+ return new ArtifactStore(value.workspace, value).tool(value.onArtifact);
175
+ }
176
+
177
+ export function createArtifactTool(workspace, onArtifact, options) {
178
+ return new ArtifactStore(workspace, options).tool(onArtifact);
179
+ }
180
+
181
+ export function artifactPath(id, directory = ARTIFACT_DIRECTORY) {
182
+ return joinAbsolutePath(artifactDirectory(directory), `${validateArtifactId(id)}.json`);
183
+ }
184
+
185
+ export function parseArtifactDocument(encoded) {
186
+ const value = exactRecord(JSON.parse(encoded), "artifact document", [
187
+ "version", "id", "title", "source", "createdAt", "updatedAt",
188
+ ]);
189
+ if (value.version !== 1) throw new TypeError("unsupported artifact version");
190
+ return {
191
+ version: 1,
192
+ id: validateArtifactId(requiredString(value.id, "artifact.id")),
193
+ title: requiredString(value.title, "artifact.title").trim(),
194
+ source: requiredString(value.source, "artifact.source"),
195
+ createdAt: timestamp(value.createdAt, "artifact.createdAt"),
196
+ updatedAt: timestamp(value.updatedAt, "artifact.updatedAt"),
197
+ };
198
+ }
199
+
200
+ function requireWorkspace(workspace) {
201
+ if (!workspace || typeof workspace !== "object") throw new TypeError("artifact workspace is required");
202
+ for (const method of ["list", "readFile", "writeFile", "remove", "mkdir"]) {
203
+ if (typeof workspace[method] !== "function") throw new TypeError(`artifact workspace.${method} must be a function`);
204
+ }
205
+ if (typeof workspace.root !== "string") throw new TypeError("artifact workspace.root must be a string");
206
+ }
207
+
208
+ function exactRecord(value, name, keys) {
209
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${name} must be an object`);
210
+ const extras = Object.keys(value).filter((key) => !keys.includes(key));
211
+ if (extras.length) throw new TypeError(`${name} has unsupported properties: ${extras.join(", ")}`);
212
+ return value;
213
+ }
214
+
215
+ function artifactDirectory(value) {
216
+ if (!/^\/(?:[a-zA-Z0-9._/-]+)?$/.test(value) || value.includes("//") || value.split("/").includes("..")) {
217
+ throw new TypeError("artifact directory must be a normalized absolute workspace path");
218
+ }
219
+ return value === "/" ? value : value.replace(/\/$/, "");
220
+ }
221
+
222
+ function defaultArtifactDirectory(root) {
223
+ return joinAbsolutePath(artifactDirectory(root), ".nanocodex/artifacts");
224
+ }
225
+
226
+ function joinAbsolutePath(directory, name) {
227
+ return `${directory === "/" ? "" : directory}/${name}`;
228
+ }
229
+
230
+ function validateArtifactId(value) {
231
+ if (!/^[a-z0-9][a-z0-9_-]*$/.test(value)) throw new TypeError("artifact id is invalid");
232
+ return value;
233
+ }
234
+
235
+ function slugArtifactId(value) {
236
+ const id = value.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
237
+ return validateArtifactId(id);
238
+ }
239
+
240
+ function requiredString(value, name) {
241
+ if (typeof value !== "string" || !value.trim()) throw new TypeError(`${name} must be a string`);
242
+ return value;
243
+ }
244
+
245
+ function timestamp(value, name) {
246
+ if (!Number.isSafeInteger(value) || value < 0) throw new TypeError(`${name} must be a timestamp`);
247
+ return value;
248
+ }
249
+
250
+ function errorMessage(error) {
251
+ return error instanceof Error ? error.message : String(error);
252
+ }
253
+
254
+ function isNotFound(error) {
255
+ return (typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "NotFoundError")
256
+ || Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT")
257
+ || (error instanceof Error && error.message === "not found");
258
+ }
259
+
260
+ async function mapConcurrent(input, concurrency, map) {
261
+ const output = new Array(input.length);
262
+ let next = 0;
263
+ await Promise.all(Array.from({ length: Math.min(concurrency, input.length) }, async () => {
264
+ while (next < input.length) {
265
+ const index = next++;
266
+ output[index] = await map(input[index]);
267
+ }
268
+ }));
269
+ return output;
270
+ }