@astrosheep/keiyaku 4.1.0 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
- package/build/src/akuma/akuma-errors.d.ts +6 -0
- package/build/src/akuma/akuma-errors.js +9 -0
- package/build/src/akuma/akuma-handle.d.ts +39 -0
- package/build/src/akuma/akuma-handle.js +263 -0
- package/build/src/akuma/akuma-observe.d.ts +19 -0
- package/build/src/akuma/akuma-observe.js +74 -0
- package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
- package/build/src/akuma/akuma-product-symbols.js +1 -0
- package/build/src/akuma/akuma-product.d.ts +18 -0
- package/build/src/akuma/akuma-product.js +154 -0
- package/build/src/akuma/akuma.d.ts +37 -81
- package/build/src/akuma/akuma.js +39 -447
- package/build/src/akuma/allowed.d.ts +1 -0
- package/build/src/akuma/allowed.js +6 -0
- package/build/src/akuma/archetype.js +8 -5
- package/build/src/akuma/body-supervisor.d.ts +26 -0
- package/build/src/akuma/body-supervisor.js +89 -0
- package/build/src/akuma/body.d.ts +45 -4
- package/build/src/akuma/body.js +145 -35
- package/build/src/akuma/coordinate.js +17 -7
- package/build/src/akuma/heart/facts.js +1 -1
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/index.js +2 -4
- package/build/src/akuma/heart/request-authority.js +4 -4
- package/build/src/akuma/heart/request-rows.js +27 -16
- package/build/src/akuma/heart/rows.js +79 -41
- package/build/src/akuma/heart/soul.js +1 -1
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +76 -11
- package/build/src/akuma/heart/tells.js +35 -18
- package/build/src/akuma/heart/timeline.js +19 -11
- package/build/src/akuma/identity.d.ts +1 -0
- package/build/src/akuma/identity.js +1 -0
- package/build/src/akuma/index.d.ts +3 -3
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/nuke.js +106 -14
- package/build/src/akuma/projection-read.d.ts +17 -0
- package/build/src/akuma/projection-read.js +135 -0
- package/build/src/akuma/projection.d.ts +1 -16
- package/build/src/akuma/projection.js +77 -154
- package/build/src/akuma/provider-recipe.js +11 -5
- package/build/src/akuma/provider.js +105 -62
- package/build/src/akuma/providers/acp/config.js +5 -6
- package/build/src/akuma/providers/acp/core.js +17 -10
- package/build/src/akuma/providers/acp/events.js +38 -29
- package/build/src/akuma/providers/acp/index.js +13 -9
- package/build/src/akuma/providers/claude/events.js +8 -12
- package/build/src/akuma/providers/claude/index.d.ts +1 -0
- package/build/src/akuma/providers/claude/index.js +55 -26
- package/build/src/akuma/providers/claude/input.js +6 -2
- package/build/src/akuma/providers/codex-app-server/events.js +61 -36
- package/build/src/akuma/providers/codex-app-server/index.js +25 -13
- package/build/src/akuma/providers/grok-build/index.js +22 -25
- package/build/src/akuma/providers/index.js +2 -18
- package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
- package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
- package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
- package/build/src/akuma/providers/pi/events.js +26 -19
- package/build/src/akuma/providers/pi/index.js +58 -40
- package/build/src/akuma/publication.js +9 -9
- package/build/src/akuma/request-execution.d.ts +6 -0
- package/build/src/akuma/request-execution.js +86 -0
- package/build/src/akuma/request-serve.d.ts +12 -1
- package/build/src/akuma/request-serve.js +19 -122
- package/build/src/akuma/request-wire.d.ts +2 -2
- package/build/src/akuma/request-wire.js +75 -102
- package/build/src/akuma/requests.js +2 -2
- package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
- package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
- package/build/src/akuma-body.js +6 -5
- package/build/src/body/amend.d.ts +4 -1
- package/build/src/body/amend.js +14 -6
- package/build/src/body/decode.js +2 -4
- package/build/src/body/envelope.js +2 -4
- package/build/src/body/region.d.ts +1 -2
- package/build/src/body/region.js +2 -70
- package/build/src/body/render.js +17 -12
- package/build/src/body/shape.js +1 -7
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +8 -1
- package/build/src/cli/commands/akuma-invoke.js +18 -6
- package/build/src/cli/commands/akuma.d.ts +0 -6
- package/build/src/cli/commands/akuma.js +11 -24
- package/build/src/cli/commands/amend.d.ts +2 -2
- package/build/src/cli/commands/amend.js +2 -4
- package/build/src/cli/commands/bind.d.ts +4 -4
- package/build/src/cli/commands/bind.js +16 -6
- package/build/src/cli/commands/contract-invoke.d.ts +25 -0
- package/build/src/cli/commands/contract-invoke.js +193 -0
- package/build/src/cli/commands/contract.d.ts +109 -10
- package/build/src/cli/commands/contract.js +339 -16
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +23 -15
- package/build/src/cli/commands/task-invoke.js +187 -67
- package/build/src/cli/commands/task-query.js +48 -24
- package/build/src/cli/commands/task.js +150 -38
- package/build/src/cli/coordinates.js +2 -4
- package/build/src/cli/invoke.js +92 -208
- package/build/src/cli/main.js +4 -2
- package/build/src/cli/parse.d.ts +3 -90
- package/build/src/cli/parse.js +27 -233
- package/build/src/cli/render/akuma-activity.d.ts +38 -0
- package/build/src/cli/render/akuma-activity.js +362 -0
- package/build/src/cli/render/akuma-tool-command.js +6 -7
- package/build/src/cli/render/akuma-tool.js +10 -8
- package/build/src/cli/render/akuma.d.ts +1 -1
- package/build/src/cli/render/akuma.js +61 -353
- package/build/src/cli/render/audit.js +5 -15
- package/build/src/cli/render/board.d.ts +1 -0
- package/build/src/cli/render/board.js +17 -0
- package/build/src/cli/render/catalog.js +81 -8
- package/build/src/cli/render/contract-history.d.ts +2 -0
- package/build/src/cli/render/contract-history.js +83 -0
- package/build/src/cli/render/contract-observation.d.ts +10 -0
- package/build/src/cli/render/contract-observation.js +58 -0
- package/build/src/cli/render/contract.d.ts +1 -2
- package/build/src/cli/render/contract.js +41 -142
- package/build/src/cli/render/kanshi.js +239 -215
- package/build/src/cli/render/receipt.js +2 -9
- package/build/src/cli/render/refusal.js +10 -15
- package/build/src/cli/render/region.js +22 -6
- package/build/src/cli/render/settings.js +4 -4
- package/build/src/cli/render/task.js +34 -14
- package/build/src/cli/render/terminal.js +16 -5
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.d.ts +6 -1
- package/build/src/cli/runtime.js +84 -63
- package/build/src/cli/selectors.js +2 -4
- package/build/src/cli/usage.js +6 -5
- package/build/src/contract-worktree.d.ts +1 -23
- package/build/src/contract-worktree.js +79 -155
- package/build/src/coordination/durable-file.js +7 -3
- package/build/src/coordination/sqlite-transaction-lock.js +29 -12
- package/build/src/core/facts/codec.js +7 -3
- package/build/src/core/facts/types.d.ts +1 -1
- package/build/src/core/subject.js +16 -9
- package/build/src/core/verbs/abandon.d.ts +1 -1
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +7 -7
- package/build/src/core/verbs/attestation.js +4 -1
- package/build/src/core/verbs/bind.d.ts +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +10 -8
- package/build/src/dispatch/index.js +8 -6
- package/build/src/duration.js +5 -1
- package/build/src/git/admission.js +5 -3
- package/build/src/git/hooks.d.ts +8 -0
- package/build/src/git/hooks.js +63 -14
- package/build/src/git/identity.js +1 -4
- package/build/src/git/integration.d.ts +2 -3
- package/build/src/git/integration.js +32 -39
- package/build/src/git/nuke.d.ts +1 -1
- package/build/src/git/nuke.js +110 -57
- package/build/src/git/observe.d.ts +13 -1
- package/build/src/git/observe.js +51 -44
- package/build/src/git/process.js +4 -2
- package/build/src/git/read-observation.js +10 -8
- package/build/src/git/reconcile.d.ts +22 -2
- package/build/src/git/reconcile.js +38 -274
- package/build/src/git/repository.d.ts +2 -0
- package/build/src/git/repository.js +13 -22
- package/build/src/git/scratch.d.ts +8 -5
- package/build/src/git/scratch.js +29 -2
- package/build/src/git/target-placement.d.ts +9 -10
- package/build/src/git/target-placement.js +59 -62
- package/build/src/git/tender.js +13 -46
- package/build/src/git/terminal-reconcile.d.ts +21 -0
- package/build/src/git/terminal-reconcile.js +278 -0
- package/build/src/git/terminal-seal.js +15 -12
- package/build/src/git/tree.js +5 -2
- package/build/src/git/workspace.d.ts +24 -2
- package/build/src/git/workspace.js +120 -16
- package/build/src/identity/coordinates.js +3 -1
- package/build/src/identity/selector.js +6 -3
- package/build/src/kanshi/fleet.d.ts +6 -0
- package/build/src/kanshi/fleet.js +27 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +60 -48
- package/build/src/kanshi/report.d.ts +11 -23
- package/build/src/kanshi/select.js +25 -24
- package/build/src/library/address.d.ts +2 -1
- package/build/src/library/address.js +7 -8
- package/build/src/library/akuma-creation.js +20 -12
- package/build/src/library/audit.d.ts +0 -1
- package/build/src/library/audit.js +1 -2
- package/build/src/library/bind.d.ts +53 -5
- package/build/src/library/bind.js +98 -22
- package/build/src/library/catalog.d.ts +1 -0
- package/build/src/library/catalog.js +6 -3
- package/build/src/library/configuration.js +3 -1
- package/build/src/library/continuation.d.ts +15 -4
- package/build/src/library/continuation.js +24 -16
- package/build/src/library/contract-bind.d.ts +26 -0
- package/build/src/library/contract-bind.js +106 -0
- package/build/src/library/contract-operations.d.ts +77 -0
- package/build/src/library/contract-operations.js +130 -0
- package/build/src/library/contract-types.d.ts +95 -0
- package/build/src/library/contract-types.js +1 -0
- package/build/src/library/contract.d.ts +19 -154
- package/build/src/library/contract.js +46 -261
- package/build/src/library/fleet.d.ts +1 -1
- package/build/src/library/fleet.js +19 -11
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +14 -0
- package/build/src/library/keiyaku.d.ts +8 -7
- package/build/src/library/keiyaku.js +3 -3
- package/build/src/library/nuke.js +14 -5
- package/build/src/library/reconcile.d.ts +9 -4
- package/build/src/library/reconcile.js +30 -24
- package/build/src/library/refusal.d.ts +13 -5
- package/build/src/library/refusal.js +7 -0
- package/build/src/library/region.d.ts +8 -7
- package/build/src/library/region.js +31 -11
- package/build/src/library/repo.js +2 -2
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/parse.js +11 -7
- package/build/src/markdown/query.js +4 -2
- package/build/src/protocol/amend.js +3 -1
- package/build/src/protocol/attempt.d.ts +7 -3
- package/build/src/protocol/attempt.js +9 -5
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +4 -14
- package/build/src/protocol/bind.d.ts +19 -6
- package/build/src/protocol/bind.js +28 -13
- package/build/src/protocol/completion.d.ts +0 -1
- package/build/src/protocol/completion.js +1 -3
- package/build/src/protocol/deliver.d.ts +1 -3
- package/build/src/protocol/deliver.js +15 -39
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +9 -7
- package/build/src/protocol/operations.d.ts +3 -7
- package/build/src/protocol/operations.js +5 -3
- package/build/src/protocol/placement.d.ts +0 -1
- package/build/src/protocol/placement.js +6 -6
- package/build/src/protocol/read/observation.d.ts +11 -0
- package/build/src/protocol/read/observation.js +37 -0
- package/build/src/protocol/read/status.d.ts +23 -12
- package/build/src/protocol/read/status.js +90 -72
- package/build/src/protocol/reconcile.d.ts +1 -0
- package/build/src/protocol/reconcile.js +2 -3
- package/build/src/protocol/reintegrate.js +1 -1
- package/build/src/protocol/review.d.ts +0 -1
- package/build/src/protocol/review.js +15 -22
- package/build/src/protocol/run.d.ts +1 -0
- package/build/src/protocol/run.js +4 -5
- package/build/src/runtime/proc/launch.d.ts +33 -0
- package/build/src/runtime/proc/launch.js +98 -0
- package/build/src/runtime/proc/line-rpc.js +9 -3
- package/build/src/runtime/proc/run.d.ts +12 -6
- package/build/src/runtime/proc/run.js +78 -21
- package/build/src/runtime/proc/stdio.js +7 -10
- package/build/src/settings.js +6 -2
- package/build/src/settlement/holder.js +13 -10
- package/build/src/settlement/settle.js +39 -6
- package/build/src/task/board.js +12 -6
- package/build/src/task/compose.js +85 -22
- package/build/src/task/context.js +21 -8
- package/build/src/task/document.js +46 -10
- package/build/src/task/identity.js +5 -2
- package/build/src/task/index.d.ts +0 -1
- package/build/src/task/index.js +119 -34
- package/build/src/task/input.js +29 -7
- package/build/src/task/mutation.js +61 -19
- package/build/src/task/operations.d.ts +6 -1
- package/build/src/task/operations.js +83 -29
- package/build/src/task/query.js +55 -26
- package/build/src/task/store.d.ts +3 -1
- package/build/src/task/store.js +81 -17
- package/build/src/verification/execution.js +14 -11
- package/build/src/workspace-place.js +19 -7
- package/build/src/world.js +16 -6
- package/package.json +8 -3
|
@@ -3,7 +3,7 @@ import { reconcileAllOperation, reconcileOperation, worldContractStates, } from
|
|
|
3
3
|
import { reconcileObservationFailure } from "../git/reconcile.js";
|
|
4
4
|
import { stateOperation } from "../protocol/operations.js";
|
|
5
5
|
import { settle, settleAll } from "../settlement/settle.js";
|
|
6
|
-
import { projectContractWorktree
|
|
6
|
+
import { projectContractWorktree } from "../contract-worktree.js";
|
|
7
7
|
import { appointManagedWorktrees, placeRegisterPath, releaseManagedWorktrees, } from "../workspace-place.js";
|
|
8
8
|
function registerLag(scope, error) {
|
|
9
9
|
return {
|
|
@@ -13,9 +13,6 @@ function registerLag(scope, error) {
|
|
|
13
13
|
diagnostic: error instanceof Error ? error.message : String(error),
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
function hereConflict(diagnostic) {
|
|
17
|
-
throw new AuthorityCorruptionError(diagnostic);
|
|
18
|
-
}
|
|
19
16
|
function emptySettlement() {
|
|
20
17
|
return { actions: [], lags: [] };
|
|
21
18
|
}
|
|
@@ -26,18 +23,13 @@ function isManagedTerminal(state) {
|
|
|
26
23
|
return state !== null && isManagedWorktree(state) && state.terminal !== null;
|
|
27
24
|
}
|
|
28
25
|
function appointableManagedContracts(states) {
|
|
29
|
-
return states
|
|
30
|
-
.filter((state) => isManagedWorktree(state) && state.terminal === null)
|
|
31
|
-
.map((state) => state.id);
|
|
26
|
+
return states.filter((state) => isManagedWorktree(state) && state.terminal === null).map((state) => state.id);
|
|
32
27
|
}
|
|
33
28
|
async function appointPlaces(scope, states) {
|
|
34
29
|
return await appointManagedWorktrees(scope, appointableManagedContracts(states));
|
|
35
30
|
}
|
|
36
31
|
function releaseEligible(state, cleanup, appointed) {
|
|
37
|
-
return cleanup !== undefined
|
|
38
|
-
&& cleanup.lag.length === 0
|
|
39
|
-
&& isManagedTerminal(state)
|
|
40
|
-
&& appointed;
|
|
32
|
+
return cleanup !== undefined && cleanup.lag.length === 0 && isManagedTerminal(state) && appointed;
|
|
41
33
|
}
|
|
42
34
|
async function releaseAppointments(scope, contracts) {
|
|
43
35
|
try {
|
|
@@ -94,35 +86,50 @@ export async function completeReconcile(input) {
|
|
|
94
86
|
retainTerminalWorktree: true,
|
|
95
87
|
...appointed,
|
|
96
88
|
});
|
|
97
|
-
const projection = await projectContractWorktree(input.scope, retained.state, appointment.register
|
|
89
|
+
const projection = await projectContractWorktree(input.scope, retained.state, appointment.register);
|
|
98
90
|
const settlement = await settle({
|
|
99
91
|
repository: input.scope,
|
|
100
92
|
channel: input.channel,
|
|
101
93
|
state: retained.state,
|
|
102
94
|
effects: retained.report.effects,
|
|
103
95
|
});
|
|
104
|
-
const cleanup = isManagedTerminal(retained.state)
|
|
105
|
-
? await reconcileOperation({ ...input, ...appointed })
|
|
106
|
-
: null;
|
|
96
|
+
const cleanup = isManagedTerminal(retained.state) ? await reconcileOperation({ ...input, ...appointed }) : null;
|
|
107
97
|
const release = releaseEligible(retained.state, cleanup?.report, appointment.place !== undefined)
|
|
108
98
|
? await releaseAppointments(input.scope, [input.contractId])
|
|
109
99
|
: undefined;
|
|
110
100
|
return {
|
|
111
101
|
effects: [...retained.report.effects, ...projection.effects, ...(cleanup?.report.effects ?? [])],
|
|
112
|
-
lag: [
|
|
102
|
+
lag: [
|
|
103
|
+
...retained.report.lag,
|
|
104
|
+
...projection.lag,
|
|
105
|
+
...(cleanup?.report.lag ?? []),
|
|
106
|
+
...(release === undefined ? [] : [release]),
|
|
107
|
+
],
|
|
113
108
|
settlement,
|
|
114
109
|
};
|
|
115
110
|
}
|
|
116
111
|
function attachReleaseLag(contracts, released, lag) {
|
|
117
112
|
const affected = new Set(released);
|
|
118
113
|
return {
|
|
114
|
+
kind: "completed",
|
|
119
115
|
contracts: contracts.map((contract) => affected.has(contract.contractId)
|
|
120
116
|
? { ...contract, report: { ...contract.report, lag: [...contract.report.lag, lag] } }
|
|
121
117
|
: contract),
|
|
122
118
|
};
|
|
123
119
|
}
|
|
120
|
+
function worldObservationDiagnostic(error) {
|
|
121
|
+
return (error instanceof Error ? error.message : String(error)).trim();
|
|
122
|
+
}
|
|
124
123
|
export async function completeRepoReconcile(input) {
|
|
125
|
-
|
|
124
|
+
let states;
|
|
125
|
+
try {
|
|
126
|
+
states = await worldContractStates(input);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error instanceof AuthorityCorruptionError || error instanceof TypeError)
|
|
130
|
+
throw error;
|
|
131
|
+
return { kind: "world-observation-failed", diagnostic: worldObservationDiagnostic(error) };
|
|
132
|
+
}
|
|
126
133
|
let appointed;
|
|
127
134
|
try {
|
|
128
135
|
appointed = await appointPlaces(input.scope, states);
|
|
@@ -140,11 +147,12 @@ export async function completeRepoReconcile(input) {
|
|
|
140
147
|
: await completeReconcile({ ...input, contractId: state.id }),
|
|
141
148
|
});
|
|
142
149
|
}
|
|
143
|
-
return { contracts };
|
|
150
|
+
return { kind: "completed", contracts };
|
|
144
151
|
}
|
|
145
152
|
const places = new Map(appointed.appointments.map((appointment) => [appointment.contract, appointment.place]));
|
|
146
153
|
const retained = await reconcileAllOperation({
|
|
147
154
|
...input,
|
|
155
|
+
states,
|
|
148
156
|
retainTerminalWorktree: true,
|
|
149
157
|
places,
|
|
150
158
|
});
|
|
@@ -157,11 +165,9 @@ export async function completeRepoReconcile(input) {
|
|
|
157
165
|
})),
|
|
158
166
|
});
|
|
159
167
|
const cleanup = retained.contracts.some((contract) => isManagedTerminal(contract.state))
|
|
160
|
-
? await reconcileAllOperation({ ...input, places })
|
|
168
|
+
? await reconcileAllOperation({ ...input, states, places })
|
|
161
169
|
: null;
|
|
162
|
-
const later = cleanup === null
|
|
163
|
-
? null
|
|
164
|
-
: new Map(cleanup.contracts.map((contract) => [contract.contractId, contract.report]));
|
|
170
|
+
const later = cleanup === null ? null : new Map(cleanup.contracts.map((contract) => [contract.contractId, contract.report]));
|
|
165
171
|
const released = [];
|
|
166
172
|
const contracts = [];
|
|
167
173
|
for (const [index, contract] of retained.contracts.entries()) {
|
|
@@ -169,7 +175,7 @@ export async function completeRepoReconcile(input) {
|
|
|
169
175
|
if (releaseEligible(contract.state, report, places.has(contract.contractId))) {
|
|
170
176
|
released.push(contract.contractId);
|
|
171
177
|
}
|
|
172
|
-
const projection = await projectContractWorktree(input.scope, contract.state, appointed
|
|
178
|
+
const projection = await projectContractWorktree(input.scope, contract.state, appointed);
|
|
173
179
|
contracts.push({
|
|
174
180
|
contractId: contract.contractId,
|
|
175
181
|
report: {
|
|
@@ -180,5 +186,5 @@ export async function completeRepoReconcile(input) {
|
|
|
180
186
|
});
|
|
181
187
|
}
|
|
182
188
|
const lag = await releaseAppointments(input.scope, released);
|
|
183
|
-
return lag === undefined ? { contracts } : attachReleaseLag(contracts, released, lag);
|
|
189
|
+
return lag === undefined ? { kind: "completed", contracts } : attachReleaseLag(contracts, released, lag);
|
|
184
190
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { ContractId } from "../core/facts/types.js";
|
|
2
2
|
import type { IntentOutcome, IntentRefusal, IntentRetry } from "../protocol/operations.js";
|
|
3
3
|
import type { AcceptedIntent } from "./mutation.js";
|
|
4
|
-
export type
|
|
5
|
-
kind: "
|
|
6
|
-
|
|
7
|
-
contract?: ContractId;
|
|
4
|
+
export type ForkSourceRefusal = Readonly<{
|
|
5
|
+
kind: "fork-source-missing" | "fork-source-unavailable" | "fork-source-invalid" | "fork-source-moved";
|
|
6
|
+
contractId: ContractId;
|
|
8
7
|
}>;
|
|
9
8
|
export type NukeConfirmationRefusal = Readonly<{
|
|
10
9
|
kind: "nuke-confirmation-mismatch";
|
|
@@ -15,7 +14,7 @@ export type NukeConfirmationRequiredRefusal = Readonly<{
|
|
|
15
14
|
kind: "nuke-confirmation-required";
|
|
16
15
|
world: string;
|
|
17
16
|
}>;
|
|
18
|
-
export type KeiyakuRefusal = IntentRefusal |
|
|
17
|
+
export type KeiyakuRefusal = IntentRefusal | ForkSourceRefusal | NukeConfirmationRefusal | NukeConfirmationRequiredRefusal;
|
|
19
18
|
export type KeiyakuRetryReason = IntentRetry;
|
|
20
19
|
export declare class KeiyakuRefused extends Error {
|
|
21
20
|
readonly refusal: KeiyakuRefusal;
|
|
@@ -28,3 +27,12 @@ export declare class KeiyakuRetry extends Error {
|
|
|
28
27
|
get code(): KeiyakuRetryReason["kind"];
|
|
29
28
|
}
|
|
30
29
|
export declare function requireAccepted<Value, Refusal extends KeiyakuRefusal>(result: IntentOutcome<Value, Refusal>): AcceptedIntent<Value>;
|
|
30
|
+
export declare function forwardedMutationFailure(error: unknown): Readonly<{
|
|
31
|
+
result: Readonly<{
|
|
32
|
+
kind: "refused";
|
|
33
|
+
refusal: KeiyakuRefusal;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "retry";
|
|
36
|
+
reason: KeiyakuRetryReason;
|
|
37
|
+
}>;
|
|
38
|
+
}>;
|
|
@@ -27,3 +27,10 @@ export function requireAccepted(result) {
|
|
|
27
27
|
throw new KeiyakuRetry(result.reason);
|
|
28
28
|
return result;
|
|
29
29
|
}
|
|
30
|
+
export function forwardedMutationFailure(error) {
|
|
31
|
+
if (error instanceof KeiyakuRefused)
|
|
32
|
+
return { result: { kind: "refused", refusal: error.refusal } };
|
|
33
|
+
if (error instanceof KeiyakuRetry)
|
|
34
|
+
return { result: { kind: "retry", reason: error.reason } };
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ContractId } from "../core/facts/types.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type GitDecodeChannel } from "../git/read-observation.js";
|
|
3
3
|
import { type RepositoryScope } from "../protocol/operations.js";
|
|
4
4
|
import type { ContractDocumentProjection } from "../protocol/read/documents.js";
|
|
5
5
|
export type RegionOverlap = Readonly<{
|
|
@@ -16,15 +16,16 @@ export type RegionObservation = Readonly<{
|
|
|
16
16
|
overlapFailure: string;
|
|
17
17
|
overlaps?: never;
|
|
18
18
|
}>;
|
|
19
|
+
export type AmendRegionObservation = RegionObservation | Readonly<{
|
|
20
|
+
overlaps?: never;
|
|
21
|
+
overlapFailure?: never;
|
|
22
|
+
}>;
|
|
19
23
|
export type RegionDeclarationRead = Readonly<{
|
|
20
24
|
contract: ContractId;
|
|
21
25
|
patterns: readonly string[];
|
|
22
26
|
}>;
|
|
23
27
|
export declare function readRegionDeclarations(documents: readonly ContractDocumentProjection[]): readonly RegionDeclarationRead[];
|
|
24
|
-
export declare function
|
|
25
|
-
|
|
26
|
-
right: string;
|
|
27
|
-
}>[];
|
|
28
|
-
export declare function regionPathMatches(patterns: readonly string[], path: string): readonly string[];
|
|
29
|
-
export declare function validateRegionPath(path: unknown): asserts path is string;
|
|
28
|
+
export declare function regionOverlaps(mine: readonly string[], declarations: readonly RegionDeclarationRead[]): readonly RegionOverlap[];
|
|
29
|
+
export declare function validateRegionPatterns(patterns: unknown): readonly [string, ...string[]];
|
|
30
30
|
export declare function observeRegion(scope: RepositoryScope, channel: GitDecodeChannel, self: ContractId, mine: readonly string[]): Promise<RegionObservation>;
|
|
31
|
+
export declare function observeChangedRegion(scope: RepositoryScope, self: ContractId, changed: ReadonlySet<string> | undefined, mine: readonly string[]): Promise<AmendRegionObservation>;
|
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
import { decodeContractDocument } from "../body/decode.js";
|
|
2
|
-
import {
|
|
2
|
+
import { assertRegionPattern, regionsOverlap } from "../body/region.js";
|
|
3
|
+
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
3
4
|
import { documentsOperationAt } from "../protocol/operations.js";
|
|
4
5
|
export function readRegionDeclarations(documents) {
|
|
5
|
-
return documents.map((document) => ({
|
|
6
|
+
return documents.map((document) => ({
|
|
7
|
+
contract: document.contract,
|
|
8
|
+
patterns: decodeContractDocument(document.documentBytes).region,
|
|
9
|
+
}));
|
|
6
10
|
}
|
|
7
|
-
export function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export function regionOverlaps(mine, declarations) {
|
|
12
|
+
const overlaps = [];
|
|
13
|
+
for (const declaration of declarations) {
|
|
14
|
+
const pairs = regionsOverlap(mine, declaration.patterns);
|
|
15
|
+
if (pairs.length === 0)
|
|
16
|
+
continue;
|
|
17
|
+
overlaps.push({
|
|
18
|
+
contract: declaration.contract,
|
|
19
|
+
patterns: pairs.map(([minePattern, theirsPattern]) => ({ mine: minePattern, theirs: theirsPattern })),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return overlaps;
|
|
12
23
|
}
|
|
13
|
-
export function
|
|
14
|
-
if (
|
|
15
|
-
throw new Error("Region
|
|
16
|
-
|
|
24
|
+
export function validateRegionPatterns(patterns) {
|
|
25
|
+
if (!Array.isArray(patterns) || patterns.length === 0)
|
|
26
|
+
throw new Error("Region query requires one or more path patterns");
|
|
27
|
+
return patterns.map((pattern) => {
|
|
28
|
+
if (typeof pattern !== "string")
|
|
29
|
+
throw new Error("Region path patterns must be strings");
|
|
30
|
+
return assertRegionPattern(pattern);
|
|
31
|
+
});
|
|
17
32
|
}
|
|
18
33
|
function diagnostic(error) {
|
|
19
34
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -42,3 +57,8 @@ export async function observeRegion(scope, channel, self, mine) {
|
|
|
42
57
|
return { overlapFailure: diagnostic(error) };
|
|
43
58
|
}
|
|
44
59
|
}
|
|
60
|
+
export async function observeChangedRegion(scope, self, changed, mine) {
|
|
61
|
+
if (!changed?.has("region"))
|
|
62
|
+
return {};
|
|
63
|
+
return await withGitDecodeChannel(scope, async (channel) => await observeRegion(scope, channel, self, mine));
|
|
64
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { currentBranchOperation, scopeOperation
|
|
1
|
+
import { currentBranchOperation, scopeOperation } from "../protocol/operations.js";
|
|
2
2
|
import { NoGitWorldError } from "../git/repository.js";
|
|
3
3
|
import { optionalNonblank, requireInput } from "./input.js";
|
|
4
4
|
import { worktreeHooksOption } from "./configuration.js";
|
|
5
5
|
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
6
|
-
import { completeRepoReconcile
|
|
6
|
+
import { completeRepoReconcile } from "./reconcile.js";
|
|
7
7
|
export { NoGitWorldError };
|
|
8
8
|
const REPO_SCOPES = new WeakMap();
|
|
9
9
|
async function resolvePinnedScope(path, gitPath) {
|
|
@@ -52,7 +52,11 @@ function header(line) {
|
|
|
52
52
|
level += 1;
|
|
53
53
|
if (level === 0 || (line[level] !== " " && line[level] !== "\t"))
|
|
54
54
|
return null;
|
|
55
|
-
const text = line
|
|
55
|
+
const text = line
|
|
56
|
+
.slice(level)
|
|
57
|
+
.trim()
|
|
58
|
+
.replace(/[ \t]+#+[ \t]*$/, "")
|
|
59
|
+
.trimEnd();
|
|
56
60
|
return text.length === 0 ? null : { level, text };
|
|
57
61
|
}
|
|
58
62
|
function listMarker(line) {
|
|
@@ -149,7 +153,10 @@ function frontmatter(lines) {
|
|
|
149
153
|
closing += 1;
|
|
150
154
|
if (closing >= lines.length)
|
|
151
155
|
return null;
|
|
152
|
-
const yaml = lines
|
|
156
|
+
const yaml = lines
|
|
157
|
+
.slice(1, closing)
|
|
158
|
+
.map((line) => line.text)
|
|
159
|
+
.join("\n");
|
|
153
160
|
const entries = parseFrontmatter(yaml);
|
|
154
161
|
const selected = lines.slice(0, closing + 1);
|
|
155
162
|
return {
|
|
@@ -149,12 +149,14 @@ class Parser {
|
|
|
149
149
|
}
|
|
150
150
|
parseListItem(marker, indent) {
|
|
151
151
|
const bodyOffset = marker.bodyStart - marker.span.start;
|
|
152
|
-
const itemTokens = [
|
|
152
|
+
const itemTokens = [
|
|
153
|
+
{
|
|
153
154
|
type: "text",
|
|
154
155
|
raw: marker.raw.slice(bodyOffset),
|
|
155
156
|
span: { start: marker.bodyStart, end: marker.span.end },
|
|
156
157
|
leadingSpaces: 0,
|
|
157
|
-
}
|
|
158
|
+
},
|
|
159
|
+
];
|
|
158
160
|
let end = marker.span.end;
|
|
159
161
|
while (!this.done()) {
|
|
160
162
|
const token = this.peek();
|
|
@@ -173,15 +175,18 @@ class Parser {
|
|
|
173
175
|
end = token.span.end;
|
|
174
176
|
}
|
|
175
177
|
const childSpan = { start: itemTokens[0].span.start, end: itemTokens.at(-1).span.end };
|
|
176
|
-
const children = new Parser(itemTokens, { mode: "item" })
|
|
177
|
-
.parseDocument("", childSpan, 0).children;
|
|
178
|
+
const children = new Parser(itemTokens, { mode: "item" }).parseDocument("", childSpan, 0).children;
|
|
178
179
|
return { type: "list_item", span: { start: marker.span.start, end }, marker: marker.marker, indent, children };
|
|
179
180
|
}
|
|
180
181
|
parseText(stop) {
|
|
181
182
|
const tokens = [];
|
|
182
183
|
while (!this.done() && !stop()) {
|
|
183
184
|
const token = this.peek();
|
|
184
|
-
if (token === undefined ||
|
|
185
|
+
if (token === undefined ||
|
|
186
|
+
token.type === "fence" ||
|
|
187
|
+
token.type === "header" ||
|
|
188
|
+
token.type === "blockquote" ||
|
|
189
|
+
token.type === "frontmatter")
|
|
185
190
|
break;
|
|
186
191
|
if (token.type === "list_marker" && (this.options.mode === "item" || token.indent <= 3))
|
|
187
192
|
break;
|
|
@@ -216,6 +221,5 @@ class Parser {
|
|
|
216
221
|
}
|
|
217
222
|
export function parseToAST(source) {
|
|
218
223
|
const bomLength = source.startsWith("\uFEFF") ? 1 : 0;
|
|
219
|
-
return new Parser(lexMarkdown(source), { mode: "document" })
|
|
220
|
-
.parseDocument(source, { start: 0, end: source.length }, bomLength);
|
|
224
|
+
return new Parser(lexMarkdown(source), { mode: "document" }).parseDocument(source, { start: 0, end: source.length }, bomLength);
|
|
221
225
|
}
|
|
@@ -42,8 +42,10 @@ export function sectionContent(document, section) {
|
|
|
42
42
|
}
|
|
43
43
|
export function indexedHeadings(index, query) {
|
|
44
44
|
const candidates = query.title === undefined
|
|
45
|
-
? query.level === undefined
|
|
46
|
-
|
|
45
|
+
? query.level === undefined
|
|
46
|
+
? []
|
|
47
|
+
: (index.byLevel.get(query.level) ?? [])
|
|
48
|
+
: (index.byTitle.get(normalizeTitle(query.title)) ?? []);
|
|
47
49
|
return query.level === undefined ? candidates : candidates.filter((node) => node.level === query.level);
|
|
48
50
|
}
|
|
49
51
|
export function directChildren(node, type) {
|
|
@@ -35,7 +35,9 @@ export async function amendOperation(input) {
|
|
|
35
35
|
? undefined
|
|
36
36
|
: { source, ...input.deriveAmendment(source) };
|
|
37
37
|
if (amendment !== undefined) {
|
|
38
|
-
observation = await extendPrerequisiteClosureAt(input.channel, observation, [
|
|
38
|
+
observation = await extendPrerequisiteClosureAt(input.channel, observation, [
|
|
39
|
+
...new Set([...(state?.terms.after ?? []), ...amendment.terms.after]),
|
|
40
|
+
]);
|
|
39
41
|
}
|
|
40
42
|
const preparation = amendment === undefined
|
|
41
43
|
? undefined
|
|
@@ -31,11 +31,14 @@ export type AcceptedAdmission = Readonly<{
|
|
|
31
31
|
export type AttemptTerminal = Readonly<{
|
|
32
32
|
kind: "collision";
|
|
33
33
|
}> | PublicationFailed;
|
|
34
|
-
export type DecidedOfferResult = AcceptedAdmission | AttemptTerminal | Readonly<{
|
|
34
|
+
export type DecidedOfferResult<Refusal = never> = AcceptedAdmission | AttemptTerminal | Readonly<{
|
|
35
35
|
kind: "redecide";
|
|
36
|
+
}> | Readonly<{
|
|
37
|
+
kind: "refused";
|
|
38
|
+
refusal: Refusal;
|
|
36
39
|
}>;
|
|
37
40
|
/** Admit one decided offer without making another legal decision. */
|
|
38
|
-
export declare function admitDecidedOffer(input: Readonly<{
|
|
41
|
+
export declare function admitDecidedOffer<Refusal = never>(input: Readonly<{
|
|
39
42
|
channel: GitDecodeChannel;
|
|
40
43
|
repository: GitRepository;
|
|
41
44
|
decisionObservation: GitDecisionObservation;
|
|
@@ -43,7 +46,8 @@ export declare function admitDecidedOffer(input: Readonly<{
|
|
|
43
46
|
offer: Offer;
|
|
44
47
|
primaryContract: ContractId;
|
|
45
48
|
assertions?: readonly GitRefAssertion[];
|
|
46
|
-
|
|
49
|
+
validateAdmission?: (observation: GitDecisionObservation) => Refusal | undefined | Promise<Refusal | undefined>;
|
|
50
|
+
}>): Promise<DecidedOfferResult<Refusal>>;
|
|
47
51
|
/** Classify an unknown atomic-publication outcome using only a captured Git observation. */
|
|
48
52
|
export declare function classifyUnknownAttempt(observation: Readonly<{
|
|
49
53
|
contracts: GitDecisionObservation["journals"];
|
|
@@ -78,13 +78,12 @@ function recoveredAcceptance(observation, offer, primaryContract) {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
async function publicationPremiseMoved(repository, observation, offer, assertions) {
|
|
81
|
-
if (await readRef(repository, GIT_REF) !== observation.admission.snapshot.commit)
|
|
81
|
+
if ((await readRef(repository, GIT_REF)) !== observation.admission.snapshot.commit)
|
|
82
82
|
return true;
|
|
83
83
|
for (const assertion of assertions)
|
|
84
|
-
if (await readRef(repository, assertion.ref) !== assertion.oid)
|
|
84
|
+
if ((await readRef(repository, assertion.ref)) !== assertion.oid)
|
|
85
85
|
return true;
|
|
86
|
-
return offer.target !== undefined
|
|
87
|
-
&& await readRef(repository, offer.target.target) !== offer.target.expectedOid;
|
|
86
|
+
return offer.target !== undefined && (await readRef(repository, offer.target.target)) !== offer.target.expectedOid;
|
|
88
87
|
}
|
|
89
88
|
/** Admit one decided offer without making another legal decision. */
|
|
90
89
|
export async function admitDecidedOffer(input) {
|
|
@@ -92,6 +91,11 @@ export async function admitDecidedOffer(input) {
|
|
|
92
91
|
const assertions = input.assertions ?? [];
|
|
93
92
|
validateOffer(offer, attempt);
|
|
94
93
|
const primary = primaryAppend(offer, primaryContract);
|
|
94
|
+
if (input.validateAdmission !== undefined) {
|
|
95
|
+
const refusal = await input.validateAdmission(decisionObservation);
|
|
96
|
+
if (refusal !== undefined)
|
|
97
|
+
return { kind: "refused", refusal };
|
|
98
|
+
}
|
|
95
99
|
const admission = await admit(repository, offer, decisionObservation.admission, assertions);
|
|
96
100
|
if (admission.kind === "accepted") {
|
|
97
101
|
return {
|
|
@@ -102,7 +106,7 @@ export async function admitDecidedOffer(input) {
|
|
|
102
106
|
};
|
|
103
107
|
}
|
|
104
108
|
if (admission.kind === "publication-failed") {
|
|
105
|
-
return await publicationPremiseMoved(repository, decisionObservation, offer, assertions)
|
|
109
|
+
return (await publicationPremiseMoved(repository, decisionObservation, offer, assertions))
|
|
106
110
|
? { kind: "redecide" }
|
|
107
111
|
: admission;
|
|
108
112
|
}
|
|
@@ -3,7 +3,7 @@ import type { ChangeId, ContractState, DeliverData } from "../core/facts/types.j
|
|
|
3
3
|
import { type AuditTargetAnswer } from "../git/target-placement.js";
|
|
4
4
|
import type { DeliveryPreparationRefusal, DocumentDerivation, IntentOutcome, MutationOperationInput, VerificationStop } from "./operations.js";
|
|
5
5
|
type AuditWorkspace = Readonly<{
|
|
6
|
-
kind: "worktree"
|
|
6
|
+
kind: "worktree";
|
|
7
7
|
path: string;
|
|
8
8
|
}>;
|
|
9
9
|
type DiffScope = DeliveryDiffScope;
|
|
@@ -7,15 +7,7 @@ import { verifyDelivery } from "./intent.js";
|
|
|
7
7
|
import { accepted, admitted } from "./outcome.js";
|
|
8
8
|
import { prepareDelivery } from "./deliver.js";
|
|
9
9
|
import { timestamp, unpackVerificationOutcome } from "./operations.js";
|
|
10
|
-
async function auditWorkspace(repository, state
|
|
11
|
-
if (state.coordinates.workspace === "here") {
|
|
12
|
-
const path = resolveHereWorkspace === undefined
|
|
13
|
-
? repository.effectiveCwd
|
|
14
|
-
: await resolveHereWorkspace(state.id);
|
|
15
|
-
return path === undefined
|
|
16
|
-
? { kind: "unappointed" }
|
|
17
|
-
: { kind: "ready", answer: { kind: "here", path } };
|
|
18
|
-
}
|
|
10
|
+
async function auditWorkspace(repository, state) {
|
|
19
11
|
const appointed = await readManagedWorktreeAppointment(repository, state.id);
|
|
20
12
|
if (appointed.kind === "failed")
|
|
21
13
|
throw new Error(appointed.diagnostic);
|
|
@@ -73,7 +65,7 @@ async function readyAuditCandidate(repository, candidate, workspace, showDiff) {
|
|
|
73
65
|
...(diff === undefined || diff === null ? {} : { diff }),
|
|
74
66
|
};
|
|
75
67
|
}
|
|
76
|
-
async function auditTargetAnswer(repository, state, candidate
|
|
68
|
+
async function auditTargetAnswer(repository, state, candidate) {
|
|
77
69
|
const target = state.coordinates.target;
|
|
78
70
|
if (target === undefined)
|
|
79
71
|
return { kind: "not-observed" };
|
|
@@ -82,7 +74,6 @@ async function auditTargetAnswer(repository, state, candidate, workspacePath) {
|
|
|
82
74
|
coordinates: { ...state.coordinates, target },
|
|
83
75
|
predecessor: candidate.integration.predecessor,
|
|
84
76
|
candidate: candidate.integration.snapshot,
|
|
85
|
-
...(workspacePath === undefined ? {} : { hereWorkspacePath: workspacePath }),
|
|
86
77
|
});
|
|
87
78
|
}
|
|
88
79
|
function blockedAudit(refusal) {
|
|
@@ -112,7 +103,7 @@ export async function auditOperation(input) {
|
|
|
112
103
|
}
|
|
113
104
|
if (derivation.verification.kind === "refused")
|
|
114
105
|
return { kind: "refused", refusal: derivation.verification.refusal };
|
|
115
|
-
const workspace = await auditWorkspace(input.scope, state
|
|
106
|
+
const workspace = await auditWorkspace(input.scope, state);
|
|
116
107
|
if (workspace.kind === "unappointed") {
|
|
117
108
|
return accepted(state, [], blockedAudit({ kind: "worktree-missing", contractId: state.id }));
|
|
118
109
|
}
|
|
@@ -120,7 +111,6 @@ export async function auditOperation(input) {
|
|
|
120
111
|
contractId: state.id,
|
|
121
112
|
coordinates: state.coordinates,
|
|
122
113
|
...(workspace.appointment === undefined ? {} : { appointment: workspace.appointment }),
|
|
123
|
-
...(workspace.answer.kind === "here" ? { workspacePath: workspace.answer.path } : {}),
|
|
124
114
|
}, {
|
|
125
115
|
title: derivation.title,
|
|
126
116
|
document: derivation.bytes,
|
|
@@ -140,7 +130,7 @@ export async function auditOperation(input) {
|
|
|
140
130
|
verification,
|
|
141
131
|
target: verification.kind === "stopped"
|
|
142
132
|
? { kind: "not-observed" }
|
|
143
|
-
: await auditTargetAnswer(input.scope, state, prepared.data
|
|
133
|
+
: await auditTargetAnswer(input.scope, state, prepared.data),
|
|
144
134
|
...(delivery === undefined ? {} : { delivery }),
|
|
145
135
|
};
|
|
146
136
|
return completedAudit(state, verified, value);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type BindTargetSelection } from "../git/observe.js";
|
|
2
|
+
export type { BindTargetSelection };
|
|
1
3
|
import type { GitRepository } from "../git/process.js";
|
|
2
4
|
import type { GitDecodeChannel } from "../git/read-observation.js";
|
|
3
5
|
import type { BindData, ActorId, ContractId } from "../core/facts/types.js";
|
|
@@ -11,21 +13,32 @@ export type TargetInputRefusal = Readonly<{
|
|
|
11
13
|
}> | Readonly<{
|
|
12
14
|
kind: "target-missing";
|
|
13
15
|
}> | Readonly<{
|
|
14
|
-
kind: "
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
kind: "unborn-head";
|
|
17
|
+
}>;
|
|
18
|
+
export type ForkSourceMovedRefusal = Readonly<{
|
|
19
|
+
kind: "fork-source-moved";
|
|
20
|
+
contractId: ContractId;
|
|
17
21
|
}>;
|
|
18
22
|
type BindOperationInput = Readonly<{
|
|
19
23
|
scope: GitRepository;
|
|
20
24
|
channel: GitDecodeChannel;
|
|
21
25
|
terms: BindData["terms"];
|
|
22
26
|
verification: VerificationDeclarationPreparation;
|
|
23
|
-
|
|
24
|
-
workspace: "worktree"
|
|
27
|
+
targetSelection?: BindTargetSelection;
|
|
28
|
+
workspace: "worktree";
|
|
25
29
|
actor?: ActorId;
|
|
26
30
|
decorateOffer?: CompanionDecorator;
|
|
27
31
|
contractId: ContractId;
|
|
32
|
+
coordinates?: Readonly<{
|
|
33
|
+
start: import("../core/facts/types.js").SnapshotId;
|
|
34
|
+
}>;
|
|
35
|
+
source?: Readonly<{
|
|
36
|
+
contractId: ContractId;
|
|
37
|
+
head: import("../core/facts/types.js").ContractHead | null;
|
|
38
|
+
start: import("../core/facts/types.js").SnapshotId;
|
|
39
|
+
document: import("../core/facts/types.js").DocumentKey;
|
|
40
|
+
}>;
|
|
28
41
|
}>;
|
|
29
42
|
export declare function bindOperation(input: BindOperationInput): Promise<IntentOutcome<Readonly<{
|
|
30
43
|
contractId: ContractId;
|
|
31
|
-
}>, BindRefusal | TargetInputRefusal | VerificationDeclarationRefusal>>;
|
|
44
|
+
}>, BindRefusal | TargetInputRefusal | VerificationDeclarationRefusal | ForkSourceMovedRefusal>>;
|
|
@@ -3,18 +3,19 @@ import { gitObjectIdForSnapshot } from "../git/identity.js";
|
|
|
3
3
|
import { decideBind } from "../core/verbs/bind.js";
|
|
4
4
|
import { admitIntent } from "./intent.js";
|
|
5
5
|
import { complete } from "./outcome.js";
|
|
6
|
-
async function bindPreparation(input,
|
|
6
|
+
async function bindPreparation(input, selection, seed) {
|
|
7
7
|
if (input.verification.kind === "refused") {
|
|
8
8
|
return { kind: "prepared", input: { ...seed, preparation: input.verification } };
|
|
9
9
|
}
|
|
10
|
-
const observed = await observeBindCoordinates(input.scope,
|
|
10
|
+
const observed = await observeBindCoordinates(input.scope, selection);
|
|
11
11
|
if (observed === null)
|
|
12
12
|
return { kind: "refused", refusal: { kind: "target-missing" } };
|
|
13
|
-
if (
|
|
14
|
-
return { kind: "refused", refusal: { kind: "
|
|
13
|
+
if (!("start" in observed)) {
|
|
14
|
+
return { kind: "refused", refusal: { kind: "unborn-head" } };
|
|
15
15
|
}
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const start = input.coordinates?.start ?? observed.start;
|
|
17
|
+
const oid = gitObjectIdForSnapshot(input.coordinates === undefined ? start : observed.start);
|
|
18
|
+
const assertions = input.coordinates === undefined ? [{ ref: observed.target ?? "HEAD", oid }] : [];
|
|
18
19
|
return {
|
|
19
20
|
kind: "prepared",
|
|
20
21
|
input: {
|
|
@@ -23,7 +24,7 @@ async function bindPreparation(input, target, seed) {
|
|
|
23
24
|
kind: "prepared",
|
|
24
25
|
data: {
|
|
25
26
|
coordinates: {
|
|
26
|
-
start
|
|
27
|
+
start,
|
|
27
28
|
...(observed.target === undefined ? {} : { target: observed.target }),
|
|
28
29
|
workspace: input.workspace,
|
|
29
30
|
},
|
|
@@ -35,12 +36,12 @@ async function bindPreparation(input, target, seed) {
|
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
export async function bindOperation(input) {
|
|
38
|
-
let
|
|
39
|
-
if (
|
|
40
|
-
const normalized = await normalizeTargetBranch(input.scope,
|
|
39
|
+
let selection = input.targetSelection ?? { kind: "targetless" };
|
|
40
|
+
if (selection.kind === "explicit") {
|
|
41
|
+
const normalized = await normalizeTargetBranch(input.scope, selection.target);
|
|
41
42
|
if (normalized === null)
|
|
42
43
|
return { kind: "refused", refusal: { kind: "invalid-target" } };
|
|
43
|
-
|
|
44
|
+
selection = { kind: "explicit", target: normalized };
|
|
44
45
|
}
|
|
45
46
|
const at = new Date().toISOString();
|
|
46
47
|
const id = input.contractId;
|
|
@@ -49,8 +50,22 @@ export async function bindOperation(input) {
|
|
|
49
50
|
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
50
51
|
at,
|
|
51
52
|
}, decideBind, {
|
|
52
|
-
observedContracts: [id, ...input.terms.after],
|
|
53
|
-
prepareInput: async (_observation, original) => bindPreparation(input,
|
|
53
|
+
observedContracts: [id, ...input.terms.after, ...(input.source === undefined ? [] : [input.source.contractId])],
|
|
54
|
+
prepareInput: async (_observation, original) => bindPreparation(input, selection, original),
|
|
55
|
+
...(input.source === undefined
|
|
56
|
+
? {}
|
|
57
|
+
: {
|
|
58
|
+
validateAdmission: (observation) => {
|
|
59
|
+
const current = observation.decision.get(input.source.contractId);
|
|
60
|
+
return current !== null &&
|
|
61
|
+
current !== undefined &&
|
|
62
|
+
current.head === input.source.head &&
|
|
63
|
+
current.coordinates.start === input.source.start &&
|
|
64
|
+
current.terms.document.key === input.source.document
|
|
65
|
+
? undefined
|
|
66
|
+
: { kind: "fork-source-moved", contractId: input.source.contractId };
|
|
67
|
+
},
|
|
68
|
+
}),
|
|
54
69
|
...(input.decorateOffer === undefined ? {} : { decorateOffer: input.decorateOffer }),
|
|
55
70
|
}), { contractId: id });
|
|
56
71
|
}
|
|
@@ -32,7 +32,6 @@ type CompletionInput = Readonly<{
|
|
|
32
32
|
verification: VerificationDeclarationPreparation;
|
|
33
33
|
initial: AcceptedProtocolStep;
|
|
34
34
|
verifyInitial: boolean;
|
|
35
|
-
hereWorkspacePath?: string;
|
|
36
35
|
}>;
|
|
37
36
|
export type CompletionResult = Readonly<{
|
|
38
37
|
admission: AcceptedProtocolStep;
|