@astrosheep/keiyaku 4.0.4 → 4.0.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/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +24 -4
- package/build/src/akuma/akuma.d.ts +2 -1
- package/build/src/akuma/akuma.js +27 -9
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +3 -10
- package/build/src/akuma/archetype.d.ts +3 -1
- package/build/src/akuma/archetype.js +11 -6
- package/build/src/akuma/body-turn.d.ts +64 -0
- package/build/src/akuma/body-turn.js +449 -0
- package/build/src/akuma/body.d.ts +4 -5
- package/build/src/akuma/body.js +9 -414
- package/build/src/akuma/heart/facts.d.ts +37 -9
- package/build/src/akuma/heart/facts.js +3 -1
- package/build/src/akuma/heart/index.d.ts +4 -13
- package/build/src/akuma/heart/index.js +14 -135
- package/build/src/akuma/heart/request-authority.d.ts +12 -0
- package/build/src/akuma/heart/request-authority.js +119 -0
- package/build/src/akuma/heart/request-rows.d.ts +16 -0
- package/build/src/akuma/heart/request-rows.js +88 -0
- package/build/src/akuma/heart/rows.d.ts +1 -28
- package/build/src/akuma/heart/rows.js +4 -138
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +11 -3
- package/build/src/akuma/heart/soul.js +0 -36
- package/build/src/akuma/heart/timeline.d.ts +1 -0
- package/build/src/akuma/heart/timeline.js +19 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/nuke.d.ts +2 -0
- package/build/src/akuma/nuke.js +152 -0
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +4 -7
- package/build/src/akuma/providers/acp/config.d.ts +8 -0
- package/build/src/akuma/providers/acp/config.js +37 -0
- package/build/src/akuma/providers/acp/core.js +12 -2
- package/build/src/akuma/providers/acp/index.d.ts +1 -8
- package/build/src/akuma/providers/acp/index.js +2 -38
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +12 -3
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +5 -2
- package/build/src/akuma/providers/grok-build/index.js +1 -2
- package/build/src/akuma/providers/index.d.ts +3 -2
- package/build/src/akuma/providers/index.js +36 -36
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +14 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +2 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +2 -2
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +29 -6
- package/build/src/akuma/request-serve.d.ts +88 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +125 -0
- package/build/src/akuma/request-wire.js +383 -0
- package/build/src/akuma/requests.d.ts +28 -94
- package/build/src/akuma/requests.js +52 -562
- package/build/src/akuma-body.d.ts +7 -0
- package/build/src/akuma-body.js +69 -2
- package/build/src/alias/index.d.ts +1 -0
- package/build/src/alias/index.js +34 -1
- package/build/src/body/arc.js +4 -29
- package/build/src/body/decode.js +5 -39
- package/build/src/body/envelope.d.ts +7 -0
- package/build/src/body/envelope.js +37 -0
- package/build/src/cli/accepted.js +21 -9
- package/build/src/cli/commands/akuma-invoke.js +1 -0
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +13 -10
- package/build/src/cli/commands/contract.d.ts +28 -17
- package/build/src/cli/commands/contract.js +23 -17
- package/build/src/cli/commands/install.d.ts +2 -2
- package/build/src/cli/commands/install.js +6 -6
- package/build/src/cli/commands/nuke.d.ts +10 -0
- package/build/src/cli/commands/nuke.js +20 -0
- package/build/src/cli/commands/task-invoke.d.ts +15 -0
- package/build/src/cli/commands/task-invoke.js +144 -24
- package/build/src/cli/commands/task-query.d.ts +2 -2
- package/build/src/cli/commands/task-query.js +1 -2
- package/build/src/cli/commands/task.js +22 -22
- package/build/src/cli/coordinates.d.ts +6 -2
- package/build/src/cli/coordinates.js +12 -56
- package/build/src/cli/invoke.d.ts +5 -4
- package/build/src/cli/invoke.js +112 -58
- package/build/src/cli/main.d.ts +0 -2
- package/build/src/cli/main.js +4 -140
- package/build/src/cli/parse.d.ts +17 -4
- package/build/src/cli/parse.js +93 -15
- package/build/src/cli/render/akuma.js +111 -53
- package/build/src/cli/render/audit.js +2 -6
- package/build/src/cli/render/contract.js +61 -20
- package/build/src/cli/render/kanshi.js +15 -5
- package/build/src/cli/render/nuke.d.ts +3 -0
- package/build/src/cli/render/nuke.js +8 -0
- package/build/src/cli/render/receipt.js +28 -1
- package/build/src/cli/render/refusal.d.ts +2 -1
- package/build/src/cli/render/refusal.js +31 -0
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/render/text.js +6 -1
- package/build/src/cli/result.d.ts +36 -9
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +140 -0
- package/build/src/cli/usage.d.ts +0 -2
- package/build/src/cli/usage.js +0 -4
- package/build/src/contract-worktree.d.ts +29 -14
- package/build/src/contract-worktree.js +131 -70
- package/build/src/core/facts/codec.js +9 -0
- package/build/src/core/facts/fold.js +13 -1
- package/build/src/core/facts/types.d.ts +8 -1
- package/build/src/core/subject.js +4 -3
- package/build/src/core/verbs/placement.d.ts +9 -1
- package/build/src/core/verbs/placement.js +24 -6
- package/build/src/core/verbs/reintegrate.d.ts +13 -0
- package/build/src/core/verbs/reintegrate.js +24 -0
- package/build/src/dispatch/index.d.ts +1 -1
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +2 -0
- package/build/src/git/hooks.js +34 -1
- package/build/src/git/integration.d.ts +9 -2
- package/build/src/git/integration.js +92 -1
- package/build/src/git/nuke.d.ts +2 -0
- package/build/src/git/nuke.js +97 -0
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +28 -0
- package/build/src/git/process.js +94 -0
- package/build/src/git/read-observation.d.ts +2 -1
- package/build/src/git/read-observation.js +3 -2
- package/build/src/git/reconcile.d.ts +4 -1
- package/build/src/git/reconcile.js +42 -8
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +7 -118
- package/build/src/git/scratch.d.ts +1 -1
- package/build/src/git/scratch.js +1 -1
- package/build/src/git/target-placement.d.ts +3 -2
- package/build/src/git/target-placement.js +15 -14
- package/build/src/git/tender.d.ts +2 -1
- package/build/src/git/tender.js +4 -3
- package/build/src/git/terminal-seal.d.ts +2 -2
- package/build/src/git/terminal-seal.js +3 -6
- package/build/src/git/workspace.d.ts +4 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/read.js +5 -1
- package/build/src/library/address.js +7 -1
- package/build/src/library/akuma-creation.d.ts +1 -0
- package/build/src/library/akuma-creation.js +8 -1
- package/build/src/library/audit.d.ts +3 -1
- package/build/src/library/audit.js +2 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +1 -1
- package/build/src/library/configuration.d.ts +1 -1
- package/build/src/library/configuration.js +52 -18
- package/build/src/library/contract.d.ts +59 -4
- package/build/src/library/contract.js +195 -34
- package/build/src/library/delivery.d.ts +4 -2
- package/build/src/library/fleet.d.ts +27 -7
- package/build/src/library/fleet.js +79 -39
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +0 -5
- package/build/src/library/keiyaku.d.ts +6 -2
- package/build/src/library/keiyaku.js +2 -0
- package/build/src/library/mutation.d.ts +3 -1
- package/build/src/library/mutation.js +3 -0
- package/build/src/library/nuke.d.ts +14 -0
- package/build/src/library/nuke.js +54 -0
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +8 -3
- package/build/src/library/refusal.d.ts +10 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +4 -1
- package/build/src/library/repo.js +10 -4
- package/build/src/protocol/abandon.d.ts +9 -0
- package/build/src/protocol/abandon.js +15 -0
- package/build/src/protocol/amend.d.ts +16 -0
- package/build/src/protocol/amend.js +77 -0
- package/build/src/protocol/arc.d.ts +6 -0
- package/build/src/protocol/arc.js +12 -0
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/audit.d.ts +53 -0
- package/build/src/protocol/audit.js +147 -0
- package/build/src/protocol/bind.d.ts +1 -1
- package/build/src/protocol/completion.d.ts +42 -0
- package/build/src/protocol/completion.js +183 -0
- package/build/src/protocol/deliver.d.ts +49 -0
- package/build/src/protocol/deliver.js +261 -0
- package/build/src/protocol/intent.d.ts +2 -1
- package/build/src/protocol/intent.js +8 -2
- package/build/src/protocol/operations.d.ts +93 -202
- package/build/src/protocol/operations.js +23 -642
- package/build/src/protocol/placement.d.ts +12 -13
- package/build/src/protocol/placement.js +8 -19
- package/build/src/protocol/read/status.d.ts +17 -5
- package/build/src/protocol/read/status.js +57 -13
- package/build/src/protocol/reconcile.d.ts +35 -0
- package/build/src/protocol/reconcile.js +41 -0
- package/build/src/protocol/reintegrate.d.ts +31 -0
- package/build/src/protocol/reintegrate.js +74 -0
- package/build/src/protocol/review.d.ts +34 -0
- package/build/src/protocol/review.js +156 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.js +9 -5
- package/build/src/settlement/fence.d.ts +3 -1
- package/build/src/settlement/fence.js +24 -0
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +1 -2
- package/build/src/task/board.d.ts +0 -1
- package/build/src/task/board.js +0 -3
- package/build/src/task/compose.d.ts +2 -2
- package/build/src/task/compose.js +13 -11
- package/build/src/task/context.d.ts +14 -2
- package/build/src/task/context.js +30 -7
- package/build/src/task/index.d.ts +7 -6
- package/build/src/task/index.js +17 -145
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +44 -0
- package/build/src/task/mutation.js +93 -0
- package/build/src/task/operations.d.ts +14 -6
- package/build/src/task/operations.js +57 -57
- package/build/src/task/store.d.ts +1 -0
- package/build/src/task/store.js +91 -3
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/workspace-place.d.ts +3 -4
- package/build/src/workspace-place.js +26 -15
- package/package.json +3 -3
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { worktreeChangeId } from "../git/integration.js";
|
|
2
|
+
import { captureTender, dirtyTenderDelta, dirtyTenderRefusal, } from "../git/tender.js";
|
|
3
|
+
import { observeContractsForAdmissionAt } from "../git/observe.js";
|
|
4
|
+
import { dependencyKeySet } from "../core/subject.js";
|
|
5
|
+
import { contractState } from "../core/facts/observation.js";
|
|
6
|
+
import { gate } from "../core/facts/types.js";
|
|
7
|
+
import { decideAttestation } from "../core/verbs/attestation.js";
|
|
8
|
+
import { admitDecidedOffer, mintAttempts } from "./attempt.js";
|
|
9
|
+
import { admitted } from "./outcome.js";
|
|
10
|
+
import { completeCandidate } from "./completion.js";
|
|
11
|
+
import { appointmentFor, readPlaceRegister } from "../workspace-place.js";
|
|
12
|
+
import { timestamp } from "./operations.js";
|
|
13
|
+
const REVIEWED = gate("reviewed");
|
|
14
|
+
async function captureReviewableWorktree(repository, stage) {
|
|
15
|
+
const appointed = stage.coordinates.workspace === "worktree"
|
|
16
|
+
? appointmentFor(await readPlaceRegister(repository), stage.contractId)
|
|
17
|
+
: undefined;
|
|
18
|
+
const tender = await captureTender(repository, {
|
|
19
|
+
...stage,
|
|
20
|
+
...(appointed === undefined ? {} : { place: appointed.place }),
|
|
21
|
+
...(stage.workspacePath === undefined ? {} : { workspacePath: stage.workspacePath }),
|
|
22
|
+
});
|
|
23
|
+
if (tender.kind === "refused")
|
|
24
|
+
return tender;
|
|
25
|
+
if (tender.data.changes.submodules.length > 0) {
|
|
26
|
+
return { kind: "refused", refusal: await dirtyTenderRefusal(repository, stage.contractId, tender.data) };
|
|
27
|
+
}
|
|
28
|
+
const workspace = await dirtyTenderDelta(repository, tender.data);
|
|
29
|
+
return {
|
|
30
|
+
kind: "prepared",
|
|
31
|
+
data: {
|
|
32
|
+
changeId: await worktreeChangeId(repository, stage, tender.data),
|
|
33
|
+
tender: tender.data,
|
|
34
|
+
...(workspace === undefined ? {} : { workspace }),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export async function prepareReview(repository, stage) {
|
|
39
|
+
const prepared = await captureReviewableWorktree(repository, stage);
|
|
40
|
+
if (prepared.kind === "refused")
|
|
41
|
+
return prepared;
|
|
42
|
+
return {
|
|
43
|
+
kind: "prepared",
|
|
44
|
+
data: {
|
|
45
|
+
changeId: prepared.data.changeId,
|
|
46
|
+
...(prepared.data.workspace === undefined ? {} : { workspace: prepared.data.workspace }),
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function reviewValue(value, completion = {}) {
|
|
51
|
+
return {
|
|
52
|
+
...(value.workspace === undefined ? {} : { workspace: value.workspace }),
|
|
53
|
+
...completion,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function reviewAttempt(input, attempt) {
|
|
57
|
+
const decisionObservation = await observeContractsForAdmissionAt(input.scope, input.channel, [input.contractId]);
|
|
58
|
+
const state = contractState(decisionObservation.decision, input.contractId);
|
|
59
|
+
let preparation;
|
|
60
|
+
let workspace;
|
|
61
|
+
let tender;
|
|
62
|
+
let workspacePath;
|
|
63
|
+
if (state !== null) {
|
|
64
|
+
workspacePath = state.terminal === null && state.coordinates.workspace === "here"
|
|
65
|
+
? await input.resolveHereWorkspace?.(state.id)
|
|
66
|
+
: undefined;
|
|
67
|
+
const prepared = await captureReviewableWorktree(input.scope, {
|
|
68
|
+
contractId: state.id,
|
|
69
|
+
coordinates: state.coordinates,
|
|
70
|
+
...(workspacePath === undefined ? {} : { workspacePath }),
|
|
71
|
+
});
|
|
72
|
+
preparation = prepared.kind === "refused"
|
|
73
|
+
? { kind: "refused", refusal: prepared.refusal }
|
|
74
|
+
: {
|
|
75
|
+
kind: "prepared",
|
|
76
|
+
data: {
|
|
77
|
+
gate: REVIEWED,
|
|
78
|
+
subject: dependencyKeySet([
|
|
79
|
+
{ kind: "document", value: state.terms.document.key },
|
|
80
|
+
{ kind: "change", value: prepared.data.changeId },
|
|
81
|
+
]),
|
|
82
|
+
verdict: input.verdict,
|
|
83
|
+
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
if (prepared.kind === "prepared") {
|
|
87
|
+
workspace = prepared.data.workspace;
|
|
88
|
+
tender = prepared.data.tender;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const decision = decideAttestation({
|
|
92
|
+
input: {
|
|
93
|
+
contractId: input.contractId,
|
|
94
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
95
|
+
at: timestamp(),
|
|
96
|
+
...(preparation === undefined ? {} : { preparation }),
|
|
97
|
+
},
|
|
98
|
+
attempt,
|
|
99
|
+
observation: decisionObservation.decision,
|
|
100
|
+
});
|
|
101
|
+
if (decision.kind === "refused")
|
|
102
|
+
return { kind: "refused", refusal: decision.refusal };
|
|
103
|
+
const admission = await admitDecidedOffer({
|
|
104
|
+
channel: input.channel,
|
|
105
|
+
repository: input.scope,
|
|
106
|
+
decisionObservation,
|
|
107
|
+
attempt,
|
|
108
|
+
offer: decision.offer,
|
|
109
|
+
primaryContract: input.contractId,
|
|
110
|
+
});
|
|
111
|
+
if (admission.kind === "accepted")
|
|
112
|
+
return {
|
|
113
|
+
...admission,
|
|
114
|
+
value: {
|
|
115
|
+
...(workspace === undefined ? {} : { workspace }),
|
|
116
|
+
...(tender === undefined ? {} : { tender }),
|
|
117
|
+
...(workspacePath === undefined ? {} : { workspacePath }),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
return admission;
|
|
121
|
+
}
|
|
122
|
+
export async function reviewOperation(input) {
|
|
123
|
+
const git = input.scope;
|
|
124
|
+
const attempts = mintAttempts({ entryCount: 1 });
|
|
125
|
+
let review = null;
|
|
126
|
+
for (let index = 0; index < attempts.length; index += 1) {
|
|
127
|
+
const result = await reviewAttempt(input, attempts[index]);
|
|
128
|
+
if (result.kind === "accepted" || result.kind === "refused") {
|
|
129
|
+
review = result;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
if (result.kind === "publication-failed")
|
|
133
|
+
return { kind: "retry", reason: result };
|
|
134
|
+
if (result.kind === "collision" && index + 1 === attempts.length)
|
|
135
|
+
return { kind: "retry", reason: result };
|
|
136
|
+
}
|
|
137
|
+
if (review === null)
|
|
138
|
+
return { kind: "retry", reason: { kind: "exhausted" } };
|
|
139
|
+
if (review.kind !== "accepted")
|
|
140
|
+
return review;
|
|
141
|
+
if (input.verdict !== "satisfied")
|
|
142
|
+
return admitted(review, reviewValue(review.value));
|
|
143
|
+
const derivation = input.deriveDocument?.(review.state);
|
|
144
|
+
const completed = await completeCandidate({
|
|
145
|
+
channel: input.channel,
|
|
146
|
+
repository: git,
|
|
147
|
+
contractId: input.contractId,
|
|
148
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
149
|
+
...(review.state.coordinates.target === undefined ? {} : { target: review.state.coordinates.target }),
|
|
150
|
+
verification: derivation?.verification ?? { kind: "prepared", data: null },
|
|
151
|
+
initial: review,
|
|
152
|
+
verifyInitial: false,
|
|
153
|
+
...(review.value.workspacePath === undefined ? {} : { hereWorkspacePath: review.value.workspacePath }),
|
|
154
|
+
});
|
|
155
|
+
return admitted(completed.admission, reviewValue(review.value, completed.evidence));
|
|
156
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type GitDecisionObservation } from "../git/observe.js";
|
|
2
2
|
import type { GitDecodeChannel, GitTreeSelection } from "../git/read-observation.js";
|
|
3
|
-
import type { GitRepository } from "../git/
|
|
3
|
+
import type { GitRepository } from "../git/process.js";
|
|
4
4
|
import type { GitRefAssertion } from "../git/repository.js";
|
|
5
5
|
import type { AttemptContext, DecideInput, OfferDecision } from "../core/decide.js";
|
|
6
6
|
import type { Offer, TreeUpdate } from "../core/facts/offer.js";
|
|
@@ -50,8 +50,14 @@ export async function terminateOwnedProcess(child, force = false) {
|
|
|
50
50
|
const pid = child.pid;
|
|
51
51
|
if (pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
52
52
|
return;
|
|
53
|
+
let exited = false;
|
|
54
|
+
const exit = new Promise((resolve) => {
|
|
55
|
+
child.once("exit", () => { exited = true; resolve(); });
|
|
56
|
+
child.once("close", () => { exited = true; resolve(); });
|
|
57
|
+
});
|
|
53
58
|
if (process.platform === "win32") {
|
|
54
59
|
await terminateWindowsTree(pid);
|
|
60
|
+
await exit;
|
|
55
61
|
return;
|
|
56
62
|
}
|
|
57
63
|
if (force) {
|
|
@@ -61,18 +67,15 @@ export async function terminateOwnedProcess(child, force = false) {
|
|
|
61
67
|
catch (error) {
|
|
62
68
|
ignoreMissingProcess(error);
|
|
63
69
|
}
|
|
70
|
+
await exit;
|
|
64
71
|
return;
|
|
65
72
|
}
|
|
66
|
-
let exited = false;
|
|
67
|
-
const exit = new Promise((resolve) => {
|
|
68
|
-
child.once("exit", () => { exited = true; resolve(); });
|
|
69
|
-
child.once("close", () => { exited = true; resolve(); });
|
|
70
|
-
});
|
|
71
73
|
try {
|
|
72
74
|
process.kill(-pid, "SIGTERM");
|
|
73
75
|
}
|
|
74
76
|
catch (error) {
|
|
75
77
|
ignoreMissingProcess(error);
|
|
78
|
+
await exit;
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
78
81
|
await Promise.race([exit, delay(TERMINATION_GRACE_MS)]);
|
|
@@ -84,6 +87,7 @@ export async function terminateOwnedProcess(child, force = false) {
|
|
|
84
87
|
catch (error) {
|
|
85
88
|
ignoreMissingProcess(error);
|
|
86
89
|
}
|
|
90
|
+
await exit;
|
|
87
91
|
}
|
|
88
92
|
export async function spawnDetachedProcess(input) {
|
|
89
93
|
const log = await open(input.log, "a");
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type HeldSqliteTransactionLock } from "../coordination/sqlite-transaction-lock.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { GitRepository } from "../git/process.js";
|
|
3
3
|
import type { TaskId } from "../task/identity.js";
|
|
4
4
|
export declare function settlementFencePath(repository: GitRepository, taskId: TaskId): string;
|
|
5
5
|
export declare function acquireTaskSettlementFence(repository: GitRepository, taskId: TaskId): Promise<HeldSqliteTransactionLock>;
|
|
6
|
+
/** Remove only the hash-addressed settlement fences owned by Contract/Git reset. */
|
|
7
|
+
export declare function nukeSettlementFences(repository: GitRepository): Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
2
3
|
import { resolve } from "node:path";
|
|
3
4
|
import { acquireSqliteTransactionLock, } from "../coordination/sqlite-transaction-lock.js";
|
|
4
5
|
import { commonGitDirectory } from "../git/repository.js";
|
|
@@ -12,3 +13,26 @@ export function acquireTaskSettlementFence(repository, taskId) {
|
|
|
12
13
|
mode: "immediate",
|
|
13
14
|
});
|
|
14
15
|
}
|
|
16
|
+
/** Remove only the hash-addressed settlement fences owned by Contract/Git reset. */
|
|
17
|
+
export async function nukeSettlementFences(repository) {
|
|
18
|
+
const root = resolve(commonGitDirectory(repository), "keiyaku", "locks", "settlement");
|
|
19
|
+
let entries;
|
|
20
|
+
try {
|
|
21
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (error.code === "ENOENT")
|
|
25
|
+
return;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
if (!/^[0-9a-f]{64}\.sqlite$/u.test(entry.name) || !entry.isFile() || entry.isSymbolicLink()) {
|
|
30
|
+
throw new Error(`Settlement fence custody is invalid: ${resolve(root, entry.name)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const path = resolve(root, entry.name);
|
|
35
|
+
const held = await acquireSqliteTransactionLock({ path, mode: "immediate" });
|
|
36
|
+
held.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TreeUpdate } from "../core/facts/offer.js";
|
|
2
2
|
import { type ContractId } from "../core/facts/types.js";
|
|
3
3
|
import type { GitDecisionObservation } from "../git/observe.js";
|
|
4
|
-
import {
|
|
4
|
+
import type { GitRepository } from "../git/process.js";
|
|
5
5
|
import { type GitDecodeChannel, type GitReadObservation, type GitTreeSelection } from "../git/read-observation.js";
|
|
6
6
|
import { type TaskId } from "../task/identity.js";
|
|
7
7
|
export declare function taskHolderObservationSelection(): GitTreeSelection;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ContractId, type ContractState } from "../core/facts/types.js";
|
|
2
2
|
import type { GitDecodeChannel } from "../git/read-observation.js";
|
|
3
3
|
import type { Effect } from "../git/reconcile.js";
|
|
4
|
-
import type { GitRepository } from "../git/
|
|
4
|
+
import type { GitRepository } from "../git/process.js";
|
|
5
5
|
import type { TaskId } from "../task/identity.js";
|
|
6
6
|
export type SettlementAction = Readonly<{
|
|
7
7
|
kind: "task";
|
|
@@ -78,11 +78,10 @@ async function settleNamespace(state, effects, actions, lags) {
|
|
|
78
78
|
const worktrees = effects.filter((effect) => effect.kind === "worktree" && effect.action !== "removed");
|
|
79
79
|
for (const effect of worktrees) {
|
|
80
80
|
try {
|
|
81
|
-
const world = await World.at(effect.path);
|
|
82
81
|
actions.push({
|
|
83
82
|
kind: "namespace-context",
|
|
84
83
|
path: effect.path,
|
|
85
|
-
action: await repairNamespaceContext(
|
|
84
|
+
action: await repairNamespaceContext(effect.path, contractNamespace(state.id)),
|
|
86
85
|
});
|
|
87
86
|
}
|
|
88
87
|
catch (error) {
|
|
@@ -66,7 +66,6 @@ export declare function taskDisposition(board: TaskBoard, task: TaskDocument): T
|
|
|
66
66
|
export declare function taskBlocked(board: TaskBoard, task: TaskDocument): boolean;
|
|
67
67
|
export declare function projectDetailFacts(board: TaskBoard, id: TaskId, relations: TaskRelationProjection): TaskDetailFacts | null;
|
|
68
68
|
export declare function projectRows(board: TaskBoard, scope: readonly string[] | null, selection: "active" | "closed" | "all"): readonly TaskRow[];
|
|
69
|
-
export declare function projectReady(board: TaskBoard, scope: readonly string[] | null): readonly TaskRow[];
|
|
70
69
|
export declare function projectBlocked(board: TaskBoard, scope: readonly string[] | null, relations: TaskRelationProjection): readonly BlockedTaskRow[];
|
|
71
70
|
export declare function projectStatusRows(board: TaskBoard, scope: readonly string[] | null): (Readonly<{
|
|
72
71
|
id: TaskId;
|
package/build/src/task/board.js
CHANGED
|
@@ -86,9 +86,6 @@ export function projectRows(board, scope, selection) {
|
|
|
86
86
|
disposition: taskDisposition(board, task),
|
|
87
87
|
})).sort((a, b) => a.priority - b.priority || Buffer.compare(Buffer.from(a.id), Buffer.from(b.id)));
|
|
88
88
|
}
|
|
89
|
-
export function projectReady(board, scope) {
|
|
90
|
-
return projectRows(board, scope, "active").filter((row) => row.disposition === "ready");
|
|
91
|
-
}
|
|
92
89
|
export function projectBlocked(board, scope, relations) {
|
|
93
90
|
return projectRows(board, scope, "active").flatMap((row) => {
|
|
94
91
|
if (!taskBlocked(board, board.tasks.get(row.id)))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type TaskId } from "./identity.js";
|
|
2
2
|
import type { WorldRoot } from "../world.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type TaskRefusal, type TaskRetry } from "./operations.js";
|
|
4
4
|
type TaskDocumentChange = Readonly<{
|
|
5
5
|
taskId: TaskId;
|
|
6
6
|
kind: "created" | "updated";
|
|
@@ -21,5 +21,5 @@ export type TaskCompositionResult = Readonly<{
|
|
|
21
21
|
}>;
|
|
22
22
|
draft: string;
|
|
23
23
|
}>;
|
|
24
|
-
export declare function composeTasks(world: WorldRoot, markdown: string, signal?: AbortSignal, actor?: string): Promise<TaskCompositionResult>;
|
|
24
|
+
export declare function composeTasks(world: WorldRoot, markdown: string, signal?: AbortSignal, actor?: string, defaultNamespace?: readonly string[]): Promise<TaskCompositionResult>;
|
|
25
25
|
export {};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
1
|
import { documentDiff } from "../markdown/diff.js";
|
|
3
|
-
import { readNamespaceContext } from "./context.js";
|
|
4
2
|
import { relationProblem } from "./board.js";
|
|
5
3
|
import { serializeTaskDocument } from "./document.js";
|
|
6
4
|
import { allocateLocalId, deriveLocalStem, formatTaskId, parseTaskId, sameNamespace } from "./identity.js";
|
|
7
5
|
import { authorityPath, readBoard, replaceAuthority, withTaskLocks } from "./store.js";
|
|
6
|
+
import { advanceTaskTimestamp } from "./operations.js";
|
|
8
7
|
function failure(diagnostic) { return { kind: "invalid-composition", diagnostic }; }
|
|
9
8
|
function parseNamespace(value) {
|
|
10
9
|
if (value === "")
|
|
@@ -118,8 +117,9 @@ function applyAssignments(document, assignments, body) {
|
|
|
118
117
|
}
|
|
119
118
|
return body === undefined ? next : { ...next, body };
|
|
120
119
|
}
|
|
121
|
-
function currentTimestamp() {
|
|
122
|
-
|
|
120
|
+
function currentTimestamp() {
|
|
121
|
+
return new Date().toISOString();
|
|
122
|
+
}
|
|
123
123
|
function createdTask(id, title, at, actor) {
|
|
124
124
|
return {
|
|
125
125
|
id, title, state: "open", priority: 2, needs: [], parent: null, supersedes: [], relates: [], note: "",
|
|
@@ -164,8 +164,13 @@ function plan(sketch, board, defaultNamespace, at, actor) {
|
|
|
164
164
|
current = { ...current, parent };
|
|
165
165
|
}
|
|
166
166
|
current = applyAssignments(current, node.assignments, node.body);
|
|
167
|
-
if (before !== null
|
|
168
|
-
|
|
167
|
+
if (before !== null
|
|
168
|
+
&& !Buffer.from(serializeTaskDocument(current)).equals(Buffer.from(serializeTaskDocument(before)))) {
|
|
169
|
+
current = {
|
|
170
|
+
...current,
|
|
171
|
+
updatedAt: advanceTaskTimestamp(before.updatedAt, at),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
169
174
|
byDepth[node.depth] = current.id;
|
|
170
175
|
byDepth.length = node.depth + 1;
|
|
171
176
|
all.set(current.id, current);
|
|
@@ -198,15 +203,12 @@ function draft(namespace, remaining) {
|
|
|
198
203
|
}
|
|
199
204
|
return `${lines.join("\n")}\n`;
|
|
200
205
|
}
|
|
201
|
-
export async function composeTasks(world, markdown, signal, actor) {
|
|
206
|
+
export async function composeTasks(world, markdown, signal, actor, defaultNamespace) {
|
|
202
207
|
const sketch = parseSketch(markdown);
|
|
203
208
|
if ("kind" in sketch)
|
|
204
209
|
return { kind: "refused", refusal: sketch };
|
|
205
210
|
const at = currentTimestamp();
|
|
206
|
-
const
|
|
207
|
-
if (context === "malformed")
|
|
208
|
-
return { kind: "refused", refusal: { kind: "invalid-namespace-context", path: resolve(world, ".keiyaku", "namespace", "current") } };
|
|
209
|
-
const namespace = context === "absent" ? [] : context;
|
|
211
|
+
const namespace = sketch.namespace ?? defaultNamespace ?? [];
|
|
210
212
|
const initial = await readBoard(world);
|
|
211
213
|
const planned = plan(sketch, initial.board, namespace, at, actor);
|
|
212
214
|
if ("kind" in planned)
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
export type NamespaceContextRead = readonly string[] | "absent" |
|
|
2
|
-
|
|
1
|
+
export type NamespaceContextRead = readonly string[] | "absent" | Readonly<{
|
|
2
|
+
kind: "malformed";
|
|
3
|
+
path: string;
|
|
4
|
+
}>;
|
|
5
|
+
export type NamespaceContextInput = Readonly<{
|
|
6
|
+
directory: string;
|
|
7
|
+
boundary: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function readNamespaceContext(coordinates: NamespaceContextInput): Promise<NamespaceContextRead>;
|
|
3
10
|
export declare function installNamespaceContext(root: string, segments: readonly string[]): Promise<void>;
|
|
4
11
|
export declare function repairNamespaceContext(root: string, segments: readonly string[]): Promise<"kept" | "installed">;
|
|
12
|
+
export declare function resolveTaskNamespaceContext(input: NamespaceContextInput): Promise<readonly string[] | Readonly<{
|
|
13
|
+
kind: "invalid-namespace-context";
|
|
14
|
+
path: string;
|
|
15
|
+
}>>;
|
|
16
|
+
export declare function writeTaskNamespaceContext(directory: string, value: readonly string[]): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lstat, mkdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { repairDerivedFile, replaceFileDurably } from "../coordination/durable-file.js";
|
|
4
4
|
import { normalizeIdentityStem } from "../identity/normalize.js";
|
|
5
5
|
function directory(root) { return join(root, ".keiyaku", "namespace"); }
|
|
@@ -10,12 +10,12 @@ function validNamespaceSegments(value) {
|
|
|
10
10
|
&& segment.length > 0 && normalizeIdentityStem({ source: segment }) === segment
|
|
11
11
|
&& !segment.includes("/") && segment !== "." && segment !== "..");
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
async function readAt(root) {
|
|
14
14
|
let bytes;
|
|
15
15
|
try {
|
|
16
16
|
const path = currentPath(root), stat = await lstat(path);
|
|
17
17
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
18
|
-
return "malformed";
|
|
18
|
+
return { kind: "malformed", path };
|
|
19
19
|
bytes = await readFile(path, "utf8");
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
@@ -23,11 +23,26 @@ export async function readNamespaceContext(root) {
|
|
|
23
23
|
return "absent";
|
|
24
24
|
throw error;
|
|
25
25
|
}
|
|
26
|
-
if (!bytes.endsWith("\n") || bytes.slice(0, -1).includes("\n"))
|
|
27
|
-
return "malformed";
|
|
26
|
+
if (!bytes.endsWith("\n") || bytes.slice(0, -1).includes("\n")) {
|
|
27
|
+
return { kind: "malformed", path: currentPath(root) };
|
|
28
|
+
}
|
|
28
29
|
const content = bytes.slice(0, -1);
|
|
29
30
|
const segments = content === "" ? [] : content.split("/");
|
|
30
|
-
return validNamespaceSegments(segments) ? segments : "malformed";
|
|
31
|
+
return validNamespaceSegments(segments) ? segments : { kind: "malformed", path: currentPath(root) };
|
|
32
|
+
}
|
|
33
|
+
export async function readNamespaceContext(coordinates) {
|
|
34
|
+
let current = coordinates.directory;
|
|
35
|
+
for (;;) {
|
|
36
|
+
const selected = await readAt(current);
|
|
37
|
+
if (selected !== "absent")
|
|
38
|
+
return selected;
|
|
39
|
+
if (current === coordinates.boundary)
|
|
40
|
+
return "absent";
|
|
41
|
+
const resolvedParent = dirname(resolve(current));
|
|
42
|
+
if (resolvedParent === current || !resolvedParent.startsWith(`${coordinates.boundary}/`))
|
|
43
|
+
return "absent";
|
|
44
|
+
current = resolvedParent;
|
|
45
|
+
}
|
|
31
46
|
}
|
|
32
47
|
export async function installNamespaceContext(root, segments) {
|
|
33
48
|
if (!validNamespaceSegments(segments))
|
|
@@ -41,7 +56,7 @@ async function installIgnore(root) {
|
|
|
41
56
|
await repairDerivedFile(ignorePath(root), "*\n");
|
|
42
57
|
}
|
|
43
58
|
export async function repairNamespaceContext(root, segments) {
|
|
44
|
-
const current = await readNamespaceContext(root);
|
|
59
|
+
const current = await readNamespaceContext({ directory: root, boundary: root });
|
|
45
60
|
if (Array.isArray(current)) {
|
|
46
61
|
await installIgnore(root);
|
|
47
62
|
return "kept";
|
|
@@ -49,3 +64,11 @@ export async function repairNamespaceContext(root, segments) {
|
|
|
49
64
|
await installNamespaceContext(root, segments);
|
|
50
65
|
return "installed";
|
|
51
66
|
}
|
|
67
|
+
export async function resolveTaskNamespaceContext(input) {
|
|
68
|
+
const selected = await readNamespaceContext(input);
|
|
69
|
+
return selected === "absent" ? [] : typeof selected === "object" && "kind" in selected
|
|
70
|
+
? { kind: "invalid-namespace-context", path: selected.path } : selected;
|
|
71
|
+
}
|
|
72
|
+
export async function writeTaskNamespaceContext(directory, value) {
|
|
73
|
+
await installNamespaceContext(directory, value);
|
|
74
|
+
}
|
|
@@ -3,7 +3,7 @@ export type { WorldRoot } from "../world.js";
|
|
|
3
3
|
import { type BlockedTaskRow, type TaskDetailFacts, type TaskDoctorIssue, type TaskRef, type TaskRow, type TaskTreeNode } from "./board.js";
|
|
4
4
|
import { type TaskCompositionResult } from "./compose.js";
|
|
5
5
|
import { TaskAuthorityCorruptionError, type TaskPriority, type TaskState } from "./document.js";
|
|
6
|
-
import {
|
|
6
|
+
import type { TaskId } from "./identity.js";
|
|
7
7
|
import { type AddTaskDocumentInput, type AddTaskInput, type TaskBatchResult, type TaskMutationResult, type TaskOutcome, type TaskRefusal, type TaskRetry, type TaskUpdateResult, type TaskView, type UpdateTaskInput } from "./operations.js";
|
|
8
8
|
import { TASK_RELATION_PREDICATE_FIELDS, type TaskPage, type TaskQueryExpression, type TaskQueryPredicate, type TaskQueryRow, type TaskQuerySort, type TaskRelationPredicateField } from "./query.js";
|
|
9
9
|
export type TaskDetail = Omit<TaskDetailFacts, "task"> & Readonly<{
|
|
@@ -53,10 +53,6 @@ declare class TasksHandle {
|
|
|
53
53
|
private readonly world;
|
|
54
54
|
readonly root: WorldRoot;
|
|
55
55
|
constructor(world: WorldRoot);
|
|
56
|
-
namespace(): Promise<TaskNamespaceResult>;
|
|
57
|
-
setNamespace(input: Readonly<{
|
|
58
|
-
namespace: readonly string[];
|
|
59
|
-
}>): Promise<void>;
|
|
60
56
|
task(input: Readonly<{
|
|
61
57
|
id: string;
|
|
62
58
|
}>): Task;
|
|
@@ -65,21 +61,25 @@ declare class TasksHandle {
|
|
|
65
61
|
list(input?: Readonly<{
|
|
66
62
|
selection?: "active" | "closed" | "all";
|
|
67
63
|
scope?: "namespace" | "world";
|
|
64
|
+
namespace?: readonly string[];
|
|
68
65
|
limit?: number;
|
|
69
66
|
}>): Promise<TaskList>;
|
|
70
67
|
ready(input?: Readonly<{
|
|
71
68
|
scope?: "namespace" | "world";
|
|
69
|
+
namespace?: readonly string[];
|
|
72
70
|
parent?: string;
|
|
73
71
|
limit?: number;
|
|
74
72
|
}>): Promise<TaskList>;
|
|
75
73
|
blocked(input?: Readonly<{
|
|
76
74
|
scope?: "namespace" | "world";
|
|
75
|
+
namespace?: readonly string[];
|
|
77
76
|
parent?: string;
|
|
78
77
|
limit?: number;
|
|
79
78
|
}>): Promise<BlockedTaskList>;
|
|
80
79
|
query(input?: Readonly<{
|
|
81
80
|
where?: TaskQueryExpression;
|
|
82
81
|
scope?: "namespace" | "world";
|
|
82
|
+
namespace?: readonly string[];
|
|
83
83
|
sort?: TaskQuerySort;
|
|
84
84
|
limit?: number;
|
|
85
85
|
}>): Promise<TaskQueryResult>;
|
|
@@ -92,11 +92,12 @@ declare class TasksHandle {
|
|
|
92
92
|
}>): Promise<TaskBatchResult>;
|
|
93
93
|
compose(input: Readonly<{
|
|
94
94
|
markdown: string;
|
|
95
|
+
namespace?: readonly string[];
|
|
95
96
|
actor?: string;
|
|
96
97
|
signal?: AbortSignal;
|
|
97
98
|
}>): Promise<TaskCompositionResult>;
|
|
98
99
|
}
|
|
99
100
|
export type Tasks = TasksHandle;
|
|
100
101
|
export declare const Tasks: Readonly<{
|
|
101
|
-
of(
|
|
102
|
+
of(world: WorldRoot): Tasks;
|
|
102
103
|
}>;
|