@cydm/pie 2.7.7 → 2.7.9

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/cli.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  logTransportLifecycle,
24
24
  migrateConfigFromAgentDir,
25
25
  truncateHeadTail
26
- } from "./chunks/chunk-IU5L5DED.js";
26
+ } from "./chunks/chunk-ABZOXNDK.js";
27
27
  import {
28
28
  resolveCliProjectRoot
29
29
  } from "./chunks/chunk-WLFOBECN.js";
@@ -72,6 +72,7 @@ import {
72
72
  interactionAttentionResolution,
73
73
  isCompactSummaryMessage,
74
74
  isExtensionEnabled,
75
+ isHostContextBlock,
75
76
  isToolAllowedInPlanMode,
76
77
  maybeAdvanceTodoExecutionState,
77
78
  modalityForReadFileUnderstandingKind,
@@ -87,8 +88,8 @@ import {
87
88
  shouldPreserveExecutionStateForUserText,
88
89
  supersedeExecutionState,
89
90
  verifyPreparedCompactionCommit
90
- } from "./chunks/chunk-UPGEXDEQ.js";
91
- import "./chunks/chunk-W5B3OXHQ.js";
91
+ } from "./chunks/chunk-AX5QEIKP.js";
92
+ import "./chunks/chunk-5SP2H5QK.js";
92
93
  import {
93
94
  Deref,
94
95
  EMPTY_ASSISTANT_CONTENT_ERROR,
@@ -113,7 +114,7 @@ import {
113
114
  sortToolModelCandidatesByCapability,
114
115
  streamSimple,
115
116
  type_exports
116
- } from "./chunks/chunk-2FEDB5GR.js";
117
+ } from "./chunks/chunk-SMGBZQI5.js";
117
118
  import {
118
119
  IsArray,
119
120
  IsBigInt,
@@ -56591,6 +56592,10 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
56591
56592
  if (!actions?.registerProvider) throw new Error("registerProvider is not available in this host mode");
56592
56593
  return actions.registerProvider(name, config);
56593
56594
  },
56595
+ registerHostEnvelopeProjector(projector) {
56596
+ if (!actions?.registerHostEnvelopeProjector) throw new Error("registerHostEnvelopeProjector is not available in this host mode");
56597
+ return actions.registerHostEnvelopeProjector(projector);
56598
+ },
56594
56599
  async loginProvider(name) {
56595
56600
  if (!actions?.loginProvider) throw new Error("loginProvider is not available in this host mode");
56596
56601
  return actions.loginProvider(name);
@@ -64348,6 +64353,10 @@ var ExtensionRunner = class {
64348
64353
  if (!runner.actions.registerProvider) throw new Error("registerProvider is not available in this host mode");
64349
64354
  return runner.trackUnregisterHandle(runner.actions.registerProvider(name, config));
64350
64355
  },
64356
+ registerHostEnvelopeProjector: (projector) => {
64357
+ if (!runner.actions.registerHostEnvelopeProjector) throw new Error("registerHostEnvelopeProjector is not available in this host mode");
64358
+ return runner.trackUnregisterHandle(runner.actions.registerHostEnvelopeProjector(projector));
64359
+ },
64351
64360
  loginProvider: async (name) => {
64352
64361
  if (!runner.actions.loginProvider) throw new Error("loginProvider is not available in this host mode");
64353
64362
  return runner.actions.loginProvider(name);
@@ -76670,6 +76679,391 @@ function renderCompactionDiffPanel(target, stats) {
76670
76679
  target.safeRequestRender();
76671
76680
  }
76672
76681
 
76682
+ // src/runtime/runtime-mode-context.ts
76683
+ var RUNTIME_MODE_ENVELOPE_KIND = "pie.runtimeMode";
76684
+ var RUNTIME_MODE_ENVELOPE_VERSION = 1;
76685
+ function runtimeModeEnvelopeRegistry() {
76686
+ return sharedRuntimeModeRegistry ??= createHostEnvelopeProjectorRegistry([{
76687
+ kind: RUNTIME_MODE_ENVELOPE_KIND,
76688
+ version: RUNTIME_MODE_ENVELOPE_VERSION,
76689
+ project: (data) => buildRuntimeModeContext(runtimeModeStateFromEnvelope(data))
76690
+ }]);
76691
+ }
76692
+ var sharedRuntimeModeRegistry;
76693
+ function runtimeModeStateFromEnvelope(data) {
76694
+ return {
76695
+ planMode: data.planMode === "planning" ? "planning" : "off",
76696
+ yoloMode: data.yoloMode === true,
76697
+ filesystemScope: data.filesystemScope === "all" ? "all" : "workspace",
76698
+ pendingTransition: typeof data.pendingTransition === "string" ? data.pendingTransition : void 0,
76699
+ activeToolNames: Array.isArray(data.activeToolNames) ? data.activeToolNames.filter((name) => typeof name === "string") : [],
76700
+ planDisabledToolNames: Array.isArray(data.planDisabledToolNames) ? data.planDisabledToolNames.filter((name) => typeof name === "string") : [],
76701
+ currentDate: typeof data.currentDate === "string" ? data.currentDate : void 0,
76702
+ timeZone: typeof data.timeZone === "string" ? data.timeZone : void 0
76703
+ };
76704
+ }
76705
+ function runtimeModeEnvelopeData(state) {
76706
+ return {
76707
+ planMode: state.planMode,
76708
+ yoloMode: state.yoloMode,
76709
+ filesystemScope: state.filesystemScope,
76710
+ ...state.pendingTransition ? { pendingTransition: state.pendingTransition } : {},
76711
+ activeToolNames: [...state.activeToolNames],
76712
+ planDisabledToolNames: [...state.planDisabledToolNames],
76713
+ ...state.currentDate ? { currentDate: state.currentDate } : {},
76714
+ ...state.timeZone ? { timeZone: state.timeZone } : {}
76715
+ };
76716
+ }
76717
+ function runtimeModeEnvelopeBlock(state) {
76718
+ return {
76719
+ type: "hostContext",
76720
+ kind: RUNTIME_MODE_ENVELOPE_KIND,
76721
+ version: RUNTIME_MODE_ENVELOPE_VERSION,
76722
+ data: runtimeModeEnvelopeData(state)
76723
+ };
76724
+ }
76725
+ function isAgentMessage(value) {
76726
+ return !!value && typeof value === "object" && "role" in value;
76727
+ }
76728
+ function prependRuntimeModeBlockToPrompt(input, block) {
76729
+ if (!block) return input;
76730
+ if (typeof input === "string") {
76731
+ return [{ ...block }, { type: "text", text: input }];
76732
+ }
76733
+ if (Array.isArray(input)) {
76734
+ if (input.length > 0 && isAgentMessage(input[0])) {
76735
+ return prependBlockToMessages(input, block);
76736
+ }
76737
+ return upsertLeadingHostContextBlock(input, block);
76738
+ }
76739
+ if (isAgentMessage(input)) {
76740
+ return prependBlockToMessages([input], block)[0];
76741
+ }
76742
+ return [block, ...input];
76743
+ }
76744
+ function upsertLeadingHostContextBlock(content, block) {
76745
+ let runEnd = 0;
76746
+ let sameKindIndex = -1;
76747
+ while (runEnd < content.length) {
76748
+ const entry = content[runEnd];
76749
+ if (entry?.type !== "hostContext") break;
76750
+ if (sameKindIndex < 0 && entry.kind === block.kind) sameKindIndex = runEnd;
76751
+ runEnd += 1;
76752
+ }
76753
+ if (sameKindIndex >= 0) {
76754
+ const copy = [...content];
76755
+ copy[sameKindIndex] = block;
76756
+ for (let index = runEnd - 1; index > sameKindIndex; index--) {
76757
+ const entry = copy[index];
76758
+ if (entry?.type === "hostContext" && entry.kind === block.kind) copy.splice(index, 1);
76759
+ }
76760
+ return copy;
76761
+ }
76762
+ return [...content.slice(0, runEnd), block, ...content.slice(runEnd)];
76763
+ }
76764
+ function prependBlockToMessages(messages, block) {
76765
+ const next = [...messages];
76766
+ let target = -1;
76767
+ for (let index = next.length - 1; index >= 0; index--) {
76768
+ if (next[index]?.role === "user") {
76769
+ target = index;
76770
+ break;
76771
+ }
76772
+ }
76773
+ if (target < 0) {
76774
+ next.push({ role: "user", content: [block], timestamp: Date.now() });
76775
+ return next;
76776
+ }
76777
+ const message = next[target];
76778
+ if (Array.isArray(message.content)) {
76779
+ next[target] = { ...message, content: upsertLeadingHostContextBlock(message.content, block) };
76780
+ } else if (typeof message.content === "string") {
76781
+ next[target] = { ...message, content: [block, { type: "text", text: message.content }] };
76782
+ } else {
76783
+ next.splice(target, 0, { role: "user", content: [block], timestamp: Date.now() });
76784
+ }
76785
+ return next;
76786
+ }
76787
+ var RUNTIME_MODE_CONTEXT_MARKER = "<runtime-mode-context>";
76788
+ var RUNTIME_MODE_CONTEXT_END_MARKER = "</runtime-mode-context>";
76789
+ function buildRuntimeModeContext(state) {
76790
+ const lines = [
76791
+ RUNTIME_MODE_CONTEXT_MARKER,
76792
+ "Current runtime mode:"
76793
+ ];
76794
+ if (state.planMode === "planning") {
76795
+ lines.push(
76796
+ "- Plan mode: active (workspace read-only; plan_scratch permits session-local temporary drafts; submit the finished plan by calling plan_submit with the ordered steps for user approval)."
76797
+ );
76798
+ if (state.planDisabledToolNames.length > 0) {
76799
+ lines.push(
76800
+ `- Disabled this turn by plan mode (calls are denied): ${state.planDisabledToolNames.join(", ")}. Do not call them while planning.`
76801
+ );
76802
+ }
76803
+ } else {
76804
+ lines.push("- Plan mode: off.");
76805
+ }
76806
+ lines.push(
76807
+ `- YOLO mode: ${state.yoloMode ? "on (filesystem sandbox directory restrictions are disabled)" : "off (workspace/protected-path restrictions apply)"}.`,
76808
+ `- Filesystem scope: ${state.filesystemScope === "all" ? "all local paths may be passed directly to file tools when permitted" : "workspace paths and configured safe roots only"}.`
76809
+ );
76810
+ if (state.pendingTransition) {
76811
+ const transitionText = {
76812
+ entered_yolo: "YOLO mode was just enabled for this turn.",
76813
+ exited_yolo: "YOLO mode was just disabled; do not assume previous absolute-path access still applies.",
76814
+ entered_plan: "Plan mode was just enabled; analyze and plan without changing the workspace. Use plan_scratch for temporary drafts, then submit the finished plan by calling plan_submit with the ordered steps for user approval.",
76815
+ exited_plan: "Plan mode was just disabled; execution tools may be used when the task requires them."
76816
+ };
76817
+ lines.push(`- Transition: ${transitionText[state.pendingTransition]}`);
76818
+ }
76819
+ if (state.currentDate) {
76820
+ lines.push(`- Current date: ${state.currentDate}${state.timeZone ? ` (${state.timeZone})` : ""}.`);
76821
+ }
76822
+ if (state.activeToolNames.length > 0) {
76823
+ lines.push(`- Active tools: ${state.activeToolNames.join(", ")}.`);
76824
+ }
76825
+ lines.push(RUNTIME_MODE_CONTEXT_END_MARKER);
76826
+ return lines.join("\n");
76827
+ }
76828
+ function runtimeModeBlockKey(state) {
76829
+ return JSON.stringify({
76830
+ planMode: state.planMode,
76831
+ yoloMode: state.yoloMode,
76832
+ filesystemScope: state.filesystemScope,
76833
+ currentDate: state.currentDate ?? null,
76834
+ timeZone: state.timeZone ?? null,
76835
+ activeToolNames: state.activeToolNames,
76836
+ planDisabledToolNames: state.planDisabledToolNames
76837
+ });
76838
+ }
76839
+ function shouldInjectRuntimeModeBlock(lastKey, state) {
76840
+ if (lastKey === null) return true;
76841
+ return runtimeModeBlockKey(state) !== lastKey;
76842
+ }
76843
+ function runtimeModeTraceData(state) {
76844
+ return {
76845
+ yoloMode: state.yoloMode,
76846
+ planMode: state.planMode,
76847
+ filesystemScope: state.filesystemScope,
76848
+ pendingTransition: state.pendingTransition,
76849
+ currentDate: state.currentDate,
76850
+ timeZone: state.timeZone,
76851
+ activeToolCount: state.activeToolNames.length,
76852
+ planDisabledToolCount: state.planDisabledToolNames.length
76853
+ };
76854
+ }
76855
+ function currentDateInZone(timeZone) {
76856
+ const parts = new Intl.DateTimeFormat("en-US", {
76857
+ year: "numeric",
76858
+ month: "2-digit",
76859
+ day: "2-digit",
76860
+ timeZone
76861
+ }).formatToParts(/* @__PURE__ */ new Date());
76862
+ const part = (type) => parts.find((p) => p.type === type)?.value ?? "00";
76863
+ return `${part("year")}-${part("month")}-${part("day")}`;
76864
+ }
76865
+ var RUNTIME_MODE_BLOCK_START_MARKER = "<runtime-mode-context>";
76866
+ function leadingRuntimeBlock(text) {
76867
+ const withoutLeadingWhitespace = text.replace(/^[\t ]+/, "");
76868
+ if (!withoutLeadingWhitespace.startsWith(RUNTIME_MODE_BLOCK_START_MARKER)) return null;
76869
+ const markerStart = text.length - withoutLeadingWhitespace.length;
76870
+ const endIndex = text.indexOf(RUNTIME_MODE_CONTEXT_END_MARKER, markerStart);
76871
+ if (endIndex < 0) return null;
76872
+ const block = text.slice(markerStart, endIndex + RUNTIME_MODE_CONTEXT_END_MARKER.length);
76873
+ const rest = text.slice(endIndex + RUNTIME_MODE_CONTEXT_END_MARKER.length).replace(/^[\t ]*(?:\r?\n){0,2}/, "");
76874
+ return { block, rest };
76875
+ }
76876
+ function stripLeadingRuntimeBlock(text) {
76877
+ const leading = leadingRuntimeBlock(text);
76878
+ return leading ? { rest: leading.rest } : null;
76879
+ }
76880
+ function lastUserMessageCarriesEnvelopeBlock(messages, block) {
76881
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
76882
+ const message = messages[index];
76883
+ if (message?.role !== "user") continue;
76884
+ const content = message.content;
76885
+ if (!Array.isArray(content) || content.length === 0) return false;
76886
+ const first = content[0];
76887
+ return first?.type === "hostContext" && first.kind === block.kind && first.version === block.version && JSON.stringify(first.data) === JSON.stringify(block.data);
76888
+ }
76889
+ return false;
76890
+ }
76891
+ function refreshRuntimeModeBlockOnLastUserMessage(messages, block) {
76892
+ for (let i = messages.length - 1; i >= 0; i--) {
76893
+ const message = messages[i];
76894
+ if (message?.role !== "user") continue;
76895
+ const content = message.content;
76896
+ if (typeof content === "string") {
76897
+ const stripped = stripLeadingRuntimeBlock(content);
76898
+ const rest = stripped ? stripped.rest : content;
76899
+ if (!rest) {
76900
+ const copy2 = [...messages];
76901
+ copy2[i] = { ...message, content: [block] };
76902
+ return copy2;
76903
+ }
76904
+ const copy = [...messages];
76905
+ copy[i] = { ...message, content: [block, { type: "text", text: rest }] };
76906
+ return copy;
76907
+ }
76908
+ if (Array.isArray(content)) {
76909
+ let leadingCount = 0;
76910
+ while (leadingCount < content.length && content[leadingCount]?.type === "hostContext") leadingCount += 1;
76911
+ if (leadingCount > 0) {
76912
+ const copy2 = [...messages];
76913
+ copy2[i] = { ...message, content: upsertLeadingHostContextBlock(content, block) };
76914
+ return copy2;
76915
+ }
76916
+ let userBlocks = content;
76917
+ const firstText = content[0];
76918
+ if (firstText?.type === "text" && typeof firstText.text === "string") {
76919
+ const stripped = stripLeadingRuntimeBlock(firstText.text);
76920
+ if (stripped) {
76921
+ userBlocks = stripped.rest ? [{ type: "text", text: stripped.rest }, ...content.slice(1)] : content.slice(1);
76922
+ }
76923
+ }
76924
+ const copy = [...messages];
76925
+ copy[i] = { ...message, content: [block, ...userBlocks] };
76926
+ return copy;
76927
+ }
76928
+ return messages;
76929
+ }
76930
+ return messages;
76931
+ }
76932
+ var RuntimeModeBlockInjector = class {
76933
+ constructor(options) {
76934
+ this.options = options;
76935
+ }
76936
+ options;
76937
+ lastKey = null;
76938
+ /** Exact frozen envelope block, including its consumed one-shot transition. */
76939
+ lastFrozenBlock = null;
76940
+ /**
76941
+ * Request-view overlay. While active, the CURRENT block is re-derived on
76942
+ * every request from the live message snapshot and applied to the latest
76943
+ * user message. It is not cached into history and it ends only when a real
76944
+ * user message freezes the current block (see `nextBlock` + the transform),
76945
+ * so consecutive tool rounds after a compaction retry keep the fresh state
76946
+ * instead of losing it after one request.
76947
+ */
76948
+ overlayActive = false;
76949
+ reset() {
76950
+ this.lastKey = null;
76951
+ this.lastFrozenBlock = null;
76952
+ this.overlayActive = true;
76953
+ }
76954
+ /**
76955
+ * Arm the request-view overlay without resetting the frozen-block key. Used
76956
+ * when the runtime shape changed while a turn is still running (compaction
76957
+ * checkpoint committed, plan approval, YOLO toggle inside a tool turn): the
76958
+ * next and subsequent model requests must see the current state even though
76959
+ * no new user message has been accepted yet.
76960
+ */
76961
+ armRefresh() {
76962
+ this.overlayActive = true;
76963
+ }
76964
+ /**
76965
+ * Envelope block to prepend to the next user message, or null when
76966
+ * unchanged. Does NOT end the overlay: the block is only proof once the
76967
+ * message carrying it reaches the request transform.
76968
+ */
76969
+ nextBlock() {
76970
+ return this.freshBlock();
76971
+ }
76972
+ /**
76973
+ * Current envelope block for a request that reuses existing history
76974
+ * (overflow retry after compaction, manual-compact continue, or the tool
76975
+ * rounds that follow a mid-turn mode change). Returns the same block for
76976
+ * every request until the latest user message itself carries that block;
76977
+ * then the overlay is retired and null is returned. Derivation is per
76978
+ * request from the given snapshot; no message array is cached.
76979
+ */
76980
+ consumeRetryRefreshBlock(messages) {
76981
+ if (!this.overlayActive) return null;
76982
+ const state = this.options.getState();
76983
+ const block = runtimeModeEnvelopeBlock(state);
76984
+ const frozenCurrent = this.lastKey === runtimeModeBlockKey(state) ? this.lastFrozenBlock : null;
76985
+ if (messages && (lastUserMessageCarriesEnvelopeBlock(messages, block) || frozenCurrent !== null && lastUserMessageCarriesEnvelopeBlock(messages, frozenCurrent))) {
76986
+ this.overlayActive = false;
76987
+ return null;
76988
+ }
76989
+ return block;
76990
+ }
76991
+ freshBlock() {
76992
+ const state = this.options.getState();
76993
+ if (!shouldInjectRuntimeModeBlock(this.lastKey, state)) return null;
76994
+ this.lastKey = runtimeModeBlockKey(state);
76995
+ if (state.pendingTransition) this.options.consumeTransition();
76996
+ this.options.noteTrace(state);
76997
+ this.lastFrozenBlock = runtimeModeEnvelopeBlock(state);
76998
+ return this.lastFrozenBlock;
76999
+ }
77000
+ };
77001
+
77002
+ // src/runtime/host-envelope-registry.ts
77003
+ var sharedCliEnvelopeRegistry;
77004
+ function cliHostEnvelopeRegistry() {
77005
+ if (sharedCliEnvelopeRegistry) return sharedCliEnvelopeRegistry;
77006
+ sharedCliEnvelopeRegistry = createHostEnvelopeProjectorRegistry();
77007
+ for (const { kind, version } of runtimeModeEnvelopeRegistry().listPins()) {
77008
+ sharedCliEnvelopeRegistry.register({
77009
+ kind,
77010
+ version,
77011
+ project: (data) => runtimeModeEnvelopeRegistry().resolve(kind, version).project(data)
77012
+ });
77013
+ }
77014
+ return sharedCliEnvelopeRegistry;
77015
+ }
77016
+ function registerExternalHostEnvelopeProjector(projector) {
77017
+ cliHostEnvelopeRegistry().register(projector);
77018
+ return () => {
77019
+ };
77020
+ }
77021
+ function resetCliHostEnvelopeRegistry() {
77022
+ sharedCliEnvelopeRegistry = void 0;
77023
+ }
77024
+ function cliHostEnvelopeKinds() {
77025
+ return cliHostEnvelopeRegistry().listPins().map(({ kind, version }) => `${kind}@${version}`).sort();
77026
+ }
77027
+ function projectCliHostEnvelopes(messages, onProjection) {
77028
+ return projectHostEnvelopes(messages, cliHostEnvelopeRegistry(), onProjection);
77029
+ }
77030
+ function isIntakeHostContextError(value) {
77031
+ return value.code !== void 0;
77032
+ }
77033
+ function intakeHostContextBlock(value) {
77034
+ if (!isHostContextBlock(value)) {
77035
+ return {
77036
+ ok: false,
77037
+ code: "host_context_invalid_shape",
77038
+ message: "hostContext must be { type: 'hostContext', kind: string, version: integer >= 1, data: object }"
77039
+ };
77040
+ }
77041
+ const block = value;
77042
+ const projector = cliHostEnvelopeRegistry().resolve(block.kind, block.version);
77043
+ if (!projector) {
77044
+ return {
77045
+ ok: false,
77046
+ code: "host_context_unknown_projector",
77047
+ message: `no projector for ${block.kind}@${block.version}; this build supports: ${cliHostEnvelopeKinds().join(", ")}`
77048
+ };
77049
+ }
77050
+ try {
77051
+ const text = projector.project(block.data);
77052
+ if (typeof text !== "string" || text.trim().length === 0) throw new Error("projector returned empty text");
77053
+ } catch (error) {
77054
+ return {
77055
+ ok: false,
77056
+ code: "host_context_unknown_projector",
77057
+ message: `projector for ${block.kind}@${block.version} rejected the data: ${error instanceof Error ? error.message : String(error)}`
77058
+ };
77059
+ }
77060
+ return { ok: true, block };
77061
+ }
77062
+ function intakeHostContextFailure(value) {
77063
+ const result = intakeHostContextBlock(value);
77064
+ return isIntakeHostContextError(result) ? { code: result.code, message: result.message } : void 0;
77065
+ }
77066
+
76673
77067
  // src/commands/interactive-compact-command.ts
76674
77068
  async function handleCompactCommand(host) {
76675
77069
  if (host.submitLock || host.isProcessing || host.isCompacting) {
@@ -76723,7 +77117,13 @@ async function handleCompactCommand(host) {
76723
77117
  if (beforeCompact?.summary) {
76724
77118
  summary = beforeCompact.summary;
76725
77119
  } else {
76726
- summary = await createCompactionSummary(preparation.messages, compactOptions);
77120
+ summary = await createCompactionSummary(
77121
+ projectCliHostEnvelopes(preparation.messages, (outcome) => host.sessionTrace.noteRuntimeEvent(
77122
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
77123
+ outcome.audit
77124
+ )),
77125
+ compactOptions
77126
+ );
76727
77127
  }
76728
77128
  const verified = verifyPreparedCompactionCommit({
76729
77129
  preparation,
@@ -79386,7 +79786,7 @@ async function createCliAutoCompactionResult(params) {
79386
79786
  systemPrompt: params.systemPrompt,
79387
79787
  signal: params.context.signal
79388
79788
  };
79389
- const summary = await createCompactionSummary(params.context.messages, compactOptions);
79789
+ const summary = await createCompactionSummary(projectCliHostEnvelopes(params.context.messages, params.onProjection), compactOptions);
79390
79790
  if (params.context.signal?.aborted) {
79391
79791
  return { aborted: true };
79392
79792
  }
@@ -79451,6 +79851,7 @@ function createClassification(kind, message, overrides) {
79451
79851
  }
79452
79852
  function classifyCliFailure(context) {
79453
79853
  const errorMessage4 = typeof context === "string" ? context : context.errorMessage;
79854
+ const structuredReplayClass = typeof context === "string" ? void 0 : context.message?.role === "assistant" ? context.message.replayClass : void 0;
79454
79855
  if (isCliContextOverflowError(errorMessage4)) {
79455
79856
  return createClassification("context_overflow", errorMessage4, {
79456
79857
  compactable: true,
@@ -79475,7 +79876,7 @@ function classifyCliFailure(context) {
79475
79876
  terminal: false
79476
79877
  });
79477
79878
  }
79478
- if (TRANSIENT_NETWORK_ERROR_PATTERN.test(errorMessage4)) {
79879
+ if (structuredReplayClass === "stream_lost" || structuredReplayClass === "stream_lost_partial" || TRANSIENT_NETWORK_ERROR_PATTERN.test(errorMessage4)) {
79479
79880
  return createClassification("transient_network", errorMessage4, {
79480
79881
  retryable: true,
79481
79882
  terminal: false
@@ -80378,7 +80779,11 @@ function createInteractiveAgentSessionController(host) {
80378
80779
  context,
80379
80780
  model: host.options.model,
80380
80781
  apiKey: host.options.apiKey,
80381
- systemPrompt: host.agent.state.systemPrompt
80782
+ systemPrompt: host.agent.state.systemPrompt,
80783
+ onProjection: (outcome) => host.sessionTrace.noteRuntimeEvent(
80784
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
80785
+ outcome.audit
80786
+ )
80382
80787
  });
80383
80788
  }
80384
80789
  },
@@ -80604,307 +81009,6 @@ function createInteractiveAgentSessionController(host) {
80604
81009
  });
80605
81010
  }
80606
81011
 
80607
- // src/runtime/runtime-mode-context.ts
80608
- var RUNTIME_MODE_ENVELOPE_KIND = "pie.runtimeMode";
80609
- var RUNTIME_MODE_ENVELOPE_VERSION = 1;
80610
- function runtimeModeEnvelopeRegistry() {
80611
- return sharedRuntimeModeRegistry ??= createHostEnvelopeProjectorRegistry([{
80612
- kind: RUNTIME_MODE_ENVELOPE_KIND,
80613
- version: RUNTIME_MODE_ENVELOPE_VERSION,
80614
- project: (data) => buildRuntimeModeContext(runtimeModeStateFromEnvelope(data))
80615
- }]);
80616
- }
80617
- var sharedRuntimeModeRegistry;
80618
- function runtimeModeStateFromEnvelope(data) {
80619
- return {
80620
- planMode: data.planMode === "planning" ? "planning" : "off",
80621
- yoloMode: data.yoloMode === true,
80622
- filesystemScope: data.filesystemScope === "all" ? "all" : "workspace",
80623
- pendingTransition: typeof data.pendingTransition === "string" ? data.pendingTransition : void 0,
80624
- activeToolNames: Array.isArray(data.activeToolNames) ? data.activeToolNames.filter((name) => typeof name === "string") : [],
80625
- planDisabledToolNames: Array.isArray(data.planDisabledToolNames) ? data.planDisabledToolNames.filter((name) => typeof name === "string") : [],
80626
- currentDate: typeof data.currentDate === "string" ? data.currentDate : void 0,
80627
- timeZone: typeof data.timeZone === "string" ? data.timeZone : void 0
80628
- };
80629
- }
80630
- function runtimeModeEnvelopeData(state) {
80631
- return {
80632
- planMode: state.planMode,
80633
- yoloMode: state.yoloMode,
80634
- filesystemScope: state.filesystemScope,
80635
- ...state.pendingTransition ? { pendingTransition: state.pendingTransition } : {},
80636
- activeToolNames: [...state.activeToolNames],
80637
- planDisabledToolNames: [...state.planDisabledToolNames],
80638
- ...state.currentDate ? { currentDate: state.currentDate } : {},
80639
- ...state.timeZone ? { timeZone: state.timeZone } : {}
80640
- };
80641
- }
80642
- function runtimeModeEnvelopeBlock(state) {
80643
- return {
80644
- type: "hostContext",
80645
- kind: RUNTIME_MODE_ENVELOPE_KIND,
80646
- version: RUNTIME_MODE_ENVELOPE_VERSION,
80647
- data: runtimeModeEnvelopeData(state)
80648
- };
80649
- }
80650
- function isAgentMessage(value) {
80651
- return !!value && typeof value === "object" && "role" in value;
80652
- }
80653
- function prependRuntimeModeBlockToPrompt(input, block) {
80654
- if (!block) return input;
80655
- if (typeof input === "string") {
80656
- return [{ ...block }, { type: "text", text: input }];
80657
- }
80658
- if (Array.isArray(input)) {
80659
- if (input.length > 0 && isAgentMessage(input[0])) {
80660
- return prependBlockToMessages(input, block);
80661
- }
80662
- return [block, ...input];
80663
- }
80664
- if (isAgentMessage(input)) {
80665
- return prependBlockToMessages([input], block)[0];
80666
- }
80667
- return [block, ...input];
80668
- }
80669
- function prependBlockToMessages(messages, block) {
80670
- const next = [...messages];
80671
- let target = -1;
80672
- for (let index = next.length - 1; index >= 0; index--) {
80673
- if (next[index]?.role === "user") {
80674
- target = index;
80675
- break;
80676
- }
80677
- }
80678
- if (target < 0) {
80679
- next.push({ role: "user", content: [block], timestamp: Date.now() });
80680
- return next;
80681
- }
80682
- const message = next[target];
80683
- if (Array.isArray(message.content)) {
80684
- next[target] = { ...message, content: [block, ...message.content] };
80685
- } else if (typeof message.content === "string") {
80686
- next[target] = { ...message, content: [block, { type: "text", text: message.content }] };
80687
- } else {
80688
- next.splice(target, 0, { role: "user", content: [block], timestamp: Date.now() });
80689
- }
80690
- return next;
80691
- }
80692
- var RUNTIME_MODE_CONTEXT_MARKER = "<runtime-mode-context>";
80693
- var RUNTIME_MODE_CONTEXT_END_MARKER = "</runtime-mode-context>";
80694
- function buildRuntimeModeContext(state) {
80695
- const lines = [
80696
- RUNTIME_MODE_CONTEXT_MARKER,
80697
- "Current runtime mode:"
80698
- ];
80699
- if (state.planMode === "planning") {
80700
- lines.push(
80701
- "- Plan mode: active (workspace read-only; plan_scratch permits session-local temporary drafts; submit the finished plan by calling plan_submit with the ordered steps for user approval)."
80702
- );
80703
- if (state.planDisabledToolNames.length > 0) {
80704
- lines.push(
80705
- `- Disabled this turn by plan mode (calls are denied): ${state.planDisabledToolNames.join(", ")}. Do not call them while planning.`
80706
- );
80707
- }
80708
- } else {
80709
- lines.push("- Plan mode: off.");
80710
- }
80711
- lines.push(
80712
- `- YOLO mode: ${state.yoloMode ? "on (filesystem sandbox directory restrictions are disabled)" : "off (workspace/protected-path restrictions apply)"}.`,
80713
- `- Filesystem scope: ${state.filesystemScope === "all" ? "all local paths may be passed directly to file tools when permitted" : "workspace paths and configured safe roots only"}.`
80714
- );
80715
- if (state.pendingTransition) {
80716
- const transitionText = {
80717
- entered_yolo: "YOLO mode was just enabled for this turn.",
80718
- exited_yolo: "YOLO mode was just disabled; do not assume previous absolute-path access still applies.",
80719
- entered_plan: "Plan mode was just enabled; analyze and plan without changing the workspace. Use plan_scratch for temporary drafts, then submit the finished plan by calling plan_submit with the ordered steps for user approval.",
80720
- exited_plan: "Plan mode was just disabled; execution tools may be used when the task requires them."
80721
- };
80722
- lines.push(`- Transition: ${transitionText[state.pendingTransition]}`);
80723
- }
80724
- if (state.currentDate) {
80725
- lines.push(`- Current date: ${state.currentDate}${state.timeZone ? ` (${state.timeZone})` : ""}.`);
80726
- }
80727
- if (state.activeToolNames.length > 0) {
80728
- lines.push(`- Active tools: ${state.activeToolNames.join(", ")}.`);
80729
- }
80730
- lines.push(RUNTIME_MODE_CONTEXT_END_MARKER);
80731
- return lines.join("\n");
80732
- }
80733
- function runtimeModeBlockKey(state) {
80734
- return JSON.stringify({
80735
- planMode: state.planMode,
80736
- yoloMode: state.yoloMode,
80737
- filesystemScope: state.filesystemScope,
80738
- currentDate: state.currentDate ?? null,
80739
- activeToolNames: state.activeToolNames,
80740
- planDisabledToolNames: state.planDisabledToolNames
80741
- });
80742
- }
80743
- function shouldInjectRuntimeModeBlock(lastKey, state) {
80744
- if (lastKey === null) return true;
80745
- return runtimeModeBlockKey(state) !== lastKey;
80746
- }
80747
- function runtimeModeTraceData(state) {
80748
- return {
80749
- yoloMode: state.yoloMode,
80750
- planMode: state.planMode,
80751
- filesystemScope: state.filesystemScope,
80752
- pendingTransition: state.pendingTransition,
80753
- currentDate: state.currentDate,
80754
- timeZone: state.timeZone,
80755
- activeToolCount: state.activeToolNames.length,
80756
- planDisabledToolCount: state.planDisabledToolNames.length
80757
- };
80758
- }
80759
- function currentDateInZone(timeZone) {
80760
- const parts = new Intl.DateTimeFormat("en-US", {
80761
- year: "numeric",
80762
- month: "2-digit",
80763
- day: "2-digit",
80764
- timeZone
80765
- }).formatToParts(/* @__PURE__ */ new Date());
80766
- const part = (type) => parts.find((p) => p.type === type)?.value ?? "00";
80767
- return `${part("year")}-${part("month")}-${part("day")}`;
80768
- }
80769
- var RUNTIME_MODE_BLOCK_START_MARKER = "<runtime-mode-context>";
80770
- function leadingRuntimeBlock(text) {
80771
- const withoutLeadingWhitespace = text.replace(/^[\t ]+/, "");
80772
- if (!withoutLeadingWhitespace.startsWith(RUNTIME_MODE_BLOCK_START_MARKER)) return null;
80773
- const markerStart = text.length - withoutLeadingWhitespace.length;
80774
- const endIndex = text.indexOf(RUNTIME_MODE_CONTEXT_END_MARKER, markerStart);
80775
- if (endIndex < 0) return null;
80776
- const block = text.slice(markerStart, endIndex + RUNTIME_MODE_CONTEXT_END_MARKER.length);
80777
- const rest = text.slice(endIndex + RUNTIME_MODE_CONTEXT_END_MARKER.length).replace(/^[\t ]*(?:\r?\n){0,2}/, "");
80778
- return { block, rest };
80779
- }
80780
- function stripLeadingRuntimeBlock(text) {
80781
- const leading = leadingRuntimeBlock(text);
80782
- return leading ? { rest: leading.rest } : null;
80783
- }
80784
- function lastUserMessageCarriesEnvelopeBlock(messages, block) {
80785
- for (let index = messages.length - 1; index >= 0; index -= 1) {
80786
- const message = messages[index];
80787
- if (message?.role !== "user") continue;
80788
- const content = message.content;
80789
- if (!Array.isArray(content) || content.length === 0) return false;
80790
- const first = content[0];
80791
- return first?.type === "hostContext" && first.kind === block.kind && first.version === block.version && JSON.stringify(first.data) === JSON.stringify(block.data);
80792
- }
80793
- return false;
80794
- }
80795
- function refreshRuntimeModeBlockOnLastUserMessage(messages, block) {
80796
- for (let i = messages.length - 1; i >= 0; i--) {
80797
- const message = messages[i];
80798
- if (message?.role !== "user") continue;
80799
- const content = message.content;
80800
- if (typeof content === "string") {
80801
- const stripped = stripLeadingRuntimeBlock(content);
80802
- const rest = stripped ? stripped.rest : content;
80803
- if (!rest) {
80804
- const copy2 = [...messages];
80805
- copy2[i] = { ...message, content: [block] };
80806
- return copy2;
80807
- }
80808
- const copy = [...messages];
80809
- copy[i] = { ...message, content: [block, { type: "text", text: rest }] };
80810
- return copy;
80811
- }
80812
- if (Array.isArray(content)) {
80813
- const first = content[0];
80814
- if (first?.type === "hostContext") {
80815
- if (first === block) return messages;
80816
- const copy2 = [...messages];
80817
- const contentCopy = [...content];
80818
- contentCopy[0] = block;
80819
- copy2[i] = { ...message, content: contentCopy };
80820
- return copy2;
80821
- }
80822
- let userBlocks = content;
80823
- const firstText = content[0];
80824
- if (firstText?.type === "text" && typeof firstText.text === "string") {
80825
- const stripped = stripLeadingRuntimeBlock(firstText.text);
80826
- if (stripped) {
80827
- userBlocks = stripped.rest ? [{ type: "text", text: stripped.rest }, ...content.slice(1)] : content.slice(1);
80828
- }
80829
- }
80830
- const copy = [...messages];
80831
- copy[i] = { ...message, content: [block, ...userBlocks] };
80832
- return copy;
80833
- }
80834
- return messages;
80835
- }
80836
- return messages;
80837
- }
80838
- var RuntimeModeBlockInjector = class {
80839
- constructor(options) {
80840
- this.options = options;
80841
- }
80842
- options;
80843
- lastKey = null;
80844
- /** Exact frozen envelope block, including its consumed one-shot transition. */
80845
- lastFrozenBlock = null;
80846
- /**
80847
- * Request-view overlay. While active, the CURRENT block is re-derived on
80848
- * every request from the live message snapshot and applied to the latest
80849
- * user message. It is not cached into history and it ends only when a real
80850
- * user message freezes the current block (see `nextBlock` + the transform),
80851
- * so consecutive tool rounds after a compaction retry keep the fresh state
80852
- * instead of losing it after one request.
80853
- */
80854
- overlayActive = false;
80855
- reset() {
80856
- this.lastKey = null;
80857
- this.lastFrozenBlock = null;
80858
- this.overlayActive = true;
80859
- }
80860
- /**
80861
- * Arm the request-view overlay without resetting the frozen-block key. Used
80862
- * when the runtime shape changed while a turn is still running (compaction
80863
- * checkpoint committed, plan approval, YOLO toggle inside a tool turn): the
80864
- * next and subsequent model requests must see the current state even though
80865
- * no new user message has been accepted yet.
80866
- */
80867
- armRefresh() {
80868
- this.overlayActive = true;
80869
- }
80870
- /**
80871
- * Envelope block to prepend to the next user message, or null when
80872
- * unchanged. Does NOT end the overlay: the block is only proof once the
80873
- * message carrying it reaches the request transform.
80874
- */
80875
- nextBlock() {
80876
- return this.freshBlock();
80877
- }
80878
- /**
80879
- * Current envelope block for a request that reuses existing history
80880
- * (overflow retry after compaction, manual-compact continue, or the tool
80881
- * rounds that follow a mid-turn mode change). Returns the same block for
80882
- * every request until the latest user message itself carries that block;
80883
- * then the overlay is retired and null is returned. Derivation is per
80884
- * request from the given snapshot; no message array is cached.
80885
- */
80886
- consumeRetryRefreshBlock(messages) {
80887
- if (!this.overlayActive) return null;
80888
- const state = this.options.getState();
80889
- const block = runtimeModeEnvelopeBlock(state);
80890
- const frozenCurrent = this.lastKey === runtimeModeBlockKey(state) ? this.lastFrozenBlock : null;
80891
- if (messages && (lastUserMessageCarriesEnvelopeBlock(messages, block) || frozenCurrent !== null && lastUserMessageCarriesEnvelopeBlock(messages, frozenCurrent))) {
80892
- this.overlayActive = false;
80893
- return null;
80894
- }
80895
- return block;
80896
- }
80897
- freshBlock() {
80898
- const state = this.options.getState();
80899
- if (!shouldInjectRuntimeModeBlock(this.lastKey, state)) return null;
80900
- this.lastKey = runtimeModeBlockKey(state);
80901
- if (state.pendingTransition) this.options.consumeTransition();
80902
- this.options.noteTrace(state);
80903
- this.lastFrozenBlock = runtimeModeEnvelopeBlock(state);
80904
- return this.lastFrozenBlock;
80905
- }
80906
- };
80907
-
80908
81012
  // src/runtime/cache-retention.ts
80909
81013
  function createCacheRetentionStreamFn(configured, getConfiguredRetention) {
80910
81014
  const base = configured ?? ((model, context, options) => streamSimple(model, context, options));
@@ -81767,6 +81871,7 @@ async function loadInteractiveExtensions(host) {
81767
81871
  host.noteRuntimeModeChanged("extension_register_provider");
81768
81872
  return unregister;
81769
81873
  },
81874
+ registerHostEnvelopeProjector: (projector) => registerExternalHostEnvelopeProjector(projector),
81770
81875
  loginProvider: async (name) => {
81771
81876
  const loggedIn = await loginExtensionProvider({
81772
81877
  provider: name,
@@ -82227,7 +82332,7 @@ var InteractiveMode = class {
82227
82332
  async init() {
82228
82333
  const activeSession = this.sessionManager.getActiveSession();
82229
82334
  this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
82230
- const { Agent } = await import("./chunks/src-C2CBPEUY.js");
82335
+ const { Agent } = await import("./chunks/src-BQUDKBQ7.js");
82231
82336
  this.agent = new Agent({
82232
82337
  initialState: {
82233
82338
  systemPrompt: this.buildSystemPrompt(),
@@ -82249,7 +82354,7 @@ var InteractiveMode = class {
82249
82354
  });
82250
82355
  return projectHostEnvelopes(
82251
82356
  structured,
82252
- runtimeModeEnvelopeRegistry(),
82357
+ cliHostEnvelopeRegistry(),
82253
82358
  (outcome) => this.sessionTrace.noteRuntimeEvent(outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected", outcome.audit)
82254
82359
  );
82255
82360
  }
@@ -82331,6 +82436,15 @@ var InteractiveMode = class {
82331
82436
  if (this.isProcessing) {
82332
82437
  throw new Error("Cannot reload while a response is being processed. Wait for the turn to finish or abort it first.");
82333
82438
  }
82439
+ const acquiredReloadLock = !this.submitLock;
82440
+ if (acquiredReloadLock) this.submitLock = true;
82441
+ try {
82442
+ await this.reloadRuntimeWhileLocked();
82443
+ } finally {
82444
+ if (acquiredReloadLock) this.submitLock = false;
82445
+ }
82446
+ }
82447
+ async reloadRuntimeWhileLocked() {
82334
82448
  const builtinDir = path30.join(getBuiltinDir(), "skills");
82335
82449
  const userDir = path30.join(os8.homedir(), ".pie", "skills");
82336
82450
  const projectDir = path30.join(this.options.cwd, ".pie", "skills");
@@ -82346,6 +82460,7 @@ var InteractiveMode = class {
82346
82460
  this.originalTools = [...this.options.allTools];
82347
82461
  this.pristineTools = [...this.options.allTools];
82348
82462
  this.agent.state.tools = [...this.options.allTools];
82463
+ resetCliHostEnvelopeRegistry();
82349
82464
  await this.extensionRunner?.dispose("reload");
82350
82465
  this.extensionWidgets?.clearAll();
82351
82466
  await this.loadExtensions();
@@ -82955,7 +83070,8 @@ function createPrintModeCompactionHandler(params) {
82955
83070
  context,
82956
83071
  model: params.model,
82957
83072
  apiKey: params.apiKey,
82958
- systemPrompt: params.systemPrompt
83073
+ systemPrompt: params.systemPrompt,
83074
+ onProjection: params.onProjection
82959
83075
  });
82960
83076
  }
82961
83077
  };
@@ -83039,6 +83155,7 @@ async function loadPrintModeExtensions(params) {
83039
83155
  setSessionName: (name) => params.sessionManager.setSessionName(name),
83040
83156
  getSessionName: () => params.sessionManager.getSessionName(),
83041
83157
  registerProvider: (name, config) => params.modelRegistry.registerProvider(name, config),
83158
+ registerHostEnvelopeProjector: (projector) => registerExternalHostEnvelopeProjector(projector),
83042
83159
  loginProvider: (name) => loginExtensionProvider({
83043
83160
  provider: name,
83044
83161
  modelRegistry: params.modelRegistry,
@@ -83093,7 +83210,7 @@ async function runPrintMode(params) {
83093
83210
  `);
83094
83211
  console.log("Assistant: ");
83095
83212
  }
83096
- const { Agent: AgentClass } = await import("./chunks/src-C2CBPEUY.js");
83213
+ const { Agent: AgentClass } = await import("./chunks/src-BQUDKBQ7.js");
83097
83214
  let agent;
83098
83215
  const printModeExtensions = await loadPrintModeExtensions({
83099
83216
  cwd: runtime.cwd,
@@ -83129,6 +83246,7 @@ async function runPrintMode(params) {
83129
83246
  tools: printModeTools
83130
83247
  });
83131
83248
  const printThinkingLevel = resolveInitialThinkingLevel({ session: runtime.sessionManager.getActiveSession(), settingsManager: runtime.settingsManager });
83249
+ const sessionTrace = new SessionTraceWriter(runtime.paths.sessionsDir, runtime.sessionManager);
83132
83250
  agent = new AgentClass({
83133
83251
  initialState: {
83134
83252
  systemPrompt: baseSystemPrompt,
@@ -83137,10 +83255,18 @@ async function runPrintMode(params) {
83137
83255
  thinkingLevel: printThinkingLevel
83138
83256
  },
83139
83257
  apiKey: runtime.apiKey,
83258
+ // Print mode restores interactive sessions verbatim (AgentSessionController
83259
+ // loads stored history on construction). Those sessions carry persisted
83260
+ // hostContext facts; project them to model-visible text or the provider
83261
+ // converters reject the request (`Unprojected hostContext block`). The
83262
+ // persisted history is never rewritten — projection builds the wire view.
83263
+ transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) => sessionTrace.noteRuntimeEvent(
83264
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
83265
+ outcome.audit
83266
+ )),
83140
83267
  // Body-free transport timeline for the main (print-mode) agent.
83141
83268
  streamFn: createTransportDiagnosticsStreamFn(params.streamFn ?? streamSimple, logTransportLifecycle)
83142
83269
  });
83143
- const sessionTrace = new SessionTraceWriter(runtime.paths.sessionsDir, runtime.sessionManager);
83144
83270
  const reportRetryStatus = createPrintModeRetryStatusReporter();
83145
83271
  const agentSessionController = new AgentSessionController({
83146
83272
  agent,
@@ -83180,7 +83306,11 @@ async function runPrintMode(params) {
83180
83306
  runner: printModeExtensions.runner,
83181
83307
  model: runtime.model,
83182
83308
  apiKey: runtime.apiKey,
83183
- systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt
83309
+ systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt,
83310
+ onProjection: (outcome) => sessionTrace.noteRuntimeEvent(
83311
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
83312
+ outcome.audit
83313
+ )
83184
83314
  }),
83185
83315
  classifyFailure: (context) => classifyCliFailure(context),
83186
83316
  onEvent: (event) => {
@@ -83380,14 +83510,17 @@ function parseInput(line) {
83380
83510
  };
83381
83511
  }
83382
83512
  if (parsed.type === "sidechat.request" && typeof parsed.requestId === "string" && typeof parsed.prompt === "string") {
83513
+ if (parsed.hostContext !== void 0 && !isHostContextBlock(parsed.hostContext)) return null;
83383
83514
  return {
83384
83515
  type: "sidechat.request",
83385
83516
  sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : void 0,
83386
83517
  requestId: parsed.requestId,
83387
- prompt: parsed.prompt
83518
+ prompt: parsed.prompt,
83519
+ hostContext: parsed.hostContext
83388
83520
  };
83389
83521
  }
83390
83522
  if ((parsed.type === "turn.request" || parsed.type === "turn.input") && typeof parsed.turnId === "string" && typeof parsed.prompt === "string") {
83523
+ if (parsed.hostContext !== void 0 && !isHostContextBlock(parsed.hostContext)) return null;
83391
83524
  const streamingBehavior = parsed.streamingBehavior;
83392
83525
  if (streamingBehavior !== void 0 && streamingBehavior !== "steer" && streamingBehavior !== "followUp") {
83393
83526
  return null;
@@ -83397,6 +83530,7 @@ function parseInput(line) {
83397
83530
  sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : void 0,
83398
83531
  turnId: parsed.turnId,
83399
83532
  prompt: parsed.prompt,
83533
+ hostContext: parsed.hostContext,
83400
83534
  streamingBehavior,
83401
83535
  cwd: typeof parsed.cwd === "string" ? parsed.cwd : void 0,
83402
83536
  metadata: isRecord3(parsed.metadata) ? parsed.metadata : void 0
@@ -83505,6 +83639,7 @@ async function loadJsonModeExtensions(params) {
83505
83639
  getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
83506
83640
  resolveModelClass: (modelClass) => params.runtime.modelRegistry.resolveModelClass(modelClass),
83507
83641
  resolveModelRef: (modelRef) => params.runtime.modelRegistry.resolveModelRef(modelRef),
83642
+ registerHostEnvelopeProjector: (projector) => registerExternalHostEnvelopeProjector(projector),
83508
83643
  getMessages: () => params.getAgent()?.state.messages ?? [],
83509
83644
  getSessionMetadata: () => ({ ...params.runtime.sessionManager.getActiveSession()?.metadata ?? {} }),
83510
83645
  setSessionMetadata: (key, value) => {
@@ -83579,7 +83714,14 @@ async function runJsonEventsMode(params) {
83579
83714
  const prewarmTimeoutMs = Number(process.env.PIE_JSON_EVENTS_PREWARM_TIMEOUT_MS || 1e4);
83580
83715
  const sidechatTimeoutMs = Number(process.env.PIE_JSON_EVENTS_SIDECHAT_TIMEOUT_MS || 3e5);
83581
83716
  await prewarmRuntime();
83582
- writeEvent({ type: "agent.ready", sessionId });
83717
+ writeEvent({
83718
+ type: "agent.ready",
83719
+ sessionId,
83720
+ // Capability broadcast: the envelope kinds THIS build can project at
83721
+ // intake (embedded external kinds included), so embedders can probe
83722
+ // before their first turn instead of learning mismatches from failures.
83723
+ capabilities: { hostContextKinds: cliHostEnvelopeKinds() }
83724
+ });
83583
83725
  function trackSidechatPromise(promise) {
83584
83726
  activeSidechatPromise = promise;
83585
83727
  void promise.finally(() => {
@@ -83681,7 +83823,7 @@ async function runJsonEventsMode(params) {
83681
83823
  timestamp: startedAt,
83682
83824
  message: {
83683
83825
  role: "user",
83684
- content: message.prompt,
83826
+ content: message.hostContext ? [message.hostContext, { type: "text", text: message.prompt }] : message.prompt,
83685
83827
  timestamp: startedAt
83686
83828
  }
83687
83829
  };
@@ -83735,7 +83877,10 @@ async function runJsonEventsMode(params) {
83735
83877
  return {
83736
83878
  error: detail.message,
83737
83879
  code: detail.code,
83738
- recoverable: detail.recoverable
83880
+ recoverable: detail.recoverable,
83881
+ // Intake failures attach the supported envelope kinds so an embedder
83882
+ // can self-correct without probing.
83883
+ ...detail.hostContextKinds ? { hostContextKinds: detail.hostContextKinds } : {}
83739
83884
  };
83740
83885
  }
83741
83886
  function errorToFailureDetail(error) {
@@ -83937,6 +84082,11 @@ async function runJsonEventsMode(params) {
83937
84082
  };
83938
84083
  try {
83939
84084
  await ensureRuntime();
84085
+ const hostContextFailure = validateIntakeHostContext(message);
84086
+ if (hostContextFailure) {
84087
+ writeSidechatFailure(message, hostContextFailure.message, hostContextFailure.code);
84088
+ return;
84089
+ }
83940
84090
  if (!agent || !runtime) {
83941
84091
  throw new Error("JSON events runtime was not initialized");
83942
84092
  }
@@ -83949,7 +84099,7 @@ async function runJsonEventsMode(params) {
83949
84099
  return;
83950
84100
  }
83951
84101
  const parent = agent;
83952
- const { Agent: AgentClass } = await import("./chunks/src-C2CBPEUY.js");
84102
+ const { Agent: AgentClass } = await import("./chunks/src-BQUDKBQ7.js");
83953
84103
  const sideAgent = new AgentClass({
83954
84104
  initialState: {
83955
84105
  systemPrompt: parent.state.systemPrompt,
@@ -83959,6 +84109,12 @@ async function runJsonEventsMode(params) {
83959
84109
  messages: structuredClone(parent.state.messages)
83960
84110
  },
83961
84111
  apiKey: runtime.apiKey,
84112
+ // The sidechat snapshot clones the parent's stored history, including
84113
+ // persisted hostContext facts; project them like the main agent does.
84114
+ transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) => trace?.noteRuntimeEvent(
84115
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
84116
+ outcome.audit
84117
+ )),
83962
84118
  // Same body-free transport timeline as the main agent: a sidechat is
83963
84119
  // an independent Responses request and previously had no record at all
83964
84120
  // when it stalled. `streamSimple` matches the host default when the
@@ -83972,7 +84128,7 @@ async function runJsonEventsMode(params) {
83972
84128
  }, sidechatTimeoutMs);
83973
84129
  timer.unref?.();
83974
84130
  try {
83975
- await sideAgent.prompt(message.prompt);
84131
+ await sideAgent.prompt(sidechatPromptBlocks(message));
83976
84132
  } finally {
83977
84133
  clearTimeout(timer);
83978
84134
  }
@@ -84303,7 +84459,7 @@ async function runJsonEventsMode(params) {
84303
84459
  if (runtime.initialModel.unconfigured || controller) {
84304
84460
  return;
84305
84461
  }
84306
- const { Agent: AgentClass } = await import("./chunks/src-C2CBPEUY.js");
84462
+ const { Agent: AgentClass } = await import("./chunks/src-BQUDKBQ7.js");
84307
84463
  if (runtimeClosing) return;
84308
84464
  const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
84309
84465
  if (runtimeClosing) {
@@ -84340,6 +84496,13 @@ async function runJsonEventsMode(params) {
84340
84496
  thinkingLevel
84341
84497
  },
84342
84498
  apiKey: runtime.apiKey,
84499
+ // Restored interactive sessions carry persisted hostContext facts; project
84500
+ // them to model-visible text at the request boundary or the provider
84501
+ // converters reject the request (`Unprojected hostContext block`).
84502
+ transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) => trace?.noteRuntimeEvent(
84503
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
84504
+ outcome.audit
84505
+ )),
84343
84506
  // Body-free transport timeline for the main (JSON-events) agent.
84344
84507
  streamFn: createJsonEventsTransportStreamFn(params.streamFn)
84345
84508
  });
@@ -84379,7 +84542,11 @@ async function runJsonEventsMode(params) {
84379
84542
  context,
84380
84543
  model: runtime.model,
84381
84544
  apiKey: runtime.apiKey,
84382
- systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt
84545
+ systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt,
84546
+ onProjection: (outcome) => trace?.noteRuntimeEvent(
84547
+ outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
84548
+ outcome.audit
84549
+ )
84383
84550
  })
84384
84551
  },
84385
84552
  classifyFailure: (context) => classifyCliFailure(context),
@@ -84473,6 +84640,15 @@ async function runJsonEventsMode(params) {
84473
84640
  syncSessionModelMetadata(runtime.sessionManager, runtime.model, thinkingLevel);
84474
84641
  }
84475
84642
  }
84643
+ function promptInputFor(message) {
84644
+ return message.hostContext ? [message.hostContext, { type: "text", text: message.prompt }] : message.prompt;
84645
+ }
84646
+ function sidechatPromptBlocks(message) {
84647
+ return message.hostContext ? [message.hostContext, { type: "text", text: message.prompt }] : [{ type: "text", text: message.prompt }];
84648
+ }
84649
+ function validateIntakeHostContext(message) {
84650
+ return message.hostContext ? intakeHostContextFailure(message.hostContext) : void 0;
84651
+ }
84476
84652
  async function runTurn(message) {
84477
84653
  if (isSessionMismatch(message)) {
84478
84654
  writeEvent({
@@ -84484,6 +84660,17 @@ async function runJsonEventsMode(params) {
84484
84660
  return;
84485
84661
  }
84486
84662
  if (activeTurn && !activeTurn.finalized) {
84663
+ const queuedHostContextFailure = validateIntakeHostContext(message);
84664
+ if (queuedHostContextFailure) {
84665
+ writeEvent({
84666
+ type: "turn.failed",
84667
+ sessionId,
84668
+ turnId: message.turnId,
84669
+ error: queuedHostContextFailure.message,
84670
+ ...queuedHostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
84671
+ });
84672
+ return;
84673
+ }
84487
84674
  await queueActiveTurnInput(message);
84488
84675
  return;
84489
84676
  }
@@ -84503,6 +84690,17 @@ async function runJsonEventsMode(params) {
84503
84690
  const turn = activeTurn;
84504
84691
  writeEvent({ type: "turn.started", sessionId: activeTurn.sessionId, turnId: activeTurn.turnId });
84505
84692
  if (params.mockResponse !== void 0) {
84693
+ const mockHostContextFailure = validateIntakeHostContext(message);
84694
+ if (mockHostContextFailure) {
84695
+ finalize("failed", {
84696
+ code: mockHostContextFailure.code,
84697
+ message: mockHostContextFailure.message,
84698
+ ...mockHostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
84699
+ });
84700
+ if (activeTurn === turn) emitSettled(turn);
84701
+ if (activeTurn === turn) activeTurn = null;
84702
+ return;
84703
+ }
84506
84704
  if (mockResponseDelayMs > 0) {
84507
84705
  await delay(mockResponseDelayMs);
84508
84706
  }
@@ -84537,6 +84735,17 @@ async function runJsonEventsMode(params) {
84537
84735
  if (activeTurn === turn) activeTurn = null;
84538
84736
  return;
84539
84737
  }
84738
+ const hostContextFailure = validateIntakeHostContext(message);
84739
+ if (hostContextFailure) {
84740
+ finalize("failed", {
84741
+ code: hostContextFailure.code,
84742
+ message: hostContextFailure.message,
84743
+ ...hostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
84744
+ });
84745
+ if (activeTurn === turn) emitSettled(turn);
84746
+ if (activeTurn === turn) activeTurn = null;
84747
+ return;
84748
+ }
84540
84749
  const activeRuntime = runtime;
84541
84750
  if (activeRuntime?.initialModel.unconfigured) {
84542
84751
  finalize("failed", activeRuntime.initialModel.warning || "No models are configured.");
@@ -84571,7 +84780,7 @@ async function runJsonEventsMode(params) {
84571
84780
  try {
84572
84781
  trace?.notePendingUserText(message.prompt);
84573
84782
  trace?.noteDispatchStart({ mode: "json-events" });
84574
- await controller.prompt(message.prompt, { source: "json-events" });
84783
+ await controller.prompt(promptInputFor(message), { source: "json-events" });
84575
84784
  trace?.noteDispatchSettled({ mode: "json-events" });
84576
84785
  trace?.noteWaitForIdleStart({ mode: "json-events" });
84577
84786
  await controller.waitForSettled();
@@ -84636,7 +84845,7 @@ async function runJsonEventsMode(params) {
84636
84845
  mode: message.streamingBehavior,
84637
84846
  turnId: message.turnId
84638
84847
  });
84639
- await activeController.prompt(message.prompt, {
84848
+ await activeController.prompt(promptInputFor(message), {
84640
84849
  source: "json-events",
84641
84850
  streamingBehavior: message.streamingBehavior,
84642
84851
  displayText: message.prompt,
@@ -84912,7 +85121,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
84912
85121
  }
84913
85122
  async function createCliTestStreamFnFromEnv() {
84914
85123
  if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
84915
- return (await import("./chunks/test-stream-LDVUVSUP.js")).createTestStreamFnFromSequenceEnv();
85124
+ return (await import("./chunks/test-stream-A5KBYYZD.js")).createTestStreamFnFromSequenceEnv();
84916
85125
  }
84917
85126
  function resolveJsonEventsDetailFlag() {
84918
85127
  for (let index = 0; index < process.argv.length; index += 1) {