@astrosheep/keiyaku 4.6.7 → 4.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -16
- package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/opencode/index.js +1 -1
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/pi/keiyaku.ts +0 -5
- package/build/skills/keiyaku/SKILL.md +5 -6
- package/build/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/src/akuma/akuma-call.d.ts +2 -0
- package/build/src/akuma/akuma-call.js +8 -2
- package/build/src/akuma/akuma-instance.d.ts +14 -1
- package/build/src/akuma/akuma-instance.js +37 -7
- package/build/src/akuma/akuma-observe.d.ts +33 -8
- package/build/src/akuma/akuma-observe.js +89 -63
- package/build/src/akuma/akuma-owner.d.ts +14 -2
- package/build/src/akuma/akuma-owner.js +49 -35
- package/build/src/akuma/akuma-selection-execution.js +9 -1
- package/build/src/akuma/akuma-stream.d.ts +22 -0
- package/build/src/akuma/akuma-stream.js +116 -0
- package/build/src/akuma/akuma-wait.d.ts +1 -40
- package/build/src/akuma/akuma-wait.js +23 -84
- package/build/src/akuma/akuma.d.ts +52 -16
- package/build/src/akuma/akuma.js +10 -10
- package/build/src/akuma/allowed.d.ts +7 -12
- package/build/src/akuma/allowed.js +13 -4
- package/build/src/akuma/archetype.d.ts +7 -15
- package/build/src/akuma/archetype.js +36 -35
- package/build/src/akuma/body-supervisor.d.ts +5 -5
- package/build/src/akuma/body-supervisor.js +22 -20
- package/build/src/akuma/body.d.ts +5 -3
- package/build/src/akuma/body.js +57 -8
- package/build/src/akuma/call-request.d.ts +30 -32
- package/build/src/akuma/call-request.js +10 -3
- package/build/src/akuma/caller.d.ts +39 -0
- package/build/src/akuma/caller.js +36 -0
- package/build/src/akuma/dispatch-association.d.ts +0 -1
- package/build/src/akuma/dispatch-association.js +0 -3
- package/build/src/akuma/heart/activity-schema.d.ts +12 -0
- package/build/src/akuma/heart/activity-schema.js +6 -0
- package/build/src/akuma/heart/facts.d.ts +16 -12
- package/build/src/akuma/heart/facts.js +8 -0
- package/build/src/akuma/heart/index.d.ts +61 -9
- package/build/src/akuma/heart/index.js +89 -24
- package/build/src/akuma/heart/rows.d.ts +3 -3
- package/build/src/akuma/heart/rows.js +5 -3
- package/build/src/akuma/heart/soul.d.ts +10 -1
- package/build/src/akuma/heart/soul.js +34 -24
- package/build/src/akuma/heart/storage.d.ts +20 -0
- package/build/src/akuma/heart/storage.js +62 -3
- package/build/src/akuma/heart/timeline.d.ts +7 -0
- package/build/src/akuma/heart/timeline.js +10 -0
- package/build/src/akuma/identity.d.ts +0 -1
- package/build/src/akuma/identity.js +2 -5
- package/build/src/akuma/index.d.ts +6 -2
- package/build/src/akuma/index.js +1 -0
- package/build/src/akuma/nuke.js +6 -28
- package/build/src/akuma/projection.d.ts +25 -11
- package/build/src/akuma/projection.js +24 -7
- package/build/src/akuma/provider-recipe.d.ts +18 -6
- package/build/src/akuma/provider-recipe.js +24 -1
- package/build/src/akuma/provider.d.ts +31 -10
- package/build/src/akuma/provider.js +105 -14
- package/build/src/akuma/providers/acp/events.js +29 -19
- package/build/src/akuma/providers/acp/index.js +2 -3
- package/build/src/akuma/providers/claude/events.js +110 -69
- package/build/src/akuma/providers/claude/index.d.ts +2 -2
- package/build/src/akuma/providers/claude/index.js +4 -8
- package/build/src/akuma/providers/codex-app-server/events.js +17 -2
- package/build/src/akuma/providers/codex-app-server/index.js +17 -11
- package/build/src/akuma/providers/decode.d.ts +33 -0
- package/build/src/akuma/providers/decode.js +65 -0
- package/build/src/akuma/providers/execution-environment.d.ts +2 -1
- package/build/src/akuma/providers/execution-environment.js +3 -0
- package/build/src/akuma/providers/grok-build/index.js +16 -48
- package/build/src/akuma/providers/index.js +2 -0
- package/build/src/akuma/providers/lifecycle.d.ts +9 -0
- package/build/src/akuma/providers/lifecycle.js +10 -0
- package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
- package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
- package/build/src/akuma/providers/opencode-sdk/events.js +146 -296
- package/build/src/akuma/providers/opencode-sdk/index.js +270 -431
- package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
- package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
- package/build/src/akuma/providers/opencode-sdk/session.js +75 -84
- package/build/src/akuma/providers/paseo/events.d.ts +33 -0
- package/build/src/akuma/providers/paseo/events.js +204 -0
- package/build/src/akuma/providers/paseo/index.d.ts +9 -0
- package/build/src/akuma/providers/paseo/index.js +357 -0
- package/build/src/akuma/providers/pi/events.d.ts +2 -0
- package/build/src/akuma/providers/pi/events.js +36 -38
- package/build/src/akuma/providers/pi/index.js +21 -35
- package/build/src/akuma/publication.d.ts +2 -0
- package/build/src/akuma/publication.js +5 -0
- package/build/src/akuma/request-lifecycle.d.ts +4 -2
- package/build/src/akuma/request-lifecycle.js +27 -12
- package/build/src/akuma/request-rendezvous.js +38 -55
- package/build/src/akuma/request-serve.d.ts +1 -1
- package/build/src/akuma/request-serve.js +77 -113
- package/build/src/akuma/requests.d.ts +3 -1
- package/build/src/akuma/requests.js +32 -0
- package/build/src/akuma/selection-observation.d.ts +129 -53
- package/build/src/akuma/selection-observation.js +3 -9
- package/build/src/akuma/turn-drive.d.ts +3 -0
- package/build/src/akuma/turn-drive.js +28 -10
- package/build/src/akuma-body.js +12 -22
- package/build/src/cli/akuma-caller.d.ts +3 -0
- package/build/src/cli/akuma-caller.js +31 -0
- package/build/src/cli/commands/akuma-grammar.js +10 -16
- package/build/src/cli/commands/akuma.js +25 -55
- package/build/src/cli/commands/contract-grammar.d.ts +9 -7
- package/build/src/cli/commands/contract-grammar.js +40 -47
- package/build/src/cli/commands/contract-help.d.ts +17 -7
- package/build/src/cli/commands/contract-help.js +50 -11
- package/build/src/cli/commands/contract.js +34 -63
- package/build/src/cli/commands/debt-grammar.d.ts +19 -0
- package/build/src/cli/commands/debt-grammar.js +323 -0
- package/build/src/cli/commands/debt-query.d.ts +5 -0
- package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
- package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
- package/build/src/cli/commands/{task.js → debt.js} +87 -164
- package/build/src/cli/coordinates.d.ts +1 -1
- package/build/src/cli/coordinates.js +1 -1
- package/build/src/cli/parse.d.ts +5 -5
- package/build/src/cli/parse.js +17 -16
- package/build/src/cli/render/akuma-activity.d.ts +11 -83
- package/build/src/cli/render/akuma-activity.js +20 -382
- package/build/src/cli/render/catalog.d.ts +4 -7
- package/build/src/cli/render/catalog.js +5 -5
- package/build/src/cli/render/contract-history.js +3 -6
- package/build/src/cli/render/contract.js +17 -52
- package/build/src/cli/render/debt.d.ts +28 -0
- package/build/src/cli/render/{task.js → debt.js} +55 -133
- package/build/src/cli/render/kanshi.js +28 -28
- package/build/src/cli/render/marks.d.ts +5 -5
- package/build/src/cli/render/marks.js +4 -10
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/render/receipt.js +3 -10
- package/build/src/cli/runtime.d.ts +1 -1
- package/build/src/cli/runtime.js +14 -20
- package/build/src/cli/scan.d.ts +1 -1
- package/build/src/cli/selectors.d.ts +3 -6
- package/build/src/cli/selectors.js +22 -53
- package/build/src/cli/usage.d.ts +1 -1
- package/build/src/cli/usage.js +4 -4
- package/build/src/contract-worktree.js +3 -3
- package/build/src/debt/board.d.ts +160 -0
- package/build/src/{task → debt}/board.js +89 -89
- package/build/src/debt/catalog.d.ts +11 -0
- package/build/src/debt/catalog.js +59 -0
- package/build/src/{task → debt}/context.d.ts +1 -1
- package/build/src/{task → debt}/context.js +1 -1
- package/build/src/{task → debt}/created-observation.d.ts +6 -10
- package/build/src/{task → debt}/created-observation.js +7 -7
- package/build/src/debt/document.d.ts +37 -0
- package/build/src/{task → debt}/document.js +37 -37
- package/build/src/debt/identity.d.ts +21 -0
- package/build/src/{task → debt}/identity.js +35 -35
- package/build/src/debt/index.d.ts +111 -0
- package/build/src/debt/index.js +203 -0
- package/build/src/{task → debt}/input.d.ts +8 -8
- package/build/src/{task → debt}/input.js +21 -21
- package/build/src/debt/lifecycle-operations.d.ts +6 -0
- package/build/src/{task → debt}/lifecycle-operations.js +27 -31
- package/build/src/debt/mutation-result.d.ts +981 -0
- package/build/src/debt/mutation-result.js +109 -0
- package/build/src/debt/mutation.d.ts +424 -0
- package/build/src/debt/mutation.js +223 -0
- package/build/src/debt/operation-types.d.ts +71 -0
- package/build/src/debt/operations.d.ts +28 -0
- package/build/src/{task → debt}/operations.js +59 -60
- package/build/src/debt/query.d.ts +76 -0
- package/build/src/{task → debt}/query.js +55 -55
- package/build/src/{task → debt}/store.d.ts +13 -13
- package/build/src/{task → debt}/store.js +58 -49
- package/build/src/debt/view.d.ts +4 -0
- package/build/src/debt/view.js +7 -0
- package/build/src/dispatch/index.d.ts +3 -3
- package/build/src/dispatch/index.js +1 -2
- package/build/src/git/observe.d.ts +6 -2
- package/build/src/git/observe.js +6 -2
- package/build/src/identity/coordinates.d.ts +1 -1
- package/build/src/index.d.ts +17 -17
- package/build/src/index.js +11 -11
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/read.js +54 -39
- package/build/src/kanshi/report.d.ts +7 -7
- package/build/src/kanshi/select.js +4 -4
- package/build/src/library/address.js +2 -4
- package/build/src/library/akuma-creation.d.ts +5 -1
- package/build/src/library/akuma-creation.js +27 -47
- package/build/src/library/akumas.d.ts +7 -7
- package/build/src/library/akumas.js +13 -9
- package/build/src/library/bind.d.ts +17 -17
- package/build/src/library/bind.js +16 -12
- package/build/src/library/contract-address.d.ts +9 -0
- package/build/src/library/contract-address.js +71 -0
- package/build/src/library/contract-composition.d.ts +4 -7
- package/build/src/library/contract-composition.js +6 -18
- package/build/src/library/contract-creation.d.ts +3 -5
- package/build/src/library/contract-creation.js +24 -22
- package/build/src/library/contract-execution.js +21 -26
- package/build/src/library/contract-outcomes.d.ts +2 -14
- package/build/src/library/contract-outcomes.js +2 -13
- package/build/src/library/contract-types.d.ts +38 -4
- package/build/src/library/delivery.d.ts +0 -2
- package/build/src/library/delivery.js +2 -5
- package/build/src/library/input.d.ts +2 -2
- package/build/src/library/input.js +5 -5
- package/build/src/library/invocation.js +2 -2
- package/build/src/library/keiyaku.d.ts +0 -5
- package/build/src/library/keiyaku.js +6 -12
- package/build/src/library/nuke.js +3 -3
- package/build/src/library/outcome.d.ts +626 -625
- package/build/src/library/outcome.js +13 -3
- package/build/src/library/reconcile.js +8 -16
- package/build/src/library/refusal.d.ts +2 -2
- package/build/src/library/repo.d.ts +3 -2
- package/build/src/library/repo.js +10 -5
- package/build/src/library/selection.d.ts +5 -8
- package/build/src/library/selection.js +22 -73
- package/build/src/plugin/akuma-signals.d.ts +2 -0
- package/build/src/plugin/akuma-signals.js +4 -0
- package/build/src/plugin/public.d.ts +32 -2
- package/build/src/plugin/runtime.js +5 -3
- package/build/src/protocol/amend.js +3 -2
- package/build/src/protocol/attempt.js +3 -8
- package/build/src/protocol/bind.d.ts +2 -2
- package/build/src/protocol/bind.js +1 -1
- package/build/src/protocol/deliver.js +3 -3
- package/build/src/protocol/operations.d.ts +1 -3
- package/build/src/protocol/operations.js +0 -8
- package/build/src/protocol/outcome.d.ts +1 -2
- package/build/src/protocol/outcome.js +1 -13
- package/build/src/protocol/placement.js +3 -10
- package/build/src/protocol/read/status.js +31 -70
- package/build/src/protocol/reintegrate.js +3 -10
- package/build/src/protocol/review.js +3 -3
- package/build/src/protocol/run.d.ts +5 -1
- package/build/src/protocol/run.js +3 -3
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/fence.d.ts +3 -3
- package/build/src/settlement/fence.js +4 -4
- package/build/src/settlement/holder.d.ts +16 -16
- package/build/src/settlement/holder.js +69 -63
- package/build/src/settlement/settle.d.ts +5 -5
- package/build/src/settlement/settle.js +53 -53
- package/package.json +19 -9
- package/plugins/paseo/plugin/index.server.ts +17 -0
- package/plugins/paseo/plugin/paseo-plugin.json +4 -0
- package/plugins/paseo/plugin/server/attach.ts +52 -0
- package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
- package/plugins/paseo/plugin/server/message.ts +60 -0
- package/plugins/paseo/plugin/server/mirror.ts +193 -0
- package/plugins/paseo/plugin/server/model.ts +14 -0
- package/plugins/paseo/plugin/server/provider.ts +276 -0
- package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
- package/plugins/paseo/plugin/server/sdk.ts +289 -0
- package/plugins/paseo/plugin/server/stop.ts +26 -0
- package/plugins/paseo/plugin/server/transport.ts +35 -0
- package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
- package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
- package/plugins/paseo/plugin/tsconfig.json +6 -0
- package/plugins/pi/keiyaku.ts +57 -0
- package/skills/keiyaku/SKILL.md +43 -0
- package/skills/keiyaku-akuma/SKILL.md +130 -0
- package/skills/keiyaku-akuma/references/automation.md +269 -0
- package/skills/keiyaku-babysit/SKILL.md +65 -0
- package/skills/keiyaku-bind/SKILL.md +216 -0
- package/skills/keiyaku-bind/agents/openai.yaml +4 -0
- package/skills/keiyaku-debt/SKILL.md +91 -0
- package/skills/keiyaku-workflow/SKILL.md +129 -0
- package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
- package/build/skills/keiyaku-task/SKILL.md +0 -104
- package/build/src/cli/commands/amend.d.ts +0 -12
- package/build/src/cli/commands/amend.js +0 -10
- package/build/src/cli/commands/bind.d.ts +0 -11
- package/build/src/cli/commands/bind.js +0 -23
- package/build/src/cli/commands/task-grammar.d.ts +0 -19
- package/build/src/cli/commands/task-grammar.js +0 -384
- package/build/src/cli/commands/task-query.d.ts +0 -5
- package/build/src/cli/render/task.d.ts +0 -41
- package/build/src/dispatch/association.d.ts +0 -1
- package/build/src/dispatch/association.js +0 -1
- package/build/src/task/board.d.ts +0 -168
- package/build/src/task/catalog.d.ts +0 -11
- package/build/src/task/catalog.js +0 -59
- package/build/src/task/compose-language.d.ts +0 -57
- package/build/src/task/compose-language.js +0 -364
- package/build/src/task/compose-parser.d.ts +0 -32
- package/build/src/task/compose-parser.js +0 -180
- package/build/src/task/compose.d.ts +0 -16
- package/build/src/task/compose.js +0 -189
- package/build/src/task/document.d.ts +0 -39
- package/build/src/task/identity.d.ts +0 -21
- package/build/src/task/index.d.ts +0 -138
- package/build/src/task/index.js +0 -269
- package/build/src/task/lifecycle-operations.d.ts +0 -6
- package/build/src/task/mutation-result.d.ts +0 -1726
- package/build/src/task/mutation-result.js +0 -198
- package/build/src/task/mutation.d.ts +0 -590
- package/build/src/task/mutation.js +0 -262
- package/build/src/task/operation-types.d.ts +0 -71
- package/build/src/task/operations.d.ts +0 -28
- package/build/src/task/query.d.ts +0 -76
- package/build/src/task/view.d.ts +0 -4
- package/build/src/task/view.js +0 -7
- /package/build/src/{task → debt}/operation-types.js +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { DebtPriority, DebtState } from "./document.js";
|
|
2
|
+
import { type DebtId } from "./identity.js";
|
|
3
|
+
import type { DebtBoard, DebtRef, DebtRelationProjection, DebtRow } from "./board.js";
|
|
4
|
+
import { type BoundedList } from "../bounded-list.js";
|
|
5
|
+
export declare const DEBT_RELATION_PREDICATE_FIELDS: readonly ["under", "needs", "blocks"];
|
|
6
|
+
export type DebtRelationPredicateField = (typeof DEBT_RELATION_PREDICATE_FIELDS)[number];
|
|
7
|
+
export type DebtQueryPredicate = Readonly<{
|
|
8
|
+
field: "state";
|
|
9
|
+
operator: "=" | "!=";
|
|
10
|
+
value: DebtState;
|
|
11
|
+
}> | Readonly<{
|
|
12
|
+
field: "priority";
|
|
13
|
+
operator: "=" | "!=" | "<" | "<=" | ">" | ">=";
|
|
14
|
+
value: DebtPriority;
|
|
15
|
+
}> | Readonly<{
|
|
16
|
+
field: "title" | "id";
|
|
17
|
+
operator: "=" | "!=" | "~";
|
|
18
|
+
value: string;
|
|
19
|
+
}> | Readonly<{
|
|
20
|
+
field: "parent";
|
|
21
|
+
operator: "=" | "!=";
|
|
22
|
+
value: DebtId | null;
|
|
23
|
+
}> | Readonly<{
|
|
24
|
+
field: "under" | "needs" | "blocks";
|
|
25
|
+
operator: "=" | "!=";
|
|
26
|
+
value: DebtId;
|
|
27
|
+
}> | Readonly<{
|
|
28
|
+
field: "ready" | "blocked";
|
|
29
|
+
operator: "=" | "!=";
|
|
30
|
+
value: boolean;
|
|
31
|
+
}> | Readonly<{
|
|
32
|
+
field: "created" | "updated";
|
|
33
|
+
operator: "=" | "!=" | "<" | "<=" | ">" | ">=";
|
|
34
|
+
value: string;
|
|
35
|
+
}>;
|
|
36
|
+
export type DebtQueryExpression = Readonly<{
|
|
37
|
+
kind: "and" | "or";
|
|
38
|
+
terms: readonly DebtQueryExpression[];
|
|
39
|
+
}> | Readonly<{
|
|
40
|
+
kind: "not";
|
|
41
|
+
term: DebtQueryExpression;
|
|
42
|
+
}> | Readonly<{
|
|
43
|
+
kind: "predicate";
|
|
44
|
+
predicate: DebtQueryPredicate;
|
|
45
|
+
}>;
|
|
46
|
+
export type DebtQuerySort = "priority" | "created" | "updated" | "id";
|
|
47
|
+
export type DebtQueryRow = DebtRow & Readonly<{
|
|
48
|
+
parent: DebtId | null;
|
|
49
|
+
needs: readonly DebtRef[];
|
|
50
|
+
blocks: readonly DebtRef[];
|
|
51
|
+
createdAt: string;
|
|
52
|
+
updatedAt: string;
|
|
53
|
+
}>;
|
|
54
|
+
export type DebtPage<Row> = BoundedList<Row>;
|
|
55
|
+
/** Semantic refusals identify the caller input part; textual offsets belong to the CLI. */
|
|
56
|
+
export declare class DebtQueryPredicateError extends TypeError {
|
|
57
|
+
readonly part: "field" | "operator" | "value";
|
|
58
|
+
constructor(message: string, part: "field" | "operator" | "value");
|
|
59
|
+
}
|
|
60
|
+
export declare function normalizeDebtQueryPredicate(value: unknown): DebtQueryPredicate;
|
|
61
|
+
export declare function normalizeDebtQuery(value: unknown): DebtQueryExpression;
|
|
62
|
+
/** CLI selection and native default share Debt-owned terminal-state semantics. */
|
|
63
|
+
export declare function debtQuerySelection(selection?: "active" | "closed" | "all", where?: DebtQueryExpression): DebtQueryExpression;
|
|
64
|
+
export declare function projectQueryRows(board: DebtBoard, relations: DebtRelationProjection, input: Readonly<{
|
|
65
|
+
scope: readonly string[] | null;
|
|
66
|
+
expression: DebtQueryExpression;
|
|
67
|
+
sort?: DebtQuerySort;
|
|
68
|
+
}>): readonly DebtQueryRow[];
|
|
69
|
+
export declare function projectQuery(board: DebtBoard, relations: DebtRelationProjection, input: Readonly<{
|
|
70
|
+
scope: readonly string[] | null;
|
|
71
|
+
expression: DebtQueryExpression;
|
|
72
|
+
sort?: DebtQuerySort;
|
|
73
|
+
limit: number;
|
|
74
|
+
}>): DebtPage<DebtQueryRow>;
|
|
75
|
+
export declare function underExpression(parent: DebtId): DebtQueryExpression;
|
|
76
|
+
export declare function queryUnderTargets(expression: DebtQueryExpression): readonly DebtId[];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { formatDebtId, parseDebtId, sameNamespace } from "./identity.js";
|
|
2
|
+
import { projectDebtRow, debtBlocked, debtDisposition, debtRef } from "./board.js";
|
|
3
3
|
import { projectBoundedList } from "../bounded-list.js";
|
|
4
|
-
export const
|
|
5
|
-
const states = ["open", "
|
|
4
|
+
export const DEBT_RELATION_PREDICATE_FIELDS = ["under", "needs", "blocks"];
|
|
5
|
+
const states = ["open", "done", "drop"];
|
|
6
6
|
const comparisons = ["=", "!=", "<", "<=", ">", ">=", "~"];
|
|
7
7
|
function fail(message) {
|
|
8
8
|
throw new TypeError(message);
|
|
@@ -18,7 +18,7 @@ function closed(value, fields, label) {
|
|
|
18
18
|
fail(`${label} has unknown field: ${key}`);
|
|
19
19
|
}
|
|
20
20
|
/** Semantic refusals identify the caller input part; textual offsets belong to the CLI. */
|
|
21
|
-
export class
|
|
21
|
+
export class DebtQueryPredicateError extends TypeError {
|
|
22
22
|
part;
|
|
23
23
|
constructor(message, part) {
|
|
24
24
|
super(message);
|
|
@@ -26,18 +26,18 @@ export class TaskQueryPredicateError extends TypeError {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
function invalidPredicate(message, part = "value") {
|
|
29
|
-
throw new
|
|
29
|
+
throw new DebtQueryPredicateError(message, part);
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function debtId(value, label) {
|
|
32
32
|
if (typeof value !== "string")
|
|
33
|
-
invalidPredicate(`${label} must be a
|
|
33
|
+
invalidPredicate(`${label} must be a DebtId`);
|
|
34
34
|
try {
|
|
35
|
-
const coordinate =
|
|
36
|
-
if (
|
|
37
|
-
invalidPredicate(`${label} must be a canonical
|
|
35
|
+
const coordinate = parseDebtId(value);
|
|
36
|
+
if (formatDebtId(coordinate) !== value)
|
|
37
|
+
invalidPredicate(`${label} must be a canonical DebtId`);
|
|
38
38
|
}
|
|
39
39
|
catch {
|
|
40
|
-
invalidPredicate(`${label} must be a canonical
|
|
40
|
+
invalidPredicate(`${label} must be a canonical DebtId`);
|
|
41
41
|
}
|
|
42
42
|
return value;
|
|
43
43
|
}
|
|
@@ -81,15 +81,15 @@ function normalizeTextPredicate(input, field, operator) {
|
|
|
81
81
|
if (operator !== "=" && operator !== "!=" && operator !== "~")
|
|
82
82
|
invalidPredicate(`${field} supports only =, !=, and ~`, "operator");
|
|
83
83
|
if (field === "id" && operator !== "~")
|
|
84
|
-
|
|
84
|
+
debtId(input.value, "id value");
|
|
85
85
|
return { field, operator, value: input.value };
|
|
86
86
|
}
|
|
87
87
|
function normalizeParentPredicate(input, operator) {
|
|
88
|
-
const value = input.value === null ? null :
|
|
88
|
+
const value = input.value === null ? null : debtId(input.value, "parent value");
|
|
89
89
|
return { field: "parent", operator: equalityOperator(operator, "parent"), value };
|
|
90
90
|
}
|
|
91
91
|
function normalizeRelationPredicate(input, field, operator) {
|
|
92
|
-
return { field, operator: equalityOperator(operator, field), value:
|
|
92
|
+
return { field, operator: equalityOperator(operator, field), value: debtId(input.value, `${field} value`) };
|
|
93
93
|
}
|
|
94
94
|
function normalizeBooleanPredicate(input, field, operator) {
|
|
95
95
|
if (typeof input.value !== "boolean")
|
|
@@ -99,7 +99,7 @@ function normalizeBooleanPredicate(input, field, operator) {
|
|
|
99
99
|
function normalizeTimestampPredicate(input, field, operator) {
|
|
100
100
|
return { field, operator: orderedOperator(operator, field), value: timestamp(input.value, `${field} value`) };
|
|
101
101
|
}
|
|
102
|
-
export function
|
|
102
|
+
export function normalizeDebtQueryPredicate(value) {
|
|
103
103
|
const input = object(value, "query predicate");
|
|
104
104
|
closed(input, ["field", "operator", "value"], "query predicate");
|
|
105
105
|
const field = input.field;
|
|
@@ -131,26 +131,26 @@ export function normalizeTaskQueryPredicate(value) {
|
|
|
131
131
|
return invalidPredicate(`unknown query field: ${field}`, "field");
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
-
export function
|
|
134
|
+
export function normalizeDebtQuery(value) {
|
|
135
135
|
const input = object(value, "query expression");
|
|
136
136
|
if (input.kind === "predicate") {
|
|
137
137
|
closed(input, ["kind", "predicate"], "query expression");
|
|
138
|
-
return { kind: "predicate", predicate:
|
|
138
|
+
return { kind: "predicate", predicate: normalizeDebtQueryPredicate(input.predicate) };
|
|
139
139
|
}
|
|
140
140
|
if (input.kind === "not") {
|
|
141
141
|
closed(input, ["kind", "term"], "query expression");
|
|
142
|
-
return { kind: "not", term:
|
|
142
|
+
return { kind: "not", term: normalizeDebtQuery(input.term) };
|
|
143
143
|
}
|
|
144
144
|
if (input.kind === "and" || input.kind === "or") {
|
|
145
145
|
closed(input, ["kind", "terms"], "query expression");
|
|
146
146
|
if (!Array.isArray(input.terms) || input.terms.length === 0)
|
|
147
147
|
fail(`${input.kind} query requires terms`);
|
|
148
|
-
return { kind: input.kind, terms: input.terms.map((term) =>
|
|
148
|
+
return { kind: input.kind, terms: input.terms.map((term) => normalizeDebtQuery(term)) };
|
|
149
149
|
}
|
|
150
150
|
fail("query expression kind is invalid");
|
|
151
151
|
}
|
|
152
|
-
/** CLI selection and native default share
|
|
153
|
-
export function
|
|
152
|
+
/** CLI selection and native default share Debt-owned terminal-state semantics. */
|
|
153
|
+
export function debtQuerySelection(selection = "active", where) {
|
|
154
154
|
if (selection === "all" && where !== undefined)
|
|
155
155
|
return where;
|
|
156
156
|
const state = (value, operator) => ({
|
|
@@ -194,10 +194,10 @@ function descendants(relations, parent) {
|
|
|
194
194
|
return result;
|
|
195
195
|
}
|
|
196
196
|
function relation(board, relations, id, field, target) {
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
197
|
+
const debt = board.debts.get(id);
|
|
198
|
+
if (debt === undefined)
|
|
199
199
|
return false;
|
|
200
|
-
return field === "needs" ?
|
|
200
|
+
return field === "needs" ? debt.needs.includes(target) : relations.blocks(id).some((ref) => ref.id === target);
|
|
201
201
|
}
|
|
202
202
|
function matchText(left, operator, right) {
|
|
203
203
|
return operator === "~" ? left.includes(right) : compare(left, operator, right);
|
|
@@ -205,56 +205,56 @@ function matchText(left, operator, right) {
|
|
|
205
205
|
function matchRelation(selected, operator) {
|
|
206
206
|
return operator === "=" ? selected : !selected;
|
|
207
207
|
}
|
|
208
|
-
function matchesPredicate(board, relations,
|
|
208
|
+
function matchesPredicate(board, relations, debt, value, under) {
|
|
209
209
|
switch (value.field) {
|
|
210
210
|
case "state":
|
|
211
|
-
return compare(
|
|
211
|
+
return compare(debt.state, value.operator, value.value);
|
|
212
212
|
case "priority":
|
|
213
|
-
return compare(
|
|
213
|
+
return compare(debt.priority, value.operator, value.value);
|
|
214
214
|
case "title":
|
|
215
|
-
return matchText(
|
|
215
|
+
return matchText(debt.title, value.operator, value.value);
|
|
216
216
|
case "id":
|
|
217
|
-
return matchText(
|
|
217
|
+
return matchText(debt.id, value.operator, value.value);
|
|
218
218
|
case "parent":
|
|
219
|
-
return compare(
|
|
219
|
+
return compare(debt.parent ?? "", value.operator, value.value ?? "");
|
|
220
220
|
case "under":
|
|
221
|
-
return matchRelation(under.get(value.value)?.has(
|
|
221
|
+
return matchRelation(under.get(value.value)?.has(debt.id) === true, value.operator);
|
|
222
222
|
case "needs":
|
|
223
|
-
return matchRelation(relation(board, relations,
|
|
223
|
+
return matchRelation(relation(board, relations, debt.id, "needs", value.value), value.operator);
|
|
224
224
|
case "blocks":
|
|
225
|
-
return matchRelation(relation(board, relations,
|
|
225
|
+
return matchRelation(relation(board, relations, debt.id, "blocks", value.value), value.operator);
|
|
226
226
|
case "ready":
|
|
227
|
-
return membership(
|
|
227
|
+
return membership(debtDisposition(board, debt) === "ready", value.operator, value.value);
|
|
228
228
|
case "blocked":
|
|
229
|
-
return membership(
|
|
229
|
+
return membership(debtBlocked(board, debt), value.operator, value.value);
|
|
230
230
|
case "created":
|
|
231
|
-
return compare(
|
|
231
|
+
return compare(debt.createdAt, value.operator, value.value);
|
|
232
232
|
case "updated":
|
|
233
|
-
return compare(
|
|
233
|
+
return compare(debt.updatedAt, value.operator, value.value);
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
|
-
function matches(board, relations,
|
|
236
|
+
function matches(board, relations, debt, expression, under) {
|
|
237
237
|
if (expression.kind === "not")
|
|
238
|
-
return !matches(board, relations,
|
|
238
|
+
return !matches(board, relations, debt, expression.term, under);
|
|
239
239
|
if (expression.kind !== "predicate") {
|
|
240
240
|
return expression.kind === "and"
|
|
241
|
-
? expression.terms.every((term) => matches(board, relations,
|
|
242
|
-
: expression.terms.some((term) => matches(board, relations,
|
|
241
|
+
? expression.terms.every((term) => matches(board, relations, debt, term, under))
|
|
242
|
+
: expression.terms.some((term) => matches(board, relations, debt, term, under));
|
|
243
243
|
}
|
|
244
|
-
return matchesPredicate(board, relations,
|
|
244
|
+
return matchesPredicate(board, relations, debt, expression.predicate, under);
|
|
245
245
|
}
|
|
246
|
-
function row(board, relations,
|
|
246
|
+
function row(board, relations, debt) {
|
|
247
247
|
return {
|
|
248
|
-
...
|
|
249
|
-
parent:
|
|
250
|
-
needs:
|
|
251
|
-
blocks: relations.blocks(
|
|
252
|
-
createdAt:
|
|
253
|
-
updatedAt:
|
|
248
|
+
...projectDebtRow(board, relations, debt),
|
|
249
|
+
parent: debt.parent,
|
|
250
|
+
needs: debt.needs.map((need) => debtRef(board, need)),
|
|
251
|
+
blocks: relations.blocks(debt.id),
|
|
252
|
+
createdAt: debt.createdAt,
|
|
253
|
+
updatedAt: debt.updatedAt,
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
|
-
function
|
|
257
|
-
return [...
|
|
256
|
+
function sortDebts(debts, sort) {
|
|
257
|
+
return [...debts].sort((left, right) => {
|
|
258
258
|
const tie = Buffer.compare(Buffer.from(left.id), Buffer.from(right.id));
|
|
259
259
|
if (sort === "id")
|
|
260
260
|
return tie;
|
|
@@ -267,9 +267,9 @@ function sortTasks(tasks, sort) {
|
|
|
267
267
|
export function projectQueryRows(board, relations, input) {
|
|
268
268
|
const { scope, expression, sort = "priority" } = input;
|
|
269
269
|
const under = new Map(queryUnderTargets(expression).map((target) => [target, descendants(relations, target)]));
|
|
270
|
-
return
|
|
271
|
-
.filter((
|
|
272
|
-
.filter((
|
|
270
|
+
return sortDebts([...board.debts.values()]
|
|
271
|
+
.filter((debt) => scope === null || sameNamespace(parseDebtId(debt.id).namespace, scope))
|
|
272
|
+
.filter((debt) => matches(board, relations, debt, expression, under)), sort).map((debt) => row(board, relations, debt));
|
|
273
273
|
}
|
|
274
274
|
export function projectQuery(board, relations, input) {
|
|
275
275
|
return projectBoundedList(projectQueryRows(board, relations, input), input.limit);
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import type { WorldRoot } from "../world.js";
|
|
2
2
|
import { type BoundedList } from "../bounded-list.js";
|
|
3
|
-
import { type
|
|
4
|
-
import { type
|
|
5
|
-
import type {
|
|
3
|
+
import { type DebtDocument } from "./document.js";
|
|
4
|
+
import { type DebtId } from "./identity.js";
|
|
5
|
+
import type { DebtBoard } from "./board.js";
|
|
6
6
|
export type BoardSnapshot = Readonly<{
|
|
7
|
-
board:
|
|
8
|
-
bytes: ReadonlyMap<
|
|
7
|
+
board: DebtBoard;
|
|
8
|
+
bytes: ReadonlyMap<DebtId, Uint8Array>;
|
|
9
9
|
}>;
|
|
10
10
|
export declare function readBoard(world: WorldRoot): Promise<BoardSnapshot>;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function readRecentDebtDocuments(world: WorldRoot, input: Readonly<{
|
|
12
12
|
namespace?: readonly string[];
|
|
13
13
|
selection?: "all" | "active";
|
|
14
14
|
limit?: number;
|
|
15
|
-
}>): Promise<BoundedList<
|
|
16
|
-
export declare function
|
|
15
|
+
}>): Promise<BoundedList<DebtDocument>>;
|
|
16
|
+
export declare function readDebtDocument(world: WorldRoot, id: DebtId): Promise<DebtDocument | undefined>;
|
|
17
17
|
export declare function replaceAuthority(input: Readonly<{
|
|
18
18
|
world: WorldRoot;
|
|
19
|
-
id:
|
|
19
|
+
id: DebtId;
|
|
20
20
|
expected: Uint8Array | null;
|
|
21
21
|
next: Uint8Array;
|
|
22
22
|
}>): Promise<"replaced" | "concurrent-modification">;
|
|
23
|
-
export declare function authorityBytesMatch(world: WorldRoot, id:
|
|
24
|
-
export declare function
|
|
23
|
+
export declare function authorityBytesMatch(world: WorldRoot, id: DebtId, expected: Uint8Array | null): Promise<boolean>;
|
|
24
|
+
export declare function nukeDebtAuthority(world: WorldRoot, options?: Readonly<{
|
|
25
25
|
timeoutMs?: number;
|
|
26
26
|
onRemoved?(count: number): void;
|
|
27
27
|
}>): Promise<number | "busy">;
|
|
28
|
-
export declare function
|
|
28
|
+
export declare function withDebtLocks<T>(input: Readonly<{
|
|
29
29
|
world: WorldRoot;
|
|
30
30
|
allocation: boolean;
|
|
31
|
-
ids: readonly
|
|
31
|
+
ids: readonly DebtId[];
|
|
32
32
|
timeoutMs?: number;
|
|
33
33
|
signal?: AbortSignal;
|
|
34
34
|
}>, action: () => Promise<T>): Promise<T | "busy">;
|
|
@@ -5,17 +5,26 @@ import { dirname, relative, resolve, sep } from "node:path";
|
|
|
5
5
|
import { acquireSqliteTransactionLock, SqliteTransactionLockError, } from "../coordination/sqlite-transaction-lock.js";
|
|
6
6
|
import { syncDirectory } from "../coordination/durable-file.js";
|
|
7
7
|
import { boundedListLimit, projectBoundedList } from "../bounded-list.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
const
|
|
11
|
-
function
|
|
12
|
-
|
|
8
|
+
import { parseDebtDocument } from "./document.js";
|
|
9
|
+
import { formatDebtId, parseDebtId, physicalDebtSegment, DEBT_LOCAL_ID_BYTES, sameNamespace, debtAuthorityPath, } from "./identity.js";
|
|
10
|
+
const DEFAULT_DEBT_LOCK_TIMEOUT_MS = 3_000;
|
|
11
|
+
async function debtsDirectory(world) {
|
|
12
|
+
const legacy = resolve(world, ".keiyaku", "tasks");
|
|
13
|
+
try {
|
|
14
|
+
await lstat(legacy);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error.code !== "ENOENT")
|
|
18
|
+
throw error;
|
|
19
|
+
return resolve(world, ".keiyaku", "debts");
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Unmigrated ledger authority: ${legacy}`);
|
|
13
22
|
}
|
|
14
23
|
function allocationLockPath(world) {
|
|
15
|
-
return resolve(world, ".keiyaku", "locks", "
|
|
24
|
+
return resolve(world, ".keiyaku", "locks", "debt-allocation.sqlite");
|
|
16
25
|
}
|
|
17
26
|
function custodyError(path) {
|
|
18
|
-
return new Error(`
|
|
27
|
+
return new Error(`Debt authority custody violation: symlink or non-authority component: ${path}`);
|
|
19
28
|
}
|
|
20
29
|
async function requireDirectory(path, mode) {
|
|
21
30
|
try {
|
|
@@ -44,14 +53,14 @@ async function requireDirectory(path, mode) {
|
|
|
44
53
|
}
|
|
45
54
|
}
|
|
46
55
|
async function resolveAuthority(world, id, mode) {
|
|
47
|
-
const coordinate =
|
|
48
|
-
const root =
|
|
49
|
-
const safePath =
|
|
56
|
+
const coordinate = parseDebtId(id);
|
|
57
|
+
const root = await debtsDirectory(world);
|
|
58
|
+
const safePath = debtAuthorityPath(root, coordinate);
|
|
50
59
|
if (!(await requireDirectory(root, mode)))
|
|
51
60
|
return { path: safePath, exists: false };
|
|
52
61
|
let parent = root;
|
|
53
62
|
for (const segment of coordinate.namespace) {
|
|
54
|
-
parent = resolve(parent,
|
|
63
|
+
parent = resolve(parent, physicalDebtSegment(segment));
|
|
55
64
|
if (!(await requireDirectory(parent, mode)))
|
|
56
65
|
return { path: safePath, exists: false };
|
|
57
66
|
}
|
|
@@ -85,27 +94,27 @@ async function authorityFiles(directory) {
|
|
|
85
94
|
}
|
|
86
95
|
return files.sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
87
96
|
}
|
|
88
|
-
function coordinateFromPath(
|
|
89
|
-
const local = relative(
|
|
90
|
-
if (local.startsWith("..") || resolve(
|
|
91
|
-
throw new Error(`invalid
|
|
97
|
+
function coordinateFromPath(debtsDirectory, path) {
|
|
98
|
+
const local = relative(debtsDirectory, path);
|
|
99
|
+
if (local.startsWith("..") || resolve(debtsDirectory, local) !== path || !local.endsWith(".md"))
|
|
100
|
+
throw new Error(`invalid Debt authority path: ${path}`);
|
|
92
101
|
const segments = local.slice(0, -3).split(sep);
|
|
93
|
-
segments.forEach((segment) =>
|
|
94
|
-
return
|
|
102
|
+
segments.forEach((segment) => physicalDebtSegment(segment));
|
|
103
|
+
return parseDebtId(`debt/${segments.join("/")}`);
|
|
95
104
|
}
|
|
96
105
|
async function ownedAuthorityCandidates(directory) {
|
|
97
106
|
const candidates = [];
|
|
98
107
|
for (const path of await authorityFiles(directory)) {
|
|
99
108
|
try {
|
|
100
|
-
candidates.push({ id:
|
|
109
|
+
candidates.push({ id: formatDebtId(coordinateFromPath(directory, path)), path });
|
|
101
110
|
}
|
|
102
111
|
catch {
|
|
103
|
-
// Files outside the
|
|
112
|
+
// Files outside the Debt identity grammar are not owned candidates.
|
|
104
113
|
}
|
|
105
114
|
}
|
|
106
115
|
return candidates;
|
|
107
116
|
}
|
|
108
|
-
async function
|
|
117
|
+
async function removeEmptyDebtDirectories(directory, removeSelf) {
|
|
109
118
|
if (!(await requireDirectory(directory, "read")))
|
|
110
119
|
return;
|
|
111
120
|
const entries = await readdir(directory);
|
|
@@ -115,7 +124,7 @@ async function removeEmptyTaskDirectories(directory, removeSelf) {
|
|
|
115
124
|
if (stat.isSymbolicLink())
|
|
116
125
|
throw custodyError(path);
|
|
117
126
|
if (stat.isDirectory())
|
|
118
|
-
await
|
|
127
|
+
await removeEmptyDebtDirectories(path, true);
|
|
119
128
|
}
|
|
120
129
|
if (!removeSelf)
|
|
121
130
|
return;
|
|
@@ -129,7 +138,7 @@ async function removeEmptyTaskDirectories(directory, removeSelf) {
|
|
|
129
138
|
}
|
|
130
139
|
}
|
|
131
140
|
export async function readBoard(world) {
|
|
132
|
-
const directory =
|
|
141
|
+
const directory = await debtsDirectory(world);
|
|
133
142
|
const paths = await authorityFiles(directory);
|
|
134
143
|
const reads = new Array(paths.length);
|
|
135
144
|
let next = 0;
|
|
@@ -140,7 +149,7 @@ export async function readBoard(world) {
|
|
|
140
149
|
try {
|
|
141
150
|
const stat = await lstat(path);
|
|
142
151
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
143
|
-
throw new Error(`
|
|
152
|
+
throw new Error(`Debt authority is not a regular file: ${path}`);
|
|
144
153
|
}
|
|
145
154
|
const coordinate = coordinateFromPath(directory, path);
|
|
146
155
|
reads[index] = { kind: "read", coordinate, source: await readFile(path) };
|
|
@@ -152,43 +161,43 @@ export async function readBoard(world) {
|
|
|
152
161
|
};
|
|
153
162
|
// Drain all owned reads; authority and errors are then judged in canonical path order.
|
|
154
163
|
await Promise.all(Array.from({ length: Math.min(8, paths.length) }, worker));
|
|
155
|
-
const
|
|
164
|
+
const debts = new Map();
|
|
156
165
|
const bytes = new Map();
|
|
157
166
|
for (const read of reads) {
|
|
158
167
|
if (read.kind === "failed")
|
|
159
168
|
throw read.error;
|
|
160
169
|
const { coordinate, source } = read;
|
|
161
|
-
const id =
|
|
162
|
-
|
|
170
|
+
const id = formatDebtId(coordinate);
|
|
171
|
+
debts.set(id, parseDebtDocument(source, coordinate));
|
|
163
172
|
bytes.set(id, source);
|
|
164
173
|
}
|
|
165
|
-
return { board: {
|
|
174
|
+
return { board: { debts }, bytes };
|
|
166
175
|
}
|
|
167
|
-
function
|
|
176
|
+
function compareRecentDebts(left, right) {
|
|
168
177
|
const updated = right.updatedAt.localeCompare(left.updatedAt);
|
|
169
178
|
return updated === 0 ? Buffer.compare(Buffer.from(left.id), Buffer.from(right.id)) : updated;
|
|
170
179
|
}
|
|
171
|
-
export async function
|
|
180
|
+
export async function readRecentDebtDocuments(world, input) {
|
|
172
181
|
const limit = boundedListLimit(input.limit);
|
|
173
|
-
const directory =
|
|
174
|
-
const
|
|
182
|
+
const directory = await debtsDirectory(world);
|
|
183
|
+
const debts = [];
|
|
175
184
|
for (const path of await authorityFiles(directory)) {
|
|
176
185
|
const metadata = await lstat(path);
|
|
177
186
|
if (!metadata.isFile() || metadata.isSymbolicLink())
|
|
178
|
-
throw new Error(`
|
|
187
|
+
throw new Error(`Debt authority is not a regular file: ${path}`);
|
|
179
188
|
const coordinate = coordinateFromPath(directory, path);
|
|
180
189
|
if (input.namespace !== undefined && !sameNamespace(coordinate.namespace, input.namespace))
|
|
181
190
|
continue;
|
|
182
|
-
const
|
|
183
|
-
if (input.selection === "active" && (
|
|
191
|
+
const debt = parseDebtDocument(await readFile(path), coordinate);
|
|
192
|
+
if (input.selection === "active" && (debt.state === "done" || debt.state === "drop"))
|
|
184
193
|
continue;
|
|
185
|
-
|
|
194
|
+
debts.push(debt);
|
|
186
195
|
}
|
|
187
|
-
return projectBoundedList(
|
|
196
|
+
return projectBoundedList(debts.sort(compareRecentDebts), limit);
|
|
188
197
|
}
|
|
189
|
-
export async function
|
|
198
|
+
export async function readDebtDocument(world, id) {
|
|
190
199
|
const resolved = await resolveAuthority(world, id, "read");
|
|
191
|
-
return resolved.exists ?
|
|
200
|
+
return resolved.exists ? parseDebtDocument(await readFile(resolved.path), parseDebtId(id)) : undefined;
|
|
192
201
|
}
|
|
193
202
|
function equal(left, right) {
|
|
194
203
|
return left === null || right === null ? left === right : Buffer.from(left).equals(Buffer.from(right));
|
|
@@ -229,8 +238,8 @@ export async function authorityBytesMatch(world, id, expected) {
|
|
|
229
238
|
return equal(await currentBytes(world, id), expected);
|
|
230
239
|
}
|
|
231
240
|
function lockPath(world, id) {
|
|
232
|
-
const coordinate =
|
|
233
|
-
return resolve(world, ".keiyaku", "locks", "
|
|
241
|
+
const coordinate = parseDebtId(id);
|
|
242
|
+
return resolve(world, ".keiyaku", "locks", "debt", ...coordinate.namespace.map((segment) => physicalDebtSegment(segment)), `${physicalDebtSegment(coordinate.localId, DEBT_LOCAL_ID_BYTES)}.sqlite`);
|
|
234
243
|
}
|
|
235
244
|
function errorDetail(error) {
|
|
236
245
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -249,15 +258,15 @@ function preserveCommittedResult(result, errors) {
|
|
|
249
258
|
};
|
|
250
259
|
}
|
|
251
260
|
}
|
|
252
|
-
throw new AggregateError(errors, "
|
|
261
|
+
throw new AggregateError(errors, "Debt lock cleanup failed");
|
|
253
262
|
}
|
|
254
|
-
export async function
|
|
255
|
-
const directory =
|
|
263
|
+
export async function nukeDebtAuthority(world, options) {
|
|
264
|
+
const directory = await debtsDirectory(world);
|
|
256
265
|
const lockOptions = options?.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs };
|
|
257
|
-
const result = await
|
|
266
|
+
const result = await withDebtLocks({ world, allocation: true, ids: [], ...lockOptions }, async () => {
|
|
258
267
|
const candidates = await ownedAuthorityCandidates(directory);
|
|
259
268
|
const ids = [...new Set(candidates.map((candidate) => candidate.id))].sort((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)));
|
|
260
|
-
return await
|
|
269
|
+
return await withDebtLocks({ world, allocation: false, ids, ...lockOptions }, async () => {
|
|
261
270
|
let removed = 0;
|
|
262
271
|
for (const candidate of candidates) {
|
|
263
272
|
try {
|
|
@@ -273,7 +282,7 @@ export async function nukeTaskAuthority(world, options) {
|
|
|
273
282
|
throw error;
|
|
274
283
|
}
|
|
275
284
|
}
|
|
276
|
-
await
|
|
285
|
+
await removeEmptyDebtDirectories(directory, false);
|
|
277
286
|
return removed;
|
|
278
287
|
});
|
|
279
288
|
});
|
|
@@ -281,7 +290,7 @@ export async function nukeTaskAuthority(world, options) {
|
|
|
281
290
|
return "busy";
|
|
282
291
|
return result;
|
|
283
292
|
}
|
|
284
|
-
export async function
|
|
293
|
+
export async function withDebtLocks(input, action) {
|
|
285
294
|
const paths = [
|
|
286
295
|
...(input.allocation ? [allocationLockPath(input.world)] : []),
|
|
287
296
|
...[...new Set(input.ids)]
|
|
@@ -296,7 +305,7 @@ export async function withTaskLocks(input, action) {
|
|
|
296
305
|
held.push(await acquireSqliteTransactionLock({
|
|
297
306
|
path,
|
|
298
307
|
mode: "immediate",
|
|
299
|
-
timeoutMs: input.timeoutMs ??
|
|
308
|
+
timeoutMs: input.timeoutMs ?? DEFAULT_DEBT_LOCK_TIMEOUT_MS,
|
|
300
309
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
301
310
|
}));
|
|
302
311
|
result = await action();
|
|
@@ -318,7 +327,7 @@ export async function withTaskLocks(input, action) {
|
|
|
318
327
|
if (failure === undefined && result !== undefined)
|
|
319
328
|
result = preserveCommittedResult(result, cleanupErrors);
|
|
320
329
|
else if (failure === undefined)
|
|
321
|
-
failure = new AggregateError(cleanupErrors, "
|
|
330
|
+
failure = new AggregateError(cleanupErrors, "Debt lock cleanup failed");
|
|
322
331
|
else {
|
|
323
332
|
const originalFailure = failure;
|
|
324
333
|
failure = new AggregateError([originalFailure, ...cleanupErrors], errorDetail(originalFailure), {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { parseDebtId } from "./identity.js";
|
|
2
|
+
export function debtView(document) {
|
|
3
|
+
return { ...document, namespace: parseDebtId(document.id).namespace };
|
|
4
|
+
}
|
|
5
|
+
export function advanceDebtTimestamp(previous, candidate) {
|
|
6
|
+
return candidate > previous ? candidate : new Date(Date.parse(previous) + 1).toISOString();
|
|
7
|
+
}
|
|
@@ -3,7 +3,7 @@ import { type AkuId } from "../akuma/identity.js";
|
|
|
3
3
|
import { type PrivateStateSeatCloseLag } from "../git/private-state-seat.js";
|
|
4
4
|
import type { GitRepository } from "../git/process.js";
|
|
5
5
|
import { type GitReadObservation } from "../git/read-observation.js";
|
|
6
|
-
import { type DispatchAssociation } from "
|
|
6
|
+
import { type DispatchAssociation } from "../akuma/dispatch-association.js";
|
|
7
7
|
export type Dispatch = Readonly<{
|
|
8
8
|
akuId: AkuId;
|
|
9
9
|
contractId: ContractId;
|
|
@@ -16,7 +16,7 @@ export type DispatchFailure = Readonly<{
|
|
|
16
16
|
kind: "publication-failed";
|
|
17
17
|
diagnostic: string;
|
|
18
18
|
}>;
|
|
19
|
-
|
|
19
|
+
type DispatchPublication = Readonly<{
|
|
20
20
|
kind: "dispatched";
|
|
21
21
|
dispatch: Dispatch;
|
|
22
22
|
seatClose?: readonly PrivateStateSeatCloseLag[];
|
|
@@ -32,6 +32,6 @@ export declare function publishDispatch(input: Readonly<{
|
|
|
32
32
|
akuId: AkuId;
|
|
33
33
|
contractId: ContractId;
|
|
34
34
|
}>): Promise<DispatchPublication>;
|
|
35
|
-
export { dispatchAssociationSchema, NO_DISPATCH_ASSOCIATION, parseDispatchAssociation, type DispatchAssociation, } from "./association.js";
|
|
36
35
|
/** Read selected associations in one targeted observation, isolating per-identity decoding failures. */
|
|
37
36
|
export declare function observeDispatchAssociations(repository: GitRepository | undefined, akuIds: readonly AkuId[]): Promise<ReadonlyMap<AkuId, DispatchAssociation>>;
|
|
37
|
+
export {};
|
|
@@ -5,7 +5,7 @@ import { parseAkuId } from "../akuma/identity.js";
|
|
|
5
5
|
import { appendPrivateStateSeatClose, confirmPrivateStatePublication, mergePrivateStateSeatClose, withPrivateStatePublicationSeat, } from "../git/private-state-seat.js";
|
|
6
6
|
import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readBlob, readGitPaths, updateGitTree, updateRefsAtomically, writeBlob, writeStateCommit, } from "../git/repository.js";
|
|
7
7
|
import { withGitDecodeChannel, withGitReadObservation, withGitTargetedReadObservation, } from "../git/read-observation.js";
|
|
8
|
-
import { NO_DISPATCH_ASSOCIATION } from "
|
|
8
|
+
import { NO_DISPATCH_ASSOCIATION } from "../akuma/dispatch-association.js";
|
|
9
9
|
const DISPATCH_ROOT = "dispatch";
|
|
10
10
|
const DISPATCH_PREFIX = `${DISPATCH_ROOT}/`;
|
|
11
11
|
const DISPATCH_SUFFIX = ".json";
|
|
@@ -186,7 +186,6 @@ export async function publishDispatch(input) {
|
|
|
186
186
|
};
|
|
187
187
|
}));
|
|
188
188
|
}
|
|
189
|
-
export { dispatchAssociationSchema, NO_DISPATCH_ASSOCIATION, parseDispatchAssociation, } from "./association.js";
|
|
190
189
|
/** Read selected associations in one targeted observation, isolating per-identity decoding failures. */
|
|
191
190
|
export async function observeDispatchAssociations(repository, akuIds) {
|
|
192
191
|
const requested = [...new Set(akuIds.map((akuId) => parseAkuId(akuId).id))];
|