@runeditrun/rer 0.0.0-stage → 0.1.1

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 (527) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -2
  3. package/bin/rer.mjs +3 -0
  4. package/cli/README.md +243 -0
  5. package/cli/adapter.mjs +10 -0
  6. package/cli/ai-local.mjs +65 -0
  7. package/cli/archive-path.mjs +52 -0
  8. package/cli/archive-vite.mjs +55 -0
  9. package/cli/archive.mjs +8 -0
  10. package/cli/auth-copy.mjs +80 -0
  11. package/cli/bounded.mjs +70 -0
  12. package/cli/cache-doctor.mjs +63 -0
  13. package/cli/container-transfer.mjs +35 -0
  14. package/cli/container.mjs +62 -0
  15. package/cli/contract.mjs +25 -0
  16. package/cli/dependencies.mjs +45 -0
  17. package/cli/dependency-approval.mjs +33 -0
  18. package/cli/dependency-doctor.mjs +34 -0
  19. package/cli/dependency-input.mjs +43 -0
  20. package/cli/deploy-config.mjs +118 -0
  21. package/cli/deploy.mjs +37 -0
  22. package/cli/dev-identity.mjs +80 -0
  23. package/cli/errors.mjs +14 -0
  24. package/cli/export.mjs +42 -0
  25. package/cli/font-cache.mjs +29 -0
  26. package/cli/hosted-output.mjs +110 -0
  27. package/cli/independent.mjs +29 -0
  28. package/cli/inspect.mjs +174 -0
  29. package/cli/jsonc.mjs +111 -0
  30. package/cli/lifecycle.mjs +148 -0
  31. package/cli/local.mjs +100 -0
  32. package/cli/main.mjs +57 -0
  33. package/cli/managed-server.mjs +143 -0
  34. package/cli/node-runtime-cache.mjs +68 -0
  35. package/cli/node-runtime-discovery.mjs +56 -0
  36. package/cli/node-runtime-download.mjs +59 -0
  37. package/cli/node-runtime.mjs +50 -0
  38. package/cli/output.mjs +22 -0
  39. package/cli/parse.mjs +77 -0
  40. package/cli/port.mjs +52 -0
  41. package/cli/portability-worker.mjs +56 -0
  42. package/cli/portability.mjs +66 -0
  43. package/cli/preview-cache.mjs +99 -0
  44. package/cli/project.mjs +48 -0
  45. package/cli/release.mjs +24 -0
  46. package/cli/runtime-front-door.mjs +46 -0
  47. package/cli/scheduled.mjs +81 -0
  48. package/cli/server-activity.mjs +12 -0
  49. package/cli/server-proxy.mjs +93 -0
  50. package/cli/server-registry.mjs +182 -0
  51. package/cli/server-resources.mjs +22 -0
  52. package/cli/settings.mjs +15 -0
  53. package/cli/setup-answers.mjs +29 -0
  54. package/cli/setup-input.mjs +113 -0
  55. package/cli/shared.mjs +7 -0
  56. package/cli/transfers.mjs +33 -0
  57. package/cli/version.mjs +36 -0
  58. package/composition/git-source.mjs +111 -0
  59. package/edition-authoring/files.mjs +81 -0
  60. package/edition-authoring/manifest.mjs +65 -0
  61. package/global/README.md +158 -0
  62. package/global/checkout.mjs +72 -0
  63. package/global/cli/command.mjs +13 -0
  64. package/global/cli/install.mjs +75 -0
  65. package/global/cli/layout.mjs +45 -0
  66. package/global/cli/status.mjs +54 -0
  67. package/global/cli/uninstall.mjs +36 -0
  68. package/global/delegate.mjs +13 -0
  69. package/global/launch/capacity.mjs +72 -0
  70. package/global/launch/dev.mjs +117 -0
  71. package/global/launch/facts.mjs +94 -0
  72. package/global/launch/failure.mjs +5 -0
  73. package/global/launch/local-defaults.mjs +4 -0
  74. package/global/launch/prepare.mjs +63 -0
  75. package/global/launch/render.mjs +44 -0
  76. package/global/launch/state.mjs +106 -0
  77. package/global/launch/steps.mjs +90 -0
  78. package/global/launch/stop.mjs +89 -0
  79. package/global/launch/worker.mjs +62 -0
  80. package/global/list.mjs +59 -0
  81. package/global/main.mjs +53 -0
  82. package/global/package-info.mjs +38 -0
  83. package/global/registry.mjs +24 -0
  84. package/global/rer.mjs +29 -0
  85. package/global/update/archive.mjs +89 -0
  86. package/global/update/command.mjs +90 -0
  87. package/global/update/latest.mjs +6 -0
  88. package/global/update/notice.mjs +58 -0
  89. package/global/update/registry.mjs +47 -0
  90. package/global/version.mjs +29 -0
  91. package/install.sh +144 -0
  92. package/modules/ai/LICENSE +21 -0
  93. package/modules/ai/README.md +90 -0
  94. package/modules/ai/client.mjs +71 -0
  95. package/modules/ai/config.mjs +39 -0
  96. package/modules/ai/dev/index.d.mts +6 -0
  97. package/modules/ai/dev/index.mjs +64 -0
  98. package/modules/ai/dev/outbox.mjs +33 -0
  99. package/modules/ai/errors.mjs +28 -0
  100. package/modules/ai/fake/index.d.mts +3 -0
  101. package/modules/ai/fake/index.mjs +82 -0
  102. package/modules/ai/index.d.mts +10 -0
  103. package/modules/ai/index.mjs +3 -0
  104. package/modules/ai/package.json +6 -0
  105. package/modules/container/README.md +156 -0
  106. package/modules/container/adapters/d1.mjs +34 -0
  107. package/modules/container/adapters/egress.mjs +40 -0
  108. package/modules/container/adapters/jobs.mjs +47 -0
  109. package/modules/container/adapters/objects.mjs +84 -0
  110. package/modules/container/adapters/retained.mjs +14 -0
  111. package/modules/container/adapters/sqlite-error.mjs +7 -0
  112. package/modules/container/adapters/sqlite-worker.mjs +26 -0
  113. package/modules/container/assets.mjs +14 -0
  114. package/modules/container/bindings.mjs +1 -0
  115. package/modules/container/boundary.mjs +38 -0
  116. package/modules/container/build.mjs +65 -0
  117. package/modules/container/deploy-input.mjs +17 -0
  118. package/modules/container/entrypoint.sh +5 -0
  119. package/modules/container/host.mjs +43 -0
  120. package/modules/container/ingress.mjs +23 -0
  121. package/modules/container/lock.mjs +11 -0
  122. package/modules/container/migrations.mjs +16 -0
  123. package/modules/container/node-engine.mjs +39 -0
  124. package/modules/container/portability-schema.mjs +14 -0
  125. package/modules/container/remote/deploy.py +76 -0
  126. package/modules/container/remote/files.py +275 -0
  127. package/modules/container/remote/resources.py +157 -0
  128. package/modules/container/runner.mjs +10 -0
  129. package/modules/container/ssh-plan.mjs +44 -0
  130. package/modules/container/ssh.mjs +63 -0
  131. package/modules/container/transfer.mjs +27 -0
  132. package/modules/container/worker-engine.mjs +32 -0
  133. package/modules/dependencies/README.md +211 -0
  134. package/modules/dependencies/approval.mjs +51 -0
  135. package/modules/dependencies/auth.mjs +40 -0
  136. package/modules/dependencies/authority.mjs +14 -0
  137. package/modules/dependencies/crypto.mjs +13 -0
  138. package/modules/dependencies/index.d.mts +23 -0
  139. package/modules/dependencies/index.mjs +113 -0
  140. package/modules/dependencies/logout.mjs +42 -0
  141. package/modules/dependencies/native.mjs +9 -0
  142. package/modules/dependencies/protocol.mjs +23 -0
  143. package/modules/dependencies/schema/approval-attempt.sql +3 -0
  144. package/modules/dependencies/schema/dependencies.sql +15 -0
  145. package/modules/dependencies/store.mjs +19 -0
  146. package/modules/deploy-kit/README.md +308 -0
  147. package/modules/deploy-kit/artifact.mjs +47 -0
  148. package/modules/deploy-kit/build-modules.mjs +21 -0
  149. package/modules/deploy-kit/check.mjs +13 -0
  150. package/modules/deploy-kit/cli.mjs +50 -0
  151. package/modules/deploy-kit/container-config.mjs +8 -0
  152. package/modules/deploy-kit/default-stage.mjs +14 -0
  153. package/modules/deploy-kit/deploy.mjs +80 -0
  154. package/modules/deploy-kit/health-request.mjs +86 -0
  155. package/modules/deploy-kit/health.mjs +99 -0
  156. package/modules/deploy-kit/index.mjs +12 -0
  157. package/modules/deploy-kit/local-only.mjs +10 -0
  158. package/modules/deploy-kit/migrations.mjs +48 -0
  159. package/modules/deploy-kit/owner-cli.mjs +63 -0
  160. package/modules/deploy-kit/owner.mjs +297 -0
  161. package/modules/deploy-kit/prepare.mjs +62 -0
  162. package/modules/deploy-kit/provider.mjs +99 -0
  163. package/modules/deploy-kit/queue-consumer.mjs +10 -0
  164. package/modules/deploy-kit/receipt.mjs +16 -0
  165. package/modules/deploy-kit/render.mjs +47 -0
  166. package/modules/deploy-kit/resources.mjs +106 -0
  167. package/modules/deploy-kit/service-grants.mjs +25 -0
  168. package/modules/deploy-kit/sql-safety.mjs +94 -0
  169. package/modules/deploy-kit/sql-tokens.mjs +49 -0
  170. package/modules/deploy-kit/teardown.mjs +100 -0
  171. package/modules/deploy-kit/templates.mjs +31 -0
  172. package/modules/deploy-kit/validation.mjs +58 -0
  173. package/modules/deploy-kit/worker.mjs +105 -0
  174. package/modules/erasure/CONTRACT.md +90 -0
  175. package/modules/erasure/README.md +221 -0
  176. package/modules/erasure/audit.mjs +23 -0
  177. package/modules/erasure/blobs.mjs +45 -0
  178. package/modules/erasure/cascade.mjs +91 -0
  179. package/modules/erasure/completion.mjs +62 -0
  180. package/modules/erasure/declaration.mjs +51 -0
  181. package/modules/erasure/fence.mjs +19 -0
  182. package/modules/erasure/index.d.mts +62 -0
  183. package/modules/erasure/index.mjs +85 -0
  184. package/modules/erasure/order.mjs +56 -0
  185. package/modules/erasure/plan.mjs +121 -0
  186. package/modules/erasure/rate.mjs +57 -0
  187. package/modules/erasure/receipt.mjs +32 -0
  188. package/modules/erasure/root.mjs +21 -0
  189. package/modules/erasure/schema/erasure-rates.sql +5 -0
  190. package/modules/erasure/schema/erasure.sql +27 -0
  191. package/modules/erasure/scope.mjs +29 -0
  192. package/modules/erasure/sql.mjs +23 -0
  193. package/modules/erasure/verification.mjs +69 -0
  194. package/modules/integrations/core/CONTRACT.md +50 -0
  195. package/modules/integrations/core/README.md +27 -0
  196. package/modules/integrations/core/crypto.ts +19 -0
  197. package/modules/integrations/core/database.ts +21 -0
  198. package/modules/integrations/core/delivery.ts +97 -0
  199. package/modules/integrations/core/destination.ts +13 -0
  200. package/modules/integrations/core/index.ts +7 -0
  201. package/modules/integrations/core/node-transport.ts +72 -0
  202. package/modules/integrations/core/public-address.ts +57 -0
  203. package/modules/integrations/core/repository.ts +74 -0
  204. package/modules/integrations/core/schema.sql +36 -0
  205. package/modules/integrations/core/sqlite.ts +20 -0
  206. package/modules/integrations/core/timestamped-body-signature.ts +38 -0
  207. package/modules/integrations/core/tokens.ts +71 -0
  208. package/modules/integrations/core/types.ts +52 -0
  209. package/modules/integrations/core/upgrade-token-usage-context.sql +5 -0
  210. package/modules/integrations/core/webhook.ts +73 -0
  211. package/modules/job-queue/README.md +173 -0
  212. package/modules/job-queue/cli.mjs +64 -0
  213. package/modules/job-queue/command.mjs +64 -0
  214. package/modules/job-queue/config.mjs +48 -0
  215. package/modules/job-queue/identity.mjs +48 -0
  216. package/modules/job-queue/index.mjs +135 -0
  217. package/modules/job-queue/membership.mjs +30 -0
  218. package/modules/job-queue/module.json +10 -0
  219. package/modules/job-queue/policy.mjs +29 -0
  220. package/modules/job-queue/processes.mjs +80 -0
  221. package/modules/job-queue/resources.mjs +37 -0
  222. package/modules/job-queue/storage.mjs +64 -0
  223. package/modules/job-queue/supervisor.mjs +30 -0
  224. package/modules/job-queue/waiting.mjs +16 -0
  225. package/modules/mail/LICENSE +21 -0
  226. package/modules/mail/README.md +336 -0
  227. package/modules/mail/doctor.mjs +81 -0
  228. package/modules/mail/index.mjs +8 -0
  229. package/modules/mail/live-proof/README.md +113 -0
  230. package/modules/mail/live-proof/run.mjs +55 -0
  231. package/modules/mail/package.json +19 -0
  232. package/modules/mail/pnpm-lock.yaml +537 -0
  233. package/modules/mail/src/adapters/cloudflare/README.md +84 -0
  234. package/modules/mail/src/adapters/cloudflare/headers.mjs +63 -0
  235. package/modules/mail/src/adapters/cloudflare/index.mjs +47 -0
  236. package/modules/mail/src/adapters/cloudflare/response.mjs +99 -0
  237. package/modules/mail/src/adapters/messaging/README.md +92 -0
  238. package/modules/mail/src/adapters/messaging/contract.mjs +66 -0
  239. package/modules/mail/src/adapters/messaging/event-schema.mjs +28 -0
  240. package/modules/mail/src/adapters/messaging/index.mjs +61 -0
  241. package/modules/mail/src/adapters/messaging/jws.mjs +68 -0
  242. package/modules/mail/src/adapters/messaging/request.mjs +52 -0
  243. package/modules/mail/src/adapters/messaging/serialize.mjs +21 -0
  244. package/modules/mail/src/adapters/resend/README.md +120 -0
  245. package/modules/mail/src/adapters/resend/index.mjs +22 -0
  246. package/modules/mail/src/adapters/resend/response.mjs +54 -0
  247. package/modules/mail/src/adapters/resend/serialize.mjs +46 -0
  248. package/modules/mail/src/adapters/resend/size.mjs +99 -0
  249. package/modules/mail/src/adapters/sendgrid/README.md +75 -0
  250. package/modules/mail/src/adapters/sendgrid/index.mjs +35 -0
  251. package/modules/mail/src/adapters/sendgrid/serialize.mjs +104 -0
  252. package/modules/mail/src/core/errors.mjs +9 -0
  253. package/modules/mail/src/core/transport.mjs +33 -0
  254. package/modules/mail/src/core/validation.mjs +172 -0
  255. package/modules/mail/src/development/index.d.mts +37 -0
  256. package/modules/mail/src/development/index.mjs +35 -0
  257. package/modules/mail/src/development/outbox.mjs +78 -0
  258. package/modules/mail/src/development/schema.sql +9 -0
  259. package/modules/mail/src/development/viewer-html.mjs +42 -0
  260. package/modules/mail/src/development/viewer.mjs +65 -0
  261. package/modules/mail/src/doctor/README.md +107 -0
  262. package/modules/mail/src/doctor/common.mjs +64 -0
  263. package/modules/mail/src/doctor/dns.mjs +102 -0
  264. package/modules/mail/src/doctor/index.mjs +28 -0
  265. package/modules/mail/src/doctor/probe.mjs +66 -0
  266. package/modules/mail/src/doctor/receive.mjs +81 -0
  267. package/modules/mail/src/doctor/records.mjs +45 -0
  268. package/modules/mail/src/events/README.md +268 -0
  269. package/modules/mail/src/events/d1-schema.sql +25 -0
  270. package/modules/mail/src/events/d1-storage.mjs +76 -0
  271. package/modules/mail/src/events/index.mjs +3 -0
  272. package/modules/mail/src/events/intake.mjs +201 -0
  273. package/modules/mail/src/events/storage.mjs +52 -0
  274. package/modules/mail/src/events/verify.mjs +92 -0
  275. package/modules/mail/src/inbound/README.md +137 -0
  276. package/modules/mail/src/inbound/bytes.mjs +91 -0
  277. package/modules/mail/src/inbound/headers.mjs +143 -0
  278. package/modules/mail/src/inbound/index.mjs +29 -0
  279. package/modules/mail/src/inbound/mime.mjs +36 -0
  280. package/modules/mail/src/inbound/multipart.mjs +27 -0
  281. package/modules/mail/src/inbound/resend-attachment.mjs +43 -0
  282. package/modules/mail/src/inbound/resend.mjs +54 -0
  283. package/modules/mail/src/inbound/sendgrid.mjs +60 -0
  284. package/modules/mail/src/sender.mjs +33 -0
  285. package/modules/mail/src/sendgrid-email/index.d.mts +33 -0
  286. package/modules/mail/src/sendgrid-email/index.mjs +86 -0
  287. package/modules/mail/src/unsubscribe/index.mjs +142 -0
  288. package/modules/operator-auth/README.md +599 -0
  289. package/modules/operator-auth/accounts/adapter.mjs +41 -0
  290. package/modules/operator-auth/accounts/admin.mjs +159 -0
  291. package/modules/operator-auth/accounts/credentials.mjs +27 -0
  292. package/modules/operator-auth/accounts/editor-owner.mjs +13 -0
  293. package/modules/operator-auth/accounts/index.d.mts +9 -0
  294. package/modules/operator-auth/accounts/index.mjs +9 -0
  295. package/modules/operator-auth/accounts/native.d.mts +38 -0
  296. package/modules/operator-auth/accounts/native.mjs +171 -0
  297. package/modules/operator-auth/accounts/oa.mjs +90 -0
  298. package/modules/operator-auth/accounts/provider-control.mjs +50 -0
  299. package/modules/operator-auth/accounts/provider-pin.mjs +14 -0
  300. package/modules/operator-auth/accounts/roles.mjs +26 -0
  301. package/modules/operator-auth/accounts/schema/dependency-setup.sql +17 -0
  302. package/modules/operator-auth/accounts/schema/dev-sessions.sql +22 -0
  303. package/modules/operator-auth/accounts/schema/domain-rules-step-up.sql +20 -0
  304. package/modules/operator-auth/accounts/schema/invitation-cancellation.sql +17 -0
  305. package/modules/operator-auth/accounts/schema/operator-auth.sql +142 -0
  306. package/modules/operator-auth/accounts/schema/provider-control.sql +30 -0
  307. package/modules/operator-auth/accounts/schema/provider-pins.sql +6 -0
  308. package/modules/operator-auth/accounts/settings-page.mjs +4 -0
  309. package/modules/operator-auth/accounts/store.mjs +246 -0
  310. package/modules/operator-auth/branding.mjs +66 -0
  311. package/modules/operator-auth/config.mjs +35 -0
  312. package/modules/operator-auth/conformance/README.md +81 -0
  313. package/modules/operator-auth/conformance/index.d.mts +43 -0
  314. package/modules/operator-auth/conformance/index.mjs +300 -0
  315. package/modules/operator-auth/conformance/presentation.mjs +57 -0
  316. package/modules/operator-auth/crypto.mjs +17 -0
  317. package/modules/operator-auth/dev/badge.mjs +62 -0
  318. package/modules/operator-auth/dev/index.d.mts +14 -0
  319. package/modules/operator-auth/dev/index.mjs +137 -0
  320. package/modules/operator-auth/dev/personas.mjs +17 -0
  321. package/modules/operator-auth/dev/sign-in-as.d.mts +3 -0
  322. package/modules/operator-auth/dev/sign-in-as.mjs +25 -0
  323. package/modules/operator-auth/dev-admission.d.mts +4 -0
  324. package/modules/operator-auth/dev-admission.mjs +10 -0
  325. package/modules/operator-auth/dev-gate.mjs +86 -0
  326. package/modules/operator-auth/docs/README.md +78 -0
  327. package/modules/operator-auth/docs/native-accounts.md +313 -0
  328. package/modules/operator-auth/docs/tanstack-start.md +218 -0
  329. package/modules/operator-auth/docs/vite-spa.md +144 -0
  330. package/modules/operator-auth/errors.mjs +9 -0
  331. package/modules/operator-auth/http.mjs +42 -0
  332. package/modules/operator-auth/identity/admission.mjs +105 -0
  333. package/modules/operator-auth/identity/after-confirm.mjs +18 -0
  334. package/modules/operator-auth/identity/email-link/confirmation.mjs +14 -0
  335. package/modules/operator-auth/identity/email-link/index.d.mts +48 -0
  336. package/modules/operator-auth/identity/email-link/index.mjs +128 -0
  337. package/modules/operator-auth/identity/email-link/message.mjs +16 -0
  338. package/modules/operator-auth/identity/index.d.mts +7 -0
  339. package/modules/operator-auth/identity/index.mjs +5 -0
  340. package/modules/operator-auth/identity/oidc/README.md +171 -0
  341. package/modules/operator-auth/identity/oidc/client-auth.mjs +16 -0
  342. package/modules/operator-auth/identity/oidc/config.mjs +102 -0
  343. package/modules/operator-auth/identity/oidc/crypto.mjs +29 -0
  344. package/modules/operator-auth/identity/oidc/errors.mjs +5 -0
  345. package/modules/operator-auth/identity/oidc/index.d.mts +33 -0
  346. package/modules/operator-auth/identity/oidc/index.mjs +287 -0
  347. package/modules/operator-auth/identity/oidc/jwt.mjs +102 -0
  348. package/modules/operator-auth/identity/oidc/network.mjs +93 -0
  349. package/modules/operator-auth/identity/oidc/presets.mjs +26 -0
  350. package/modules/operator-auth/identity/oidc/schema/oidc.sql +50 -0
  351. package/modules/operator-auth/identity/oidc/store.mjs +68 -0
  352. package/modules/operator-auth/identity/principal.mjs +28 -0
  353. package/modules/operator-auth/index.d.mts +223 -0
  354. package/modules/operator-auth/index.mjs +11 -0
  355. package/modules/operator-auth/input.mjs +55 -0
  356. package/modules/operator-auth/local-cli.mjs +16 -0
  357. package/modules/operator-auth/page.mjs +34 -0
  358. package/modules/operator-auth/policy.mjs +20 -0
  359. package/modules/operator-auth/routes.mjs +91 -0
  360. package/modules/operator-auth/service.mjs +152 -0
  361. package/modules/operator-auth/signin/index.mjs +67 -0
  362. package/modules/owner-claim/README.md +137 -0
  363. package/modules/owner-claim/idp.mjs +40 -0
  364. package/modules/owner-claim/index.d.mts +27 -0
  365. package/modules/owner-claim/index.mjs +39 -0
  366. package/modules/owner-claim/page.mjs +11 -0
  367. package/modules/owner-claim/schema/idp.sql +4 -0
  368. package/modules/owner-claim/schema/owner-claim.sql +18 -0
  369. package/modules/owner-claim/transaction.mjs +87 -0
  370. package/modules/owner-claim/verify.mjs +80 -0
  371. package/modules/portability/README.md +444 -0
  372. package/modules/portability/bridge.mjs +102 -0
  373. package/modules/portability/catalogue.mjs +118 -0
  374. package/modules/portability/cli-options.mjs +38 -0
  375. package/modules/portability/cli.mjs +56 -0
  376. package/modules/portability/copies.mjs +68 -0
  377. package/modules/portability/dev-data.mjs +32 -0
  378. package/modules/portability/diff.mjs +33 -0
  379. package/modules/portability/export.mjs +129 -0
  380. package/modules/portability/files.mjs +65 -0
  381. package/modules/portability/format.mjs +122 -0
  382. package/modules/portability/generated.mjs +60 -0
  383. package/modules/portability/hash.mjs +79 -0
  384. package/modules/portability/http.mjs +42 -0
  385. package/modules/portability/import.mjs +185 -0
  386. package/modules/portability/index.d.mts +58 -0
  387. package/modules/portability/index.mjs +22 -0
  388. package/modules/portability/journal.mjs +49 -0
  389. package/modules/portability/legacy-files.mjs +43 -0
  390. package/modules/portability/legacy-safety.mjs +27 -0
  391. package/modules/portability/lines.mjs +36 -0
  392. package/modules/portability/migration-history.mjs +18 -0
  393. package/modules/portability/migration-statements.mjs +23 -0
  394. package/modules/portability/payloads.mjs +52 -0
  395. package/modules/portability/provider-data.mjs +25 -0
  396. package/modules/portability/restore-safety.mjs +30 -0
  397. package/modules/portability/schema/portability.sql +25 -0
  398. package/modules/portability/storage.mjs +49 -0
  399. package/modules/release/README.md +212 -0
  400. package/modules/release/catalogue.mjs +79 -0
  401. package/modules/release/export.mjs +51 -0
  402. package/modules/release/produce.mjs +136 -0
  403. package/modules/release/public-child-transport-state.cjs +29 -0
  404. package/modules/release/public-child.mjs +71 -0
  405. package/modules/release/public-git.mjs +21 -0
  406. package/modules/release/publication-scan.mjs +22 -0
  407. package/modules/release/publish-handoff.mjs +37 -0
  408. package/modules/release/source.mjs +71 -0
  409. package/modules/release/test-summary.mjs +50 -0
  410. package/onboarding/README.md +163 -0
  411. package/onboarding/activity.mjs +31 -0
  412. package/onboarding/adapter-auth.mjs +88 -0
  413. package/onboarding/adapter-hosting.mjs +35 -0
  414. package/onboarding/adapter-labels.mjs +13 -0
  415. package/onboarding/adapter-settings.mjs +129 -0
  416. package/onboarding/adapter.mjs +238 -0
  417. package/onboarding/agent-handoff.mjs +9 -0
  418. package/onboarding/app-processes.mjs +21 -0
  419. package/onboarding/archive-output.d.mts +3 -0
  420. package/onboarding/archive-output.mjs +54 -0
  421. package/onboarding/command-custody.mjs +24 -0
  422. package/onboarding/command-recovery.mjs +8 -0
  423. package/onboarding/commands.mjs +166 -0
  424. package/onboarding/dependency-approval.mjs +36 -0
  425. package/onboarding/dev-identity.mjs +23 -0
  426. package/onboarding/email.mjs +24 -0
  427. package/onboarding/failures.mjs +42 -0
  428. package/onboarding/input-limits.mjs +7 -0
  429. package/onboarding/installer-inputs.mjs +24 -0
  430. package/onboarding/launcher.mjs +34 -0
  431. package/onboarding/local/build-files.mjs +64 -0
  432. package/onboarding/local/build.mjs +49 -0
  433. package/onboarding/local/environment.mjs +30 -0
  434. package/onboarding/local/files.mjs +35 -0
  435. package/onboarding/local/operation.mjs +166 -0
  436. package/onboarding/local/owner.mjs +34 -0
  437. package/onboarding/local/process-table.mjs +114 -0
  438. package/onboarding/local/recovery.mjs +79 -0
  439. package/onboarding/local/state.mjs +31 -0
  440. package/onboarding/metadata.mjs +7 -0
  441. package/onboarding/operator-install.mjs +45 -0
  442. package/onboarding/operator-installer.mjs +39 -0
  443. package/onboarding/operator-prerequisites.mjs +27 -0
  444. package/onboarding/package.json +6 -0
  445. package/onboarding/prefill.mjs +16 -0
  446. package/onboarding/private-files.mjs +97 -0
  447. package/onboarding/private.mjs +35 -0
  448. package/onboarding/process-cleanup.mjs +134 -0
  449. package/onboarding/process-diagnostics.mjs +91 -0
  450. package/onboarding/process-scope.mjs +118 -0
  451. package/onboarding/process-table.mjs +118 -0
  452. package/onboarding/process-tree.mjs +36 -0
  453. package/onboarding/production-modules.mjs +22 -0
  454. package/onboarding/production-options.mjs +40 -0
  455. package/onboarding/production-plan.mjs +8 -0
  456. package/onboarding/production-runtime.mjs +30 -0
  457. package/onboarding/project-vite.mjs +14 -0
  458. package/onboarding/providers.mjs +289 -0
  459. package/onboarding/queue.mjs +53 -0
  460. package/onboarding/queued-entry.mjs +34 -0
  461. package/onboarding/readiness.mjs +59 -0
  462. package/onboarding/redaction-jwt.mjs +32 -0
  463. package/onboarding/redaction.mjs +298 -0
  464. package/onboarding/schema/SETUP.schema.json +514 -0
  465. package/onboarding/schema/dependencies.mjs +35 -0
  466. package/onboarding/schema/json-schema.mjs +202 -0
  467. package/onboarding/schema/setup-validation.mjs +325 -0
  468. package/onboarding/secrets.mjs +21 -0
  469. package/onboarding/server.mjs +188 -0
  470. package/onboarding/setup-manifest.mjs +116 -0
  471. package/onboarding/state.mjs +46 -0
  472. package/onboarding/theme-files.mjs +37 -0
  473. package/onboarding/theme.mjs +118 -0
  474. package/onboarding/ui/activity.js +98 -0
  475. package/onboarding/ui/address-client.mjs +33 -0
  476. package/onboarding/ui/app.js +377 -0
  477. package/onboarding/ui/index.html +1 -0
  478. package/onboarding/ui/model-core.mjs +127 -0
  479. package/onboarding/ui/model.mjs +5 -0
  480. package/onboarding/ui/style.css +63 -0
  481. package/onboarding/ui/theme.css +37 -0
  482. package/onboarding/ui/workspace-art.js +30 -0
  483. package/onboarding/wrangler-auth.mjs +43 -0
  484. package/operations/README.md +246 -0
  485. package/operations/operations.mjs +168 -0
  486. package/operations/project-operations.mjs +157 -0
  487. package/package.json +11 -4
  488. package/scripts/publish-check/README.md +72 -0
  489. package/scripts/publish-check/checksum_maps.py +52 -0
  490. package/scripts/publish-check/cli.py +34 -0
  491. package/scripts/publish-check/command_arguments.py +51 -0
  492. package/scripts/publish-check/command_shell_quotes.py +41 -0
  493. package/scripts/publish-check/command_source_quotes.py +120 -0
  494. package/scripts/publish-check/content_identities.py +250 -0
  495. package/scripts/publish-check/copy_identities.py +41 -0
  496. package/scripts/publish-check/der.py +61 -0
  497. package/scripts/publish-check/destination.py +117 -0
  498. package/scripts/publish-check/env_values.py +74 -0
  499. package/scripts/publish-check/font_licence.py +23 -0
  500. package/scripts/publish-check/git_history.py +115 -0
  501. package/scripts/publish-check/github_refs.py +217 -0
  502. package/scripts/publish-check/gitleaks.py +72 -0
  503. package/scripts/publish-check/gitleaks.toml +40 -0
  504. package/scripts/publish-check/history_scan.py +176 -0
  505. package/scripts/publish-check/hit_location.py +18 -0
  506. package/scripts/publish-check/hygiene_config.py +42 -0
  507. package/scripts/publish-check/hygiene_text.py +11 -0
  508. package/scripts/publish-check/identity-recipe.mjs +54 -0
  509. package/scripts/publish-check/json_identity.py +79 -0
  510. package/scripts/publish-check/license-exceptions.json +11 -0
  511. package/scripts/publish-check/licenses.py +49 -0
  512. package/scripts/publish-check/policy.py +18 -0
  513. package/scripts/publish-check/project_identity.py +89 -0
  514. package/scripts/publish-check/provenance.py +91 -0
  515. package/scripts/publish-check/provenance_pins.py +33 -0
  516. package/scripts/publish-check/public_base.py +63 -0
  517. package/scripts/publish-check/public_hygiene.py +80 -0
  518. package/scripts/publish-check/publication-config.json +12 -0
  519. package/scripts/publish-check/publication_config.py +34 -0
  520. package/scripts/publish-check/report.py +52 -0
  521. package/scripts/publish-check/repository_commands.py +75 -0
  522. package/scripts/publish-check/repository_intent.py +52 -0
  523. package/scripts/publish-check/reviewed.py +41 -0
  524. package/scripts/publish-check/source_hashes.mjs +6 -0
  525. package/scripts/publish-check/tree_scan.py +88 -0
  526. package/scripts/publish-check/trust_bundle.py +87 -0
  527. package/scripts/publish-check.mjs +58 -0
@@ -0,0 +1,127 @@
1
+ export function createModel(seed) {
2
+ const fields = seed.fields;
3
+ const safeKeys = seed.safeKeys || Object.keys(fields).filter(key => fields[key].type !== 'password');
4
+ const product = seed.product;
5
+ const branding = seed.branding || product;
6
+ const features = seed.features || {};
7
+ // Browser editions opt specific safe values into the collapsed answer summary.
8
+ const summaryDefaults = [...new Set((Array.isArray(seed.summaryDefaults) ? seed.summaryDefaults : []).filter(key => safeKeys.includes(key) && fields[key]?.type !== 'password'))];
9
+ function normalizeWebsite(value) {
10
+ const text = typeof value === 'string' ? value.trim() : '';
11
+ if (!text) return '';
12
+ if (/^[a-z][a-z\d+.-]*:/i.test(text) && !/^[\w.-]+:\d+(?:[/?#]|$)/.test(text)) return text;
13
+ return text.startsWith('//') ? 'https:' + text : 'https://' + text;
14
+ }
15
+ function safeDraft(draft) { return Object.fromEntries(safeKeys.filter(key => typeof draft[key] === 'string').map(key => [key, draft[key]])); }
16
+ function initialDraft(state) {
17
+ const draft = { ...safeDraft(seed.initialValues?.(state) || {}), ...safeDraft(state.draft || {}) };
18
+ const accounts = state.known?.providers?.cloudflare?.accounts || [];
19
+ if (features.hosting && !draft.accountId && accounts.length === 1) draft.accountId = accounts[0].id;
20
+ // This explicit edition feature makes the local/no-email starting choices reviewable in setup.
21
+ if (features.localTrialWithoutEmail === true) {
22
+ if (features.hosting && !draft.target && fields.target?.valid?.('local')) draft.target = 'local';
23
+ }
24
+ return normalizeAutomaticDraft(draft);
25
+ }
26
+ function secretReady(key, draft, known = {}) {
27
+ const readiness = known.secretReadiness || {};
28
+ if (readiness.scopes?.[key]) return readiness[key] === true && Object.entries(readiness.scopes[key]).every(([field,value]) => draft[field] === value);
29
+ return readiness[key] === true;
30
+ }
31
+ const hostingKeys = ['target', 'accountId', 'prefix', 'appOrigin', 'apiToken'];
32
+ function hostingModel(draft, known = {}) {
33
+ if (!features.hosting) return { complete: true, accessReady: false };
34
+ const accessReady = Boolean(known.providers?.cloudflare?.authenticated || fields.apiToken.valid(draft.apiToken) || secretReady('apiToken', draft, known));
35
+ const complete = draft.target === 'local' || (draft.target === 'remote' && accessReady && ['accountId', 'prefix', 'appOrigin'].every(key => fields[key].valid(draft[key])));
36
+ return { complete, accessReady };
37
+ }
38
+ function setupModel(draft, known = {}) {
39
+ const keys = [...(seed.requiredKeys?.(draft, known) || Object.keys(fields).filter(key => !fields[key].optional))];
40
+ const connections = [];
41
+ if (features.hosting && draft.target === 'remote') {
42
+ keys.push('accountId', 'prefix', 'appOrigin');
43
+ if (!known.providers?.cloudflare?.authenticated && !fields.apiToken.valid(draft.apiToken) && !secretReady('apiToken', draft, known)) connections.push('cloudflare');
44
+ }
45
+ const missing = keys.filter(key => !fields[key].valid(draft[key]) && !(fields[key].type === 'password' && secretReady(key, draft, known)));
46
+ const complete = keys.filter(key => fields[key].valid(draft[key]) || (fields[key].type === 'password' && secretReady(key, draft, known)));
47
+ return { missing, complete, connections, remaining: missing.length + connections.length, ready: !missing.length && !connections.length };
48
+ }
49
+ function installInput(draft) {
50
+ if (seed.installInput) return seed.installInput(draft);
51
+ return { ...safeDraft(draft), ...Object.fromEntries(Object.keys(fields).filter(key => fields[key].type === 'password' && draft[key]).map(key => [key, draft[key]])) };
52
+ }
53
+ function displayValue(key, value) { return fields[key]?.options?.find(([option]) => option === value)?.[1] || value; }
54
+ function summaryKeys(draft, state = {}) {
55
+ const answered = new Set(Array.isArray(state.answered) ? state.answered : []), sources = state.sources || {};
56
+ return safeKeys.filter(key => {
57
+ const field = fields[key], value = draft[key], source = sources[key];
58
+ if (typeof value !== 'string' || !value.trim() || field?.type === 'password' || typeof field?.valid !== 'function' || !field.valid(value)) return false;
59
+ return answered.has(key) || ['agent', 'browser', 'saved'].includes(source) || summaryDefaults.includes(key);
60
+ });
61
+ }
62
+
63
+ function failureDetails(state = {}) {
64
+ const error = typeof state.error === 'string' ? state.error : '';
65
+ // Commands append their private log path after the captured output. A child
66
+ // can print its own Log: lines, so only the final, anchored line is metadata.
67
+ const diagnostic = error.match(/\nLast output \(up to 40 lines\):\n([\s\S]*)\nLog: ([^\r\n]+)$/);
68
+ const commandOutput = diagnostic?.[1] || '';
69
+ return {
70
+ step: typeof state.step === 'string' && state.step ? state.step : 'the last installation step',
71
+ output: commandOutput === '(no output)' ? '' : commandOutput,
72
+ logPath: diagnostic?.[2] || '',
73
+ };
74
+ }
75
+ function failureNote(failure) {
76
+ const note = failure.output
77
+ ? `Output from ${failure.step} is shown above.`
78
+ : `Installation stopped during ${failure.step}. Review the installation activity above.`;
79
+ return note + (failure.logPath ? ` Installer log: ${failure.logPath}` : '');
80
+ }
81
+
82
+ function mergeAgentDraft(draft, state, appliedRevision = 0, pendingKeys = []) {
83
+ const update = state.lastUpdate;
84
+ if (!Number.isFinite(update?.revision) || update.revision <= appliedRevision) return draft;
85
+ const keys = new Set(Object.entries(state.sources || {}).filter(([, source]) => source === 'agent').map(([key]) => key));
86
+ if (update.source === 'agent' && Array.isArray(update.keys)) for (const key of update.keys) keys.add(key);
87
+ const pending = new Set(pendingKeys), values = safeDraft(state.draft || {}), merged = { ...draft }; let changed = false;
88
+ for (const key of keys) if (!pending.has(key) && Object.hasOwn(values, key) && values[key] !== draft[key]) { merged[key] = values[key]; changed = true; }
89
+ return changed ? merged : draft;
90
+ }
91
+
92
+ function derivePrefix(value) {
93
+ let slug = String(value || '').normalize('NFKD').replace(/[\u0300-\u036f]/g, '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
94
+ if (!slug) return '';
95
+ if (!/^[a-z]/.test(slug) || slug.length < 3) slug = (product.slugPrefix || 'app') + '-' + slug;
96
+ return slug.slice(0, 40).replace(/-+$/g, '');
97
+ }
98
+ function normalizeAutomaticDraft(value) {
99
+ const draft = { ...value };
100
+ if (!features.hosting) return draft;
101
+ draft.prefixMode ||= draft.prefix ? 'custom' : 'automatic';
102
+ draft.addressMode ||= draft.appOrigin ? 'custom' : 'automatic';
103
+ if (draft.prefixMode === 'automatic') draft.prefix = derivePrefix(draft[seed.nameKey]);
104
+ return draft;
105
+ }
106
+ // Navigation is deliberately separate from readiness: only the user advances a step.
107
+ const setupGroups = seed.setupGroups.map(group => ({ ...group, complete: group.complete || (group.kind === 'hosting'
108
+ ? ((draft, known) => (!features.hosting || hostingModel(draft, known).complete))
109
+ : ((draft, known) => !setupModel(draft, known).missing.some(key => group.keys.includes(key)))) }));
110
+ function readySummary(draft) { return seed.readySummary?.(draft) || `${draft[seed.nameKey] || product.name} is ready to be installed.`; }
111
+ function nextIncompleteGroup(draft, known = {}) {
112
+ return setupGroups.find(group => !group.complete(draft, known))?.id || null;
113
+ }
114
+
115
+ // Retain steps the owner actually reached; only unvisited, complete groups drop out.
116
+ // Editing known details is separate from the numbered setup journey.
117
+ function setupProgress(draft, known = {}, { active = null, visited = [], editing = false } = {}) {
118
+ const group = setupGroups.find(group => group.id === active);
119
+ if (!group) return 'Your choices are ready';
120
+ if (editing) return `Editing ${group.title}`;
121
+ const reached = [...new Set([...visited, active])];
122
+ const remaining = setupGroups.filter(group => !reached.includes(group.id) && !group.complete(draft, known));
123
+ return `Step ${reached.indexOf(active) + 1} of ${reached.length + remaining.length}`;
124
+ }
125
+
126
+ return { fields, safeKeys, product, branding, features, summaryDefaults, normalizeWebsite, safeDraft, initialDraft, secretReady, hostingKeys, hostingModel, setupModel, installInput, displayValue, summaryKeys, failureDetails, failureNote, mergeAgentDraft, derivePrefix, normalizeAutomaticDraft, setupGroups, readySummary, nextIncompleteGroup, setupProgress };
127
+ }
@@ -0,0 +1,5 @@
1
+ import * as seed from './seed.mjs';
2
+ import {readSetupManifestBytes,createInstallerModel} from './setup-manifest.mjs';
3
+ const [manifestResponse,schemaResponse,optionsResponse]=await Promise.all([fetch('/rer-setup.json'),fetch('/SETUP.schema.json'),fetch('/model-options.json')]);
4
+ const manifest=readSetupManifestBytes(new Uint8Array(await manifestResponse.arrayBuffer()),new Uint8Array(await schemaResponse.arrayBuffer()));
5
+ export const { fields, safeKeys, product, branding, features, summaryDefaults, normalizeWebsite, safeDraft, initialDraft, secretReady, hostingKeys, hostingModel, setupModel, installInput, displayValue, summaryKeys, failureDetails, failureNote, mergeAgentDraft, derivePrefix, normalizeAutomaticDraft, setupGroups, readySummary, nextIncompleteGroup, setupProgress, fieldVisible, fieldDefinition, groupDefinition, groupKeys, secretScopes, nameKey } = createInstallerModel(manifest,seed,await optionsResponse.json());
@@ -0,0 +1,63 @@
1
+ *{box-sizing:border-box}[hidden]{display:none!important}body{margin:0;color:#173753;font:15px/1.6 Inter,Arial,sans-serif}.scene{min-height:100vh;padding:64px 5vw;background:#164661 url('/ocean.png') center/cover}.layout{max-width:1360px;margin:auto;display:grid;grid-template-columns:minmax(290px,.9fr) minmax(0,1.5fr);column-gap:70px;row-gap:24px;align-items:start}.sidebar{padding:0 28px;color:#f7f8ff;background:transparent;border:0;box-shadow:none}.brand{grid-column:1/-1;font-size:22px;font-weight:700;color:#f7f8ff;margin:0;padding-left:28px}.known-row{padding:7px 0;display:grid;grid-template-columns:1fr auto;gap:2px 15px}.known-label{font-size:12px}.known-value{grid-column:1;font-weight:500;font-size:14px;overflow-wrap:anywhere}.known-source{grid-column:1;font-size:10px;line-height:1.3}.edit{border:0;background:none;color:#dfcaff;font:inherit;cursor:pointer;padding:0;align-self:center;grid-column:2;grid-row:1/4}summary{cursor:pointer}.panel{padding:38px 40px;border-radius:26px;background:rgba(251,252,255,.97);box-shadow:0 18px 64px #001c3b33;min-width:0}.panel h1{font-size:29px;letter-spacing:-.6px;line-height:1.25;margin:0 0 24px}.fields{display:grid;gap:18px}.field{border:1px solid #e0e8f6;border-radius:15px;padding:20px;background:rgba(255,255,255,.5);min-width:0}.field label,.field-title{font-size:15px;font-weight:600;display:block;margin:0 0 7px;color:#153b66}.input{display:block;width:100%;min-width:0;padding:12px 14px;border:1px solid #cdd6e5;border-radius:10px;background:#fff;color:#173753;font:inherit}.input:focus-visible,button:focus-visible,a:focus-visible,summary:focus-visible{outline:3px solid #b796ff;outline-offset:3px}.help{color:#64788e;font-size:13px;line-height:1.6;margin:8px 0 0}.status{color:#57728b;font-size:13px;margin:10px 0}.field .edit{color:#7542d3;display:block;margin-top:12px;font-size:13px}.primary,.secondary{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:12px 24px;border-radius:25px;font:600 14px/1.5 Inter,Arial,sans-serif;cursor:pointer;text-decoration:none}.primary{border:0;background:linear-gradient(120deg,#9255fc,#6537e7);color:white;box-shadow:0 5px 12px #7949de28}.secondary{border:1px solid #d2dcea;background:transparent;color:#224567}.actions{display:flex;justify-content:flex-end;margin-top:26px}.primary:disabled{opacity:.5;cursor:default}.error{padding:14px;background:#fff0ee;border:1px solid #f0c6c0;border-radius:10px;color:#98291b}.logs{white-space:pre-wrap;overflow-wrap:anywhere;max-height:360px;overflow:auto;background:#edf1f8;padding:16px;border-radius:12px;font:12px/1.65 monospace}.known-editor{grid-column:1/-1}.known-editor .input{margin-top:6px}.editor-actions{display:flex;gap:15px;margin-top:10px}.editor-actions button{font:inherit;border:0;background:none;padding:0;color:#dfcaff;cursor:pointer}.known-editor .help{color:#d5dff0}.ready-summary{padding:20px;background:#f1ecfc;border-radius:14px;color:#4f4570;margin:0}.connection-editor .field{margin-top:12px;background:#fff;color:#173753}.connection-actions{display:flex;gap:15px;align-items:center;flex-wrap:wrap}.token-field{margin-top:16px}.connected{color:#d1f2e9}.secret-value{font-size:13px}.badge{font-size:10px;color:#d0bcfa}
2
+ @media(max-width:1000px){.layout{gap:28px;grid-template-columns:minmax(250px,.85fr) minmax(0,1.4fr)}.panel{padding:28px}.sidebar{padding:0 22px}.brand{padding-left:22px}.scene{padding:35px 24px}}
3
+ @media(max-width:700px){.scene{padding:20px 16px;background-attachment:scroll}.layout{display:block}.brand{margin-bottom:24px}.sidebar{margin-bottom:24px;padding-left:0;padding-right:0}.panel{padding:25px 20px}.panel h1{font-size:25px}.field{padding:17px}.primary{width:100%}}
4
+
5
+ .agent-activity.known-group{backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);border:0;border-radius:13px;background:linear-gradient(110deg,rgba(38,60,116,.5),rgba(132,118,143,.5));overflow:hidden;margin-bottom:16px}.known-group-header{display:flex;align-items:center;gap:16px;padding:16px 15px 7px}.known-group-title{font-size:16px;margin:0;font-weight:700;line-height:1.3}.category-icon{width:36px;height:36px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;border-radius:11px;background:linear-gradient(135deg,#aa98ff,#e5d1ff);color:#412199;box-shadow:inset 0 0 8px #ffffff44}.category-icon svg{width:23px;height:23px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.workspace .category-icon{background:linear-gradient(135deg,#a2dbff,#4fa9f5);color:#0070df}.hosting .category-icon,.email .category-icon{background:linear-gradient(135deg,#0ed4b6,#31f2cf);color:#005761}.known-group-body{padding:6px 16px 13px 23px}.known-group .known-row:last-child{padding-bottom:0}#known-summary .known-label{font-size:11px}.known-row{min-width:0}.known-editor{min-width:0}.group-symbols{position:absolute;width:0;height:0;overflow:hidden}.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(max-width:700px){.known-group-header{gap:12px}.known-group-body{padding-left:15px}.known-group-title{font-size:15px}}
6
+
7
+ #fields>.field[data-field]{border:0;border-radius:0;background:transparent;padding:0}#fields{gap:24px}.select-wrap{position:relative}.select-wrap:after{content:"";position:absolute;right:18px;top:50%;width:7px;height:7px;border-right:1.5px solid #64788e;border-bottom:1.5px solid #64788e;transform:translateY(-70%) rotate(45deg);pointer-events:none}.select-wrap select{appearance:none;-webkit-appearance:none;padding-right:44px}
8
+
9
+ .known-value{display:flex;align-items:center;gap:7px;min-width:0}.known-value-text{min-width:0;overflow-wrap:anywhere}.value-icon,.colour-swatch{width:18px;height:18px;flex-shrink:0}.colour-swatch{width:16px;height:16px}.value-icon{fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.colour-swatch{border-radius:4px;box-shadow:inset 0 0 0 1px #ffffff70}
10
+
11
+ .target-choices{border:0;margin:0 0 8px;padding:0;display:flex;gap:8px;flex-wrap:wrap}.target-choices legend{margin-bottom:7px;padding:0}.target-choice{display:flex;align-items:center;gap:6px;padding:8px 10px;border:1px solid #ffffff35;border-radius:8px;font-size:12px;cursor:pointer;position:relative}.target-choice:has(input:checked){background:#ffffff20;border-color:#69efd0}.target-choice input{position:absolute;opacity:0;width:1px;height:1px}.target-choice:has(input:focus-visible){outline:3px solid #b796ff;outline-offset:3px}.target-tick{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border:1px solid #ffffff60;border-radius:50%;color:transparent;font-size:11px;flex-shrink:0}.target-choice input:checked+.target-tick{background:#69efd0;border-color:#69efd0;color:#005761}
12
+
13
+ .panel .target-choices{margin:0}.panel .target-choices legend{color:#153b66;font-size:15px;font-weight:600}.panel .target-choice{color:#173753;border-color:#cdd6e5;font-size:14px}.panel .target-choice:has(input:checked){background:#e9e4ff;border-color:#7542d3}.panel .target-tick{border-color:#8296aa}
14
+
15
+ .colour-control{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.colour-control input[type="color"]{width:52px;height:42px;padding:3px;flex-shrink:0;cursor:pointer}.colour-caption{font-size:14px}.known-editor .colour-control{margin-top:6px}.known-editor .colour-control .input{margin-top:0}
16
+
17
+ .panel label.target-choice{display:flex;align-items:center;gap:10px;padding:10px 12px;margin:0;line-height:1.4;font-weight:500}.panel .target-choices{gap:10px}.target-choice .value-icon{display:block}
18
+
19
+ .hosting-unit{display:grid;gap:18px}.hosting-unit>.field{border:0;border-radius:0;background:transparent;padding:0}.hosting-unit>[data-provider]{border-left:3px solid #ded3f8;padding-left:16px}.hosting-unit .field[data-field]{margin-top:14px}.hosting-unit>.field[data-field]{margin-top:0}.hosting-unit>.status{margin:0}
20
+
21
+ .secondary:disabled{opacity:.5;cursor:default}
22
+
23
+ .email-unit{display:grid;gap:18px}.email-unit>.field,.advanced>.field{border:0;border-radius:0;background:transparent;padding:0}.email-unit>.help{margin:0}.choice-copy{display:block}.choice-copy .help{display:block;margin:5px 0 0;font-weight:400;font-size:12px}.hosting-unit>.target-choices .target-choice{flex:1 1 200px;align-items:flex-start}.hosting-unit>.target-choices .target-tick{margin-top:3px}.hosting-unit>.target-choices .value-icon{margin-top:2px}.connection-row .field-title{font-size:14px}.connection-row>.help{margin-top:0}.connection-row .secondary{min-height:36px;padding:7px 15px;font-size:13px}.advanced{font-size:13px}.advanced summary{color:#64788e}.advanced-toggle{display:flex;align-items:center;gap:8px;margin:15px 0 8px}.advanced .field{margin-top:8px}.panel .advanced>.field>label{font-size:13px}.panel .edit{color:#7542d3}.email-unit .target-choices legend{font-size:15px;font-weight:600;color:#153b66;margin-bottom:7px}
24
+
25
+ .step-progress{font-size:12px;color:#64788e;margin:0 0 8px}.actions{gap:12px}.actions #back{margin-right:auto}.known-group-header .edit{margin-left:auto;font-size:12px}.known-group-header .known-group-title{flex:1}#heading:focus{outline:none}
26
+
27
+ .agent-activity{min-width:0;padding-bottom:16px;background:rgba(0,0,0,.5)}.agent-activity .known-group-header{padding-left:16px;padding-right:16px;justify-content:space-between;gap:12px;flex-wrap:wrap}.agent-activity .known-group-title{min-width:0}.agent-activity-message{font-size:13px;line-height:1.55;margin:6px 16px 0;color:#f7f8ff;overflow-wrap:anywhere}.agent-activity-history{margin:10px 16px 0;color:#d5e4f3;font-size:11px}.agent-activity-history summary{width:fit-content}.agent-activity-events{padding-left:15px;margin:8px 0 0;line-height:1.5}.agent-activity-events li{padding:3px 0;overflow-wrap:anywhere}
28
+
29
+ .agent-connect{display:block;margin:0 0 0 auto;max-width:100%;padding:7px 12px;border:1px solid #ffffff80;border-radius:8px;background:transparent;color:#fff;font:600 12px/1.5 Inter,Arial,sans-serif;cursor:pointer}.agent-handoff{width:min(540px,calc(100vw - 32px));max-height:calc(100dvh - 32px);padding:26px;border:0;border-radius:20px;background:#fbfcff;color:#173753;box-shadow:0 18px 64px #001c3b55}.agent-handoff::backdrop{background:#001c3b80}.agent-handoff h2{margin:0;font-size:22px;line-height:1.3}.agent-handoff textarea{margin-top:18px;resize:vertical;font:12px/1.6 monospace;min-height:140px}.agent-handoff-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}.agent-handoff .status{min-height:21px}.agent-handoff .primary{width:auto}@media(max-width:700px){.agent-handoff{padding:20px}}
30
+
31
+ .agent-working{display:inline-flex;align-items:center;gap:7px;margin-left:auto;color:#f7f8ff;font-size:12px;line-height:1.5;white-space:nowrap}.agent-working-spinner{width:12px;height:12px;border:1.5px solid #ffffff50;border-top-color:currentColor;border-radius:50%;animation:agent-working-spin .9s linear infinite}@keyframes agent-working-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.agent-working-spinner{animation:none}}
32
+
33
+ textarea.input{resize:vertical;min-height:100px}
34
+
35
+
36
+
37
+ .primary{background:var(--installer-accent,#7542d3);color:var(--installer-accent-text,#fff)}
38
+
39
+ .known-summary{min-width:0;margin-top:16px;color:#173753}
40
+ .known-summary>summary{width:fit-content;max-width:100%;padding:9px 12px;border:1px solid #d2dcea;border-radius:9px;background:#f4f6fb;color:#224567;font-weight:600}
41
+ .known-summary[open]>summary{margin-bottom:12px}
42
+ .known-summary #known{min-width:0}
43
+ .connection-row .help{overflow-wrap:anywhere}
44
+ #stop-installation{margin-top:14px}
45
+ @media(max-width:700px){
46
+ .scene{padding:16px}
47
+ .layout{display:grid;grid-template-columns:minmax(0,1fr);gap:12px}
48
+ .brand{grid-column:1;grid-row:1;margin:0;padding:0}
49
+ .panel{grid-column:1;grid-row:2;padding:20px 18px}
50
+ .panel h1{font-size:24px;margin-bottom:16px}
51
+ .sidebar{grid-column:1;grid-row:3;display:grid;gap:12px;margin:8px 0 0;padding:0}
52
+ #form{padding-bottom:74px}
53
+ .actions{position:fixed;left:0;right:0;bottom:0;z-index:20;justify-content:flex-end;gap:10px;margin:0;padding:12px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid #e0e8f6;background:#fbfcff;box-shadow:0 -8px 24px #001c3b18}
54
+ .actions .primary{width:auto;min-width:0;flex:1}
55
+ .actions .secondary{width:auto;flex:0 0 auto;padding-inline:16px}
56
+ .known-summary>summary{max-width:100%}
57
+ }
58
+
59
+ .target-choice .help{color:#42546b}
60
+
61
+ #known-summary .known-group{border:0;border-radius:13px;background:#f2f5fc;overflow:hidden;margin-bottom:16px}#known-summary .known-group.workspace{background:#eef7fc}#known-summary .known-group.hosting,#known-summary .known-group.email{background:#eaf8f6}#known-summary .known-label,#known-summary .known-source{color:#42546b}#known-summary .known-group-title,#known-summary .known-value{color:#173753}#known-summary .known-group .edit{color:#4d2e87}.help-link{color:#4d2e87;font-weight:600;text-decoration:underline}.failure-log-path{margin:12px 0 0;color:#42546b;font-size:12px;overflow-wrap:anywhere}#retry-installation{margin-top:14px}
62
+
63
+ h1,h2,h3,legend{text-wrap:balance}p,.help,.status,.known-source,.agent-activity-message,.choice-copy{text-wrap:pretty}
@@ -0,0 +1,37 @@
1
+ /* Loaded only for a seed that declares a theme (rer-theme.css); every rule is
2
+ scoped to .rer-themed so an unthemed installer keeps style.css alone. */
3
+ .rer-themed body{color:var(--rer-text);font-family:var(--rer-font-body,Inter,Arial,sans-serif)}
4
+ .rer-themed .scene{background:var(--rer-page)}
5
+ .rer-themed .brand,.rer-themed .panel h1,.rer-themed .agent-handoff h2,.rer-themed .known-group-title{font-family:var(--rer-font-heading,var(--rer-font-body,inherit))}
6
+ .rer-themed .brand,.rer-themed .sidebar{color:var(--rer-text)}
7
+ /* content toggles the mark only when --rer-logo is declared; the background draws it at size. */
8
+ .rer-themed .brand{display:flex;align-items:center;gap:12px}
9
+ .rer-themed .brand::before{content:var(--rer-logo,none);display:block;flex:none;width:36px;height:36px;overflow:hidden;text-indent:200%;white-space:nowrap;background:var(--rer-logo) center/contain no-repeat}
10
+ .rer-themed .panel{background:var(--rer-surface);border-radius:var(--rer-radius,26px);box-shadow:0 1px 2px #0000000d,0 14px 36px #00000014}
11
+ .rer-themed .field label,.rer-themed .field-title,.rer-themed .panel .target-choices legend,.rer-themed .email-unit .target-choices legend{color:var(--rer-text)}
12
+ .rer-themed .input{border-color:var(--rer-border);background:var(--rer-surface);color:var(--rer-text);border-radius:calc(var(--rer-radius,20px) / 2)}
13
+ .rer-themed .input:focus-visible,.rer-themed button:focus-visible,.rer-themed a:focus-visible,.rer-themed summary:focus-visible,.rer-themed .target-choice:has(input:focus-visible){outline-color:var(--rer-focus)}
14
+ .rer-themed .help,.rer-themed .status,.rer-themed .step-progress,.rer-themed .advanced summary,.rer-themed .target-choice .help,.rer-themed .failure-log-path,.rer-themed .agent-activity-history,.rer-themed .known-editor .help{color:var(--rer-muted)}
15
+ .rer-themed .select-wrap:after{border-color:var(--rer-muted)}
16
+ .rer-themed .edit,.rer-themed .field .edit,.rer-themed .panel .edit,.rer-themed .help-link,.rer-themed #known-summary .known-group .edit,.rer-themed .editor-actions button{color:var(--rer-link,var(--rer-text))}
17
+ .rer-themed .primary,.rer-themed .secondary,.rer-themed .agent-connect{font-family:inherit;border-radius:var(--rer-radius,25px)}
18
+ .rer-themed .primary{background:var(--rer-accent,var(--installer-accent,#7542d3));color:var(--rer-accent-text,var(--installer-accent-text,#fff));box-shadow:none}
19
+ .rer-themed .secondary,.rer-themed .agent-connect{border:1px solid var(--rer-border);background:transparent;color:var(--rer-text)}
20
+ .rer-themed .logs,.rer-themed .ready-summary{background:var(--rer-page);color:var(--rer-text);border-radius:calc(var(--rer-radius,24px) / 2)}
21
+ .rer-themed .panel .target-choice{color:var(--rer-text);border-color:var(--rer-border)}
22
+ .rer-themed .panel .target-choice:has(input:checked){background:var(--rer-page);border-color:var(--rer-focus);box-shadow:inset 0 0 0 1px var(--rer-focus)}
23
+ .rer-themed .target-tick,.rer-themed .panel .target-tick{border-color:var(--rer-muted)}
24
+ .rer-themed .target-choice input:checked+.target-tick{background:var(--rer-accent,var(--rer-text));border-color:var(--rer-accent,var(--rer-text));color:var(--rer-accent-text,var(--rer-surface))}
25
+ .rer-themed .hosting-unit>[data-provider]{border-left-color:var(--rer-border)}
26
+ .rer-themed .connection-editor .field{background:var(--rer-surface);color:var(--rer-text)}
27
+ .rer-themed .agent-activity.known-group,.rer-themed .agent-activity,.rer-themed .known-group{background:var(--rer-surface);color:var(--rer-text);backdrop-filter:none;-webkit-backdrop-filter:none;border-radius:var(--rer-radius,13px);box-shadow:0 1px 2px #0000000d}
28
+ .rer-themed .agent-activity-message,.rer-themed .agent-working,.rer-themed .connected,.rer-themed .badge{color:var(--rer-text)}
29
+ .rer-themed .agent-working-spinner{border-color:var(--rer-border);border-top-color:currentColor}
30
+ .rer-themed .category-icon,.rer-themed .workspace .category-icon,.rer-themed .hosting .category-icon,.rer-themed .email .category-icon{background:var(--rer-accent,var(--rer-page));color:var(--rer-accent-text,var(--rer-text));box-shadow:none;border-radius:calc(var(--rer-radius,22px) / 2)}
31
+ .rer-themed .known-summary{color:var(--rer-text)}
32
+ .rer-themed .known-summary>summary{border-color:var(--rer-border);background:var(--rer-page);color:var(--rer-text);border-radius:calc(var(--rer-radius,18px) / 2)}
33
+ .rer-themed #known-summary .known-group,.rer-themed #known-summary .known-group.workspace,.rer-themed #known-summary .known-group.hosting,.rer-themed #known-summary .known-group.email{background:var(--rer-page);box-shadow:none}
34
+ .rer-themed #known-summary .known-label,.rer-themed #known-summary .known-source{color:var(--rer-muted)}
35
+ .rer-themed #known-summary .known-group-title,.rer-themed #known-summary .known-value{color:var(--rer-text)}
36
+ .rer-themed .agent-handoff{background:var(--rer-surface);color:var(--rer-text);border-radius:var(--rer-radius,20px)}
37
+ @media(max-width:700px){.rer-themed .actions{background:var(--rer-surface);border-top-color:var(--rer-border)}}
@@ -0,0 +1,30 @@
1
+
2
+ // Art is requested only when the user commits a changed workspace field.
3
+ export function workspaceArt({ request, read, save, model: {fields} }) {
4
+ const contextKeys = Object.keys(fields).filter(key => fields[key].artwork);
5
+ const activeKeys = draft => contextKeys.filter(key => fields[key].visible?.(draft) !== false);
6
+ const signature = draft => JSON.stringify(activeKeys(draft).map(key => [key, draft[key]]));
7
+ let dirty = false, attached = false, lastRequested = '', committing = Promise.resolve();
8
+ return {
9
+ update(state) { attached = state.agent?.attached === true; },
10
+ edited(key) { if (contextKeys.includes(key)) dirty = true; },
11
+ commit() {
12
+ committing = committing.catch(() => {}).then(async () => {
13
+ if (!dirty) return;
14
+ const draft = read(), current = signature(draft);
15
+ await save();
16
+ if (signature(read()) !== current) return;
17
+ if (!attached) return;
18
+ if (!activeKeys(draft).every(key => {
19
+ const definition = fields[key].definition?.(draft) ?? fields[key];
20
+ return (definition.optional && !draft[key]) || definition.valid(draft[key]);
21
+ })) return;
22
+ if (current === lastRequested) { dirty = false; return; }
23
+ await request('/api/workspace-art', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
24
+ lastRequested = current;
25
+ if (signature(read()) === current) dirty = false;
26
+ });
27
+ return committing;
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,43 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ export function assertProductionCloudflare(env) {
6
+ for(const name of ['WRANGLER_API_ENVIRONMENT','CLOUDFLARE_API_ENVIRONMENT'])if(env[name]&&env[name]!=='production')throw Error('The selected Cloudflare environment is not supported by this installer.');
7
+ for(const name of ['CLOUDFLARE_API_BASE_URL','CF_API_BASE_URL'])if(env[name]&&env[name].replace(/\/$/,'')!=='https://api.cloudflare.com/client/v4')throw Error('The selected Cloudflare API address is not supported by this installer.');
8
+ if(env.CLOUDFLARE_COMPLIANCE_REGION)throw Error('The selected Cloudflare environment is not supported by this installer.');
9
+ }
10
+
11
+ /** Wrangler 4.45.4's actual credential-file layout; no login, refresh, or profile switching. */
12
+ export async function legacyWranglerCredentials(version, { env=process.env, home=homedir(), platform=process.platform, now=Date.now() }={}) {
13
+ if (version !== '4.45.4') throw Error('This Wrangler version does not provide a supported credential reader.');
14
+ assertProductionCloudflare(env);
15
+ if (env.WRANGLER_PROFILE) throw Error('The selected Wrangler environment is not supported by the credential reader.');
16
+ const legacy=join(home,'.wrangler');
17
+ let directory;
18
+ try { if((await stat(legacy)).isDirectory())directory=legacy; } catch(error) { if(error.code!=='ENOENT')throw error; }
19
+ if(!directory){
20
+ const base=env.XDG_CONFIG_HOME || (platform==='darwin'?join(home,'Library','Preferences'):platform==='win32'?join(env.APPDATA||join(home,'AppData','Roaming'),'xdg.config'):join(home,'.config'));
21
+ directory=join(base,'.wrangler');
22
+ }
23
+ const text=await readFile(join(directory,'config','default.toml'),'utf8');
24
+ if(text.length>65536)throw Error('Wrangler credential file is too large.');
25
+ // Wrangler emits simple quoted TOML scalar values. Reject other encodings instead of guessing.
26
+ const scalar=key=>{
27
+ const matches=[...text.matchAll(new RegExp('^'+key+'\\s*=\\s*("[^"\\r\\n]*"|\'[^\'\\r\\n]*\')\\s*(?:#.*)?$','gm'))];
28
+ if(matches.length!==1)return undefined;
29
+ const value=matches[0][1];return value[0]==='"'?JSON.parse(value):value.slice(1,-1);
30
+ };
31
+ const token=scalar('oauth_token'),expires=Date.parse(scalar('expiration_time'));
32
+ if(typeof token!=='string'||!token||/[\r\n]/.test(token)||!Number.isFinite(expires)||expires<=now)throw Error('Wrangler credentials are missing or expired.');
33
+ return {type:'oauth',token};
34
+ }
35
+ export async function wranglerCredentials(root, env, run) {
36
+ assertProductionCloudflare(env);
37
+ const options={cwd:root,env:{...env,CI:'true',WRANGLER_SEND_METRICS:'false'}};
38
+ try { return JSON.parse(await run('wrangler',['auth','token','--json'],options)); }
39
+ catch {
40
+ const version=(await run('wrangler',['--version'],options)).trim();
41
+ return legacyWranglerCredentials(version,{env});
42
+ }
43
+ }
@@ -0,0 +1,246 @@
1
+ # Operations manifests and command inspection
2
+
3
+ First-party seeds expose inspection through their portable RER command. From the
4
+ seed root:
5
+
6
+ ```sh
7
+ rer describe --json
8
+ rer check --profile first-party --json
9
+ ```
10
+
11
+ `describe` returns the command contract: profile, declared Node and pnpm pins,
12
+ exposed verbs and supported flags, effects, matching package aliases, and local
13
+ state/settings locations. It reads `OPERATIONS.json` and the declared command
14
+ adapter; it does not return the operations manifest itself or test environment
15
+ values.
16
+
17
+ `check` validates declared command input files and required enabled loops.
18
+ The first-party profile also enforces the manifest's `seedContract` marker,
19
+ adapter hooks and flags, command targets, package aliases, tool pins, complete
20
+ portable source inventory and copied source hashes. An explicit
21
+ `--profile first-party` rejects a missing marker. With `--json`, it emits a
22
+ result event containing `ok`, `exitCode` and individual clauses on stdout;
23
+ without it, failed clauses are printed for the owner. Exit 0 means the structural
24
+ checks passed; failures exit nonzero. Read the seed's `OPERATIONS.md` to resolve
25
+ manifest or source problems.
26
+
27
+ These commands require Node but no installed packages. They do not run setup,
28
+ deployment, verification, configuration validators, environment readiness checks
29
+ or network requests. Structural success does not establish installed tool
30
+ versions, configured local inputs, provider access, remote health or product
31
+ acceptance. `rer doctor --json` separately diagnoses installed
32
+ tools and local inputs through the manifest inspector.
33
+
34
+ ## Internal manifest tooling
35
+
36
+ The shared `operations.mjs` and `project-operations.mjs` modules implement
37
+ `readOperations`, `describeOperations` and `inspectOperations` for RER and other
38
+ local consumers. They ship together under the portable source tree. Manifest
39
+ reading validates fields, referenced documents and configuration modules, and
40
+ resolves declared command inputs. `describeOperations` returns the operations
41
+ manifest after checking command availability; it is distinct from RER's public
42
+ command descriptor.
43
+ Run directly in a project that has `scripts/rer.mjs`, `operations.mjs describe`
44
+ and `check` forward to that `scripts/rer.mjs` with `describe` and `check`. In an
45
+ independent project without RER they print the inspector's own JSON and advice,
46
+ naming the script by the path it was run from.
47
+
48
+ `inspectOperations` checks required environment names, selected loop inputs and
49
+ an optional pure `validateConfiguration(env)` module. It reports input names
50
+ and suppresses validator details and values because parser exceptions may contain
51
+ credentials. Consumers can pair the reported input names with
52
+ `environmentSources` and operating documentation to guide setup. Missing inputs
53
+ need configuration before readiness can pass; malformed supplied values are
54
+ reported without exposing them. Inspection never executes the declared
55
+ setup, deployment or verification commands. Generated deployment caches and build
56
+ artifacts, provider identity and permissions, credential validity, delivery,
57
+ deployed health and acceptance remain unchecked.
58
+
59
+ An optional `environmentSources` map explains where declared inputs come from.
60
+ Keys must name declared inputs; values must be short, plain source guidance
61
+ without URLs or credentials. Add safe sources so owners can find inputs without
62
+ putting values in the descriptor.
63
+
64
+ Version 1 manifests require edition identity, `OPERATIONS.md`, `ACCEPTANCE.md`,
65
+ `scripts/operations-config.mjs` and valid package command declarations for setup,
66
+ deploy and verify. The adapter validates local configuration only. Version 2
67
+ supports project-owned commands and documents as described below.
68
+
69
+ Run `node --test operations/*.test.mjs` in Base. Composition copies the shared
70
+ modules from its pinned Base commit. Configuration adapters stay project-owned;
71
+ these modules do not create a shared deployment engine or change authentication.
72
+
73
+ ## Independent projects (version 2)
74
+
75
+ The manifest inspector is optional tooling, not the RER management admission
76
+ contract.
77
+ Software can keep its own language, framework, package manager, source layout and
78
+ operating procedures. A project choosing this inspector can use `OPERATIONS.json`
79
+ version 2 without `edition.json`, `seed.json`, `package.json`, `pnpm`, or a fixed
80
+ acceptance filename. Copy both `operations.mjs` and `project-operations.mjs` together.
81
+ Version 1 uses the edition-specific requirements listed above.
82
+
83
+ ```json
84
+ {
85
+ "version": 2,
86
+ "project": "publisher/project",
87
+ "runtime": { "requirements": [{ "name": "python", "version": ">=3.11" }] },
88
+ "requiredEnvironment": [],
89
+ "commands": {
90
+ "verify": {
91
+ "argv": ["python3", "tools/verify.py"],
92
+ "inputs": ["tools/verify.py"],
93
+ "effects": "Runs local checks; no remote writes."
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ Command names and argument arrays are project-owned; consumers should invoke
100
+ them directly without an implicit shell. Manifest inspection never invokes them.
101
+ `inputs` lists checkout files required to invoke the command, including its
102
+ script or build manifest. Missing inputs make that
103
+ command unavailable. Absolute paths, traversal and symlinks outside the checkout
104
+ are rejected. Declare accurate effects, including provider writes, migrations
105
+ and destructive actions; a description is not execution authorization.
106
+
107
+ Optional `documentation.document` and `acceptance.document` reference project-owned
108
+ local documents. For a version 2 project, a declared `documentation.document`
109
+ pointer is the setup guidance named by the internal inspector summary; without
110
+ that pointer, it names the project setup documentation generally. If no setup command is declared, the
111
+ summary reports that and directs the owner to the available setup guidance.
112
+ Optional `configuration.module` references a local ES module
113
+ exporting `validateConfiguration(env)`. It must only validate local configuration;
114
+ `inspectOperations` imports and calls it, so inspect untrusted source before
115
+ running a diagnostic that uses it, including RER doctor.
116
+ Without a module, configuration checking covers required environment names only.
117
+ Runtime requirements are descriptive: neither command availability in PATH nor
118
+ installed versions are checked. All command inputs must be declared accurately;
119
+ the inspector does not infer arbitrary language or build-system dependencies.
120
+
121
+ An optional per-input source map can guide setup without putting values in the
122
+ descriptor or diagnostic output:
123
+
124
+ ```json
125
+ {
126
+ "requiredEnvironment": ["RESEND_API_KEY"],
127
+ "environmentSources": {
128
+ "RESEND_API_KEY": "1Password production vault, mail integration item"
129
+ }
130
+ }
131
+ ```
132
+
133
+ For v2, source keys may also name inputs selected by declared mail loops. Source
134
+ text is limited to 8–180 characters and rejects URLs, equals assignments,
135
+ credential labels containing values, and token-like values. Use a document pointer
136
+ such as `OPERATIONS.md` or plain guidance such as `Team vault: production mail item`;
137
+ never paste an environment assignment or credential into this metadata.
138
+ `inspectOperations` still reports local inputs only; remote deployment,
139
+ provider access, and acceptance remain unchecked.
140
+
141
+ Agents can adapt any software and author operating knowledge in its repository.
142
+ Provider targets must separately support and verify the actual declared effects,
143
+ resources, migrations and recovery. This local descriptor does not admit a project
144
+ to hosted execution, provision resources, or prove provider/runtime compatibility.
145
+
146
+ ## Required loops (version 2)
147
+
148
+ A v2 descriptor may add a declarative `loops` array:
149
+
150
+ ```json
151
+ "loops": [
152
+ { "id": "ticket-replies", "type": "mail", "required": true, "enabled": true, "provider": "resend" },
153
+ { "id": "nightly-summary", "type": "worker", "required": false, "enabled": false }
154
+ ]
155
+ ```
156
+
157
+ `inspectOperations` fails for required disabled loops, missing/blank selected
158
+ mail inputs or a conflicting `MAIL_PROVIDER`. SendGrid requires `SENDGRID_API_KEY`; Resend requires
159
+ `RESEND_API_KEY`; Cloudflare Sending requires `CLOUDFLARE_EMAIL_API_TOKEN` and a
160
+ 32-hex `CLOUDFLARE_EMAIL_ACCOUNT_ID`. Other providers' keys cannot satisfy the
161
+ selection. Disabled optional features stay optional. This is a local input check,
162
+ not credential validity, DNS verification, delivery or remote runtime health.
163
+
164
+ A mail loop can instead declare `binding` to follow a runtime-selected provider
165
+ and project-owned environment names. `provider` and `binding` are mutually
166
+ exclusive. For example:
167
+
168
+ ```json
169
+ {
170
+ "id": "sign-in-mail",
171
+ "type": "mail",
172
+ "required": true,
173
+ "enabled": true,
174
+ "binding": {
175
+ "providerEnvironment": "MAIL_PROVIDER",
176
+ "providers": {
177
+ "sendgrid": { "apiKeyEnvironment": "MAIL_API_KEY", "requiredEnvironment": ["MAIL_FROM"] },
178
+ "resend": { "apiKeyEnvironment": "MAIL_API_KEY", "requiredEnvironment": ["MAIL_FROM"] },
179
+ "development": {
180
+ "requiredEnvironment": ["MAIL_FROM"],
181
+ "development": { "modeEnvironment": "ENVIRONMENT", "originEnvironment": "APP_URL" }
182
+ }
183
+ },
184
+ "whenUnset": {
185
+ "provider": "resend",
186
+ "apiKeyEnvironment": "RESEND_API_KEY",
187
+ "requiredEnvironment": ["RESEND_FROM_EMAIL"]
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ Every environment name must match `[A-Z][A-Z0-9_]*`. A nonempty `providers` map
194
+ supports `sendgrid`, `resend`, `cloudflare` and `development` only. Every provider
195
+ entry declares `requiredEnvironment` (an empty array is allowed). Hosted entries
196
+ also require `apiKeyEnvironment`; Cloudflare additionally requires
197
+ `accountIdEnvironment`, checked as 32 hex characters. Those account declarations
198
+ are exclusive to Cloudflare. Only the selected entry's inputs can satisfy its
199
+ readiness check. The inspector checks presence and the declared guard; a project's
200
+ configuration module remains responsible for its native sender and credential
201
+ validation. A required mail loop still fails when foundation-only configuration
202
+ is valid but mail has not been configured.
203
+
204
+ Optional `whenUnset` declares a hosted provider and its inputs with the same
205
+ shape. It applies only if the selector is absent (`undefined`), never for blank,
206
+ unknown or non-string selectors. It cannot select development. Without
207
+ `whenUnset`, an absent selector blocks readiness and names the selector input.
208
+
209
+ Development entries require `development.modeEnvironment` and
210
+ `development.originEnvironment` and cannot declare a credential. The mode must
211
+ be exactly `development`. The origin must be a canonical HTTP(S) loopback origin
212
+ (host exactly `localhost`, `127.0.0.1` or `[::1]`, with optional port and trailing
213
+ slash), without user information, path, query or fragment. Alternate numeric
214
+ hosts and normalization-dependent spellings are rejected. Preview, production
215
+ and remote origins cannot satisfy this guard. No host lookup occurs. This only
216
+ checks a declared development guard; it does not create or send to an outbox.
217
+
218
+ Malformed loop or binding fields, unknown properties and unsupported providers
219
+ are rejected even for disabled loops. Valid optional disabled loops continue to
220
+ pass; required disabled loops continue to block readiness. `environmentSources`
221
+ may name the selector and any input declared by any provider or `whenUnset`.
222
+ Missing-input guidance uses the actual selected names and their declared source;
223
+ Inspector results and summaries never include environment values. Both modules
224
+ ship together; no additional runtime adapter is needed.
225
+
226
+ The [deploy kit](../modules/deploy-kit/README.md) creates new v2 inspector and
227
+ edition-authoring templates without overwriting an existing edition. Both inspector
228
+ modules ship together.
229
+
230
+ ## First-party command profile
231
+
232
+ OPERATIONS v2 may declare:
233
+
234
+ ```json
235
+ "seedContract": {
236
+ "version": 1,
237
+ "profile": "first-party",
238
+ "adapter": "scripts/installer/local.mjs"
239
+ }
240
+ ```
241
+
242
+ The adapter exports `commandAdapter` and `install`. First-party adopters use the
243
+ shared RER commands and contract described above. The manifest inspector retains
244
+ its environment, configuration and loop diagnostics for RER doctor; RER check
245
+ performs structural validation before dependency installation. Independent
246
+ projects retain their own supported argument arrays and stack.