@oharness/engine 0.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 (256) hide show
  1. package/dist/agent/agent.d.ts +196 -0
  2. package/dist/agent/agent.js +758 -0
  3. package/dist/agent/agent.js.map +1 -0
  4. package/dist/agent/compaction.d.ts +68 -0
  5. package/dist/agent/compaction.js +179 -0
  6. package/dist/agent/compaction.js.map +1 -0
  7. package/dist/agent/hooks.d.ts +77 -0
  8. package/dist/agent/hooks.js +152 -0
  9. package/dist/agent/hooks.js.map +1 -0
  10. package/dist/agent/memory.d.ts +45 -0
  11. package/dist/agent/memory.js +147 -0
  12. package/dist/agent/memory.js.map +1 -0
  13. package/dist/agent/overflow.d.ts +35 -0
  14. package/dist/agent/overflow.js +69 -0
  15. package/dist/agent/overflow.js.map +1 -0
  16. package/dist/agent/permissions.d.ts +181 -0
  17. package/dist/agent/permissions.js +289 -0
  18. package/dist/agent/permissions.js.map +1 -0
  19. package/dist/agent/prompt.d.ts +25 -0
  20. package/dist/agent/prompt.js +63 -0
  21. package/dist/agent/prompt.js.map +1 -0
  22. package/dist/agent/session.d.ts +108 -0
  23. package/dist/agent/session.js +231 -0
  24. package/dist/agent/session.js.map +1 -0
  25. package/dist/agent/settings.d.ts +37 -0
  26. package/dist/agent/settings.js +113 -0
  27. package/dist/agent/settings.js.map +1 -0
  28. package/dist/agent/skills.d.ts +58 -0
  29. package/dist/agent/skills.js +225 -0
  30. package/dist/agent/skills.js.map +1 -0
  31. package/dist/agent/store.d.ts +308 -0
  32. package/dist/agent/store.js +596 -0
  33. package/dist/agent/store.js.map +1 -0
  34. package/dist/agent/subagent.d.ts +44 -0
  35. package/dist/agent/subagent.js +138 -0
  36. package/dist/agent/subagent.js.map +1 -0
  37. package/dist/agent/titles.d.ts +8 -0
  38. package/dist/agent/titles.js +23 -0
  39. package/dist/agent/titles.js.map +1 -0
  40. package/dist/agent/workspace.d.ts +60 -0
  41. package/dist/agent/workspace.js +156 -0
  42. package/dist/agent/workspace.js.map +1 -0
  43. package/dist/artifacts/publish.d.ts +94 -0
  44. package/dist/artifacts/publish.js +104 -0
  45. package/dist/artifacts/publish.js.map +1 -0
  46. package/dist/artifacts/store.d.ts +324 -0
  47. package/dist/artifacts/store.js +500 -0
  48. package/dist/artifacts/store.js.map +1 -0
  49. package/dist/auth/index.d.ts +13 -0
  50. package/dist/auth/index.js +10 -0
  51. package/dist/auth/index.js.map +1 -0
  52. package/dist/auth/manager.d.ts +83 -0
  53. package/dist/auth/manager.js +266 -0
  54. package/dist/auth/manager.js.map +1 -0
  55. package/dist/auth/oauth.d.ts +83 -0
  56. package/dist/auth/oauth.js +327 -0
  57. package/dist/auth/oauth.js.map +1 -0
  58. package/dist/auth/providers/account.d.ts +59 -0
  59. package/dist/auth/providers/account.js +282 -0
  60. package/dist/auth/providers/account.js.map +1 -0
  61. package/dist/auth/providers/anthropic.d.ts +24 -0
  62. package/dist/auth/providers/anthropic.js +209 -0
  63. package/dist/auth/providers/anthropic.js.map +1 -0
  64. package/dist/auth/providers/generic.d.ts +57 -0
  65. package/dist/auth/providers/generic.js +155 -0
  66. package/dist/auth/providers/generic.js.map +1 -0
  67. package/dist/auth/providers/official.d.ts +3 -0
  68. package/dist/auth/providers/official.js +90 -0
  69. package/dist/auth/providers/official.js.map +1 -0
  70. package/dist/auth/providers/ottoport.d.ts +3 -0
  71. package/dist/auth/providers/ottoport.js +60 -0
  72. package/dist/auth/providers/ottoport.js.map +1 -0
  73. package/dist/auth/store.d.ts +22 -0
  74. package/dist/auth/store.js +138 -0
  75. package/dist/auth/store.js.map +1 -0
  76. package/dist/auth/types.d.ts +167 -0
  77. package/dist/auth/types.js +16 -0
  78. package/dist/auth/types.js.map +1 -0
  79. package/dist/config.d.ts +197 -0
  80. package/dist/config.js +195 -0
  81. package/dist/config.js.map +1 -0
  82. package/dist/core/errors.d.ts +46 -0
  83. package/dist/core/errors.js +83 -0
  84. package/dist/core/errors.js.map +1 -0
  85. package/dist/core/tokens.d.ts +12 -0
  86. package/dist/core/tokens.js +56 -0
  87. package/dist/core/tokens.js.map +1 -0
  88. package/dist/core/types.d.ts +91 -0
  89. package/dist/core/types.js +49 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/harness.d.ts +302 -0
  92. package/dist/harness.js +695 -0
  93. package/dist/harness.js.map +1 -0
  94. package/dist/index.d.ts +32 -0
  95. package/dist/index.js +21 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/mcp/client.d.ts +55 -0
  98. package/dist/mcp/client.js +199 -0
  99. package/dist/mcp/client.js.map +1 -0
  100. package/dist/mcp/index.d.ts +13 -0
  101. package/dist/mcp/index.js +8 -0
  102. package/dist/mcp/index.js.map +1 -0
  103. package/dist/mcp/manager.d.ts +77 -0
  104. package/dist/mcp/manager.js +325 -0
  105. package/dist/mcp/manager.js.map +1 -0
  106. package/dist/mcp/oauth.d.ts +63 -0
  107. package/dist/mcp/oauth.js +302 -0
  108. package/dist/mcp/oauth.js.map +1 -0
  109. package/dist/mcp/protocol.d.ts +130 -0
  110. package/dist/mcp/protocol.js +14 -0
  111. package/dist/mcp/protocol.js.map +1 -0
  112. package/dist/mcp/registry.d.ts +52 -0
  113. package/dist/mcp/registry.js +100 -0
  114. package/dist/mcp/registry.js.map +1 -0
  115. package/dist/mcp/registry.json +293 -0
  116. package/dist/mcp/secrets.d.ts +20 -0
  117. package/dist/mcp/secrets.js +75 -0
  118. package/dist/mcp/secrets.js.map +1 -0
  119. package/dist/mcp/transport.d.ts +51 -0
  120. package/dist/mcp/transport.js +158 -0
  121. package/dist/mcp/transport.js.map +1 -0
  122. package/dist/paths.d.ts +37 -0
  123. package/dist/paths.js +63 -0
  124. package/dist/paths.js.map +1 -0
  125. package/dist/plugins.d.ts +55 -0
  126. package/dist/plugins.js +201 -0
  127. package/dist/plugins.js.map +1 -0
  128. package/dist/providers/builtin.d.ts +23 -0
  129. package/dist/providers/builtin.js +141 -0
  130. package/dist/providers/builtin.js.map +1 -0
  131. package/dist/providers/catalog.d.ts +129 -0
  132. package/dist/providers/catalog.js +254 -0
  133. package/dist/providers/catalog.js.map +1 -0
  134. package/dist/providers/catalog.json +472 -0
  135. package/dist/providers/discovery.d.ts +16 -0
  136. package/dist/providers/discovery.js +161 -0
  137. package/dist/providers/discovery.js.map +1 -0
  138. package/dist/providers/http.d.ts +24 -0
  139. package/dist/providers/http.js +139 -0
  140. package/dist/providers/http.js.map +1 -0
  141. package/dist/providers/index.d.ts +10 -0
  142. package/dist/providers/index.js +8 -0
  143. package/dist/providers/index.js.map +1 -0
  144. package/dist/providers/piai.d.ts +124 -0
  145. package/dist/providers/piai.js +551 -0
  146. package/dist/providers/piai.js.map +1 -0
  147. package/dist/providers/registry.d.ts +65 -0
  148. package/dist/providers/registry.js +195 -0
  149. package/dist/providers/registry.js.map +1 -0
  150. package/dist/providers/resilient.d.ts +46 -0
  151. package/dist/providers/resilient.js +117 -0
  152. package/dist/providers/resilient.js.map +1 -0
  153. package/dist/providers/types.d.ts +182 -0
  154. package/dist/providers/types.js +50 -0
  155. package/dist/providers/types.js.map +1 -0
  156. package/dist/schedule/cron.d.ts +35 -0
  157. package/dist/schedule/cron.js +125 -0
  158. package/dist/schedule/cron.js.map +1 -0
  159. package/dist/schedule/scheduler.d.ts +87 -0
  160. package/dist/schedule/scheduler.js +237 -0
  161. package/dist/schedule/scheduler.js.map +1 -0
  162. package/dist/storage/kv.d.ts +56 -0
  163. package/dist/storage/kv.js +173 -0
  164. package/dist/storage/kv.js.map +1 -0
  165. package/dist/storage/migrate.d.ts +11 -0
  166. package/dist/storage/migrate.js +93 -0
  167. package/dist/storage/migrate.js.map +1 -0
  168. package/dist/storage/project.d.ts +9 -0
  169. package/dist/storage/project.js +57 -0
  170. package/dist/storage/project.js.map +1 -0
  171. package/dist/storage/records.d.ts +32 -0
  172. package/dist/storage/records.js +48 -0
  173. package/dist/storage/records.js.map +1 -0
  174. package/dist/sync/client.d.ts +79 -0
  175. package/dist/sync/client.js +118 -0
  176. package/dist/sync/client.js.map +1 -0
  177. package/dist/sync/mirror.d.ts +85 -0
  178. package/dist/sync/mirror.js +389 -0
  179. package/dist/sync/mirror.js.map +1 -0
  180. package/dist/sync/protocol.d.ts +67 -0
  181. package/dist/sync/protocol.js +16 -0
  182. package/dist/sync/protocol.js.map +1 -0
  183. package/dist/sync/settings.d.ts +56 -0
  184. package/dist/sync/settings.js +60 -0
  185. package/dist/sync/settings.js.map +1 -0
  186. package/dist/tools/builtin/artifact.d.ts +16 -0
  187. package/dist/tools/builtin/artifact.js +134 -0
  188. package/dist/tools/builtin/artifact.js.map +1 -0
  189. package/dist/tools/builtin/bash.d.ts +3 -0
  190. package/dist/tools/builtin/bash.js +142 -0
  191. package/dist/tools/builtin/bash.js.map +1 -0
  192. package/dist/tools/builtin/fs.d.ts +19 -0
  193. package/dist/tools/builtin/fs.js +280 -0
  194. package/dist/tools/builtin/fs.js.map +1 -0
  195. package/dist/tools/builtin/index.d.ts +22 -0
  196. package/dist/tools/builtin/index.js +42 -0
  197. package/dist/tools/builtin/index.js.map +1 -0
  198. package/dist/tools/builtin/mcp-resource.d.ts +3 -0
  199. package/dist/tools/builtin/mcp-resource.js +220 -0
  200. package/dist/tools/builtin/mcp-resource.js.map +1 -0
  201. package/dist/tools/builtin/memory.d.ts +10 -0
  202. package/dist/tools/builtin/memory.js +76 -0
  203. package/dist/tools/builtin/memory.js.map +1 -0
  204. package/dist/tools/builtin/recall.d.ts +13 -0
  205. package/dist/tools/builtin/recall.js +163 -0
  206. package/dist/tools/builtin/recall.js.map +1 -0
  207. package/dist/tools/builtin/search.d.ts +3 -0
  208. package/dist/tools/builtin/search.js +240 -0
  209. package/dist/tools/builtin/search.js.map +1 -0
  210. package/dist/tools/builtin/skill.d.ts +10 -0
  211. package/dist/tools/builtin/skill.js +46 -0
  212. package/dist/tools/builtin/skill.js.map +1 -0
  213. package/dist/tools/builtin/task.d.ts +9 -0
  214. package/dist/tools/builtin/task.js +68 -0
  215. package/dist/tools/builtin/task.js.map +1 -0
  216. package/dist/tools/builtin/todo.d.ts +20 -0
  217. package/dist/tools/builtin/todo.js +63 -0
  218. package/dist/tools/builtin/todo.js.map +1 -0
  219. package/dist/tools/define.d.ts +19 -0
  220. package/dist/tools/define.js +39 -0
  221. package/dist/tools/define.js.map +1 -0
  222. package/dist/tools/index.d.ts +7 -0
  223. package/dist/tools/index.js +5 -0
  224. package/dist/tools/index.js.map +1 -0
  225. package/dist/tools/registry.d.ts +39 -0
  226. package/dist/tools/registry.js +101 -0
  227. package/dist/tools/registry.js.map +1 -0
  228. package/dist/tools/types.d.ts +112 -0
  229. package/dist/tools/types.js +22 -0
  230. package/dist/tools/types.js.map +1 -0
  231. package/dist/util/id.d.ts +9 -0
  232. package/dist/util/id.js +19 -0
  233. package/dist/util/id.js.map +1 -0
  234. package/dist/util/json.d.ts +25 -0
  235. package/dist/util/json.js +100 -0
  236. package/dist/util/json.js.map +1 -0
  237. package/dist/util/jwt.d.ts +74 -0
  238. package/dist/util/jwt.js +177 -0
  239. package/dist/util/jwt.js.map +1 -0
  240. package/dist/util/logger.d.ts +13 -0
  241. package/dist/util/logger.js +59 -0
  242. package/dist/util/logger.js.map +1 -0
  243. package/dist/util/queue.d.ts +26 -0
  244. package/dist/util/queue.js +106 -0
  245. package/dist/util/queue.js.map +1 -0
  246. package/dist/util/schema.d.ts +17 -0
  247. package/dist/util/schema.js +98 -0
  248. package/dist/util/schema.js.map +1 -0
  249. package/dist/util/shell.d.ts +20 -0
  250. package/dist/util/shell.js +24 -0
  251. package/dist/util/shell.js.map +1 -0
  252. package/official.json +4 -0
  253. package/package.json +38 -0
  254. package/skills/artifact-authoring/SKILL.md +81 -0
  255. package/skills/canvas/SKILL.md +85 -0
  256. package/skills/skill-authoring/SKILL.md +85 -0
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Artifacts: the things a turn produces, as opposed to the things it says.
3
+ *
4
+ * A file written to the working tree is already a deliverable and the review
5
+ * pane already shows it as a diff. This is for the other case — a chart, a
6
+ * rendered page, a document the model is iterating on — where the deliverable
7
+ * has no natural home on disk and where the interesting question is "what does
8
+ * it look like now", not "what changed since last time".
9
+ *
10
+ * The two properties that make this more than `write` to a temp file:
11
+ *
12
+ * - Identity. An artifact has an id chosen by the model, so a second call
13
+ * with the same id is a revision rather than a new object. That is the
14
+ * whole mechanism: without it every edit would litter the panel with a
15
+ * near-duplicate and the frontend would have no way to know which one is
16
+ * current.
17
+ * - Versions. Every revision is kept, so a frontend can offer "back to the
18
+ * one before you broke it" without the model having to re-derive it.
19
+ *
20
+ * Content lives here and never travels in the event stream. Artifacts are
21
+ * routinely tens of kilobytes and are rewritten in full on every revision;
22
+ * putting that in an event would push it through the SSE relay and into every
23
+ * frontend's memory on every keystroke of a rewrite. Frontends get a
24
+ * descriptor and fetch the body if and when they are going to show it.
25
+ */
26
+ /**
27
+ * How much a frontend has to be able to do to show an artifact honestly.
28
+ *
29
+ * This list is the contract between the engine and every frontend, and it is
30
+ * deliberately short. It is not "which mime types exist" — it is "how many
31
+ * fundamentally different rendering capabilities do we ask a frontend for",
32
+ * and every entry costs each frontend an implementation or an honest refusal.
33
+ * Adding one is a decision, which is why the list is closed and why
34
+ * test/artifacts.test.ts fails when a frontend has no declared answer for a
35
+ * member of it.
36
+ *
37
+ * text Plain prose or data. Any frontend can show this.
38
+ * markdown Structured prose. A frontend without a renderer shows the source,
39
+ * which is still readable — that is why it is separate from `code`.
40
+ * code Source, with a language hint. Degrades to text.
41
+ * image Raster bytes. A terminal generally cannot; see the TUI's answer.
42
+ * vector SVG. Renderable as a document, but also readable as source.
43
+ * page Self-contained HTML that must execute to mean anything. This is
44
+ * the only kind that requires a sandbox, and the only one with no
45
+ * honest textual degradation.
46
+ */
47
+ export const ARTIFACT_KINDS = ["text", "markdown", "code", "image", "vector", "page"];
48
+ /**
49
+ * The mime that means "this is a canvas".
50
+ *
51
+ * Deliberately a mime and not a seventh entry in ARTIFACT_KINDS. That list is
52
+ * the set of *rendering capabilities* we ask every frontend for, and a canvas
53
+ * asks for nothing new: it is HTML that has to execute, which is exactly what
54
+ * `page` already means. What differs is who wrote the surrounding document —
55
+ * for a `page` the model did, for a canvas the harness does, wrapping the
56
+ * model's artboards in an editor. A frontend that knows nothing about canvases
57
+ * still shows one correctly, because what it receives from /artifact/view is a
58
+ * complete page. Adding a kind would instead have forced every frontend, the
59
+ * website and a database enum to declare an answer to a question none of them
60
+ * actually needed to be asked.
61
+ */
62
+ export const CANVAS_MIME = "text/canvas+html";
63
+ /** Whether a mime names a canvas, tolerant of charset parameters and case. */
64
+ export function isCanvas(mime) {
65
+ return mime.split(";")[0].trim().toLowerCase() === CANVAS_MIME;
66
+ }
67
+ /** Mime types the model may name, and the capability each one implies. */
68
+ const KIND_BY_MIME = {
69
+ "text/plain": "text",
70
+ "text/markdown": "markdown",
71
+ "text/html": "page",
72
+ // A canvas is served as a document that must execute, so it lands on the
73
+ // same capability as any other page. See CANVAS_MIME.
74
+ [CANVAS_MIME]: "page",
75
+ "image/svg+xml": "vector",
76
+ "image/png": "image",
77
+ "image/jpeg": "image",
78
+ "application/json": "code",
79
+ };
80
+ /**
81
+ * The capability a mime type implies, falling back by family.
82
+ *
83
+ * Unknown types resolve to `text` rather than throwing: a model that invents
84
+ * `text/x-rst` should get a usable artifact showing its source, not a tool
85
+ * error that costs a turn. The fallback is deliberately the least capable
86
+ * kind — guessing upward would mean handing an unvetted string to a renderer.
87
+ */
88
+ export function kindForMime(mime) {
89
+ const base = mime.split(";")[0].trim().toLowerCase();
90
+ const known = KIND_BY_MIME[base];
91
+ if (known)
92
+ return known;
93
+ if (base.startsWith("image/"))
94
+ return "image";
95
+ if (base.startsWith("text/"))
96
+ return "text";
97
+ return "text";
98
+ }
99
+ /** True for kinds whose body is only meaningful when executed by a browser. */
100
+ export function needsSandbox(kind) {
101
+ return kind === "page";
102
+ }
103
+ /** Reject a log line this build cannot make sense of, rather than half-read it. */
104
+ export function asArtifactRevision(value) {
105
+ if (!value || typeof value !== "object")
106
+ return undefined;
107
+ const c = value;
108
+ if (typeof c.artifact !== "string" || typeof c.content !== "string")
109
+ return undefined;
110
+ if (typeof c.title !== "string" || typeof c.mime !== "string")
111
+ return undefined;
112
+ if (typeof c.version !== "number")
113
+ return undefined;
114
+ return {
115
+ ...(typeof c.id === "string" ? { id: c.id } : {}),
116
+ ...(typeof c.seq === "number" ? { seq: c.seq } : {}),
117
+ ...(typeof c.device === "string" ? { device: c.device } : {}),
118
+ artifact: c.artifact,
119
+ title: c.title,
120
+ mime: c.mime,
121
+ ...(typeof c.language === "string" ? { language: c.language } : {}),
122
+ version: c.version,
123
+ content: c.content,
124
+ at: typeof c.at === "number" ? c.at : 0,
125
+ ...(c.author === "user" ? { author: "user" } : {}),
126
+ };
127
+ }
128
+ /** Ids are addressable in a URL path, so the character set is restricted. */
129
+ const ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;
130
+ export function isValidArtifactId(id) {
131
+ // Rejected rather than sanitised. A sanitising rule would let two different
132
+ // ids collapse onto one artifact, and the model would have no way to see it
133
+ // happen — it would just find its previous revision silently overwritten.
134
+ return ID_PATTERN.test(id) && !id.includes("..");
135
+ }
136
+ /**
137
+ * How many revisions of one artifact are kept.
138
+ *
139
+ * Bounded because the store is memory and a model iterating on a page can
140
+ * produce dozens of revisions in a turn. The newest is never dropped; the
141
+ * oldest go first.
142
+ */
143
+ const MAX_VERSIONS = 20;
144
+ /** Refused rather than truncated: half a document renders as a broken one. */
145
+ export const MAX_ARTIFACT_BYTES = 2 * 1024 * 1024;
146
+ export class ArtifactStore {
147
+ items = new Map();
148
+ /**
149
+ * Told about every revision this store accepts.
150
+ *
151
+ * A callback rather than a store reference, so this file keeps knowing
152
+ * nothing about disks, projects or sync — it holds artifacts, and whoever
153
+ * owns it decides what durability means. It is also what keeps the two
154
+ * writers symmetrical: a model's `put` and a person's `edit` are the same
155
+ * kind of event to anything downstream, which is the property that was
156
+ * missing when only one of them left a trace.
157
+ */
158
+ onRevision;
159
+ announce(artifact, revision) {
160
+ if (!this.onRevision)
161
+ return;
162
+ this.onRevision({
163
+ artifact: artifact.id,
164
+ title: artifact.title,
165
+ mime: artifact.mime,
166
+ ...(artifact.language ? { language: artifact.language } : {}),
167
+ version: revision.version,
168
+ content: revision.content,
169
+ at: revision.createdAt,
170
+ ...(revision.author ? { author: revision.author } : {}),
171
+ });
172
+ }
173
+ /**
174
+ * Record a revision, creating the artifact if this id is new.
175
+ *
176
+ * Returns the descriptor rather than the artifact so callers cannot hold a
177
+ * reference into the store and mutate a stored version in place.
178
+ */
179
+ put(input) {
180
+ if (!isValidArtifactId(input.id)) {
181
+ throw new Error(`Invalid artifact id ${JSON.stringify(input.id)}: use letters, digits, dot, dash or underscore (max 64).`);
182
+ }
183
+ const bytes = Buffer.byteLength(input.content, "utf8");
184
+ if (bytes > MAX_ARTIFACT_BYTES) {
185
+ throw new Error(`Artifact is ${bytes} bytes, over the ${MAX_ARTIFACT_BYTES} byte limit.`);
186
+ }
187
+ const existing = this.items.get(input.id);
188
+ const version = existing ? existing.versions[existing.versions.length - 1].version + 1 : 1;
189
+ const revision = {
190
+ version,
191
+ content: input.content,
192
+ createdAt: Date.now(),
193
+ bytes,
194
+ };
195
+ const artifact = existing ?? {
196
+ id: input.id,
197
+ title: input.title,
198
+ mime: input.mime,
199
+ kind: kindForMime(input.mime),
200
+ versions: [],
201
+ };
202
+ // Title and mime follow the latest revision: renaming an artifact or
203
+ // switching it from markdown to HTML is a legitimate edit, and forcing a
204
+ // new id for it would break the identity that makes revisions work.
205
+ artifact.title = input.title;
206
+ artifact.mime = input.mime;
207
+ artifact.kind = kindForMime(input.mime);
208
+ if (input.language !== undefined)
209
+ artifact.language = input.language;
210
+ artifact.versions.push(revision);
211
+ if (artifact.versions.length > MAX_VERSIONS) {
212
+ artifact.versions.splice(0, artifact.versions.length - MAX_VERSIONS);
213
+ }
214
+ this.items.set(artifact.id, artifact);
215
+ this.announce(artifact, revision);
216
+ return describe(artifact, revision);
217
+ }
218
+ /**
219
+ * Record a revision a *person* wrote, in a frontend, to an artifact that
220
+ * already exists.
221
+ *
222
+ * Separate from `put` rather than a flag on it, because the two have
223
+ * different preconditions and different failure modes. `put` may create, and
224
+ * takes a title and a mime because the model is declaring what the thing is.
225
+ * An edit may only revise: there is no such thing as a person creating an
226
+ * artifact out of nothing here, and letting an edit invent one would give a
227
+ * frontend a way to conjure artifacts the transcript has no record of. It
228
+ * also leaves title and mime alone — the canvas editor changes content, and
229
+ * silently relabelling the artifact because a save round-tripped a field is
230
+ * not something anybody asked for.
231
+ *
232
+ * Returns undefined for an unknown id so the caller can answer 404 rather
233
+ * than distinguishing exception types; the size ceiling still throws,
234
+ * because that one is a rejected write and not a missing thing.
235
+ */
236
+ edit(id, content) {
237
+ const artifact = this.items.get(id);
238
+ if (!artifact)
239
+ return undefined;
240
+ const bytes = Buffer.byteLength(content, "utf8");
241
+ if (bytes > MAX_ARTIFACT_BYTES) {
242
+ throw new Error(`Artifact is ${bytes} bytes, over the ${MAX_ARTIFACT_BYTES} byte limit.`);
243
+ }
244
+ const revision = {
245
+ version: artifact.versions[artifact.versions.length - 1].version + 1,
246
+ content,
247
+ createdAt: Date.now(),
248
+ bytes,
249
+ author: "user",
250
+ };
251
+ artifact.versions.push(revision);
252
+ if (artifact.versions.length > MAX_VERSIONS) {
253
+ artifact.versions.splice(0, artifact.versions.length - MAX_VERSIONS);
254
+ }
255
+ this.announce(artifact, revision);
256
+ return describe(artifact, revision);
257
+ }
258
+ /**
259
+ * Put back a revision that was read from disk or arrived over sync.
260
+ *
261
+ * Separate from `put` and `edit` because it is not a new event: the version
262
+ * number and the author were decided when it first happened, and inventing
263
+ * fresh ones here would renumber a history that other things already refer
264
+ * to. It also stays silent — announcing would write the log back to the log.
265
+ */
266
+ restore(revision) {
267
+ if (!isValidArtifactId(revision.artifact))
268
+ return;
269
+ const existing = this.items.get(revision.artifact);
270
+ const artifact = existing ?? {
271
+ id: revision.artifact,
272
+ title: revision.title,
273
+ mime: revision.mime,
274
+ kind: kindForMime(revision.mime),
275
+ versions: [],
276
+ };
277
+ // The newest line wins on the fields that describe the thing, exactly as
278
+ // the live path lets a revision rename or retype an artifact.
279
+ artifact.title = revision.title;
280
+ artifact.mime = revision.mime;
281
+ artifact.kind = kindForMime(revision.mime);
282
+ if (revision.language !== undefined)
283
+ artifact.language = revision.language;
284
+ // A log can be replayed twice — a resume after a sync pull, say — so a
285
+ // version already held is not appended again.
286
+ if (artifact.versions.some((v) => v.version === revision.version)) {
287
+ this.items.set(artifact.id, artifact);
288
+ return;
289
+ }
290
+ artifact.versions.push({
291
+ version: revision.version,
292
+ content: revision.content,
293
+ createdAt: revision.at,
294
+ bytes: Buffer.byteLength(revision.content, "utf8"),
295
+ ...(revision.author ? { author: revision.author } : {}),
296
+ });
297
+ artifact.versions.sort((a, b) => a.version - b.version);
298
+ if (artifact.versions.length > MAX_VERSIONS) {
299
+ artifact.versions.splice(0, artifact.versions.length - MAX_VERSIONS);
300
+ }
301
+ this.items.set(artifact.id, artifact);
302
+ }
303
+ /** The latest revision, or a specific one. Undefined if either is unknown. */
304
+ get(id, version) {
305
+ const artifact = this.items.get(id);
306
+ if (!artifact)
307
+ return undefined;
308
+ const revision = version === undefined
309
+ ? artifact.versions[artifact.versions.length - 1]
310
+ : artifact.versions.find((v) => v.version === version);
311
+ return revision ? { artifact, revision } : undefined;
312
+ }
313
+ /** Every artifact at its latest revision, oldest first. */
314
+ list() {
315
+ return [...this.items.values()].map((artifact) => describe(artifact, artifact.versions[artifact.versions.length - 1]));
316
+ }
317
+ /**
318
+ * Every revision this store holds, oldest first, in the shape it is written
319
+ * down in.
320
+ *
321
+ * Exists for the one-time seeding of a session whose artifacts were rebuilt
322
+ * by replaying its transcript: without it that session's log would start at
323
+ * whatever happened next, and the versions that came before would vanish the
324
+ * moment the log took precedence over the replay.
325
+ */
326
+ export() {
327
+ const out = [];
328
+ for (const artifact of this.items.values()) {
329
+ for (const revision of artifact.versions) {
330
+ out.push({
331
+ artifact: artifact.id,
332
+ title: artifact.title,
333
+ mime: artifact.mime,
334
+ ...(artifact.language ? { language: artifact.language } : {}),
335
+ version: revision.version,
336
+ content: revision.content,
337
+ at: revision.createdAt,
338
+ ...(revision.author ? { author: revision.author } : {}),
339
+ });
340
+ }
341
+ }
342
+ return out.sort((a, b) => a.at - b.at || a.version - b.version);
343
+ }
344
+ /** Record that this artifact now has a URL on the site. */
345
+ markPublished(id, publication) {
346
+ const artifact = this.items.get(id);
347
+ if (!artifact)
348
+ return undefined;
349
+ artifact.publication = publication;
350
+ return describe(artifact, artifact.versions[artifact.versions.length - 1]);
351
+ }
352
+ /** Forget a publication after it has been withdrawn from the site. */
353
+ clearPublication(id) {
354
+ const artifact = this.items.get(id);
355
+ if (!artifact)
356
+ return undefined;
357
+ delete artifact.publication;
358
+ return describe(artifact, artifact.versions[artifact.versions.length - 1]);
359
+ }
360
+ delete(id) {
361
+ return this.items.delete(id);
362
+ }
363
+ get size() {
364
+ return this.items.size;
365
+ }
366
+ }
367
+ function describe(artifact, revision) {
368
+ return {
369
+ id: artifact.id,
370
+ title: artifact.title,
371
+ mime: artifact.mime,
372
+ kind: artifact.kind,
373
+ ...(artifact.language ? { language: artifact.language } : {}),
374
+ version: revision.version,
375
+ bytes: revision.bytes,
376
+ ...(revision.author ? { author: revision.author } : {}),
377
+ versionCount: artifact.versions.length,
378
+ ...(artifact.publication ? { publication: artifact.publication } : {}),
379
+ };
380
+ }
381
+ /**
382
+ * Where the store hangs off the session.
383
+ *
384
+ * In `session.state` rather than a field on Session, for the same reason the
385
+ * todo list is: that map is already the session-scoped scratch space tools
386
+ * reach through `ctx.host.state`, and it is already copied into and out of
387
+ * subagents. A field would need both of those paths taught about it.
388
+ *
389
+ * Consequence worth stating plainly: this is memory, so artifacts live as long
390
+ * as the process. That matches the todo list and is the right default for a
391
+ * scratch surface — but it means a frontend must not treat an artifact as a
392
+ * durable deliverable. Anything that needs to outlive the session gets written
393
+ * to the working tree with `write`.
394
+ */
395
+ export const ARTIFACTS_KEY = "artifacts:store";
396
+ /**
397
+ * Rebuild a session's artifacts from its transcript.
398
+ *
399
+ * The store is memory, so resuming a conversation used to bring back every
400
+ * message and none of the things those messages made: the panel was empty, the
401
+ * cards were gone, and an artifact the user had been looking at ten minutes
402
+ * earlier had no way back. The content was never actually lost — an artifact's
403
+ * body is the argument of the `artifact_write` call that made it, and that is
404
+ * in the transcript like any other tool call. This replays those calls.
405
+ *
406
+ * Replaying in order is what restores the version history for free: the second
407
+ * call for an id becomes v2 exactly as it did the first time round.
408
+ *
409
+ * Calls whose result came back an error are skipped — they never made an
410
+ * artifact, and re-running them here would invent one that never existed.
411
+ *
412
+ * What this cannot bring back is a revision written by a person — a canvas
413
+ * edit is not a tool call and so leaves no trace in the transcript. A resumed
414
+ * session therefore shows the model's last version as the latest, and the
415
+ * edits made on top of it are gone. Stated here rather than fixed, because
416
+ * fixing it means deciding where a human-authored revision is durably stored,
417
+ * and every cheap answer (a synthetic tool call, a user message carrying the
418
+ * body) either lies about who acted or pays the artifact's full size in
419
+ * transcript tokens on every save.
420
+ */
421
+ export function rehydrateArtifacts(store, messages) {
422
+ // Which calls failed. Collected first because the result arrives in a later
423
+ // message than the call it answers.
424
+ const failed = new Set();
425
+ for (const message of messages) {
426
+ if (!Array.isArray(message.content))
427
+ continue;
428
+ for (const block of message.content) {
429
+ if (block.type === "tool_result" && block.isError)
430
+ failed.add(block.toolCallId);
431
+ }
432
+ }
433
+ let restored = 0;
434
+ for (const message of messages) {
435
+ if (!Array.isArray(message.content))
436
+ continue;
437
+ for (const block of message.content) {
438
+ if (block.type !== "tool_call" || block.name !== ARTIFACT_TOOL)
439
+ continue;
440
+ if (failed.has(block.id))
441
+ continue;
442
+ const input = block.input;
443
+ if (!input || typeof input !== "object")
444
+ continue;
445
+ const { id, title, mime, content, language } = input;
446
+ if (typeof id !== "string" || typeof title !== "string")
447
+ continue;
448
+ if (typeof mime !== "string" || typeof content !== "string")
449
+ continue;
450
+ try {
451
+ store.put({
452
+ id,
453
+ title,
454
+ mime,
455
+ content,
456
+ ...(typeof language === "string" ? { language } : {}),
457
+ });
458
+ restored++;
459
+ }
460
+ catch {
461
+ // A transcript can hold a call the store would refuse today — an id
462
+ // whose rules have since tightened, a body over a limit that has since
463
+ // come down. Skipping one is right; refusing to restore the rest
464
+ // because of it is not.
465
+ }
466
+ }
467
+ }
468
+ return restored;
469
+ }
470
+ /**
471
+ * Rebuild a session's artifacts from what was written down, in order.
472
+ *
473
+ * Preferred over `rehydrateArtifacts` wherever a log exists, and the two must
474
+ * not both run: replay derives version numbers by counting writes, the log
475
+ * carries the numbers that actually happened, and applying one on top of the
476
+ * other would renumber the history and duplicate every revision.
477
+ *
478
+ * The transcript replay stays as the fallback, and has to: every session
479
+ * recorded before artifacts were written down has no log, and refusing to
480
+ * rebuild those would take away something that works today.
481
+ */
482
+ export function restoreArtifacts(store, revisions) {
483
+ for (const revision of revisions)
484
+ store.restore(revision);
485
+ return store.size;
486
+ }
487
+ /**
488
+ * The tool whose calls this reads. A constant rather than the string inline so
489
+ * renaming the tool cannot quietly stop old sessions from restoring.
490
+ */
491
+ const ARTIFACT_TOOL = "artifact_write";
492
+ export function getArtifactStore(state) {
493
+ const existing = state.get(ARTIFACTS_KEY);
494
+ if (existing instanceof ArtifactStore)
495
+ return existing;
496
+ const created = new ArtifactStore();
497
+ state.set(ARTIFACTS_KEY, created);
498
+ return created;
499
+ }
500
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/artifacts/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { AuthStore } from "./store.ts";
2
+ export { AuthManager, BUILTIN_AUTH_PROVIDERS } from "./manager.ts";
3
+ export type { AuthStatus } from "./manager.ts";
4
+ export { anthropicAuth, antAccessToken, ANT_PROFILE_MARKER } from "./providers/anthropic.ts";
5
+ export { ottoportAuth, ottoportBaseUrl } from "./providers/ottoport.ts";
6
+ export { officialAuth, officialBaseUrl } from "./providers/official.ts";
7
+ export { browserSignInUrl, exchangeHandoff, siteUrl } from "./providers/account.ts";
8
+ export { apiKeyProvider, oauthProvider } from "./providers/generic.ts";
9
+ export type { OAuthProviderOptions } from "./providers/generic.ts";
10
+ export { createPkce, exchangeToken, refreshCredential, startAuthCodeFlow, startDeviceFlow, startLoopbackFlow, toCredential, } from "./oauth.ts";
11
+ export type { DeviceFlowOptions, AuthCodeFlowOptions, TokenResponse } from "./oauth.ts";
12
+ export { isExpired } from "./types.ts";
13
+ export type { ApiCredential, ApiKeyMethod, AuthContext, AuthMethod, AuthProvider, AuthResolver, AuthorizeResult, CallbackResult, Credential, OAuthCredential, OAuthMethod, Prompt, PromptCondition, ResolvedAuth, SelectPrompt, TextPrompt, WellKnownCredential, } from "./types.ts";
@@ -0,0 +1,10 @@
1
+ export { AuthStore } from "./store.js";
2
+ export { AuthManager, BUILTIN_AUTH_PROVIDERS } from "./manager.js";
3
+ export { anthropicAuth, antAccessToken, ANT_PROFILE_MARKER } from "./providers/anthropic.js";
4
+ export { ottoportAuth, ottoportBaseUrl } from "./providers/ottoport.js";
5
+ export { officialAuth, officialBaseUrl } from "./providers/official.js";
6
+ export { browserSignInUrl, exchangeHandoff, siteUrl } from "./providers/account.js";
7
+ export { apiKeyProvider, oauthProvider } from "./providers/generic.js";
8
+ export { createPkce, exchangeToken, refreshCredential, startAuthCodeFlow, startDeviceFlow, startLoopbackFlow, toCredential, } from "./oauth.js";
9
+ export { isExpired } from "./types.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type { Logger } from "../util/logger.ts";
2
+ import { AuthStore } from "./store.ts";
3
+ import type { AuthContext, AuthMethod, AuthProvider, AuthorizeResult, Credential, Prompt, ResolvedAuth } from "./types.ts";
4
+ export interface AuthStatus {
5
+ providerId: string;
6
+ label: string;
7
+ authenticated: boolean;
8
+ /** Where the credential came from: `env:…`, `stored:oauth`, `ant-cli`, … */
9
+ source?: string;
10
+ /** For OAuth credentials, when the access token expires. */
11
+ expiresAt?: number;
12
+ methods: Array<{
13
+ index: number;
14
+ type: AuthMethod["type"];
15
+ label: string;
16
+ }>;
17
+ }
18
+ export declare const BUILTIN_AUTH_PROVIDERS: AuthProvider[];
19
+ /**
20
+ * Owns credentials: stores them, resolves them per request, and refreshes
21
+ * OAuth tokens before they expire.
22
+ *
23
+ * Refresh is in-flight-deduplicated. Without that, a turn issuing several
24
+ * parallel tool calls fires several simultaneous refreshes, and providers that
25
+ * rotate the refresh token on use will invalidate each other's result.
26
+ */
27
+ export declare class AuthManager {
28
+ readonly store: AuthStore;
29
+ private readonly providers;
30
+ private readonly logger;
31
+ private readonly refreshing;
32
+ constructor(opts?: {
33
+ store?: AuthStore;
34
+ providers?: AuthProvider[];
35
+ logger?: Logger;
36
+ });
37
+ register(provider: AuthProvider): this;
38
+ get(providerId: string): AuthProvider | undefined;
39
+ list(): AuthProvider[];
40
+ /**
41
+ * Resolve credentials for a request. Safe to call on every request — that is
42
+ * the point, since a token valid at startup may not be valid an hour later.
43
+ */
44
+ resolve(ctx: AuthContext): Promise<ResolvedAuth | undefined>;
45
+ /**
46
+ * The current access token for an OAuth provider, refreshed if it has run
47
+ * out.
48
+ *
49
+ * Separate from `resolve` because the caller wants the token itself rather
50
+ * than the headers a model request would carry — sync sends it to a server
51
+ * that is not a model provider, and digging it back out of a header would
52
+ * depend on how that provider happens to spell authorization today.
53
+ *
54
+ * Read per use, never held: these last an hour, and something that cached
55
+ * one would work until it silently did not.
56
+ */
57
+ accessToken(providerId: string): Promise<string | undefined>;
58
+ /** Whether a provider has usable credentials, without making a request. */
59
+ isAuthenticated(providerId: string): Promise<boolean>;
60
+ status(): Promise<AuthStatus[]>;
61
+ /**
62
+ * Which prompts apply given the answers collected so far. Conditional
63
+ * prompts let one method cover, say, public vs enterprise deployments
64
+ * without the CLI knowing anything about either.
65
+ */
66
+ promptsFor(method: AuthMethod, answers?: Record<string, string>): Prompt[];
67
+ /** Validate collected answers. Returns the first failure, if any. */
68
+ validate(method: AuthMethod, answers: Record<string, string>): {
69
+ field: string;
70
+ message: string;
71
+ } | undefined;
72
+ /** Begin an OAuth login. The caller drives the returned flow. */
73
+ authorize(providerId: string, methodIndex: number, answers?: Record<string, string>): Promise<AuthorizeResult>;
74
+ /** Complete an API-key login (or an OAuth method's non-interactive variant). */
75
+ submit(providerId: string, methodIndex: number, answers: Record<string, string>): Promise<Credential>;
76
+ /** Store the result of a completed OAuth callback. */
77
+ complete(providerId: string, result: Awaited<ReturnType<AuthorizeResult["callback"]>>): Promise<Credential>;
78
+ logout(providerId: string): Promise<boolean>;
79
+ private persist;
80
+ private methodAt;
81
+ /** Collapse concurrent refreshes of the same provider into one exchange. */
82
+ private refreshOnce;
83
+ }