@astrosheep/keiyaku 4.0.3 → 4.0.4

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 (141) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +15 -1
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +20 -13
  9. package/build/src/akuma/akuma.d.ts +34 -11
  10. package/build/src/akuma/akuma.js +121 -61
  11. package/build/src/akuma/allowed.d.ts +7 -0
  12. package/build/src/akuma/allowed.js +40 -0
  13. package/build/src/akuma/archetype.d.ts +7 -4
  14. package/build/src/akuma/archetype.js +15 -16
  15. package/build/src/akuma/body.d.ts +3 -1
  16. package/build/src/akuma/body.js +9 -6
  17. package/build/src/akuma/heart/facts.d.ts +49 -7
  18. package/build/src/akuma/heart/index.d.ts +4 -8
  19. package/build/src/akuma/heart/index.js +76 -15
  20. package/build/src/akuma/heart/rows.d.ts +7 -5
  21. package/build/src/akuma/heart/rows.js +98 -11
  22. package/build/src/akuma/heart/schema.d.ts +1 -1
  23. package/build/src/akuma/heart/schema.js +15 -10
  24. package/build/src/akuma/heart/soul.js +3 -1
  25. package/build/src/akuma/heart/storage.d.ts +1 -0
  26. package/build/src/akuma/heart/storage.js +15 -0
  27. package/build/src/akuma/heart/timeline.d.ts +1 -5
  28. package/build/src/akuma/heart/timeline.js +8 -17
  29. package/build/src/akuma/index.d.ts +4 -1
  30. package/build/src/akuma/index.js +1 -0
  31. package/build/src/akuma/projection.d.ts +17 -3
  32. package/build/src/akuma/projection.js +40 -3
  33. package/build/src/akuma/provider.d.ts +1 -1
  34. package/build/src/akuma/provider.js +2 -1
  35. package/build/src/akuma/providers/acp/core.d.ts +3 -1
  36. package/build/src/akuma/providers/acp/core.js +4 -4
  37. package/build/src/akuma/providers/acp/events.d.ts +11 -3
  38. package/build/src/akuma/providers/acp/events.js +78 -4
  39. package/build/src/akuma/providers/claude/events.js +62 -3
  40. package/build/src/akuma/providers/codex-app-server/events.js +1 -13
  41. package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
  42. package/build/src/akuma/providers/grok-build/index.js +72 -2
  43. package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
  44. package/build/src/akuma/providers/pi/events.js +17 -3
  45. package/build/src/akuma/providers/unified-patch.d.ts +4 -0
  46. package/build/src/akuma/providers/unified-patch.js +14 -0
  47. package/build/src/akuma/publication.d.ts +1 -1
  48. package/build/src/akuma/publication.js +1 -1
  49. package/build/src/akuma/requests.d.ts +70 -4
  50. package/build/src/akuma/requests.js +288 -77
  51. package/build/src/akuma-body.d.ts +1 -0
  52. package/build/src/akuma-body.js +31 -0
  53. package/build/src/cli/accepted.d.ts +4 -1
  54. package/build/src/cli/accepted.js +26 -4
  55. package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
  56. package/build/src/cli/commands/akuma-invoke.js +18 -10
  57. package/build/src/cli/commands/akuma.d.ts +11 -2
  58. package/build/src/cli/commands/akuma.js +65 -26
  59. package/build/src/cli/commands/amend.d.ts +1 -1
  60. package/build/src/cli/commands/amend.js +1 -1
  61. package/build/src/cli/commands/contract.d.ts +3 -3
  62. package/build/src/cli/commands/contract.js +1 -1
  63. package/build/src/cli/commands/install.js +2 -2
  64. package/build/src/cli/commands/task-query.d.ts +1 -1
  65. package/build/src/cli/commands/task-query.js +11 -5
  66. package/build/src/cli/coordinates.d.ts +1 -0
  67. package/build/src/cli/coordinates.js +5 -1
  68. package/build/src/cli/invoke.d.ts +1 -0
  69. package/build/src/cli/invoke.js +90 -73
  70. package/build/src/cli/main.d.ts +2 -0
  71. package/build/src/cli/main.js +29 -4
  72. package/build/src/cli/parse.d.ts +1 -0
  73. package/build/src/cli/parse.js +4 -0
  74. package/build/src/cli/render/akuma.d.ts +2 -2
  75. package/build/src/cli/render/akuma.js +84 -13
  76. package/build/src/cli/render/audit.js +16 -2
  77. package/build/src/cli/render/contract.d.ts +2 -0
  78. package/build/src/cli/render/contract.js +203 -36
  79. package/build/src/cli/render/kanshi.js +64 -29
  80. package/build/src/cli/render/receipt.d.ts +2 -1
  81. package/build/src/cli/render/receipt.js +9 -1
  82. package/build/src/cli/render/text.js +3 -1
  83. package/build/src/cli/result.d.ts +38 -3
  84. package/build/src/cli/selectors.d.ts +1 -0
  85. package/build/src/cli/selectors.js +9 -6
  86. package/build/src/contract-worktree.js +3 -0
  87. package/build/src/dispatch/index.js +50 -39
  88. package/build/src/git/hooks.d.ts +0 -4
  89. package/build/src/git/hooks.js +0 -36
  90. package/build/src/git/integration.d.ts +2 -6
  91. package/build/src/git/integration.js +8 -8
  92. package/build/src/git/reconcile.d.ts +6 -1
  93. package/build/src/git/reconcile.js +55 -9
  94. package/build/src/git/tender.d.ts +19 -4
  95. package/build/src/git/tender.js +44 -13
  96. package/build/src/git/terminal-seal.d.ts +14 -0
  97. package/build/src/git/terminal-seal.js +15 -2
  98. package/build/src/git/workspace.d.ts +1 -0
  99. package/build/src/git/workspace.js +12 -4
  100. package/build/src/index.d.ts +1 -1
  101. package/build/src/kanshi/index.d.ts +1 -1
  102. package/build/src/kanshi/index.js +1 -1
  103. package/build/src/kanshi/read.d.ts +9 -1
  104. package/build/src/kanshi/read.js +91 -37
  105. package/build/src/kanshi/report.d.ts +1 -0
  106. package/build/src/library/address.d.ts +5 -14
  107. package/build/src/library/address.js +20 -22
  108. package/build/src/library/akuma-creation.d.ts +4 -2
  109. package/build/src/library/akuma-creation.js +43 -26
  110. package/build/src/library/bind.js +3 -3
  111. package/build/src/library/catalog.d.ts +1 -2
  112. package/build/src/library/catalog.js +11 -6
  113. package/build/src/library/configuration.d.ts +4 -0
  114. package/build/src/library/configuration.js +19 -0
  115. package/build/src/library/contract.d.ts +15 -1
  116. package/build/src/library/contract.js +51 -4
  117. package/build/src/library/fleet.d.ts +47 -9
  118. package/build/src/library/fleet.js +184 -44
  119. package/build/src/library/input.js +1 -0
  120. package/build/src/library/keiyaku.d.ts +4 -4
  121. package/build/src/library/keiyaku.js +1 -2
  122. package/build/src/protocol/bind.d.ts +1 -2
  123. package/build/src/protocol/bind.js +2 -16
  124. package/build/src/protocol/operations.d.ts +4 -1
  125. package/build/src/protocol/operations.js +33 -27
  126. package/build/src/protocol/read/status.d.ts +3 -1
  127. package/build/src/protocol/read/status.js +24 -14
  128. package/build/src/runtime/proc/run.d.ts +1 -0
  129. package/build/src/runtime/proc/run.js +9 -2
  130. package/build/src/settlement/settle.d.ts +1 -0
  131. package/build/src/settlement/settle.js +4 -1
  132. package/build/src/task/board.d.ts +18 -3
  133. package/build/src/task/board.js +73 -26
  134. package/build/src/task/index.d.ts +3 -3
  135. package/build/src/task/index.js +7 -5
  136. package/build/src/task/operations.d.ts +2 -19
  137. package/build/src/task/operations.js +29 -7
  138. package/build/src/task/query.d.ts +9 -2
  139. package/build/src/task/query.js +32 -64
  140. package/build/src/verification/execution.js +2 -1
  141. package/package.json +3 -1
@@ -1,7 +1,7 @@
1
1
  import { resolve } from "node:path";
2
2
  import { documentDiff } from "../markdown/diff.js";
3
3
  import { installNamespaceContext, readNamespaceContext } from "./context.js";
4
- import { relationProblem, projectBlocked, projectRows, projectStatusRows } from "./board.js";
4
+ import { createTaskRelations, projectTaskBoardObservation, relationProblem, projectBlocked, projectRows, } from "./board.js";
5
5
  import { parseTaskCreationDocument, serializeTaskDocument } from "./document.js";
6
6
  import { allocateLocalId, deriveLocalStem, formatTaskId, parseTaskId, sameNamespace } from "./identity.js";
7
7
  import { authorityPath, readBoard, replaceAuthority, withTaskLocks, } from "./store.js";
@@ -183,9 +183,14 @@ export async function readyTasks(world, scope, parent, limit = DEFAULT_TASK_LIMI
183
183
  const board = (await readBoard(world)).board;
184
184
  if (parent !== undefined && !board.tasks.has(parent))
185
185
  return { kind: "refused", refusal: { kind: "task-missing", taskId: parent } };
186
+ const relations = createTaskRelations(board);
186
187
  const ready = { kind: "predicate", predicate: { field: "ready", operator: "=", value: true } };
187
188
  const expression = parent === undefined ? ready : { kind: "and", terms: [ready, underExpression(parent)] };
188
- const selectedRows = projectQuery(board, selected, expression, "priority", Math.max(1, board.tasks.size)).rows;
189
+ const selectedRows = projectQuery(board, relations, {
190
+ scope: selected,
191
+ expression,
192
+ limit: Math.max(1, board.tasks.size),
193
+ }).rows;
189
194
  const rows = selectedRows.map(({ parent: _parent, needs: _needs, blocks: _blocks, createdAt: _createdAt, updatedAt: _updatedAt, ...row }) => row);
190
195
  return { kind: "accepted", value: projectPage(rows, limit) };
191
196
  }
@@ -196,26 +201,43 @@ export async function blockedTasks(world, scope, parent, limit = DEFAULT_TASK_LI
196
201
  const board = (await readBoard(world)).board;
197
202
  if (parent !== undefined && !board.tasks.has(parent))
198
203
  return { kind: "refused", refusal: { kind: "task-missing", taskId: parent } };
204
+ const relations = createTaskRelations(board);
199
205
  const blocked = { kind: "predicate", predicate: { field: "blocked", operator: "=", value: true } };
200
206
  const expression = parent === undefined ? blocked : { kind: "and", terms: [blocked, underExpression(parent)] };
201
- const selectedRows = projectQuery(board, selected, expression, "priority", Math.max(1, board.tasks.size)).rows;
207
+ const selectedRows = projectQuery(board, relations, {
208
+ scope: selected,
209
+ expression,
210
+ limit: Math.max(1, board.tasks.size),
211
+ }).rows;
202
212
  const ids = new Set(selectedRows.map((row) => row.id));
203
- return { kind: "accepted", value: projectPage(projectBlocked(board, selected).filter((row) => ids.has(row.id)), limit) };
213
+ return {
214
+ kind: "accepted",
215
+ value: projectPage(projectBlocked(board, selected, relations).filter((row) => ids.has(row.id)), limit),
216
+ };
204
217
  }
205
218
  export async function queryTasks(world, expression, scope, sort = "priority", limit = DEFAULT_TASK_LIMIT) {
206
219
  const selected = await readScope(world, scope);
207
220
  if (selected !== null && !Array.isArray(selected))
208
221
  return { kind: "refused", refusal: selected };
209
222
  const board = (await readBoard(world)).board;
223
+ const relations = createTaskRelations(board);
210
224
  for (const target of queryUnderTargets(expression))
211
225
  if (!board.tasks.has(target)) {
212
226
  return { kind: "refused", refusal: { kind: "task-missing", taskId: target } };
213
227
  }
214
- return { kind: "accepted", value: projectQuery(board, selected, expression, sort, limit) };
228
+ return {
229
+ kind: "accepted",
230
+ value: projectQuery(board, relations, {
231
+ scope: selected,
232
+ expression,
233
+ sort,
234
+ limit,
235
+ }),
236
+ };
215
237
  }
216
238
  /** Internal composite observation from one complete Task board read. */
217
- export async function observeTaskStatusRows(world) {
218
- return projectStatusRows((await readBoard(world)).board, null);
239
+ export async function observeTaskBoard(world) {
240
+ return projectTaskBoardObservation((await readBoard(world)).board);
219
241
  }
220
242
  /** Internal identity catalog from one complete Task board read. */
221
243
  export async function observeTaskCatalogRows(world) {
@@ -1,8 +1,10 @@
1
1
  import type { TaskPriority, TaskState } from "./document.js";
2
2
  import { type TaskId } from "./identity.js";
3
- import type { BlockedTaskRow, TaskBoard, TaskRef, TaskRow } from "./board.js";
3
+ import type { BlockedTaskRow, TaskBoard, TaskRef, TaskRelationProjection, TaskRow } from "./board.js";
4
4
  export declare const DEFAULT_TASK_LIMIT = 100;
5
5
  export declare const MAX_TASK_LIMIT = 1000;
6
+ export declare const TASK_RELATION_PREDICATE_FIELDS: readonly ["under", "needs", "blocks"];
7
+ export type TaskRelationPredicateField = (typeof TASK_RELATION_PREDICATE_FIELDS)[number];
6
8
  export type TaskQueryComparison = "=" | "!=" | "<" | "<=" | ">" | ">=" | "~";
7
9
  export type TaskQueryPredicate = Readonly<{
8
10
  field: "state";
@@ -58,7 +60,12 @@ export type TaskPage<Row> = Readonly<{
58
60
  truncated: boolean;
59
61
  }>;
60
62
  export declare function normalizeTaskQuery(value: unknown): TaskQueryExpression;
61
- export declare function projectQuery(board: TaskBoard, scope: readonly string[] | null, expression: TaskQueryExpression, sort?: TaskQuerySort, limit?: number): TaskPage<TaskQueryRow>;
63
+ export declare function projectQuery(board: TaskBoard, relations: TaskRelationProjection, input: Readonly<{
64
+ scope: readonly string[] | null;
65
+ expression: TaskQueryExpression;
66
+ sort?: TaskQuerySort;
67
+ limit?: number;
68
+ }>): TaskPage<TaskQueryRow>;
62
69
  export declare function projectPage<Row>(rows: readonly Row[], limit?: number): TaskPage<Row>;
63
70
  export declare function underExpression(parent: TaskId): TaskQueryExpression;
64
71
  export declare function queryUnderTargets(expression: TaskQueryExpression): readonly TaskId[];
@@ -1,7 +1,11 @@
1
1
  import { formatTaskId, parseTaskId, sameNamespace } from "./identity.js";
2
- import { taskDisposition } from "./board.js";
2
+ import { taskBlocked, taskDisposition, taskRef } from "./board.js";
3
3
  export const DEFAULT_TASK_LIMIT = 100;
4
4
  export const MAX_TASK_LIMIT = 1_000;
5
+ export const TASK_RELATION_PREDICATE_FIELDS = ["under", "needs", "blocks"];
6
+ function isTaskRelationPredicateField(value) {
7
+ return TASK_RELATION_PREDICATE_FIELDS.includes(value);
8
+ }
5
9
  const states = ["open", "in_progress", "on_hold", "done", "drop"];
6
10
  const comparisons = ["=", "!=", "<", "<=", ">", ">=", "~"];
7
11
  function fail(message) { throw new TypeError(message); }
@@ -97,14 +101,14 @@ function predicate(value) {
97
101
  case "title": return normalizeTextPredicate(input, "title", operator);
98
102
  case "id": return normalizeTextPredicate(input, "id", operator);
99
103
  case "parent": return normalizeParentPredicate(input, operator);
100
- case "under": return normalizeRelationPredicate(input, "under", operator);
101
- case "needs": return normalizeRelationPredicate(input, "needs", operator);
102
- case "blocks": return normalizeRelationPredicate(input, "blocks", operator);
103
104
  case "ready": return normalizeBooleanPredicate(input, "ready", operator);
104
105
  case "blocked": return normalizeBooleanPredicate(input, "blocked", operator);
105
106
  case "created": return normalizeTimestampPredicate(input, "created", operator);
106
107
  case "updated": return normalizeTimestampPredicate(input, "updated", operator);
107
- default: return fail(`unknown query field: ${field}`);
108
+ default:
109
+ if (isTaskRelationPredicateField(field))
110
+ return normalizeRelationPredicate(input, field, operator);
111
+ return fail(`unknown query field: ${field}`);
108
112
  }
109
113
  }
110
114
  export function normalizeTaskQuery(value) {
@@ -139,46 +143,24 @@ function compare(left, operator, right) {
139
143
  return left >= right;
140
144
  }
141
145
  function membership(left, operator, right) { return operator === "=" ? left === right : left !== right; }
142
- function indexChildren(board) {
143
- const children = new Map();
144
- for (const task of board.tasks.values()) {
145
- if (task.parent === null)
146
- continue;
147
- const siblings = children.get(task.parent) ?? [];
148
- siblings.push(task.id);
149
- children.set(task.parent, siblings);
150
- }
151
- return children;
152
- }
153
- function indexReverseNeeds(board) {
154
- const reverse = new Map();
155
- for (const task of board.tasks.values()) {
156
- for (const need of task.needs) {
157
- const blockers = reverse.get(need) ?? new Set();
158
- blockers.add(task.id);
159
- reverse.set(need, blockers);
160
- }
161
- }
162
- return reverse;
163
- }
164
- function descendants(children, parent) {
146
+ function descendants(relations, parent) {
165
147
  const result = new Set(), pending = [parent];
166
148
  while (pending.length > 0) {
167
149
  const current = pending.shift();
168
- for (const child of children.get(current) ?? []) {
169
- if (result.has(child))
150
+ for (const child of relations.children(current)) {
151
+ if (result.has(child.id))
170
152
  continue;
171
- result.add(child);
172
- pending.push(child);
153
+ result.add(child.id);
154
+ pending.push(child.id);
173
155
  }
174
156
  }
175
157
  return result;
176
158
  }
177
- function relation(board, reverseNeeds, id, field, target) {
159
+ function relation(board, relations, id, field, target) {
178
160
  const task = board.tasks.get(id);
179
161
  if (task === undefined)
180
162
  return false;
181
- return field === "needs" ? task.needs.includes(target) : reverseNeeds.get(target)?.has(id) === true;
163
+ return field === "needs" ? task.needs.includes(target) : relations.blocks(id).some((ref) => ref.id === target);
182
164
  }
183
165
  function matchText(left, operator, right) {
184
166
  return operator === "~" ? left.includes(right) : compare(left, operator, right);
@@ -186,18 +168,7 @@ function matchText(left, operator, right) {
186
168
  function matchRelation(selected, operator) {
187
169
  return operator === "=" ? selected : !selected;
188
170
  }
189
- function isBlocked(board, task) {
190
- const active = task.state === "open" || task.state === "in_progress";
191
- return active && task.needs.some((need) => {
192
- const target = board.tasks.get(need);
193
- return target === undefined || (target.state !== "done" && target.state !== "drop");
194
- });
195
- }
196
- function taskRef(board, id) {
197
- const task = board.tasks.get(id);
198
- return task === undefined ? { id, title: null, state: "missing" } : { id, title: task.title, state: task.state };
199
- }
200
- function matchesPredicate(board, reverseNeeds, task, value, under) {
171
+ function matchesPredicate(board, relations, task, value, under) {
201
172
  switch (value.field) {
202
173
  case "state": return compare(task.state, value.operator, value.value);
203
174
  case "priority": return compare(task.priority, value.operator, value.value);
@@ -205,32 +176,30 @@ function matchesPredicate(board, reverseNeeds, task, value, under) {
205
176
  case "id": return matchText(task.id, value.operator, value.value);
206
177
  case "parent": return compare(task.parent ?? "", value.operator, value.value ?? "");
207
178
  case "under": return matchRelation(under.get(value.value)?.has(task.id) === true, value.operator);
208
- case "needs": return matchRelation(relation(board, reverseNeeds, task.id, "needs", value.value), value.operator);
209
- case "blocks": return matchRelation(relation(board, reverseNeeds, task.id, "blocks", value.value), value.operator);
179
+ case "needs": return matchRelation(relation(board, relations, task.id, "needs", value.value), value.operator);
180
+ case "blocks": return matchRelation(relation(board, relations, task.id, "blocks", value.value), value.operator);
210
181
  case "ready": return membership(taskDisposition(board, task) === "ready", value.operator, value.value);
211
- case "blocked": return membership(isBlocked(board, task), value.operator, value.value);
182
+ case "blocked": return membership(taskBlocked(board, task), value.operator, value.value);
212
183
  case "created": return compare(task.createdAt, value.operator, value.value);
213
184
  case "updated": return compare(task.updatedAt, value.operator, value.value);
214
185
  }
215
186
  }
216
- function matches(board, reverseNeeds, task, expression, under) {
187
+ function matches(board, relations, task, expression, under) {
217
188
  if (expression.kind === "not")
218
- return !matches(board, reverseNeeds, task, expression.term, under);
189
+ return !matches(board, relations, task, expression.term, under);
219
190
  if (expression.kind !== "predicate") {
220
191
  return expression.kind === "and"
221
- ? expression.terms.every((term) => matches(board, reverseNeeds, task, term, under))
222
- : expression.terms.some((term) => matches(board, reverseNeeds, task, term, under));
192
+ ? expression.terms.every((term) => matches(board, relations, task, term, under))
193
+ : expression.terms.some((term) => matches(board, relations, task, term, under));
223
194
  }
224
- return matchesPredicate(board, reverseNeeds, task, expression.predicate, under);
195
+ return matchesPredicate(board, relations, task, expression.predicate, under);
225
196
  }
226
- function row(board, reverseNeeds, task) {
197
+ function row(board, relations, task) {
227
198
  return {
228
199
  id: task.id, title: task.title, state: task.state, priority: task.priority, disposition: taskDisposition(board, task),
229
200
  parent: task.parent,
230
201
  needs: task.needs.map((need) => taskRef(board, need)),
231
- blocks: [...(reverseNeeds.get(task.id) ?? [])]
232
- .sort((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)))
233
- .map((id) => taskRef(board, id)),
202
+ blocks: relations.blocks(task.id),
234
203
  createdAt: task.createdAt, updatedAt: task.updatedAt,
235
204
  };
236
205
  }
@@ -245,13 +214,12 @@ function sortTasks(tasks, sort) {
245
214
  return (sort === "updated" ? -compared : compared) || tie;
246
215
  });
247
216
  }
248
- export function projectQuery(board, scope, expression, sort = "priority", limit = DEFAULT_TASK_LIMIT) {
249
- const children = indexChildren(board);
250
- const reverseNeeds = indexReverseNeeds(board);
251
- const under = new Map(queryUnderTargets(expression).map((target) => [target, descendants(children, target)]));
217
+ export function projectQuery(board, relations, input) {
218
+ const { scope, expression, sort = "priority", limit = DEFAULT_TASK_LIMIT } = input;
219
+ const under = new Map(queryUnderTargets(expression).map((target) => [target, descendants(relations, target)]));
252
220
  const selected = sortTasks([...board.tasks.values()].filter((task) => scope === null || sameNamespace(parseTaskId(task.id).namespace, scope))
253
- .filter((task) => matches(board, reverseNeeds, task, expression, under)), sort);
254
- const rows = selected.slice(0, limit).map((task) => row(board, reverseNeeds, task));
221
+ .filter((task) => matches(board, relations, task, expression, under)), sort);
222
+ const rows = selected.slice(0, limit).map((task) => row(board, relations, task));
255
223
  return { rows, total: selected.length, returned: rows.length, truncated: rows.length < selected.length };
256
224
  }
257
225
  export function projectPage(rows, limit = DEFAULT_TASK_LIMIT) {
@@ -1,4 +1,5 @@
1
- import { runHookCommands, worktreeHooksFrom } from "../git/hooks.js";
1
+ import { runHookCommands } from "../git/hooks.js";
2
+ import { worktreeHooksFrom } from "../library/configuration.js";
2
3
  import { runProcess } from "../runtime/proc/run.js";
3
4
  const SUMMARY_BYTES = 32 * 1024;
4
5
  function argvFor(declaration) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "files": [
5
5
  "build"
6
6
  ],
@@ -43,6 +43,7 @@
43
43
  "test:typecheck": "tsc -p tsconfig.json --noEmit"
44
44
  },
45
45
  "devDependencies": {
46
+ "@types/cross-spawn": "^6.0.6",
46
47
  "@types/node": "^25.0.0",
47
48
  "@typescript-eslint/parser": "^8.66.0",
48
49
  "eslint": "^9.39.5",
@@ -55,6 +56,7 @@
55
56
  "@anthropic-ai/claude-agent-sdk": "^0.3.226",
56
57
  "@earendil-works/pi-coding-agent": "0.80.10",
57
58
  "@opencode-ai/sdk": "1.18.3",
59
+ "cross-spawn": "^7.0.6",
58
60
  "diff": "^8.0.4",
59
61
  "yaml": "^2.9.0"
60
62
  },