@astrosheep/keiyaku 4.0.1 → 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 (245) hide show
  1. package/README.md +137 -5
  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/package.json +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
  9. package/build/src/akuma/abort.d.ts +2 -0
  10. package/build/src/akuma/abort.js +50 -0
  11. package/build/src/akuma/akuma.d.ts +23 -14
  12. package/build/src/akuma/akuma.js +120 -104
  13. package/build/src/akuma/archetype.d.ts +7 -6
  14. package/build/src/akuma/archetype.js +68 -41
  15. package/build/src/akuma/body.d.ts +3 -5
  16. package/build/src/akuma/body.js +408 -213
  17. package/build/src/akuma/heart/facts.d.ts +25 -34
  18. package/build/src/akuma/heart/facts.js +18 -7
  19. package/build/src/akuma/heart/index.d.ts +39 -42
  20. package/build/src/akuma/heart/index.js +134 -93
  21. package/build/src/akuma/heart/rows.d.ts +9 -31
  22. package/build/src/akuma/heart/rows.js +26 -44
  23. package/build/src/akuma/heart/schema.d.ts +1 -1
  24. package/build/src/akuma/heart/schema.js +7 -15
  25. package/build/src/akuma/heart/soul.d.ts +8 -0
  26. package/build/src/akuma/heart/soul.js +136 -0
  27. package/build/src/akuma/heart/storage.d.ts +28 -14
  28. package/build/src/akuma/heart/storage.js +86 -26
  29. package/build/src/akuma/identity.d.ts +2 -2
  30. package/build/src/akuma/identity.js +9 -9
  31. package/build/src/akuma/index.d.ts +6 -1
  32. package/build/src/akuma/index.js +6 -0
  33. package/build/src/akuma/projection.d.ts +117 -38
  34. package/build/src/akuma/projection.js +208 -97
  35. package/build/src/akuma/provider-recipe.d.ts +24 -0
  36. package/build/src/akuma/provider-recipe.js +100 -0
  37. package/build/src/akuma/provider.d.ts +12 -4
  38. package/build/src/akuma/provider.js +117 -70
  39. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  40. package/build/src/akuma/providers/acp/core.js +159 -0
  41. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  42. package/build/src/akuma/providers/acp/events.js +73 -0
  43. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  44. package/build/src/akuma/providers/acp/index.js +94 -0
  45. package/build/src/akuma/providers/claude/events.js +66 -13
  46. package/build/src/akuma/providers/claude/index.d.ts +2 -1
  47. package/build/src/akuma/providers/claude/index.js +35 -21
  48. package/build/src/akuma/providers/codex-app-server/events.js +4 -1
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
  50. package/build/src/akuma/providers/codex-app-server/index.js +24 -31
  51. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  52. package/build/src/akuma/providers/grok-build/index.js +70 -0
  53. package/build/src/akuma/providers/index.d.ts +5 -3
  54. package/build/src/akuma/providers/index.js +24 -59
  55. package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
  56. package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
  57. package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
  58. package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
  59. package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
  60. package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
  61. package/build/src/akuma/providers/pi/events.js +49 -11
  62. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  63. package/build/src/akuma/providers/pi/index.js +50 -21
  64. package/build/src/akuma/publication.d.ts +3 -3
  65. package/build/src/akuma/publication.js +28 -40
  66. package/build/src/akuma/requests.d.ts +9 -7
  67. package/build/src/akuma/requests.js +92 -65
  68. package/build/src/alias/index.d.ts +2 -2
  69. package/build/src/alias/index.js +10 -10
  70. package/build/src/body/decode.js +7 -1
  71. package/build/src/body/region.d.ts +2 -0
  72. package/build/src/body/region.js +77 -7
  73. package/build/src/cli/accepted.d.ts +17 -13
  74. package/build/src/cli/accepted.js +72 -34
  75. package/build/src/cli/actor.js +3 -3
  76. package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
  77. package/build/src/cli/commands/akuma-invoke.js +14 -9
  78. package/build/src/cli/commands/akuma.d.ts +13 -3
  79. package/build/src/cli/commands/akuma.js +67 -34
  80. package/build/src/cli/commands/contract.d.ts +18 -5
  81. package/build/src/cli/commands/contract.js +9 -3
  82. package/build/src/cli/commands/task-invoke.d.ts +17 -4
  83. package/build/src/cli/commands/task-invoke.js +43 -20
  84. package/build/src/cli/commands/task-query.d.ts +5 -0
  85. package/build/src/cli/commands/task-query.js +247 -0
  86. package/build/src/cli/commands/task.d.ts +3 -1
  87. package/build/src/cli/commands/task.js +51 -13
  88. package/build/src/cli/coordinates.d.ts +18 -0
  89. package/build/src/cli/coordinates.js +120 -0
  90. package/build/src/cli/draft.d.ts +8 -0
  91. package/build/src/cli/draft.js +96 -0
  92. package/build/src/cli/invoke.d.ts +4 -3
  93. package/build/src/cli/invoke.js +160 -179
  94. package/build/src/cli/main.js +34 -6
  95. package/build/src/cli/parse.d.ts +9 -2
  96. package/build/src/cli/parse.js +29 -7
  97. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  98. package/build/src/cli/render/akuma-tool-command.js +144 -0
  99. package/build/src/cli/render/akuma-tool.d.ts +2 -2
  100. package/build/src/cli/render/akuma-tool.js +30 -4
  101. package/build/src/cli/render/akuma.d.ts +1 -0
  102. package/build/src/cli/render/akuma.js +211 -116
  103. package/build/src/cli/render/audit.d.ts +3 -0
  104. package/build/src/cli/render/audit.js +104 -0
  105. package/build/src/cli/render/contract.d.ts +3 -3
  106. package/build/src/cli/render/contract.js +192 -79
  107. package/build/src/cli/render/kanshi.js +263 -168
  108. package/build/src/cli/render/receipt.d.ts +19 -0
  109. package/build/src/cli/render/receipt.js +106 -0
  110. package/build/src/cli/render/refusal.d.ts +16 -2
  111. package/build/src/cli/render/refusal.js +88 -20
  112. package/build/src/cli/render/region.d.ts +2 -0
  113. package/build/src/cli/render/region.js +17 -0
  114. package/build/src/cli/render/task.d.ts +2 -1
  115. package/build/src/cli/render/task.js +223 -60
  116. package/build/src/cli/render/terminal.d.ts +7 -0
  117. package/build/src/cli/render/terminal.js +46 -0
  118. package/build/src/cli/render/text.js +6 -3
  119. package/build/src/cli/result.d.ts +115 -20
  120. package/build/src/cli/usage.d.ts +1 -0
  121. package/build/src/cli/usage.js +3 -0
  122. package/build/src/contract-worktree.d.ts +6 -5
  123. package/build/src/contract-worktree.js +95 -57
  124. package/build/src/coordination/durable-file.d.ts +4 -3
  125. package/build/src/coordination/durable-file.js +29 -25
  126. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  127. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  128. package/build/src/core/facts/fold.js +1 -6
  129. package/build/src/core/facts/gate.d.ts +1 -0
  130. package/build/src/core/facts/gate.js +1 -0
  131. package/build/src/core/verbs/amend.d.ts +1 -1
  132. package/build/src/core/verbs/amend.js +0 -11
  133. package/build/src/core/verbs/deliver.d.ts +1 -1
  134. package/build/src/core/verbs/deliver.js +1 -7
  135. package/build/src/core/verbs/placement.d.ts +1 -1
  136. package/build/src/core/verbs/placement.js +4 -1
  137. package/build/src/dispatch/index.d.ts +2 -2
  138. package/build/src/dispatch/index.js +17 -17
  139. package/build/src/git/admission.d.ts +1 -1
  140. package/build/src/git/admission.js +11 -11
  141. package/build/src/git/hooks.js +13 -13
  142. package/build/src/git/integration.d.ts +14 -15
  143. package/build/src/git/integration.js +80 -44
  144. package/build/src/git/observe.d.ts +5 -3
  145. package/build/src/git/observe.js +18 -12
  146. package/build/src/git/read-observation.js +9 -9
  147. package/build/src/git/reconcile.d.ts +2 -0
  148. package/build/src/git/reconcile.js +138 -95
  149. package/build/src/git/repository.d.ts +27 -19
  150. package/build/src/git/repository.js +155 -83
  151. package/build/src/git/scratch.d.ts +7 -3
  152. package/build/src/git/scratch.js +44 -37
  153. package/build/src/git/target-placement.d.ts +40 -4
  154. package/build/src/git/target-placement.js +221 -101
  155. package/build/src/git/tender.d.ts +6 -5
  156. package/build/src/git/tender.js +24 -43
  157. package/build/src/git/terminal-seal.d.ts +1 -1
  158. package/build/src/git/terminal-seal.js +7 -5
  159. package/build/src/git/workspace.d.ts +36 -4
  160. package/build/src/git/workspace.js +53 -18
  161. package/build/src/identity/selector.js +1 -1
  162. package/build/src/index.d.ts +3 -3
  163. package/build/src/index.js +1 -1
  164. package/build/src/kanshi/index.d.ts +2 -2
  165. package/build/src/kanshi/index.js +1 -1
  166. package/build/src/kanshi/read.d.ts +2 -1
  167. package/build/src/kanshi/read.js +118 -27
  168. package/build/src/kanshi/report.d.ts +50 -0
  169. package/build/src/kanshi/select.d.ts +5 -0
  170. package/build/src/kanshi/select.js +32 -0
  171. package/build/src/library/address.d.ts +12 -3
  172. package/build/src/library/address.js +77 -46
  173. package/build/src/library/akuma-creation.d.ts +6 -1
  174. package/build/src/library/akuma-creation.js +86 -13
  175. package/build/src/library/audit.d.ts +18 -0
  176. package/build/src/library/audit.js +44 -0
  177. package/build/src/library/bind.js +4 -4
  178. package/build/src/library/catalog.d.ts +1 -1
  179. package/build/src/library/catalog.js +5 -8
  180. package/build/src/library/contract.d.ts +5 -6
  181. package/build/src/library/contract.js +11 -35
  182. package/build/src/library/delivery.d.ts +2 -1
  183. package/build/src/library/fleet.d.ts +2 -2
  184. package/build/src/library/fleet.js +35 -71
  185. package/build/src/library/keiyaku.d.ts +3 -2
  186. package/build/src/library/keiyaku.js +1 -0
  187. package/build/src/library/mutation.d.ts +7 -6
  188. package/build/src/library/mutation.js +23 -25
  189. package/build/src/library/reconcile.d.ts +29 -0
  190. package/build/src/library/reconcile.js +179 -0
  191. package/build/src/library/region.d.ts +12 -0
  192. package/build/src/library/region.js +15 -1
  193. package/build/src/library/repo.d.ts +4 -16
  194. package/build/src/library/repo.js +13 -38
  195. package/build/src/protocol/attempt.js +6 -6
  196. package/build/src/protocol/bind.js +4 -4
  197. package/build/src/protocol/intent.d.ts +15 -2
  198. package/build/src/protocol/intent.js +21 -6
  199. package/build/src/protocol/operations.d.ts +73 -22
  200. package/build/src/protocol/operations.js +292 -88
  201. package/build/src/protocol/outcome.d.ts +9 -3
  202. package/build/src/protocol/outcome.js +3 -1
  203. package/build/src/protocol/placement.d.ts +15 -4
  204. package/build/src/protocol/placement.js +58 -25
  205. package/build/src/protocol/read/status.d.ts +8 -1
  206. package/build/src/protocol/read/status.js +61 -14
  207. package/build/src/runtime/proc/line-rpc.d.ts +3 -8
  208. package/build/src/runtime/proc/line-rpc.js +16 -43
  209. package/build/src/runtime/proc/run.d.ts +15 -29
  210. package/build/src/runtime/proc/run.js +113 -105
  211. package/build/src/runtime/proc/stdio.d.ts +18 -0
  212. package/build/src/runtime/proc/stdio.js +58 -0
  213. package/build/src/settings.d.ts +2 -2
  214. package/build/src/settings.js +8 -8
  215. package/build/src/settlement/fence.d.ts +0 -4
  216. package/build/src/settlement/fence.js +0 -9
  217. package/build/src/settlement/holder.d.ts +11 -1
  218. package/build/src/settlement/holder.js +25 -0
  219. package/build/src/settlement/settle.d.ts +1 -1
  220. package/build/src/settlement/settle.js +52 -89
  221. package/build/src/task/board.d.ts +3 -3
  222. package/build/src/task/board.js +6 -9
  223. package/build/src/task/compose.d.ts +1 -1
  224. package/build/src/task/compose.js +18 -10
  225. package/build/src/task/context.d.ts +3 -3
  226. package/build/src/task/context.js +14 -14
  227. package/build/src/task/document.d.ts +2 -1
  228. package/build/src/task/document.js +15 -5
  229. package/build/src/task/index.d.ts +19 -7
  230. package/build/src/task/index.js +42 -23
  231. package/build/src/task/operations.d.ts +15 -9
  232. package/build/src/task/operations.js +78 -48
  233. package/build/src/task/query.d.ts +67 -0
  234. package/build/src/task/query.js +279 -0
  235. package/build/src/task/store.d.ts +2 -2
  236. package/build/src/task/store.js +40 -25
  237. package/build/src/verification/execution.d.ts +4 -2
  238. package/build/src/verification/execution.js +9 -5
  239. package/build/src/workspace-place.d.ts +41 -0
  240. package/build/src/workspace-place.js +386 -0
  241. package/build/src/world.d.ts +13 -2
  242. package/build/src/world.js +81 -48
  243. package/package.json +3 -2
  244. package/build/src/protocol/read/audit.d.ts +0 -31
  245. package/build/src/protocol/read/audit.js +0 -55
@@ -1,21 +1,89 @@
1
- function dirtyWorkspace(value) {
2
- return typeof value === "object" && value !== null && "kind" in value && value.kind === "dirty-workspace";
3
- }
4
- export function renderRefusal(result) {
5
- const contract = result.contract === undefined ? "" : ` ${result.contract}`;
6
- if (dirtyWorkspace(result.refusal)) {
7
- const lines = [`refused ${result.verb}${contract} dirty-workspace`];
8
- for (const category of ["staged", "unstaged", "untracked", "submodules"]) {
9
- const label = category === "submodules" ? "submodule" : category;
10
- for (const path of result.refusal[category])
11
- lines.push(`dirty ${label} ${path}`);
12
- }
13
- const { filesChanged, insertions, deletions } = result.refusal.shortStat;
14
- lines.push(`shortstat files=${filesChanged} insertions=${insertions} deletions=${deletions}`);
15
- if (result.refusal.option !== undefined) {
16
- lines.push(`option ${result.refusal.option.flag} ${result.refusal.option.available ? "available" : "unavailable"}`);
17
- }
18
- return lines.join("\n");
19
- }
20
- return `refused ${result.verb}${contract} ${JSON.stringify(result.refusal)}`;
1
+ import { displayColumns, gitShortStat, renderOpaqueBlock, safeText } from "./terminal.js";
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function wrap(lines, text, indent, columns) {
6
+ lines.push(...renderOpaqueBlock(text, indent, columns));
7
+ }
8
+ function collectionLines(name, members, indent, columns) {
9
+ if (members.length === 0)
10
+ return renderOpaqueBlock(`${name} 0`, indent, columns);
11
+ return [
12
+ ...renderOpaqueBlock(name, indent, columns),
13
+ ...members.flatMap((member) => renderOpaqueBlock(member, `${indent}│ `, columns)),
14
+ ];
15
+ }
16
+ function skipAddressedContract(addressed, contractId) {
17
+ return addressed !== undefined && contractId === addressed;
18
+ }
19
+ function refusalIdentity(refusal, addressed) {
20
+ const contractId = "contractId" in refusal ? refusal.contractId : undefined;
21
+ return skipAddressedContract(addressed, contractId) ? undefined : contractId;
22
+ }
23
+ function refusalHead(kind, identity, details) {
24
+ return [kind, identity === undefined ? undefined : `contractId=${identity}`, ...details]
25
+ .filter((part) => part !== undefined).join(" ");
26
+ }
27
+ function renderDirtyRefusal(refusal, indent, columns, identity) {
28
+ const lines = [];
29
+ wrap(lines, refusalHead(refusal.kind, identity, []), indent, columns);
30
+ for (const name of ["staged", "unstaged", "untracked", "submodules"]) {
31
+ lines.push(...collectionLines(name, refusal[name], indent, columns));
32
+ }
33
+ wrap(lines, gitShortStat(refusal.shortStat), indent, columns);
34
+ if (refusal.option !== undefined) {
35
+ wrap(lines, `option ${refusal.option.flag} ${refusal.option.available ? "available" : "unavailable"}`, indent, columns);
36
+ }
37
+ return lines;
38
+ }
39
+ export function renderRefusalFacts(refusal, indent, columns, addressed) {
40
+ const identity = refusalIdentity(refusal, addressed);
41
+ if (refusal.kind === "dirty-workspace")
42
+ return renderDirtyRefusal(refusal, indent, columns, identity);
43
+ if (refusal.kind === "integration-failed") {
44
+ const lines = [
45
+ ...renderOpaqueBlock(refusalHead(refusal.kind, identity, [`reason=${refusal.reason}`, `targetHead=${refusal.targetHead}`]), indent, columns),
46
+ ];
47
+ if (refusal.conflictPaths !== undefined)
48
+ lines.push(...collectionLines("conflictPaths", refusal.conflictPaths, indent, columns));
49
+ return lines;
50
+ }
51
+ if (refusal.kind === "integration-unsupported") {
52
+ return renderOpaqueBlock(refusalHead(refusal.kind, identity, [`requiredGit=${refusal.requiredGit}`]), indent, columns);
53
+ }
54
+ if (refusal.kind === "checkout-not-followable") {
55
+ const lines = [...renderOpaqueBlock(refusalHead(refusal.kind, identity, [`target=${refusal.target}`, `path=${refusal.path}`, `reason=${refusal.reason}`]), indent, columns)];
56
+ lines.push(...collectionLines("paths", refusal.paths, indent, columns));
57
+ return lines;
58
+ }
59
+ if (refusal.kind === "workspace-not-on-target") {
60
+ return renderOpaqueBlock(refusalHead(refusal.kind, identity, [`target=${refusal.target}`, `branch=${refusal.branch}`]), indent, columns);
61
+ }
62
+ if (refusal.kind === "here-target-mismatch") {
63
+ return renderOpaqueBlock(`here-target-mismatch target=${refusal.target} branch=${refusal.branch}`, indent, columns);
64
+ }
65
+ if (refusal.kind === "here-worktree-appointed") {
66
+ return renderOpaqueBlock(refusalHead(refusal.kind, undefined, [refusal.contract === undefined ? "" : `contract=${refusal.contract}`, `path=${refusal.path}`]), indent, columns);
67
+ }
68
+ return renderOpaqueBlock(refusalHead(refusal.kind, identity, []), indent, columns);
69
+ }
70
+ export function renderRefusal(result, context) {
71
+ const columns = context?.columns ?? 80;
72
+ const base = `! ${result.verb} refused`;
73
+ const lines = result.contract === undefined
74
+ ? [base]
75
+ : displayColumns(`${base} — ${result.contract}`) <= columns
76
+ ? [`${base} — ${result.contract}`]
77
+ : [`${base} —`, ` ${safeText(result.contract)}`];
78
+ if (isRecord(result.refusal) && typeof result.refusal.kind === "string") {
79
+ lines.push(...renderRefusalFacts(result.refusal, " ", columns, result.contract));
80
+ }
81
+ const output = lines.join("\n");
82
+ return result.draft === undefined ? output : `${output}\n${renderBindDraftReceipt(result.draft)}`;
83
+ }
84
+ export function renderBindDraftReceipt(receipt) {
85
+ return [
86
+ ...(receipt.path === undefined ? [] : [`draft preserved: ${receipt.path}`]),
87
+ ...(receipt.warning === undefined ? [] : [`warning: ${receipt.warning}`]),
88
+ ].join("\n");
21
89
  }
@@ -0,0 +1,2 @@
1
+ import type { RegionRead, Section } from "../../kanshi/index.js";
2
+ export declare function renderRegionText(section: Section<RegionRead>): string;
@@ -0,0 +1,17 @@
1
+ function rows(section) {
2
+ if (section.kind === "absent")
3
+ return [];
4
+ if (section.kind === "failed")
5
+ return [`region failed ${section.failure.message}`];
6
+ const value = section.value;
7
+ if (value.kind === "declarations")
8
+ return value.declarations.map((declaration) => `region ${declaration.contract} ${declaration.patterns.join(" ")}`);
9
+ if (value.kind === "contract")
10
+ return [`region ${value.declaration.contract} ${value.declaration.patterns.join(" ")}`];
11
+ if (value.kind === "path")
12
+ return value.matches.map((match) => `path ${value.path} ${match.contract} ${match.pattern}`);
13
+ return value.intersections.flatMap((intersection) => intersection.patterns.map((pattern) => `overlap ${intersection.left} ${pattern.left} ~ ${intersection.right} ${pattern.right}`));
14
+ }
15
+ export function renderRegionText(section) {
16
+ return rows(section).join("\n");
17
+ }
@@ -1,6 +1,7 @@
1
1
  import type { TaskCompositionResult } from "../../task/index.js";
2
2
  import type { TaskInvocationResult } from "../commands/task-invoke.js";
3
3
  import type { ParsedTaskCommand } from "../commands/task.js";
4
- export declare function renderTaskText(command: ParsedTaskCommand, result: TaskInvocationResult): string;
4
+ import { type TextRenderContext } from "./terminal.js";
5
+ export declare function renderTaskText(command: ParsedTaskCommand, result: TaskInvocationResult, context?: TextRenderContext): string;
5
6
  export declare function renderTaskIncompleteDiagnostic(result: TaskCompositionResult): string;
6
7
  export declare function taskExitCode(result: TaskInvocationResult): number;
@@ -1,93 +1,256 @@
1
- function row(value) {
2
- const disposition = "disposition" in value ? value.disposition : value.state;
3
- return `${value.id} - P${value.priority} - ${disposition} - ${value.title}`;
1
+ import { outcomeLines, receiptPayload } from "./receipt.js";
2
+ import { displayColumns, renderTextBlock, safeText } from "./terminal.js";
3
+ const DEFAULT_CONTEXT = { columns: 80, color: false };
4
+ function isWorldObservation(result) {
5
+ return typeof result === "object" && result !== null
6
+ && "kind" in result
7
+ && (result.kind === "present" || result.kind === "absent" || result.kind === "failed");
4
8
  }
5
- function changes(values) {
6
- return values.map((change) => change.documentDiff).filter((diff) => diff.length > 0).join("\n");
9
+ function markFor(word) {
10
+ if (word === "in_progress")
11
+ return "●";
12
+ if (word === "ready" || word === "open")
13
+ return "○";
14
+ if (word === "blocked" || word === "missing")
15
+ return "!";
16
+ if (word === "on_hold")
17
+ return "·";
18
+ if (word === "done")
19
+ return "✓";
20
+ if (word === "drop")
21
+ return "×";
22
+ return "?";
7
23
  }
8
- function failure(result) {
9
- return result.kind === "retry" ? `retry ${JSON.stringify(result.reason)}` : `refused ${JSON.stringify(result.refusal)}`;
24
+ function priorityText(priority) {
25
+ return priority === null ? "P?" : `P${priority}`;
10
26
  }
11
- function renderRows(result) {
27
+ function scanUnit(id, priority, word) {
28
+ return `${markFor(word)} ${id} · ${priorityText(priority)} ${word}`;
29
+ }
30
+ function entityLines(entity, columns, indent = "") {
31
+ const scan = `${indent}${scanUnit(entity.id, entity.priority, entity.word)}`;
32
+ if (entity.title === null || entity.title.length === 0)
33
+ return [scan];
34
+ const title = safeText(entity.title);
35
+ const inline = `${scan} — ${title}`;
36
+ if (displayColumns(inline) <= columns)
37
+ return [inline];
38
+ return [`${scan} —`, ...renderTextBlock(title, `${indent} `, columns)];
39
+ }
40
+ function listEntity(item) {
41
+ return { id: item.id, priority: item.priority, word: item.disposition, title: item.title };
42
+ }
43
+ function stateEntity(task) {
44
+ return { id: task.id, priority: "priority" in task && task.priority !== undefined ? task.priority : null, word: task.state, title: task.title };
45
+ }
46
+ function projectRefusal(refusal) {
47
+ if (refusal.kind === "task-missing")
48
+ return { line: `task-missing ${refusal.taskId}` };
49
+ if (refusal.kind === "invalid-lifecycle-transition") {
50
+ return { line: `invalid-lifecycle-transition ${refusal.taskId} ${refusal.state} ${refusal.verb}` };
51
+ }
52
+ if (refusal.kind === "invalid-namespace-context")
53
+ return { line: `invalid-namespace-context ${refusal.path}` };
54
+ if (refusal.kind === "relation-owned-by-other") {
55
+ return { line: `relation-owned-by-other ${refusal.taskId} ${refusal.related} ${refusal.declaringTask}` };
56
+ }
57
+ return { line: refusal.kind, diagnostic: refusal.diagnostic };
58
+ }
59
+ function appendDiagnostic(lines, diagnostic) {
60
+ if (diagnostic !== undefined)
61
+ receiptPayload(lines, "diagnostic", diagnostic);
62
+ }
63
+ function renderFailure(verb, result, columns) {
64
+ if (result.kind === "retry") {
65
+ return [...outcomeLines("?", verb, "retry", undefined, columns), result.reason].join("\n");
66
+ }
67
+ const lines = [...outcomeLines("!", verb, "refused", undefined, columns)];
68
+ const facts = projectRefusal(result.refusal);
69
+ lines.push(facts.line);
70
+ appendDiagnostic(lines, facts.diagnostic);
71
+ return lines.join("\n");
72
+ }
73
+ function edge(label, ref, mark) {
74
+ const prefix = mark === undefined ? ` ${label}` : ` ${mark} ${label}`;
75
+ return `${prefix} ${ref.id} · ${ref.state}`;
76
+ }
77
+ function pageHeading(view, page) {
78
+ if (page.truncated)
79
+ return `${view} ${page.returned} of ${page.total} · limit ${page.returned}`;
80
+ return `${view} ${page.returned}`;
81
+ }
82
+ function renderListRow(item, columns) {
83
+ const lines = [...entityLines(listEntity(item), columns)];
84
+ if ("blockers" in item) {
85
+ for (const blocker of item.blockers)
86
+ lines.push(` needs ${blocker.id} · ${blocker.state}`);
87
+ }
88
+ return lines;
89
+ }
90
+ function renderRows(command, result, columns) {
12
91
  if (result.kind !== "accepted")
13
- return failure(result);
14
- return result.value.map((item) => {
15
- const blockers = "blockers" in item ? item.blockers.map((blocker) => blocker.id).join(", ") : undefined;
16
- return `${row(item)}${blockers === undefined ? "" : ` <- ${blockers}`}`;
17
- }).join("\n");
92
+ return renderFailure(command.action, result, columns);
93
+ const view = command.action === "ls" ? "tasks" : command.action;
94
+ return [pageHeading(view, result.value), ...result.value.rows.flatMap((item) => renderListRow(item, columns))].join("\n");
18
95
  }
19
- function renderShow(result) {
96
+ function renderShow(result, columns) {
20
97
  if ("kind" in result)
21
- return result.kind === "accepted" ? row(result.value) : failure(result);
22
- const task = result.task, lines = [
23
- row(task), `namespace: ${task.namespace.join("/") || "root"}`,
24
- `createdAt: ${task.createdAt}`, `updatedAt: ${task.updatedAt}`, `note: ${task.note}`,
98
+ return result.kind === "accepted" ? entityLines(stateEntity(result.value), columns).join("\n") : renderFailure("show", result, columns);
99
+ const task = result.task;
100
+ const lines = [
101
+ ...entityLines(stateEntity(task), columns),
102
+ ...renderTextBlock(`created ${task.createdAt} · updated ${task.updatedAt}`, "", columns),
103
+ ...(task.createdBy === undefined ? [] : [`created-by ${task.createdBy}`]),
25
104
  ];
26
- for (const [label, values] of [
27
- ["needs", task.needs], ["blockers", result.blockers.map((item) => item.id)], ["blocks", result.blocks.map((item) => item.id)],
28
- ["children", result.children.map((item) => item.id)], ["supersedes", task.supersedes],
29
- ["superseded by", result.supersededBy.map((item) => item.id)], ["related", result.related.map((item) => item.id)],
30
- ])
31
- if (values.length > 0)
32
- lines.push(`${label}: ${values.join(", ")}`);
33
- if (task.parent !== null)
34
- lines.push(`parent: ${task.parent}`);
105
+ for (const need of result.needs.filter((item) => !item.released))
106
+ lines.push(edge("needs", need, "!"));
107
+ for (const need of result.needs.filter((item) => item.released))
108
+ lines.push(edge("needs", need, "✓"));
109
+ for (const item of result.blocks)
110
+ lines.push(edge("blocks", item));
111
+ if (result.parent !== null)
112
+ lines.push(edge("parent", result.parent));
113
+ for (const item of result.children)
114
+ lines.push(edge("child", item));
115
+ for (const item of result.supersedes)
116
+ lines.push(edge("supersedes", item));
117
+ for (const item of result.supersededBy)
118
+ lines.push(edge("superseded-by", item));
119
+ for (const item of result.related)
120
+ lines.push(edge("related", item));
121
+ if (task.note.length > 0)
122
+ receiptPayload(lines, "note", task.note);
35
123
  if (task.body.length > 0)
36
- lines.push("", task.body);
124
+ receiptPayload(lines, "body", task.body);
37
125
  return lines.join("\n");
38
126
  }
39
- function treeLines(node, depth = 0) {
40
- const marker = node.cycle ? "cycle" : node.reference ? "reference" : node.task.state;
41
- const line = `${" ".repeat(depth)}${node.task.id} - ${node.task.priority === null ? "P?" : `P${node.task.priority}`} - ${marker}${node.task.title === null ? "" : ` - ${node.task.title}`}`;
42
- return [line, ...node.needs.flatMap((child) => treeLines(child, depth + 1))];
127
+ function treeLines(node, columns, depth = 0) {
128
+ const indent = " ".repeat(depth);
129
+ if (node.cycle === true)
130
+ return [`${indent}! ${node.task.id} · cycle`];
131
+ return [
132
+ ...entityLines(stateEntity(node.task), columns, indent),
133
+ ...node.children.flatMap((child) => treeLines(child, columns, depth + 1)),
134
+ ];
43
135
  }
44
136
  function doctorIssue(issue) {
45
137
  if (issue.kind === "missing-target")
46
- return `${issue.taskId}: ${issue.relation} target missing: ${issue.target}`;
138
+ return `! missing-target ${issue.taskId} ${issue.relation} ${issue.target}`;
47
139
  if (issue.kind === "self-relation")
48
- return `${issue.taskId}: self ${issue.relation}`;
49
- return `${issue.relation} cycle: ${issue.tasks.join(" -> ")}`;
140
+ return `! self-relation ${issue.taskId} ${issue.relation}`;
141
+ return `! cycle ${issue.relation} ${issue.tasks.join(" ")}`;
50
142
  }
51
- export function renderTaskText(command, result) {
143
+ function renderDoctor(report) {
144
+ if (report.issues.length === 0)
145
+ return "healthy";
146
+ const noun = report.issues.length === 1 ? "issue" : "issues";
147
+ return [`${report.issues.length} ${noun}`, ...report.issues.map(doctorIssue)].join("\n");
148
+ }
149
+ function renderAcceptedMutation(verb, task, columns, documentDiff) {
150
+ const lines = [
151
+ ...outcomeLines("✓", verb, "accepted", task.id, columns),
152
+ ...entityLines(stateEntity(task), columns),
153
+ ];
154
+ if (documentDiff !== undefined)
155
+ receiptPayload(lines, "diff", documentDiff);
156
+ return lines.join("\n");
157
+ }
158
+ function renderMutation(command, result, columns) {
159
+ if (result.kind !== "accepted")
160
+ return renderFailure(command.action, result, columns);
161
+ if (command.action !== "update") {
162
+ return renderAcceptedMutation(command.action, result.value, columns);
163
+ }
164
+ const value = result.value;
165
+ return renderAcceptedMutation(command.action, value.task, columns, value.documentDiff);
166
+ }
167
+ function renderBatchItem(verb, item) {
168
+ if (item.outcome.kind === "accepted")
169
+ return `✓ ${verb} ${item.id}`;
170
+ if (item.outcome.kind === "retry")
171
+ return `? ${verb} ${item.id} · ${item.outcome.reason}`;
172
+ const facts = projectRefusal(item.outcome.refusal);
173
+ const lines = [`! ${verb} ${item.id} · ${facts.line}`];
174
+ appendDiagnostic(lines, facts.diagnostic);
175
+ return lines.join("\n");
176
+ }
177
+ function renderBatch(verb, batch) {
178
+ return batch.items.map((item) => renderBatchItem(verb, item)).join("\n");
179
+ }
180
+ function composeDiffs(lines, changes) {
181
+ for (const change of changes)
182
+ receiptPayload(lines, `diff ${change.taskId}`, change.documentDiff);
183
+ }
184
+ function stoppedLines(stopped) {
185
+ if (stopped.kind === "retry")
186
+ return [`? stopped ${stopped.reason}`];
187
+ const facts = projectRefusal(stopped);
188
+ const lines = [`! stopped ${facts.line}`];
189
+ appendDiagnostic(lines, facts.diagnostic);
190
+ return lines;
191
+ }
192
+ function renderCompose(result, columns) {
193
+ if (result.kind === "incomplete")
194
+ return "";
195
+ if (result.kind !== "accepted")
196
+ return renderFailure("compose", result, columns);
197
+ const lines = [`✓ compose accepted · ${result.documentChanges.length} changed`];
198
+ composeDiffs(lines, result.documentChanges);
199
+ return lines.join("\n");
200
+ }
201
+ export function renderTaskText(command, result, context = DEFAULT_CONTEXT) {
202
+ if (isWorldObservation(result)) {
203
+ if (result.kind === "absent")
204
+ return "task world absent";
205
+ if (result.kind === "failed") {
206
+ const lines = ["task world failed"];
207
+ receiptPayload(lines, "diagnostic", result.failure.message);
208
+ return lines.join("\n");
209
+ }
210
+ result = result.value;
211
+ }
212
+ return renderTaskValue(command, result, context.columns);
213
+ }
214
+ function renderTaskValue(command, result, columns) {
52
215
  if (command.action === "show")
53
- return renderShow(result);
54
- if (command.action === "ls" || command.action === "ready" || command.action === "blocked")
55
- return renderRows(result);
216
+ return renderShow(result, columns);
217
+ if (command.action === "ls" || command.action === "ready" || command.action === "blocked" || command.action === "query") {
218
+ return renderRows(command, result, columns);
219
+ }
56
220
  if (command.action === "tree") {
57
221
  const tree = result;
58
- return tree.kind === "accepted" ? treeLines(tree.value).join("\n") : failure(tree);
59
- }
60
- if (command.action === "doctor") {
61
- const report = result;
62
- return report.issues.length === 0 ? "healthy" : report.issues.map(doctorIssue).join("\n");
222
+ return tree.kind === "accepted" ? treeLines(tree.value, columns).join("\n") : renderFailure(command.action, tree, columns);
63
223
  }
224
+ if (command.action === "doctor")
225
+ return renderDoctor(result);
64
226
  if (command.action === "namespace") {
65
227
  const namespace = result;
66
- return namespace.kind === "accepted" ? namespace.value.join("/") || "root" : failure(namespace);
67
- }
68
- if (command.action === "compose") {
69
- const composition = result;
70
- return composition.kind === "accepted" ? changes(composition.documentChanges) : composition.kind === "incomplete" ? "" : failure(composition);
228
+ if (namespace.kind !== "accepted")
229
+ return renderFailure(command.action, namespace, columns);
230
+ return `namespace ${namespace.value.length === 0 ? "root" : namespace.value.join("/")}`;
71
231
  }
232
+ if (command.action === "compose")
233
+ return renderCompose(result, columns);
72
234
  if (command.action === "hold" || command.action === "done" || command.action === "drop") {
73
- const batch = result;
74
- return batch.items.map((item) => item.outcome.kind === "accepted" ? `accepted ${item.id}` : `${item.id}: ${failure(item.outcome)}`).join("\n");
75
- }
76
- const mutation = result;
77
- if (mutation.kind !== "accepted")
78
- return failure(mutation);
79
- if (command.action === "update") {
80
- const value = mutation.value;
81
- return [row(value.task), value.documentDiff].filter((line) => line.length > 0).join("\n");
235
+ return renderBatch(command.action, result);
82
236
  }
83
- return row(mutation.value);
237
+ return renderMutation(command, result, columns);
84
238
  }
85
239
  export function renderTaskIncompleteDiagnostic(result) {
86
240
  if (result.kind !== "incomplete")
87
241
  return "";
88
- return [`incomplete ${JSON.stringify(result.stopped)}`, changes(result.documentChanges)].filter((line) => line.length > 0).join("\n");
242
+ const lines = [`! compose incomplete · ${result.documentChanges.length} admitted`, ...stoppedLines(result.stopped)];
243
+ composeDiffs(lines, result.documentChanges);
244
+ return lines.join("\n");
89
245
  }
90
246
  export function taskExitCode(result) {
247
+ if (isWorldObservation(result)) {
248
+ if (result.kind === "absent")
249
+ return 1;
250
+ if (result.kind === "failed")
251
+ return 3;
252
+ result = result.value;
253
+ }
91
254
  if (typeof result === "object" && result !== null && "issues" in result)
92
255
  return result.issues.length === 0 ? 0 : 1;
93
256
  if (typeof result === "object" && result !== null && "items" in result) {
@@ -2,6 +2,12 @@ export type TextRenderContext = Readonly<{
2
2
  columns: number;
3
3
  color: boolean;
4
4
  }>;
5
+ export type GitShortStat = Readonly<{
6
+ filesChanged: number;
7
+ insertions: number;
8
+ deletions: number;
9
+ }>;
10
+ export declare function gitShortStat(stat: GitShortStat): string;
5
11
  export declare function displayColumns(value: string): number;
6
12
  export declare function takeDisplayColumns(value: string, maximum: number): Readonly<{
7
13
  text: string;
@@ -19,5 +25,6 @@ export declare function renderBoundedTextBlock(value: string, input: Readonly<{
19
25
  export declare function safeText(value: string): string;
20
26
  export declare function renderFacts(primary: string, facts: readonly string[], columns: number): readonly string[];
21
27
  export declare function renderTextBlock(value: string, indent: string, columns: number): readonly string[];
28
+ export declare function renderOpaqueBlock(value: string, indent: string, columns: number): readonly string[];
22
29
  export declare function renderVoiceRuler(left: string, right: string, columns: number): string;
23
30
  export declare function tone(value: string, kind: "dim" | "alert", color: boolean): string;
@@ -1,3 +1,16 @@
1
+ export function gitShortStat(stat) {
2
+ const files = stat.filesChanged === 1 ? "1 file changed" : `${stat.filesChanged} files changed`;
3
+ const parts = [files];
4
+ if (stat.insertions === 1)
5
+ parts.push("1 insertion(+)");
6
+ else if (stat.insertions !== 0)
7
+ parts.push(`${stat.insertions} insertions(+)`);
8
+ if (stat.deletions === 1)
9
+ parts.push("1 deletion(-)");
10
+ else if (stat.deletions !== 0)
11
+ parts.push(`${stat.deletions} deletions(-)`);
12
+ return parts.join(", ");
13
+ }
1
14
  const GRAPHEMES = new Intl.Segmenter("und", { granularity: "grapheme" });
2
15
  const WIDE_RANGES = [
3
16
  [0x1100, 0x115f], [0x2329, 0x232a], [0x2e80, 0xa4cf], [0xac00, 0xd7a3],
@@ -137,6 +150,39 @@ export function renderTextBlock(value, indent, columns) {
137
150
  lines.push(current);
138
151
  return lines;
139
152
  }
153
+ export function renderOpaqueBlock(value, indent, columns) {
154
+ let rest = safeText(value);
155
+ if (rest.length === 0)
156
+ return [indent.trimEnd()];
157
+ const continuation = `${indent} `;
158
+ const lines = [];
159
+ let prefix = indent;
160
+ while (rest.length > 0) {
161
+ const budget = columns - displayColumns(prefix);
162
+ if (budget <= 0) {
163
+ if (prefix === continuation) {
164
+ lines.push(`${prefix}${rest}`);
165
+ break;
166
+ }
167
+ lines.push(prefix.trimEnd());
168
+ prefix = continuation;
169
+ continue;
170
+ }
171
+ if (displayColumns(rest) <= budget) {
172
+ lines.push(`${prefix}${rest}`);
173
+ break;
174
+ }
175
+ const taken = takeDisplayColumns(rest, budget);
176
+ if (taken.text.length === 0) {
177
+ lines.push(`${prefix}${rest}`);
178
+ break;
179
+ }
180
+ lines.push(`${prefix}${taken.text}`);
181
+ rest = taken.rest;
182
+ prefix = continuation;
183
+ }
184
+ return lines;
185
+ }
140
186
  export function renderVoiceRuler(left, right, columns) {
141
187
  const width = Math.max(20, Math.min(80, columns));
142
188
  const occupied = displayColumns(left) + displayColumns(right) + 2;
@@ -3,6 +3,7 @@ import { renderAccepted, renderRetry } from "./contract.js";
3
3
  import { renderKanshiText } from "./kanshi.js";
4
4
  import { renderRefusal } from "./refusal.js";
5
5
  import { renderCatalogText } from "./catalog.js";
6
+ import { renderRegionText } from "./region.js";
6
7
  export function renderText(result, context) {
7
8
  if (result.kind === "guidance")
8
9
  return result.guidance;
@@ -10,11 +11,13 @@ export function renderText(result, context) {
10
11
  return renderKanshiText(result.report, context, result.selection);
11
12
  if (result.kind === "catalog")
12
13
  return renderCatalogText(result.catalog);
14
+ if (result.kind === "region")
15
+ return renderRegionText(result.region);
13
16
  if (result.kind === "accepted")
14
- return renderAccepted(result);
17
+ return renderAccepted(result, context);
15
18
  if (result.kind === "refused")
16
- return renderRefusal(result);
19
+ return renderRefusal(result, context);
17
20
  if (result.kind === "retry")
18
- return renderRetry(result);
21
+ return renderRetry(result, context);
19
22
  return renderObservation(result);
20
23
  }