@astrosheep/keiyaku 4.5.20 → 4.5.21
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 +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -8
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +237 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +6 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +2 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -3
- package/build/src/akuma/akuma-handle.d.ts +5 -1
- package/build/src/akuma/akuma-handle.js +4 -1
- package/build/src/akuma/akuma-instance.d.ts +7 -2
- package/build/src/akuma/akuma-instance.js +14 -7
- package/build/src/akuma/akuma-observe.d.ts +11 -0
- package/build/src/akuma/akuma-observe.js +22 -0
- package/build/src/akuma/akuma-product.d.ts +1 -0
- package/build/src/akuma/akuma-product.js +3 -0
- package/build/src/akuma/akuma.d.ts +1 -0
- package/build/src/akuma/body.d.ts +25 -5
- package/build/src/akuma/body.js +65 -8
- package/build/src/akuma/call-request.d.ts +2 -0
- package/build/src/akuma/call-request.js +2 -0
- package/build/src/akuma/fleet-execution.d.ts +28 -0
- package/build/src/akuma/fleet-execution.js +36 -4
- package/build/src/akuma/fleet-request.d.ts +10 -0
- package/build/src/akuma/fleet-request.js +11 -2
- package/build/src/akuma/heart/facts.d.ts +2 -0
- package/build/src/akuma/heart/index.d.ts +1 -0
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/rows.d.ts +2 -0
- package/build/src/akuma/heart/rows.js +7 -5
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +3 -1
- package/build/src/akuma/heart/tells.js +6 -5
- package/build/src/akuma/heart/timeline.js +1 -1
- package/build/src/akuma/provider.d.ts +1 -1
- package/build/src/akuma/provider.js +1 -1
- package/build/src/akuma/providers/acp/core.js +3 -6
- package/build/src/akuma/providers/claude/index.js +9 -12
- package/build/src/akuma/providers/codex-app-server/index.js +4 -11
- package/build/src/akuma/providers/execution-environment.d.ts +6 -0
- package/build/src/akuma/providers/execution-environment.js +24 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +30 -23
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +8 -1
- package/build/src/akuma/providers/opencode-sdk/session.js +6 -5
- package/build/src/akuma/providers/pi/events.js +7 -2
- package/build/src/akuma/providers/pi/index.js +3 -2
- package/build/src/akuma/request-rendezvous.js +8 -3
- package/build/src/akuma/turn-drive.d.ts +1 -0
- package/build/src/akuma/turn-drive.js +2 -0
- package/build/src/akuma-body.js +2 -0
- package/build/src/body/amend.js +6 -4
- package/build/src/body/decode.d.ts +3 -1
- package/build/src/body/decode.js +53 -17
- package/build/src/body/region.d.ts +9 -1
- package/build/src/body/region.js +87 -12
- package/build/src/body/render.js +1 -1
- package/build/src/body/verification.d.ts +3 -1
- package/build/src/body/verification.js +4 -1
- package/build/src/cli/accepted.js +19 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +133 -13
- package/build/src/cli/commands/akuma.js +11 -4
- package/build/src/cli/commands/contract-help.js +17 -4
- package/build/src/cli/commands/contract.js +6 -4
- package/build/src/cli/commands/status-set.js +15 -24
- package/build/src/cli/main.js +5 -0
- package/build/src/cli/parse.d.ts +2 -0
- package/build/src/cli/parse.js +5 -0
- package/build/src/cli/render/akuma-activity.d.ts +99 -2
- package/build/src/cli/render/akuma-activity.js +484 -40
- package/build/src/cli/render/akuma.d.ts +10 -0
- package/build/src/cli/render/akuma.js +28 -21
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/board.js +1 -1
- package/build/src/cli/render/catalog.js +16 -13
- package/build/src/cli/render/contract-history.js +39 -10
- package/build/src/cli/render/contract-observation.js +10 -6
- package/build/src/cli/render/contract.js +109 -106
- package/build/src/cli/render/execution-progress.d.ts +23 -1
- package/build/src/cli/render/execution-progress.js +151 -28
- package/build/src/cli/render/kanshi-akuma.js +27 -39
- package/build/src/cli/render/kanshi.js +33 -26
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/render/receipt.d.ts +1 -1
- package/build/src/cli/render/receipt.js +5 -5
- package/build/src/cli/render/refusal.js +10 -7
- package/build/src/cli/render/region.js +1 -1
- package/build/src/cli/render/settings.js +12 -2
- package/build/src/cli/render/status-line.d.ts +30 -0
- package/build/src/cli/render/status-line.js +58 -0
- package/build/src/cli/render/status-set.js +1 -1
- package/build/src/cli/render/task.d.ts +2 -0
- package/build/src/cli/render/task.js +11 -7
- package/build/src/cli/render/terminal.d.ts +0 -1
- package/build/src/cli/render/terminal.js +47 -15
- package/build/src/cli/result.d.ts +1 -0
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +13 -7
- package/build/src/cli/usage.js +2 -2
- package/build/src/cli/version.d.ts +1 -0
- package/build/src/cli/version.js +25 -0
- package/build/src/git/workspace.d.ts +1 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/identity/mint.d.ts +13 -0
- package/build/src/identity/mint.js +26 -0
- package/build/src/identity/normalize.d.ts +4 -0
- package/build/src/identity/normalize.js +30 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/kanshi/read.js +17 -4
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/akuma-creation.d.ts +2 -0
- package/build/src/library/akuma-creation.js +33 -17
- package/build/src/library/bind.js +18 -16
- package/build/src/library/contract-bind.d.ts +3 -1
- package/build/src/library/contract-bind.js +5 -3
- package/build/src/library/contract-operations.d.ts +2 -2
- package/build/src/library/contract-operations.js +1 -1
- package/build/src/library/contract-types.d.ts +1 -0
- package/build/src/library/fleet.d.ts +4 -1
- package/build/src/library/fleet.js +32 -8
- package/build/src/plugin/akuma-signals.d.ts +6 -0
- package/build/src/plugin/akuma-signals.js +8 -0
- package/build/src/plugin/public.d.ts +4 -0
- package/build/src/plugin/runtime.js +4 -1
- package/build/src/protocol/amend.js +4 -3
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/bind.js +41 -14
- package/build/src/protocol/completion.d.ts +3 -0
- package/build/src/protocol/completion.js +7 -1
- package/build/src/protocol/deliver.js +165 -92
- package/build/src/protocol/execution-observation.d.ts +0 -4
- package/build/src/protocol/intent.d.ts +15 -20
- package/build/src/protocol/intent.js +29 -17
- package/build/src/protocol/operations.d.ts +2 -0
- package/build/src/protocol/placement.js +5 -1
- package/build/src/protocol/read/status.d.ts +1 -0
- package/build/src/protocol/read/status.js +10 -2
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +70 -43
- package/build/src/protocol/result-codec.js +9 -7
- package/build/src/protocol/review.js +53 -30
- package/build/src/protocol/run.d.ts +83 -36
- package/build/src/protocol/run.js +90 -75
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settings.js +5 -14
- package/build/src/task/document.d.ts +5 -1
- package/build/src/task/document.js +6 -1
- package/build/src/verification/execution.d.ts +0 -1
- package/build/src/verification/execution.js +0 -24
- package/build/src/verification/observation.d.ts +0 -4
- package/build/src/verification/observation.js +1 -2
- package/package.json +3 -1
- package/build/src/git/verification-environment.d.ts +0 -10
- package/build/src/git/verification-environment.js +0 -281
|
@@ -12,6 +12,16 @@ export function gitShortStat(stat) {
|
|
|
12
12
|
return parts.join(", ");
|
|
13
13
|
}
|
|
14
14
|
const GRAPHEMES = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
15
|
+
const NON_ASCII = /[^\x20-\x7e]/u;
|
|
16
|
+
const MARK = /\p{Mark}/u;
|
|
17
|
+
const PICTOGRAPHIC = /\p{Extended_Pictographic}/u;
|
|
18
|
+
const EMOJI_DEFAULT = /\p{Emoji_Presentation}/u;
|
|
19
|
+
const ZWJ = 0x200d;
|
|
20
|
+
const TEXT_PRESENTATION = 0xfe0e;
|
|
21
|
+
const EMOJI_PRESENTATION = 0xfe0f;
|
|
22
|
+
const REGIONAL_FIRST = 0x1f1e6;
|
|
23
|
+
const REGIONAL_LAST = 0x1f1ff;
|
|
24
|
+
const ZERO_WIDTH = new Set([0x200b, 0x200c, 0x200d, 0x200e, 0x200f, 0x2060, 0xfeff]);
|
|
15
25
|
const WIDE_RANGES = [
|
|
16
26
|
[0x1100, 0x115f],
|
|
17
27
|
[0x2329, 0x232a],
|
|
@@ -25,33 +35,59 @@ const WIDE_RANGES = [
|
|
|
25
35
|
[0x1f300, 0x1faff],
|
|
26
36
|
[0x20000, 0x3fffd],
|
|
27
37
|
];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (point ===
|
|
38
|
+
/** Columns one code point occupies when its grapheme cluster gives it no wider form. */
|
|
39
|
+
function baseColumns(point) {
|
|
40
|
+
if (point === 0 || point < 0x20 || (point >= 0x7f && point < 0xa0))
|
|
31
41
|
return 0;
|
|
32
|
-
if (point
|
|
42
|
+
if (ZERO_WIDTH.has(point) || MARK.test(String.fromCodePoint(point)))
|
|
33
43
|
return 0;
|
|
34
44
|
if (point === 0x303f)
|
|
35
45
|
return 1;
|
|
36
46
|
return WIDE_RANGES.some(([first, last]) => point >= first && point <= last) ? 2 : 1;
|
|
37
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Columns one grapheme cluster occupies. A cluster is one terminal cell group even
|
|
50
|
+
* when it is built from many code points, so ZWJ sequences, flags, keycaps and
|
|
51
|
+
* variation selectors never count the width of their parts.
|
|
52
|
+
*/
|
|
53
|
+
function graphemeColumns(cluster) {
|
|
54
|
+
const points = [...cluster].map((character) => character.codePointAt(0));
|
|
55
|
+
if (points.every((point) => point === EMOJI_PRESENTATION || point === TEXT_PRESENTATION))
|
|
56
|
+
return 0;
|
|
57
|
+
const first = points[0];
|
|
58
|
+
if (points.length > 1 && points.every((point) => point >= REGIONAL_FIRST && point <= REGIONAL_LAST))
|
|
59
|
+
return 2;
|
|
60
|
+
// A presentation selector decides a text-default symbol: text stays narrow, emoji widens it.
|
|
61
|
+
if (points.includes(TEXT_PRESENTATION))
|
|
62
|
+
return baseColumns(first);
|
|
63
|
+
if (points.includes(EMOJI_PRESENTATION))
|
|
64
|
+
return 2;
|
|
65
|
+
// A joined pictographic sequence is one wide cluster; a plain text symbol is not.
|
|
66
|
+
if (points.includes(ZWJ) && PICTOGRAPHIC.test(cluster))
|
|
67
|
+
return 2;
|
|
68
|
+
if (EMOJI_DEFAULT.test(cluster))
|
|
69
|
+
return 2;
|
|
70
|
+
return baseColumns(first);
|
|
71
|
+
}
|
|
38
72
|
export function displayColumns(value) {
|
|
73
|
+
if (!NON_ASCII.test(value))
|
|
74
|
+
return value.length;
|
|
39
75
|
let columns = 0;
|
|
40
|
-
for (const
|
|
41
|
-
columns +=
|
|
76
|
+
for (const { segment } of GRAPHEMES.segment(value))
|
|
77
|
+
columns += graphemeColumns(segment);
|
|
42
78
|
return columns;
|
|
43
79
|
}
|
|
44
80
|
export function takeDisplayColumns(value, maximum) {
|
|
45
|
-
const
|
|
81
|
+
const clusters = [...GRAPHEMES.segment(value)].map(({ segment }) => segment);
|
|
46
82
|
let columns = 0;
|
|
47
83
|
let index = 0;
|
|
48
|
-
for (; index <
|
|
49
|
-
const width =
|
|
84
|
+
for (; index < clusters.length; index += 1) {
|
|
85
|
+
const width = graphemeColumns(clusters[index]);
|
|
50
86
|
if (columns + width > maximum)
|
|
51
87
|
break;
|
|
52
88
|
columns += width;
|
|
53
89
|
}
|
|
54
|
-
return { text:
|
|
90
|
+
return { text: clusters.slice(0, index).join(""), rest: clusters.slice(index).join("") };
|
|
55
91
|
}
|
|
56
92
|
export function truncateDisplayText(value, maximum) {
|
|
57
93
|
const clean = safeText(value);
|
|
@@ -210,10 +246,6 @@ export function tone(value, kind, color) {
|
|
|
210
246
|
const code = kind === "dim" ? 2 : kind === "recent" ? 32 : kind === "attention" ? 33 : 31;
|
|
211
247
|
return `\u001b[${code}m${value}\u001b[0m`;
|
|
212
248
|
}
|
|
213
|
-
export function boundedActivity(value, columns, prefix) {
|
|
214
|
-
const budget = Math.max(1, columns - displayColumns(prefix));
|
|
215
|
-
return `activity "${truncateDisplayText(value, Math.max(1, budget - displayColumns('activity ""')))}` + `"`;
|
|
216
|
-
}
|
|
217
249
|
export function plumbFacts(facts, columns) {
|
|
218
250
|
const lines = [];
|
|
219
251
|
let current = " ";
|
|
@@ -255,7 +287,7 @@ export function entityLines(entity) {
|
|
|
255
287
|
];
|
|
256
288
|
}
|
|
257
289
|
export function renderSectionBlock({ name, rows, hasMore = false, }) {
|
|
258
|
-
const lines = [
|
|
290
|
+
const lines = [`${name}`, "", ...rows.flat()];
|
|
259
291
|
if (hasMore)
|
|
260
292
|
lines.push("…");
|
|
261
293
|
return lines;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { TaskInvocationResult } from "./commands/task-invoke.js";
|
|
2
2
|
import type { ParsedCommand, ParsedExecution } from "./parse.js";
|
|
3
|
+
import type { ExecutionEvent } from "../library/execution.js";
|
|
4
|
+
export declare function writeExecutionProgress(events: AsyncIterable<ExecutionEvent>, stream?: NodeJS.WritableStream): Promise<void>;
|
|
3
5
|
export declare function writeTask(command: Extract<ParsedCommand, {
|
|
4
6
|
command: "task";
|
|
5
7
|
}>, result: TaskInvocationResult): Promise<number>;
|
package/build/src/cli/runtime.js
CHANGED
|
@@ -5,10 +5,16 @@ import { safeText } from "./render/terminal.js";
|
|
|
5
5
|
function writeCliStream(stream, body) {
|
|
6
6
|
stream.write(body.endsWith("\n") ? body : `${body}\n`);
|
|
7
7
|
}
|
|
8
|
-
async function writeExecutionProgress(events) {
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export async function writeExecutionProgress(events, stream = process.stderr) {
|
|
9
|
+
const { renderExecutionProgress } = await import("./render/execution-progress.js");
|
|
10
|
+
const terminal = stream;
|
|
11
|
+
await renderExecutionProgress(events, {
|
|
12
|
+
stream: terminal,
|
|
13
|
+
context: {
|
|
14
|
+
columns: terminal.isTTY === true && Number.isInteger(terminal.columns) ? (terminal.columns ?? 80) : 80,
|
|
15
|
+
color: false,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
12
18
|
}
|
|
13
19
|
function cliCancellation() {
|
|
14
20
|
const controller = new AbortController();
|
|
@@ -132,7 +138,7 @@ function writeWorldScopeRefusal(error, command) {
|
|
|
132
138
|
const body = command.output === "json"
|
|
133
139
|
? JSON.stringify(error.refusal)
|
|
134
140
|
: [
|
|
135
|
-
|
|
141
|
+
`× selector ${error.refusal.kind}`,
|
|
136
142
|
` world ${safeText(error.refusal.world)}`,
|
|
137
143
|
...error.refusal.ids.map((id) => ` given ${safeText(id)}`),
|
|
138
144
|
` accepts ${guide.accepts}`,
|
|
@@ -154,9 +160,9 @@ async function commandFailureText(error, command) {
|
|
|
154
160
|
}, "selector");
|
|
155
161
|
}
|
|
156
162
|
const { renderRefusalFacts } = await import("./render/refusal.js");
|
|
157
|
-
return [
|
|
163
|
+
return [`× ${command.command} refused`, ...renderRefusalFacts(error.refusal, " ", displayContext().columns)].join("\n");
|
|
158
164
|
}
|
|
159
|
-
return
|
|
165
|
+
return `× ${command.command} failed\n diagnostic ${safeText(diagnostic)}`;
|
|
160
166
|
}
|
|
161
167
|
export async function runCliCommand(invocation) {
|
|
162
168
|
const command = invocation.command;
|
package/build/src/cli/usage.js
CHANGED
|
@@ -34,9 +34,9 @@ export function unknownCommandGuide(guide, given) {
|
|
|
34
34
|
}
|
|
35
35
|
export function renderUsageMessage(diagnostic, guide, kind = "usage") {
|
|
36
36
|
if (guide === undefined) {
|
|
37
|
-
return
|
|
37
|
+
return `× ${kind}\n diagnostic ${diagnostic}`;
|
|
38
38
|
}
|
|
39
|
-
const lines = [
|
|
39
|
+
const lines = [`× ${kind} ${guide.scope}`];
|
|
40
40
|
if (!guide.hideDiagnostic && diagnostic.length > 0) {
|
|
41
41
|
lines.push(` diagnostic ${diagnostic}`);
|
|
42
42
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installedPackageVersion(): Promise<string>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
const PACKAGE_NAME = "@astrosheep/keiyaku";
|
|
3
|
+
export async function installedPackageVersion() {
|
|
4
|
+
const manifest = JSON.parse(await readFile(owningManifestUrl(), "utf8"));
|
|
5
|
+
if (!isOwningManifest(manifest)) {
|
|
6
|
+
throw new Error(`Keiyaku package manifest must name ${PACKAGE_NAME} and contain a nonempty version`);
|
|
7
|
+
}
|
|
8
|
+
return manifest.version;
|
|
9
|
+
}
|
|
10
|
+
function owningManifestUrl() {
|
|
11
|
+
const relativePath = import.meta.url.endsWith("/src/cli/version.ts")
|
|
12
|
+
? "../../package.json"
|
|
13
|
+
: import.meta.url.endsWith("/build/src/cli/version.js")
|
|
14
|
+
? "../../../package.json"
|
|
15
|
+
: undefined;
|
|
16
|
+
if (relativePath === undefined)
|
|
17
|
+
throw new Error("Keiyaku package metadata has an unsupported module layout");
|
|
18
|
+
return new URL(relativePath, import.meta.url);
|
|
19
|
+
}
|
|
20
|
+
function isOwningManifest(value) {
|
|
21
|
+
if (typeof value !== "object" || value === null)
|
|
22
|
+
return false;
|
|
23
|
+
const manifest = value;
|
|
24
|
+
return manifest.name === PACKAGE_NAME && typeof manifest.version === "string" && manifest.version.trim().length > 0;
|
|
25
|
+
}
|
|
@@ -49,7 +49,7 @@ export type WorkspaceChangeCounts = Readonly<{
|
|
|
49
49
|
}>;
|
|
50
50
|
export type ConflictRecovery = Readonly<{
|
|
51
51
|
materialize: "deliver --materialize-conflict --include-dirty";
|
|
52
|
-
|
|
52
|
+
deliver: "deliver --include-dirty";
|
|
53
53
|
staging: "not-required";
|
|
54
54
|
}>;
|
|
55
55
|
export declare const conflictRecovery: ConflictRecovery;
|
|
@@ -195,7 +195,7 @@ export async function unmergedWorkspacePaths(repository, workspace) {
|
|
|
195
195
|
}
|
|
196
196
|
export const conflictRecovery = Object.freeze({
|
|
197
197
|
materialize: "deliver --materialize-conflict --include-dirty",
|
|
198
|
-
|
|
198
|
+
deliver: "deliver --include-dirty",
|
|
199
199
|
staging: "not-required",
|
|
200
200
|
});
|
|
201
201
|
function countsOf(changes) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mint one identity segment from a fitted stem by drawing a fresh random suffix
|
|
3
|
+
* and letting the caller admit the candidate. A collision redraws the suffix
|
|
4
|
+
* within the attempt budget; exhaustion returns the last collision rather than
|
|
5
|
+
* lengthening the identity.
|
|
6
|
+
*/
|
|
7
|
+
export declare function mintIdentitySegment<Value>(input: Readonly<{
|
|
8
|
+
stem: string;
|
|
9
|
+
attempts: number;
|
|
10
|
+
drawSuffix: () => string;
|
|
11
|
+
attempt: (segment: string) => Promise<Value>;
|
|
12
|
+
collision: (value: Value) => boolean;
|
|
13
|
+
}>): Promise<Value>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const IDENTITY_SUFFIX_PATTERN = /^[0-9a-f]{4}$/u;
|
|
2
|
+
function requireIdentitySuffix(value) {
|
|
3
|
+
if (!IDENTITY_SUFFIX_PATTERN.test(value)) {
|
|
4
|
+
throw new Error("identity suffix must be four lowercase hexadecimal digits");
|
|
5
|
+
}
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Mint one identity segment from a fitted stem by drawing a fresh random suffix
|
|
10
|
+
* and letting the caller admit the candidate. A collision redraws the suffix
|
|
11
|
+
* within the attempt budget; exhaustion returns the last collision rather than
|
|
12
|
+
* lengthening the identity.
|
|
13
|
+
*/
|
|
14
|
+
export async function mintIdentitySegment(input) {
|
|
15
|
+
if (!Number.isSafeInteger(input.attempts) || input.attempts < 1) {
|
|
16
|
+
throw new Error("identity mint attempt budget must be a positive safe integer");
|
|
17
|
+
}
|
|
18
|
+
let result;
|
|
19
|
+
for (let index = 0; index < input.attempts; index += 1) {
|
|
20
|
+
const suffix = requireIdentitySuffix(input.drawSuffix());
|
|
21
|
+
result = await input.attempt(`${input.stem}-${suffix}`);
|
|
22
|
+
if (!input.collision(result))
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export declare function normalizeIdentityStem(input: Readonly<{
|
|
2
2
|
source: string;
|
|
3
3
|
}>): string;
|
|
4
|
+
export declare function fitIdentityStemWords(input: Readonly<{
|
|
5
|
+
stem: string;
|
|
6
|
+
maxCodePoints: number;
|
|
7
|
+
}>): string;
|
|
4
8
|
export declare function fitIdentityStem(input: Readonly<{
|
|
5
9
|
stem: string;
|
|
6
10
|
maxBytes: number;
|
|
@@ -21,6 +21,36 @@ export function normalizeIdentityStem(input) {
|
|
|
21
21
|
}
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
|
+
export function fitIdentityStemWords(input) {
|
|
25
|
+
if (!Number.isSafeInteger(input.maxCodePoints) || input.maxCodePoints < 1) {
|
|
26
|
+
throw new Error("identity stem code point budget must be a positive safe integer");
|
|
27
|
+
}
|
|
28
|
+
const words = input.stem.split("-");
|
|
29
|
+
let fitted = truncateGraphemes(words[0], input.maxCodePoints);
|
|
30
|
+
let count = [...fitted].length;
|
|
31
|
+
for (const word of words.slice(1)) {
|
|
32
|
+
const candidate = count + 1 + [...word].length;
|
|
33
|
+
if (candidate > input.maxCodePoints)
|
|
34
|
+
break;
|
|
35
|
+
fitted += `-${word}`;
|
|
36
|
+
count = candidate;
|
|
37
|
+
}
|
|
38
|
+
if (fitted.length === 0)
|
|
39
|
+
throw new Error("identity stem is empty after fitting");
|
|
40
|
+
return fitted;
|
|
41
|
+
}
|
|
42
|
+
function truncateGraphemes(value, maxCodePoints) {
|
|
43
|
+
let result = "";
|
|
44
|
+
let count = 0;
|
|
45
|
+
for (const { segment } of GRAPHEMES.segment(value)) {
|
|
46
|
+
const size = [...segment].length;
|
|
47
|
+
if (count + size > maxCodePoints)
|
|
48
|
+
break;
|
|
49
|
+
result += segment;
|
|
50
|
+
count += size;
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
24
54
|
export function fitIdentityStem(input) {
|
|
25
55
|
if (!Number.isSafeInteger(input.maxBytes) || input.maxBytes < 1) {
|
|
26
56
|
throw new Error("identity stem byte budget must be a positive safe integer");
|
package/build/src/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from "./library/keiyaku.js";
|
|
2
|
+
export { Akuma, Schema, ALLOWED_ACTIONS, AkumaBusyError, AkumaDecodeError, AkumaNotBornError, AkumaProviderError, } from "./akuma/index.js";
|
|
3
|
+
export type { AkumaBirthInput, AkumaHistoryOptions, AkumaIdleOptions, AkumaSignalOptions, AkumaTellOptions, InterruptReceipt, KillEvidence, JsonSchema, JsonSchemaDocument, AkuId, AkumaStatus, ActivityHistory, ActivityRow, AllowedAction, AllowedActions, } from "./akuma/index.js";
|
|
2
4
|
export { settings } from "./settings.js";
|
|
3
5
|
export { World, WorldError } from "./world.js";
|
|
4
6
|
export type { WorldResolution, WorldResolutionInput, WorldRoot } from "./world.js";
|
package/build/src/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from "./library/keiyaku.js";
|
|
2
|
+
export { Akuma, Schema, ALLOWED_ACTIONS, AkumaBusyError, AkumaDecodeError, AkumaNotBornError, AkumaProviderError, } from "./akuma/index.js";
|
|
2
3
|
export { settings } from "./settings.js";
|
|
3
4
|
export { World, WorldError } from "./world.js";
|
package/build/src/kanshi/read.js
CHANGED
|
@@ -15,7 +15,7 @@ import { readDocuments } from "../protocol/read/documents.js";
|
|
|
15
15
|
import { contractId } from "../core/facts/types.js";
|
|
16
16
|
import { selectKanshi, selectRegion } from "./select.js";
|
|
17
17
|
import { FLEET_SNAPSHOT_ROWS, FLEET_VISIBLE_ROWS } from "./fleet.js";
|
|
18
|
-
import { observeRecentTaskStatus } from "../task/index.js";
|
|
18
|
+
import { observeRecentTaskStatus, TaskAuthorityCorruptionError } from "../task/index.js";
|
|
19
19
|
function diagnostic(error) {
|
|
20
20
|
let source;
|
|
21
21
|
if (error instanceof Error)
|
|
@@ -224,6 +224,15 @@ function joinTasks(rows, holders, observeContract) {
|
|
|
224
224
|
return { ...row, contract: { id: contractId, observed: observeContract(contractId) } };
|
|
225
225
|
});
|
|
226
226
|
}
|
|
227
|
+
/** Attribute a Task board failure to the malformed document that caused it, when one is known. */
|
|
228
|
+
function taskFailure(error) {
|
|
229
|
+
return {
|
|
230
|
+
message: diagnostic(error),
|
|
231
|
+
...(error instanceof TaskAuthorityCorruptionError && error.coordinate !== undefined
|
|
232
|
+
? { coordinate: error.coordinate }
|
|
233
|
+
: {}),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
227
236
|
async function readTaskWorld(path) {
|
|
228
237
|
if (path === null)
|
|
229
238
|
return { kind: "absent" };
|
|
@@ -231,14 +240,18 @@ async function readTaskWorld(path) {
|
|
|
231
240
|
return { kind: "present", observation: await observeTaskBoard(path) };
|
|
232
241
|
}
|
|
233
242
|
catch (error) {
|
|
234
|
-
return { kind: "failed", failure:
|
|
243
|
+
return { kind: "failed", failure: taskFailure(error) };
|
|
235
244
|
}
|
|
236
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* A selected Contract's own Task namespace view. A failed Task board is reported once by the
|
|
248
|
+
* board's Task section, so the entity block omits it rather than repeating the same row.
|
|
249
|
+
*/
|
|
237
250
|
function namespaceTaskSection(board, id) {
|
|
238
251
|
if (board.kind === "absent")
|
|
239
252
|
return { kind: "absent" };
|
|
240
253
|
if (board.kind === "failed")
|
|
241
|
-
return
|
|
254
|
+
return undefined;
|
|
242
255
|
return { kind: "present", value: board.observation.selectNamespace(contractNamespace(id)) };
|
|
243
256
|
}
|
|
244
257
|
async function readTasks(path, holders, observeContract) {
|
|
@@ -247,7 +260,7 @@ async function readTasks(path, holders, observeContract) {
|
|
|
247
260
|
return observeRecentTaskStatus(path, { limit: 10 }).then((recent) => ({
|
|
248
261
|
kind: "present",
|
|
249
262
|
value: { root: path, hasMore: recent.hasMore, rows: joinTasks(recent.rows, holders, observeContract) },
|
|
250
|
-
}), (error) => ({ kind: "failed", failure:
|
|
263
|
+
}), (error) => ({ kind: "failed", failure: taskFailure(error) }));
|
|
251
264
|
}
|
|
252
265
|
async function joinAkuma(path, observeContract, dispatches, aliases) {
|
|
253
266
|
if (aliases.kind !== "present")
|
|
@@ -54,6 +54,7 @@ export type CallInput = Readonly<{
|
|
|
54
54
|
alias?: AkumaAlias;
|
|
55
55
|
allowed?: readonly AllowedAction[];
|
|
56
56
|
schema?: Schema<unknown>;
|
|
57
|
+
initiator?: string;
|
|
57
58
|
}>;
|
|
58
59
|
export type CallObservation = Readonly<{
|
|
59
60
|
kind: "detached";
|
|
@@ -89,6 +90,7 @@ export type BornCall = Readonly<{
|
|
|
89
90
|
schemaTell?: Readonly<{
|
|
90
91
|
body: string;
|
|
91
92
|
schema: Schema<unknown>;
|
|
93
|
+
initiator?: string;
|
|
92
94
|
}>;
|
|
93
95
|
}>;
|
|
94
96
|
export type ForkInput = Readonly<{
|
|
@@ -242,26 +242,29 @@ async function resolveAliasStage(path, alias, dispatch, akuma) {
|
|
|
242
242
|
return { kind: "failed", failure: integrationFailure(error) };
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
|
+
const CALL_INPUT_KEYS = [
|
|
246
|
+
"path",
|
|
247
|
+
"archetype",
|
|
248
|
+
"body",
|
|
249
|
+
"cwd",
|
|
250
|
+
"readonly",
|
|
251
|
+
"mode",
|
|
252
|
+
"timeoutMs",
|
|
253
|
+
"home",
|
|
254
|
+
"settings",
|
|
255
|
+
"contract",
|
|
256
|
+
"alias",
|
|
257
|
+
"allowed",
|
|
258
|
+
"schema",
|
|
259
|
+
"initiator",
|
|
260
|
+
];
|
|
245
261
|
async function prepareCall(input, context) {
|
|
246
262
|
const values = requireInput(input, "Keiyaku.call input");
|
|
247
|
-
onlyKeys(values,
|
|
248
|
-
"path",
|
|
249
|
-
"archetype",
|
|
250
|
-
"body",
|
|
251
|
-
"cwd",
|
|
252
|
-
"readonly",
|
|
253
|
-
"mode",
|
|
254
|
-
"timeoutMs",
|
|
255
|
-
"home",
|
|
256
|
-
"settings",
|
|
257
|
-
"contract",
|
|
258
|
-
"alias",
|
|
259
|
-
"allowed",
|
|
260
|
-
"schema",
|
|
261
|
-
], "Keiyaku.call input");
|
|
263
|
+
onlyKeys(values, CALL_INPUT_KEYS, "Keiyaku.call input");
|
|
262
264
|
const path = await World.prove(nonblank(values.path, "path"));
|
|
263
265
|
const archetype = nonblank(values.archetype, "archetype");
|
|
264
266
|
const body = text(values.body, "body");
|
|
267
|
+
const initiator = values.initiator === undefined ? undefined : text(values.initiator, "initiator");
|
|
265
268
|
const readonlyRequested = callReadonly(values.readonly, "readonly must be true").readonly;
|
|
266
269
|
const cwd = values.cwd === undefined ? undefined : nonblank(values.cwd, "cwd");
|
|
267
270
|
const mode = callMode(values.mode);
|
|
@@ -279,6 +282,7 @@ async function prepareCall(input, context) {
|
|
|
279
282
|
const call = {
|
|
280
283
|
archetype,
|
|
281
284
|
...(values.schema === undefined ? { body } : {}),
|
|
285
|
+
...(initiator === undefined ? {} : { initiator }),
|
|
282
286
|
...(readonlyRequested === undefined ? {} : { readonly: readonlyRequested }),
|
|
283
287
|
...(values.allowed === undefined ? {} : { allowed: values.allowed }),
|
|
284
288
|
...(values.schema === undefined ? {} : { schema: values.schema }),
|
|
@@ -305,7 +309,15 @@ async function prepareCall(input, context) {
|
|
|
305
309
|
timeoutMs,
|
|
306
310
|
dispatch,
|
|
307
311
|
alias: aliasStage,
|
|
308
|
-
...(values.schema === undefined
|
|
312
|
+
...(values.schema === undefined
|
|
313
|
+
? {}
|
|
314
|
+
: {
|
|
315
|
+
schemaTell: {
|
|
316
|
+
body,
|
|
317
|
+
schema: values.schema,
|
|
318
|
+
...(initiator === undefined ? {} : { initiator }),
|
|
319
|
+
},
|
|
320
|
+
}),
|
|
309
321
|
};
|
|
310
322
|
}
|
|
311
323
|
async function publishCall(born, execution) {
|
|
@@ -326,8 +338,12 @@ async function publishCall(born, execution) {
|
|
|
326
338
|
target: handle.id,
|
|
327
339
|
body: tell.body,
|
|
328
340
|
schema: tell.schema,
|
|
341
|
+
...(tell.initiator === undefined ? {} : { initiator: tell.initiator }),
|
|
329
342
|
})
|
|
330
|
-
: PublicAkuma.select(born.path, handle.id).tell(tell.body, {
|
|
343
|
+
: PublicAkuma.select(born.path, handle.id).tell(tell.body, {
|
|
344
|
+
schema: tell.schema,
|
|
345
|
+
...(tell.initiator === undefined ? {} : { initiator: tell.initiator }),
|
|
346
|
+
}));
|
|
331
347
|
if (born.mode === "detach")
|
|
332
348
|
void pending.catch(() => undefined);
|
|
333
349
|
else
|
|
@@ -2,16 +2,17 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { decodeContractDocument } from "../body/decode.js";
|
|
3
3
|
import { contractIdFromSegment } from "../core/facts/types.js";
|
|
4
4
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
5
|
-
import {
|
|
5
|
+
import { mintIdentitySegment } from "../identity/mint.js";
|
|
6
|
+
import { fitIdentityStemWords, normalizeIdentityStem } from "../identity/normalize.js";
|
|
6
7
|
import { bindOperation } from "../protocol/bind.js";
|
|
7
8
|
import { stateOperation } from "../protocol/operations.js";
|
|
8
9
|
import { claimTaskHolder, claimTaskHolderWithFence } from "../settlement/holder.js";
|
|
9
10
|
import { KeiyakuRefused } from "./refusal.js";
|
|
10
11
|
import { contractTerms, documentDerivation } from "./input.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return
|
|
12
|
+
const CONTRACT_ID_CODE_POINTS = 32;
|
|
13
|
+
const CONTRACT_ID_ATTEMPTS = 4;
|
|
14
|
+
function drawContractSuffix() {
|
|
15
|
+
return randomBytes(2).toString("hex");
|
|
15
16
|
}
|
|
16
17
|
async function attempt(input, id) {
|
|
17
18
|
return bindOperation({
|
|
@@ -33,16 +34,17 @@ async function attempt(input, id) {
|
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
async function attemptCandidates(input) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
const stem = fitIdentityStemWords({
|
|
38
|
+
stem: normalizeIdentityStem({ source: input.title }) || "contract",
|
|
39
|
+
maxCodePoints: CONTRACT_ID_CODE_POINTS,
|
|
40
|
+
});
|
|
41
|
+
return await mintIdentitySegment({
|
|
42
|
+
stem,
|
|
43
|
+
attempts: CONTRACT_ID_ATTEMPTS,
|
|
44
|
+
drawSuffix: drawContractSuffix,
|
|
45
|
+
attempt: (segment) => attempt(input, contractIdFromSegment(segment)),
|
|
46
|
+
collision: (result) => result.kind === "refused" && result.refusal.kind === "contract-exists",
|
|
47
|
+
});
|
|
46
48
|
}
|
|
47
49
|
export async function admitBindWithAppointment(input) {
|
|
48
50
|
return await attemptCandidates(input);
|
|
@@ -86,7 +88,7 @@ export async function admitForkBindWithAppointment(input) {
|
|
|
86
88
|
throw error;
|
|
87
89
|
}
|
|
88
90
|
const markdown = sourceDocument.document.bytes.replace(/^\s*#\s*[^\r\n]*(?:\r?\n|$)/u, `# Fork · ${sourceDocument.title}${sourceDocument.document.bytes.includes("\r\n") ? "\r\n" : "\n"}`);
|
|
89
|
-
const document = decodeContractDocument(markdown);
|
|
91
|
+
const document = decodeContractDocument(markdown, { requireTimeout: true });
|
|
90
92
|
const terms = contractTerms(document, source.terms.gates, source.terms.after);
|
|
91
93
|
const admission = await attemptCandidates({
|
|
92
94
|
scope: input.scope,
|
|
@@ -20,7 +20,9 @@ type BindInput = Readonly<{
|
|
|
20
20
|
type BindResult<Handle> = Readonly<Omit<MutationResult<Handle>, "value"> & {
|
|
21
21
|
keiyaku: Handle;
|
|
22
22
|
workspace?: ContractWorkspaceLocation;
|
|
23
|
-
} & RegionObservation
|
|
23
|
+
} & RegionObservation & {
|
|
24
|
+
warnings?: readonly string[];
|
|
25
|
+
}>;
|
|
24
26
|
type HandleFactory<Handle> = (contractId: ContractId, scope: RepositoryScope) => Handle;
|
|
25
27
|
export declare function bindKeiyaku<Handle>(input: BindInput, createHandle: HandleFactory<Handle>): Promise<BindResult<Handle>>;
|
|
26
28
|
export declare function parseMarkdownBindDocument(markdown: string): import("../body/types.js").DecodedContractDocument;
|
|
@@ -7,10 +7,11 @@ import { completionInput, completeHolderMutation, completeMutation } from "./mut
|
|
|
7
7
|
import { reconcileLagScope } from "./reconcile.js";
|
|
8
8
|
import { requireAccepted } from "./refusal.js";
|
|
9
9
|
import { observeRegion } from "./region.js";
|
|
10
|
+
import { regionWarnings } from "../body/region.js";
|
|
10
11
|
import { scopeForRepo } from "./repo.js";
|
|
11
12
|
import { worktreeHooksOption } from "./configuration.js";
|
|
12
13
|
import { placeRegisterPath, readManagedWorktreeAppointment, } from "../workspace-place.js";
|
|
13
|
-
async function acceptedBindResult(result, region, scope, contractId) {
|
|
14
|
+
async function acceptedBindResult(result, region, scope, contractId, warnings = []) {
|
|
14
15
|
const { value: keiyaku, ...base } = result;
|
|
15
16
|
const appointment = await readManagedWorktreeAppointment(scope, contractId);
|
|
16
17
|
const registerPath = placeRegisterPath(scope);
|
|
@@ -34,6 +35,7 @@ async function acceptedBindResult(result, region, scope, contractId) {
|
|
|
34
35
|
pending: scopedAppointmentLag.length === 0
|
|
35
36
|
? base.pending
|
|
36
37
|
: [...base.pending, { surface: "reconciliation", required: true }],
|
|
38
|
+
...(warnings.length === 0 ? {} : { warnings }),
|
|
37
39
|
...region,
|
|
38
40
|
};
|
|
39
41
|
}
|
|
@@ -85,7 +87,7 @@ export async function bindKeiyaku(input, createHandle) {
|
|
|
85
87
|
return bindMarkdownFromValues(values, "targetless", createHandle);
|
|
86
88
|
}
|
|
87
89
|
export function parseMarkdownBindDocument(markdown) {
|
|
88
|
-
return decodeContractDocument(requireMarkdown(markdown));
|
|
90
|
+
return decodeContractDocument(requireMarkdown(markdown), { requireTimeout: true });
|
|
89
91
|
}
|
|
90
92
|
/** Internal CLI composition; not exported from the package root. */
|
|
91
93
|
export async function bindFromCli(input, createHandle) {
|
|
@@ -133,6 +135,6 @@ async function bindMarkdownFromValues(values, omittedTarget, createHandle) {
|
|
|
133
135
|
admission: admission.admission,
|
|
134
136
|
requireAccepted,
|
|
135
137
|
});
|
|
136
|
-
return await acceptedBindResult(result, await observeRegion(scope, channel, id, document.region), scope, id);
|
|
138
|
+
return await acceptedBindResult(result, await observeRegion(scope, channel, id, document.region), scope, id, regionWarnings(document.region));
|
|
137
139
|
});
|
|
138
140
|
}
|
|
@@ -91,7 +91,7 @@ declare const materializedHandoffReferenceSchema: z.ZodObject<{
|
|
|
91
91
|
handoffBase: z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/facts/types.js").SnapshotId, string>>;
|
|
92
92
|
recovery: z.ZodObject<{
|
|
93
93
|
materialize: z.ZodLiteral<"deliver --materialize-conflict --include-dirty">;
|
|
94
|
-
|
|
94
|
+
deliver: z.ZodLiteral<"deliver --include-dirty">;
|
|
95
95
|
staging: z.ZodLiteral<"not-required">;
|
|
96
96
|
}, z.core.$strict>;
|
|
97
97
|
conflictPaths: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<readonly string[], string[]>>;
|
|
@@ -216,7 +216,7 @@ declare const contractServiceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
216
216
|
handoffBase: z.ZodPipe<z.ZodString, z.ZodTransform<import("../core/facts/types.js").SnapshotId, string>>;
|
|
217
217
|
recovery: z.ZodObject<{
|
|
218
218
|
materialize: z.ZodLiteral<"deliver --materialize-conflict --include-dirty">;
|
|
219
|
-
|
|
219
|
+
deliver: z.ZodLiteral<"deliver --include-dirty">;
|
|
220
220
|
staging: z.ZodLiteral<"not-required">;
|
|
221
221
|
}, z.core.$strict>;
|
|
222
222
|
conflictPaths: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<readonly string[], string[]>>;
|
|
@@ -31,7 +31,7 @@ const contractRequestBaseSchema = z.object({ repoRoot: absolutePathSchema, contr
|
|
|
31
31
|
const conflictRecoverySchema = z
|
|
32
32
|
.object({
|
|
33
33
|
materialize: z.literal("deliver --materialize-conflict --include-dirty"),
|
|
34
|
-
|
|
34
|
+
deliver: z.literal("deliver --include-dirty"),
|
|
35
35
|
staging: z.literal("not-required"),
|
|
36
36
|
})
|
|
37
37
|
.strict();
|
|
@@ -13,6 +13,7 @@ import type { ContractWorkspaceLocation } from "../workspace-place.js";
|
|
|
13
13
|
export type BindResult = Readonly<Omit<MutationResult<Keiyaku>, "value"> & {
|
|
14
14
|
keiyaku: Keiyaku;
|
|
15
15
|
workspace?: ContractWorkspaceLocation;
|
|
16
|
+
warnings?: readonly string[];
|
|
16
17
|
} & RegionObservation>;
|
|
17
18
|
export type Fact = JournalEntry;
|
|
18
19
|
export type ContractHistoryEvent = Readonly<{
|