@astrosheep/keiyaku 4.5.7 → 4.5.9

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 (244) hide show
  1. package/README.md +10 -0
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +12 -11
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +33 -12
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
  12. package/build/src/akuma/abort.d.ts +2 -1
  13. package/build/src/akuma/abort.js +6 -23
  14. package/build/src/akuma/akuma-handle.js +4 -2
  15. package/build/src/akuma/akuma-observe.d.ts +2 -0
  16. package/build/src/akuma/akuma-observe.js +1 -0
  17. package/build/src/akuma/akuma-product.js +9 -7
  18. package/build/src/akuma/akuma.d.ts +392 -9
  19. package/build/src/akuma/akuma.js +31 -1
  20. package/build/src/akuma/allowed.d.ts +1 -1
  21. package/build/src/akuma/allowed.js +1 -0
  22. package/build/src/akuma/archetype.js +1 -1
  23. package/build/src/akuma/body.d.ts +8 -5
  24. package/build/src/akuma/body.js +12 -5
  25. package/build/src/akuma/call-request.d.ts +80 -0
  26. package/build/src/akuma/call-request.js +211 -0
  27. package/build/src/akuma/heart/facts.d.ts +16 -78
  28. package/build/src/akuma/heart/facts.js +11 -0
  29. package/build/src/akuma/heart/index.d.ts +3 -2
  30. package/build/src/akuma/heart/index.js +4 -1
  31. package/build/src/akuma/heart/request-authority.d.ts +5 -4
  32. package/build/src/akuma/heart/request-authority.js +20 -34
  33. package/build/src/akuma/heart/request-rows.js +12 -23
  34. package/build/src/akuma/heart/schema.d.ts +1 -1
  35. package/build/src/akuma/heart/schema.js +5 -13
  36. package/build/src/akuma/index.d.ts +1 -1
  37. package/build/src/akuma/index.js +1 -1
  38. package/build/src/akuma/projection-read.d.ts +1 -0
  39. package/build/src/akuma/projection-read.js +8 -1
  40. package/build/src/akuma/projection.d.ts +907 -137
  41. package/build/src/akuma/projection.js +193 -9
  42. package/build/src/akuma/provider.d.ts +30 -3
  43. package/build/src/akuma/provider.js +111 -0
  44. package/build/src/akuma/providers/acp/core.d.ts +2 -2
  45. package/build/src/akuma/providers/acp/core.js +13 -6
  46. package/build/src/akuma/providers/acp/index.js +5 -4
  47. package/build/src/akuma/providers/claude/events.d.ts +2 -2
  48. package/build/src/akuma/providers/claude/events.js +16 -3
  49. package/build/src/akuma/providers/claude/index.d.ts +3 -3
  50. package/build/src/akuma/providers/claude/index.js +16 -5
  51. package/build/src/akuma/providers/codex-app-server/events.d.ts +2 -2
  52. package/build/src/akuma/providers/codex-app-server/events.js +25 -4
  53. package/build/src/akuma/providers/codex-app-server/index.js +18 -6
  54. package/build/src/akuma/providers/grok-build/index.js +5 -4
  55. package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
  56. package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
  57. package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
  58. package/build/src/akuma/providers/pi/index.js +72 -58
  59. package/build/src/akuma/request-lifecycle.d.ts +4 -10
  60. package/build/src/akuma/request-lifecycle.js +7 -5
  61. package/build/src/akuma/request-rendezvous.d.ts +26 -0
  62. package/build/src/akuma/request-rendezvous.js +100 -0
  63. package/build/src/akuma/request-serve.d.ts +6 -66
  64. package/build/src/akuma/request-serve.js +83 -210
  65. package/build/src/akuma/request-wire.d.ts +109 -115
  66. package/build/src/akuma/request-wire.js +63 -318
  67. package/build/src/akuma/requests.d.ts +19 -47
  68. package/build/src/akuma/requests.js +51 -107
  69. package/build/src/akuma/turn-drive.d.ts +5 -3
  70. package/build/src/akuma/turn-drive.js +39 -11
  71. package/build/src/akuma-body.d.ts +7 -2
  72. package/build/src/akuma-body.js +68 -46
  73. package/build/src/body/amend.js +18 -19
  74. package/build/src/cli/accepted.d.ts +1 -1
  75. package/build/src/cli/accepted.js +2 -2
  76. package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
  77. package/build/src/cli/commands/akuma-invoke.js +17 -9
  78. package/build/src/cli/commands/akuma.js +8 -8
  79. package/build/src/cli/commands/contract-invoke.d.ts +3 -2
  80. package/build/src/cli/commands/contract-invoke.js +42 -30
  81. package/build/src/cli/commands/contract.d.ts +16 -20
  82. package/build/src/cli/commands/contract.js +58 -25
  83. package/build/src/cli/commands/install.d.ts +2 -1
  84. package/build/src/cli/commands/install.js +3 -2
  85. package/build/src/cli/commands/task-invoke.d.ts +3 -0
  86. package/build/src/cli/commands/task-invoke.js +23 -140
  87. package/build/src/cli/commands/task.js +54 -20
  88. package/build/src/cli/invoke.js +39 -25
  89. package/build/src/cli/main.js +2 -1
  90. package/build/src/cli/parse.d.ts +2 -2
  91. package/build/src/cli/parse.js +56 -27
  92. package/build/src/cli/render/akuma-activity.d.ts +3 -0
  93. package/build/src/cli/render/akuma-activity.js +45 -29
  94. package/build/src/cli/render/akuma-tool.d.ts +5 -1
  95. package/build/src/cli/render/akuma.js +4 -8
  96. package/build/src/cli/render/audit.js +1 -1
  97. package/build/src/cli/render/catalog.js +80 -21
  98. package/build/src/cli/render/contract-observation.d.ts +2 -0
  99. package/build/src/cli/render/contract-observation.js +11 -0
  100. package/build/src/cli/render/contract.js +35 -62
  101. package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
  102. package/build/src/cli/render/kanshi-akuma.js +132 -0
  103. package/build/src/cli/render/kanshi.js +131 -213
  104. package/build/src/cli/render/receipt.d.ts +1 -2
  105. package/build/src/cli/render/receipt.js +76 -26
  106. package/build/src/cli/render/refusal.js +2 -10
  107. package/build/src/cli/render/region.js +5 -2
  108. package/build/src/cli/render/settings.d.ts +1 -1
  109. package/build/src/cli/render/settings.js +27 -8
  110. package/build/src/cli/render/task.js +22 -5
  111. package/build/src/cli/render/terminal.d.ts +32 -1
  112. package/build/src/cli/render/terminal.js +77 -1
  113. package/build/src/cli/result.d.ts +3 -3
  114. package/build/src/cli/runtime.js +4 -2
  115. package/build/src/cli/selectors.d.ts +2 -1
  116. package/build/src/cli/selectors.js +4 -3
  117. package/build/src/cli/square-edge.js +120 -36
  118. package/build/src/cli/usage.js +2 -1
  119. package/build/src/contract-guidance.d.ts +5 -0
  120. package/build/src/contract-guidance.js +121 -0
  121. package/build/src/contract-worktree.d.ts +0 -1
  122. package/build/src/contract-worktree.js +32 -83
  123. package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
  124. package/build/src/coordination/sqlite-transaction-lock.js +5 -0
  125. package/build/src/core/facts/codec.d.ts +2 -0
  126. package/build/src/core/facts/codec.js +4 -0
  127. package/build/src/core/verbs/placement.d.ts +6 -1
  128. package/build/src/core/verbs/placement.js +5 -3
  129. package/build/src/dispatch/index.d.ts +0 -2
  130. package/build/src/dispatch/index.js +54 -55
  131. package/build/src/git/admission.js +2 -2
  132. package/build/src/git/hooks.d.ts +9 -15
  133. package/build/src/git/hooks.js +23 -317
  134. package/build/src/git/nuke.d.ts +2 -1
  135. package/build/src/git/nuke.js +39 -21
  136. package/build/src/git/private-state-seat.d.ts +12 -0
  137. package/build/src/git/private-state-seat.js +39 -0
  138. package/build/src/git/process.d.ts +6 -0
  139. package/build/src/git/process.js +26 -11
  140. package/build/src/git/read-observation.js +29 -20
  141. package/build/src/git/reconcile.d.ts +13 -1
  142. package/build/src/git/reconcile.js +70 -11
  143. package/build/src/git/ref-migration.d.ts +22 -0
  144. package/build/src/git/ref-migration.js +55 -0
  145. package/build/src/git/repository.d.ts +10 -6
  146. package/build/src/git/repository.js +16 -8
  147. package/build/src/git/target-placement.d.ts +1 -0
  148. package/build/src/git/target-placement.js +5 -0
  149. package/build/src/git/tender.d.ts +1 -0
  150. package/build/src/git/terminal-reconcile.d.ts +1 -1
  151. package/build/src/git/terminal-reconcile.js +22 -20
  152. package/build/src/git/workspace.d.ts +14 -0
  153. package/build/src/git/workspace.js +44 -0
  154. package/build/src/kanshi/index.d.ts +1 -1
  155. package/build/src/kanshi/read.js +16 -16
  156. package/build/src/kanshi/report.d.ts +2 -2
  157. package/build/src/library/address.d.ts +9 -3
  158. package/build/src/library/address.js +3 -2
  159. package/build/src/library/akuma-creation.d.ts +4 -3
  160. package/build/src/library/akuma-creation.js +19 -13
  161. package/build/src/library/audit.d.ts +14 -6
  162. package/build/src/library/audit.js +13 -23
  163. package/build/src/library/catalog.d.ts +3 -1
  164. package/build/src/library/catalog.js +20 -6
  165. package/build/src/library/composition.d.ts +385 -0
  166. package/build/src/library/composition.js +28 -0
  167. package/build/src/library/configuration.js +8 -2
  168. package/build/src/library/continuation.js +66 -30
  169. package/build/src/library/contract-bind.js +10 -2
  170. package/build/src/library/contract-forwarding-reconciliation-result.d.ts +102 -0
  171. package/build/src/library/contract-forwarding-reconciliation-result.js +92 -0
  172. package/build/src/library/contract-forwarding-result.d.ts +4464 -0
  173. package/build/src/library/contract-forwarding-result.js +521 -0
  174. package/build/src/library/contract-forwarding.d.ts +71 -0
  175. package/build/src/library/contract-forwarding.js +114 -0
  176. package/build/src/library/contract-handle.d.ts +38 -0
  177. package/build/src/library/contract-handle.js +314 -0
  178. package/build/src/library/contract-operations.d.ts +214 -69
  179. package/build/src/library/contract-operations.js +189 -118
  180. package/build/src/library/contract-types.d.ts +7 -3
  181. package/build/src/library/contract.d.ts +21 -34
  182. package/build/src/library/contract.js +29 -287
  183. package/build/src/library/fleet-result.d.ts +1580 -0
  184. package/build/src/library/fleet-result.js +98 -0
  185. package/build/src/library/fleet.d.ts +112 -54
  186. package/build/src/library/fleet.js +211 -71
  187. package/build/src/library/input.d.ts +3 -1
  188. package/build/src/library/input.js +11 -1
  189. package/build/src/library/keiyaku.d.ts +388 -20
  190. package/build/src/library/keiyaku.js +13 -21
  191. package/build/src/library/mutation.d.ts +3 -3
  192. package/build/src/library/mutation.js +5 -9
  193. package/build/src/library/nuke.d.ts +1 -1
  194. package/build/src/library/nuke.js +4 -3
  195. package/build/src/library/reconcile.d.ts +4 -0
  196. package/build/src/library/reconcile.js +2 -0
  197. package/build/src/library/refusal.d.ts +0 -9
  198. package/build/src/library/refusal.js +0 -7
  199. package/build/src/protocol/amend.js +56 -50
  200. package/build/src/protocol/attempt.d.ts +2 -0
  201. package/build/src/protocol/attempt.js +8 -1
  202. package/build/src/protocol/completion.js +7 -0
  203. package/build/src/protocol/deliver.js +6 -2
  204. package/build/src/protocol/operations.d.ts +4 -1
  205. package/build/src/protocol/operations.js +5 -2
  206. package/build/src/protocol/placement.d.ts +1 -0
  207. package/build/src/protocol/placement.js +52 -38
  208. package/build/src/protocol/read/observation.d.ts +1 -4
  209. package/build/src/protocol/read/observation.js +2 -15
  210. package/build/src/protocol/reintegrate.js +62 -58
  211. package/build/src/protocol/review.js +5 -0
  212. package/build/src/protocol/run.js +17 -13
  213. package/build/src/runtime/proc/run.d.ts +9 -0
  214. package/build/src/runtime/proc/run.js +51 -4
  215. package/build/src/runtime/proc/termination.js +26 -22
  216. package/build/src/runtime/proc/windows-launch.exe +0 -0
  217. package/build/src/settlement/holder.d.ts +2 -1
  218. package/build/src/settlement/holder.js +15 -4
  219. package/build/src/settlement/settle.js +99 -33
  220. package/build/src/task/board.d.ts +68 -27
  221. package/build/src/task/board.js +31 -1
  222. package/build/src/task/catalog.d.ts +4 -0
  223. package/build/src/task/catalog.js +23 -0
  224. package/build/src/task/compose-language.js +33 -7
  225. package/build/src/task/compose-parser.d.ts +1 -1
  226. package/build/src/task/compose-parser.js +1 -1
  227. package/build/src/task/compose.js +2 -0
  228. package/build/src/task/index.d.ts +12 -4
  229. package/build/src/task/index.js +97 -16
  230. package/build/src/task/mutation-result.d.ts +923 -0
  231. package/build/src/task/mutation-result.js +140 -0
  232. package/build/src/task/mutation.d.ts +552 -28
  233. package/build/src/task/mutation.js +304 -97
  234. package/build/src/task/operations.d.ts +1 -4
  235. package/build/src/task/operations.js +0 -6
  236. package/build/src/task/public.d.ts +2 -0
  237. package/build/src/task/public.js +1 -0
  238. package/build/src/workspace-place.d.ts +7 -2
  239. package/build/src/workspace-place.js +34 -24
  240. package/build/src/world.d.ts +1 -0
  241. package/build/src/world.js +11 -0
  242. package/package.json +8 -6
  243. package/build/src/akuma/request-execution.d.ts +0 -8
  244. package/build/src/akuma/request-execution.js +0 -98
@@ -1,9 +1,12 @@
1
1
  function overlapBlocks(overlaps) {
2
2
  return overlaps.flatMap((overlap) => {
3
- const count = overlap.patterns.length;
3
+ const patterns = overlap.patterns.filter((pattern) => pattern.mine !== pattern.theirs);
4
+ if (patterns.length === 0)
5
+ return [`overlap ${overlap.contract} exact match`];
6
+ const count = patterns.length;
4
7
  return [
5
8
  `overlap ${overlap.contract} ${count} ${count === 1 ? "pair" : "pairs"}`,
6
- ...overlap.patterns.map((pattern) => ` ${pattern.mine} ~ ${pattern.theirs}`),
9
+ ...patterns.map((pattern) => ` ${pattern.mine} ~ ${pattern.theirs}`),
7
10
  ];
8
11
  });
9
12
  }
@@ -1,3 +1,3 @@
1
1
  import type { Settings } from "../../settings.js";
2
2
  export declare function settingsJsonValue(value: Settings): unknown;
3
- export declare function renderSettingsText(value: Settings): string;
3
+ export declare function renderSettingsText(value: Settings, columns?: number): string;
@@ -1,11 +1,19 @@
1
+ import { displayColumns, renderTextBlock } from "./terminal.js";
1
2
  function namespaceNames(value) {
2
3
  return [
3
4
  ...new Set([value.scopes.user, value.scopes.project].flatMap((scope) => (scope.kind === "read" ? scope.namespaces : []))),
4
5
  ].sort();
5
6
  }
6
- function scope(name, value) {
7
- const path = value.path === undefined ? "" : ` ${value.path}`;
8
- return value.kind === "failed" ? `${name} failed${path} ${value.diagnostic}` : `${name} ${value.kind}${path}`;
7
+ function jsonLines(value, indent) {
8
+ return JSON.stringify(value, null, 2)
9
+ .split("\n")
10
+ .map((line) => `${indent}${line}`);
11
+ }
12
+ function labeledTokens(label, tokens, indent, columns) {
13
+ const inline = [label, ...tokens].filter((part) => part.length > 0).join(" ");
14
+ if (displayColumns(`${indent}${inline}`) <= columns)
15
+ return [`${indent}${inline}`];
16
+ return [...renderTextBlock(label, indent, columns), ...tokens.map((token) => `${indent} ${token}`)];
9
17
  }
10
18
  export function settingsJsonValue(value) {
11
19
  return {
@@ -13,18 +21,29 @@ export function settingsJsonValue(value) {
13
21
  namespaces: namespaceNames(value).map((name) => value.namespace(name)),
14
22
  };
15
23
  }
16
- export function renderSettingsText(value) {
17
- const lines = [scope("user", value.scopes.user), scope("project", value.scopes.project)];
24
+ export function renderSettingsText(value, columns = 80) {
25
+ const lines = [
26
+ "settings",
27
+ ...scopeLines("user", value.scopes.user, columns),
28
+ ...scopeLines("project", value.scopes.project, columns),
29
+ ];
18
30
  for (const name of namespaceNames(value)) {
19
31
  const view = value.namespace(name);
20
- lines.push(`namespace ${name} ${view.kind}`);
32
+ lines.push(...renderTextBlock(`namespace ${name} ${view.kind}`, " ", columns));
21
33
  if (view.kind === "failed") {
22
34
  for (const failure of view.failures)
23
- lines.push(`failure ${failure.scope} ${failure.diagnostic}`);
35
+ lines.push(...renderTextBlock(`failure ${failure.scope} ${failure.diagnostic}`, " ", columns));
24
36
  }
25
37
  for (const entry of view.entries) {
26
- lines.push(`entry ${entry.name} ${entry.source}${entry.shadows ? " shadows user" : ""} ${JSON.stringify(entry.value)}`);
38
+ lines.push(...renderTextBlock(`entry ${entry.name} ${entry.source}${entry.shadows ? " shadows user" : ""}`, " ", columns));
39
+ lines.push(...jsonLines(entry.value, " "));
27
40
  }
28
41
  }
29
42
  return lines.join("\n");
30
43
  }
44
+ function scopeLines(name, value, columns) {
45
+ const tokens = value.path === undefined ? [] : [value.path];
46
+ if (value.kind === "failed")
47
+ tokens.push(value.diagnostic);
48
+ return labeledTokens(`${name} ${value.kind}`, tokens, " ", columns);
49
+ }
@@ -12,10 +12,12 @@ function markFor(word) {
12
12
  return "●";
13
13
  if (word === "ready" || word === "open")
14
14
  return "○";
15
- if (word === "blocked" || word === "missing")
15
+ if (word === "blocked")
16
+ return "‖";
17
+ if (word === "missing")
16
18
  return "!";
17
19
  if (word === "on_hold")
18
- return "·";
20
+ return "⧗";
19
21
  if (word === "done")
20
22
  return "✓";
21
23
  if (word === "drop")
@@ -104,7 +106,7 @@ function compactFacts(item) {
104
106
  return [
105
107
  `updated ${updatedAge(item.updatedAt)}`,
106
108
  ...(item.bodyPresent ? [] : ["no body"]),
107
- ...(item.children === undefined ? [] : [`children ${item.children.live}/${item.children.total} live`]),
109
+ ...(item.children === undefined ? [] : [`children ${item.children.live} live · ${item.children.total} total`]),
108
110
  ].join(" · ");
109
111
  }
110
112
  function listEntity(item, omitDisposition) {
@@ -130,6 +132,8 @@ function shellQuote(value) {
130
132
  function recoveryCommand(command, total) {
131
133
  const parts = ["keiyaku", "task", command.action];
132
134
  if (command.action === "ls") {
135
+ if (command.positionals.length > 0)
136
+ parts.push(command.positionals[0]);
133
137
  if (command.flags.closed === true)
134
138
  parts.push("--closed");
135
139
  if (command.flags.all === true)
@@ -158,8 +162,16 @@ function renderRows(command, result, columns) {
158
162
  ` ${recoveryCommand(command, result.value.total)}`,
159
163
  ]
160
164
  : [];
165
+ const scope = command.action === "ls"
166
+ ? command.flags.world === true
167
+ ? "world"
168
+ : command.positionals.length > 0
169
+ ? `namespace ${command.positionals[0].replace(/^task\//u, "").replace(/\/$/u, "") || "root"}`
170
+ : "current namespace"
171
+ : undefined;
172
+ const heading = scope === undefined ? pageHeading(view, result.value) : `${pageHeading(view, result.value)} · ${scope}`;
161
173
  return [
162
- pageHeading(view, result.value),
174
+ heading,
163
175
  ...result.value.rows.flatMap((item) => renderListRow(item, columns, command.action === "ready")),
164
176
  ...footer,
165
177
  ].join("\n");
@@ -328,7 +340,12 @@ function renderTaskValue(command, result, columns) {
328
340
  }
329
341
  if (command.action === "compose")
330
342
  return renderCompose(result, columns);
331
- if (command.action === "hold" || command.action === "done" || command.action === "drop") {
343
+ if (command.action === "start" ||
344
+ command.action === "hold" ||
345
+ command.action === "done" ||
346
+ command.action === "drop") {
347
+ if (!(typeof result === "object" && result !== null && "items" in result))
348
+ return renderMutation(command, result, columns);
332
349
  return renderBatch(command.action, result);
333
350
  }
334
351
  return renderMutation(command, result, columns);
@@ -23,6 +23,37 @@ export declare function renderBoundedTextBlock(value: string, input: Readonly<{
23
23
  truncated?: boolean;
24
24
  }>): readonly string[];
25
25
  export declare function safeText(value: string): string;
26
+ type CheckoutNotFollowable = Readonly<{
27
+ reason: "staged" | "conflict" | "untracked";
28
+ path: string;
29
+ target: string;
30
+ paths: readonly string[];
31
+ }>;
32
+ export declare function checkoutNotFollowableLines(refusal: CheckoutNotFollowable): readonly string[];
26
33
  export declare function renderTextBlock(value: string, indent: string, columns: number): readonly string[];
27
34
  export declare function renderOpaqueBlock(value: string, indent: string, columns: number): readonly string[];
28
- export declare function tone(value: string, kind: "dim" | "alert", color: boolean): string;
35
+ export type SemanticTone = "dim" | "recent" | "attention" | "alert";
36
+ export declare const RECENT_TONE_MS: number;
37
+ export declare function elapsedMilliseconds(source: string | null | undefined, observedAt: string): number | null;
38
+ export declare function tone(value: string, kind: SemanticTone, color: boolean): string;
39
+ export declare function boundedActivity(value: string, columns: number, prefix: string): string;
40
+ export declare function plumbFacts(facts: readonly string[], columns: number): readonly string[];
41
+ export declare function identityLine(mark: string, identity: string, extra?: string): string;
42
+ export declare function entityLines(entity: Readonly<{
43
+ mark: string;
44
+ identity: string;
45
+ state: string;
46
+ title: string;
47
+ facts: readonly string[];
48
+ context: TextRenderContext;
49
+ }>): readonly string[];
50
+ export declare function renderSectionBlock({ name, unit, selector, continuation, rows, total, neutral, }: Readonly<{
51
+ name: string;
52
+ unit: string;
53
+ selector: string;
54
+ continuation?: string;
55
+ rows: readonly (readonly string[])[];
56
+ total: number;
57
+ neutral?: boolean;
58
+ }>): readonly string[];
59
+ export {};
@@ -118,6 +118,22 @@ export function renderBoundedTextBlock(value, input) {
118
118
  export function safeText(value) {
119
119
  return value.replaceAll(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu, (character) => (/\s/u.test(character) ? " " : "�"));
120
120
  }
121
+ export function checkoutNotFollowableLines(refusal) {
122
+ const lines = [
123
+ "! checkout-not-followable",
124
+ ` checkout: ${safeText(refusal.path)}`,
125
+ ` target: ${safeText(refusal.target)}`,
126
+ ` reason: ${refusal.reason}`,
127
+ ];
128
+ if (refusal.paths.length === 0) {
129
+ lines.push(" paths: (none)");
130
+ }
131
+ else {
132
+ lines.push(" paths:");
133
+ lines.push(...refusal.paths.map((path) => ` - ${JSON.stringify(path)}`));
134
+ }
135
+ return lines;
136
+ }
121
137
  export function renderTextBlock(value, indent, columns) {
122
138
  const words = safeText(value)
123
139
  .trim()
@@ -172,8 +188,68 @@ export function renderOpaqueBlock(value, indent, columns) {
172
188
  }
173
189
  return lines;
174
190
  }
191
+ export const RECENT_TONE_MS = 5 * 60 * 1_000;
192
+ export function elapsedMilliseconds(source, observedAt) {
193
+ if (source === null || source === undefined)
194
+ return null;
195
+ const sourceMs = Date.parse(source);
196
+ const observedMs = Date.parse(observedAt);
197
+ if (!Number.isFinite(sourceMs) || !Number.isFinite(observedMs))
198
+ return null;
199
+ return Math.max(0, observedMs - sourceMs);
200
+ }
175
201
  export function tone(value, kind, color) {
176
202
  if (!color)
177
203
  return value;
178
- return kind === "dim" ? `\u001b[2m${value}\u001b[0m` : `\u001b[31m${value}\u001b[0m`;
204
+ const code = kind === "dim" ? 2 : kind === "recent" ? 32 : kind === "attention" ? 33 : 31;
205
+ return `\u001b[${code}m${value}\u001b[0m`;
206
+ }
207
+ const KANSHI_NARROW_COLUMNS = 72;
208
+ export function boundedActivity(value, columns, prefix) {
209
+ const budget = Math.max(1, columns - displayColumns(prefix));
210
+ return `activity "${truncateDisplayText(value, Math.max(1, budget - displayColumns('activity ""')))}` + `"`;
211
+ }
212
+ export function plumbFacts(facts, columns) {
213
+ const clean = facts.map(safeText).filter((fact) => fact.length > 0);
214
+ if (clean.length === 0)
215
+ return [];
216
+ const lines = [];
217
+ let current = " │ ";
218
+ for (const fact of clean) {
219
+ const candidate = current === " │ " ? ` │ ${fact}` : `${current} · ${fact}`;
220
+ if (current !== " │ " && displayColumns(candidate) > columns) {
221
+ lines.push(current);
222
+ current = ` │ ${fact}`;
223
+ }
224
+ else
225
+ current = candidate;
226
+ }
227
+ lines.push(current);
228
+ return lines;
229
+ }
230
+ export function identityLine(mark, identity, extra = "") {
231
+ return extra.length === 0 ? `${mark} ${safeText(identity)}` : `${mark} ${safeText(identity)} ${safeText(extra)}`;
232
+ }
233
+ export function entityLines(entity) {
234
+ const { mark, identity, state, title, facts, context } = entity;
235
+ if (context.columns > KANSHI_NARROW_COLUMNS) {
236
+ return [identityLine(mark, identity, `· ${state} · ${title}`), ...plumbFacts(facts, context.columns)];
237
+ }
238
+ return [
239
+ `${mark} ${safeText(state)}`,
240
+ ` ${safeText(identity)}`,
241
+ ...(title.length === 0 ? [] : renderTextBlock(safeText(title), " ", context.columns)),
242
+ ...plumbFacts(facts, context.columns),
243
+ ];
244
+ }
245
+ export function renderSectionBlock({ name, unit, selector, continuation, rows, total, neutral = false, }) {
246
+ const lines = [`[ ${name} ] ${total}${neutral ? ` ${unit}` : " live"}`, "", ...rows.flat()];
247
+ if (lines.at(-1) !== "")
248
+ lines.push("");
249
+ lines.push(rows.length === total
250
+ ? ` (all ${total}${neutral ? "" : " live"} ${unit} shown)`
251
+ : ` + ${total - rows.length} more${neutral ? "" : " live"} ${unit} not shown`);
252
+ if (rows.length !== total)
253
+ lines.push(` ${continuation ?? `keiyaku ls ${selector}/`}`);
254
+ return lines;
179
255
  }
@@ -27,14 +27,14 @@ export type AcceptedFact = (AcceptedFactEnvelope & Readonly<{
27
27
  }>["data"];
28
28
  }>);
29
29
  export type Lag = ReconcileReport["lag"][number];
30
- type MutationEnvelope = Pick<MutationResult<unknown>, "head" | "effects" | "settlement">;
30
+ type MutationEnvelope = Pick<MutationResult<unknown>, "head" | "settlementLags" | "recoverySnapshot">;
31
31
  export type AcceptedEnvelope = Readonly<{
32
32
  kind: "accepted";
33
33
  contract: ContractId;
34
34
  head: MutationEnvelope["head"];
35
35
  facts: readonly AcceptedFact[];
36
- effects: MutationEnvelope["effects"];
37
- settlement: MutationEnvelope["settlement"];
36
+ settlementLags: MutationEnvelope["settlementLags"];
37
+ recoverySnapshot?: MutationEnvelope["recoverySnapshot"];
38
38
  lag?: readonly [Lag, ...Lag[]];
39
39
  }>;
40
40
  export type AcceptedBindResult = AcceptedEnvelope & Readonly<{
@@ -11,7 +11,7 @@ export function invocationStart(command) {
11
11
  return "⧖ auditing";
12
12
  if (command.command === "reconcile")
13
13
  return "⧖ reconciling";
14
- return command.command === "install" ? "⧖ installing skills" : undefined;
14
+ return command.command === "install" ? "⧖ installing harness integrations" : undefined;
15
15
  }
16
16
  function writeCliStream(stream, body) {
17
17
  stream.write(body.endsWith("\n") ? body : `${body}\n`);
@@ -106,7 +106,9 @@ async function writeResult(command, result) {
106
106
  if (command.command === "settings") {
107
107
  const { renderSettingsText, settingsJsonValue } = await import("./render/settings.js");
108
108
  const value = result.value;
109
- writeCliStream(process.stdout, command.output === "json" ? JSON.stringify(settingsJsonValue(value)) : renderSettingsText(value));
109
+ writeCliStream(process.stdout, command.output === "json"
110
+ ? JSON.stringify(settingsJsonValue(value))
111
+ : renderSettingsText(value, displayContext().columns));
110
112
  return 0;
111
113
  }
112
114
  if (isAkumaOutput(command, result))
@@ -1,10 +1,11 @@
1
1
  import { Keiyaku, type ContractBoard, type ContractId, type Repo } from "../index.js";
2
+ import { type ExecutionContext } from "../akuma/requests.js";
2
3
  import type { KanshiReport } from "../kanshi/index.js";
3
4
  export type SelectedContract = Readonly<{
4
5
  id: ContractId;
5
6
  contract: Keiyaku;
6
7
  }>;
7
- export declare function contractFromInput(repo: Repo, value: string): SelectedContract;
8
+ export declare function contractFromInput(repo: Repo, value: string, execution?: ExecutionContext): SelectedContract;
8
9
  export declare function resolveContextualContract(board: ContractBoard, selector: string | undefined, scope: string): ContractId;
9
10
  export declare function canonicalContractSelector(selector: string): ContractId;
10
11
  export declare function resolveKanshiContract(report: KanshiReport, selector: string): string;
@@ -1,6 +1,7 @@
1
1
  import { resolve } from "node:path";
2
2
  import { identitySegments } from "../identity/coordinates.js";
3
- import { Keiyaku } from "../index.js";
3
+ import { keiyakuOf } from "../library/contract.js";
4
+ import { localExecutionContext } from "../akuma/requests.js";
4
5
  import { CliUsageError } from "./parse.js";
5
6
  function selectorError(message) {
6
7
  throw new CliUsageError(message);
@@ -12,10 +13,10 @@ function activeManagedCandidates(rows) {
12
13
  return [{ id: contract.id, worktreePath: contract.worktreePath }];
13
14
  });
14
15
  }
15
- export function contractFromInput(repo, value) {
16
+ export function contractFromInput(repo, value, execution = localExecutionContext()) {
16
17
  try {
17
18
  const id = value;
18
- return { id, contract: Keiyaku.of({ repo, id }) };
19
+ return { id, contract: keiyakuOf({ repo, id }, execution) };
19
20
  }
20
21
  catch (error) {
21
22
  selectorError(error instanceof Error ? error.message : String(error));
@@ -1,18 +1,20 @@
1
- import { bindCurrentParticipant, Square, squareAssignedParticipantName, unbindCurrentParticipant, } from "@astrosheep/square";
1
+ import { bindCurrentParticipant, createHostLedgerPort, Square, squareAssignedParticipantName, } from "@astrosheep/square";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
2
4
  import { keiyakuSquarePath } from "../world.js";
3
- async function openKeiyakuSquare(path) {
5
+ async function openKeiyakuSquare(path, environment, hostLedger) {
4
6
  try {
5
- return await Square.at({ path });
7
+ return await Square.at({ path, env: environment, hostLedger });
6
8
  }
7
9
  catch (error) {
8
10
  if (error.code !== "ENOENT" && error.code !== "unavailable")
9
11
  throw error;
10
12
  try {
11
- return await Square.build({ path, markdown: "" });
13
+ return await Square.build({ path, markdown: "", env: environment, hostLedger });
12
14
  }
13
15
  catch (buildError) {
14
16
  try {
15
- return await Square.at({ path });
17
+ return await Square.at({ path, env: environment, hostLedger });
16
18
  }
17
19
  catch {
18
20
  throw buildError;
@@ -20,56 +22,138 @@ async function openKeiyakuSquare(path) {
20
22
  }
21
23
  }
22
24
  }
25
+ function squareInvocationEnvironment(environment, path) {
26
+ const ledgerRoot = environment.SQUARE_REGISTRY === undefined ? undefined : dirname(environment.SQUARE_REGISTRY);
27
+ return {
28
+ ...environment,
29
+ SQUARE_HOST_LEDGER_USER: environment.SQUARE_HOST_LEDGER_USER ?? ledgerRoot ?? join(homedir(), ".square", "host-ledger"),
30
+ SQUARE_HOST_LEDGER_LOCAL: environment.SQUARE_HOST_LEDGER_LOCAL ??
31
+ ledgerRoot ??
32
+ join(environment.PWD ?? dirname(path), ".square", "host-ledger"),
33
+ };
34
+ }
35
+ function invocationHostLedger(environment) {
36
+ return createHostLedgerPort({
37
+ userPath: environment.SQUARE_HOST_LEDGER_USER,
38
+ localPath: environment.SQUARE_HOST_LEDGER_LOCAL,
39
+ });
40
+ }
41
+ async function participantBindings(hostLedger, path, name) {
42
+ return await hostLedger.listPresence({ location: path, participant: name });
43
+ }
44
+ function presenceKey({ location, participant, session, channel }) {
45
+ return JSON.stringify([location, participant, session, channel]);
46
+ }
47
+ function exactPresenceKey({ location, participant, session, channel }) {
48
+ return { location, participant, session, channel };
49
+ }
50
+ async function bestEffort(operation) {
51
+ try {
52
+ await operation();
53
+ }
54
+ catch { }
55
+ }
56
+ async function rollbackSquareEdge(input) {
57
+ const { path, environment, hostLedger, name, allocated, joined, listening, createdBindings } = input;
58
+ if (listening || joined) {
59
+ let square;
60
+ await bestEffort(async () => {
61
+ square = await Square.at({ path, env: environment, hostLedger });
62
+ });
63
+ let participant;
64
+ if (square !== undefined)
65
+ await bestEffort(async () => {
66
+ participant = await square.join(name);
67
+ });
68
+ if (participant !== undefined && listening)
69
+ await bestEffort(async () => participant.ignore(allocated.id));
70
+ if (participant !== undefined && joined)
71
+ await bestEffort(async () => participant.done());
72
+ if (square !== undefined)
73
+ await bestEffort(async () => square.close());
74
+ }
75
+ for (const binding of createdBindings)
76
+ await bestEffort(async () => hostLedger.removePresence(binding));
77
+ }
23
78
  export async function recognizeAndListen(worldRoot, environment, allocated) {
24
- const name = squareAssignedParticipantName(environment);
25
- if (name === undefined)
26
- return;
27
79
  const path = keiyakuSquarePath(worldRoot);
28
- const square = await openKeiyakuSquare(path);
80
+ const squareEnvironment = squareInvocationEnvironment(environment, path);
81
+ let name;
82
+ try {
83
+ const assigned = squareAssignedParticipantName(squareEnvironment);
84
+ if (assigned === undefined)
85
+ return;
86
+ name = assigned;
87
+ }
88
+ catch {
89
+ return;
90
+ }
91
+ const hostLedger = invocationHostLedger(squareEnvironment);
29
92
  let joined = false;
30
- let bound = false;
31
93
  let listening = false;
32
- const rollback = async () => {
33
- if (listening || joined) {
34
- const rollbackSquare = await Square.at({ path });
35
- try {
36
- const rollbackParticipant = await rollbackSquare.join(name);
37
- if (listening)
38
- await rollbackParticipant.ignore(allocated.id);
39
- if (joined)
40
- await rollbackParticipant.done();
41
- }
42
- finally {
43
- await rollbackSquare.close();
44
- }
94
+ let bindingsBeforeCall = [];
95
+ let hasBindingSnapshot = false;
96
+ let createdBindings = [];
97
+ const rememberCreatedBindings = async () => {
98
+ const beforeKeys = new Set(bindingsBeforeCall.map(presenceKey));
99
+ createdBindings = (await participantBindings(hostLedger, path, name))
100
+ .filter((binding) => !beforeKeys.has(presenceKey(binding)))
101
+ .map(exactPresenceKey);
102
+ };
103
+ const refreshCreatedBindings = async () => {
104
+ try {
105
+ await rememberCreatedBindings();
45
106
  }
46
- if (bound)
47
- await unbindCurrentParticipant(path, name, environment);
107
+ catch { }
48
108
  };
109
+ const rollback = async () => await rollbackSquareEdge({
110
+ path,
111
+ environment: squareEnvironment,
112
+ hostLedger,
113
+ name,
114
+ allocated,
115
+ joined,
116
+ listening,
117
+ createdBindings,
118
+ });
119
+ let square;
49
120
  try {
121
+ bindingsBeforeCall = await participantBindings(hostLedger, path, name);
122
+ hasBindingSnapshot = true;
123
+ square = await openKeiyakuSquare(path, squareEnvironment, hostLedger);
50
124
  const joinedResult = await square.joinWithActivity(name);
51
125
  joined = joinedResult.activity !== null;
52
126
  const participant = joinedResult.participant;
53
- bound = (await bindCurrentParticipant(path, name, environment)).created;
127
+ await bindCurrentParticipant(path, name, squareEnvironment);
128
+ await rememberCreatedBindings();
54
129
  const listener = participant;
55
- const change = await listener.listen(allocated.id);
130
+ let change;
131
+ try {
132
+ change = await listener.listen(allocated.id);
133
+ }
134
+ catch {
135
+ // Keep birth independent from an older or drifting Square name grammar.
136
+ await refreshCreatedBindings();
137
+ await rollback();
138
+ return;
139
+ }
56
140
  listening = change.activity !== null;
141
+ await square.close();
142
+ square = undefined;
57
143
  return {
58
144
  committed: true,
59
145
  participantName: name,
60
146
  rollback,
61
147
  };
62
148
  }
63
- catch (error) {
64
- try {
65
- await rollback();
66
- }
67
- catch {
68
- /* preserve the original Square edge failure */
69
- }
70
- throw error;
149
+ catch {
150
+ if (hasBindingSnapshot)
151
+ await refreshCreatedBindings();
152
+ await rollback();
153
+ return;
71
154
  }
72
155
  finally {
73
- await square.close();
156
+ if (square !== undefined)
157
+ await square.close().catch(() => undefined);
74
158
  }
75
159
  }
@@ -17,7 +17,8 @@ export function usageLine(usage) {
17
17
  .map((line, index) => {
18
18
  if (index === 0)
19
19
  return `usage: keiyaku ${line}`;
20
- return line.startsWith("task ") ? ` keiyaku ${line}` : ` ${line.trimStart()}`;
20
+ const continuation = line.trimStart();
21
+ return ` keiyaku ${continuation.startsWith("keiyaku ") ? continuation.slice("keiyaku ".length) : continuation}`;
21
22
  })
22
23
  .join("\n");
23
24
  }
@@ -0,0 +1,5 @@
1
+ import type { ContractId, ContractState } from "./core/facts/types.js";
2
+ export declare const CONTRACT_DELIVERER_SKILL: string;
3
+ export declare const CONTRACT_REVIEWER_SKILL: string;
4
+ export declare function renderContractAppointment(contract: ContractId): string;
5
+ export declare function renderContractGuidance(state: ContractState): string;