@astrosheep/keiyaku 4.5.11 → 4.5.13
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.
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +135 -377
- package/build/integrations/pi/keiyaku.ts +11 -116
- package/build/src/akuma/akuma-errors.d.ts +1 -0
- package/build/src/akuma/akuma-errors.js +1 -0
- package/build/src/akuma/akuma-handle.d.ts +1 -0
- package/build/src/akuma/akuma-handle.js +6 -7
- package/build/src/akuma/akuma-product.d.ts +6 -8
- package/build/src/akuma/akuma-product.js +141 -57
- package/build/src/akuma/akuma.d.ts +5 -7
- package/build/src/akuma/akuma.js +1 -22
- package/build/src/akuma/archetype.d.ts +6 -5
- package/build/src/akuma/archetype.js +137 -38
- package/build/src/akuma/body.d.ts +5 -5
- package/build/src/akuma/body.js +223 -63
- package/build/src/akuma/call-input.d.ts +4 -0
- package/build/src/akuma/call-input.js +21 -0
- package/build/src/akuma/call-request.d.ts +5 -8
- package/build/src/akuma/call-request.js +28 -73
- package/build/src/akuma/fleet-execution.d.ts +26 -0
- package/build/src/akuma/fleet-execution.js +109 -0
- package/build/src/{library/fleet-result.d.ts → akuma/fleet-observation.d.ts} +13 -57
- package/build/src/{library/fleet-result.js → akuma/fleet-observation.js} +4 -25
- package/build/src/akuma/fleet-request.d.ts +122 -0
- package/build/src/akuma/fleet-request.js +168 -0
- package/build/src/akuma/heart/facts.d.ts +23 -0
- package/build/src/akuma/heart/facts.js +7 -0
- package/build/src/akuma/heart/index.d.ts +43 -4
- package/build/src/akuma/heart/index.js +107 -7
- package/build/src/akuma/heart/request-authority.d.ts +2 -0
- package/build/src/akuma/heart/request-authority.js +28 -3
- package/build/src/akuma/heart/request-rows.d.ts +2 -0
- package/build/src/akuma/heart/request-rows.js +24 -5
- package/build/src/akuma/heart/rows.d.ts +4 -1
- package/build/src/akuma/heart/rows.js +46 -19
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +28 -6
- package/build/src/akuma/heart/storage.d.ts +1 -1
- package/build/src/akuma/heart/tells.d.ts +29 -0
- package/build/src/akuma/heart/tells.js +136 -5
- package/build/src/akuma/heart/timeline.js +9 -3
- package/build/src/akuma/projection-read.js +36 -3
- package/build/src/akuma/projection.js +3 -4
- package/build/src/akuma/provider.d.ts +4 -0
- package/build/src/akuma/provider.js +56 -3
- package/build/src/akuma/providers/claude/index.js +3 -0
- package/build/src/akuma/providers/codex-app-server/index.js +14 -12
- package/build/src/akuma/providers/pi/index.js +7 -1
- package/build/src/akuma/publication.js +65 -49
- package/build/src/akuma/request-lifecycle.d.ts +5 -4
- package/build/src/akuma/request-lifecycle.js +29 -16
- package/build/src/akuma/request-rendezvous.d.ts +15 -12
- package/build/src/akuma/request-rendezvous.js +80 -51
- package/build/src/akuma/request-serve.d.ts +1 -2
- package/build/src/akuma/request-serve.js +94 -39
- package/build/src/akuma/request-wire.d.ts +57 -26
- package/build/src/akuma/request-wire.js +64 -25
- package/build/src/akuma/turn-drive.d.ts +5 -4
- package/build/src/akuma/turn-drive.js +27 -11
- package/build/src/akuma-body.d.ts +4 -6
- package/build/src/akuma-body.js +19 -17
- package/build/src/bounded-list.d.ts +8 -0
- package/build/src/bounded-list.js +14 -0
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +1 -0
- package/build/src/cli/commands/akuma-invoke.js +1 -25
- package/build/src/cli/commands/contract-help.d.ts +5 -2
- package/build/src/cli/commands/contract-help.js +62 -12
- package/build/src/cli/commands/contract-invoke.d.ts +5 -0
- package/build/src/cli/commands/contract-invoke.js +26 -1
- package/build/src/cli/commands/contract.js +50 -18
- package/build/src/cli/commands/task-invoke.js +10 -2
- package/build/src/cli/commands/task-query.js +3 -4
- package/build/src/cli/coordinates.d.ts +13 -0
- package/build/src/cli/coordinates.js +38 -24
- package/build/src/cli/draft.d.ts +1 -1
- package/build/src/cli/invoke.js +14 -1
- package/build/src/cli/render/akuma-activity.d.ts +0 -1
- package/build/src/cli/render/akuma-activity.js +5 -38
- package/build/src/cli/render/akuma.js +4 -1
- package/build/src/cli/render/audit.js +4 -1
- package/build/src/cli/render/catalog.js +13 -39
- package/build/src/cli/render/contract.js +4 -14
- package/build/src/cli/render/kanshi-akuma.js +3 -8
- package/build/src/cli/render/kanshi.js +8 -34
- package/build/src/cli/render/nuke.js +7 -3
- package/build/src/cli/render/receipt.d.ts +1 -0
- package/build/src/cli/render/receipt.js +8 -0
- package/build/src/cli/render/refusal.js +4 -3
- package/build/src/cli/render/task.js +4 -37
- package/build/src/cli/render/terminal.d.ts +2 -6
- package/build/src/cli/render/terminal.js +4 -9
- package/build/src/cli/result.d.ts +2 -1
- package/build/src/contract-guidance.js +13 -3
- package/build/src/contract-worktree.d.ts +1 -0
- package/build/src/contract-worktree.js +26 -2
- package/build/src/core/facts/codec.d.ts +2 -1
- package/build/src/core/facts/codec.js +3 -0
- package/build/src/core/facts/gate.d.ts +2 -1
- package/build/src/core/facts/gate.js +63 -0
- package/build/src/core/verbs/abandon.d.ts +2 -1
- package/build/src/core/verbs/abandon.js +16 -0
- package/build/src/core/verbs/amend.d.ts +2 -1
- package/build/src/core/verbs/amend.js +20 -0
- package/build/src/core/verbs/arc.d.ts +2 -1
- package/build/src/core/verbs/arc.js +16 -0
- package/build/src/core/verbs/attestation.d.ts +2 -1
- package/build/src/core/verbs/attestation.js +16 -0
- package/build/src/core/verbs/bind.d.ts +2 -1
- package/build/src/core/verbs/bind.js +16 -0
- package/build/src/core/verbs/deliver.d.ts +2 -1
- package/build/src/core/verbs/deliver.js +16 -0
- package/build/src/core/verbs/placement.d.ts +2 -1
- package/build/src/core/verbs/placement.js +58 -1
- package/build/src/dispatch/association.d.ts +13 -0
- package/build/src/dispatch/association.js +20 -0
- package/build/src/dispatch/index.d.ts +6 -0
- package/build/src/dispatch/index.js +27 -3
- package/build/src/git/hooks.d.ts +9 -1
- package/build/src/git/hooks.js +79 -1
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +6 -11
- package/build/src/git/private-state-seat.d.ts +26 -1
- package/build/src/git/private-state-seat.js +78 -13
- package/build/src/git/process.d.ts +2 -0
- package/build/src/git/reconcile.d.ts +1 -2
- package/build/src/git/reconcile.js +0 -6
- package/build/src/git/repository.d.ts +0 -2
- package/build/src/git/repository.js +27 -25
- package/build/src/git/result-codec.d.ts +29 -0
- package/build/src/git/result-codec.js +306 -0
- package/build/src/git/target-placement.js +2 -8
- package/build/src/git/workspace.d.ts +2 -0
- package/build/src/git/workspace.js +4 -0
- package/build/src/index.d.ts +1 -0
- package/build/src/kanshi/fleet.js +1 -1
- package/build/src/kanshi/read.js +55 -28
- package/build/src/kanshi/report.d.ts +4 -3
- package/build/src/kanshi/select.js +14 -1
- package/build/src/library/address.d.ts +1 -0
- package/build/src/library/address.js +4 -7
- package/build/src/library/akuma-creation.d.ts +5 -3
- package/build/src/library/akuma-creation.js +90 -33
- package/build/src/library/audit.js +2 -1
- package/build/src/library/catalog.d.ts +10 -2
- package/build/src/library/catalog.js +65 -25
- package/build/src/library/composition.d.ts +1 -0
- package/build/src/library/composition.js +1 -0
- package/build/src/library/configuration.d.ts +4 -21
- package/build/src/library/configuration.js +2 -158
- package/build/src/library/continuation.d.ts +20 -1
- package/build/src/library/continuation.js +36 -0
- package/build/src/library/contract-bind.d.ts +1 -0
- package/build/src/library/contract-bind.js +16 -5
- package/build/src/library/contract-forwarding.d.ts +2 -2
- package/build/src/library/contract-forwarding.js +18 -4
- package/build/src/library/contract-handle.js +4 -3
- package/build/src/library/contract-operations.d.ts +5 -9
- package/build/src/library/contract-operations.js +34 -47
- package/build/src/library/contract.d.ts +11 -2
- package/build/src/library/contract.js +21 -1
- package/build/src/library/delivery.d.ts +4 -1
- package/build/src/library/delivery.js +47 -0
- package/build/src/library/fleet.d.ts +4 -136
- package/build/src/library/fleet.js +31 -315
- package/build/src/library/keiyaku.d.ts +7 -3
- package/build/src/library/keiyaku.js +1 -0
- package/build/src/library/mutation.d.ts +431 -3
- package/build/src/library/mutation.js +192 -19
- package/build/src/library/nuke.d.ts +7 -1
- package/build/src/library/nuke.js +18 -4
- package/build/src/library/reconcile.d.ts +14 -0
- package/build/src/library/reconcile.js +22 -8
- package/build/src/library/refusal.d.ts +9 -1
- package/build/src/library/refusal.js +76 -0
- package/build/src/library/region.d.ts +0 -8
- package/build/src/library/region.js +1 -29
- package/build/src/library/result-codec.d.ts +2 -0
- package/build/src/library/result-codec.js +12 -0
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/types.d.ts +2 -1
- package/build/src/markdown/types.js +3 -1
- package/build/src/plugin/akuma-signals.d.ts +12 -0
- package/build/src/plugin/akuma-signals.js +14 -0
- package/build/src/plugin/public.d.ts +51 -0
- package/build/src/plugin/public.js +1 -0
- package/build/src/plugin/runtime.d.ts +14 -0
- package/build/src/plugin/runtime.js +357 -0
- package/build/src/protocol/amend.js +3 -3
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/attempt.js +1 -1
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +1 -1
- package/build/src/protocol/bind.d.ts +3 -1
- package/build/src/protocol/bind.js +26 -0
- package/build/src/protocol/completion.js +0 -1
- package/build/src/protocol/deliver.d.ts +1 -1
- package/build/src/protocol/deliver.js +136 -57
- package/build/src/protocol/intent.d.ts +0 -1
- package/build/src/protocol/intent.js +0 -1
- package/build/src/protocol/operations.d.ts +9 -2
- package/build/src/protocol/operations.js +16 -1
- package/build/src/protocol/outcome.d.ts +3 -0
- package/build/src/protocol/outcome.js +17 -1
- package/build/src/protocol/placement.js +10 -3
- package/build/src/protocol/read/status.d.ts +8 -0
- package/build/src/protocol/read/status.js +49 -0
- package/build/src/protocol/reintegrate.js +10 -3
- package/build/src/protocol/result-codec.d.ts +22 -0
- package/build/src/protocol/result-codec.js +442 -0
- package/build/src/protocol/review.d.ts +1 -1
- package/build/src/protocol/review.js +81 -46
- package/build/src/protocol/run.d.ts +22 -2
- package/build/src/protocol/run.js +119 -29
- package/build/src/runtime/proc/lifecycle.js +1 -1
- package/build/src/runtime/proc/line-rpc.d.ts +7 -1
- package/build/src/runtime/proc/line-rpc.js +49 -9
- package/build/src/runtime/proc/run.d.ts +0 -1
- package/build/src/runtime/proc/run.js +1 -11
- package/build/src/runtime/proc/termination.d.ts +1 -0
- package/build/src/runtime/proc/termination.js +63 -18
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.d.ts +10 -0
- package/build/src/settings.js +88 -2
- package/build/src/settlement/result-codec.d.ts +2 -0
- package/build/src/settlement/result-codec.js +56 -0
- package/build/src/settlement/settle.d.ts +5 -12
- package/build/src/settlement/settle.js +60 -55
- package/build/src/task/board.d.ts +3 -0
- package/build/src/task/board.js +22 -4
- package/build/src/task/catalog.d.ts +13 -2
- package/build/src/task/catalog.js +59 -5
- package/build/src/task/compose.d.ts +4 -2
- package/build/src/task/compose.js +56 -30
- package/build/src/task/created-observation.d.ts +39 -0
- package/build/src/task/created-observation.js +26 -0
- package/build/src/task/identity.d.ts +6 -0
- package/build/src/task/identity.js +48 -7
- package/build/src/task/index.d.ts +4 -3
- package/build/src/task/index.js +19 -16
- package/build/src/task/input.d.ts +3 -1
- package/build/src/task/input.js +7 -4
- package/build/src/task/lifecycle-operations.d.ts +6 -0
- package/build/src/task/lifecycle-operations.js +116 -0
- package/build/src/task/mutation-result.d.ts +762 -20
- package/build/src/task/mutation-result.js +34 -9
- package/build/src/task/mutation.d.ts +4 -9
- package/build/src/task/mutation.js +17 -52
- package/build/src/task/operation-types.d.ts +114 -0
- package/build/src/task/operation-types.js +1 -0
- package/build/src/task/operations.d.ts +6 -113
- package/build/src/task/operations.js +75 -117
- package/build/src/task/query.d.ts +8 -11
- package/build/src/task/query.js +7 -14
- package/build/src/task/store.d.ts +11 -1
- package/build/src/task/store.js +169 -55
- package/build/src/task/view.d.ts +4 -0
- package/build/src/task/view.js +7 -0
- package/build/src/verification/declaration.d.ts +1 -0
- package/build/src/verification/declaration.js +18 -1
- package/build/src/verification/execution.d.ts +0 -1
- package/build/src/verification/execution.js +5 -5
- package/build/src/world.d.ts +0 -2
- package/build/src/world.js +3 -7
- package/package.json +17 -5
- package/build/src/cli/square-edge.d.ts +0 -7
- package/build/src/cli/square-edge.js +0 -159
- package/build/src/git/ref-migration.d.ts +0 -22
- package/build/src/git/ref-migration.js +0 -55
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +0 -102
- package/build/src/library/contract-forwarding-reconciliation-result.js +0 -92
- package/build/src/library/contract-forwarding-result.d.ts +0 -4270
- package/build/src/library/contract-forwarding-result.js +0 -521
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { contractSegment } from "../core/facts/types.js";
|
|
2
4
|
import { identityCoordinate, identitySegments } from "../identity/coordinates.js";
|
|
3
5
|
import { normalizeIdentityStem } from "../identity/normalize.js";
|
|
4
6
|
const STEM_CODE_POINTS = 32;
|
|
7
|
+
const TASK_FILENAME_BYTES = 255;
|
|
8
|
+
const TASK_EXTENSION_BYTES = Buffer.byteLength(".md");
|
|
9
|
+
const TASK_LOCK_EXTENSION_BYTES = Buffer.byteLength(".sqlite");
|
|
10
|
+
const GENERATED_SUFFIX = "-0000";
|
|
11
|
+
export const TASK_LOCK_ID_BYTES = TASK_FILENAME_BYTES - TASK_LOCK_EXTENSION_BYTES;
|
|
12
|
+
export const TASK_LOCAL_ID_BYTES = TASK_FILENAME_BYTES - TASK_EXTENSION_BYTES - TASK_LOCK_EXTENSION_BYTES - Buffer.byteLength(GENERATED_SUFFIX);
|
|
13
|
+
const GENERATED_STEM_BYTES = TASK_LOCAL_ID_BYTES - Buffer.byteLength(GENERATED_SUFFIX);
|
|
14
|
+
const WINDOWS_RESERVED = /^(?:con|prn|aux|nul|clock\$|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
|
|
5
15
|
export function isTaskSegment(value) {
|
|
6
16
|
return (value.length > 0 &&
|
|
7
17
|
value !== "." &&
|
|
@@ -26,8 +36,19 @@ export function formatTaskId(coordinate) {
|
|
|
26
36
|
throw new TypeError("task coordinate contains a noncanonical segment");
|
|
27
37
|
return identityCoordinate({ family: "task", segments: [...coordinate.namespace, coordinate.localId] });
|
|
28
38
|
}
|
|
39
|
+
export function canonicalTaskId(value) {
|
|
40
|
+
const id = formatTaskId(parseTaskId(value));
|
|
41
|
+
if (id !== value)
|
|
42
|
+
throw new TypeError("task ID is not canonical");
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
45
|
+
export function contractNamespace(id) {
|
|
46
|
+
return ["kei", contractSegment(id)];
|
|
47
|
+
}
|
|
29
48
|
export function taskAuthorityPath(tasksDirectory, coordinate) {
|
|
30
|
-
|
|
49
|
+
if (![...coordinate.namespace, coordinate.localId].every(isTaskSegment))
|
|
50
|
+
throw new TypeError("task coordinate contains a noncanonical segment");
|
|
51
|
+
return join(tasksDirectory, ...coordinate.namespace.map((segment) => physicalTaskSegment(segment)), `${physicalTaskSegment(coordinate.localId)}.md`);
|
|
31
52
|
}
|
|
32
53
|
export function deriveLocalStem(title) {
|
|
33
54
|
const stem = normalizeIdentityStem({ source: title });
|
|
@@ -43,17 +64,37 @@ export function deriveLocalStem(title) {
|
|
|
43
64
|
fitted += `-${word}`;
|
|
44
65
|
count = candidate;
|
|
45
66
|
}
|
|
46
|
-
return fitted;
|
|
67
|
+
return fitPhysicalStem(fitted);
|
|
47
68
|
}
|
|
48
69
|
export function allocateLocalId(stem, occupied) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const candidate = `${stem}-${suffix}`;
|
|
70
|
+
const seed = randomBytes(2).readUInt16BE(0);
|
|
71
|
+
for (let offset = 0; offset <= 0xffff; offset += 1) {
|
|
72
|
+
const suffix = ((seed + offset) & 0xffff).toString(16).padStart(4, "0");
|
|
73
|
+
const candidate = `${fitPhysicalStem(stem, suffix)}-${suffix}`;
|
|
53
74
|
if (!occupied.has(candidate))
|
|
54
75
|
return candidate;
|
|
55
76
|
}
|
|
56
|
-
throw new Error("task identity
|
|
77
|
+
throw new Error("task identity hexadecimal suffix space exhausted");
|
|
78
|
+
}
|
|
79
|
+
function fitPhysicalStem(stem, suffix) {
|
|
80
|
+
const maxBytes = suffix === undefined ? GENERATED_STEM_BYTES : TASK_LOCAL_ID_BYTES - Buffer.byteLength(`-${suffix}`);
|
|
81
|
+
let result = "";
|
|
82
|
+
for (const segment of new Intl.Segmenter("und", { granularity: "grapheme" }).segment(stem)) {
|
|
83
|
+
if (Buffer.byteLength(result + segment.segment) > maxBytes)
|
|
84
|
+
break;
|
|
85
|
+
result += segment.segment;
|
|
86
|
+
}
|
|
87
|
+
result = result.replace(/-+$/u, "");
|
|
88
|
+
if (result.length === 0)
|
|
89
|
+
throw new TypeError("task title cannot fit the physical filename budget");
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
export function physicalTaskSegment(segment, maxBytes = TASK_LOCAL_ID_BYTES) {
|
|
93
|
+
if (Buffer.byteLength(segment) <= maxBytes && !WINDOWS_RESERVED.test(segment))
|
|
94
|
+
return segment;
|
|
95
|
+
if (Buffer.byteLength(segment) > maxBytes)
|
|
96
|
+
throw new TypeError("task identity cannot fit the physical filename budget");
|
|
97
|
+
throw new TypeError("task identity contains a Windows-reserved physical segment");
|
|
57
98
|
}
|
|
58
99
|
export function sameNamespace(left, right) {
|
|
59
100
|
return left.length === right.length && left.every((segment, index) => segment === right[index]);
|
|
@@ -5,7 +5,7 @@ import { type BlockedTaskRow, type TaskDetailFacts, type TaskDoctorIssue, type T
|
|
|
5
5
|
import { type TaskCompositionAlias, type TaskCompositionBodyPreview, type TaskCompositionResult } from "./compose.js";
|
|
6
6
|
import { TaskAuthorityCorruptionError, type TaskPriority, type TaskState } from "./document.js";
|
|
7
7
|
import type { TaskId } from "./identity.js";
|
|
8
|
-
import { type AddTaskDocumentInput, type AddTaskInput, type TaskBatchResult, type TaskCompositionDiagnostic, type TaskMutationResult, type TaskOutcome, type TaskRefusal, type TaskRetry, type TaskUpdateResult, type TaskView, type UpdateTaskInput } from "./operations.js";
|
|
8
|
+
import { type AddTaskDocumentInput, type AddTaskInput, type TaskBatchResult, type TaskCleanupFailure, type TaskCompositionDiagnostic, type TaskMutationResult, type TaskOutcome, type TaskRefusal, type TaskRetry, type TaskUpdateResult, type TaskView, type UpdateTaskInput } from "./operations.js";
|
|
9
9
|
import { TASK_RELATION_PREDICATE_FIELDS, type TaskPage, type TaskQueryExpression, type TaskQueryPredicate, type TaskQueryRow, type TaskQuerySort, type TaskRelationPredicateField } from "./query.js";
|
|
10
10
|
export type TaskDetail = Omit<TaskDetailFacts, "task"> & Readonly<{
|
|
11
11
|
task: TaskView;
|
|
@@ -23,9 +23,11 @@ export type TaskDoctorReport = Readonly<{
|
|
|
23
23
|
issues: readonly TaskDoctorIssue[];
|
|
24
24
|
}>;
|
|
25
25
|
export type TaskDecompositionTree = TaskOutcome<TaskTreeNode>;
|
|
26
|
-
export type { AddTaskDocumentInput, AddTaskInput, BlockedTaskRow, TaskBatchResult, TaskCompositionDiagnostic, TaskCompositionAlias, TaskCompositionBodyPreview, TaskCompositionResult, TaskDoctorIssue, TaskId, TaskMutationResult, TaskOutcome, TaskPriority, TaskRef, TaskRefusal, TaskRetry, TaskRow, TaskState, TaskTreeNode, TaskUpdateResult, TaskView, UpdateTaskInput, TaskPage, TaskQueryExpression, TaskQueryPredicate, TaskQueryRow, TaskQuerySort, TaskRelationPredicateField, };
|
|
26
|
+
export type { AddTaskDocumentInput, AddTaskInput, BlockedTaskRow, TaskBatchResult, TaskCleanupFailure, TaskCompositionDiagnostic, TaskCompositionAlias, TaskCompositionBodyPreview, TaskCompositionResult, TaskDoctorIssue, TaskId, TaskMutationResult, TaskOutcome, TaskPriority, TaskRef, TaskRefusal, TaskRetry, TaskRow, TaskState, TaskTreeNode, TaskUpdateResult, TaskView, UpdateTaskInput, TaskPage, TaskQueryExpression, TaskQueryPredicate, TaskQueryRow, TaskQuerySort, TaskRelationPredicateField, };
|
|
27
27
|
export type { LibraryExecution } from "../akuma/requests.js";
|
|
28
28
|
export { TaskAuthorityCorruptionError, TASK_RELATION_PREDICATE_FIELDS };
|
|
29
|
+
export { observeRecentTaskStatus, type RecentTaskStatusRow } from "./catalog.js";
|
|
30
|
+
export { taskRowViewLimit } from "./input.js";
|
|
29
31
|
declare class TaskHandle {
|
|
30
32
|
readonly id: TaskId;
|
|
31
33
|
private readonly world;
|
|
@@ -108,7 +110,6 @@ declare class TasksHandle {
|
|
|
108
110
|
}>): Promise<TaskCompositionResult>;
|
|
109
111
|
}
|
|
110
112
|
export type Tasks = TasksHandle;
|
|
111
|
-
export declare function tasksForExecution(world: WorldRoot, execution: ExecutionContext): Tasks;
|
|
112
113
|
type TasksOfInput = Readonly<{
|
|
113
114
|
execution?: LibraryExecution;
|
|
114
115
|
}>;
|
package/build/src/task/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { executionChannel, libraryExecution, localExecutionContext, } from "../akuma/requests.js";
|
|
2
2
|
import { requestForwardedTask } from "./mutation.js";
|
|
3
|
-
import { buildTree, createTaskRelations, diagnoseBoard,
|
|
3
|
+
import { buildTree, createTaskRelations, diagnoseBoard, } from "./board.js";
|
|
4
4
|
import { composeTasks, } from "./compose.js";
|
|
5
5
|
import { TaskAuthorityCorruptionError } from "./document.js";
|
|
6
|
-
import { addTask, addTaskDocument, batchTasks, blockedTasks, lifecycleTask, listTasks, queryTasks, readyTasks, taskView, updateTask, } from "./operations.js";
|
|
6
|
+
import { addTask, addTaskDocument, batchTasks, blockedTasks, lifecycleTask, listTasks, queryTasks, readTaskDetail, readyTasks, taskView, updateTask, } from "./operations.js";
|
|
7
7
|
import { readBoard } from "./store.js";
|
|
8
|
-
import { actor, addInput, closed,
|
|
9
|
-
import { normalizeTaskQuery, TASK_RELATION_PREDICATE_FIELDS,
|
|
8
|
+
import { actor, addInput, closed, namespace, record, signal, sort, taskRowViewLimit, taskId as id, taskIds, text, updateInput, } from "./input.js";
|
|
9
|
+
import { normalizeTaskQuery, TASK_RELATION_PREDICATE_FIELDS, } from "./query.js";
|
|
10
10
|
export { TaskAuthorityCorruptionError, TASK_RELATION_PREDICATE_FIELDS };
|
|
11
|
+
export { observeRecentTaskStatus } from "./catalog.js";
|
|
12
|
+
export { taskRowViewLimit } from "./input.js";
|
|
11
13
|
function forwardTask(directory, world, request, signal) {
|
|
12
14
|
return requestForwardedTask({
|
|
13
15
|
directory,
|
|
@@ -26,8 +28,7 @@ class TaskHandle {
|
|
|
26
28
|
this.execution = execution;
|
|
27
29
|
}
|
|
28
30
|
async read() {
|
|
29
|
-
const
|
|
30
|
-
const facts = projectDetailFacts(board, this.id, createTaskRelations(board));
|
|
31
|
+
const facts = await readTaskDetail(this.world, this.id);
|
|
31
32
|
return facts === null ? null : { ...facts, task: taskView(facts.task) };
|
|
32
33
|
}
|
|
33
34
|
async tree() {
|
|
@@ -140,7 +141,8 @@ class TasksHandle {
|
|
|
140
141
|
throw new TypeError("selection must be active, closed, or all");
|
|
141
142
|
if (v.scope !== undefined && v.scope !== "namespace" && v.scope !== "world")
|
|
142
143
|
throw new TypeError("scope must be namespace or world");
|
|
143
|
-
|
|
144
|
+
const selectedLimit = taskRowViewLimit(v.limit);
|
|
145
|
+
return listTasks(this.world, namespace(v.namespace), v.selection ?? "active", v.scope, selectedLimit);
|
|
144
146
|
}
|
|
145
147
|
async ready(input = {}) {
|
|
146
148
|
const v = record(input, "ready input");
|
|
@@ -148,7 +150,8 @@ class TasksHandle {
|
|
|
148
150
|
if (v.scope !== undefined && v.scope !== "namespace" && v.scope !== "world")
|
|
149
151
|
throw new TypeError("scope must be namespace or world");
|
|
150
152
|
const parent = v.parent === undefined ? undefined : id(v.parent);
|
|
151
|
-
|
|
153
|
+
const selectedLimit = taskRowViewLimit(v.limit);
|
|
154
|
+
return readyTasks(this.world, namespace(v.namespace), v.scope, parent, selectedLimit);
|
|
152
155
|
}
|
|
153
156
|
async blocked(input = {}) {
|
|
154
157
|
const v = record(input, "blocked input");
|
|
@@ -156,7 +159,8 @@ class TasksHandle {
|
|
|
156
159
|
if (v.scope !== undefined && v.scope !== "namespace" && v.scope !== "world")
|
|
157
160
|
throw new TypeError("scope must be namespace or world");
|
|
158
161
|
const parent = v.parent === undefined ? undefined : id(v.parent);
|
|
159
|
-
|
|
162
|
+
const selectedLimit = taskRowViewLimit(v.limit);
|
|
163
|
+
return blockedTasks(this.world, namespace(v.namespace), v.scope, parent, selectedLimit);
|
|
160
164
|
}
|
|
161
165
|
async query(input = {}) {
|
|
162
166
|
const v = record(input, "query input");
|
|
@@ -173,13 +177,14 @@ class TasksHandle {
|
|
|
173
177
|
}
|
|
174
178
|
: normalizeTaskQuery(v.where);
|
|
175
179
|
const selected = namespace(v.namespace);
|
|
180
|
+
const selectedLimit = taskRowViewLimit(v.limit);
|
|
176
181
|
return queryTasks({
|
|
177
182
|
world: this.world,
|
|
178
183
|
...(selected === undefined ? {} : { namespace: selected }),
|
|
179
184
|
expression,
|
|
180
185
|
...(v.scope === undefined ? {} : { scope: v.scope }),
|
|
181
186
|
sort: sort(v.sort) ?? "priority",
|
|
182
|
-
limit:
|
|
187
|
+
limit: selectedLimit,
|
|
183
188
|
});
|
|
184
189
|
}
|
|
185
190
|
async doctor() {
|
|
@@ -239,11 +244,6 @@ class TasksHandle {
|
|
|
239
244
|
return composeTasks(local);
|
|
240
245
|
}
|
|
241
246
|
}
|
|
242
|
-
export function tasksForExecution(world, execution) {
|
|
243
|
-
if (typeof world !== "string")
|
|
244
|
-
throw new TypeError("Tasks.of world must be a WorldRoot");
|
|
245
|
-
return new TasksHandle(world, execution);
|
|
246
|
-
}
|
|
247
247
|
function tasksOfExecution(input) {
|
|
248
248
|
if (input === undefined)
|
|
249
249
|
return localExecutionContext();
|
|
@@ -253,6 +253,9 @@ function tasksOfExecution(input) {
|
|
|
253
253
|
}
|
|
254
254
|
export const Tasks = Object.freeze({
|
|
255
255
|
of(world, input) {
|
|
256
|
-
|
|
256
|
+
const execution = tasksOfExecution(input);
|
|
257
|
+
if (typeof world !== "string")
|
|
258
|
+
throw new TypeError("Tasks.of world must be a WorldRoot");
|
|
259
|
+
return new TasksHandle(world, execution);
|
|
257
260
|
},
|
|
258
261
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type TaskPriority, type TaskState } from "./document.js";
|
|
2
2
|
import { type TaskId } from "./identity.js";
|
|
3
3
|
import type { AddTaskInput, UpdateTaskInput } from "./operations.js";
|
|
4
|
-
import {
|
|
4
|
+
import type { TaskQuerySort } from "./query.js";
|
|
5
5
|
export declare function record(value: unknown, label: string): Record<string, unknown>;
|
|
6
6
|
export declare function closed(value: Record<string, unknown>, allowed: readonly string[], label: string): void;
|
|
7
7
|
export declare function taskId(value: unknown): TaskId;
|
|
@@ -12,6 +12,8 @@ export declare function text(value: unknown, label: string): string | undefined;
|
|
|
12
12
|
export declare function actor(value: unknown): string | undefined;
|
|
13
13
|
export declare function priority(value: unknown): TaskPriority | undefined;
|
|
14
14
|
export declare function limit(value: unknown): number | undefined;
|
|
15
|
+
/** Validates and supplies the shared bounded-list limit for Task row views. */
|
|
16
|
+
export declare function taskRowViewLimit(value: unknown): number;
|
|
15
17
|
export declare function sort(value: unknown): TaskQuerySort | undefined;
|
|
16
18
|
export declare function state(value: unknown): TaskState | undefined;
|
|
17
19
|
export declare function addInput(input: unknown): AddTaskInput;
|
package/build/src/task/input.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isTaskSegment, parseTaskId } from "./identity.js";
|
|
2
|
-
import {
|
|
2
|
+
import { boundedListLimit } from "../bounded-list.js";
|
|
3
3
|
export function record(value, label) {
|
|
4
4
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
5
5
|
throw new TypeError(`${label} must be an object`);
|
|
@@ -74,11 +74,14 @@ export function priority(value) {
|
|
|
74
74
|
export function limit(value) {
|
|
75
75
|
if (value === undefined)
|
|
76
76
|
return undefined;
|
|
77
|
-
if (typeof value !== "number"
|
|
78
|
-
throw new TypeError(
|
|
79
|
-
}
|
|
77
|
+
if (typeof value !== "number")
|
|
78
|
+
throw new TypeError("limit must be a number");
|
|
80
79
|
return value;
|
|
81
80
|
}
|
|
81
|
+
/** Validates and supplies the shared bounded-list limit for Task row views. */
|
|
82
|
+
export function taskRowViewLimit(value) {
|
|
83
|
+
return boundedListLimit(value);
|
|
84
|
+
}
|
|
82
85
|
export function sort(value) {
|
|
83
86
|
if (value === undefined)
|
|
84
87
|
return undefined;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type SettledTaskResult, type TaskBatchResult, type TaskLifecycleVerb, type TaskMutationResult } from "./operation-types.js";
|
|
2
|
+
import type { TaskId } from "./identity.js";
|
|
3
|
+
import type { WorldRoot } from "../world.js";
|
|
4
|
+
export declare function lifecycleTask(world: WorldRoot, id: TaskId, verb: TaskLifecycleVerb, signal?: AbortSignal, note?: string): Promise<TaskMutationResult>;
|
|
5
|
+
export declare function batchTasks(world: WorldRoot, verb: "start" | "done" | "drop" | "hold", ids: readonly TaskId[], signal?: AbortSignal, note?: string): Promise<TaskBatchResult>;
|
|
6
|
+
export declare function settleTask(world: WorldRoot, id: TaskId): Promise<SettledTaskResult>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { serializeTaskDocument } from "./document.js";
|
|
2
|
+
import { authorityBytesMatch, readBoard, replaceAuthority, withTaskLocks } from "./store.js";
|
|
3
|
+
import { advanceTaskTimestamp, taskView } from "./view.js";
|
|
4
|
+
const TRANSITIONS = {
|
|
5
|
+
start: { open: "in_progress" },
|
|
6
|
+
stop: { in_progress: "open" },
|
|
7
|
+
hold: { open: "on_hold", in_progress: "on_hold" },
|
|
8
|
+
resume: { on_hold: "open" },
|
|
9
|
+
done: { open: "done", in_progress: "done", on_hold: "done" },
|
|
10
|
+
drop: { open: "drop", in_progress: "drop", on_hold: "drop" },
|
|
11
|
+
};
|
|
12
|
+
function currentTaskBoard(board, bytes) {
|
|
13
|
+
return { board, bytes: new Map(bytes) };
|
|
14
|
+
}
|
|
15
|
+
function retry(reason) {
|
|
16
|
+
return { kind: "retry", reason };
|
|
17
|
+
}
|
|
18
|
+
async function transitionLifecycle(world, id, verb, currentBoard, options = {}) {
|
|
19
|
+
const { note, freshness = "none" } = options;
|
|
20
|
+
const current = currentBoard.board.tasks.get(id);
|
|
21
|
+
if (current === undefined) {
|
|
22
|
+
return freshness === "batch" && !(await authorityBytesMatch(world, id, null))
|
|
23
|
+
? retry("concurrent-modification")
|
|
24
|
+
: { kind: "refused", refusal: { kind: "task-missing", taskId: id } };
|
|
25
|
+
}
|
|
26
|
+
const state = TRANSITIONS[verb][current.state];
|
|
27
|
+
if (state === undefined) {
|
|
28
|
+
return freshness === "batch" && !(await authorityBytesMatch(world, id, currentBoard.bytes.get(id)))
|
|
29
|
+
? retry("concurrent-modification")
|
|
30
|
+
: { kind: "refused", refusal: { kind: "invalid-lifecycle-transition", taskId: id, state: current.state, verb } };
|
|
31
|
+
}
|
|
32
|
+
const at = new Date().toISOString();
|
|
33
|
+
const next = {
|
|
34
|
+
...current,
|
|
35
|
+
state,
|
|
36
|
+
...(note === undefined ? {} : { note }),
|
|
37
|
+
updatedAt: advanceTaskTimestamp(current.updatedAt, at),
|
|
38
|
+
};
|
|
39
|
+
const bytes = serializeTaskDocument(next);
|
|
40
|
+
if ((await replaceAuthority({
|
|
41
|
+
world,
|
|
42
|
+
id,
|
|
43
|
+
expected: currentBoard.bytes.get(id),
|
|
44
|
+
next: bytes,
|
|
45
|
+
})) !== "replaced") {
|
|
46
|
+
return retry("concurrent-modification");
|
|
47
|
+
}
|
|
48
|
+
currentBoard.board = {
|
|
49
|
+
tasks: new Map(currentBoard.board.tasks).set(id, next),
|
|
50
|
+
};
|
|
51
|
+
currentBoard.bytes.set(id, bytes);
|
|
52
|
+
return { kind: "accepted", value: taskView(next) };
|
|
53
|
+
}
|
|
54
|
+
async function lifecycleFromCurrentBoard(world, id, verb, currentBoard, options = {}) {
|
|
55
|
+
const { signal, note } = options;
|
|
56
|
+
const result = await withTaskLocks({ world, allocation: false, ids: [id], ...(signal === undefined ? {} : { signal }) }, async () => transitionLifecycle(world, id, verb, currentBoard, {
|
|
57
|
+
freshness: "batch",
|
|
58
|
+
...(note === undefined ? {} : { note }),
|
|
59
|
+
}));
|
|
60
|
+
return result === "busy" ? retry("busy") : result;
|
|
61
|
+
}
|
|
62
|
+
export async function lifecycleTask(world, id, verb, signal, note) {
|
|
63
|
+
const result = await withTaskLocks({ world, allocation: false, ids: [id], ...(signal === undefined ? {} : { signal }) }, async () => {
|
|
64
|
+
const snapshot = await readBoard(world);
|
|
65
|
+
const options = note === undefined ? {} : { note };
|
|
66
|
+
return transitionLifecycle(world, id, verb, currentTaskBoard(snapshot.board, snapshot.bytes), options);
|
|
67
|
+
});
|
|
68
|
+
return result === "busy" ? retry("busy") : result;
|
|
69
|
+
}
|
|
70
|
+
export async function batchTasks(world, verb, ids, signal, note) {
|
|
71
|
+
signal?.throwIfAborted();
|
|
72
|
+
const snapshot = await readBoard(world);
|
|
73
|
+
const currentBoard = currentTaskBoard(snapshot.board, snapshot.bytes);
|
|
74
|
+
const items = [];
|
|
75
|
+
for (const id of ids) {
|
|
76
|
+
signal?.throwIfAborted();
|
|
77
|
+
items.push({
|
|
78
|
+
id,
|
|
79
|
+
outcome: await lifecycleFromCurrentBoard(world, id, verb, currentBoard, {
|
|
80
|
+
...(signal === undefined ? {} : { signal }),
|
|
81
|
+
...(note === undefined ? {} : { note }),
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return { items };
|
|
86
|
+
}
|
|
87
|
+
export async function settleTask(world, id) {
|
|
88
|
+
const result = await withTaskLocks({ world, allocation: false, ids: [id] }, async () => {
|
|
89
|
+
const snapshot = await readBoard(world), current = snapshot.board.tasks.get(id);
|
|
90
|
+
if (current === undefined)
|
|
91
|
+
return { kind: "refused", refusal: { kind: "task-missing", taskId: id } };
|
|
92
|
+
if (current.state === "done")
|
|
93
|
+
return { kind: "unchanged" };
|
|
94
|
+
if (current.state === "drop") {
|
|
95
|
+
return {
|
|
96
|
+
kind: "refused",
|
|
97
|
+
refusal: { kind: "invalid-lifecycle-transition", taskId: id, state: current.state, verb: "done" },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const next = {
|
|
101
|
+
...current,
|
|
102
|
+
state: "done",
|
|
103
|
+
updatedAt: advanceTaskTimestamp(current.updatedAt, new Date().toISOString()),
|
|
104
|
+
};
|
|
105
|
+
const replaced = await replaceAuthority({
|
|
106
|
+
world,
|
|
107
|
+
id,
|
|
108
|
+
expected: snapshot.bytes.get(id),
|
|
109
|
+
next: serializeTaskDocument(next),
|
|
110
|
+
});
|
|
111
|
+
return replaced === "replaced"
|
|
112
|
+
? { kind: "changed", task: taskView(next), action: "done" }
|
|
113
|
+
: { kind: "retry", reason: "concurrent-modification" };
|
|
114
|
+
});
|
|
115
|
+
return result === "busy" ? { kind: "retry", reason: "busy" } : result;
|
|
116
|
+
}
|