@astrosheep/keiyaku 4.6.3 → 4.6.6
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-akuma/SKILL.md +47 -11
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +8 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +37 -25
- package/build/src/akuma/akuma-observe.d.ts +18 -15
- package/build/src/akuma/akuma-observe.js +75 -16
- package/build/src/akuma/akuma-wait.d.ts +4 -3
- package/build/src/akuma/akuma-wait.js +75 -53
- package/build/src/akuma/akuma.d.ts +6 -4
- package/build/src/akuma/akuma.js +4 -0
- package/build/src/akuma/call-initial-tell.d.ts +2 -2
- package/build/src/akuma/call-initial-tell.js +1 -1
- package/build/src/akuma/call-request.d.ts +2 -2
- package/build/src/akuma/heart/index.d.ts +7 -2
- package/build/src/akuma/heart/index.js +50 -5
- package/build/src/akuma/heart/tells.d.ts +33 -2
- package/build/src/akuma/heart/tells.js +24 -18
- package/build/src/akuma/heart/timeline.d.ts +23 -1
- package/build/src/akuma/heart/timeline.js +28 -21
- package/build/src/akuma/projection.d.ts +10 -10
- package/build/src/akuma/providers/pi/index.js +72 -39
- package/build/src/akuma/selection-observation.d.ts +20 -20
- package/build/src/akuma-body.js +1 -0
- package/build/src/alias/index.d.ts +0 -1
- package/build/src/alias/index.js +0 -4
- package/build/src/body/amend.d.ts +0 -4
- package/build/src/body/amend.js +0 -3
- package/build/src/body/region.d.ts +0 -1
- package/build/src/body/region.js +0 -3
- package/build/src/body/verification.d.ts +0 -1
- package/build/src/cli/commands/akuma-grammar.js +23 -66
- package/build/src/cli/commands/akuma.js +17 -30
- package/build/src/cli/commands/contract-grammar.d.ts +14 -1
- package/build/src/cli/commands/contract-grammar.js +54 -21
- package/build/src/cli/commands/contract-help.d.ts +9 -8
- package/build/src/cli/commands/contract-help.js +14 -7
- package/build/src/cli/commands/contract.js +57 -117
- package/build/src/cli/commands/install.d.ts +5 -5
- package/build/src/cli/commands/install.js +1 -4
- package/build/src/cli/commands/task-grammar.js +10 -66
- package/build/src/cli/commands/task.d.ts +0 -1
- package/build/src/cli/commands/task.js +34 -53
- package/build/src/cli/coordinates.d.ts +1 -2
- package/build/src/cli/coordinates.js +1 -4
- package/build/src/cli/parse.d.ts +2 -3
- package/build/src/cli/parse.js +24 -66
- package/build/src/cli/render/akuma.d.ts +3 -16
- package/build/src/cli/render/akuma.js +1 -13
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/contract.js +34 -32
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
- package/build/src/cli/render/kanshi-akuma.js +14 -7
- package/build/src/cli/render/kanshi.d.ts +3 -1
- package/build/src/cli/render/kanshi.js +44 -32
- package/build/src/cli/render/receipt.js +6 -1
- package/build/src/cli/render/task.d.ts +1 -1
- package/build/src/cli/render/task.js +3 -27
- package/build/src/cli/render/terminal.d.ts +6 -2
- package/build/src/cli/render/terminal.js +8 -2
- package/build/src/cli/runtime.js +3 -16
- package/build/src/cli/scan.d.ts +26 -0
- package/build/src/cli/scan.js +82 -0
- package/build/src/cli/streams.d.ts +5 -0
- package/build/src/cli/streams.js +11 -0
- package/build/src/contract-worktree.js +38 -21
- package/build/src/core/facts/codec.d.ts +1 -2
- package/build/src/core/facts/codec.js +5 -11
- package/build/src/core/facts/types.d.ts +16 -2
- package/build/src/core/facts/types.js +15 -0
- package/build/src/core/verbs/abandon.js +3 -9
- package/build/src/core/verbs/amend.js +2 -9
- package/build/src/core/verbs/arc.js +6 -13
- package/build/src/core/verbs/attestation.js +2 -9
- package/build/src/core/verbs/bind.js +2 -9
- package/build/src/core/verbs/deliver.js +2 -9
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +2 -9
- package/build/src/core/verbs/reintegrate.d.ts +1 -1
- package/build/src/core/verbs/reintegrate.js +2 -9
- package/build/src/dispatch/index.d.ts +2 -2
- package/build/src/dispatch/index.js +33 -11
- package/build/src/git/hooks.d.ts +2 -4
- package/build/src/git/hooks.js +0 -12
- package/build/src/git/integration.d.ts +5 -3
- package/build/src/git/integration.js +36 -25
- package/build/src/git/nuke.js +4 -4
- package/build/src/git/observe.d.ts +4 -4
- package/build/src/git/observe.js +5 -5
- package/build/src/git/process.d.ts +1 -4
- package/build/src/git/process.js +1 -11
- package/build/src/git/read-observation.js +1 -1
- package/build/src/git/reconcile.d.ts +1 -1
- package/build/src/git/reconcile.js +15 -13
- package/build/src/git/repository.d.ts +2 -6
- package/build/src/git/repository.js +18 -31
- package/build/src/git/scratch.d.ts +6 -6
- package/build/src/git/scratch.js +110 -46
- package/build/src/git/target-placement.d.ts +5 -5
- package/build/src/git/target-placement.js +18 -33
- package/build/src/git/tender.d.ts +6 -2
- package/build/src/git/tender.js +19 -12
- package/build/src/git/terminal-reconcile.js +24 -13
- package/build/src/git/terminal-seal.d.ts +2 -5
- package/build/src/git/terminal-seal.js +5 -3
- package/build/src/git/workspace.d.ts +17 -13
- package/build/src/git/workspace.js +58 -41
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +8 -1
- package/build/src/kanshi/read.js +72 -7
- package/build/src/kanshi/report.d.ts +12 -0
- package/build/src/library/akuma-creation.d.ts +4 -4
- package/build/src/library/bind.d.ts +1 -63
- package/build/src/library/bind.js +3 -9
- package/build/src/library/contract-creation.js +2 -30
- package/build/src/library/contract-execution.d.ts +0 -1
- package/build/src/library/contract-execution.js +9 -34
- package/build/src/library/contract-operations.d.ts +5 -1
- package/build/src/library/contract-operations.js +7 -3
- package/build/src/library/contract-types.d.ts +1 -1
- package/build/src/library/delivery.d.ts +91 -93
- package/build/src/library/delivery.js +2 -1
- package/build/src/library/input.d.ts +0 -2
- package/build/src/library/input.js +0 -4
- package/build/src/library/invocation.d.ts +0 -1
- package/build/src/library/invocation.js +3 -25
- package/build/src/library/outcome.d.ts +651 -602
- package/build/src/library/outcome.js +4 -4
- package/build/src/library/reconcile.d.ts +6 -0
- package/build/src/library/reconcile.js +31 -1
- package/build/src/library/repo.d.ts +0 -1
- package/build/src/library/selection.d.ts +1 -10
- package/build/src/library/selection.js +14 -15
- package/build/src/protocol/abandon.d.ts +1 -1
- package/build/src/protocol/abandon.js +3 -10
- package/build/src/protocol/amend.js +2 -5
- package/build/src/protocol/arc.d.ts +1 -1
- package/build/src/protocol/arc.js +2 -9
- package/build/src/protocol/attempt.d.ts +3 -20
- package/build/src/protocol/attempt.js +6 -5
- package/build/src/protocol/audit.d.ts +1 -0
- package/build/src/protocol/audit.js +10 -11
- package/build/src/protocol/completion.d.ts +129 -55
- package/build/src/protocol/completion.js +62 -73
- package/build/src/protocol/deliver.d.ts +7 -5
- package/build/src/protocol/deliver.js +74 -44
- package/build/src/protocol/execution-observation.d.ts +2 -4
- package/build/src/protocol/execution-observation.js +3 -7
- package/build/src/protocol/intent.d.ts +1 -1
- package/build/src/protocol/intent.js +1 -0
- package/build/src/protocol/operations.d.ts +24 -12
- package/build/src/protocol/operations.js +36 -15
- package/build/src/protocol/placement.d.ts +2 -1
- package/build/src/protocol/placement.js +21 -5
- package/build/src/protocol/progress.d.ts +1 -1
- package/build/src/protocol/read/status.js +58 -41
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +10 -19
- package/build/src/protocol/review.d.ts +3 -28
- package/build/src/protocol/review.js +10 -37
- package/build/src/protocol/run.d.ts +19 -7
- package/build/src/protocol/run.js +19 -9
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -4
- package/build/src/settlement/holder.js +3 -6
- package/build/src/task/board.d.ts +6 -0
- package/build/src/task/board.js +30 -1
- package/build/src/task/catalog.js +1 -4
- package/build/src/task/compose.d.ts +0 -1
- package/build/src/task/compose.js +0 -1
- package/build/src/task/context.d.ts +0 -1
- package/build/src/task/context.js +0 -3
- package/build/src/task/created-observation.d.ts +5 -1
- package/build/src/task/created-observation.js +12 -5
- package/build/src/task/index.d.ts +1 -1
- package/build/src/task/index.js +7 -6
- package/build/src/task/input.d.ts +0 -6
- package/build/src/task/input.js +2 -14
- package/build/src/task/mutation.d.ts +3 -4
- package/build/src/task/mutation.js +11 -39
- package/build/src/task/operations.d.ts +2 -7
- package/build/src/task/operations.js +37 -49
- package/build/src/task/query.d.ts +0 -1
- package/build/src/task/query.js +1 -4
- package/build/src/task/store.d.ts +0 -2
- package/build/src/task/store.js +27 -11
- package/build/src/verification/declaration.js +3 -2
- package/build/src/verification/execution.d.ts +3 -2
- package/build/src/verification/execution.js +10 -6
- package/build/src/workspace-place.d.ts +0 -1
- package/build/src/workspace-place.js +0 -11
- package/package.json +7 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { observeActiveContractWorld, observeContractsForAdmissionInObservationAt, observeDeliveryTargetAt, withContractReadObservationAt, } from "../../git/observe.js";
|
|
2
|
-
import { decodeContractDocument
|
|
2
|
+
import { decodeContractDocument } from "../../body/decode.js";
|
|
3
3
|
import { dependencyKeys } from "../../core/subject.js";
|
|
4
|
-
import { observeTargetLag, observeWorkspace,
|
|
4
|
+
import { observeTargetLag, observeWorkspace, readConflictHandoffs, conflictRecovery, worktreePath, } from "../../git/workspace.js";
|
|
5
5
|
import { appointmentFor, readPlaceRegister } from "../../workspace-place.js";
|
|
6
6
|
import { gateReports, latestCurrentAttestations } from "../../core/facts/gate.js";
|
|
7
7
|
import { gate, } from "../../core/facts/types.js";
|
|
@@ -26,12 +26,10 @@ function phaseFor(state) {
|
|
|
26
26
|
return "abandoned";
|
|
27
27
|
return "bound";
|
|
28
28
|
}
|
|
29
|
-
function verificationFor(state
|
|
30
|
-
if (document === undefined)
|
|
31
|
-
return undefined;
|
|
32
|
-
if (verificationDefinition(document) === null)
|
|
33
|
-
return { kind: "undeclared" };
|
|
29
|
+
function verificationFor(state) {
|
|
34
30
|
const verifiedGate = gate("verified");
|
|
31
|
+
if (!state.terms.gates.includes(verifiedGate))
|
|
32
|
+
return { kind: "undeclared" };
|
|
35
33
|
const current = latestCurrentAttestations(state, new Set([verifiedGate])).get(verifiedGate);
|
|
36
34
|
if (current !== undefined) {
|
|
37
35
|
const snapshot = dependencyKeys(current.data.subject).find((key) => key.kind === "snapshot")?.value;
|
|
@@ -53,20 +51,26 @@ export function lastJournalAtFor(entries) {
|
|
|
53
51
|
throw new Error("present Contract journal is empty");
|
|
54
52
|
return last.at;
|
|
55
53
|
}
|
|
56
|
-
|
|
54
|
+
function appointedWorkspace(repository, register, state) {
|
|
57
55
|
const appointed = appointmentFor(register, state.id);
|
|
56
|
+
return appointed === undefined
|
|
57
|
+
? undefined
|
|
58
|
+
: { contractId: state.id, place: appointed.place, workspace: worktreePath(repository, appointed.place) };
|
|
59
|
+
}
|
|
60
|
+
async function readSelectedHandoffs(observation, workspaces) {
|
|
61
|
+
return await readConflictHandoffs(observation.repository, observation.readBlobs, workspaces.flatMap((workspace) => (workspace === undefined ? [] : [workspace])));
|
|
62
|
+
}
|
|
63
|
+
async function managedWorkspaceFacts(repository, state, appointed, targetObservation, handoff) {
|
|
58
64
|
if (appointed === undefined) {
|
|
59
65
|
return {
|
|
60
|
-
appointed,
|
|
61
66
|
workspaceObservation: { kind: "unappointed" },
|
|
62
67
|
targetLag: state.coordinates.target === undefined ? { kind: "none" } : { kind: "unknown" },
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
|
-
const path =
|
|
66
|
-
const [workspaceObservation, targetLag
|
|
70
|
+
const path = appointed.workspace;
|
|
71
|
+
const [workspaceObservation, targetLag] = await Promise.all([
|
|
67
72
|
observeWorkspace(repository, { kind: "worktree", path }, path),
|
|
68
73
|
observeTargetLag(repository, path, targetObservation?.head),
|
|
69
|
-
conflictHandoffFor(repository, { contractId: state.id, place: appointed.place, workspace: path }),
|
|
70
74
|
]);
|
|
71
75
|
const projectedWorkspaceObservation = handoff !== undefined &&
|
|
72
76
|
(workspaceObservation.kind === "clean" || workspaceObservation.kind === "dirty") &&
|
|
@@ -80,7 +84,7 @@ async function managedWorkspaceFacts(repository, state, register, targetObservat
|
|
|
80
84
|
},
|
|
81
85
|
}
|
|
82
86
|
: workspaceObservation;
|
|
83
|
-
return {
|
|
87
|
+
return { workspaceObservation: projectedWorkspaceObservation, targetLag };
|
|
84
88
|
}
|
|
85
89
|
function afterEndpoint(state) {
|
|
86
90
|
if (state === undefined || state === null)
|
|
@@ -104,12 +108,11 @@ function reverseDependents(id, rows) {
|
|
|
104
108
|
.sort((left, right) => left.contractId.localeCompare(right.contractId));
|
|
105
109
|
}
|
|
106
110
|
async function rowFor(input) {
|
|
107
|
-
const { repository, state, bindAt, lastJournalAt, targetObservation,
|
|
108
|
-
const workspace = state.coordinates.workspace;
|
|
111
|
+
const { repository, state, bindAt, lastJournalAt, targetObservation, workspace, handoff, after, dependents } = input;
|
|
109
112
|
const gates = gateReports(state);
|
|
110
113
|
const document = documentFor(state);
|
|
111
|
-
const verification = verificationFor(state
|
|
112
|
-
const
|
|
114
|
+
const verification = verificationFor(state);
|
|
115
|
+
const facts = await managedWorkspaceFacts(repository, state, workspace, targetObservation, handoff);
|
|
113
116
|
return {
|
|
114
117
|
id: state.id,
|
|
115
118
|
title: titleFor(document),
|
|
@@ -117,11 +120,11 @@ async function rowFor(input) {
|
|
|
117
120
|
phaseAt: phaseAtFor(state, bindAt),
|
|
118
121
|
lastJournalAt,
|
|
119
122
|
disposition: state.terminal === null ? "active" : "terminal",
|
|
120
|
-
workspace,
|
|
121
|
-
worktreePath:
|
|
122
|
-
workspaceObservation,
|
|
123
|
+
workspace: state.coordinates.workspace,
|
|
124
|
+
worktreePath: workspace?.workspace ?? null,
|
|
125
|
+
workspaceObservation: facts.workspaceObservation,
|
|
123
126
|
target: state.coordinates.target ?? null,
|
|
124
|
-
targetLag,
|
|
127
|
+
targetLag: facts.targetLag,
|
|
125
128
|
delivery: state.delivery === null || state.currentIntegration === null
|
|
126
129
|
? null
|
|
127
130
|
: { ...state.delivery.data, integration: state.currentIntegration },
|
|
@@ -163,23 +166,27 @@ export async function readContractBoard(observation, include) {
|
|
|
163
166
|
}
|
|
164
167
|
}
|
|
165
168
|
const register = await readPlaceRegister(observation.repository);
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
169
|
+
const selected = [...contracts.values()].flatMap((value) => value.state === null
|
|
170
|
+
? []
|
|
171
|
+
: [
|
|
172
|
+
{
|
|
173
|
+
...value,
|
|
174
|
+
state: value.state,
|
|
175
|
+
workspace: appointedWorkspace(observation.repository, register, value.state),
|
|
176
|
+
},
|
|
177
|
+
]);
|
|
178
|
+
const handoffs = await readSelectedHandoffs(observation, selected.map(({ workspace }) => workspace));
|
|
179
|
+
const projected = await Promise.all(selected.map(async ({ state, entries, workspace }) => await rowFor({
|
|
180
|
+
repository: observation.repository,
|
|
181
|
+
state,
|
|
182
|
+
bindAt: entries[0].at,
|
|
183
|
+
lastJournalAt: lastJournalAtFor(entries),
|
|
184
|
+
targetObservation: await observeDeliveryTargetAt(observation, state),
|
|
185
|
+
workspace,
|
|
186
|
+
handoff: handoffs.get(state.id),
|
|
187
|
+
after: afterEdges(state, endpoints),
|
|
188
|
+
dependents: [],
|
|
189
|
+
})));
|
|
183
190
|
const rows = projected.map((row) => ({ ...row, dependents: reverseDependents(row.id, projected) }));
|
|
184
191
|
return {
|
|
185
192
|
root: observation.repository.primaryWorktree,
|
|
@@ -218,13 +225,19 @@ export async function readContractCatalogue(observation, limit) {
|
|
|
218
225
|
const afterIds = selected.rows.flatMap(({ state }) => state.terms.after);
|
|
219
226
|
const endpoints = await afterEndpointMap(observation, new Map(observed.eligibility), afterIds);
|
|
220
227
|
const register = await readPlaceRegister(observation.repository);
|
|
221
|
-
const
|
|
228
|
+
const selectedWorkspaces = selected.rows.map((value) => ({
|
|
229
|
+
...value,
|
|
230
|
+
workspace: appointedWorkspace(observation.repository, register, value.state),
|
|
231
|
+
}));
|
|
232
|
+
const handoffs = await readSelectedHandoffs(observation, selectedWorkspaces.map(({ workspace }) => workspace));
|
|
233
|
+
const rows = await Promise.all(selectedWorkspaces.map(async ({ state, bindAt, lastJournalAt, workspace }) => await rowFor({
|
|
222
234
|
repository: observation.repository,
|
|
223
235
|
state,
|
|
224
236
|
bindAt,
|
|
225
237
|
lastJournalAt,
|
|
226
238
|
targetObservation: await observeDeliveryTargetAt(observation, state),
|
|
227
|
-
|
|
239
|
+
workspace,
|
|
240
|
+
handoff: handoffs.get(state.id),
|
|
228
241
|
after: afterEdges(state, endpoints),
|
|
229
242
|
dependents: reverseDependentsFromStates(state.id, active),
|
|
230
243
|
})));
|
|
@@ -257,6 +270,9 @@ export async function readContractObservation(observation, id) {
|
|
|
257
270
|
if (state === null)
|
|
258
271
|
return { kind: "missing", id };
|
|
259
272
|
const endpoints = await afterEndpointMap(observation, new Map([[id, state]]), state.terms.after);
|
|
273
|
+
const register = await readPlaceRegister(observation.repository);
|
|
274
|
+
const workspace = appointedWorkspace(observation.repository, register, state);
|
|
275
|
+
const handoffs = await readSelectedHandoffs(observation, [workspace]);
|
|
260
276
|
return {
|
|
261
277
|
kind: "present",
|
|
262
278
|
row: await rowFor({
|
|
@@ -265,7 +281,8 @@ export async function readContractObservation(observation, id) {
|
|
|
265
281
|
bindAt: record.entries[0].at,
|
|
266
282
|
lastJournalAt: lastJournalAtFor(record.entries),
|
|
267
283
|
targetObservation: await observeDeliveryTargetAt(observation, state),
|
|
268
|
-
|
|
284
|
+
workspace,
|
|
285
|
+
handoff: handoffs.get(state.id),
|
|
269
286
|
after: afterEdges(state, endpoints),
|
|
270
287
|
dependents: [],
|
|
271
288
|
}),
|
|
@@ -11,7 +11,7 @@ type TargetMissing = Readonly<{
|
|
|
11
11
|
kind: "target-missing";
|
|
12
12
|
contractId: ContractId;
|
|
13
13
|
}>;
|
|
14
|
-
|
|
14
|
+
type ReintegrationRefusal = ReintegrateRefusal | TargetMissing | IntegrationPreparationRefusal;
|
|
15
15
|
export type ReintegrationResult = (AcceptedAdmission & Readonly<{
|
|
16
16
|
value: ReintegratedData;
|
|
17
17
|
}>) | Readonly<{
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { contractState } from "../core/facts/observation.js";
|
|
2
2
|
import { decideReintegrate } from "../core/verbs/reintegrate.js";
|
|
3
|
-
import { materializeReintegrationSnapshot, persistedTender, planIntegration, } from "../git/integration.js";
|
|
3
|
+
import { materializeReintegrationSnapshot, persistedTender, planIntegration, reusableIntegrationSnapshot, } from "../git/integration.js";
|
|
4
4
|
import { observeContractsForAdmissionAt } from "../git/observe.js";
|
|
5
5
|
import { appendPrivateStateSeatClose, mergePrivateStateSeatClose, withPrivateStatePublicationSeat, } from "../git/private-state-seat.js";
|
|
6
6
|
import { admitDecidedOffer, mintAttempts } from "./attempt.js";
|
|
7
|
-
import { timestamp } from "./operations.js";
|
|
8
|
-
import {
|
|
7
|
+
import { recordedIntegrationSnapshots, timestamp } from "./operations.js";
|
|
8
|
+
import { externalPreparation, STALE_PRIVATE_STATE_PREPARATION, } from "./run.js";
|
|
9
9
|
import { runUnderTargetPlacementFence } from "./placement.js";
|
|
10
10
|
function reintegrationResultWithSeatClose(outcome) {
|
|
11
11
|
return mergePrivateStateSeatClose(outcome, (value, closeLag) => {
|
|
@@ -16,23 +16,16 @@ function reintegrationResultWithSeatClose(outcome) {
|
|
|
16
16
|
}
|
|
17
17
|
/** Plan and materialize the target-specific reintegration artifacts outside the publication seat. */
|
|
18
18
|
async function prepareExternalReintegration(input) {
|
|
19
|
-
|
|
20
|
-
const state = contractState(observation.decision, input.contractId);
|
|
21
|
-
if (state === null)
|
|
22
|
-
return { kind: "unavailable" };
|
|
23
|
-
return {
|
|
24
|
-
kind: "artifacts",
|
|
25
|
-
witness: contractStateWitness(state),
|
|
26
|
-
artifacts: await planReintegrationArtifacts(input, state),
|
|
27
|
-
};
|
|
19
|
+
return await externalPreparation({ ...input, scope: input.repository }, (observation, state) => planReintegrationArtifacts(input, state, recordedIntegrationSnapshots(observation.journals.get(state.id)?.entries ?? [])));
|
|
28
20
|
}
|
|
29
|
-
async function planReintegrationArtifacts(input, state) {
|
|
21
|
+
async function planReintegrationArtifacts(input, state, recordedIntegrations) {
|
|
30
22
|
if (state.delivery === null || state.currentIntegration === null)
|
|
31
23
|
return { kind: "defer" };
|
|
32
24
|
const planned = await planIntegration(input.repository, { contractId: input.contractId, coordinates: state.coordinates }, await persistedTender(input.repository, state.delivery.data.tenderSnapshot), state.delivery.data.policy.requireBranchesToBeUpToDate);
|
|
33
25
|
if (planned.kind === "refused")
|
|
34
26
|
return { kind: "refused", refusal: planned.refusal };
|
|
35
|
-
const snapshot = await
|
|
27
|
+
const snapshot = (await reusableIntegrationSnapshot(input.repository, planned.data.tree, planned.data.predecessor, recordedIntegrations)) ??
|
|
28
|
+
(await materializeReintegrationSnapshot(input.repository, planned.data.tree, planned.data.predecessor, state.delivery.data.integration.snapshot));
|
|
36
29
|
return {
|
|
37
30
|
kind: "prepared",
|
|
38
31
|
data: { predecessor: planned.data.predecessor, snapshot },
|
|
@@ -80,14 +73,12 @@ async function runReintegration(input) {
|
|
|
80
73
|
if (decision.kind === "refused")
|
|
81
74
|
return { kind: "refused", refusal: decision.refusal };
|
|
82
75
|
const admitted = await admitDecidedOffer({
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
...input,
|
|
77
|
+
scope: input.repository,
|
|
85
78
|
seat,
|
|
86
|
-
|
|
79
|
+
observation,
|
|
87
80
|
attempt,
|
|
88
81
|
offer: decision.offer,
|
|
89
|
-
primaryContract: input.contractId,
|
|
90
|
-
...(input.progress === undefined ? {} : { progress: input.progress }),
|
|
91
82
|
...(assembled.kind === "prepared" ? { assertions: [assembled.assertion] } : {}),
|
|
92
83
|
});
|
|
93
84
|
if (admitted.kind === "accepted") {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { type ActiveContractRefusal } from "../core/facts/observation.js";
|
|
3
|
-
import type { AttestationData
|
|
3
|
+
import type { AttestationData } from "../core/facts/types.js";
|
|
4
4
|
import type { LeadingOutcome } from "./outcome.js";
|
|
5
|
-
import type { MutationOperationInput
|
|
5
|
+
import type { MutationOperationInput } from "./operations.js";
|
|
6
6
|
type ReviewPreparationRefusal = Readonly<{
|
|
7
7
|
kind: "worktree-missing";
|
|
8
8
|
contractId: import("../core/facts/types.js").ContractId;
|
|
@@ -12,18 +12,6 @@ type ReviewOperationInput = MutationOperationInput & Readonly<{
|
|
|
12
12
|
verdict: AttestationData["verdict"];
|
|
13
13
|
summary?: string;
|
|
14
14
|
}>;
|
|
15
|
-
declare const reviewWorkspaceEvidenceSchema: z.ZodObject<{
|
|
16
|
-
staged: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
17
|
-
unstaged: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
18
|
-
untracked: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
19
|
-
shortStat: z.ZodObject<{
|
|
20
|
-
filesChanged: z.ZodNumber;
|
|
21
|
-
insertions: z.ZodNumber;
|
|
22
|
-
deletions: z.ZodNumber;
|
|
23
|
-
}, z.core.$strict>;
|
|
24
|
-
unmergedPaths: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
25
|
-
}, z.core.$strict>;
|
|
26
|
-
type ReviewWorkspaceEvidence = z.infer<typeof reviewWorkspaceEvidenceSchema>;
|
|
27
15
|
export declare const reviewAdmissionValueSchema: z.ZodObject<{
|
|
28
16
|
workspace: z.ZodOptional<z.ZodObject<{
|
|
29
17
|
staged: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
@@ -37,19 +25,6 @@ export declare const reviewAdmissionValueSchema: z.ZodObject<{
|
|
|
37
25
|
unmergedPaths: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
38
26
|
}, z.core.$strict>>;
|
|
39
27
|
}, z.core.$strict>;
|
|
40
|
-
|
|
41
|
-
export declare function prepareReview(repository: RepositoryScope, stage: Readonly<{
|
|
42
|
-
contractId: import("../core/facts/types.js").ContractId;
|
|
43
|
-
coordinates: ContractState["coordinates"];
|
|
44
|
-
}>): Promise<{
|
|
45
|
-
kind: "prepared";
|
|
46
|
-
data: Readonly<{
|
|
47
|
-
changeId: DeliverData["integration"]["changeId"];
|
|
48
|
-
workspace?: ReviewWorkspaceEvidence;
|
|
49
|
-
}>;
|
|
50
|
-
} | {
|
|
51
|
-
kind: "refused";
|
|
52
|
-
refusal: ReviewPreparationRefusal;
|
|
53
|
-
}>;
|
|
28
|
+
type ReviewAdmissionValue = z.infer<typeof reviewAdmissionValueSchema>;
|
|
54
29
|
export declare function admitReviewOperation(input: ReviewOperationInput): Promise<LeadingOutcome<ReviewAdmissionValue, ReviewRefusal>>;
|
|
55
30
|
export {};
|
|
@@ -4,7 +4,7 @@ import { worktreeChangeId } from "../git/integration.js";
|
|
|
4
4
|
import { captureTender, dirtyTenderDelta, dirtyTenderRefusal } from "../git/tender.js";
|
|
5
5
|
import { observeContractsForAdmissionAt } from "../git/observe.js";
|
|
6
6
|
import { unmergedWorkspacePaths, worktreePath } from "../git/workspace.js";
|
|
7
|
-
import {
|
|
7
|
+
import { externalPreparation, privateStateSeatAttempt, runBoundedAttempts, sameWorktreeWitness, STALE_PRIVATE_STATE_PREPARATION, } from "./run.js";
|
|
8
8
|
import { dependencyKeySet } from "../core/subject.js";
|
|
9
9
|
import { contractState } from "../core/facts/observation.js";
|
|
10
10
|
import { gate } from "../core/facts/types.js";
|
|
@@ -51,18 +51,6 @@ async function captureReviewableWorktree(repository, stage) {
|
|
|
51
51
|
},
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
export async function prepareReview(repository, stage) {
|
|
55
|
-
const prepared = await captureReviewableWorktree(repository, stage);
|
|
56
|
-
if (prepared.kind === "refused")
|
|
57
|
-
return prepared;
|
|
58
|
-
return {
|
|
59
|
-
kind: "prepared",
|
|
60
|
-
data: {
|
|
61
|
-
changeId: prepared.data.changeId,
|
|
62
|
-
...(prepared.data.workspace === undefined ? {} : { workspace: prepared.data.workspace }),
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
54
|
function preparedReviewCapture(input, state, changeId) {
|
|
67
55
|
return {
|
|
68
56
|
kind: "prepared",
|
|
@@ -95,25 +83,19 @@ async function recaptureReviewWorktree(input, state) {
|
|
|
95
83
|
}
|
|
96
84
|
/** Capture the reviewable worktree from one non-authoritative private-state read. */
|
|
97
85
|
async function prepareExternalReview(input) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
coordinates: state.coordinates,
|
|
105
|
-
});
|
|
106
|
-
return {
|
|
107
|
-
kind: "artifacts",
|
|
108
|
-
witness: contractStateWitness(state),
|
|
109
|
-
artifacts: prepared.kind === "refused"
|
|
86
|
+
return await externalPreparation(input, async (_, state) => {
|
|
87
|
+
const prepared = await captureReviewableWorktree(input.scope, {
|
|
88
|
+
contractId: state.id,
|
|
89
|
+
coordinates: state.coordinates,
|
|
90
|
+
});
|
|
91
|
+
return prepared.kind === "refused"
|
|
110
92
|
? { kind: "refused", refusal: prepared.refusal }
|
|
111
93
|
: {
|
|
112
94
|
kind: "captured",
|
|
113
95
|
...(prepared.data.workspace === undefined ? {} : { workspace: prepared.data.workspace }),
|
|
114
96
|
worktree: reviewWorktreeInput(prepared),
|
|
115
|
-
}
|
|
116
|
-
};
|
|
97
|
+
};
|
|
98
|
+
});
|
|
117
99
|
}
|
|
118
100
|
/** Assemble the in-custody attestation input from the fresh Contract and validated artifacts. */
|
|
119
101
|
async function assembleReviewAttempt(input, observation, external) {
|
|
@@ -149,16 +131,7 @@ async function decideAndAdmitReview(input, attempt, seat, observation, assembled
|
|
|
149
131
|
});
|
|
150
132
|
if (decision.kind === "refused")
|
|
151
133
|
return { kind: "refused", refusal: decision.refusal };
|
|
152
|
-
const admission = await admitDecidedOffer({
|
|
153
|
-
channel: input.channel,
|
|
154
|
-
repository: input.scope,
|
|
155
|
-
seat,
|
|
156
|
-
decisionObservation: observation,
|
|
157
|
-
attempt,
|
|
158
|
-
offer: decision.offer,
|
|
159
|
-
primaryContract: input.contractId,
|
|
160
|
-
...(input.progress === undefined ? {} : { progress: input.progress }),
|
|
161
|
-
});
|
|
134
|
+
const admission = await admitDecidedOffer({ ...input, seat, observation, attempt, offer: decision.offer });
|
|
162
135
|
if (admission.kind !== "accepted")
|
|
163
136
|
return admission;
|
|
164
137
|
return {
|
|
@@ -7,7 +7,7 @@ import type { GitRepository } from "../git/process.js";
|
|
|
7
7
|
import { type GitRefAssertion } from "../git/repository.js";
|
|
8
8
|
import type { AttemptContext, DecideInput, OfferDecision } from "../core/decide.js";
|
|
9
9
|
import type { Offer, TreeUpdate } from "../core/facts/offer.js";
|
|
10
|
-
import type { ChangeId, ContractHead, ContractId, SnapshotId } from "../core/facts/types.js";
|
|
10
|
+
import type { ChangeId, ContractHead, ContractId, ContractState, SnapshotId } from "../core/facts/types.js";
|
|
11
11
|
import type { GitObjectId } from "../git/identity.js";
|
|
12
12
|
import { type AcceptedAdmission, type AttemptTerminal } from "./attempt.js";
|
|
13
13
|
export declare const STALE_PRIVATE_STATE_PREPARATION: {
|
|
@@ -104,14 +104,14 @@ type ProtocolAdmission<Input extends Readonly<{
|
|
|
104
104
|
observationSelection?: GitTreeSelection;
|
|
105
105
|
}>;
|
|
106
106
|
/** An intent whose invocation is already its decision input. */
|
|
107
|
-
|
|
107
|
+
type DirectRunProtocolInput<Seed extends Readonly<{
|
|
108
108
|
contractId: ContractId;
|
|
109
109
|
}>, Refusal> = ProtocolAdmission<Seed, Refusal> & Readonly<{
|
|
110
110
|
input: Seed;
|
|
111
111
|
preparation?: undefined;
|
|
112
112
|
}>;
|
|
113
113
|
/** An intent whose repeatable preparation runs outside custody and is assembled inside it. */
|
|
114
|
-
|
|
114
|
+
type SplitRunProtocolInput<Input extends Readonly<{
|
|
115
115
|
contractId: ContractId;
|
|
116
116
|
}>, Refusal, Seed extends Readonly<{
|
|
117
117
|
contractId: ContractId;
|
|
@@ -124,7 +124,7 @@ export type RunProtocolInput<Input extends Readonly<{
|
|
|
124
124
|
}>, Refusal, Seed extends Readonly<{
|
|
125
125
|
contractId: ContractId;
|
|
126
126
|
}> = Input, Prepared = Seed> = DirectRunProtocolInput<Seed, Refusal> | SplitRunProtocolInput<Input, Refusal, Seed, Prepared>;
|
|
127
|
-
|
|
127
|
+
type PreparedProtocolAttempt<Refusal> = Readonly<{
|
|
128
128
|
kind: "stale";
|
|
129
129
|
}> | Readonly<{
|
|
130
130
|
kind: "refused";
|
|
@@ -143,7 +143,6 @@ export type PreparedProtocolAttempt<Refusal> = Readonly<{
|
|
|
143
143
|
export type ContractStateWitness = Readonly<{
|
|
144
144
|
head: ContractHead | null;
|
|
145
145
|
}>;
|
|
146
|
-
export declare function contractStateWitness(state: ContractStateWitness): ContractStateWitness;
|
|
147
146
|
/**
|
|
148
147
|
* A physical worktree capture carried across custody as a witness, never as authority.
|
|
149
148
|
*
|
|
@@ -162,8 +161,21 @@ export type WorktreeWitness = Readonly<{
|
|
|
162
161
|
changeId: ChangeId;
|
|
163
162
|
}>;
|
|
164
163
|
export declare function sameWorktreeWitness(prepared: WorktreeWitness | undefined, fresh: WorktreeWitness | undefined): boolean;
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
/**
|
|
165
|
+
* The repeatable outside-custody preamble shared by prepared operations: one non-authoritative
|
|
166
|
+
* observation of the invoked Contract, and the artifacts its fresh state justifies.
|
|
167
|
+
*/
|
|
168
|
+
export declare function externalPreparation<Artifacts>(input: Readonly<{
|
|
169
|
+
scope: GitRepository;
|
|
170
|
+
channel: GitDecodeChannel;
|
|
171
|
+
contractId: ContractId;
|
|
172
|
+
}>, artifacts: (observation: GitDecisionObservation, state: ContractState) => Promise<Artifacts>): Promise<Readonly<{
|
|
173
|
+
kind: "unavailable";
|
|
174
|
+
}> | Readonly<{
|
|
175
|
+
kind: "artifacts";
|
|
176
|
+
witness: ContractStateWitness;
|
|
177
|
+
artifacts: Artifacts;
|
|
178
|
+
}>>;
|
|
167
179
|
export declare function privateStateSeatAttempt<T>(repository: GitRepository, action: (seat: PrivateStatePublicationSeat) => Promise<T>, wrap: (outcome: PrivateStateSeatOutcome<T>) => T): Promise<T | AttemptTerminal>;
|
|
168
180
|
/** Form one decided offer without admitting or reinterpreting it. */
|
|
169
181
|
export declare function prepareProtocolAttempt<Input extends Readonly<{
|
|
@@ -3,6 +3,7 @@ import { publicationFailedSchema } from "../git/admission.js";
|
|
|
3
3
|
import { extendAdmissionPathsAt, observeContractsForAdmissionAt } from "../git/observe.js";
|
|
4
4
|
import { appendPrivateStateSeatClose, isPrivateStateSeatContention, mergePrivateStateSeatClose, withPrivateStatePublicationSeat, } from "../git/private-state-seat.js";
|
|
5
5
|
import { GIT_REF, readRefs } from "../git/repository.js";
|
|
6
|
+
import { contractState } from "../core/facts/observation.js";
|
|
6
7
|
import { admitDecidedOffer } from "./attempt.js";
|
|
7
8
|
export const STALE_PRIVATE_STATE_PREPARATION = {
|
|
8
9
|
kind: "stale",
|
|
@@ -26,7 +27,7 @@ export async function runBoundedAttempts(attempts, attempt) {
|
|
|
26
27
|
}
|
|
27
28
|
return { kind: "exhausted" };
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
function contractStateWitness(state) {
|
|
30
31
|
return { head: state.head };
|
|
31
32
|
}
|
|
32
33
|
export function sameWorktreeWitness(prepared, fresh) {
|
|
@@ -38,17 +39,28 @@ export function sameWorktreeWitness(prepared, fresh) {
|
|
|
38
39
|
prepared.dirty === fresh.dirty &&
|
|
39
40
|
prepared.changeId === fresh.changeId);
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
async function privateStateAssertionsMatch(repository, assertions) {
|
|
42
43
|
if (assertions.length === 0)
|
|
43
44
|
return true;
|
|
44
45
|
const refs = await readRefs(repository, [GIT_REF, ...assertions.map((assertion) => assertion.ref)]);
|
|
45
46
|
return assertions.every((assertion) => refs.get(assertion.ref) === assertion.oid);
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
function publicationFailedFromSeatError(error) {
|
|
48
49
|
if (isPrivateStateSeatContention(error))
|
|
49
50
|
return { kind: "publication-failed", diagnostic: error.message };
|
|
50
51
|
throw error;
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The repeatable outside-custody preamble shared by prepared operations: one non-authoritative
|
|
55
|
+
* observation of the invoked Contract, and the artifacts its fresh state justifies.
|
|
56
|
+
*/
|
|
57
|
+
export async function externalPreparation(input, artifacts) {
|
|
58
|
+
const observation = await observeContractsForAdmissionAt(input.scope, input.channel, [input.contractId]);
|
|
59
|
+
const state = contractState(observation.decision, input.contractId);
|
|
60
|
+
if (state === null)
|
|
61
|
+
return { kind: "unavailable" };
|
|
62
|
+
return { kind: "artifacts", witness: contractStateWitness(state), artifacts: await artifacts(observation, state) };
|
|
63
|
+
}
|
|
52
64
|
export async function privateStateSeatAttempt(repository, action, wrap) {
|
|
53
65
|
try {
|
|
54
66
|
return wrap(await withPrivateStatePublicationSeat(repository, action));
|
|
@@ -100,16 +112,14 @@ async function admitDecidedProtocolOffer(admission, primaryContract, seat, decis
|
|
|
100
112
|
if (decided.kind === "refused")
|
|
101
113
|
return decided;
|
|
102
114
|
return await admitDecidedOffer({
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
...admission,
|
|
116
|
+
scope: admission.repository,
|
|
117
|
+
contractId: primaryContract,
|
|
105
118
|
seat,
|
|
106
|
-
|
|
119
|
+
observation: decided.observation,
|
|
107
120
|
attempt: decided.attempt,
|
|
108
121
|
offer: decided.offer,
|
|
109
|
-
primaryContract,
|
|
110
|
-
...(admission.progress === undefined ? {} : { progress: admission.progress }),
|
|
111
122
|
assertions: decided.assertions,
|
|
112
|
-
...(admission.validateAdmission === undefined ? {} : { validateAdmission: admission.validateAdmission }),
|
|
113
123
|
});
|
|
114
124
|
}
|
|
115
125
|
function protocolAttemptWithSeatClose(outcome) {
|
|
Binary file
|
|
@@ -26,10 +26,9 @@ type TaskHolderAdmission<T extends AdmissionOutcome> = Readonly<{
|
|
|
26
26
|
taskId: TaskId;
|
|
27
27
|
diagnostic: string;
|
|
28
28
|
}>;
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function claimTaskHolderWithFence<T extends AdmissionOutcome>(repository: GitRepository, taskId: TaskId, action: () => T | Promise<T>): Promise<TaskHolderAdmission<T>>;
|
|
29
|
+
export declare function admitWithTaskHolderFence<T extends AdmissionOutcome>(repository: GitRepository, taskId: TaskId, action: () => T | Promise<T>): Promise<TaskHolderAdmission<T>>;
|
|
31
30
|
export declare function releaseTaskHolder(channel: GitDecodeChannel, observation: GitDecisionObservation, owner: ContractId): Promise<TreeUpdate | null>;
|
|
32
|
-
|
|
31
|
+
type TaskHolderReleasePublication = Readonly<{
|
|
33
32
|
kind: "released";
|
|
34
33
|
}> | Readonly<{
|
|
35
34
|
kind: "not-held";
|
|
@@ -40,7 +39,6 @@ export type TaskHolderReleasePublication = Readonly<{
|
|
|
40
39
|
/** Publish the released holder against the same frozen observation that decided the release. */
|
|
41
40
|
export declare function publishTaskHolderRelease(repository: GitRepository, channel: GitDecodeChannel, observation: GitDecisionObservation, owner: ContractId, seat: PrivateStatePublicationSeat): Promise<TaskHolderReleasePublication>;
|
|
42
41
|
export declare function readTaskHolderProjectionFromDecision(channel: GitDecodeChannel, observation: GitDecisionObservation): Promise<TaskHolderProjection>;
|
|
43
|
-
export declare function observeTaskHolderProjection(repository: GitRepository, channel: GitDecodeChannel): Promise<TaskHolderProjection>;
|
|
44
42
|
export declare function releaseTaskHolderWithFence<T extends AdmissionOutcome>(repository: GitRepository, channel: GitDecodeChannel, owner: ContractId, action: () => T | Promise<T>): Promise<TaskHolderAdmission<T>>;
|
|
45
43
|
export declare function readTaskHoldersAt(observation: Pick<GitReadObservation, "snapshot" | "readBlobs">): Promise<readonly TaskHolder[]>;
|
|
46
44
|
export declare function readTaskHolderProjectionAt(observation: GitReadObservation): Promise<TaskHolderProjection>;
|
|
@@ -87,7 +87,7 @@ export function claimTaskHolder(taskId, owner) {
|
|
|
87
87
|
function detail(error) {
|
|
88
88
|
return error instanceof Error ? error.message : String(error);
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
function finishTaskHolderAdmission(taskId, result, close) {
|
|
91
91
|
try {
|
|
92
92
|
close();
|
|
93
93
|
return { kind: "completed", result };
|
|
@@ -98,7 +98,7 @@ export function finishTaskHolderAdmission(taskId, result, close) {
|
|
|
98
98
|
return { kind: "accepted-release-failed", result, taskId, diagnostic: detail(error) };
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
async function admitWithTaskHolderFence(repository, taskId, action) {
|
|
101
|
+
export async function admitWithTaskHolderFence(repository, taskId, action) {
|
|
102
102
|
const held = await acquireTaskSettlementFence(repository, taskId);
|
|
103
103
|
let result;
|
|
104
104
|
try {
|
|
@@ -115,9 +115,6 @@ async function admitWithTaskHolderFence(repository, taskId, action) {
|
|
|
115
115
|
}
|
|
116
116
|
return finishTaskHolderAdmission(taskId, result, () => held.close());
|
|
117
117
|
}
|
|
118
|
-
export function claimTaskHolderWithFence(repository, taskId, action) {
|
|
119
|
-
return admitWithTaskHolderFence(repository, taskId, action);
|
|
120
|
-
}
|
|
121
118
|
export async function releaseTaskHolder(channel, observation, owner) {
|
|
122
119
|
const current = (await readTaskHolderProjectionFromDecision(channel, observation)).get(owner) ?? null;
|
|
123
120
|
return current === null || current.disposition !== "held" ? null : update({ ...current, disposition: "released" });
|
|
@@ -180,7 +177,7 @@ export async function readTaskHolderProjectionFromDecision(channel, observation)
|
|
|
180
177
|
};
|
|
181
178
|
return projectTaskHolders(await readTaskHoldersAt(read));
|
|
182
179
|
}
|
|
183
|
-
|
|
180
|
+
function observeTaskHolderProjection(repository, channel) {
|
|
184
181
|
return withGitTargetedReadObservation(repository, channel, taskHolderObservationSelection(), readTaskHolderProjectionAt);
|
|
185
182
|
}
|
|
186
183
|
async function heldTaskForContract(repository, channel, owner) {
|
|
@@ -118,6 +118,12 @@ export declare function projectOwnedDetailFacts(board: TaskBoard, id: TaskId): T
|
|
|
118
118
|
export declare function projectDetailFacts(board: TaskBoard, id: TaskId, relations: TaskRelationProjection): TaskDetailFacts | null;
|
|
119
119
|
export declare function projectTaskRow(board: TaskBoard, relations: TaskRelationProjection, task: TaskDocument): TaskRow;
|
|
120
120
|
export declare function projectRows(board: TaskBoard, relations: TaskRelationProjection, scope: readonly string[] | null, selection: "active" | "closed" | "all"): readonly TaskRow[];
|
|
121
|
+
/**
|
|
122
|
+
* Rows for the identities that created work, grouped by creator. Only documents a
|
|
123
|
+
* requested identity created reach row projection, and each group keeps the
|
|
124
|
+
* established row order.
|
|
125
|
+
*/
|
|
126
|
+
export declare function projectCreatedByRows(board: TaskBoard, relations: TaskRelationProjection, createdByIds: readonly string[]): ReadonlyMap<string, readonly TaskRow[]>;
|
|
121
127
|
export declare function projectBlocked(board: TaskBoard, scope: readonly string[] | null, relations: TaskRelationProjection): readonly BlockedTaskRow[];
|
|
122
128
|
export declare function projectStatusRows(board: TaskBoard, relations: TaskRelationProjection, scope: readonly string[] | null): ({
|
|
123
129
|
id: `task/${string}`;
|
package/build/src/task/board.js
CHANGED
|
@@ -142,7 +142,36 @@ export function projectRows(board, relations, scope, selection) {
|
|
|
142
142
|
.filter((task) => inScope(task, scope))
|
|
143
143
|
.filter((task) => selection === "all" || (selection === "closed") === terminal(task.state))
|
|
144
144
|
.map((task) => projectTaskRow(board, relations, task))
|
|
145
|
-
.sort(
|
|
145
|
+
.sort(compareTaskRows);
|
|
146
|
+
}
|
|
147
|
+
/** The established Task row order: priority first, then canonical identity bytes. */
|
|
148
|
+
function compareTaskRows(left, right) {
|
|
149
|
+
return left.priority - right.priority || Buffer.compare(Buffer.from(left.id), Buffer.from(right.id));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Rows for the identities that created work, grouped by creator. Only documents a
|
|
153
|
+
* requested identity created reach row projection, and each group keeps the
|
|
154
|
+
* established row order.
|
|
155
|
+
*/
|
|
156
|
+
export function projectCreatedByRows(board, relations, createdByIds) {
|
|
157
|
+
const requested = new Set(createdByIds);
|
|
158
|
+
const attributed = [];
|
|
159
|
+
for (const task of board.tasks.values()) {
|
|
160
|
+
const createdBy = task.createdBy;
|
|
161
|
+
if (createdBy === undefined || !requested.has(createdBy))
|
|
162
|
+
continue;
|
|
163
|
+
attributed.push({ createdBy, row: projectTaskRow(board, relations, task) });
|
|
164
|
+
}
|
|
165
|
+
attributed.sort((left, right) => compareTaskRows(left.row, right.row));
|
|
166
|
+
const grouped = new Map();
|
|
167
|
+
for (const { createdBy, row } of attributed) {
|
|
168
|
+
const rows = grouped.get(createdBy);
|
|
169
|
+
if (rows === undefined)
|
|
170
|
+
grouped.set(createdBy, [row]);
|
|
171
|
+
else
|
|
172
|
+
rows.push(row);
|
|
173
|
+
}
|
|
174
|
+
return grouped;
|
|
146
175
|
}
|
|
147
176
|
export function projectBlocked(board, scope, relations) {
|
|
148
177
|
return projectRows(board, relations, scope, "active").flatMap((row) => {
|