@astrosheep/keiyaku 4.6.19 → 4.6.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 +7 -3
- package/build/plugins/pi/README.md +111 -0
- package/build/plugins/pi/akuma-tools.ts +310 -0
- package/build/plugins/pi/keiyaku.ts +2 -0
- package/build/src/akuma/akuma-call.d.ts +4 -1
- package/build/src/akuma/akuma-call.js +24 -7
- package/build/src/akuma/akuma-instance.d.ts +28 -8
- package/build/src/akuma/akuma-instance.js +85 -42
- package/build/src/akuma/akuma-owner.d.ts +18 -9
- package/build/src/akuma/akuma-owner.js +31 -25
- package/build/src/akuma/akuma-selection-execution.d.ts +4 -1
- package/build/src/akuma/akuma-selection-execution.js +8 -4
- package/build/src/akuma/akuma.d.ts +17 -0
- package/build/src/akuma/body-launch.d.ts +107 -0
- package/build/src/akuma/body-launch.js +57 -0
- package/build/src/akuma/body-supervisor.d.ts +7 -6
- package/build/src/akuma/body-supervisor.js +17 -12
- package/build/src/akuma/body.d.ts +13 -94
- package/build/src/akuma/body.js +124 -296
- package/build/src/akuma/call-input.d.ts +2 -0
- package/build/src/akuma/call-input.js +21 -1
- package/build/src/akuma/call-request.d.ts +6 -2
- package/build/src/akuma/call-request.js +9 -1
- package/build/src/akuma/detached-body.d.ts +9 -0
- package/build/src/akuma/detached-body.js +94 -0
- package/build/src/akuma/execution-instructions.d.ts +8 -0
- package/build/src/akuma/execution-instructions.js +17 -0
- package/build/src/akuma/heart/facts.d.ts +21 -1
- package/build/src/akuma/heart/facts.js +10 -0
- package/build/src/akuma/heart/index.d.ts +16 -1
- package/build/src/akuma/heart/index.js +95 -30
- package/build/src/akuma/heart/rows.d.ts +14 -2
- package/build/src/akuma/heart/rows.js +48 -4
- package/build/src/akuma/heart/schema.d.ts +4 -1
- package/build/src/akuma/heart/schema.js +87 -30
- package/build/src/akuma/heart/soul.js +4 -0
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +59 -15
- package/build/src/akuma/heart/timeline.d.ts +6 -4
- package/build/src/akuma/heart/timeline.js +14 -4
- package/build/src/akuma/in-process-body.d.ts +5 -0
- package/build/src/akuma/in-process-body.js +57 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/projection.d.ts +44 -1
- package/build/src/akuma/projection.js +13 -1
- package/build/src/akuma/provider.d.ts +4 -0
- package/build/src/akuma/providers/acp/core.js +1 -1
- package/build/src/akuma/providers/acp/index.js +3 -0
- package/build/src/akuma/providers/claude/index.js +8 -5
- package/build/src/akuma/providers/codex-app-server/configuration.d.ts +5 -0
- package/build/src/akuma/providers/codex-app-server/configuration.js +72 -0
- package/build/src/akuma/providers/codex-app-server/index.js +7 -10
- package/build/src/akuma/providers/execution-environment.d.ts +8 -2
- package/build/src/akuma/providers/execution-environment.js +10 -1
- package/build/src/akuma/providers/grok-build/index.js +23 -16
- package/build/src/akuma/providers/index.d.ts +1 -0
- package/build/src/akuma/providers/index.js +8 -0
- package/build/src/akuma/providers/opencode-sdk/index.js +9 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +6 -0
- package/build/src/akuma/providers/opencode-sdk/session.js +4 -3
- package/build/src/akuma/providers/paseo/index.js +8 -2
- package/build/src/akuma/providers/pi/index.js +27 -10
- package/build/src/akuma/publication.d.ts +4 -3
- package/build/src/akuma/publication.js +21 -18
- package/build/src/akuma/selection-observation.d.ts +51 -0
- package/build/src/akuma/selection-owner-port.d.ts +2 -1
- package/build/src/akuma/selection-owner-port.js +4 -3
- package/build/src/akuma/turn-drive.d.ts +4 -2
- package/build/src/akuma/turn-drive.js +58 -21
- package/build/src/akuma-body.d.ts +0 -10
- package/build/src/akuma-body.js +13 -118
- package/build/src/body-host.d.ts +28 -0
- package/build/src/body-host.js +86 -0
- package/build/src/body-requests.d.ts +13 -0
- package/build/src/body-requests.js +131 -0
- package/build/src/cli/commands/akuma-grammar.d.ts +8 -1
- package/build/src/cli/commands/akuma-grammar.js +36 -6
- package/build/src/cli/commands/akuma.js +11 -0
- package/build/src/cli/commands/report.d.ts +6 -0
- package/build/src/cli/commands/report.js +31 -0
- package/build/src/cli/parse.js +1 -0
- package/build/src/cli/render/akuma-activity.js +27 -17
- package/build/src/cli/render/terminal.d.ts +5 -0
- package/build/src/cli/render/terminal.js +7 -0
- package/build/src/cli/runtime.js +4 -1
- package/build/src/index.d.ts +3 -1
- package/build/src/index.js +1 -0
- package/build/src/library/akuma-creation.d.ts +7 -3
- package/build/src/library/akuma-creation.js +23 -11
- package/build/src/library/akumas.d.ts +4 -1
- package/build/src/library/akumas.js +13 -5
- package/build/src/library/selection.d.ts +2 -1
- package/build/src/library/selection.js +6 -3
- package/build/src/plugin/public.d.ts +11 -0
- package/build/src/plugin/runtime.js +1 -0
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +3 -3
- package/plugins/paseo/plugin/server/keiyaku.ts +1 -0
- package/plugins/paseo/plugin/server/mirror.ts +2 -2
- package/plugins/pi/README.md +111 -0
- package/plugins/pi/akuma-tools.ts +310 -0
- package/plugins/pi/keiyaku.ts +2 -0
|
@@ -2,7 +2,7 @@ import { defaultWaitComplete } from "../../akuma/akuma-observe.js";
|
|
|
2
2
|
import { renderDiffstat, toolContent, toolRepr } from "./akuma-tool.js";
|
|
3
3
|
import { dispositionText } from "./debt.js";
|
|
4
4
|
import { debtDispositionMark } from "./marks.js";
|
|
5
|
-
import { DEFAULT_CLI_COLUMNS, displayColumns, padToDisplay, renderBoundedPayload, renderBoundedTextBlock, safeText, takeDisplayColumns, takeDisplayColumnsFromEnd, truncateDisplayText, truncateMiddleDisplayText, } from "./terminal.js";
|
|
5
|
+
import { DEFAULT_CLI_COLUMNS, diagnosticLines, displayColumns, padToDisplay, renderBoundedPayload, renderBoundedTextBlock, safeText, takeDisplayColumns, takeDisplayColumnsFromEnd, truncateDisplayText, truncateMiddleDisplayText, } from "./terminal.js";
|
|
6
6
|
export const DEFAULT_CONTEXT = { columns: DEFAULT_CLI_COLUMNS, color: false };
|
|
7
7
|
/** The action family's fixed 3-cell state margin and minimum verb cell. */
|
|
8
8
|
const ACTION_MARGIN = " ";
|
|
@@ -64,8 +64,8 @@ export function panelHead(id, alias, contract, context = []) {
|
|
|
64
64
|
export function actionReceipt(input) {
|
|
65
65
|
return [`${input.mark} ${input.verb} ${identity(input.id, input.alias)}`, ...subordinateLines(input.evidence ?? [])];
|
|
66
66
|
}
|
|
67
|
-
function contractFacts(contract) {
|
|
68
|
-
return contract.kind === "failed" ?
|
|
67
|
+
function contractFacts(contract, columns) {
|
|
68
|
+
return contract.kind === "failed" ? diagnosticLines("contract association", contract.diagnostic, columns) : [];
|
|
69
69
|
}
|
|
70
70
|
/** The action family's one mark cell: a settled success stays blank, and live is only a frame mark. */
|
|
71
71
|
function toolMargin(row, live) {
|
|
@@ -76,7 +76,8 @@ function toolMargin(row, live) {
|
|
|
76
76
|
return row.state.status === "ok" ? ACTION_MARGIN : "! ";
|
|
77
77
|
}
|
|
78
78
|
function rowText(row, tool) {
|
|
79
|
-
if (row.kind === "
|
|
79
|
+
if (row.kind === "report" ||
|
|
80
|
+
row.kind === "said" ||
|
|
80
81
|
row.kind === "thought" ||
|
|
81
82
|
row.kind === "note" ||
|
|
82
83
|
row.kind === "call" ||
|
|
@@ -89,7 +90,7 @@ function rowText(row, tool) {
|
|
|
89
90
|
if (row.kind === "outcome")
|
|
90
91
|
return row.outcome.kind === "answered"
|
|
91
92
|
? { text: row.outcome.answer, lines: 3 }
|
|
92
|
-
: { text: row.outcome.diagnostic, lines: 2 };
|
|
93
|
+
: { text: row.outcome.kind === "canceled" ? "canceled" : row.outcome.diagnostic, lines: 2 };
|
|
93
94
|
if (row.kind === "turn")
|
|
94
95
|
return { text: "", lines: 1 };
|
|
95
96
|
if (row.kind !== "tool")
|
|
@@ -118,10 +119,15 @@ function rowPrefix(row, tool, columns, view) {
|
|
|
118
119
|
return actionPrefix(toolMargin(row, view.live === true), tool.label, columns);
|
|
119
120
|
if (row.kind === "thought")
|
|
120
121
|
return actionPrefix(ACTION_MARGIN, "think", columns);
|
|
122
|
+
if (row.kind === "report")
|
|
123
|
+
return actionPrefix(ACTION_MARGIN, "report", columns);
|
|
121
124
|
if (row.kind === "note")
|
|
122
125
|
return actionPrefix(ACTION_MARGIN, "note", columns);
|
|
123
126
|
if (row.kind === "outcome")
|
|
124
|
-
return {
|
|
127
|
+
return {
|
|
128
|
+
first: row.outcome.kind === "answered" ? TOP_ANSWER : row.outcome.kind === "canceled" ? "○ " : TOP_FAILURE,
|
|
129
|
+
continuation: TOP_CONTINUATION,
|
|
130
|
+
};
|
|
125
131
|
if (row.kind === "said")
|
|
126
132
|
return { first: TOP_SPEAK, continuation: TOP_SPEAK };
|
|
127
133
|
if (row.kind === "tell" && row.state === "pending")
|
|
@@ -724,7 +730,7 @@ function renderDebtContextLines(created, columns) {
|
|
|
724
730
|
if (created === undefined)
|
|
725
731
|
return [];
|
|
726
732
|
if (created.kind === "failed")
|
|
727
|
-
return
|
|
733
|
+
return diagnosticLines("created debts", created.diagnostic, columns);
|
|
728
734
|
if (created.rows.length === 0)
|
|
729
735
|
return [];
|
|
730
736
|
return [`debts ${created.rows.length}`, ...created.rows.flatMap((row) => renderDebtRow(row, columns))];
|
|
@@ -736,7 +742,10 @@ function snapshotCore(view, context, options) {
|
|
|
736
742
|
...(options.showAllowed === true ? [`allowed ${view.status.allowed.join(", ") || "none"}`] : []),
|
|
737
743
|
...(view.status.cwd === undefined ? [] : [safeText(view.status.cwd)]),
|
|
738
744
|
];
|
|
739
|
-
const facts = [
|
|
745
|
+
const facts = [
|
|
746
|
+
...contractFacts(view.contract, context.columns - SUBORDINATE_INDENT.length),
|
|
747
|
+
...(options.facts ?? []),
|
|
748
|
+
];
|
|
740
749
|
return {
|
|
741
750
|
activity,
|
|
742
751
|
head: panelHead(view.status.id, options.alias, view.contract, contextFacts),
|
|
@@ -803,7 +812,7 @@ export function historyRawAnswer(result, historyId) {
|
|
|
803
812
|
if (historyId === undefined || result.kind !== "exact")
|
|
804
813
|
return undefined;
|
|
805
814
|
const outcome = result.outcome.outcome;
|
|
806
|
-
return outcome.kind === "answered" ? outcome.answer : outcome.diagnostic;
|
|
815
|
+
return outcome.kind === "answered" ? outcome.answer : outcome.kind === "canceled" ? "canceled" : outcome.diagnostic;
|
|
807
816
|
}
|
|
808
817
|
/** One compact wait result line: an observed life mark, the complete identity, a bounded summary. */
|
|
809
818
|
const WAIT_SUMMARY_SEPARATOR = " — ";
|
|
@@ -844,7 +853,9 @@ function waitSummary(status) {
|
|
|
844
853
|
? { mark: "✓", state: "completed" }
|
|
845
854
|
: outcome.kind === "answered"
|
|
846
855
|
? { mark: "✓", state: preview(outcome.answer, "answered") }
|
|
847
|
-
:
|
|
856
|
+
: outcome.kind === "canceled"
|
|
857
|
+
? { mark: "○", state: "canceled" }
|
|
858
|
+
: { mark: "!", state: preview(outcome.diagnostic, "failed") });
|
|
848
859
|
return {
|
|
849
860
|
...observed,
|
|
850
861
|
summary: [
|
|
@@ -875,7 +886,9 @@ export function historyText(result, presentation, context) {
|
|
|
875
886
|
return `${result.kind === "unknown-history" ? result.historyId : "unknown"} has no matching retained outcome`;
|
|
876
887
|
return result.outcome.outcome.kind === "answered"
|
|
877
888
|
? result.outcome.outcome.answer
|
|
878
|
-
: result.outcome.outcome.
|
|
889
|
+
: result.outcome.outcome.kind === "canceled"
|
|
890
|
+
? "canceled"
|
|
891
|
+
: result.outcome.outcome.diagnostic;
|
|
879
892
|
}
|
|
880
893
|
if (presentation.last === true)
|
|
881
894
|
return result.kind === "last" ? result.answer : "no answer retained";
|
|
@@ -945,14 +958,11 @@ export function tellText(result, alias, context) {
|
|
|
945
958
|
if (wake.kind !== "failed")
|
|
946
959
|
return verdict;
|
|
947
960
|
const child = "child" in wake ? wake.child : undefined;
|
|
948
|
-
const failure = `! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
|
|
949
961
|
return [
|
|
950
962
|
verdict,
|
|
951
|
-
...subordinateLines(
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
columns: context.columns - SUBORDINATE_INDENT.length,
|
|
955
|
-
lines: Number.MAX_SAFE_INTEGER,
|
|
963
|
+
...subordinateLines(diagnosticLines("tell delivery", wake.diagnostic, context.columns - SUBORDINATE_INDENT.length, {
|
|
964
|
+
state: "failed",
|
|
965
|
+
suffix: child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`,
|
|
956
966
|
})),
|
|
957
967
|
].join("\n");
|
|
958
968
|
}
|
|
@@ -31,6 +31,11 @@ export declare function renderBoundedTextBlock(value: string, input: Readonly<{
|
|
|
31
31
|
lines?: number;
|
|
32
32
|
truncated?: boolean;
|
|
33
33
|
}>): readonly string[];
|
|
34
|
+
/** A tool diagnostic names its subject first; only its bounded payload carries the cause. */
|
|
35
|
+
export declare function diagnosticLines(subject: string, cause: string, columns: number, options?: Readonly<{
|
|
36
|
+
state?: "unavailable" | "failed";
|
|
37
|
+
suffix?: string;
|
|
38
|
+
}>): readonly string[];
|
|
34
39
|
type BoundedPayload = Readonly<{
|
|
35
40
|
text: string;
|
|
36
41
|
first: string;
|
|
@@ -168,6 +168,13 @@ export function renderBoundedTextBlock(value, input) {
|
|
|
168
168
|
}
|
|
169
169
|
return lines.length === 0 ? [input.first.trimEnd()] : lines;
|
|
170
170
|
}
|
|
171
|
+
/** A tool diagnostic names its subject first; only its bounded payload carries the cause. */
|
|
172
|
+
export function diagnosticLines(subject, cause, columns, options = {}) {
|
|
173
|
+
return [
|
|
174
|
+
`! ${safeText(subject)} ${options.state ?? "unavailable"}${safeText(options.suffix ?? "")}`,
|
|
175
|
+
...renderBoundedTextBlock(cause, { first: " ", continuation: " ", columns }),
|
|
176
|
+
];
|
|
177
|
+
}
|
|
171
178
|
export function renderBoundedPayload(input) {
|
|
172
179
|
return input.preserveLines === true ? renderPreservedPayload(input) : renderFoldedPayload(input);
|
|
173
180
|
}
|
package/build/src/cli/runtime.js
CHANGED
|
@@ -7,6 +7,7 @@ import { isParsedAkumaCommand, runAkumaCommand } from "./commands/akuma.js";
|
|
|
7
7
|
import { admitBindMarkdown, runContractCommand, runContractHistoryCommand } from "./commands/contract.js";
|
|
8
8
|
import { installOutcome, installHarnesses, renderInstallText } from "./commands/install.js";
|
|
9
9
|
import { runDebtCommand } from "./commands/debt.js";
|
|
10
|
+
import { runReport } from "./commands/report.js";
|
|
10
11
|
import { runWhoami } from "./commands/whoami.js";
|
|
11
12
|
import { resolveInvocationCoordinates } from "./coordinates.js";
|
|
12
13
|
import { BindDraftError } from "./draft.js";
|
|
@@ -167,7 +168,7 @@ async function runCommand(invocation, input) {
|
|
|
167
168
|
try {
|
|
168
169
|
const runtime = {
|
|
169
170
|
environment,
|
|
170
|
-
execution: command.command
|
|
171
|
+
execution: ["whoami", "report"].includes(command.command)
|
|
171
172
|
? localExecutionContext()
|
|
172
173
|
: await executionForEnvironment(environment, cancellation.signal),
|
|
173
174
|
...(home === undefined ? {} : { home }),
|
|
@@ -187,6 +188,8 @@ async function runCommand(invocation, input) {
|
|
|
187
188
|
...(invocation.cwd === undefined ? {} : { cwd: invocation.cwd }),
|
|
188
189
|
});
|
|
189
190
|
}
|
|
191
|
+
if (command.command === "report")
|
|
192
|
+
return await runReport(command, runtime);
|
|
190
193
|
const coordinates = await invocationCoordinates(invocation, input, environment);
|
|
191
194
|
if (command.command === "whoami")
|
|
192
195
|
return await runWhoami(command, coordinates, environment);
|
package/build/src/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* Settings, and Plugin surfaces. Internal composition, execution, and
|
|
9
9
|
* configuration helpers stay off this entry; only CLI and Body import them.
|
|
10
10
|
*/
|
|
11
|
+
export { AkumaHost } from "./body-host.js";
|
|
12
|
+
export type { AkumaHostScope } from "./body-host.js";
|
|
11
13
|
export { AuthorityCorruptionError } from "./core/facts/errors.js";
|
|
12
14
|
/**
|
|
13
15
|
* The package root: the curated Contract, Akuma, Akumas, Debt, Kanshi, World,
|
|
@@ -46,7 +48,7 @@ export { actorId } from "./core/facts/types.js";
|
|
|
46
48
|
*/
|
|
47
49
|
export { z } from "zod";
|
|
48
50
|
export { ALLOWED_ACTIONS, Akuma, AkumaArchetypeError, AkumaBusyError, AkumaDecodeError, AkumaNotBornError, AkumaProviderError, Schema, listArchetypeDefinitions, } from "./akuma/index.js";
|
|
49
|
-
export type { AkumaCaller, AkumaOrigin, ActivityHistory, ActivityRow, AkuId, AkumaAskObservation, AkumaAskOptions, AkumaAskResult, AkumaBirthInput, AkumaHistoryOptions, AkumaHostOptions, AkumaIdleOptions, AkumaIdleResult, AkumaSignalOptions, AkumaStatus, AkumaStreamSnapshot, AkumaTellOptions, AkumaTellResult, AllowedAction, AllowedActions, ArchetypeCatalog, ArchetypeCatalogInput, ArchetypeCatalogRow, InterruptReceipt, JsonSchema, JsonSchemaDocument, KillEvidence, SchemaLike, StandardSchemaV1, } from "./akuma/index.js";
|
|
51
|
+
export type { AkumaCaller, AkumaOrigin, ActivityHistory, ActivityRow, AkuId, AkumaAskObservation, AkumaAskOptions, AkumaAskResult, AkumaBirthInput, AkumaHistoryOptions, AkumaHostOptions, AkumaIdleOptions, AkumaIdleResult, AkumaReportOptions, AkumaReportResult, AkumaSignalOptions, AkumaStatus, AkumaStreamSnapshot, AkumaTellOptions, AkumaTellResult, AllowedAction, AllowedActions, ArchetypeCatalog, ArchetypeCatalogInput, ArchetypeCatalogRow, InterruptReceipt, JsonSchema, JsonSchemaDocument, KillEvidence, SchemaLike, StandardSchemaV1, } from "./akuma/index.js";
|
|
50
52
|
export type { ActorId, ChangeId, ContractHead, ContractId, ContractState, JournalEntry as Fact, FactKind, SnapshotId, } from "./core/facts/types.js";
|
|
51
53
|
export { kanshi, kanshiCategory, observeKanshi, selectKanshi, selectRegion } from "./kanshi/index.js";
|
|
52
54
|
export type { AkumaKanshiRow, AkumaKanshiWorld, ContractEndpointObservation, ContractHolderObservation, ContractKanshiBoard, ContractKanshiRow, KanshiCategoryInput, KanshiCategoryReport, KanshiInput, KanshiRegionSelection, KanshiReport, KanshiSelection, RegionDeclaration, RegionRead, Section, DebtKanshiRow, DebtKanshiWorld, } from "./kanshi/index.js";
|
package/build/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Settings, and Plugin surfaces. Internal composition, execution, and
|
|
9
9
|
* configuration helpers stay off this entry; only CLI and Body import them.
|
|
10
10
|
*/
|
|
11
|
+
export { AkumaHost } from "./body-host.js";
|
|
11
12
|
export { AuthorityCorruptionError } from "./core/facts/errors.js";
|
|
12
13
|
/**
|
|
13
14
|
* The package root: the curated Contract, Akuma, Akumas, Debt, Kanshi, World,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type AkumaCaller } from "../akuma/caller.js";
|
|
2
2
|
import { type ForkReceipt } from "../akuma/akuma-owner.js";
|
|
3
|
+
import type { BodyLauncher } from "../akuma/body-launch.js";
|
|
3
4
|
import { type AskObserver } from "../akuma/akuma-selection-execution.js";
|
|
4
5
|
import type { AkumaStatus } from "../akuma/akuma.js";
|
|
5
6
|
import type { AllowedAction } from "../akuma/allowed.js";
|
|
6
7
|
import type { TellResult } from "../akuma/body.js";
|
|
7
8
|
import { type AkuId } from "../akuma/identity.js";
|
|
8
|
-
import {
|
|
9
|
+
import type { ExecutionContext } from "../akuma/requests.js";
|
|
9
10
|
import { type Schema } from "../akuma/schema.js";
|
|
10
11
|
import type { AkumaAskResult } from "../akuma/selection-observation.js";
|
|
11
12
|
import { type AliasBinding } from "../alias/index.js";
|
|
@@ -62,6 +63,8 @@ export type CallInput = Readonly<{
|
|
|
62
63
|
contract?: Keiyaku;
|
|
63
64
|
alias?: AkumaAlias;
|
|
64
65
|
allowed?: readonly AllowedAction[];
|
|
66
|
+
writableDirectories?: readonly string[];
|
|
67
|
+
bare?: boolean;
|
|
65
68
|
schema?: Schema<unknown>;
|
|
66
69
|
initiator?: string;
|
|
67
70
|
caller?: AkumaCaller;
|
|
@@ -99,6 +102,7 @@ export type CallResult = Readonly<{
|
|
|
99
102
|
export type ForkInput = Readonly<{
|
|
100
103
|
akuma: string;
|
|
101
104
|
at: string;
|
|
105
|
+
bare?: boolean;
|
|
102
106
|
repo?: Repo;
|
|
103
107
|
caller?: AkumaCaller;
|
|
104
108
|
initiator?: string;
|
|
@@ -116,8 +120,8 @@ export type ForkResult = Readonly<{
|
|
|
116
120
|
}>);
|
|
117
121
|
export declare function callAkumas(input: CallInput & Readonly<{
|
|
118
122
|
path: WorldRoot;
|
|
119
|
-
}>, execution
|
|
123
|
+
}>, execution: ExecutionContext, spawn: BodyLauncher, reportDiagnostic?: (message: string) => void): Promise<CallResult>;
|
|
120
124
|
export declare function forkAkumas(input: ForkInput & Readonly<{
|
|
121
125
|
path: WorldRoot;
|
|
122
|
-
}
|
|
126
|
+
}>, spawn: BodyLauncher): Promise<ForkResult>;
|
|
123
127
|
export {};
|
|
@@ -5,9 +5,8 @@ import { decodeAkumaCaller } from "../akuma/caller.js";
|
|
|
5
5
|
import { admitAkumaCall } from "../akuma/akuma-call.js";
|
|
6
6
|
import { AkumaOwner } from "../akuma/akuma-owner.js";
|
|
7
7
|
import { decodeAskObservation, observeAdmittedAskAkuma } from "../akuma/akuma-selection-execution.js";
|
|
8
|
-
import { canonicalBirthCwd } from "../akuma/call-input.js";
|
|
8
|
+
import { bareOption, canonicalBirthCwd } from "../akuma/call-input.js";
|
|
9
9
|
import { pathsForAkuId } from "../akuma/identity.js";
|
|
10
|
-
import { localExecutionContext } from "../akuma/requests.js";
|
|
11
10
|
import { schemaJsonText } from "../akuma/schema.js";
|
|
12
11
|
import { moveAlias } from "../alias/index.js";
|
|
13
12
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
@@ -180,6 +179,8 @@ const CALL_INPUT_KEYS = [
|
|
|
180
179
|
"contract",
|
|
181
180
|
"alias",
|
|
182
181
|
"allowed",
|
|
182
|
+
"writableDirectories",
|
|
183
|
+
"bare",
|
|
183
184
|
"schema",
|
|
184
185
|
"initiator",
|
|
185
186
|
"caller",
|
|
@@ -194,6 +195,7 @@ async function parseCallInput(input) {
|
|
|
194
195
|
const body = callBody(values.body);
|
|
195
196
|
const initiator = values.initiator === undefined ? undefined : text(values.initiator, "initiator");
|
|
196
197
|
const caller = decodeAkumaCaller(values.caller);
|
|
198
|
+
const bare = bareOption(values.bare);
|
|
197
199
|
const cwd = values.cwd === undefined ? undefined : nonblank(values.cwd, "cwd");
|
|
198
200
|
const mode = callMode(values.mode);
|
|
199
201
|
validateCallBodyOptions(body, values, mode);
|
|
@@ -211,8 +213,7 @@ async function parseCallInput(input) {
|
|
|
211
213
|
: {
|
|
212
214
|
tellId: randomUUID(),
|
|
213
215
|
body,
|
|
214
|
-
...(
|
|
215
|
-
...(schema === undefined ? {} : { schema }),
|
|
216
|
+
...(schema === undefined ? {} : { schema, schemaJson: schemaJson }),
|
|
216
217
|
...(initiator === undefined ? {} : { initiator }),
|
|
217
218
|
};
|
|
218
219
|
return {
|
|
@@ -226,6 +227,10 @@ async function parseCallInput(input) {
|
|
|
226
227
|
...(settings === undefined ? {} : { settings }),
|
|
227
228
|
...(alias === undefined ? {} : { alias }),
|
|
228
229
|
...(values.allowed === undefined ? {} : { allowed: values.allowed }),
|
|
230
|
+
...(values.writableDirectories === undefined
|
|
231
|
+
? {}
|
|
232
|
+
: { writableDirectories: values.writableDirectories }),
|
|
233
|
+
...(bare === undefined ? {} : { bare }),
|
|
229
234
|
seat,
|
|
230
235
|
...(caller === undefined ? {} : { caller }),
|
|
231
236
|
...(initiator === undefined ? {} : { initiator }),
|
|
@@ -256,6 +261,8 @@ function callAdmissionInput(input, execution) {
|
|
|
256
261
|
},
|
|
257
262
|
}),
|
|
258
263
|
...(input.allowed === undefined ? {} : { allowed: input.allowed }),
|
|
264
|
+
...(input.writableDirectories === undefined ? {} : { writableDirectories: input.writableDirectories }),
|
|
265
|
+
...(input.bare === undefined ? {} : { bare: input.bare }),
|
|
259
266
|
...(execution === undefined ? {} : { cwd: execution.cwd }),
|
|
260
267
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
261
268
|
};
|
|
@@ -320,13 +327,16 @@ async function observeCall(input, reportDiagnostic) {
|
|
|
320
327
|
}
|
|
321
328
|
catch (error) {
|
|
322
329
|
if (input.signal?.aborted)
|
|
323
|
-
throw error;
|
|
330
|
+
throw knownChildFailure(error, input.akuma);
|
|
324
331
|
return failedCall(input.result, input.initialTell.tellId, error, input.receipt);
|
|
325
332
|
}
|
|
326
333
|
}
|
|
327
334
|
/** One failure that still names the child the invocation durably admitted. */
|
|
328
335
|
function knownChildFailure(reason, akuma) {
|
|
329
|
-
const
|
|
336
|
+
const cause = reason instanceof Error ? reason : new Error(reason === undefined ? "call aborted" : String(reason));
|
|
337
|
+
// One AbortSignal may cancel several parallel calls. Never overwrite another
|
|
338
|
+
// invocation's leading birth on its shared reason object.
|
|
339
|
+
const error = Object.isExtensible(cause) && !Object.hasOwn(cause, "akuma") ? cause : new Error(cause.message, { cause });
|
|
330
340
|
Object.defineProperty(error, "akuma", { value: akuma, enumerable: false });
|
|
331
341
|
return error;
|
|
332
342
|
}
|
|
@@ -334,14 +344,14 @@ function knownChildFailure(reason, akuma) {
|
|
|
334
344
|
function asError(failure) {
|
|
335
345
|
return failure instanceof Error ? failure : new Error(failure === undefined ? "call failed" : String(failure));
|
|
336
346
|
}
|
|
337
|
-
export async function callAkumas(input, execution
|
|
347
|
+
export async function callAkumas(input, execution, spawn, reportDiagnostic) {
|
|
338
348
|
const parsed = await parseCallInput(input);
|
|
339
349
|
const selectedExecution = await resolveCallExecution(parsed.cwd === undefined ? {} : { cwd: parsed.cwd });
|
|
340
350
|
const seat = parsed.seat;
|
|
341
351
|
const admitted = await admitAkumaCall(parsed.path, callConfiguration(parsed, execution), {
|
|
342
352
|
...callAdmissionInput(parsed, selectedExecution),
|
|
343
353
|
...(seat === undefined ? {} : { contractId: seat.id }),
|
|
344
|
-
}, selectedExecution === undefined ? {} : { cwdCanonical: true });
|
|
354
|
+
}, selectedExecution === undefined ? {} : { cwdCanonical: true }, spawn);
|
|
345
355
|
const dispatch = seat === undefined
|
|
346
356
|
? { kind: "none" }
|
|
347
357
|
: await dispatchStage({ repository: seat.scope, akuId: admitted.id, contractId: seat.id });
|
|
@@ -380,9 +390,10 @@ export async function callAkumas(input, execution = localExecutionContext(), rep
|
|
|
380
390
|
...(parsed.observe === undefined ? {} : { observe: parsed.observe }),
|
|
381
391
|
}, reportDiagnostic);
|
|
382
392
|
}
|
|
383
|
-
export async function forkAkumas(input) {
|
|
393
|
+
export async function forkAkumas(input, spawn) {
|
|
384
394
|
const values = requireInput(input, "Akumas.fork input");
|
|
385
|
-
onlyKeys(values, ["path", "akuma", "at", "repo", "caller", "initiator"], "Akumas.fork input");
|
|
395
|
+
onlyKeys(values, ["path", "akuma", "at", "bare", "repo", "caller", "initiator"], "Akumas.fork input");
|
|
396
|
+
const bare = bareOption(values.bare);
|
|
386
397
|
const caller = decodeAkumaCaller(values.caller);
|
|
387
398
|
const initiator = values.initiator === undefined ? undefined : text(values.initiator, "initiator");
|
|
388
399
|
const at = nonblank(values.at, "at");
|
|
@@ -391,9 +402,10 @@ export async function forkAkumas(input) {
|
|
|
391
402
|
const repository = values.repo === undefined ? undefined : scopeForRepo(values.repo);
|
|
392
403
|
const receipt = await new AkumaOwner(akuma, path).fork({
|
|
393
404
|
at,
|
|
405
|
+
...(bare === undefined ? {} : { bare }),
|
|
394
406
|
...(caller === undefined ? {} : { caller }),
|
|
395
407
|
...(initiator === undefined ? {} : { initiator }),
|
|
396
|
-
});
|
|
408
|
+
}, spawn);
|
|
397
409
|
if (receipt.kind !== "forked")
|
|
398
410
|
return { ...receipt, parent: akuma };
|
|
399
411
|
const dispatch = repository === undefined
|
|
@@ -3,6 +3,7 @@ import { type AkumaHostOptions } from "../akuma/akuma-instance.js";
|
|
|
3
3
|
import type { AkumaList, AkumaListInput } from "../akuma/akuma.js";
|
|
4
4
|
import type { TellResult, TellWake } from "../akuma/body.js";
|
|
5
5
|
import { type ExecutionContext } from "../akuma/requests.js";
|
|
6
|
+
import type { BodyLauncher } from "../akuma/body-launch.js";
|
|
6
7
|
import type { DispatchAssociation } from "../akuma/dispatch-association.js";
|
|
7
8
|
import type { CreatedDebtObservation } from "../debt/created-observation.js";
|
|
8
9
|
import { type WorldRoot } from "../world.js";
|
|
@@ -18,7 +19,7 @@ export type { AkumaAskResult, AkumaHistoryResult, AkumaKillResult, AkumaList, Ak
|
|
|
18
19
|
export type Akumas = AkumasHandle;
|
|
19
20
|
declare class AkumasHandle {
|
|
20
21
|
#private;
|
|
21
|
-
constructor(world: WorldRoot, execution: ExecutionContext, host?: AkumaHostOptions);
|
|
22
|
+
constructor(world: WorldRoot, execution: ExecutionContext, spawn: BodyLauncher, host?: AkumaHostOptions);
|
|
22
23
|
list(input?: AkumaListInput): Promise<AkumaList>;
|
|
23
24
|
call(input: CallInput): Promise<CallResult>;
|
|
24
25
|
fork(input: ForkInput): Promise<ForkResult>;
|
|
@@ -43,6 +44,8 @@ declare class AkumasHandle {
|
|
|
43
44
|
* internal channel through `akumasWithExecution` instead of a second constructor.
|
|
44
45
|
*/
|
|
45
46
|
export declare function akumasWithExecution(world: WorldRoot, execution: ExecutionContext, host?: AkumaHostOptions): Akumas;
|
|
47
|
+
/** Internal host composition, independent of the captured request route. */
|
|
48
|
+
export declare function akumasWithLauncher(world: WorldRoot, execution: ExecutionContext, spawn: BodyLauncher, host?: AkumaHostOptions): Akumas;
|
|
46
49
|
export declare const Akumas: Readonly<{
|
|
47
50
|
of(world: WorldRoot, host?: AkumaHostOptions): Akumas;
|
|
48
51
|
}>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { captureAkumaHostDiagnostic } from "../akuma/akuma-instance.js";
|
|
3
3
|
import { readAkumaRoster } from "../akuma/akuma.js";
|
|
4
4
|
import { localExecutionContext } from "../akuma/requests.js";
|
|
5
|
+
import { captureAkumaHost } from "../body-host.js";
|
|
5
6
|
import { readAliases } from "../alias/index.js";
|
|
6
7
|
import { World } from "../world.js";
|
|
7
8
|
import { sweepInactiveAkumas } from "./akuma-retention.js";
|
|
@@ -12,15 +13,17 @@ export { AkumaAddressError, AkumaWorldScopeError } from "./address.js";
|
|
|
12
13
|
class AkumasHandle {
|
|
13
14
|
#world;
|
|
14
15
|
#execution;
|
|
16
|
+
#spawn;
|
|
15
17
|
#selection;
|
|
16
18
|
#reportDiagnostic;
|
|
17
19
|
#maintenance;
|
|
18
|
-
constructor(world, execution, host) {
|
|
20
|
+
constructor(world, execution, spawn, host) {
|
|
19
21
|
this.#world = world;
|
|
20
22
|
this.#execution = execution;
|
|
23
|
+
this.#spawn = spawn;
|
|
21
24
|
// One typed route seam captured at construction: no operation re-derives it.
|
|
22
25
|
this.#reportDiagnostic = captureAkumaHostDiagnostic(host);
|
|
23
|
-
this.#selection = selectionSeam(execution, this.#reportDiagnostic);
|
|
26
|
+
this.#selection = selectionSeam(execution, spawn, this.#reportDiagnostic);
|
|
24
27
|
Object.freeze(this);
|
|
25
28
|
}
|
|
26
29
|
async list(input) {
|
|
@@ -31,14 +34,14 @@ class AkumasHandle {
|
|
|
31
34
|
return withRosterAliases(roster, await readAliases(path));
|
|
32
35
|
}
|
|
33
36
|
call(input) {
|
|
34
|
-
const pending = callAkumas(this.withWorld(input, "Akumas.call input"), this.#execution, this.#reportDiagnostic);
|
|
37
|
+
const pending = callAkumas(this.withWorld(input, "Akumas.call input"), this.#execution, this.#spawn, this.#reportDiagnostic);
|
|
35
38
|
return pending.then(async (result) => {
|
|
36
39
|
await this.maintain(this.#world);
|
|
37
40
|
return result;
|
|
38
41
|
});
|
|
39
42
|
}
|
|
40
43
|
fork(input) {
|
|
41
|
-
const pending = forkAkumas(this.withWorld(input, "Akumas.fork input"));
|
|
44
|
+
const pending = forkAkumas(this.withWorld(input, "Akumas.fork input"), this.#spawn);
|
|
42
45
|
return pending.then(async (result) => {
|
|
43
46
|
if (result.kind === "forked")
|
|
44
47
|
await this.maintain(this.#world);
|
|
@@ -117,9 +120,14 @@ function withRosterAliases(roster, bindings) {
|
|
|
117
120
|
* internal channel through `akumasWithExecution` instead of a second constructor.
|
|
118
121
|
*/
|
|
119
122
|
export function akumasWithExecution(world, execution, host) {
|
|
123
|
+
const { spawn, reportDiagnostic } = captureAkumaHost(host);
|
|
124
|
+
return akumasWithLauncher(world, execution, spawn, reportDiagnostic === undefined ? undefined : { reportDiagnostic });
|
|
125
|
+
}
|
|
126
|
+
/** Internal host composition, independent of the captured request route. */
|
|
127
|
+
export function akumasWithLauncher(world, execution, spawn, host) {
|
|
120
128
|
if (typeof world !== "string")
|
|
121
129
|
throw new TypeError("Akumas.of world must be a WorldRoot");
|
|
122
|
-
return new AkumasHandle(world, execution, host);
|
|
130
|
+
return new AkumasHandle(world, execution, spawn, host);
|
|
123
131
|
}
|
|
124
132
|
export const Akumas = Object.freeze({
|
|
125
133
|
of(world, host) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BodyLauncher } from "../akuma/body-launch.js";
|
|
1
2
|
import { type AskObserver } from "../akuma/akuma-selection-execution.js";
|
|
2
3
|
import { type AkumaStatus } from "../akuma/akuma.js";
|
|
3
4
|
import { type ActivityHistory, type OutcomeRow } from "../akuma/projection.js";
|
|
@@ -32,7 +33,7 @@ export type SelectionSeam = Readonly<{
|
|
|
32
33
|
tell(addressed: AddressedAkuma, input: AkumaTellInput, signal?: AbortSignal): Promise<AkumaTellResult>;
|
|
33
34
|
ask<T>(addressed: AddressedAkuma, input: AkumaAskInput<T>, signal?: AbortSignal): Promise<AkumaAskResult<T>>;
|
|
34
35
|
}>;
|
|
35
|
-
export declare function selectionSeam(execution: ExecutionContext, reportDiagnostic?: (message: string) => void): SelectionSeam;
|
|
36
|
+
export declare function selectionSeam(execution: ExecutionContext, spawn: BodyLauncher, reportDiagnostic?: (message: string) => void): SelectionSeam;
|
|
36
37
|
export type AkumaWaitInput = AkumaSetAddressInput & Readonly<{
|
|
37
38
|
completion?: "any" | "all";
|
|
38
39
|
timeoutMs?: number;
|
|
@@ -17,11 +17,11 @@ import { outcomePluginObserver, stderrPluginDiagnostic, withAkumaWaitDeferrals }
|
|
|
17
17
|
import { addressAkuma, addressAkumaSet, resolveAkuma, resolveAkumaSet, } from "./address.js";
|
|
18
18
|
import { requireInput } from "./input.js";
|
|
19
19
|
import { scopeForRepo } from "./repo.js";
|
|
20
|
-
export function selectionSeam(execution, reportDiagnostic = stderrPluginDiagnostic) {
|
|
20
|
+
export function selectionSeam(execution, spawn, reportDiagnostic = stderrPluginDiagnostic) {
|
|
21
21
|
const channel = executionChannel(execution);
|
|
22
22
|
const routed = channel.kind === "body-request"
|
|
23
23
|
? forwardedSelection(channel.directory, reportDiagnostic)
|
|
24
|
-
: localSelection(reportDiagnostic);
|
|
24
|
+
: localSelection(spawn, reportDiagnostic);
|
|
25
25
|
return {
|
|
26
26
|
...routed,
|
|
27
27
|
wait: async (addressed, mode) => await withAkumaWaitDeferrals({ world: addressed.path, reportDiagnostic }, addressed.orderedIds, mode.signal, async () => {
|
|
@@ -68,17 +68,19 @@ function forwardedSelection(directory, reportDiagnostic) {
|
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
function localSelection(reportDiagnostic) {
|
|
71
|
+
function localSelection(spawn, reportDiagnostic) {
|
|
72
72
|
return {
|
|
73
73
|
addressOne: addressAkuma,
|
|
74
74
|
addressSet: addressAkumaSet,
|
|
75
75
|
wait: async (addressed, mode) => await localWait(addressed, mode),
|
|
76
76
|
kill: async (addressed, abort) => await executeKillAkuma({
|
|
77
|
+
spawn,
|
|
77
78
|
path: addressed.path,
|
|
78
79
|
ids: addressed.orderedIds,
|
|
79
80
|
...(abort === undefined ? {} : { signal: abort }),
|
|
80
81
|
}),
|
|
81
82
|
tell: async (addressed, input, abort) => await executeTellAkuma({
|
|
83
|
+
spawn,
|
|
82
84
|
path: addressed.path,
|
|
83
85
|
id: addressed.id,
|
|
84
86
|
body: input.body,
|
|
@@ -88,6 +90,7 @@ function localSelection(reportDiagnostic) {
|
|
|
88
90
|
}),
|
|
89
91
|
ask: async (addressed, input, abort) => {
|
|
90
92
|
const result = await executeAskAkuma({
|
|
93
|
+
spawn,
|
|
91
94
|
path: addressed.path,
|
|
92
95
|
id: addressed.id,
|
|
93
96
|
outcomeObserved: outcomePluginObserver({ world: addressed.path, reportDiagnostic }),
|
|
@@ -13,6 +13,8 @@ export type PluginOutcome = Readonly<{
|
|
|
13
13
|
}> | Readonly<{
|
|
14
14
|
kind: "failed";
|
|
15
15
|
reason: string;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
kind: "canceled";
|
|
16
18
|
}>;
|
|
17
19
|
export type PluginBodyEnd = "exited" | "broke-off" | "put-down" | "hung";
|
|
18
20
|
export type PluginAkumaOrigin = Readonly<{
|
|
@@ -54,6 +56,15 @@ export type PluginSignalMap = Readonly<{
|
|
|
54
56
|
historyId: string;
|
|
55
57
|
observer?: string;
|
|
56
58
|
}>;
|
|
59
|
+
"akuma.reported": Readonly<{
|
|
60
|
+
akumaId: string;
|
|
61
|
+
bodySequence: number;
|
|
62
|
+
turnSequence: number;
|
|
63
|
+
reportSequence: number;
|
|
64
|
+
text: string;
|
|
65
|
+
at: string;
|
|
66
|
+
initiator?: string;
|
|
67
|
+
}>;
|
|
57
68
|
"akuma.turn-started": Readonly<{
|
|
58
69
|
akumaId: string;
|
|
59
70
|
turnSequence: number;
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/keiyaku",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.21",
|
|
4
4
|
"workspaces": [
|
|
5
5
|
"plugins/square",
|
|
6
6
|
"plugins/paseo/forwarder"
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
83
83
|
"@anthropic-ai/claude-agent-sdk": "^0.3.226",
|
|
84
|
-
"@astrosheep/keiyaku-plugin-square": "0.1.
|
|
85
|
-
"@astrosheep/square": "
|
|
84
|
+
"@astrosheep/keiyaku-plugin-square": "0.1.15",
|
|
85
|
+
"@astrosheep/square": "^0.3.98",
|
|
86
86
|
"@getpaseo/client": "0.11.2",
|
|
87
87
|
"@getpaseo/protocol": "0.11.2",
|
|
88
88
|
"@opencode/client": "2.0.20",
|
|
@@ -24,6 +24,7 @@ const row = z.union([
|
|
|
24
24
|
z.object({ kind: z.literal("answered"), historyId: z.string().optional(), answer: z.string(),
|
|
25
25
|
foldedSaidSequence: count.optional() }),
|
|
26
26
|
z.object({ kind: z.literal("failed"), historyId: z.string().optional(), diagnostic: z.string() }),
|
|
27
|
+
z.object({ kind: z.literal("canceled"), historyId: z.string().optional() }),
|
|
27
28
|
]) }),
|
|
28
29
|
base.extend({ kind: z.literal("tool"), ...turnFields, name: z.string(), toolId: z.string().optional(), call,
|
|
29
30
|
state: z.union([z.enum(["active", "unsettled"]), z.object({ status: z.enum(["ok", "error"]),
|
|
@@ -170,11 +170,11 @@ export function createMirror(sessionId: string, emit: Emit) {
|
|
|
170
170
|
} else if (row.kind === "note") {
|
|
171
171
|
item({ type: "notification", id: `keiyaku:note/${row.sequence}`, level: "info", message: row.text }, row.at);
|
|
172
172
|
} else if (row.kind === "outcome") {
|
|
173
|
-
item(row.outcome.kind === "answered"
|
|
173
|
+
if (row.outcome.kind !== "canceled") item(row.outcome.kind === "answered"
|
|
174
174
|
? { type: "assistant_message", id: row.outcome.foldedSaidSequence === undefined
|
|
175
175
|
? `keiyaku:turn/${row.turnSequence}` : `keiyaku:said/${row.outcome.foldedSaidSequence}`, text: row.outcome.answer }
|
|
176
176
|
: { type: "error", id: `keiyaku:turn/${row.turnSequence}`, message: row.outcome.diagnostic }, row.at);
|
|
177
|
-
finish(openTurns.get(row.turnSequence), row.outcome.kind === "answered" ? "completed" :
|
|
177
|
+
finish(openTurns.get(row.turnSequence), row.outcome.kind === "answered" ? "completed" : row.outcome.kind,
|
|
178
178
|
row.outcome.kind === "failed" ? row.outcome.diagnostic : undefined);
|
|
179
179
|
}
|
|
180
180
|
}
|