@astrosheep/keiyaku 4.0.0 → 4.0.2

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 (308) hide show
  1. package/README.md +133 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
  12. package/build/src/akuma/abort.d.ts +2 -0
  13. package/build/src/akuma/abort.js +50 -0
  14. package/build/src/akuma/akuma.d.ts +50 -33
  15. package/build/src/akuma/akuma.js +175 -127
  16. package/build/src/akuma/archetype.d.ts +14 -5
  17. package/build/src/akuma/archetype.js +85 -39
  18. package/build/src/akuma/body.d.ts +3 -5
  19. package/build/src/akuma/body.js +490 -183
  20. package/build/src/akuma/coordinate.d.ts +9 -0
  21. package/build/src/akuma/coordinate.js +22 -0
  22. package/build/src/akuma/heart/facts.d.ts +88 -45
  23. package/build/src/akuma/heart/facts.js +19 -8
  24. package/build/src/akuma/heart/index.d.ts +64 -55
  25. package/build/src/akuma/heart/index.js +172 -252
  26. package/build/src/akuma/heart/rows.d.ts +38 -83
  27. package/build/src/akuma/heart/rows.js +117 -155
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +61 -22
  30. package/build/src/akuma/heart/soul.d.ts +8 -0
  31. package/build/src/akuma/heart/soul.js +136 -0
  32. package/build/src/akuma/heart/storage.d.ts +47 -0
  33. package/build/src/akuma/heart/storage.js +224 -0
  34. package/build/src/akuma/heart/tells.d.ts +12 -0
  35. package/build/src/akuma/heart/tells.js +79 -0
  36. package/build/src/akuma/heart/timeline.d.ts +15 -0
  37. package/build/src/akuma/heart/timeline.js +86 -0
  38. package/build/src/akuma/identity.d.ts +2 -2
  39. package/build/src/akuma/identity.js +9 -9
  40. package/build/src/akuma/index.d.ts +10 -3
  41. package/build/src/akuma/index.js +7 -1
  42. package/build/src/akuma/projection.d.ts +176 -0
  43. package/build/src/akuma/projection.js +256 -0
  44. package/build/src/akuma/provider-recipe.d.ts +24 -0
  45. package/build/src/akuma/provider-recipe.js +100 -0
  46. package/build/src/akuma/provider.d.ts +67 -13
  47. package/build/src/akuma/provider.js +172 -105
  48. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  49. package/build/src/akuma/providers/acp/core.js +159 -0
  50. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  51. package/build/src/akuma/providers/acp/events.js +73 -0
  52. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  53. package/build/src/akuma/providers/acp/index.js +94 -0
  54. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  55. package/build/src/akuma/providers/claude/events.js +238 -0
  56. package/build/src/akuma/providers/claude/index.d.ts +47 -0
  57. package/build/src/akuma/providers/claude/index.js +279 -0
  58. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  59. package/build/src/akuma/providers/claude/input.js +109 -0
  60. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  61. package/build/src/akuma/providers/codex-app-server/events.js +15 -12
  62. package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
  63. package/build/src/akuma/providers/codex-app-server/index.js +77 -33
  64. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  65. package/build/src/akuma/providers/grok-build/index.js +70 -0
  66. package/build/src/akuma/providers/index.d.ts +5 -3
  67. package/build/src/akuma/providers/index.js +35 -56
  68. package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
  69. package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
  70. package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
  71. package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
  72. package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
  73. package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
  74. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  75. package/build/src/akuma/providers/pi/events.js +166 -0
  76. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  77. package/build/src/akuma/providers/pi/index.js +191 -0
  78. package/build/src/akuma/publication.d.ts +3 -3
  79. package/build/src/akuma/publication.js +28 -40
  80. package/build/src/akuma/requests.d.ts +9 -6
  81. package/build/src/akuma/requests.js +95 -65
  82. package/build/src/alias/index.d.ts +4 -3
  83. package/build/src/alias/index.js +12 -13
  84. package/build/src/body/decode.js +7 -1
  85. package/build/src/body/region.d.ts +2 -0
  86. package/build/src/body/region.js +77 -7
  87. package/build/src/body/render.js +2 -1
  88. package/build/src/body/shape.js +7 -1
  89. package/build/src/body/verification.js +19 -4
  90. package/build/src/cli/accepted.d.ts +18 -12
  91. package/build/src/cli/accepted.js +73 -34
  92. package/build/src/cli/actor.js +3 -3
  93. package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
  94. package/build/src/cli/commands/akuma-invoke.js +101 -52
  95. package/build/src/cli/commands/akuma.d.ts +27 -9
  96. package/build/src/cli/commands/akuma.js +151 -80
  97. package/build/src/cli/commands/contract.d.ts +155 -0
  98. package/build/src/cli/commands/contract.js +20 -0
  99. package/build/src/cli/commands/install.js +2 -0
  100. package/build/src/cli/commands/task-invoke.d.ts +19 -4
  101. package/build/src/cli/commands/task-invoke.js +65 -17
  102. package/build/src/cli/commands/task-query.d.ts +5 -0
  103. package/build/src/cli/commands/task-query.js +247 -0
  104. package/build/src/cli/commands/task.d.ts +3 -1
  105. package/build/src/cli/commands/task.js +52 -14
  106. package/build/src/cli/coordinates.d.ts +18 -0
  107. package/build/src/cli/coordinates.js +120 -0
  108. package/build/src/cli/draft.d.ts +8 -0
  109. package/build/src/cli/draft.js +96 -0
  110. package/build/src/cli/invoke.d.ts +9 -3
  111. package/build/src/cli/invoke.js +287 -108
  112. package/build/src/cli/main.js +54 -7
  113. package/build/src/cli/parse.d.ts +21 -117
  114. package/build/src/cli/parse.js +79 -84
  115. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  116. package/build/src/cli/render/akuma-tool-command.js +144 -0
  117. package/build/src/cli/render/akuma-tool.d.ts +4 -2
  118. package/build/src/cli/render/akuma-tool.js +35 -5
  119. package/build/src/cli/render/akuma.d.ts +3 -1
  120. package/build/src/cli/render/akuma.js +247 -212
  121. package/build/src/cli/render/audit.d.ts +3 -0
  122. package/build/src/cli/render/audit.js +104 -0
  123. package/build/src/cli/render/catalog.d.ts +2 -0
  124. package/build/src/cli/render/catalog.js +16 -0
  125. package/build/src/cli/render/contract.d.ts +3 -3
  126. package/build/src/cli/render/contract.js +200 -54
  127. package/build/src/cli/render/kanshi.js +272 -129
  128. package/build/src/cli/render/receipt.d.ts +19 -0
  129. package/build/src/cli/render/receipt.js +106 -0
  130. package/build/src/cli/render/refusal.d.ts +16 -2
  131. package/build/src/cli/render/refusal.js +88 -3
  132. package/build/src/cli/render/region.d.ts +2 -0
  133. package/build/src/cli/render/region.js +17 -0
  134. package/build/src/cli/render/task.d.ts +2 -1
  135. package/build/src/cli/render/task.js +223 -60
  136. package/build/src/cli/render/terminal.d.ts +20 -0
  137. package/build/src/cli/render/terminal.js +121 -0
  138. package/build/src/cli/render/text.js +11 -3
  139. package/build/src/cli/result.d.ts +126 -19
  140. package/build/src/cli/usage.d.ts +1 -0
  141. package/build/src/cli/usage.js +3 -0
  142. package/build/src/contract-worktree.d.ts +44 -0
  143. package/build/src/contract-worktree.js +251 -0
  144. package/build/src/coordination/durable-file.d.ts +5 -1
  145. package/build/src/coordination/durable-file.js +57 -10
  146. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  147. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  148. package/build/src/core/facts/codec.js +23 -4
  149. package/build/src/core/facts/eligibility.d.ts +1 -10
  150. package/build/src/core/facts/eligibility.js +0 -49
  151. package/build/src/core/facts/fold.js +1 -6
  152. package/build/src/core/facts/gate.d.ts +1 -0
  153. package/build/src/core/facts/gate.js +1 -0
  154. package/build/src/core/facts/observation.d.ts +3 -0
  155. package/build/src/core/facts/observation.js +12 -0
  156. package/build/src/core/facts/types.d.ts +10 -3
  157. package/build/src/core/subject.js +2 -2
  158. package/build/src/core/verbs/amend.d.ts +1 -1
  159. package/build/src/core/verbs/amend.js +3 -18
  160. package/build/src/core/verbs/bind.js +2 -16
  161. package/build/src/core/verbs/deliver.d.ts +1 -1
  162. package/build/src/core/verbs/deliver.js +14 -4
  163. package/build/src/core/verbs/placement.d.ts +1 -1
  164. package/build/src/core/verbs/placement.js +7 -9
  165. package/build/src/dispatch/index.d.ts +5 -3
  166. package/build/src/dispatch/index.js +30 -21
  167. package/build/src/duration.d.ts +10 -0
  168. package/build/src/duration.js +22 -0
  169. package/build/src/git/admission.d.ts +2 -2
  170. package/build/src/git/admission.js +33 -23
  171. package/build/src/git/hooks.d.ts +15 -0
  172. package/build/src/git/hooks.js +70 -18
  173. package/build/src/git/identity.d.ts +5 -1
  174. package/build/src/git/identity.js +23 -4
  175. package/build/src/git/integration.d.ts +48 -0
  176. package/build/src/git/integration.js +250 -0
  177. package/build/src/git/observe.d.ts +29 -15
  178. package/build/src/git/observe.js +185 -76
  179. package/build/src/git/read-observation.d.ts +41 -0
  180. package/build/src/git/read-observation.js +361 -0
  181. package/build/src/git/reconcile.d.ts +17 -5
  182. package/build/src/git/reconcile.js +305 -109
  183. package/build/src/git/repository.d.ts +41 -18
  184. package/build/src/git/repository.js +220 -114
  185. package/build/src/git/scratch.d.ts +17 -0
  186. package/build/src/git/scratch.js +73 -0
  187. package/build/src/git/target-placement.d.ts +92 -0
  188. package/build/src/git/target-placement.js +375 -0
  189. package/build/src/git/tender.d.ts +49 -0
  190. package/build/src/git/tender.js +63 -0
  191. package/build/src/git/terminal-seal.d.ts +24 -0
  192. package/build/src/git/terminal-seal.js +89 -0
  193. package/build/src/git/tree.d.ts +2 -2
  194. package/build/src/git/tree.js +4 -0
  195. package/build/src/git/workspace.d.ts +53 -0
  196. package/build/src/git/workspace.js +139 -0
  197. package/build/src/identity/selector.d.ts +6 -0
  198. package/build/src/identity/selector.js +19 -0
  199. package/build/src/index.d.ts +4 -2
  200. package/build/src/index.js +2 -1
  201. package/build/src/kanshi/index.d.ts +2 -2
  202. package/build/src/kanshi/index.js +1 -1
  203. package/build/src/kanshi/read.d.ts +7 -3
  204. package/build/src/kanshi/read.js +245 -45
  205. package/build/src/kanshi/report.d.ts +81 -6
  206. package/build/src/kanshi/select.d.ts +5 -0
  207. package/build/src/kanshi/select.js +33 -1
  208. package/build/src/library/address.d.ts +57 -0
  209. package/build/src/library/address.js +165 -0
  210. package/build/src/library/akuma-creation.d.ts +16 -7
  211. package/build/src/library/akuma-creation.js +96 -22
  212. package/build/src/library/audit.d.ts +18 -0
  213. package/build/src/library/audit.js +44 -0
  214. package/build/src/library/bind.d.ts +21 -0
  215. package/build/src/library/bind.js +56 -0
  216. package/build/src/library/catalog.d.ts +58 -0
  217. package/build/src/library/catalog.js +69 -0
  218. package/build/src/library/configuration.d.ts +6 -15
  219. package/build/src/library/configuration.js +14 -17
  220. package/build/src/library/contract.d.ts +23 -49
  221. package/build/src/library/contract.js +171 -185
  222. package/build/src/library/delivery.d.ts +24 -0
  223. package/build/src/library/delivery.js +21 -0
  224. package/build/src/library/fleet.d.ts +65 -0
  225. package/build/src/library/fleet.js +153 -0
  226. package/build/src/library/input.d.ts +3 -0
  227. package/build/src/library/input.js +19 -0
  228. package/build/src/library/keiyaku.d.ts +18 -3
  229. package/build/src/library/keiyaku.js +12 -1
  230. package/build/src/library/mutation.d.ts +39 -0
  231. package/build/src/library/mutation.js +37 -0
  232. package/build/src/library/reconcile.d.ts +29 -0
  233. package/build/src/library/reconcile.js +179 -0
  234. package/build/src/library/refusal.d.ts +21 -0
  235. package/build/src/library/refusal.js +29 -0
  236. package/build/src/library/region.d.ts +14 -1
  237. package/build/src/library/region.js +18 -4
  238. package/build/src/library/repo.d.ts +4 -13
  239. package/build/src/library/repo.js +14 -24
  240. package/build/src/protocol/attempt.d.ts +16 -3
  241. package/build/src/protocol/attempt.js +41 -10
  242. package/build/src/protocol/bind.d.ts +9 -2
  243. package/build/src/protocol/bind.js +48 -40
  244. package/build/src/protocol/intent.d.ts +57 -20
  245. package/build/src/protocol/intent.js +55 -79
  246. package/build/src/protocol/operations.d.ts +152 -43
  247. package/build/src/protocol/operations.js +482 -166
  248. package/build/src/protocol/outcome.d.ts +14 -3
  249. package/build/src/protocol/outcome.js +11 -3
  250. package/build/src/protocol/placement.d.ts +41 -0
  251. package/build/src/protocol/placement.js +147 -0
  252. package/build/src/protocol/read/documents.d.ts +2 -2
  253. package/build/src/protocol/read/documents.js +4 -4
  254. package/build/src/protocol/read/status.d.ts +18 -5
  255. package/build/src/protocol/read/status.js +73 -13
  256. package/build/src/protocol/run.d.ts +49 -7
  257. package/build/src/protocol/run.js +53 -25
  258. package/build/src/runtime/proc/line-rpc.d.ts +4 -8
  259. package/build/src/runtime/proc/line-rpc.js +22 -28
  260. package/build/src/runtime/proc/run.d.ts +23 -21
  261. package/build/src/runtime/proc/run.js +123 -89
  262. package/build/src/runtime/proc/stdio.d.ts +18 -0
  263. package/build/src/runtime/proc/stdio.js +58 -0
  264. package/build/src/settings.d.ts +7 -1
  265. package/build/src/settings.js +32 -17
  266. package/build/src/settlement/fence.d.ts +5 -0
  267. package/build/src/settlement/fence.js +14 -0
  268. package/build/src/settlement/holder.d.ts +35 -4
  269. package/build/src/settlement/holder.js +127 -28
  270. package/build/src/settlement/settle.d.ts +9 -1
  271. package/build/src/settlement/settle.js +74 -37
  272. package/build/src/task/board.d.ts +23 -5
  273. package/build/src/task/board.js +17 -10
  274. package/build/src/task/compose.d.ts +2 -2
  275. package/build/src/task/compose.js +18 -10
  276. package/build/src/task/context.d.ts +3 -3
  277. package/build/src/task/context.js +15 -20
  278. package/build/src/task/document.d.ts +2 -1
  279. package/build/src/task/document.js +15 -5
  280. package/build/src/task/index.d.ts +27 -15
  281. package/build/src/task/index.js +57 -35
  282. package/build/src/task/operations.d.ts +38 -13
  283. package/build/src/task/operations.js +80 -46
  284. package/build/src/task/query.d.ts +67 -0
  285. package/build/src/task/query.js +279 -0
  286. package/build/src/task/store.d.ts +5 -7
  287. package/build/src/task/store.js +43 -28
  288. package/build/src/verification/declaration.d.ts +1 -0
  289. package/build/src/verification/execution.d.ts +51 -0
  290. package/build/src/verification/execution.js +108 -0
  291. package/build/src/workspace-place.d.ts +41 -0
  292. package/build/src/workspace-place.js +386 -0
  293. package/build/src/world.d.ts +24 -0
  294. package/build/src/world.js +136 -0
  295. package/package.json +8 -4
  296. package/build/src/akuma/activity.d.ts +0 -66
  297. package/build/src/akuma/activity.js +0 -139
  298. package/build/src/akuma/providers/claude.js +0 -305
  299. package/build/src/context-root.d.ts +0 -4
  300. package/build/src/context-root.js +0 -15
  301. package/build/src/git/delivery.d.ts +0 -20
  302. package/build/src/git/delivery.js +0 -109
  303. package/build/src/git/verification.d.ts +0 -14
  304. package/build/src/git/verification.js +0 -56
  305. package/build/src/protocol/read/audit.d.ts +0 -25
  306. package/build/src/protocol/read/audit.js +0 -39
  307. package/build/src/verification/producer.d.ts +0 -23
  308. package/build/src/verification/producer.js +0 -54
@@ -0,0 +1,386 @@
1
+ import { mkdir, readFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { replaceFileDurably } from "./coordination/durable-file.js";
4
+ import { acquireSqliteTransactionLock } from "./coordination/sqlite-transaction-lock.js";
5
+ import { AuthorityCorruptionError } from "./core/facts/errors.js";
6
+ import { contractId } from "./core/facts/types.js";
7
+ import { worktreePath } from "./git/workspace.js";
8
+ export const CONTRACT_PLACES = Object.freeze([
9
+ "atlantis",
10
+ "hogwarts",
11
+ "narnia",
12
+ "neverland",
13
+ "mordor",
14
+ "shire",
15
+ "olympus",
16
+ "valhalla",
17
+ "asgard",
18
+ "hades",
19
+ "camelot",
20
+ "avalon",
21
+ "utopia",
22
+ "azkaban",
23
+ "konoha",
24
+ "namek",
25
+ "laputa",
26
+ "tatooine",
27
+ "stomach",
28
+ "eyeball",
29
+ "braincell",
30
+ "appendix",
31
+ "nostril",
32
+ "armpit",
33
+ "chineseroom",
34
+ "catbox",
35
+ "babel",
36
+ "teapot",
37
+ "blackhole",
38
+ "wormhole",
39
+ "devnull",
40
+ "localhost",
41
+ "recyclebin",
42
+ "bikeshed",
43
+ "serverroom",
44
+ "spawnpoint",
45
+ "bossroom",
46
+ "hiddenlevel",
47
+ "warpzone",
48
+ "styx",
49
+ "limbo",
50
+ "purgatory",
51
+ "penglai",
52
+ "longgong",
53
+ "nantianmen",
54
+ "guimenguan",
55
+ "naiheqiao",
56
+ "backrooms",
57
+ "bermuda",
58
+ "upsidedown",
59
+ "mindpalace",
60
+ "pandorabox",
61
+ "friendzone",
62
+ "comfortzone",
63
+ "echochamber",
64
+ "rabbithole",
65
+ "ivorytower",
66
+ "doghouse",
67
+ "panicroom",
68
+ "shoebox",
69
+ "snowglobe",
70
+ "dollhouse",
71
+ "donuthole",
72
+ "dumpster",
73
+ "blanketfort",
74
+ "kotatsu",
75
+ "fishbowl",
76
+ "pokeball",
77
+ "pineapple",
78
+ "titanic",
79
+ "disneyland",
80
+ "ikea",
81
+ "costco",
82
+ "warppipe",
83
+ "tetris",
84
+ "minecraft",
85
+ "ufo",
86
+ "catbus",
87
+ "timemachine",
88
+ "moonbox",
89
+ "huaguoshan",
90
+ "pansidong",
91
+ "bellybutton",
92
+ "sock",
93
+ "spam",
94
+ "downloads",
95
+ "toilet",
96
+ "blender",
97
+ "toaster",
98
+ "litterbox",
99
+ "kiddiepool",
100
+ "beanbag",
101
+ "vacuum",
102
+ "elevator",
103
+ "glovebox",
104
+ "attic",
105
+ "cloud",
106
+ "wall",
107
+ "can",
108
+ "cup",
109
+ "wc",
110
+ "bean",
111
+ "bus",
112
+ "helicopter",
113
+ "commandroom",
114
+ "box",
115
+ "jar",
116
+ "pot",
117
+ "wok",
118
+ "bowl",
119
+ "bucket",
120
+ "drawer",
121
+ "sofa",
122
+ "fridge",
123
+ "microwave",
124
+ "well",
125
+ "ditch",
126
+ "puddle",
127
+ "tent",
128
+ "cave",
129
+ "shed",
130
+ "garage",
131
+ "basement",
132
+ "balcony",
133
+ "corner",
134
+ "pigpen",
135
+ "henhouse",
136
+ "excavator",
137
+ "tank",
138
+ "submarine",
139
+ "treehouse",
140
+ "igloo",
141
+ "phonebooth",
142
+ "mailbox",
143
+ "doormat",
144
+ "bathtub",
145
+ "wardrobe",
146
+ "quicksand",
147
+ "tarpit",
148
+ "haystack",
149
+ "manhole",
150
+ "chimney",
151
+ "dryer",
152
+ "fittingroom",
153
+ "lazysusan",
154
+ "revolvingdoor",
155
+ "minibar",
156
+ "casino",
157
+ "karaoke",
158
+ "pinball",
159
+ "funhouse",
160
+ "burrito",
161
+ "dumpling",
162
+ "hotpot",
163
+ "bento",
164
+ "teabag",
165
+ "fortunecookie",
166
+ "airlock",
167
+ "escapepod",
168
+ "hammock",
169
+ "legroom",
170
+ "sidequest",
171
+ "lootbox",
172
+ "gutter",
173
+ "pawnshop",
174
+ "hermitcrab",
175
+ "couchgap",
176
+ "dumbwaiter",
177
+ "petridish",
178
+ "baggageclaim",
179
+ "morgue",
180
+ "ballpit",
181
+ "clawmachine",
182
+ ]);
183
+ const PLACE_INDEX = new Map(CONTRACT_PLACES.map((base, index) => [base, index]));
184
+ const PLACE_VERSION = 1;
185
+ const GENERATION_SUFFIX = /^(?:[2-9]|[1-9][0-9]+)$/u;
186
+ function placePaths(repository) {
187
+ return {
188
+ authority: join(repository.commonDirectory, "keiyaku", "places.json"),
189
+ lock: join(repository.commonDirectory, "keiyaku", "locks", "places.sqlite"),
190
+ };
191
+ }
192
+ export function placeRegisterPath(repository) {
193
+ return placePaths(repository).authority;
194
+ }
195
+ function indexedRegister(appointments) {
196
+ return {
197
+ appointments,
198
+ byPlace: new Map(appointments.map((appointment) => [appointment.place, appointment])),
199
+ byContract: new Map(appointments.map((appointment) => [appointment.contract, appointment])),
200
+ };
201
+ }
202
+ function parsedPlace(value) {
203
+ if (PLACE_INDEX.has(value))
204
+ return { base: value, generation: 1n };
205
+ for (let end = value.length - 1; end > 0; end -= 1) {
206
+ const base = value.slice(0, end);
207
+ const suffix = value.slice(end);
208
+ if (PLACE_INDEX.has(base) && GENERATION_SUFFIX.test(suffix)) {
209
+ return { base, generation: BigInt(suffix) };
210
+ }
211
+ }
212
+ return undefined;
213
+ }
214
+ function composePlace(base, generation) {
215
+ return (generation === 1n ? base : `${base}${generation.toString()}`);
216
+ }
217
+ export function place(value) {
218
+ if (parsedPlace(value) === undefined)
219
+ throw new TypeError(`Place is not canonical: ${value}`);
220
+ return value;
221
+ }
222
+ export function nextPlace(current) {
223
+ if (current === undefined)
224
+ return place(CONTRACT_PLACES[0]);
225
+ const parsed = parsedPlace(current);
226
+ if (parsed === undefined)
227
+ throw new TypeError(`Place is not canonical: ${current}`);
228
+ const index = PLACE_INDEX.get(parsed.base);
229
+ return index + 1 < CONTRACT_PLACES.length
230
+ ? composePlace(CONTRACT_PLACES[index + 1], parsed.generation)
231
+ : composePlace(CONTRACT_PLACES[0], parsed.generation + 1n);
232
+ }
233
+ export function firstFreePlace(register) {
234
+ for (let candidate = nextPlace();; candidate = nextPlace(candidate)) {
235
+ if (!register.byPlace.has(candidate))
236
+ return candidate;
237
+ }
238
+ }
239
+ export function canonicalPlaceRegister(register) {
240
+ const appointments = Object.fromEntries(register.appointments
241
+ .slice()
242
+ .sort((left, right) => Buffer.compare(Buffer.from(left.place), Buffer.from(right.place)))
243
+ .map((appointment) => [appointment.place, appointment.contract]));
244
+ return `${JSON.stringify({ version: PLACE_VERSION, appointments })}\n`;
245
+ }
246
+ function placeCorruption(path, message, cause) {
247
+ throw new AuthorityCorruptionError(`${message}: ${path}`, cause === undefined ? {} : { cause });
248
+ }
249
+ export function decodePlaceRegister(path, bytes) {
250
+ let value;
251
+ try {
252
+ if (!bytes.endsWith("\n") || bytes.slice(0, -1).includes("\n")) {
253
+ placeCorruption(path, "Place file is not one canonical JSON line");
254
+ }
255
+ value = JSON.parse(bytes);
256
+ }
257
+ catch (error) {
258
+ if (error instanceof AuthorityCorruptionError)
259
+ throw error;
260
+ return placeCorruption(path, "invalid Place JSON", error);
261
+ }
262
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
263
+ placeCorruption(path, "Place file must be an object");
264
+ }
265
+ const record = value;
266
+ if (Object.keys(record).length !== 2 || !Object.hasOwn(record, "version") || !Object.hasOwn(record, "appointments")) {
267
+ placeCorruption(path, "Place file has invalid fields");
268
+ }
269
+ if (record.version !== PLACE_VERSION)
270
+ placeCorruption(path, `Place file version must be ${PLACE_VERSION}`);
271
+ if (typeof record.appointments !== "object" || record.appointments === null || Array.isArray(record.appointments)) {
272
+ placeCorruption(path, "Place appointments must be an object");
273
+ }
274
+ const appointments = [];
275
+ const contracts = new Set();
276
+ for (const [rawPlace, rawContract] of Object.entries(record.appointments)) {
277
+ if (typeof rawContract !== "string")
278
+ placeCorruption(path, "Place appointment must be a ContractId");
279
+ try {
280
+ const appointed = { place: place(rawPlace), contract: contractId(rawContract) };
281
+ if (contracts.has(appointed.contract))
282
+ placeCorruption(path, "Place file has duplicate Contract appointment");
283
+ contracts.add(appointed.contract);
284
+ appointments.push(appointed);
285
+ }
286
+ catch (error) {
287
+ return placeCorruption(path, "Place appointment is invalid", error);
288
+ }
289
+ }
290
+ appointments.sort((left, right) => Buffer.compare(Buffer.from(left.place), Buffer.from(right.place)));
291
+ const register = indexedRegister(appointments);
292
+ if (canonicalPlaceRegister(register) !== bytes)
293
+ placeCorruption(path, "Place bytes are not canonical");
294
+ return register;
295
+ }
296
+ export function emptyPlaceRegister() {
297
+ return indexedRegister([]);
298
+ }
299
+ export async function readPlaceRegister(repository) {
300
+ const path = placePaths(repository).authority;
301
+ try {
302
+ return decodePlaceRegister(path, await readFile(path, "utf8"));
303
+ }
304
+ catch (error) {
305
+ if (error.code === "ENOENT")
306
+ return emptyPlaceRegister();
307
+ throw error;
308
+ }
309
+ }
310
+ export function appointmentFor(register, contract) {
311
+ return register.byContract.get(contract);
312
+ }
313
+ async function mutatePlaceRegister(repository, mutate) {
314
+ const location = placePaths(repository);
315
+ const held = await acquireSqliteTransactionLock({ path: location.lock, mode: "immediate" });
316
+ try {
317
+ const current = await readPlaceRegister(repository);
318
+ const next = mutate(current);
319
+ const bytes = canonicalPlaceRegister(next);
320
+ try {
321
+ if (await readFile(location.authority, "utf8") === bytes)
322
+ return next;
323
+ }
324
+ catch (error) {
325
+ if (error.code !== "ENOENT")
326
+ throw error;
327
+ }
328
+ await mkdir(dirname(location.authority), { recursive: true });
329
+ await replaceFileDurably(location.authority, bytes);
330
+ return next;
331
+ }
332
+ finally {
333
+ held.close();
334
+ }
335
+ }
336
+ function withAppointments(register, contracts) {
337
+ const additions = [];
338
+ const occupied = new Set(register.byPlace.keys());
339
+ const known = new Set(register.byContract.keys());
340
+ let cursor;
341
+ for (const contract of contracts) {
342
+ if (known.has(contract))
343
+ continue;
344
+ let candidate = cursor === undefined ? nextPlace() : nextPlace(cursor);
345
+ while (occupied.has(candidate))
346
+ candidate = nextPlace(candidate);
347
+ additions.push({ place: candidate, contract });
348
+ occupied.add(candidate);
349
+ known.add(contract);
350
+ cursor = candidate;
351
+ }
352
+ return additions.length === 0 ? register : indexedRegister([...register.appointments, ...additions]);
353
+ }
354
+ export async function appointManagedWorktrees(repository, contracts) {
355
+ return await mutatePlaceRegister(repository, (current) => withAppointments(current, contracts));
356
+ }
357
+ export async function appointManagedWorktree(repository, contract) {
358
+ const appointed = appointmentFor(await appointManagedWorktrees(repository, [contract]), contract);
359
+ if (appointed === undefined)
360
+ throw new Error(`Place appointment was not recorded: ${contract}`);
361
+ return appointed;
362
+ }
363
+ export async function releaseManagedWorktrees(repository, contracts) {
364
+ if (contracts.length === 0)
365
+ return;
366
+ const drop = new Set(contracts);
367
+ await mutatePlaceRegister(repository, (current) => {
368
+ const kept = current.appointments.filter((appointment) => !drop.has(appointment.contract));
369
+ return kept.length === current.appointments.length ? current : indexedRegister(kept);
370
+ });
371
+ }
372
+ export async function releaseManagedWorktree(repository, contract) {
373
+ await releaseManagedWorktrees(repository, [contract]);
374
+ }
375
+ export async function readManagedWorktreeAppointment(repository, contract, register) {
376
+ try {
377
+ const snapshot = register ?? await readPlaceRegister(repository);
378
+ const appointed = appointmentFor(snapshot, contract);
379
+ return appointed === undefined
380
+ ? { kind: "unappointed" }
381
+ : { kind: "appointed", place: appointed.place, path: worktreePath(repository, appointed.place) };
382
+ }
383
+ catch (error) {
384
+ return { kind: "failed", diagnostic: error instanceof Error ? error.message : String(error) };
385
+ }
386
+ }
@@ -0,0 +1,24 @@
1
+ declare const WORLD_BRAND: unique symbol;
2
+ export type WorldRoot = string & {
3
+ readonly [WORLD_BRAND]: true;
4
+ };
5
+ export type WorldResolutionInput = Readonly<{
6
+ cwd: string;
7
+ repositoryRoot?: string;
8
+ }>;
9
+ export type WorldResolution = Readonly<{
10
+ root: WorldRoot | null;
11
+ candidate: WorldRoot | null;
12
+ establish: () => Promise<WorldRoot>;
13
+ }>;
14
+ export declare class WorldError extends Error {
15
+ readonly kind: "invalid-world" | "home-world" | "root-world";
16
+ constructor(kind: "invalid-world" | "home-world" | "root-world", message: string);
17
+ }
18
+ type WorldInput = string | WorldResolutionInput;
19
+ export declare const World: Readonly<{
20
+ resolve(input: WorldInput): Promise<WorldResolution>;
21
+ locate(input: WorldInput): Promise<WorldRoot | null>;
22
+ at(input: string): Promise<WorldRoot>;
23
+ }>;
24
+ export {};
@@ -0,0 +1,136 @@
1
+ import { mkdir, realpath, stat } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join, parse, resolve } from "node:path";
4
+ const WORLD_BRAND = Symbol("keiyaku.world");
5
+ export class WorldError extends Error {
6
+ kind;
7
+ constructor(kind, message) {
8
+ super(message);
9
+ this.name = "WorldError";
10
+ this.kind = kind;
11
+ }
12
+ }
13
+ async function homeRoot() {
14
+ try {
15
+ return await realpath(resolve(homedir()));
16
+ }
17
+ catch {
18
+ return resolve(homedir());
19
+ }
20
+ }
21
+ async function directory(input, label) {
22
+ if (typeof input !== "string" || input.trim().length === 0) {
23
+ throw new TypeError(`${label} must be a nonblank path`);
24
+ }
25
+ const path = resolve(input);
26
+ let real;
27
+ try {
28
+ real = await realpath(path);
29
+ }
30
+ catch (error) {
31
+ throw new WorldError("invalid-world", `world path is not an existing directory: ${path}`);
32
+ }
33
+ try {
34
+ if (!(await stat(real)).isDirectory())
35
+ throw new Error("not a directory");
36
+ }
37
+ catch {
38
+ throw new WorldError("invalid-world", `world path is not a directory: ${real}`);
39
+ }
40
+ return real;
41
+ }
42
+ function brand(path) { return path; }
43
+ function marker(root) { return join(root, ".keiyaku"); }
44
+ async function rejectReservedRoot(root) {
45
+ if (root === await homeRoot()) {
46
+ throw new WorldError("home-world", "the user home directory cannot be a Keiyaku world");
47
+ }
48
+ if (root === parse(root).root) {
49
+ throw new WorldError("root-world", "the filesystem root cannot be a Keiyaku world");
50
+ }
51
+ }
52
+ async function ensureMarker(root) {
53
+ const path = marker(root);
54
+ try {
55
+ if (!(await stat(path)).isDirectory())
56
+ throw new Error("not a directory");
57
+ return;
58
+ }
59
+ catch (error) {
60
+ if (error.code !== "ENOENT") {
61
+ throw new WorldError("invalid-world", `world marker is not a directory: ${path}`);
62
+ }
63
+ }
64
+ await mkdir(path, { recursive: true });
65
+ }
66
+ async function inputValues(input, label) {
67
+ if (typeof input === "string")
68
+ return { cwd: await directory(input, label) };
69
+ if (input === null || typeof input !== "object")
70
+ throw new TypeError(`${label} must be a path or resolution input`);
71
+ const cwd = await directory(input.cwd, `${label} cwd`);
72
+ if (input.repositoryRoot === undefined)
73
+ return { cwd };
74
+ return { cwd, repositoryRoot: await directory(input.repositoryRoot, `${label} repository root`) };
75
+ }
76
+ async function locateMarker(input) {
77
+ let candidate = input;
78
+ const home = await homeRoot();
79
+ for (;;) {
80
+ const filesystemRoot = parse(candidate).root;
81
+ if (candidate !== home && candidate !== filesystemRoot) {
82
+ try {
83
+ if (!(await stat(marker(candidate))).isDirectory()) {
84
+ throw new WorldError("invalid-world", `world marker is not a directory: ${marker(candidate)}`);
85
+ }
86
+ return brand(candidate);
87
+ }
88
+ catch (error) {
89
+ if (error instanceof WorldError)
90
+ throw error;
91
+ if (error.code !== "ENOENT") {
92
+ throw new WorldError("invalid-world", `world marker is not a directory: ${marker(candidate)}`);
93
+ }
94
+ }
95
+ }
96
+ const parent = dirname(candidate);
97
+ if (parent === candidate || candidate === filesystemRoot)
98
+ return null;
99
+ candidate = parent;
100
+ }
101
+ }
102
+ async function exact(input) {
103
+ const root = await directory(input, "world");
104
+ await rejectReservedRoot(root);
105
+ await ensureMarker(root);
106
+ return brand(root);
107
+ }
108
+ async function resolved(input) {
109
+ const values = await inputValues(input, "world location");
110
+ const root = values.repositoryRoot === undefined ? await locateMarker(values.cwd) : brand(values.repositoryRoot);
111
+ const selected = root ?? brand(values.cwd);
112
+ let candidate = selected;
113
+ try {
114
+ await rejectReservedRoot(selected);
115
+ }
116
+ catch (error) {
117
+ if (root !== null || !(error instanceof WorldError))
118
+ throw error;
119
+ candidate = null;
120
+ }
121
+ return Object.freeze({
122
+ root,
123
+ candidate,
124
+ async establish() {
125
+ const established = candidate ?? brand(values.cwd);
126
+ await rejectReservedRoot(established);
127
+ await ensureMarker(established);
128
+ return established;
129
+ },
130
+ });
131
+ }
132
+ export const World = Object.freeze({
133
+ resolve(input) { return resolved(input); },
134
+ async locate(input) { return (await resolved(input)).root; },
135
+ at(input) { return exact(input); },
136
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "files": [
5
5
  "build"
6
6
  ],
@@ -34,10 +34,11 @@
34
34
  "scripts": {
35
35
  "build": "node --input-type=module -e \"import { rmSync } from 'node:fs'; rmSync('build', { recursive: true, force: true })\" && tsc -p tsconfig.json && node scripts/copy-integrations.js && node --input-type=module -e \"import { chmodSync } from 'node:fs'; chmodSync('build/src/cli/index.js', 0o755)\"",
36
36
  "review:model-impact": "node --import tsx scripts/model-change-impact.ts",
37
- "test": "npm run test:architecture && npm run test:maintainability && npm run test:reachability && node --import tsx --test tests/**/*.test.ts tests/maintainability.test.js && npm run test:dogfood",
37
+ "test": "npm run build && npm run test:architecture && npm run test:maintainability && npm run test:reachability && node --import tsx scripts/run-tests.mjs",
38
38
  "test:architecture": "node --import tsx scripts/check-architecture.ts",
39
- "test:dogfood": "npm run build && node --import tsx --test tests/day1-shell-dogfood.dogfood.ts",
39
+ "test:e2e": "npm run build && node --import tsx --test tests/packaged-cli.e2e.ts",
40
40
  "test:maintainability": "node scripts/check-maintainability.js",
41
+ "test:focused": "node --import tsx --test --test-reporter=dot",
41
42
  "test:reachability": "knip --include files,dependencies,unlisted,unresolved,duplicates",
42
43
  "test:typecheck": "tsc -p tsconfig.json --noEmit"
43
44
  },
@@ -50,11 +51,14 @@
50
51
  "typescript": "^5.9.0"
51
52
  },
52
53
  "dependencies": {
54
+ "@agentclientprotocol/sdk": "^1.3.0",
53
55
  "@anthropic-ai/claude-agent-sdk": "^0.3.226",
56
+ "@earendil-works/pi-coding-agent": "0.80.10",
57
+ "@opencode-ai/sdk": "1.18.3",
54
58
  "diff": "^8.0.4",
55
59
  "yaml": "^2.9.0"
56
60
  },
57
- "description": "Keiyaku v4 is a clean implementation of an agent-facing contract workflow.",
61
+ "description": "Keiyaku is an agent-facing contract workflow.",
58
62
  "directories": {
59
63
  "doc": "docs",
60
64
  "test": "tests"
@@ -1,66 +0,0 @@
1
- import { type ToolCall, type ToolResult } from "./provider.js";
2
- import type { ActivityFact, ActivitySlice, TellFact, TurnFact } from "./heart/index.js";
3
- export type ActivityRow = Readonly<{
4
- kind: "said";
5
- sequence: number;
6
- bodySequence: number;
7
- at: string;
8
- text: string;
9
- }> | Readonly<{
10
- kind: "thought";
11
- sequence: number;
12
- bodySequence: number;
13
- at: string;
14
- text: string;
15
- }> | Readonly<{
16
- kind: "tool";
17
- sequence: number;
18
- bodySequence: number;
19
- at: string;
20
- completedAt?: string;
21
- durationMs?: number;
22
- name: string;
23
- call: ToolCall;
24
- state: "running" | ToolResult;
25
- }> | Readonly<{
26
- kind: "note";
27
- sequence: number;
28
- bodySequence: number;
29
- at: string;
30
- text: string;
31
- }>;
32
- export type PendingTell = Readonly<{
33
- id: string;
34
- body: string;
35
- recordedAt: string;
36
- }>;
37
- export type ActivitySnapshot = Readonly<{
38
- rows: readonly ActivityRow[];
39
- pendingTells: readonly PendingTell[];
40
- omitted: number;
41
- lowestRetained: number | null;
42
- highest: number | null;
43
- }>;
44
- export type ActivityHistory = Readonly<{
45
- rows: readonly ActivityRow[];
46
- turns: readonly TurnFact[];
47
- omitted: number;
48
- hasEarlier: boolean;
49
- hasLater: boolean;
50
- historyLost: boolean;
51
- lowestRetained: number | null;
52
- highest: number | null;
53
- }>;
54
- /** Fold the complete retained typed event window before any display budget. */
55
- export declare function foldActivity(facts: readonly ActivityFact[]): readonly ActivityRow[];
56
- /** Apply the one bounded recent selection after folding semantic rows. */
57
- export declare function selectActivitySnapshot(facts: readonly ActivityFact[], input?: Readonly<{
58
- pending?: readonly TellFact[];
59
- lowestRetained?: number | null;
60
- highest?: number | null;
61
- }>): ActivitySnapshot;
62
- /** Project a cursor page; history never applies the recent snapshot pinning rules. */
63
- export declare function projectActivityHistory(slice: ActivitySlice, turns: readonly TurnFact[], input: Readonly<{
64
- since?: boolean;
65
- limit: number;
66
- }>): ActivityHistory;