@akagilnc/pi-workflow-roles 0.1.5365 → 0.1.5375
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/dist/acp-host/production-host.js +5585 -5655
- package/dist/activation-ledger-git.js +2 -2
- package/dist/activation-ledger-topology.js +1 -7
- package/dist/analyst-entry.js +4 -8
- package/dist/analyst-gate-cycles-read.js +3 -11
- package/dist/analyst-index.js +3 -9
- package/dist/analyst-ledger.js +1 -11
- package/dist/analyst-metric-families/acceptance-success-rework.js +1 -3
- package/dist/analyst-metric-families/round-timeline.js +1 -3
- package/dist/analyst-page.js +2 -2
- package/dist/archivist-record-topology.js +2 -2
- package/dist/audit-escalation.js +2 -1
- package/dist/auditor-soul.js +2 -1
- package/dist/collector-config.js +6 -8
- package/dist/compliance-transport.js +2 -1
- package/dist/countersign-contracts.js +2 -1
- package/dist/diarist-contracts.js +3 -2
- package/dist/doctor-contracts.js +1 -3
- package/dist/doctor-evidence.js +7 -8
- package/dist/dossier-resolution.js +1 -3
- package/dist/engine-detour-usage.js +1 -3
- package/dist/gatekeeper-role.js +2 -9
- package/dist/gleaner-left-contracts.js +2 -1
- package/dist/headless-host/description.js +14 -17
- package/dist/headless-host/production-host.js +1665 -1737
- package/dist/host-session-record.js +3 -2
- package/dist/inspector-contracts.js +2 -1
- package/dist/ledger-session-read.js +1 -3
- package/dist/merger-contracts.js +9 -9
- package/dist/migrate-book-topology.js +348 -314
- package/dist/navigator-attendance.js +9 -11
- package/dist/navigator-invocation-identity.js +3 -2
- package/dist/navigator-public-session.js +3 -5
- package/dist/navigator-session-contracts.js +8 -10
- package/dist/navigator-work-base.js +5 -8
- package/dist/notary-contracts.js +3 -5
- package/dist/package-contracts/auditor-output.js +1 -3
- package/dist/package-contracts/fixer-packet.js +3 -6
- package/dist/package-contracts/gatekeeper-output.js +1 -3
- package/dist/package-contracts/navigator-output.js +8 -8
- package/dist/package-contracts/terminating-infrastructure.js +5 -9
- package/dist/package-contracts/terminating-tools.js +4 -3
- package/dist/public-cli/analyst-run.js +3 -2
- package/dist/public-cli/auto-resume.js +4 -9
- package/dist/public-cli/cli.js +66 -64
- package/dist/public-cli/config.js +12 -11
- package/dist/public-cli/countersign-run.js +1 -3
- package/dist/public-cli/host-providers.js +7 -14
- package/dist/public-cli/instruction-seat-run.js +69 -43
- package/dist/public-cli/invocation.js +141 -136
- package/dist/public-cli/main.js +1919 -1968
- package/dist/public-cli/post-admission.js +89 -89
- package/dist/public-cli/role-seat-runtime.js +29 -0
- package/dist/public-cli/run-lifecycle.js +20 -32
- package/dist/public-cli/settlement.js +10 -26
- package/dist/public-cli/turn-request.js +14 -0
- package/dist/public-role-summons.js +23 -35
- package/dist/receipt-delivery-policy.js +1 -3
- package/dist/role-run-placement.js +7 -5
- package/dist/role-run-relocation.js +12 -19
- package/dist/run-terminal-artifacts.js +1 -11
- package/dist/run-ticket-number.js +2 -4
- package/dist/session-assistant-usage.js +2 -1
- package/dist/session-dialogue.js +1 -14
- package/dist/sitian-reader.js +2 -4
- package/dist/submission-correctable-error.js +2 -1
- package/dist/submission-errors.js +2 -1
- package/dist/submission-gate.js +2 -1
- package/dist/submission-ledger.js +4 -5
- package/dist/ticket-provenance-contracts.js +1 -3
- package/dist/ticket-provenance.js +2 -1
- package/dist/typed-provider-http.js +4 -7
- package/dist/unknown-value.js +28 -0
- package/dist/user-dialogue-stdin.js +2 -1
- package/package.json +1 -1
- package/src/acp-host/role-turn-host.ts +4 -2
- package/src/activation-ledger-git.ts +3 -2
- package/src/activation-ledger-topology.ts +4 -12
- package/src/analyst-entry.ts +3 -11
- package/src/analyst-gate-cycles-read.ts +3 -15
- package/src/analyst-index.ts +3 -13
- package/src/analyst-ledger.ts +2 -16
- package/src/analyst-metric-families/acceptance-success-rework.ts +2 -4
- package/src/analyst-metric-families/round-timeline.ts +2 -4
- package/src/analyst-page.ts +2 -2
- package/src/archivist-record-topology.ts +2 -2
- package/src/audit-escalation.ts +2 -1
- package/src/auditor-soul.ts +3 -1
- package/src/book-topology-migration-placement.ts +8 -21
- package/src/book-topology-migrators-t11.ts +16 -15
- package/src/book-topology-mixed-volume-migrators.ts +3 -6
- package/src/book-topology-record-class-migrators.ts +7 -10
- package/src/book-topology-runs-migrator.ts +4 -3
- package/src/collector-config.ts +7 -9
- package/src/compliance-transport.ts +2 -1
- package/src/countersign-contracts.ts +2 -1
- package/src/diarist-contracts.ts +3 -2
- package/src/doctor-contracts.ts +3 -1
- package/src/doctor-evidence.ts +8 -7
- package/src/doctor-role.ts +4 -2
- package/src/dossier-resolution.ts +2 -4
- package/src/engine-detour-tool.ts +0 -2
- package/src/engine-detour-usage.ts +2 -4
- package/src/external-host-turn-loop.ts +3 -1
- package/src/factory-board.ts +1 -8
- package/src/gatekeeper-role.ts +2 -10
- package/src/gleaner-left-contracts.ts +3 -1
- package/src/headless-host/description.ts +15 -18
- package/src/headless-host/role-turn-host.ts +10 -9
- package/src/host-session-record.ts +4 -2
- package/src/inspector-contracts.ts +2 -1
- package/src/ledger-session-read.ts +2 -5
- package/src/merger-contracts.ts +10 -9
- package/src/navigator-attendance.ts +10 -12
- package/src/navigator-invocation-identity.ts +3 -2
- package/src/navigator-public-session.ts +4 -6
- package/src/navigator-session-contracts.ts +8 -11
- package/src/navigator-work-base.ts +5 -8
- package/src/navigator-work-context.ts +2 -1
- package/src/notary-contracts.ts +4 -6
- package/src/oauth-keepalive.ts +5 -18
- package/src/package-contracts/auditor-output.ts +2 -4
- package/src/package-contracts/fixer-packet.ts +4 -6
- package/src/package-contracts/gatekeeper-output.ts +2 -4
- package/src/package-contracts/judge-output.ts +0 -1
- package/src/package-contracts/navigator-output.ts +8 -8
- package/src/package-contracts/terminating-infrastructure.ts +6 -20
- package/src/package-contracts/terminating-tools.ts +8 -12
- package/src/pi/adapter.ts +0 -1
- package/src/pi/role-turn-host.ts +0 -1
- package/src/public-cli/analyst-run.ts +4 -2
- package/src/public-cli/auto-resume.ts +5 -12
- package/src/public-cli/cli.ts +77 -83
- package/src/public-cli/config.ts +16 -27
- package/src/public-cli/countersign-run.ts +2 -4
- package/src/public-cli/host-providers.ts +10 -27
- package/src/public-cli/instruction-seat-run.ts +87 -58
- package/src/public-cli/invocation.ts +159 -172
- package/src/public-cli/post-admission.ts +115 -103
- package/src/public-cli/role-seat-runtime.ts +72 -0
- package/src/public-cli/run-lifecycle.ts +27 -67
- package/src/public-cli/settlement.ts +11 -33
- package/src/public-cli/terminal.ts +2 -17
- package/src/public-cli/turn-request.ts +26 -0
- package/src/public-role-summons.ts +24 -48
- package/src/receipt-delivery-policy.ts +1 -4
- package/src/reviewer-role.ts +0 -1
- package/src/role-envelope.ts +5 -3
- package/src/role-run-placement.ts +9 -10
- package/src/role-run-relocation.ts +13 -23
- package/src/role-runtime.ts +9 -15
- package/src/run-terminal-artifacts.ts +2 -16
- package/src/run-ticket-number.ts +4 -10
- package/src/session-assistant-usage.ts +3 -1
- package/src/session-dialogue.ts +1 -4
- package/src/session-identity.ts +0 -1
- package/src/sitian-reader.ts +2 -4
- package/src/submission-correctable-error.ts +3 -1
- package/src/submission-errors.ts +2 -1
- package/src/submission-gate.ts +3 -1
- package/src/submission-ledger.ts +5 -6
- package/src/ticket-provenance-contracts.ts +1 -4
- package/src/ticket-provenance.ts +3 -1
- package/src/ticket-snapshot.ts +2 -4
- package/src/ticket-trajectory.ts +1 -8
- package/src/typed-provider-http.ts +5 -15
- package/src/unknown-value.ts +34 -0
- package/src/user-dialogue-stdin.ts +3 -1
- package/src/worker-role.ts +2 -5
- package/src/worker-submission-gates.ts +5 -7
|
@@ -11,6 +11,8 @@ import { basename, dirname, join } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import { roleRunArtifactsDirectory } from "./role-run-placement.ts";
|
|
13
13
|
|
|
14
|
+
import { isRecord, errorText, isMissingPathError } from "./unknown-value.ts";
|
|
15
|
+
|
|
14
16
|
export const RUN_TERMINAL_ARTIFACT_FILES = [
|
|
15
17
|
"report.json",
|
|
16
18
|
"error.json",
|
|
@@ -49,22 +51,6 @@ export type RunTerminalArtifactRead =
|
|
|
49
51
|
readonly reason: string;
|
|
50
52
|
};
|
|
51
53
|
|
|
52
|
-
function isMissingPathError(error: unknown): boolean {
|
|
53
|
-
return (
|
|
54
|
-
error instanceof Error
|
|
55
|
-
&& "code" in error
|
|
56
|
-
&& (error.code === "ENOENT" || error.code === "ENOTDIR")
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function errorText(error: unknown): string {
|
|
61
|
-
return error instanceof Error ? error.message : String(error);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
65
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
54
|
/**
|
|
69
55
|
* Minimum producer-owned face shared by settlement terminal artifacts
|
|
70
56
|
* (report / error / audit-incomplete). Consumer-driven: enough to identify a
|
package/src/run-ticket-number.ts
CHANGED
|
@@ -8,18 +8,12 @@
|
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
|
|
11
|
+
import { isEnoent, isRecord } from "./unknown-value.ts";
|
|
12
|
+
|
|
11
13
|
/** Sole on-disk page for worktree-basename ticket derivation (#865). */
|
|
12
14
|
export const MIGRATION_TICKET_DERIVATION_PAGE =
|
|
13
15
|
"migration-ticket-derivation.json" as const;
|
|
14
16
|
|
|
15
|
-
function isEnoent(error: unknown): boolean {
|
|
16
|
-
return (
|
|
17
|
-
error instanceof Error &&
|
|
18
|
-
"code" in error &&
|
|
19
|
-
(error as NodeJS.ErrnoException).code === "ENOENT"
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
17
|
/** Sole safe-positive ticket invariant (bind / admission / placement / readers). */
|
|
24
18
|
export function isSafePositiveTicketNumber(value: unknown): value is number {
|
|
25
19
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
|
|
@@ -69,10 +63,10 @@ async function readJsonObject(
|
|
|
69
63
|
): Promise<Record<string, unknown> | undefined> {
|
|
70
64
|
try {
|
|
71
65
|
const raw: unknown = JSON.parse(await readFile(path, "utf8"));
|
|
72
|
-
if (
|
|
66
|
+
if (!isRecord(raw)) {
|
|
73
67
|
return undefined;
|
|
74
68
|
}
|
|
75
|
-
return raw
|
|
69
|
+
return raw;
|
|
76
70
|
} catch (error) {
|
|
77
71
|
if (isEnoent(error)) return undefined;
|
|
78
72
|
throw error;
|
|
@@ -7,6 +7,8 @@ import { join } from "node:path";
|
|
|
7
7
|
|
|
8
8
|
import type { PublicSummonResult } from "./public-role-summons.ts";
|
|
9
9
|
|
|
10
|
+
import { errorText } from "./unknown-value.ts";
|
|
11
|
+
|
|
10
12
|
export async function readAssistantUsageFromSessionFile(
|
|
11
13
|
sessionFile: string,
|
|
12
14
|
): Promise<Usage | undefined> {
|
|
@@ -30,7 +32,7 @@ export async function readAssistantUsageFromSessionFile(
|
|
|
30
32
|
});
|
|
31
33
|
} catch (error) {
|
|
32
34
|
throw new Error(
|
|
33
|
-
`session usage parse failed (${sessionFile}): ${
|
|
35
|
+
`session usage parse failed (${sessionFile}): ${errorText(error)}`,
|
|
34
36
|
{ cause: error },
|
|
35
37
|
);
|
|
36
38
|
}
|
package/src/session-dialogue.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.ts";
|
|
1
2
|
/**
|
|
2
3
|
* 对话事实适配(ADR 0075 `dialogue-only` / `no-tool-output` / `speaker-required`)。
|
|
3
4
|
*
|
|
@@ -20,10 +21,6 @@ export type DialogueEvent = {
|
|
|
20
21
|
readonly id?: string;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
24
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
24
|
/**
|
|
28
25
|
* 原生 id:行级或消息体级主键的单一实现(bound 解析与落盘共用)。
|
|
29
26
|
* Pi/CC:行上 `uuid`/`id`;Codex:`response_item.payload.id`(或 `message.id`)。
|
package/src/session-identity.ts
CHANGED
package/src/sitian-reader.ts
CHANGED
|
@@ -15,9 +15,7 @@ import type {
|
|
|
15
15
|
SitianRecord,
|
|
16
16
|
} from "./sitian-contracts.ts";
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
-
}
|
|
18
|
+
import { isRecord, errorText } from "./unknown-value.ts";
|
|
21
19
|
|
|
22
20
|
/** Read a Sitian record volume with full traversal and non-destructive diagnostics. */
|
|
23
21
|
export async function readSitianRecords(recordFile: string): Promise<SitianReadResult> {
|
|
@@ -53,7 +51,7 @@ export async function readSitianRecords(recordFile: string): Promise<SitianReadR
|
|
|
53
51
|
kind: "malformed",
|
|
54
52
|
line: index + 1,
|
|
55
53
|
raw: line,
|
|
56
|
-
error:
|
|
54
|
+
error: errorText(error),
|
|
57
55
|
});
|
|
58
56
|
}
|
|
59
57
|
}
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
WorkerUnfinishedReasonReminderError,
|
|
7
7
|
} from "./submission-errors.ts";
|
|
8
8
|
|
|
9
|
+
import { errorText } from "./unknown-value.ts";
|
|
10
|
+
|
|
9
11
|
/** Shared, unforgeable identity for submission errors that the same session may correct. */
|
|
10
12
|
const correctableSubmissionErrorBrand = Symbol("ak-roles.correctable-submission-error");
|
|
11
13
|
|
|
@@ -49,7 +51,7 @@ export type CorrectableExecuteRejectionProjection = {
|
|
|
49
51
|
export function projectCorrectableExecuteRejection(
|
|
50
52
|
error: unknown,
|
|
51
53
|
): CorrectableExecuteRejectionProjection {
|
|
52
|
-
const diagnostic =
|
|
54
|
+
const diagnostic = errorText(error);
|
|
53
55
|
if (error instanceof GatekeeperDecisionError) {
|
|
54
56
|
return { diagnostic, details: { ...(error.result as Record<string, unknown>) } };
|
|
55
57
|
}
|
package/src/submission-errors.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SubmissionGateNonPassResult } from "./gatekeeper-role.ts";
|
|
2
2
|
import { readableGateItem } from "./readable-gate-item.ts";
|
|
3
|
+
import { isRecord } from "./unknown-value.ts";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Tool-result text the parent model sees (#753 / #750 evidence).
|
|
@@ -69,7 +70,7 @@ export function unreadableDiscriminatorNotice(field: string, received: unknown):
|
|
|
69
70
|
|
|
70
71
|
/** The received discriminator only — never the rest of the receipt. */
|
|
71
72
|
export function receivedDiscriminator(receipt: unknown, field: string): unknown {
|
|
72
|
-
if (
|
|
73
|
+
if (!isRecord(receipt)) return undefined;
|
|
73
74
|
if (!Object.hasOwn(receipt, field)) return undefined;
|
|
74
75
|
return (receipt as Record<string, unknown>)[field];
|
|
75
76
|
}
|
package/src/submission-gate.ts
CHANGED
|
@@ -36,7 +36,7 @@ export function latestQueueStatus(terminal: TerminalResult | undefined): string
|
|
|
36
36
|
if (outcome.kind === "audit_escalation") return "escalate";
|
|
37
37
|
if (outcome.kind !== "accepted") return undefined;
|
|
38
38
|
const latest = outcome.payloads?.[outcome.payloads.length - 1];
|
|
39
|
-
if (
|
|
39
|
+
if (isRecord(latest)) {
|
|
40
40
|
const status = (latest as { status?: unknown }).status;
|
|
41
41
|
if (typeof status === "string" && status.trim() !== "") return status;
|
|
42
42
|
}
|
|
@@ -54,6 +54,8 @@ export function latestQueuePayload(terminal: TerminalResult | undefined): unknow
|
|
|
54
54
|
}
|
|
55
55
|
import { sessionFileFromPublicSummon } from "./session-assistant-usage.ts";
|
|
56
56
|
|
|
57
|
+
import { isRecord } from "./unknown-value.ts";
|
|
58
|
+
|
|
57
59
|
/**
|
|
58
60
|
* Shared-envelope default officer summon (ADR 0018).
|
|
59
61
|
* Role modules must not own this drive seam — only project results.
|
package/src/submission-ledger.ts
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
type RoleHost,
|
|
13
13
|
} from "./host-contracts.ts";
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.ts";
|
|
17
16
|
import { readSitianRecords, resolveSitianRecordPathInLedger, sitianReport, type RecordPointer } from "./sitian-facade.ts";
|
|
18
17
|
import type { SitianRecord } from "./sitian-contracts.ts";
|
|
@@ -22,6 +21,8 @@ import { isCorrectableExecuteError } from "./submission-correctable-error.ts";
|
|
|
22
21
|
import { failOnInfrastructureFailureDeclaration, infrastructureFailureDiagnostic } from "./package-contracts/terminating-infrastructure.ts";
|
|
23
22
|
import { REVIEW_SUBMISSION_OUTPUT_TOOL_NAME } from "./review-submission.ts";
|
|
24
23
|
|
|
24
|
+
import { isRecord, errorText } from "./unknown-value.ts";
|
|
25
|
+
|
|
25
26
|
export type SubmissionCall = { readonly id: string; readonly name: string };
|
|
26
27
|
export type SubmissionOutcomeKind = "correctable-rejection" | "audit-escalation" | "infrastructure";
|
|
27
28
|
/** Typed correctable-rejection codes — bounce/reminder paths only (#836: no sole/non-terminate reject). */
|
|
@@ -662,9 +663,7 @@ export function createSubmissionLedgerHost(
|
|
|
662
663
|
// host-failure seam. Tool identity comes from the registry map.
|
|
663
664
|
const reviewEscalate = tool.name === REVIEW_SUBMISSION_OUTPUT_TOOL_NAME
|
|
664
665
|
&& infrastructureFailureDiagnostic(params) !== undefined
|
|
665
|
-
&& params
|
|
666
|
-
&& typeof params === "object"
|
|
667
|
-
&& !Array.isArray(params)
|
|
666
|
+
&& isRecord(params)
|
|
668
667
|
&& (params as Record<string, unknown>).status === "escalate";
|
|
669
668
|
if (!reviewEscalate) {
|
|
670
669
|
failOnInfrastructureFailureDeclaration(
|
|
@@ -688,7 +687,7 @@ export function createSubmissionLedgerHost(
|
|
|
688
687
|
toolCallId,
|
|
689
688
|
outcome: "correctable-rejection",
|
|
690
689
|
code: "typed-bounce",
|
|
691
|
-
diagnostic:
|
|
690
|
+
diagnostic: errorText(error),
|
|
692
691
|
role,
|
|
693
692
|
accepted: params,
|
|
694
693
|
});
|
|
@@ -699,7 +698,7 @@ export function createSubmissionLedgerHost(
|
|
|
699
698
|
attemptId,
|
|
700
699
|
toolCallId,
|
|
701
700
|
outcome: "infrastructure",
|
|
702
|
-
diagnostic:
|
|
701
|
+
diagnostic: errorText(error),
|
|
703
702
|
role,
|
|
704
703
|
accepted: params,
|
|
705
704
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.ts";
|
|
1
2
|
/**
|
|
2
3
|
* 起居录(ticket-provenance)typed 形状 —— ADR 0075 / ADR 0081 / #1090。
|
|
3
4
|
*
|
|
@@ -61,10 +62,6 @@ export type TicketProvenanceLine = {
|
|
|
61
62
|
readonly text: string;
|
|
62
63
|
};
|
|
63
64
|
|
|
64
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
65
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
65
|
function positiveInteger(value: unknown): number | undefined {
|
|
69
66
|
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 1) return value;
|
|
70
67
|
if (typeof value === "string" && /^[1-9][0-9]*$/.test(value)) {
|
package/src/ticket-provenance.ts
CHANGED
|
@@ -32,6 +32,8 @@ import {
|
|
|
32
32
|
type TicketProvenanceSession,
|
|
33
33
|
} from "./ticket-provenance-contracts.ts";
|
|
34
34
|
|
|
35
|
+
import { errorText } from "./unknown-value.ts";
|
|
36
|
+
|
|
35
37
|
/**
|
|
36
38
|
* Typed input failure for diarist bounds/session path (reask, not infrastructure).
|
|
37
39
|
* Accept hook discriminates with instanceof — never Error.message prefixes.
|
|
@@ -281,7 +283,7 @@ async function projectSessionRanges(input: {
|
|
|
281
283
|
if (error instanceof TicketProvenanceInputError) throw error;
|
|
282
284
|
const code = errnoCode(error);
|
|
283
285
|
if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR") {
|
|
284
|
-
const detail =
|
|
286
|
+
const detail = errorText(error);
|
|
285
287
|
throw new TicketProvenanceInputError(
|
|
286
288
|
`session unreadable: ${input.session.path} (${detail})`,
|
|
287
289
|
{ cause: error },
|
package/src/ticket-snapshot.ts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { createGhApiRunner, type GhApiRunner } from "./gh-api-runner.ts";
|
|
15
15
|
|
|
16
|
+
import { isRecord } from "./unknown-value.ts";
|
|
17
|
+
|
|
16
18
|
export type BookRepoBinding = {
|
|
17
19
|
bookKey: string;
|
|
18
20
|
owner: string;
|
|
@@ -92,10 +94,6 @@ export class TicketSnapshotApiError extends Error {
|
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
96
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
97
|
function requireNonEmpty(value: string, label: string): string {
|
|
100
98
|
const trimmed = value.trim();
|
|
101
99
|
if (!trimmed) throw new Error(`${label} must be a non-empty string`);
|
package/src/ticket-trajectory.ts
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
} from "./package-contracts/terminating-tools.ts";
|
|
47
47
|
import { LEGACY_REVIEW_OUTPUT_ROLES, PACKAGED_ROLE_REGISTRY } from "./packaged-role-registry.ts";
|
|
48
48
|
|
|
49
|
+
import { isRecord, isMissingPathError } from "./unknown-value.ts";
|
|
49
50
|
|
|
50
51
|
/** Declared refresh bound for the same viewing surface (seconds). */
|
|
51
52
|
export const DEFAULT_REFRESH_BOUNDARY_SECONDS = 30;
|
|
@@ -122,14 +123,6 @@ export type TicketTrajectoryRun = {
|
|
|
122
123
|
|
|
123
124
|
type ParsedRun = TicketTrajectoryRun;
|
|
124
125
|
|
|
125
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
126
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function isMissingPathError(error: unknown): boolean {
|
|
130
|
-
return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
126
|
/** realpath when the node exists; lexical path only for recognized absence — never for other errors. */
|
|
134
127
|
async function realpathOrLexicalIfMissing(path: string): Promise<string> {
|
|
135
128
|
try {
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
|
|
8
|
+
import { isEnoent, isRecord } from "./unknown-value.ts";
|
|
9
|
+
|
|
8
10
|
const TYPED_HTTP_FILE = "typed-provider-http.json";
|
|
9
11
|
|
|
10
12
|
export type TypedProviderHttpObservation = {
|
|
@@ -27,13 +29,7 @@ export async function clearTypedProviderHttpObservation(
|
|
|
27
29
|
try {
|
|
28
30
|
await unlink(typedProviderHttpPath(runDirectory));
|
|
29
31
|
} catch (error) {
|
|
30
|
-
if (
|
|
31
|
-
error instanceof Error &&
|
|
32
|
-
"code" in error &&
|
|
33
|
-
(error as { code?: unknown }).code === "ENOENT"
|
|
34
|
-
) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
32
|
+
if (isEnoent(error)) return;
|
|
37
33
|
throw error;
|
|
38
34
|
}
|
|
39
35
|
}
|
|
@@ -75,17 +71,11 @@ export async function readLatestTypedProviderHttpObservation(
|
|
|
75
71
|
try {
|
|
76
72
|
text = await readFile(typedProviderHttpPath(runDirectory), "utf8");
|
|
77
73
|
} catch (error) {
|
|
78
|
-
if (
|
|
79
|
-
error instanceof Error &&
|
|
80
|
-
"code" in error &&
|
|
81
|
-
(error as { code?: unknown }).code === "ENOENT"
|
|
82
|
-
) {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
74
|
+
if (isEnoent(error)) return undefined;
|
|
85
75
|
throw error;
|
|
86
76
|
}
|
|
87
77
|
const raw: unknown = JSON.parse(text);
|
|
88
|
-
if (
|
|
78
|
+
if (!isRecord(raw)) {
|
|
89
79
|
throw new Error("typed provider HTTP observation must be a JSON object");
|
|
90
80
|
}
|
|
91
81
|
const record = raw as Record<string, unknown>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Guard } from "typebox/guard";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sole readers for a plain object, a Node errno, and an Error message.
|
|
5
|
+
* Callers choose which codes count; ENOTDIR is not ENOENT.
|
|
6
|
+
* Plain objects are TypeBox `Guard.IsObjectNotArray`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
10
|
+
return Guard.IsObjectNotArray(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function errnoCode(error: unknown): string | undefined {
|
|
14
|
+
return error !== null && typeof error === "object" && "code" in error
|
|
15
|
+
&& typeof (error as { code: unknown }).code === "string"
|
|
16
|
+
? (error as { code: string }).code
|
|
17
|
+
: undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** `Error.message`, otherwise `String(value)`. */
|
|
21
|
+
export function errorText(error: unknown): string {
|
|
22
|
+
return error instanceof Error ? error.message : String(error);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** True only for ENOENT on an Error. ENOTDIR and every other code stay distinct. */
|
|
26
|
+
export function isEnoent(error: unknown): boolean {
|
|
27
|
+
return error instanceof Error && errnoCode(error) === "ENOENT";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** ENOENT or ENOTDIR on an Error. */
|
|
31
|
+
export function isMissingPathError(error: unknown): boolean {
|
|
32
|
+
const code = errnoCode(error);
|
|
33
|
+
return error instanceof Error && (code === "ENOENT" || code === "ENOTDIR");
|
|
34
|
+
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Pi's piped-stdin reader trims the wrapper; the body field keeps original bytes.
|
|
4
4
|
* No size cap and no path/pointer substitute — the whole dialogue rides the envelope.
|
|
5
5
|
*/
|
|
6
|
+
import { isRecord } from "./unknown-value.ts";
|
|
7
|
+
|
|
6
8
|
export const USER_DIALOGUE_STDIN_KIND = "ak-user-dialogue" as const;
|
|
7
9
|
|
|
8
10
|
export type UserDialogueStdinEnvelope = {
|
|
@@ -15,7 +17,7 @@ export function encodeUserDialogueStdin(body: string): string {
|
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
function isUserDialogueEnvelope(value: unknown): value is UserDialogueStdinEnvelope {
|
|
18
|
-
if (
|
|
20
|
+
if (!isRecord(value)) return false;
|
|
19
21
|
const record = value as { kind?: unknown; body?: unknown };
|
|
20
22
|
return record.kind === USER_DIALOGUE_STDIN_KIND && typeof record.body === "string";
|
|
21
23
|
}
|
package/src/worker-role.ts
CHANGED
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
matchFixerBashForbiddenLiteral,
|
|
30
30
|
} from "./fixer-bash-seatbelt.ts";
|
|
31
31
|
|
|
32
|
+
import { isRecord } from "./unknown-value.ts";
|
|
33
|
+
|
|
32
34
|
export {
|
|
33
35
|
CODER_OUTPUT_TOOL_NAME,
|
|
34
36
|
FIXER_OUTPUT_TOOL_NAME,
|
|
@@ -104,10 +106,6 @@ export type WorkerRoleRuntime = {
|
|
|
104
106
|
armSubmissionGate(cwd: string, parent: { getSessionFile(): string | undefined }): void;
|
|
105
107
|
};
|
|
106
108
|
|
|
107
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
108
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
109
|
/** Read only the field that selects the worker's next package-owned path. */
|
|
112
110
|
function workerStatusOf(output: WorkerOutput): string | undefined {
|
|
113
111
|
return isRecord(output) && typeof output.status === "string"
|
|
@@ -130,7 +128,6 @@ export function validateWorkerOutput(
|
|
|
130
128
|
return validateAcceptedWorkerDetails(output, "Coder") as CoderOutput;
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
|
|
134
131
|
/** Reminder bounces stay typed rejects; IO/infrastructure keep identity via host failInfrastructure. */
|
|
135
132
|
function assertAcceptableThroughHost(
|
|
136
133
|
submissionGate: { assertAcceptable(status: string, details?: unknown): void },
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
} from "./submission-errors.ts";
|
|
18
18
|
import { WORKER_DONE_STATUSES } from "./worker-submission-contracts.ts";
|
|
19
19
|
|
|
20
|
+
import { isRecord } from "./unknown-value.ts";
|
|
21
|
+
|
|
20
22
|
export { WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError } from "./submission-errors.ts";
|
|
21
23
|
export { WORKER_DONE_STATUSES } from "./worker-submission-contracts.ts";
|
|
22
24
|
|
|
@@ -152,15 +154,11 @@ function uninstallPackageWorkerHooks(cwd: string): void {
|
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
156
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
157
|
/** ADR 0050: a written explanation, including text carried by an object key. */
|
|
160
158
|
function containsWrittenReason(value: unknown): boolean {
|
|
161
159
|
if (typeof value === "string") return value.trim().length > 0;
|
|
162
160
|
if (Array.isArray(value)) return value.some(containsWrittenReason);
|
|
163
|
-
if (
|
|
161
|
+
if (isRecord(value)) {
|
|
164
162
|
return Object.entries(value).some(
|
|
165
163
|
([key, item]) => containsWrittenReason(key) || containsWrittenReason(item),
|
|
166
164
|
);
|
|
@@ -169,8 +167,8 @@ function containsWrittenReason(value: unknown): boolean {
|
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
function unfinishedReasonPresent(details?: unknown): boolean {
|
|
172
|
-
if (
|
|
173
|
-
return containsWrittenReason(
|
|
170
|
+
if (!isRecord(details)) return false;
|
|
171
|
+
return containsWrittenReason(details.reason);
|
|
174
172
|
}
|
|
175
173
|
|
|
176
174
|
function readGateState(session: HostRecordSession): {
|