@defrex/autobuild 0.8.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 (251) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +192 -0
  3. package/SPEC.md +2269 -0
  4. package/bin/ab-build-runner.ts +47 -0
  5. package/bin/ab-dev.ts +27 -0
  6. package/bin/ab-dispatch-kernel.ts +92 -0
  7. package/bin/ab-harvest-runner.ts +29 -0
  8. package/bin/ab-init-probe.ts +19 -0
  9. package/bin/ab-process-group-reaper.ts +32 -0
  10. package/bin/ab.ts +6 -0
  11. package/bin/agent/ab +3 -0
  12. package/docs/answering-blocked-builds.md +89 -0
  13. package/docs/architecture.md +726 -0
  14. package/docs/assets/headline-wide.png +0 -0
  15. package/docs/configuration.md +1623 -0
  16. package/docs/hosted-dispatcher-cutover-validation.md +178 -0
  17. package/docs/hosted-dispatcher.md +204 -0
  18. package/docs/mcp.md +119 -0
  19. package/docs/operator-api.md +186 -0
  20. package/docs/remote-store-protocol.md +972 -0
  21. package/docs/remote-ticket-protocol.md +79 -0
  22. package/docs/setup.md +289 -0
  23. package/docs/spec-standard.md +63 -0
  24. package/docs/ticket-dependencies.md +59 -0
  25. package/docs/vercel-sandbox-rollout-probe.md +7 -0
  26. package/package.json +135 -0
  27. package/packages/core/src/cli/args.ts +74 -0
  28. package/packages/core/src/cli/artifact.ts +182 -0
  29. package/packages/core/src/cli/binary.ts +198 -0
  30. package/packages/core/src/cli/build-control.ts +789 -0
  31. package/packages/core/src/cli/build-progress.ts +55 -0
  32. package/packages/core/src/cli/bulk-control.ts +385 -0
  33. package/packages/core/src/cli/context.ts +470 -0
  34. package/packages/core/src/cli/dashboard/actions.ts +59 -0
  35. package/packages/core/src/cli/dashboard/cells.ts +92 -0
  36. package/packages/core/src/cli/dashboard/composer.ts +230 -0
  37. package/packages/core/src/cli/dashboard/detail.ts +100 -0
  38. package/packages/core/src/cli/dashboard/frame-image.ts +373 -0
  39. package/packages/core/src/cli/dashboard/live.ts +152 -0
  40. package/packages/core/src/cli/dashboard/model.ts +1173 -0
  41. package/packages/core/src/cli/dashboard/poll.ts +196 -0
  42. package/packages/core/src/cli/dashboard/render.ts +1568 -0
  43. package/packages/core/src/cli/dashboard/selection.ts +66 -0
  44. package/packages/core/src/cli/dashboard/session-feed.ts +244 -0
  45. package/packages/core/src/cli/dashboard/session-view.ts +506 -0
  46. package/packages/core/src/cli/dashboard/transcript.ts +108 -0
  47. package/packages/core/src/cli/dev.ts +46 -0
  48. package/packages/core/src/cli/dispatch-frontend.ts +1045 -0
  49. package/packages/core/src/cli/dispatch-process.ts +259 -0
  50. package/packages/core/src/cli/dispatch.ts +3692 -0
  51. package/packages/core/src/cli/dotenv.ts +48 -0
  52. package/packages/core/src/cli/env.ts +206 -0
  53. package/packages/core/src/cli/harvest.ts +698 -0
  54. package/packages/core/src/cli/help.ts +713 -0
  55. package/packages/core/src/cli/init-agent.ts +106 -0
  56. package/packages/core/src/cli/init-validation.ts +583 -0
  57. package/packages/core/src/cli/init.ts +756 -0
  58. package/packages/core/src/cli/installation.ts +333 -0
  59. package/packages/core/src/cli/keyboard.ts +261 -0
  60. package/packages/core/src/cli/main.ts +1399 -0
  61. package/packages/core/src/cli/mcp.ts +279 -0
  62. package/packages/core/src/cli/models.ts +65 -0
  63. package/packages/core/src/cli/observe.ts +55 -0
  64. package/packages/core/src/cli/plugin.ts +227 -0
  65. package/packages/core/src/cli/pr-attachments.ts +138 -0
  66. package/packages/core/src/cli/pr-summary.ts +124 -0
  67. package/packages/core/src/cli/publication-settlement.ts +188 -0
  68. package/packages/core/src/cli/repo-state.ts +213 -0
  69. package/packages/core/src/cli/repository-status.ts +80 -0
  70. package/packages/core/src/cli/self-update.ts +443 -0
  71. package/packages/core/src/cli/status.ts +895 -0
  72. package/packages/core/src/cli/store-opening.contract.ts +289 -0
  73. package/packages/core/src/cli/store-opening.ts +167 -0
  74. package/packages/core/src/cli/store-ref.ts +33 -0
  75. package/packages/core/src/cli/terminal-restore.ts +174 -0
  76. package/packages/core/src/cli/terminal.ts +361 -0
  77. package/packages/core/src/cli/terminals.ts +995 -0
  78. package/packages/core/src/cli/testkit.ts +194 -0
  79. package/packages/core/src/cli/ticket.ts +484 -0
  80. package/packages/core/src/cli/upgrade-agent.ts +180 -0
  81. package/packages/core/src/cli/upgrade-commit.ts +468 -0
  82. package/packages/core/src/cli/upgrade-notice.ts +91 -0
  83. package/packages/core/src/cli/upgrade-progress.ts +110 -0
  84. package/packages/core/src/cli/upgrade.ts +888 -0
  85. package/packages/core/src/cli/wait.ts +587 -0
  86. package/packages/core/src/cli/watch.ts +932 -0
  87. package/packages/core/src/config/live.ts +255 -0
  88. package/packages/core/src/config/load.ts +98 -0
  89. package/packages/core/src/config/roles.ts +438 -0
  90. package/packages/core/src/config/schema.ts +774 -0
  91. package/packages/core/src/distribution.ts +24 -0
  92. package/packages/core/src/events/catalog.ts +201 -0
  93. package/packages/core/src/events/envelope.ts +59 -0
  94. package/packages/core/src/events/payloads.ts +618 -0
  95. package/packages/core/src/events/repository.ts +559 -0
  96. package/packages/core/src/events/sessions.ts +180 -0
  97. package/packages/core/src/harvest/schema.ts +147 -0
  98. package/packages/core/src/ids.ts +45 -0
  99. package/packages/core/src/integration/harness.ts +681 -0
  100. package/packages/core/src/kernel/auto-merge.ts +259 -0
  101. package/packages/core/src/kernel/converge.ts +117 -0
  102. package/packages/core/src/kernel/dispatch-settings.ts +60 -0
  103. package/packages/core/src/kernel/dispatch-status.ts +141 -0
  104. package/packages/core/src/kernel/engine.ts +1047 -0
  105. package/packages/core/src/kernel/harvest.ts +823 -0
  106. package/packages/core/src/kernel/origin.ts +69 -0
  107. package/packages/core/src/kernel/phases.ts +196 -0
  108. package/packages/core/src/kernel/plan-verify-selection.ts +105 -0
  109. package/packages/core/src/kernel/pr-attachments.ts +82 -0
  110. package/packages/core/src/kernel/reducer.ts +752 -0
  111. package/packages/core/src/kernel/stall.ts +155 -0
  112. package/packages/core/src/kernel/verify-applicability.ts +52 -0
  113. package/packages/core/src/markdown.ts +67 -0
  114. package/packages/core/src/ontology.ts +288 -0
  115. package/packages/core/src/open-map.ts +203 -0
  116. package/packages/core/src/operator/annotations.ts +187 -0
  117. package/packages/core/src/operator/client.ts +311 -0
  118. package/packages/core/src/operator/control.ts +117 -0
  119. package/packages/core/src/operator/index.ts +62 -0
  120. package/packages/core/src/operator/presentation.ts +22 -0
  121. package/packages/core/src/operator/protocol.ts +98 -0
  122. package/packages/core/src/operator/query.ts +201 -0
  123. package/packages/core/src/operator/registry.ts +1043 -0
  124. package/packages/core/src/operator/requests.ts +138 -0
  125. package/packages/core/src/operator/sandbox.ts +458 -0
  126. package/packages/core/src/operator/server.ts +616 -0
  127. package/packages/core/src/operator/sessions.ts +223 -0
  128. package/packages/core/src/operator/tickets.ts +177 -0
  129. package/packages/core/src/plugin-sdk/index.ts +174 -0
  130. package/packages/core/src/plugins/contract-entry.ts +74 -0
  131. package/packages/core/src/plugins/contract-env.ts +3 -0
  132. package/packages/core/src/plugins/load.ts +259 -0
  133. package/packages/core/src/plugins/manifest.ts +236 -0
  134. package/packages/core/src/plugins/registry.ts +274 -0
  135. package/packages/core/src/plugins/runtimes.ts +75 -0
  136. package/packages/core/src/ports/forge/contract.ts +258 -0
  137. package/packages/core/src/ports/forge/create.ts +74 -0
  138. package/packages/core/src/ports/forge/fake.ts +488 -0
  139. package/packages/core/src/ports/forge/github-pr-attachments.ts +351 -0
  140. package/packages/core/src/ports/forge/github-transport.ts +352 -0
  141. package/packages/core/src/ports/forge/github.ts +1162 -0
  142. package/packages/core/src/ports/forge/local-git.ts +568 -0
  143. package/packages/core/src/ports/runner/claude.ts +873 -0
  144. package/packages/core/src/ports/runner/cli-stream.ts +90 -0
  145. package/packages/core/src/ports/runner/codex.ts +873 -0
  146. package/packages/core/src/ports/runner/contract.ts +492 -0
  147. package/packages/core/src/ports/runner/fake.ts +213 -0
  148. package/packages/core/src/ports/runner/json-record.ts +2 -0
  149. package/packages/core/src/ports/runner/live-contract-fixture.ts +176 -0
  150. package/packages/core/src/ports/runner/one-shot.ts +29 -0
  151. package/packages/core/src/ports/runner/pi-bridge-core.ts +136 -0
  152. package/packages/core/src/ports/runner/pi-bridge.js +6 -0
  153. package/packages/core/src/ports/runner/pi-rpc.ts +454 -0
  154. package/packages/core/src/ports/runner/pi.ts +617 -0
  155. package/packages/core/src/ports/runner/production.ts +74 -0
  156. package/packages/core/src/ports/runner/provider-error.ts +121 -0
  157. package/packages/core/src/ports/runner/routing.ts +234 -0
  158. package/packages/core/src/ports/runner/runtime.ts +214 -0
  159. package/packages/core/src/ports/runner/session-env.ts +34 -0
  160. package/packages/core/src/ports/runner/stream-parts.ts +103 -0
  161. package/packages/core/src/ports/tickets/contract.ts +570 -0
  162. package/packages/core/src/ports/tickets/create.ts +135 -0
  163. package/packages/core/src/ports/tickets/fake.ts +215 -0
  164. package/packages/core/src/ports/tickets/file.ts +559 -0
  165. package/packages/core/src/ports/tickets/linear.ts +811 -0
  166. package/packages/core/src/ports/tickets/operations.ts +161 -0
  167. package/packages/core/src/ports/tickets/remote-index.ts +13 -0
  168. package/packages/core/src/ports/tickets/remote-protocol.ts +80 -0
  169. package/packages/core/src/ports/tickets/remote-server.ts +185 -0
  170. package/packages/core/src/ports/tickets/remote.ts +130 -0
  171. package/packages/core/src/ports/tickets/update.ts +51 -0
  172. package/packages/core/src/ports/types.ts +528 -0
  173. package/packages/core/src/ports/workspace/build-execution.ts +123 -0
  174. package/packages/core/src/ports/workspace/contract.ts +136 -0
  175. package/packages/core/src/ports/workspace/create.ts +132 -0
  176. package/packages/core/src/ports/workspace/distribution-archive.ts +317 -0
  177. package/packages/core/src/ports/workspace/fake.ts +432 -0
  178. package/packages/core/src/ports/workspace/git-worktree.ts +848 -0
  179. package/packages/core/src/ports/workspace/harvest-execution.ts +111 -0
  180. package/packages/core/src/ports/workspace/in-process-build-execution.ts +30 -0
  181. package/packages/core/src/ports/workspace/local-build-execution.ts +88 -0
  182. package/packages/core/src/ports/workspace/operator-sandbox.ts +142 -0
  183. package/packages/core/src/ports/workspace/phase-scratch.ts +156 -0
  184. package/packages/core/src/ports/workspace/vercel-sandbox.ts +2541 -0
  185. package/packages/core/src/processes/build-child-exit.ts +78 -0
  186. package/packages/core/src/processes/build-child.ts +119 -0
  187. package/packages/core/src/processes/build-execution-state.ts +95 -0
  188. package/packages/core/src/processes/build-parent-watch.ts +35 -0
  189. package/packages/core/src/processes/build-runner.ts +2614 -0
  190. package/packages/core/src/processes/dispatcher.ts +2825 -0
  191. package/packages/core/src/processes/execution-settlement.ts +171 -0
  192. package/packages/core/src/processes/harvest-child.ts +115 -0
  193. package/packages/core/src/processes/harvest-execution-state.ts +121 -0
  194. package/packages/core/src/processes/harvest-runner.ts +1656 -0
  195. package/packages/core/src/processes/harvest.ts +595 -0
  196. package/packages/core/src/processes/infrastructure-failure-budget.ts +146 -0
  197. package/packages/core/src/processes/phase-failure-budget.ts +52 -0
  198. package/packages/core/src/processes/process-group-reaper.ts +35 -0
  199. package/packages/core/src/processes/process-group.ts +65 -0
  200. package/packages/core/src/processes/publication-loss.ts +62 -0
  201. package/packages/core/src/processes/publication-state.ts +93 -0
  202. package/packages/core/src/processes/sandbox-state.ts +101 -0
  203. package/packages/core/src/registry.ts +24 -0
  204. package/packages/core/src/sessions/reducer.ts +185 -0
  205. package/packages/core/src/skills.ts +7 -0
  206. package/packages/core/src/spec-standard.ts +47 -0
  207. package/packages/core/src/store/adapter.ts +80 -0
  208. package/packages/core/src/store/build-scope.ts +272 -0
  209. package/packages/core/src/store/contract.ts +2581 -0
  210. package/packages/core/src/store/local/blobs.ts +38 -0
  211. package/packages/core/src/store/local/schema.ts +180 -0
  212. package/packages/core/src/store/local/store.ts +1713 -0
  213. package/packages/core/src/store/memory.ts +1138 -0
  214. package/packages/core/src/store/phase-session.ts +425 -0
  215. package/packages/core/src/store/remote/client.ts +780 -0
  216. package/packages/core/src/store/remote/index.ts +12 -0
  217. package/packages/core/src/store/remote/protocol.ts +348 -0
  218. package/packages/core/src/store/remote/server.ts +923 -0
  219. package/packages/core/src/store/remote/token.ts +137 -0
  220. package/packages/core/src/store/remote/version.ts +10 -0
  221. package/packages/core/src/store/retention.ts +91 -0
  222. package/packages/core/src/store/session-handle.ts +265 -0
  223. package/packages/core/src/store/streams/assemble.ts +79 -0
  224. package/packages/core/src/store/streams/lock.ts +42 -0
  225. package/packages/core/src/store/streams/session-writer.ts +306 -0
  226. package/packages/core/src/store/streams/types.ts +171 -0
  227. package/packages/core/src/store/streams/wait.ts +127 -0
  228. package/packages/core/src/store/subscribe.ts +105 -0
  229. package/packages/core/src/store/types.ts +466 -0
  230. package/packages/core/src/testing/fixed.ts +44 -0
  231. package/packages/core/src/testing/store-failures.ts +32 -0
  232. package/packages/core/src/zod-issues.ts +91 -0
  233. package/skills/code-review/SKILL.md +100 -0
  234. package/skills/finalize/SKILL.md +44 -0
  235. package/skills/guide/SKILL.md +1781 -0
  236. package/skills/guide/references/operator-api.md +164 -0
  237. package/skills/guide/references/plugin-authoring.md +354 -0
  238. package/skills/guide/references/remote-store-protocol.md +972 -0
  239. package/skills/guide/references/remote-ticket-protocol.md +79 -0
  240. package/skills/guide/references/setup.md +289 -0
  241. package/skills/guide/references/spec-standard.md +63 -0
  242. package/skills/guide/references/ticket-dependencies.md +59 -0
  243. package/skills/harvest/SKILL.md +66 -0
  244. package/skills/harvest-review/SKILL.md +63 -0
  245. package/skills/implement/SKILL.md +82 -0
  246. package/skills/plan/SKILL.md +123 -0
  247. package/skills/plan-review/SKILL.md +121 -0
  248. package/skills/reconcile/SKILL.md +65 -0
  249. package/skills/spec/SKILL.md +132 -0
  250. package/skills/tickets/SKILL.md +139 -0
  251. package/templates/autobuild.toml +36 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Content-addressed blobs as a plain directory (SPEC §7.1, §7.2.1): files
3
+ * sharded `root/<hash[0:2]>/<hash>`. Put is idempotent — the hash *is* the
4
+ * identity, so an existing file is already the requested content.
5
+ */
6
+ import { randomUUID } from 'node:crypto'
7
+ import { mkdir, rename } from 'node:fs/promises'
8
+ import { join } from 'node:path'
9
+ import type { BlobStore } from '../types'
10
+
11
+ export class DirBlobStore implements BlobStore {
12
+ constructor(readonly root: string) {}
13
+
14
+ private pathFor(hash: string): string {
15
+ return join(this.root, hash.slice(0, 2), hash)
16
+ }
17
+
18
+ async put(hash: string, bytes: Uint8Array): Promise<void> {
19
+ const path = this.pathFor(hash)
20
+ if (await Bun.file(path).exists()) return
21
+ await mkdir(join(this.root, hash.slice(0, 2)), { recursive: true })
22
+ // Write-then-rename so a crashed write never leaves a truncated blob
23
+ // wearing a valid content address. The temp name is unique per call
24
+ // (pid + uuid): concurrent puts of the same hash — separate processes
25
+ // sharing one local store (§7.1) — must never share a temp path, or one
26
+ // writer's O_TRUNC reopen could truncate the bytes another is about to
27
+ // rename into the final content address.
28
+ const partial = `${path}.${process.pid}.${randomUUID()}.partial`
29
+ await Bun.write(partial, bytes)
30
+ await rename(partial, path)
31
+ }
32
+
33
+ async get(hash: string): Promise<Uint8Array | null> {
34
+ const file = Bun.file(this.pathFor(hash))
35
+ if (!(await file.exists())) return null
36
+ return new Uint8Array(await file.arrayBuffer())
37
+ }
38
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Drizzle schema for the local SQLite BuildStore (SPEC §7.1): simple,
3
+ * normalized, boring. Lease + heartbeat are mutable liveness columns on
4
+ * `builds`, never events (§15.2.6). Events and artifacts store JSON in text
5
+ * columns; bulk content lives behind the BlobStore — the database stores
6
+ * refs (sha256 blobRef), never blobs.
7
+ *
8
+ * `store.ts` bootstraps these tables with inline DDL at open; that DDL must
9
+ * be kept in lockstep with this schema (this file is the drizzle-kit source
10
+ * of truth).
11
+ */
12
+ import { integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core'
13
+ import type { Actor } from '../../events/envelope'
14
+ import type { TicketRef } from '../../ontology'
15
+ import type { StreamPart } from '../streams/types'
16
+
17
+ export const builds = sqliteTable('builds', {
18
+ slug: text('slug').primaryKey(),
19
+ repo: text('repo').notNull(),
20
+ repoOrigin: text('repo_origin'),
21
+ ticket: text('ticket', { mode: 'json' }).$type<TicketRef>(),
22
+ branch: text('branch'),
23
+ createdAt: text('created_at').notNull(),
24
+ updatedAt: text('updated_at').notNull(),
25
+ leaseHolder: text('lease_holder'),
26
+ leaseExpiresAt: text('lease_expires_at'),
27
+ leaseTtlMs: integer('lease_ttl_ms'),
28
+ heartbeatAt: text('heartbeat_at'),
29
+ })
30
+
31
+ export const events = sqliteTable(
32
+ 'events',
33
+ {
34
+ build: text('build').notNull(),
35
+ /** Per-build, monotonic from 1, assigned in-transaction on append (§15.1). */
36
+ seq: integer('seq').notNull(),
37
+ ts: text('ts').notNull(),
38
+ actor: text('actor', { mode: 'json' }).notNull().$type<Actor>(),
39
+ type: text('type').notNull(),
40
+ payload: text('payload', { mode: 'json' }).notNull(),
41
+ },
42
+ (t) => [primaryKey({ columns: [t.build, t.seq] })],
43
+ )
44
+
45
+ export const repoStreams = sqliteTable('repo_streams', {
46
+ repo: text('repo').primaryKey(),
47
+ createdAt: text('created_at').notNull(),
48
+ updatedAt: text('updated_at').notNull(),
49
+ leaseHolder: text('lease_holder'),
50
+ leaseExpiresAt: text('lease_expires_at'),
51
+ leaseTtlMs: integer('lease_ttl_ms'),
52
+ heartbeatAt: text('heartbeat_at'),
53
+ })
54
+
55
+ export const repoEvents = sqliteTable(
56
+ 'repo_events',
57
+ {
58
+ repo: text('repo').notNull(),
59
+ seq: integer('seq').notNull(),
60
+ ts: text('ts').notNull(),
61
+ actor: text('actor', { mode: 'json' }).notNull().$type<Actor>(),
62
+ type: text('type').notNull(),
63
+ payload: text('payload', { mode: 'json' }).notNull(),
64
+ },
65
+ (t) => [primaryKey({ columns: [t.repo, t.seq] })],
66
+ )
67
+
68
+ export const repoArtifacts = sqliteTable(
69
+ 'repo_artifacts',
70
+ {
71
+ repo: text('repo').notNull(),
72
+ kind: text('kind').notNull(),
73
+ revision: integer('revision').notNull(),
74
+ blobRef: text('blob_ref').notNull(),
75
+ metadata: text('metadata', { mode: 'json' }).notNull().$type<Record<string, unknown>>(),
76
+ createdAt: text('created_at').notNull(),
77
+ },
78
+ (t) => [primaryKey({ columns: [t.repo, t.kind, t.revision] })],
79
+ )
80
+
81
+ /** Operator sessions (SPEC §7.1.1): hosted-only durable orchestrator
82
+ * conversation state. Adapters implement the contract uniformly; nothing
83
+ * local creates one. */
84
+ export const sessions = sqliteTable('sessions', {
85
+ id: text('id').primaryKey(),
86
+ repo: text('repo').notNull(),
87
+ operator: text('operator').notNull(),
88
+ title: text('title'),
89
+ /** Store-assigned monotonic creation sequence (assigned in-transaction at
90
+ * `createSession`, never reused — sessions are never deleted). The
91
+ * `listSessions` same-timestamp tiebreak; not part of `SessionRecord`. */
92
+ creationSeq: integer('creation_seq').notNull(),
93
+ createdAt: text('created_at').notNull(),
94
+ updatedAt: text('updated_at').notNull(),
95
+ })
96
+
97
+ export const sessionEvents = sqliteTable(
98
+ 'session_events',
99
+ {
100
+ session: text('session')
101
+ .notNull()
102
+ .references(() => sessions.id, { onDelete: 'cascade' }),
103
+ /** Per-session, monotonic from 1, assigned in-transaction on append. */
104
+ seq: integer('seq').notNull(),
105
+ ts: text('ts').notNull(),
106
+ actor: text('actor', { mode: 'json' }).notNull().$type<Actor>(),
107
+ type: text('type').notNull(),
108
+ payload: text('payload', { mode: 'json' }).notNull(),
109
+ },
110
+ (t) => [primaryKey({ columns: [t.session, t.seq] })],
111
+ )
112
+
113
+ export const sessionArtifacts = sqliteTable(
114
+ 'session_artifacts',
115
+ {
116
+ session: text('session')
117
+ .notNull()
118
+ .references(() => sessions.id, { onDelete: 'cascade' }),
119
+ kind: text('kind').notNull(),
120
+ revision: integer('revision').notNull(),
121
+ blobRef: text('blob_ref').notNull(),
122
+ metadata: text('metadata', { mode: 'json' }).notNull().$type<Record<string, unknown>>(),
123
+ createdAt: text('created_at').notNull(),
124
+ },
125
+ (t) => [primaryKey({ columns: [t.session, t.kind, t.revision] })],
126
+ )
127
+
128
+ export const artifacts = sqliteTable(
129
+ 'artifacts',
130
+ {
131
+ build: text('build').notNull(),
132
+ kind: text('kind').notNull(),
133
+ /** 0-based per (build, kind) — the first deposit of a kind is rev 0 (§6.3). */
134
+ revision: integer('revision').notNull(),
135
+ /** sha256 content address into the BlobStore (§7.1). */
136
+ blobRef: text('blob_ref').notNull(),
137
+ metadata: text('metadata', { mode: 'json' }).notNull().$type<Record<string, unknown>>(),
138
+ createdAt: text('created_at').notNull(),
139
+ },
140
+ (t) => [primaryKey({ columns: [t.build, t.kind, t.revision] })],
141
+ )
142
+
143
+ /** Streams (SPEC §7.6): the third primitive. Scope is fixed at create; the
144
+ * CHECKs guarantee exactly one of build/repo/session is set, matching the
145
+ * scope kind. */
146
+ export const streams = sqliteTable('streams', {
147
+ id: text('id').primaryKey(),
148
+ scopeKind: text('scope_kind').notNull(),
149
+ build: text('build'),
150
+ repo: text('repo'),
151
+ session: text('session'),
152
+ label: text('label').notNull(),
153
+ format: text('format').notNull(),
154
+ status: text('status').notNull(),
155
+ outcome: text('outcome'),
156
+ artifactKind: text('artifact_kind'),
157
+ artifactRevision: integer('artifact_revision'),
158
+ artifactBlobRef: text('artifact_blob_ref'),
159
+ createdAt: text('created_at').notNull(),
160
+ closedAt: text('closed_at'),
161
+ /** Store-assigned monotonic creation sequence (assigned in-transaction at
162
+ * `createStream`, never reused — streams are never deleted; retention
163
+ * prunes `stream_chunks` only). The `listStreams` same-timestamp tiebreak;
164
+ * not part of `StreamRecord`. */
165
+ creationSeq: integer('creation_seq').notNull(),
166
+ })
167
+
168
+ export const streamChunks = sqliteTable(
169
+ 'stream_chunks',
170
+ {
171
+ stream: text('stream')
172
+ .notNull()
173
+ .references(() => streams.id, { onDelete: 'cascade' }),
174
+ /** Per-stream, monotonic from 1, assigned in-transaction on append. */
175
+ seq: integer('seq').notNull(),
176
+ ts: text('ts').notNull(),
177
+ parts: text('parts', { mode: 'json' }).notNull().$type<StreamPart[]>(),
178
+ },
179
+ (t) => [primaryKey({ columns: [t.stream, t.seq] })],
180
+ )