@sema-agent/core 5.35.0 → 5.36.0
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/CHANGELOG.md +58 -0
- package/dist/agents/subagent.js +29 -2
- package/dist/core/auto-compaction.d.ts +23 -0
- package/dist/core/auto-compaction.js +8 -0
- package/dist/core/checkpoint-store.d.ts +16 -0
- package/dist/core/context-guard.d.ts +41 -0
- package/dist/core/context-guard.js +76 -0
- package/dist/core/memory-engine/engine.js +1 -1
- package/dist/core/park-selfcheck.d.ts +5 -0
- package/dist/core/runner/assemble-result.d.ts +3 -0
- package/dist/core/runner/assemble-result.js +3 -0
- package/dist/core/runner/git-status-frame.d.ts +219 -0
- package/dist/core/runner/git-status-frame.js +212 -0
- package/dist/core/runner/prepare-task.d.ts +16 -0
- package/dist/core/runner/prepare-task.js +27 -34
- package/dist/core/runner/runtask.js +266 -5
- package/dist/core/task-registry-agent.d.ts +15 -0
- package/dist/core/task-registry-agent.js +9 -0
- package/dist/core/task-registry.d.ts +3 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/types.d.ts +27 -7
- package/dist/engine/harness/types.d.ts +65 -1
- package/dist/engine/harness/types.js +20 -0
- package/dist/engine/session/import-validate.js +10 -1
- package/dist/engine/session/session.d.ts +37 -1
- package/dist/engine/session/session.js +56 -1
- package/dist/internal/harness-types.d.ts +1 -0
- package/dist/internal/harness.d.ts +2 -0
- package/dist/internal/harness.js +2 -0
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/prompts/default.d.ts +20 -7
- package/dist/prompts/default.js +2 -7
- package/package.json +1 -1
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { AgentMessage, ExecutionEnv, GitAnnouncementKind, SessionTreeEntry } from "../../internal/harness-types.js";
|
|
2
|
+
/** Bound into the hash domain: bump when the frame's wording/structure changes so the upgraded
|
|
3
|
+
* renderer re-announces on its first leg instead of being suppressed by a pre-upgrade hash. */
|
|
4
|
+
export declare const GIT_STATUS_FRAME_FORMAT_VERSION = 1;
|
|
5
|
+
/**
|
|
6
|
+
* The frame's own first paragraph (replaces the CC "will not update during the conversation" head,
|
|
7
|
+
* which would be FALSE under the frame protocol). Wording obligations: self-declares the update
|
|
8
|
+
* semantics (latest frame supersedes earlier ones), promises re-send on VISIBLE-view change only
|
|
9
|
+
* (truncation-bound honesty), and "observed while preparing" does not claim an atomic instant (the
|
|
10
|
+
* probe is two shell round-trips and a write can land between them).
|
|
11
|
+
*/
|
|
12
|
+
export declare const GIT_STATUS_FRAME_PREAMBLE = "This is the git status observed while preparing this request. When the visible snapshot changes it will be re-sent in a later message \u2014 the most recent git status frame supersedes earlier ones.";
|
|
13
|
+
/** Tombstone body — the probes could not reach git at all while earlier frames announced a
|
|
14
|
+
* positive view (sent once, on the availability flip edge only). */
|
|
15
|
+
export declare const GIT_STATUS_UNAVAILABLE_BODY = "Git status is currently unavailable; the most recent git status frame above may be stale.";
|
|
16
|
+
/** Tombstone body — the directory stopped being a git repository while earlier frames announced a
|
|
17
|
+
* positive view (sent once, on the flip edge; the env block's static is-repo line flips the same leg). */
|
|
18
|
+
export declare const GIT_STATUS_NON_REPO_BODY = "The working directory is no longer a git repository; earlier git status frames no longer apply.";
|
|
19
|
+
/** The `steering_injected` echo previews for the frame — CONSTANT wordings on purpose: branch and
|
|
20
|
+
* status text are repo-controlled and must not enter the event telemetry plane through the echo. */
|
|
21
|
+
export declare const GIT_STATUS_ECHO_PREVIEW: Record<GitAnnouncementKind, string>;
|
|
22
|
+
/** The raw material of one probe cycle, as prepare-task resolved it (§4.3 unified ladder):
|
|
23
|
+
* - `full` — §E14 and the H4 snapshot both succeeded: `snapshot` = the pre-rendered
|
|
24
|
+
* {@link import("../../prompts/default.js").buildGitSnapshot} block (CC template,
|
|
25
|
+
* sanitized + bounded by its renderer);
|
|
26
|
+
* - `degraded` — §E14 yielded git facts but the H4 snapshot failed (exit 41/42, timeout, sentinel
|
|
27
|
+
* mis-split): branch + dirtiness are all that is honestly known;
|
|
28
|
+
* - `unavailable` — the §E14 probe itself failed (git facts unknowable this leg);
|
|
29
|
+
* - `non-repo` — the probe ran and the cwd is not a git repository. */
|
|
30
|
+
export type GitStatusProbeOutcome = {
|
|
31
|
+
kind: "full";
|
|
32
|
+
snapshot: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "degraded";
|
|
35
|
+
branch?: string;
|
|
36
|
+
dirty?: boolean;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "unavailable";
|
|
39
|
+
} | {
|
|
40
|
+
kind: "non-repo";
|
|
41
|
+
};
|
|
42
|
+
/** Render the frame BODY (the text inside the `<system-reminder>` shell) for one probe outcome. */
|
|
43
|
+
export declare function renderGitStatusFrameBody(outcome: GitStatusProbeOutcome): string;
|
|
44
|
+
/**
|
|
45
|
+
* Content hash of a rendered frame body — the hash half of the `(kind, hash)` comparison tuple.
|
|
46
|
+
* Digest domain = format version + canonical repo root + kind + body, NUL-separated (none of the
|
|
47
|
+
* inputs may contain NUL: the body is sanitized text, the root a canonical path). `canonicalRoot`
|
|
48
|
+
* is the ExecutionEnv-canonicalized worktree root (or cwd outside a repo) so identical bytes from
|
|
49
|
+
* two different checkouts never share an announcement.
|
|
50
|
+
*/
|
|
51
|
+
export declare function hashGitStatusFrame(kind: GitAnnouncementKind, body: string, canonicalRoot: string): string;
|
|
52
|
+
/** One resolved frame — outcome rendered and hashed, ready for the (kind, hash) compare. */
|
|
53
|
+
export interface ResolvedGitStatusFrame {
|
|
54
|
+
kind: GitAnnouncementKind;
|
|
55
|
+
body: string;
|
|
56
|
+
hash: string;
|
|
57
|
+
/** Pre-rendered DEGRADED body + hash for the same probe cycle (present only when kind is
|
|
58
|
+
* `full`): the one-shot deterministic shrink target of the irreducible-core over-budget arc —
|
|
59
|
+
* computed at prepare time because the request-build path must not re-run probes. */
|
|
60
|
+
shrunk?: {
|
|
61
|
+
body: string;
|
|
62
|
+
hash: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** Render + hash one probe outcome (and its deterministic degraded shrink target when full). */
|
|
66
|
+
export declare function resolveGitStatusFrame(outcome: GitStatusProbeOutcome, canonicalRoot: string, degradedMaterial?: {
|
|
67
|
+
branch?: string;
|
|
68
|
+
dirty?: boolean;
|
|
69
|
+
}): ResolvedGitStatusFrame;
|
|
70
|
+
/**
|
|
71
|
+
* The run-local git-status lane state (one per run, on `Prepared`) — the coordination surface
|
|
72
|
+
* between prepare (probe resolution), the run loop (delivery + receipt + compaction re-assertion)
|
|
73
|
+
* and the request-build context handler (trim protection). Deliberately a plain mutable ref, the
|
|
74
|
+
* `announcedListingsRef` discipline.
|
|
75
|
+
*/
|
|
76
|
+
export interface GitStatusLaneRef {
|
|
77
|
+
/** This leg's resolved frame (undefined ⇒ hands-less leg: the lane is out of scope, announced
|
|
78
|
+
* state untouched — the env block equally carried no git facts for such a leg). */
|
|
79
|
+
frame?: ResolvedGitStatusFrame;
|
|
80
|
+
/** Canonical repo root the frame was hashed against. */
|
|
81
|
+
canonicalRoot?: string;
|
|
82
|
+
/** The announced state as THIS run knows it (seeded from the read ladder at leg start, advanced
|
|
83
|
+
* at each receipt) — mirrored onto the suspend checkpoint. `pending: true` ⇒ a re-announcement
|
|
84
|
+
* is owed (frame append failed / compaction restated pending); the next boundary retries. */
|
|
85
|
+
announced?: {
|
|
86
|
+
kind: GitAnnouncementKind;
|
|
87
|
+
hash: string;
|
|
88
|
+
entryId?: string;
|
|
89
|
+
pending?: true;
|
|
90
|
+
};
|
|
91
|
+
/** Exact WRAPPED text of the newest announced frame — the frame SEGMENT, on both carry forms
|
|
92
|
+
* (rescan doc-rot fix: r1 moved this off "the whole first-message text"; the contract here had
|
|
93
|
+
* kept the pre-r1 words). The context guard finds the carrier by CONTAINING this engine-held
|
|
94
|
+
* string (engine-region gated), protects that carrier as a replace-by-key slot — only the newest
|
|
95
|
+
* carrier is protected, older frames trim like ordinary history — and charges the irreducible
|
|
96
|
+
* core by THIS segment, never by the whole carrier (the objective riding the same message keeps
|
|
97
|
+
* its own overflow exit). */
|
|
98
|
+
protectedText?: string;
|
|
99
|
+
/** One-shot latch of the irreducible-core arc's DISCLOSURE: the request view substituted the
|
|
100
|
+
* degraded rendering at least once (the substitution itself is per-request deterministic; the
|
|
101
|
+
* disclosure + pending re-announcement fire only on the first). */
|
|
102
|
+
overBudgetShrunk?: boolean;
|
|
103
|
+
/** The exact WRAPPED frame segment of the protected carrier and its degraded substitution target
|
|
104
|
+
* (both `<system-reminder>`-shelled, exactly as delivered) — the irreducible-core shrink is a
|
|
105
|
+
* literal string replace of `find` with `replace` inside the carrier's text. Set at delivery
|
|
106
|
+
* alongside {@link GitStatusLaneRef.protectedText}; present only for a full-kind frame. */
|
|
107
|
+
wrappedShrink?: {
|
|
108
|
+
find: string;
|
|
109
|
+
replace: string;
|
|
110
|
+
};
|
|
111
|
+
/** Wired by the run loop once its queue exists: re-assert the current frame (compaction landing
|
|
112
|
+
* + boundary retry both call this). */
|
|
113
|
+
reassert?: () => Promise<void>;
|
|
114
|
+
/** F5 (falsification round 1) — the typed terminal's surface bridge: the loop converts a
|
|
115
|
+
* context-hook throw into a failure MESSAGE (text only), so the thrown `code` never reaches
|
|
116
|
+
* result assembly on its own. Set alongside the throw; the run loop lifts it into
|
|
117
|
+
* `TaskResult.errorCode`. */
|
|
118
|
+
terminalCode?: "irreducible_core_over_budget";
|
|
119
|
+
/** F4 (falsification round 1) — the receipt's mirror write, PARKED instead of fired: a
|
|
120
|
+
* fire-and-forget CAS append from inside the message_end walk can race the loop's own next
|
|
121
|
+
* transcript append and fail the CRITICAL write with a conflict. The run loop flushes this at
|
|
122
|
+
* serialization points only (turn boundary, prompt settle); an unflushed slot at suspend is
|
|
123
|
+
* covered by the checkpoint rung (the frame IS on the branch — visibility check passes). */
|
|
124
|
+
mirrorOwed?: {
|
|
125
|
+
kind: GitAnnouncementKind;
|
|
126
|
+
hash: string;
|
|
127
|
+
entryId: string;
|
|
128
|
+
};
|
|
129
|
+
/** The duplicate-tolerant receipt slot: set when a frame delivery is in flight, settled by the
|
|
130
|
+
* run loop's `message_end` walk when the CARRYING message commits (matched on the exact
|
|
131
|
+
* engine-held message text). Commit-on-receipt, never commit-before-append — the git lane's
|
|
132
|
+
* error asymmetry is the REVERSE of the listing lane's (a false "announced" = stale git facts
|
|
133
|
+
* forever; a duplicate frame = a few idempotent kilobytes). */
|
|
134
|
+
pendingReceipt?: {
|
|
135
|
+
text: string;
|
|
136
|
+
commit: (entryId: string) => void;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* prepare-side probe half of the lane (H4, extracted from prepareTask under the design/238 D-7
|
|
141
|
+
* body ratchet): run the CC-shape snapshot round-trip through the SAME ExecutionEnv seam when the
|
|
142
|
+
* §E14 probe confirmed a repo, resolve the outcome through the §4.3 unified kind ladder, and hash
|
|
143
|
+
* the rendered frame with the canonical repo root bound in. `envFacts` carries the §E14 results
|
|
144
|
+
* (read-only here). Every degrade names its reason through `onDegrade` — including the sentinel
|
|
145
|
+
* MIS-SPLIT arm (parts !== 4), which previously dropped the snapshot with ZERO telemetry (the
|
|
146
|
+
* loud-bad-value fix). Returns the run's lane ref (empty on a hands-less leg).
|
|
147
|
+
*
|
|
148
|
+
* H4 anchor notes carried from the prepareTask body: four sections split by a sentinel line —
|
|
149
|
+
* main-branch inference (CC qP symref → [inferred, main, master] each show-ref → renderer falls
|
|
150
|
+
* back "main"), `git config user.name`, `git --no-optional-locks status --short`, and
|
|
151
|
+
* `git --no-optional-locks log --oneline -n 5` (CC-exact commands). 1.256 复审 MED-4: the two
|
|
152
|
+
* REQUIRED sections fail the WHOLE script with distinct exit codes (41 = status, 42 = log) so a
|
|
153
|
+
* failing status never half-renders as "(clean)"; both now DEGRADE the frame to the branch+dirty
|
|
154
|
+
* residual instead of silently skipping. The main-branch/user sections stay best-effort.
|
|
155
|
+
*/
|
|
156
|
+
export declare function probeGitStatusLane(args: {
|
|
157
|
+
executionEnv: Pick<ExecutionEnv, "exec" | "canonicalPath">;
|
|
158
|
+
envFacts: {
|
|
159
|
+
isGitRepo?: boolean;
|
|
160
|
+
gitBranch?: string;
|
|
161
|
+
gitDirty?: boolean;
|
|
162
|
+
gitWorktreeRoot?: string;
|
|
163
|
+
cwd?: string;
|
|
164
|
+
};
|
|
165
|
+
handsEnabled: boolean;
|
|
166
|
+
taskRoot: string;
|
|
167
|
+
onDegrade: (reason: string) => void;
|
|
168
|
+
}): Promise<GitStatusLaneRef>;
|
|
169
|
+
/**
|
|
170
|
+
* Request-build half of the trim protection (extracted from prepareTask's context handler under the
|
|
171
|
+
* same D-7 ratchet): wraps {@link protectGitFrame} with the lane ref's state — the substitution
|
|
172
|
+
* pair, the one-shot disclosure latch and the pending re-announcement on the first shrink — and
|
|
173
|
+
* converts the over-budget verdict into the LOUD typed terminal (`irreducible_core_over_budget`),
|
|
174
|
+
* never a pretended trim success. Returns the (possibly re-inserted / shrunk) request view.
|
|
175
|
+
*/
|
|
176
|
+
export declare function applyGitFrameGuard(args: {
|
|
177
|
+
before: AgentMessage[];
|
|
178
|
+
trimmed: AgentMessage[];
|
|
179
|
+
budgetTokens: number;
|
|
180
|
+
ref: GitStatusLaneRef;
|
|
181
|
+
charsPerToken?: number;
|
|
182
|
+
onDegrade: (message: string) => void;
|
|
183
|
+
}): AgentMessage[];
|
|
184
|
+
/**
|
|
185
|
+
* R2-1 + R3-1/R3-2 + r4-2 (falsification rounds 2-4) — the transcript-side classifier of engine
|
|
186
|
+
* git frames. The mirror plane is a CACHE of "which frame is newest"; the TRANSCRIPT is the truth,
|
|
187
|
+
* and the two diverge exactly when a mirror write was lost. This scan finds the NEWEST engine git
|
|
188
|
+
* frame on the branch, with TOP-LEVEL WRAPPED-UNIT matching:
|
|
189
|
+
* - positive frame: the wrapped unit's head (open tag + newline + the frame preamble);
|
|
190
|
+
* - tombstone: the exact wrapped unit (open tag + newline + tombstone body + newline + close tag);
|
|
191
|
+
* - the occurrence must sit inside the message's ENGINE region (engineMinted / enginePrefixChars
|
|
192
|
+
* / engineSegments — metadata gates, never user-text shape-guessing), AND at TOP LEVEL (r4-2:
|
|
193
|
+
* start-of-text or right after a close tag — a hook relay that QUOTES the exact frame unit
|
|
194
|
+
* nests it inside its own shell with prose before the open tag, and is rejected);
|
|
195
|
+
* - within one message the LAST top-level unit wins (textual order = issue order).
|
|
196
|
+
*/
|
|
197
|
+
export declare function newestEngineGitFrame(branch: SessionTreeEntry[]): {
|
|
198
|
+
entryId: string;
|
|
199
|
+
positive: boolean;
|
|
200
|
+
} | undefined;
|
|
201
|
+
/**
|
|
202
|
+
* Remove POSITIVE git_status wrapped units from an engine-region text before a downstream parser
|
|
203
|
+
* scans it (rescan P3): the frame embeds REPO-CONTROLLED lines (branch names, commit subjects —
|
|
204
|
+
* tag-neutralized at wrap, but plain text rides verbatim), and the listing-replay parser reads
|
|
205
|
+
* engine-region text as trusted state — a commit subject spelling a listing header could reset the
|
|
206
|
+
* announced-set to empty (one spurious roster re-announcement). Tombstone units are constants
|
|
207
|
+
* (zero repo text) and need no stripping. The wrap sanitizer neutralizes the system-reminder CLOSE
|
|
208
|
+
* TAG inside the body (not `<` generally — refuter-precision note), so a unit's body cannot
|
|
209
|
+
* contain the close tag and the first close tag after a head is that unit's own on every
|
|
210
|
+
* contiguous region sema mints; the ownership check below is defense-in-depth for foreign text.
|
|
211
|
+
*/
|
|
212
|
+
export declare function stripGitStatusUnits(text: string): string;
|
|
213
|
+
/**
|
|
214
|
+
* The readable-absence tombstone question (R2-1), answered by the classifier above: does the
|
|
215
|
+
* branch carry a still-context-visible POSITIVE engine frame as its newest git frame? A newest
|
|
216
|
+
* TOMBSTONE means the disowning already happened (no re-spam); no frame at all means a genuinely
|
|
217
|
+
* fresh lane (no tombstone out of nowhere).
|
|
218
|
+
*/
|
|
219
|
+
export declare function branchCarriesVisiblePositiveGitFrame(branch: SessionTreeEntry[]): boolean;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { GIT_SNAPSHOT_CC_PREAMBLE, buildGitSnapshot } from "../../prompts/default.js";
|
|
3
|
+
import { inlineUntrusted } from "../untrusted-text.js";
|
|
4
|
+
import { engineRegionCovers, protectGitFrame } from "../context-guard.js";
|
|
5
|
+
import { gitFrameContextVisible } from "../../internal/harness.js";
|
|
6
|
+
export const GIT_STATUS_FRAME_FORMAT_VERSION = 1;
|
|
7
|
+
export const GIT_STATUS_FRAME_PREAMBLE = "This is the git status observed while preparing this request. When the visible snapshot changes it will be re-sent in a later message — the most recent git status frame supersedes earlier ones.";
|
|
8
|
+
export const GIT_STATUS_UNAVAILABLE_BODY = "Git status is currently unavailable; the most recent git status frame above may be stale.";
|
|
9
|
+
export const GIT_STATUS_NON_REPO_BODY = "The working directory is no longer a git repository; earlier git status frames no longer apply.";
|
|
10
|
+
export const GIT_STATUS_ECHO_PREVIEW = {
|
|
11
|
+
full: "git status updated",
|
|
12
|
+
degraded: "git status updated (degraded: branch and dirtiness only)",
|
|
13
|
+
unavailable: "git status unavailable",
|
|
14
|
+
"non-repo": "git status: no longer a git repository",
|
|
15
|
+
};
|
|
16
|
+
function toWellFormedText(s) {
|
|
17
|
+
const native = s.toWellFormed;
|
|
18
|
+
if (typeof native === "function")
|
|
19
|
+
return native.call(s);
|
|
20
|
+
return s.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�");
|
|
21
|
+
}
|
|
22
|
+
export function renderGitStatusFrameBody(outcome) {
|
|
23
|
+
switch (outcome.kind) {
|
|
24
|
+
case "full": {
|
|
25
|
+
const body = outcome.snapshot.startsWith(GIT_SNAPSHOT_CC_PREAMBLE)
|
|
26
|
+
? GIT_STATUS_FRAME_PREAMBLE + outcome.snapshot.slice(GIT_SNAPSHOT_CC_PREAMBLE.length)
|
|
27
|
+
: `${GIT_STATUS_FRAME_PREAMBLE}\n\n${outcome.snapshot}`;
|
|
28
|
+
return toWellFormedText(body);
|
|
29
|
+
}
|
|
30
|
+
case "degraded": {
|
|
31
|
+
const lines = [GIT_STATUS_FRAME_PREAMBLE];
|
|
32
|
+
lines.push(`Current branch: ${inlineUntrusted(outcome.branch ?? "HEAD")}`);
|
|
33
|
+
if (outcome.dirty !== undefined) {
|
|
34
|
+
lines.push(`Git working tree: ${outcome.dirty ? "has uncommitted changes" : "clean"}`);
|
|
35
|
+
}
|
|
36
|
+
return toWellFormedText(lines.join("\n\n"));
|
|
37
|
+
}
|
|
38
|
+
case "unavailable":
|
|
39
|
+
return GIT_STATUS_UNAVAILABLE_BODY;
|
|
40
|
+
case "non-repo":
|
|
41
|
+
return GIT_STATUS_NON_REPO_BODY;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function hashGitStatusFrame(kind, body, canonicalRoot) {
|
|
45
|
+
return `sha256:${createHash("sha256")
|
|
46
|
+
.update(`${GIT_STATUS_FRAME_FORMAT_VERSION}\u0000${canonicalRoot}\u0000${kind}\u0000${body}`)
|
|
47
|
+
.digest("hex")}`;
|
|
48
|
+
}
|
|
49
|
+
export function resolveGitStatusFrame(outcome, canonicalRoot, degradedMaterial) {
|
|
50
|
+
const body = renderGitStatusFrameBody(outcome);
|
|
51
|
+
const resolved = {
|
|
52
|
+
kind: outcome.kind,
|
|
53
|
+
body,
|
|
54
|
+
hash: hashGitStatusFrame(outcome.kind, body, canonicalRoot),
|
|
55
|
+
};
|
|
56
|
+
if (outcome.kind === "full") {
|
|
57
|
+
const shrunkBody = renderGitStatusFrameBody({ kind: "degraded", ...(degradedMaterial ?? {}) });
|
|
58
|
+
resolved.shrunk = { body: shrunkBody, hash: hashGitStatusFrame("degraded", shrunkBody, canonicalRoot) };
|
|
59
|
+
}
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
62
|
+
export async function probeGitStatusLane(args) {
|
|
63
|
+
const { executionEnv, envFacts, handsEnabled, taskRoot, onDegrade } = args;
|
|
64
|
+
const ref = {};
|
|
65
|
+
if (!handsEnabled)
|
|
66
|
+
return ref;
|
|
67
|
+
let outcome;
|
|
68
|
+
if (envFacts.isGitRepo === true) {
|
|
69
|
+
const SEP = "@@SEMA_ENV_GIT_SPLIT@@";
|
|
70
|
+
outcome = {
|
|
71
|
+
kind: "degraded",
|
|
72
|
+
...(envFacts.gitBranch !== undefined ? { branch: envFacts.gitBranch } : {}),
|
|
73
|
+
...(envFacts.gitDirty !== undefined ? { dirty: envFacts.gitDirty } : {}),
|
|
74
|
+
};
|
|
75
|
+
try {
|
|
76
|
+
const snap = await executionEnv.exec(`(m=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null); m=\${m#origin/}; for s in "$m" main master; do if [ -n "$s" ] && git show-ref --verify --quiet "refs/remotes/origin/$s"; then echo "$s"; break; fi; done) || true; echo "${SEP}"; (git config user.name 2>/dev/null || true); echo "${SEP}"; gs=$(git --no-optional-locks status --short) || exit 41; printf '%s\\n' "$gs"; echo "${SEP}"; gl=$(git --no-optional-locks log --oneline -n 5) || exit 42; printf '%s\\n' "$gl"`, { cwd: envFacts.cwd, timeout: 10 });
|
|
77
|
+
if (snap.ok && snap.value.exitCode === 0) {
|
|
78
|
+
const parts = snap.value.stdout.split(`${SEP}\n`);
|
|
79
|
+
if (parts.length === 4) {
|
|
80
|
+
outcome = {
|
|
81
|
+
kind: "full",
|
|
82
|
+
snapshot: buildGitSnapshot({
|
|
83
|
+
branch: envFacts.gitBranch ?? "HEAD",
|
|
84
|
+
mainBranch: parts[0].trim() || "main",
|
|
85
|
+
...(parts[1].trim() ? { userName: parts[1].trim() } : {}),
|
|
86
|
+
status: parts[2],
|
|
87
|
+
log: parts[3],
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
onDegrade(`sentinel mis-split (${parts.length} sections, expected 4)`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
onDegrade(snap.ok
|
|
97
|
+
? snap.value.exitCode === 41
|
|
98
|
+
? "git status failed (exit 41)"
|
|
99
|
+
: snap.value.exitCode === 42
|
|
100
|
+
? "git log failed (exit 42)"
|
|
101
|
+
: `git exited ${snap.value.exitCode}`
|
|
102
|
+
: `exec failed: ${snap.error.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
onDegrade(err instanceof Error ? err.message : String(err));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (envFacts.isGitRepo === false) {
|
|
110
|
+
outcome = { kind: "non-repo" };
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
outcome = { kind: "unavailable" };
|
|
114
|
+
}
|
|
115
|
+
const rootRaw = envFacts.gitWorktreeRoot ?? envFacts.cwd ?? taskRoot;
|
|
116
|
+
let canonicalRoot = rootRaw;
|
|
117
|
+
try {
|
|
118
|
+
const c = await executionEnv.canonicalPath(rootRaw);
|
|
119
|
+
if (c.ok)
|
|
120
|
+
canonicalRoot = c.value;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
}
|
|
124
|
+
ref.canonicalRoot = canonicalRoot;
|
|
125
|
+
ref.frame = resolveGitStatusFrame(outcome, canonicalRoot, {
|
|
126
|
+
...(envFacts.gitBranch !== undefined ? { branch: envFacts.gitBranch } : {}),
|
|
127
|
+
...(envFacts.gitDirty !== undefined ? { dirty: envFacts.gitDirty } : {}),
|
|
128
|
+
});
|
|
129
|
+
return ref;
|
|
130
|
+
}
|
|
131
|
+
export function applyGitFrameGuard(args) {
|
|
132
|
+
const { before, trimmed, budgetTokens, ref, charsPerToken, onDegrade } = args;
|
|
133
|
+
if (ref.protectedText === undefined)
|
|
134
|
+
return trimmed;
|
|
135
|
+
const guarded = protectGitFrame(before, trimmed, budgetTokens, {
|
|
136
|
+
protectedText: ref.protectedText,
|
|
137
|
+
...(ref.frame?.kind === "full" && ref.frame.shrunk !== undefined && ref.wrappedShrink !== undefined ? { substitute: ref.wrappedShrink } : {}),
|
|
138
|
+
}, charsPerToken);
|
|
139
|
+
if (guarded.action === "over_budget") {
|
|
140
|
+
ref.terminalCode = "irreducible_core_over_budget";
|
|
141
|
+
throw Object.assign(new Error("irreducible core over budget: the compaction summary plus the git status frame alone exceed the request budget — no trim can produce an honest request"), { code: "irreducible_core_over_budget" });
|
|
142
|
+
}
|
|
143
|
+
if (guarded.action === "shrunk" && !ref.overBudgetShrunk) {
|
|
144
|
+
ref.overBudgetShrunk = true;
|
|
145
|
+
if (ref.announced !== undefined)
|
|
146
|
+
ref.announced = { ...ref.announced, pending: true };
|
|
147
|
+
onDegrade("git status frame degraded under budget pressure: the full snapshot no longer fits the request budget — requests carry the branch+dirty residual; the degraded view will be re-announced");
|
|
148
|
+
}
|
|
149
|
+
return guarded.messages;
|
|
150
|
+
}
|
|
151
|
+
export function newestEngineGitFrame(branch) {
|
|
152
|
+
const positiveHead = `<system-reminder>\n${GIT_STATUS_FRAME_PREAMBLE}`;
|
|
153
|
+
const tombUnits = [`<system-reminder>\n${GIT_STATUS_UNAVAILABLE_BODY}\n</system-reminder>`, `<system-reminder>\n${GIT_STATUS_NON_REPO_BODY}\n</system-reminder>`];
|
|
154
|
+
const topLevel = (text, at) => {
|
|
155
|
+
if (at === 0)
|
|
156
|
+
return true;
|
|
157
|
+
const before = text.slice(0, at).replace(/\n+$/, "");
|
|
158
|
+
return before === "" || before.endsWith("</system-reminder>");
|
|
159
|
+
};
|
|
160
|
+
const allTopLevel = (text, needle, m) => {
|
|
161
|
+
const out = [];
|
|
162
|
+
for (let at = text.indexOf(needle); at !== -1; at = text.indexOf(needle, at + 1)) {
|
|
163
|
+
if (topLevel(text, at) && engineRegionCovers(m, at, needle.length))
|
|
164
|
+
out.push(at);
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
};
|
|
168
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
169
|
+
const entry = branch[i];
|
|
170
|
+
if (entry === undefined || entry.type !== "message")
|
|
171
|
+
continue;
|
|
172
|
+
const m = entry.message;
|
|
173
|
+
if (m.role !== "user")
|
|
174
|
+
continue;
|
|
175
|
+
const c = m.content;
|
|
176
|
+
const text = typeof c === "string" ? c : Array.isArray(c) && c.length >= 1 && c[0].type === "text" ? (c[0].text ?? "") : undefined;
|
|
177
|
+
if (text === undefined)
|
|
178
|
+
continue;
|
|
179
|
+
let best;
|
|
180
|
+
for (const at of allTopLevel(text, positiveHead, m)) {
|
|
181
|
+
if (best === undefined || at > best.at)
|
|
182
|
+
best = { at, positive: true };
|
|
183
|
+
}
|
|
184
|
+
for (const unit of tombUnits) {
|
|
185
|
+
for (const at of allTopLevel(text, unit, m)) {
|
|
186
|
+
if (best === undefined || at > best.at)
|
|
187
|
+
best = { at, positive: false };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (best !== undefined)
|
|
191
|
+
return { entryId: entry.id, positive: best.positive };
|
|
192
|
+
}
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
export function stripGitStatusUnits(text) {
|
|
196
|
+
const head = `<system-reminder>\n${GIT_STATUS_FRAME_PREAMBLE}`;
|
|
197
|
+
const close = "</system-reminder>";
|
|
198
|
+
let out = text;
|
|
199
|
+
for (let at = out.indexOf(head); at !== -1; at = out.indexOf(head)) {
|
|
200
|
+
const end = out.indexOf(close, at);
|
|
201
|
+
if (end === -1)
|
|
202
|
+
break;
|
|
203
|
+
if (out.slice(at + head.length, end).includes("<system-reminder>"))
|
|
204
|
+
break;
|
|
205
|
+
out = out.slice(0, at) + out.slice(end + close.length);
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
export function branchCarriesVisiblePositiveGitFrame(branch) {
|
|
210
|
+
const newest = newestEngineGitFrame(branch);
|
|
211
|
+
return newest !== undefined && newest.positive && gitFrameContextVisible(branch, newest.entryId);
|
|
212
|
+
}
|
|
@@ -17,6 +17,7 @@ import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-de
|
|
|
17
17
|
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
18
18
|
import { type OutputRef, type BlockedRef, type SkillListingEntry } from "./synthetic-tools.js";
|
|
19
19
|
import type { MemoryEngine } from "../memory-engine/engine.js";
|
|
20
|
+
import { type GitStatusLaneRef } from "./git-status-frame.js";
|
|
20
21
|
import { type ToolManifestRow } from "../../prompt-assembly/tool-catalog.js";
|
|
21
22
|
import type { ToolDisclosureManifest } from "../trace.js";
|
|
22
23
|
import type { TaskNotificationPayload } from "../task-notification.js";
|
|
@@ -747,6 +748,12 @@ export interface Prepared {
|
|
|
747
748
|
skills?: readonly string[];
|
|
748
749
|
models?: readonly string[];
|
|
749
750
|
};
|
|
751
|
+
/** env-tail migration (#254 shape) — the git-status frame lane's run-local state: this leg's
|
|
752
|
+
* resolved frame (probe outcome rendered + hashed at prepare), the announced `(kind, hash)`
|
|
753
|
+
* mirror the checkpoint serializer reads, the trim-protection slot the request-build context
|
|
754
|
+
* handler matches on, and the re-assert closure the compaction landing + boundary retry call.
|
|
755
|
+
* Always present (empty object on a hands-less leg — the lane is then out of scope). */
|
|
756
|
+
gitStatusRef: GitStatusLaneRef;
|
|
750
757
|
/** G1 通告层 — narrow post-compact getter over the process task registry: THIS run's visible
|
|
751
758
|
* pending/running background tasks (same owner/scope/session identity the TaskOutput/TaskStop tools
|
|
752
759
|
* use), as a bounded display projection (id/description/status — never handles/env/abort). Called by
|
|
@@ -1244,6 +1251,15 @@ export interface RunInternals {
|
|
|
1244
1251
|
* stamping. TRUSTED run-scoped channel (never a {@link TaskSpec} field).
|
|
1245
1252
|
*/
|
|
1246
1253
|
delegationTaskType?: import("../types.js").DelegationTaskType;
|
|
1254
|
+
/**
|
|
1255
|
+
* #258 — the registry row's stop-cycle generation this run executes as (fresh spawn = 1, a
|
|
1256
|
+
* revival's bumped counter), threaded by the BACKGROUND delegation lanes from the registry's own
|
|
1257
|
+
* `cycleSeq` so every `task_progress` tick the run mints carries it as `seq` (same axis as
|
|
1258
|
+
* `TaskNotificationPayload.seq` / `BackgroundChildEvent.seq`). Absent for runs with no `a*` row
|
|
1259
|
+
* (sync children, workflow agents, top-level) — same absence-is-a-fact posture as
|
|
1260
|
+
* {@link delegationTaskType} above. TRUSTED run-scoped channel (never a TaskSpec field).
|
|
1261
|
+
*/
|
|
1262
|
+
cycleSeq?: number;
|
|
1247
1263
|
/** δ 批 [1498]⑦/A-3 — the ROOT host session of the whole delegation tree (fixed point: the
|
|
1248
1264
|
* spawner passes its own `ctx.rootSessionId ?? ctx.sessionId`, so depth 1 gets the host session
|
|
1249
1265
|
* and every deeper level inherits it verbatim). `parentSessionId` is the IMMEDIATE spawner —
|
|
@@ -56,7 +56,8 @@ import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js"
|
|
|
56
56
|
import { NAMESPACED_NAME_SHAPES, prepareSafetyScan } from "./prepare-safety-scan.js";
|
|
57
57
|
import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
|
|
58
58
|
import { prepareWorkspaceRestore, rebaseWorkspacePath, remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./prepare-workspace-restore.js";
|
|
59
|
-
import { defaultPromptProvider, buildEnvironmentContext,
|
|
59
|
+
import { defaultPromptProvider, buildEnvironmentContext, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
60
|
+
import { applyGitFrameGuard, probeGitStatusLane } from "./git-status-frame.js";
|
|
60
61
|
import { assemblePrompt } from "../../prompt-assembly/assemble.js";
|
|
61
62
|
import { auditToolCollisions, getToolContract, projectToolManifest } from "../../prompt-assembly/tool-catalog.js";
|
|
62
63
|
import { resolveEpochAgainstBundled } from "../../prompt-assembly/epoch.js";
|
|
@@ -1875,38 +1876,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1875
1876
|
}
|
|
1876
1877
|
catch {
|
|
1877
1878
|
}
|
|
1878
|
-
if (envFacts.isGitRepo === true) {
|
|
1879
|
-
const SEP = "@@SEMA_ENV_GIT_SPLIT@@";
|
|
1880
|
-
try {
|
|
1881
|
-
const snap = await executionEnv.exec(`(m=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null); m=\${m#origin/}; for s in "$m" main master; do if [ -n "$s" ] && git show-ref --verify --quiet "refs/remotes/origin/$s"; then echo "$s"; break; fi; done) || true; echo "${SEP}"; (git config user.name 2>/dev/null || true); echo "${SEP}"; gs=$(git --no-optional-locks status --short) || exit 41; printf '%s\\n' "$gs"; echo "${SEP}"; gl=$(git --no-optional-locks log --oneline -n 5) || exit 42; printf '%s\\n' "$gl"`, { cwd: envFacts.cwd, timeout: 10 });
|
|
1882
|
-
if (snap.ok && snap.value.exitCode === 0) {
|
|
1883
|
-
const parts = snap.value.stdout.split(`${SEP}\n`);
|
|
1884
|
-
if (parts.length === 4) {
|
|
1885
|
-
envFacts.gitSnapshot = buildGitSnapshot({
|
|
1886
|
-
branch: envFacts.gitBranch ?? "HEAD",
|
|
1887
|
-
mainBranch: parts[0].trim() || "main",
|
|
1888
|
-
...(parts[1].trim() ? { userName: parts[1].trim() } : {}),
|
|
1889
|
-
status: parts[2],
|
|
1890
|
-
log: parts[3],
|
|
1891
|
-
});
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
else {
|
|
1895
|
-
const reason = snap.ok
|
|
1896
|
-
? snap.value.exitCode === 41
|
|
1897
|
-
? "git status failed (exit 41)"
|
|
1898
|
-
: snap.value.exitCode === 42
|
|
1899
|
-
? "git log failed (exit 42)"
|
|
1900
|
-
: `git exited ${snap.value.exitCode}`
|
|
1901
|
-
: `exec failed: ${snap.error.message}`;
|
|
1902
|
-
deps.onError?.(new Error(`env git snapshot skipped — ${reason}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
catch (err) {
|
|
1906
|
-
deps.onError?.(new Error(`env git snapshot skipped — ${err instanceof Error ? err.message : String(err)}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
1879
|
}
|
|
1880
|
+
const gitStatusRef = await probeGitStatusLane({
|
|
1881
|
+
executionEnv,
|
|
1882
|
+
envFacts,
|
|
1883
|
+
handsEnabled,
|
|
1884
|
+
taskRoot: taskRootFinal,
|
|
1885
|
+
onDegrade: (reason) => deps.onError?.(new Error(`env git snapshot degraded — ${reason}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" }),
|
|
1886
|
+
});
|
|
1910
1887
|
if (toolFaceSnapshot.exclude !== undefined && toolFaceSnapshot.exclude.length > 0) {
|
|
1911
1888
|
const excluded = new Set(toolFaceSnapshot.exclude);
|
|
1912
1889
|
for (let i = tools.length - 1; i >= 0; i--)
|
|
@@ -3577,6 +3554,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3577
3554
|
...(announcedListingsRef.models !== undefined ? { models: [...announcedListingsRef.models] } : {}),
|
|
3578
3555
|
}
|
|
3579
3556
|
: undefined,
|
|
3557
|
+
gitAnnouncement: gitStatusRef.announced !== undefined ? { ...gitStatusRef.announced } : undefined,
|
|
3580
3558
|
delegationProvenance: internals?.delegationProvenance !== undefined ? { ...internals.delegationProvenance.ref.current } : undefined,
|
|
3581
3559
|
});
|
|
3582
3560
|
const commitSuspendSaga = async (token, cp, remoteEnv, remoteHandle) => {
|
|
@@ -4388,6 +4366,20 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4388
4366
|
ts: Date.now(),
|
|
4389
4367
|
}));
|
|
4390
4368
|
}
|
|
4369
|
+
trimmed = applyGitFrameGuard({
|
|
4370
|
+
before: edited,
|
|
4371
|
+
trimmed,
|
|
4372
|
+
budgetTokens: guardAt,
|
|
4373
|
+
ref: gitStatusRef,
|
|
4374
|
+
charsPerToken,
|
|
4375
|
+
onDegrade: (message) => {
|
|
4376
|
+
try {
|
|
4377
|
+
deps.onError?.(new Error(message), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
|
|
4378
|
+
}
|
|
4379
|
+
catch {
|
|
4380
|
+
}
|
|
4381
|
+
},
|
|
4382
|
+
});
|
|
4391
4383
|
const swept = dropOrphanToolResults(trimmed);
|
|
4392
4384
|
if (swept.dropped.length > 0) {
|
|
4393
4385
|
try {
|
|
@@ -4404,7 +4396,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4404
4396
|
mediaCapped !== capped ||
|
|
4405
4397
|
edited !== mediaCapped ||
|
|
4406
4398
|
trimDroppedMessages ||
|
|
4407
|
-
swept.dropped.length > 0
|
|
4399
|
+
swept.dropped.length > 0 ||
|
|
4400
|
+
gitStatusRef.overBudgetShrunk === true;
|
|
4408
4401
|
return { messages: swept.messages };
|
|
4409
4402
|
});
|
|
4410
4403
|
const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
|
|
@@ -4593,7 +4586,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4593
4586
|
const effectiveReadFaceObserved = carrierReadFace();
|
|
4594
4587
|
const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
|
|
4595
4588
|
const preparedHolder = {};
|
|
4596
|
-
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath: taskRootFinal, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
4589
|
+
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath: taskRootFinal, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
4597
4590
|
const prepared = buildPrepared();
|
|
4598
4591
|
preparedHolder.current = prepared;
|
|
4599
4592
|
return prepared;
|