@alan-ai-hq/agent-manager-darwin-arm64 0.1.138 → 0.1.140

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/alan-agent.cjs CHANGED
@@ -20782,7 +20782,11 @@ var init_github_proxy = __esm({
20782
20782
  ];
20783
20783
  gitHubProxyUpstreamSchema = external_exports.enum(GITHUB_PROXY_UPSTREAMS);
20784
20784
  GITHUB_PROXY_PLACEHOLDER_TOKEN = "proxy-injected";
20785
- GITHUB_PROXY_REFUSAL_CODES = ["host_not_proxied", "machine_not_allowed"];
20785
+ GITHUB_PROXY_REFUSAL_CODES = [
20786
+ "host_not_proxied",
20787
+ "machine_not_allowed",
20788
+ "github_not_connected"
20789
+ ];
20786
20790
  gitHubProxyErrorSchema = external_exports.object({
20787
20791
  message: external_exports.string().min(1),
20788
20792
  documentation_url: external_exports.string(),
@@ -22071,13 +22075,9 @@ So when a turn depends on something the repository cannot tell you \u2014 a valu
22071
22075
  What comes back is the answer, not a step towards it. Carry its specifics into what you write or change \u2014 the value, the constraint, the reason, the person \u2014 and say plainly when the evidence contradicts what was asked for. Retrieving a decision and then producing work that ignores it is worse than never having searched, because it looks informed.
22072
22076
 
22073
22077
  Skip it when nothing team-specific is at stake: source-code questions, general knowledge, mechanical work fully specified in the request, or an exact ID already in hand.`;
22074
- ALAN_PLATFORM_TOOL_ROUTING_PROMPT = `## Alan platform tools
22075
-
22076
- Use the matching Alan MCP tool to retrieve or change canonical Alan records \u2014 tasks, sessions, documents, artifacts, and their relationships \u2014 to perform Alan platform actions such as managing runs or machines, or to act through a provider identity connected to Alan. This applies whether the agent runs locally or in the cloud. Do not use a shell CLI, browser, raw HTTP, or local files to bypass an unavailable or unauthorized Alan MCP action; those paths bypass Alan's identity, authorization, audit trail, and task linkage.
22077
-
22078
- Use computer use and browser tools for authorized product debugging and QA, including inspecting the authenticated Alan app, its transient DOM and CSS state, and exercising UI flows in development or test environments. These tools are also available for ordinary browser and computer tasks outside Alan. Use local tools for repository, process, and log diagnostics. Exercising a UI for QA is not a substitute for carrying out a blocked platform record action.
22078
+ ALAN_PLATFORM_TOOL_ROUTING_PROMPT = `## Alan platform and GitHub
22079
22079
 
22080
- A tool missing from the currently offered set is not proof that it is unavailable. Use the host's tool-discovery mechanism once. If the tool is still not exposed, or its call reports unavailable or unauthorized, name the blocked capability and stop that platform action only; continue independent debugging and testing. Do not bypass a workflow or role tool allowlist.`;
22080
+ Use Alan MCP tools for canonical Alan records and platform actions: tasks, sessions, documents, artifacts, runs, and machines. Use the available repository tools for GitHub work, including git and gh when useful. If a cloud GitHub request reports github_not_connected, call request_github_connection in the current conversation and end the turn. The chat will offer GitHub authorization and resume after the user connects. Continue other independent work when possible.`;
22081
22081
  ALAN_IDENTITY_PROMPT = `You are Alan, the software factory agent. Alan ships software end to end \u2014 plan, write, review, test, deploy.
22082
22082
 
22083
22083
  ## How Alan is structured
@@ -22115,10 +22115,10 @@ Team
22115
22115
 
22116
22116
  ${ALAN_PLATFORM_TOOL_ROUTING_PROMPT}
22117
22117
 
22118
- ## Record & Entity Resolution (Tasks, PRs, Docs, Epics)
22118
+ ## Record & Entity Resolution (Tasks, Docs, Epics)
22119
22119
 
22120
- When the user refers to a specific task, pull request, document, or epic by human identifier (e.g. \`AL-2980\`, \`2980\`, \`#45\`), title, or topic phrase:
22121
- - **Always resolve it with \`find_records\` first** (pass \`kinds: ["task"]\`, \`["document"]\`, \`["pull_request"]\`, or \`["epic"]\`).
22120
+ When the user refers to a specific task, document, or epic by human identifier (e.g. \`AL-2980\`, \`2980\`), title, or topic phrase:
22121
+ - **Always resolve it with \`find_records\` first** (pass \`kinds: ["task"]\`, \`["document"]\`, or \`["epic"]\`).
22122
22122
  - **Never scan with \`list_tasks\` or \`list_epics\`** to locate a specific item whose number or title you were already given \u2014 list tools are strictly for paginating browsable boards of work, not for lookup.
22123
22123
  - Once \`find_records\` returns the entity, call \`get_task\` / \`get_epic\` / \`get_document\` with the resolved identifier or UUID if full relational details, comments, or subtasks are required.
22124
22124
 
@@ -22610,8 +22610,8 @@ function decode3(bytes, start, end) {
22610
22610
  }
22611
22611
  async function linuxStartTicks(pid) {
22612
22612
  try {
22613
- const stat21 = await (0, import_promises9.readFile)(`/proc/${pid}/stat`, "utf8");
22614
- const fields = stat21.slice(stat21.lastIndexOf(")") + 2).split(" ");
22613
+ const stat22 = await (0, import_promises9.readFile)(`/proc/${pid}/stat`, "utf8");
22614
+ const fields = stat22.slice(stat22.lastIndexOf(")") + 2).split(" ");
22615
22615
  return fields[19];
22616
22616
  } catch {
22617
22617
  return void 0;
@@ -24658,35 +24658,99 @@ var init_reduce = __esm({
24658
24658
  });
24659
24659
 
24660
24660
  // ../shared/dist/agent/acp/conversation-messages.js
24661
+ function hasProviderCopy(meta3) {
24662
+ return Object.keys(meta3).some((key) => PROVIDER_COPY_META_KEYS.has(key));
24663
+ }
24664
+ function withoutProviderCopies(meta3) {
24665
+ return Object.fromEntries(Object.entries(meta3).filter(([key]) => !PROVIDER_COPY_META_KEYS.has(key)));
24666
+ }
24667
+ function toolContentText(content) {
24668
+ if (!Array.isArray(content))
24669
+ return null;
24670
+ const parts4 = [];
24671
+ for (const block of content) {
24672
+ const inner = isRecord8(block) && block.type === "content" ? block.content : block;
24673
+ if (!isRecord8(inner) || typeof inner.text !== "string")
24674
+ return null;
24675
+ parts4.push(inner.text);
24676
+ }
24677
+ return parts4.join("\n");
24678
+ }
24679
+ function parsedFromRawOutput(update) {
24680
+ const name = typeof update.name === "string" ? update.name : typeof update.title === "string" ? update.title : "";
24681
+ if (isAskUserQuestionTool(name, update.rawInput))
24682
+ return true;
24683
+ const input2 = typeof update.rawInput === "string" ? update.rawInput : JSON.stringify(update.rawInput ?? null);
24684
+ return /search_?context/i.test(`${name} ${input2}`.replace(/search_?code_?context/gi, ""));
24685
+ }
24686
+ function repeatsContent(update) {
24687
+ const output2 = update.rawOutput;
24688
+ if (typeof output2 !== "string" || output2.length === 0)
24689
+ return false;
24690
+ return output2 === toolContentText(update.content) && !parsedFromRawOutput(update);
24691
+ }
24692
+ function withoutProviderCopiesOf(value2) {
24693
+ if (!value2._meta || !hasProviderCopy(value2._meta))
24694
+ return value2;
24695
+ return { ...value2, _meta: withoutProviderCopies(value2._meta) };
24696
+ }
24697
+ function pageUpdate(update) {
24698
+ const meta3 = isRecord8(update._meta) ? update._meta : void 0;
24699
+ const dropPayload = meta3 !== void 0 && hasProviderCopy(meta3);
24700
+ const dropOutput = repeatsContent(update);
24701
+ if (!dropPayload && !dropOutput)
24702
+ return update;
24703
+ const entries = Object.entries(update).filter(([key]) => !(dropOutput && key === "rawOutput") && !(dropPayload && key === "_meta"));
24704
+ const slim = {
24705
+ ...Object.fromEntries(entries),
24706
+ sessionUpdate: update.sessionUpdate
24707
+ };
24708
+ if (dropPayload && meta3 !== void 0) {
24709
+ slim._meta = withoutProviderCopies(meta3);
24710
+ }
24711
+ return slim;
24712
+ }
24713
+ function pageNode(node2) {
24714
+ return {
24715
+ ...node2,
24716
+ event: { ...node2.event, update: pageUpdate(node2.event.update) },
24717
+ children: node2.children.map(pageNode)
24718
+ };
24719
+ }
24661
24720
  function compactConversationMessageTurns(turns, keepNewestEntries) {
24662
24721
  return turns.map((turn, index) => ({
24663
24722
  ...turn,
24664
24723
  display: turn.display.map((displayTurn) => {
24724
+ const working = displayTurn.working.map(pageNode);
24665
24725
  if (!displayTurn.final)
24666
- return displayTurn;
24726
+ return { ...displayTurn, working };
24667
24727
  return {
24668
24728
  ...displayTurn,
24669
- working: displayTurn.working.map((node2) => node2.key === displayTurn.final?.key ? {
24729
+ working: working.map((node2) => node2.key === displayTurn.final?.key ? {
24670
24730
  ...node2,
24671
24731
  children: [],
24672
24732
  event: {
24673
24733
  ...node2.event,
24674
24734
  update: { ...node2.event.update, content: [] }
24675
24735
  }
24676
- } : node2)
24736
+ } : node2),
24737
+ final: pageNode(displayTurn.final)
24677
24738
  };
24678
24739
  }),
24679
24740
  state: {
24680
24741
  ...turn.state,
24742
+ // Readers use only media updates from `unknown`; a provider's command list alone was 77 KB.
24743
+ unknown: turn.state.unknown.filter((update) => MEDIA_SESSION_UPDATE_KINDS.has(update.sessionUpdate)),
24681
24744
  entries: index === 0 && keepNewestEntries ? turn.state.entries.map((entry) => {
24682
- if (entry.kind === "message")
24683
- return entry.role === "user" ? entry : { ...entry, content: [] };
24684
- const ask = isAskUserQuestionTool(entry.title || entry.toolKind, entry.rawInput);
24745
+ const kept = withoutProviderCopiesOf(entry);
24746
+ if (kept.kind === "message")
24747
+ return kept.role === "user" ? kept : { ...kept, content: [] };
24748
+ const ask = isAskUserQuestionTool(kept.title || kept.toolKind, kept.rawInput);
24685
24749
  return {
24686
- ...entry,
24750
+ ...kept,
24687
24751
  content: [],
24688
24752
  locations: [],
24689
- rawInput: ask ? entry.rawInput : void 0,
24753
+ rawInput: ask ? kept.rawInput : void 0,
24690
24754
  rawOutput: void 0
24691
24755
  };
24692
24756
  }) : []
@@ -24779,12 +24843,58 @@ function conversationTurnView(ordinal, state, previousDisplay = []) {
24779
24843
  read: prepareConversationTurnRead(state)
24780
24844
  };
24781
24845
  }
24846
+ function diffArray(previous, next) {
24847
+ const changes = [];
24848
+ for (const [index, value2] of next.entries()) {
24849
+ if (previous[index] !== value2)
24850
+ changes.push({ index, value: value2 });
24851
+ }
24852
+ return { length: next.length, changes };
24853
+ }
24854
+ function stateFields(state) {
24855
+ const { entries: _entries, unknown: _unknown2, presentation: _presentation, ...fields } = state;
24856
+ return fields;
24857
+ }
24858
+ function diffTranscriptState(previous, next) {
24859
+ return {
24860
+ entries: diffArray(previous.entries, next.entries),
24861
+ unknown: diffArray(previous.unknown, next.unknown),
24862
+ fields: stateFields(next)
24863
+ };
24864
+ }
24865
+ function createLiveTurnFrameEncoder() {
24866
+ const sent = /* @__PURE__ */ new Map();
24867
+ return (ordinal, state) => {
24868
+ const previous = sent.get(ordinal);
24869
+ sent.delete(ordinal);
24870
+ sent.set(ordinal, state);
24871
+ for (const oldest of sent.keys()) {
24872
+ if (sent.size <= SENT_LIVE_TURNS)
24873
+ break;
24874
+ sent.delete(oldest);
24875
+ }
24876
+ return previous ? { kind: "patch", ordinal, patch: diffTranscriptState(previous, state) } : { kind: "snapshot", ordinal, state };
24877
+ };
24878
+ }
24782
24879
  function isRecord8(value2) {
24783
24880
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
24784
24881
  }
24785
24882
  function isTranscriptState(value2) {
24786
24883
  return isRecord8(value2) && typeof value2.state === "string" && Array.isArray(value2.entries) && Array.isArray(value2.notices) && Array.isArray(value2.unknown);
24787
24884
  }
24885
+ function isArrayPatch(value2) {
24886
+ return isRecord8(value2) && Number.isSafeInteger(value2.length) && Array.isArray(value2.changes) && value2.changes.every((change) => isRecord8(change) && Number.isSafeInteger(change.index) && "value" in change);
24887
+ }
24888
+ function isTranscriptStatePatch(value2) {
24889
+ return isRecord8(value2) && isArrayPatch(value2.entries) && isArrayPatch(value2.unknown) && isRecord8(value2.fields) && typeof value2.fields.state === "string" && Array.isArray(value2.fields.notices);
24890
+ }
24891
+ function isLiveTurnFrame(value2) {
24892
+ if (!isRecord8(value2) || !Number.isSafeInteger(value2.ordinal))
24893
+ return false;
24894
+ if (value2.kind === "snapshot")
24895
+ return isTranscriptState(value2.state);
24896
+ return value2.kind === "patch" && isTranscriptStatePatch(value2.patch);
24897
+ }
24788
24898
  function isPendingAsk(value2) {
24789
24899
  return value2 === null || isRecord8(value2) && typeof value2.toolCallId === "string" && isRecord8(value2.rawInput) && Array.isArray(value2.questions) && value2.questions.every((question) => isRecord8(question) && typeof question.question === "string" && (question.header === void 0 || typeof question.header === "string") && typeof question.multiSelect === "boolean" && Array.isArray(question.options) && question.options.every((option2) => isRecord8(option2) && typeof option2.label === "string" && (option2.description === void 0 || typeof option2.description === "string")));
24790
24900
  }
@@ -24800,6 +24910,7 @@ function isConversationMessageTurn(value2) {
24800
24910
  function isConversationMessagesPage(value2) {
24801
24911
  return isRecord8(value2) && typeof value2.revision === "string" && typeof value2.streamCursor === "string" && (value2.before === null || typeof value2.before === "string") && Array.isArray(value2.turns) && value2.turns.every(isConversationMessageTurn);
24802
24912
  }
24913
+ var PROVIDER_PAYLOAD_META_KEY, PROVIDER_EVENT_META_KEY, PROVIDER_COPY_META_KEYS, LIVE_TURN_FRAMES, LIVE_TURN_EVENT, SENT_LIVE_TURNS;
24803
24914
  var init_conversation_messages = __esm({
24804
24915
  "../shared/dist/agent/acp/conversation-messages.js"() {
24805
24916
  "use strict";
@@ -24810,6 +24921,16 @@ var init_conversation_messages = __esm({
24810
24921
  init_prepare_conversation_turns();
24811
24922
  init_reduce();
24812
24923
  init_transcript_http();
24924
+ init_types2();
24925
+ PROVIDER_PAYLOAD_META_KEY = "alan.dev/providerPayload";
24926
+ PROVIDER_EVENT_META_KEY = "alan.dev/providerEvent";
24927
+ PROVIDER_COPY_META_KEYS = /* @__PURE__ */ new Set([
24928
+ PROVIDER_PAYLOAD_META_KEY,
24929
+ PROVIDER_EVENT_META_KEY
24930
+ ]);
24931
+ LIVE_TURN_FRAMES = "patch";
24932
+ LIVE_TURN_EVENT = "live_turn";
24933
+ SENT_LIVE_TURNS = 8;
24813
24934
  }
24814
24935
  });
24815
24936
 
@@ -24835,15 +24956,6 @@ var init_transcript_byte_decoder = __esm({
24835
24956
  });
24836
24957
 
24837
24958
  // ../shared/dist/agent/acp/transcript-fold.js
24838
- function snapshotTranscriptState(state) {
24839
- return {
24840
- ...state,
24841
- entries: state.entries.map((entry) => entry.kind === "message" ? { ...entry, content: [...entry.content] } : { ...entry, content: [...entry.content], locations: [...entry.locations] }),
24842
- notices: [...state.notices],
24843
- unknown: [...state.unknown],
24844
- ...state.activities ? { activities: state.activities.map((activity) => ({ ...activity })) } : {}
24845
- };
24846
- }
24847
24959
  function isRecord9(value2) {
24848
24960
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
24849
24961
  }
@@ -24884,9 +24996,130 @@ function scopeTranscriptEvent(value2) {
24884
24996
  scoped.content = scopedContent(update.content, turnId);
24885
24997
  return { ...event, update: scoped };
24886
24998
  }
24999
+ function placeMessage(cache2, message2, updateOffset, entryOffset, startsWithPrompt) {
25000
+ const cached2 = cache2.get(message2.messageId);
25001
+ const source = message2.state;
25002
+ const sameSource = cached2?.source === source;
25003
+ if (sameSource && cached2.updateCount === source.updateCount && cached2.updateOffset === updateOffset && cached2.entryOffset === entryOffset && cached2.startsWithPrompt === startsWithPrompt)
25004
+ return cached2.state;
25005
+ const replacedEntries = cached2 && !sameSource ? cached2.source.entries : void 0;
25006
+ const entries = source.entries.map((entry, index) => {
25007
+ const previous = cached2?.state.entries[index];
25008
+ const lastUpdateIndex = entry.lastUpdateIndex === void 0 ? void 0 : entry.lastUpdateIndex + updateOffset;
25009
+ if (previous && cached2.updateOffset === updateOffset && previous.id === entry.id && previous.kind === entry.kind && (sameSource ? entry.lastUpdateIndex !== void 0 && previous.lastUpdateIndex === lastUpdateIndex : replacedEntries?.[index] === entry))
25010
+ return previous;
25011
+ return entry.kind === "message" ? { ...entry, lastUpdateIndex, content: [...entry.content] } : {
25012
+ ...entry,
25013
+ lastUpdateIndex,
25014
+ content: [...entry.content],
25015
+ locations: [...entry.locations]
25016
+ };
25017
+ });
25018
+ const state = {
25019
+ ...source,
25020
+ entries,
25021
+ notices: [...source.notices],
25022
+ unknown: [...source.unknown],
25023
+ ...source.activities ? {
25024
+ activities: source.activities.map((activity) => ({
25025
+ ...activity,
25026
+ firstEntryIndex: entryOffset + activity.firstEntryIndex - (startsWithPrompt && activity.firstEntryIndex === 0 ? 1 : 0)
25027
+ }))
25028
+ } : {}
25029
+ };
25030
+ cache2.set(message2.messageId, {
25031
+ source,
25032
+ updateCount: source.updateCount,
25033
+ updateOffset,
25034
+ entryOffset,
25035
+ startsWithPrompt,
25036
+ state
25037
+ });
25038
+ return state;
25039
+ }
25040
+ function anchoredUpdateOffset(ordered, cache2) {
25041
+ let natural = 0;
25042
+ for (const message2 of ordered) {
25043
+ const placed = cache2.get(message2.messageId);
25044
+ if (placed)
25045
+ return natural - placed.updateOffset;
25046
+ natural += message2.state.updateCount ?? 0;
25047
+ }
25048
+ return 0;
25049
+ }
25050
+ function mergeTranscriptMessages(messages, cache2) {
25051
+ const merged = emptyTranscript();
25052
+ const ordered = [...messages].sort((left, right) => (left.turnOrdinal ?? 0) - (right.turnOrdinal ?? 0) || left.messageId.localeCompare(right.messageId));
25053
+ let updateOffset = -anchoredUpdateOffset(ordered, cache2);
25054
+ const seenToolIds = /* @__PURE__ */ new Set();
25055
+ const seenNotices = /* @__PURE__ */ new Set();
25056
+ for (const message2 of ordered) {
25057
+ const entryOffset = merged.entries.length;
25058
+ const previous = merged.entries.at(-1);
25059
+ const startsWithPrompt = message2.role !== "user" && previous?.kind === "message" && previous.role === "user";
25060
+ const state = placeMessage(cache2, message2, updateOffset, entryOffset, startsWithPrompt);
25061
+ const removedBefore = [0];
25062
+ const duplicateToolIds = /* @__PURE__ */ new Set();
25063
+ for (const entry of state.entries) {
25064
+ const parentId = entry._meta?.["alan.dev/parentToolCallId"];
25065
+ const rawId = entry._meta?.[TRANSCRIPT_TOOL_RESPONSE_ID_META];
25066
+ const providerEvent = entry._meta?.["alan.dev/providerEvent"];
25067
+ const providerEventId = providerEvent && typeof providerEvent === "object" && "id" in providerEvent ? providerEvent.id : void 0;
25068
+ const toolId = entry.kind === "tool_call" && typeof rawId === "string" && typeof providerEventId === "string" ? `${rawId}:${providerEventId}` : void 0;
25069
+ const duplicate = toolId !== void 0 && seenToolIds.has(toolId) || typeof parentId === "string" && duplicateToolIds.has(parentId);
25070
+ if (!duplicate) {
25071
+ merged.entries.push(entry);
25072
+ if (toolId)
25073
+ seenToolIds.add(toolId);
25074
+ }
25075
+ if (duplicate && toolId)
25076
+ duplicateToolIds.add(entry.id);
25077
+ removedBefore.push((removedBefore.at(-1) ?? 0) + Number(duplicate));
25078
+ }
25079
+ if (state.activities?.length) {
25080
+ merged.activities ??= [];
25081
+ merged.activities.push(...state.activities.map((activity, index) => ({
25082
+ ...activity,
25083
+ firstEntryIndex: activity.firstEntryIndex - (removedBefore[message2.state.activities?.[index]?.firstEntryIndex ?? 0] ?? 0)
25084
+ })));
25085
+ }
25086
+ for (const notice2 of state.notices) {
25087
+ const key = JSON.stringify([notice2.level, notice2.message]);
25088
+ if (seenNotices.has(key))
25089
+ continue;
25090
+ seenNotices.add(key);
25091
+ merged.notices.push({
25092
+ ...notice2,
25093
+ firstEntryIndex: startsWithPrompt ? entryOffset - 1 : entryOffset
25094
+ });
25095
+ }
25096
+ merged.unknown.push(...state.unknown);
25097
+ if (state.userMessageAt !== void 0)
25098
+ merged.userMessageAt = Math.max(merged.userMessageAt ?? state.userMessageAt, state.userMessageAt);
25099
+ if (message2.role !== "user") {
25100
+ merged.state = state.state;
25101
+ merged.stopReason = state.stopReason;
25102
+ merged.thinkingTokens = state.thinkingTokens;
25103
+ if (state.awaitingToolCallIds)
25104
+ merged.awaitingToolCallIds = state.awaitingToolCallIds;
25105
+ else
25106
+ delete merged.awaitingToolCallIds;
25107
+ }
25108
+ if (state.plan)
25109
+ merged.plan = state.plan;
25110
+ if (state.usage)
25111
+ merged.usage = state.usage;
25112
+ if (state.title)
25113
+ merged.title = state.title;
25114
+ updateOffset += state.updateCount ?? 0;
25115
+ }
25116
+ merged.updateCount = updateOffset;
25117
+ return merged;
25118
+ }
24887
25119
  var init_transcript_fold = __esm({
24888
25120
  "../shared/dist/agent/acp/transcript-fold.js"() {
24889
25121
  "use strict";
25122
+ init_reduce();
24890
25123
  init_transcript_http();
24891
25124
  init_types2();
24892
25125
  }
@@ -24925,7 +25158,7 @@ var init_acp = __esm({
24925
25158
  }
24926
25159
  });
24927
25160
 
24928
- // ../agent-core/dist/chunk-UGRKZTAD.js
25161
+ // ../agent-core/dist/chunk-XC5676SG.js
24929
25162
  function textBlock(text2) {
24930
25163
  return { type: "text", text: text2 };
24931
25164
  }
@@ -25156,13 +25389,13 @@ function withoutInlineMedia(update) {
25156
25389
  };
25157
25390
  }
25158
25391
  var PROVIDER_PAYLOAD_META, TOOL_RESULT_ONLY_META, PARENT_TOOL_CALL_META, SUBAGENT_LAUNCHER_META, SUBAGENT_TASK_ID_META, SUBAGENT_OUTPUT_FILE_META, USAGE_META, TODOS_META, NOTICE_KIND_META, ASK_USER_QUESTIONS_META, USER_ANSWER_META, AWAITING_TOOL_CALLS_META2, EXIT_PLAN_MODE_INPUT_META, BACKGROUND_TASK_META, TASK_PROGRESS_META, RATE_LIMIT_META, MODEL_META, TOOLS_META, SLASH_COMMANDS_META, TOOL_KIND_RULES, ANSWER_PREFIX, ACCEPT_WORDS, MIN_INLINE_MEDIA_CHARS, DATA_URL_PREFIX, BASE64_BODY;
25159
- var init_chunk_UGRKZTAD = __esm({
25160
- "../agent-core/dist/chunk-UGRKZTAD.js"() {
25392
+ var init_chunk_XC5676SG = __esm({
25393
+ "../agent-core/dist/chunk-XC5676SG.js"() {
25161
25394
  "use strict";
25162
25395
  init_chunk_YXWJW7I5();
25163
25396
  init_constants();
25164
25397
  init_acp();
25165
- PROVIDER_PAYLOAD_META = "alan.dev/providerPayload";
25398
+ PROVIDER_PAYLOAD_META = PROVIDER_PAYLOAD_META_KEY;
25166
25399
  TOOL_RESULT_ONLY_META = "alan.dev/toolResultOnly";
25167
25400
  PARENT_TOOL_CALL_META = "alan.dev/parentToolCallId";
25168
25401
  SUBAGENT_LAUNCHER_META = "alan.dev/subagentLauncher";
@@ -25207,12 +25440,12 @@ var init_chunk_UGRKZTAD = __esm({
25207
25440
  var init_acp2 = __esm({
25208
25441
  "../agent-core/dist/acp.js"() {
25209
25442
  "use strict";
25210
- init_chunk_UGRKZTAD();
25443
+ init_chunk_XC5676SG();
25211
25444
  init_chunk_YXWJW7I5();
25212
25445
  }
25213
25446
  });
25214
25447
 
25215
- // ../agent-core/dist/chunk-DALFHI4B.js
25448
+ // ../agent-core/dist/chunk-SBT5W7L4.js
25216
25449
  function isRecordValue(value2) {
25217
25450
  return value2 !== null;
25218
25451
  }
@@ -25391,10 +25624,10 @@ function readTranscriptTurns(transcript, chunk, baseOffset, skipped = []) {
25391
25624
  return { turns, consumedBytes: consumedEnd - baseOffset };
25392
25625
  }
25393
25626
  var import_fs3, NEWLINE2, TranscriptCursor, TranscriptLineLookup, CONTENT_UPDATES;
25394
- var init_chunk_DALFHI4B = __esm({
25395
- "../agent-core/dist/chunk-DALFHI4B.js"() {
25627
+ var init_chunk_SBT5W7L4 = __esm({
25628
+ "../agent-core/dist/chunk-SBT5W7L4.js"() {
25396
25629
  "use strict";
25397
- init_chunk_UGRKZTAD();
25630
+ init_chunk_XC5676SG();
25398
25631
  init_chunk_YXWJW7I5();
25399
25632
  import_fs3 = require("fs");
25400
25633
  NEWLINE2 = 10;
@@ -25947,7 +26180,7 @@ var init_chunk_54ZRJOQP = __esm({
25947
26180
  }
25948
26181
  });
25949
26182
 
25950
- // ../agent-core/dist/chunk-KHYYC5IN.js
26183
+ // ../agent-core/dist/chunk-VMGVHPBB.js
25951
26184
  function collectStrings(value2, out) {
25952
26185
  if (typeof value2 === "string") out.push(value2);
25953
26186
  else if (Array.isArray(value2)) for (const item of value2) collectStrings(item, out);
@@ -26039,8 +26272,8 @@ function readMediaFiles(candidates2, cwd, mimeByExt, maxBytes) {
26039
26272
  seen.add(path4);
26040
26273
  const mimeType = mimeByExt[(0, import_path3.extname)(path4).toLowerCase()];
26041
26274
  if (!mimeType) continue;
26042
- const stat21 = (0, import_fs4.statSync)(path4);
26043
- if (!stat21.isFile() || stat21.size <= 0 || stat21.size > maxBytes) continue;
26275
+ const stat22 = (0, import_fs4.statSync)(path4);
26276
+ if (!stat22.isFile() || stat22.size <= 0 || stat22.size > maxBytes) continue;
26044
26277
  files.push({ path: path4, mimeType, buffer: (0, import_fs4.readFileSync)(path4) });
26045
26278
  }
26046
26279
  return files;
@@ -26317,10 +26550,10 @@ function silentStartError(name, timeoutMs) {
26317
26550
  };
26318
26551
  }
26319
26552
  var import_crypto3, import_fs4, import_path3, IMAGE_MIME_BY_EXT, VIDEO_MIME_BY_EXT, IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, AGENT_BROWSER_MENTION, LocalMediaReader, SessionOpenRefusal, JsonRpcError, ACP_PROTOCOL_VERSION, ACP_ERROR, STDERR_TAIL_LINES, RESULT_EXIT_GRACE_MS, PerTurnSession;
26320
- var init_chunk_KHYYC5IN = __esm({
26321
- "../agent-core/dist/chunk-KHYYC5IN.js"() {
26553
+ var init_chunk_VMGVHPBB = __esm({
26554
+ "../agent-core/dist/chunk-VMGVHPBB.js"() {
26322
26555
  "use strict";
26323
- init_chunk_UGRKZTAD();
26556
+ init_chunk_XC5676SG();
26324
26557
  init_chunk_54ZRJOQP();
26325
26558
  init_chunk_M6YHY2EZ();
26326
26559
  init_chunk_YXWJW7I5();
@@ -27985,6 +28218,9 @@ function classifyResultError(event, context) {
27985
28218
  if (classified.errorKind !== "unknown_cli_error" || !isApiError) return classified;
27986
28219
  return { ...specForErrorKind("provider_error"), message: classified.message };
27987
28220
  }
28221
+ function isIdleUpdate(update) {
28222
+ return isUpdate(update, "state_update") && update.state === "idle";
28223
+ }
27988
28224
  function isSettled22(update) {
27989
28225
  return update.status === "completed" || update.status === "failed" || update.status === "cancelled";
27990
28226
  }
@@ -28412,9 +28648,9 @@ var import_crypto6, import_fs5, import_path5, import_crypto7, import_promises31,
28412
28648
  var init_claude = __esm({
28413
28649
  "../agent-core/dist/providers/claude.js"() {
28414
28650
  "use strict";
28415
- init_chunk_DALFHI4B();
28416
- init_chunk_KHYYC5IN();
28417
- init_chunk_UGRKZTAD();
28651
+ init_chunk_SBT5W7L4();
28652
+ init_chunk_VMGVHPBB();
28653
+ init_chunk_XC5676SG();
28418
28654
  init_chunk_54ZRJOQP();
28419
28655
  init_chunk_J2KTV5FP();
28420
28656
  init_chunk_M6YHY2EZ();
@@ -28721,6 +28957,7 @@ var init_claude = __esm({
28721
28957
  #failure;
28722
28958
  #authFailure;
28723
28959
  #resultSeen = false;
28960
+ #heldIdle;
28724
28961
  constructor(options = {}) {
28725
28962
  this.#options = options;
28726
28963
  this.taskRecords = options.taskRecords ?? new TaskRecords(options.now ?? (() => systemClock2.now()));
@@ -28768,7 +29005,17 @@ var init_claude = __esm({
28768
29005
  readEvent(event) {
28769
29006
  const parsed = this.#revise(parseClaudeEvent(event, this.grammar), event);
28770
29007
  parsed.push(...this.#handle(event));
28771
- const updates = parsed.map((update) => this.taskRecords.stamp(update));
29008
+ const kept = parsed.filter((update) => {
29009
+ if (!isIdleUpdate(update)) return true;
29010
+ if (this.#finalized) return true;
29011
+ this.#heldIdle = update;
29012
+ return false;
29013
+ });
29014
+ if (this.#finalized && this.#heldIdle !== void 0) {
29015
+ if (!kept.some(isIdleUpdate)) kept.push(this.#heldIdle);
29016
+ this.#heldIdle = void 0;
29017
+ }
29018
+ const updates = kept.map((update) => this.taskRecords.stamp(update));
28772
29019
  for (const update of updates) this.#applyRunState(update);
28773
29020
  return updates;
28774
29021
  }
@@ -31189,9 +31436,9 @@ var import_fs6, import_path6, import_crypto8, import_crypto9, import_crypto10, T
31189
31436
  var init_codex = __esm({
31190
31437
  "../agent-core/dist/providers/codex.js"() {
31191
31438
  "use strict";
31192
- init_chunk_DALFHI4B();
31193
- init_chunk_KHYYC5IN();
31194
- init_chunk_UGRKZTAD();
31439
+ init_chunk_SBT5W7L4();
31440
+ init_chunk_VMGVHPBB();
31441
+ init_chunk_XC5676SG();
31195
31442
  init_chunk_54ZRJOQP();
31196
31443
  init_chunk_J2KTV5FP();
31197
31444
  init_chunk_M6YHY2EZ();
@@ -42460,8 +42707,8 @@ var require_tar_stream = __commonJS({
42460
42707
  var init_dist = __esm({
42461
42708
  "../agent-core/dist/index.js"() {
42462
42709
  "use strict";
42463
- init_chunk_KHYYC5IN();
42464
- init_chunk_UGRKZTAD();
42710
+ init_chunk_VMGVHPBB();
42711
+ init_chunk_XC5676SG();
42465
42712
  init_chunk_54ZRJOQP();
42466
42713
  init_chunk_M6YHY2EZ();
42467
42714
  init_chunk_YXWJW7I5();
@@ -43207,8 +43454,8 @@ var import_promises48, import_path9, import_crypto12, import_promises49, CURSOR_
43207
43454
  var init_acp3 = __esm({
43208
43455
  "../agent-core/dist/providers/acp.js"() {
43209
43456
  "use strict";
43210
- init_chunk_KHYYC5IN();
43211
- init_chunk_UGRKZTAD();
43457
+ init_chunk_VMGVHPBB();
43458
+ init_chunk_XC5676SG();
43212
43459
  init_chunk_54ZRJOQP();
43213
43460
  init_chunk_J2KTV5FP();
43214
43461
  init_chunk_M6YHY2EZ();
@@ -44092,15 +44339,16 @@ function createPersistentDriver(provider4, options) {
44092
44339
  return void 0;
44093
44340
  };
44094
44341
  const resumeNotice = (spec, session, sink) => {
44342
+ if (spec.resumeFallbackContext) {
44343
+ log.info("holder.session_resume_fallback", { harness: provider4.harness, runId: spec.runId });
44344
+ return { session, contextPrefix: spec.resumeFallbackContext };
44345
+ }
44095
44346
  sink.onEvent({
44096
44347
  seq: 0,
44097
44348
  at: clock.now(),
44098
44349
  update: noticeUpdate("warning", "session_resume_failed", RESUME_UNAVAILABLE)
44099
44350
  });
44100
- return {
44101
- session,
44102
- ...spec.resumeFallbackContext ? { contextPrefix: spec.resumeFallbackContext } : {}
44103
- };
44351
+ return { session };
44104
44352
  };
44105
44353
  const managedMcpAccess = async (signal) => {
44106
44354
  const managed = options.managedMcp;
@@ -44175,6 +44423,7 @@ function createPersistentDriver(provider4, options) {
44175
44423
  };
44176
44424
  const _events = __using(_stack, session.onEvent(forward));
44177
44425
  live.turn = turn;
44426
+ record2({ sessionUpdate: "state_update", state: "running" });
44178
44427
  if (session.pid !== void 0) sink.onSpawned(session.pid);
44179
44428
  const onAbort = () => {
44180
44429
  void session.cancel();
@@ -44911,8 +45160,8 @@ var import_http10, import_crypto13, import_promises50, import_path10, import_pat
44911
45160
  var init_opencode = __esm({
44912
45161
  "../agent-core/dist/providers/opencode.js"() {
44913
45162
  "use strict";
44914
- init_chunk_KHYYC5IN();
44915
- init_chunk_UGRKZTAD();
45163
+ init_chunk_VMGVHPBB();
45164
+ init_chunk_XC5676SG();
44916
45165
  init_chunk_54ZRJOQP();
44917
45166
  init_chunk_J2KTV5FP();
44918
45167
  init_chunk_M6YHY2EZ();
@@ -44927,6 +45176,7 @@ var init_opencode = __esm({
44927
45176
  import_path11 = require("path");
44928
45177
  import_url2 = require("url");
44929
45178
  init_acp();
45179
+ init_acp();
44930
45180
  import_crypto14 = require("crypto");
44931
45181
  init_agent2();
44932
45182
  IDLE_SOCKET_MS3 = 4e3;
@@ -45245,7 +45495,7 @@ var init_opencode = __esm({
45245
45495
  ["DataPolicyError", "model_mismatch"]
45246
45496
  ]);
45247
45497
  OPENCODE_ABORTED_ERROR = "MessageAbortedError";
45248
- PROVIDER_EVENT_META = "alan.dev/providerEvent";
45498
+ PROVIDER_EVENT_META = PROVIDER_EVENT_META_KEY;
45249
45499
  TASK_TOOL_NAME = "task";
45250
45500
  TASK_RESULT_TAG = /<task_result>\n?([\s\S]*?)\n?<\/task_result>/;
45251
45501
  TASK_ERROR_TAG = /<task_error>\n?([\s\S]*?)\n?<\/task_error>/;
@@ -46106,7 +46356,7 @@ function createAlanCodeHolderDriver(options) {
46106
46356
  open: open6,
46107
46357
  turnInput: async (spec, inputs, contextPrefix) => openCodeTurnInput(spec, {
46108
46358
  attachments: inputs.attachments,
46109
- skills: [],
46359
+ skills: inputs.skills,
46110
46360
  ...contextPrefix === void 0 ? {} : { contextPrefix }
46111
46361
  })
46112
46362
  },
@@ -46719,8 +46969,8 @@ var import_crypto15, import_promises51, FACTORY_API_VERSION, FACTORY_PROTOCOL_VE
46719
46969
  var init_droid = __esm({
46720
46970
  "../agent-core/dist/providers/droid.js"() {
46721
46971
  "use strict";
46722
- init_chunk_KHYYC5IN();
46723
- init_chunk_UGRKZTAD();
46972
+ init_chunk_VMGVHPBB();
46973
+ init_chunk_XC5676SG();
46724
46974
  init_chunk_54ZRJOQP();
46725
46975
  init_chunk_J2KTV5FP();
46726
46976
  init_chunk_M6YHY2EZ();
@@ -47122,7 +47372,7 @@ function createDroidHolderDriver(options) {
47122
47372
  },
47123
47373
  turnInput: (spec, inputs, contextPrefix) => droidTurnInput(spec, {
47124
47374
  attachments: inputs.attachments,
47125
- skills: [],
47375
+ skills: inputs.skills,
47126
47376
  ...contextPrefix === void 0 ? {} : { contextPrefix }
47127
47377
  })
47128
47378
  },
@@ -47170,7 +47420,7 @@ function createOpenCodeHolderDriver(options) {
47170
47420
  },
47171
47421
  turnInput: async (spec, inputs, contextPrefix) => openCodeTurnInput(spec, {
47172
47422
  attachments: inputs.attachments,
47173
- skills: [],
47423
+ skills: inputs.skills,
47174
47424
  ...contextPrefix === void 0 ? {} : { contextPrefix }
47175
47425
  })
47176
47426
  },
@@ -47821,9 +48071,9 @@ var import_promises52, import_path12, import_fs8, import_path13, import_path14,
47821
48071
  var init_antigravity = __esm({
47822
48072
  "../agent-core/dist/providers/antigravity.js"() {
47823
48073
  "use strict";
47824
- init_chunk_DALFHI4B();
47825
- init_chunk_KHYYC5IN();
47826
- init_chunk_UGRKZTAD();
48074
+ init_chunk_SBT5W7L4();
48075
+ init_chunk_VMGVHPBB();
48076
+ init_chunk_XC5676SG();
47827
48077
  init_chunk_54ZRJOQP();
47828
48078
  init_chunk_M6YHY2EZ();
47829
48079
  init_chunk_ITTV3UIM();
@@ -48526,8 +48776,8 @@ var import_promises53, import_path15, import_crypto17, COMMAND_CODE_GRAMMAR_NAME
48526
48776
  var init_command_code = __esm({
48527
48777
  "../agent-core/dist/providers/command-code.js"() {
48528
48778
  "use strict";
48529
- init_chunk_KHYYC5IN();
48530
- init_chunk_UGRKZTAD();
48779
+ init_chunk_VMGVHPBB();
48780
+ init_chunk_XC5676SG();
48531
48781
  init_chunk_54ZRJOQP();
48532
48782
  init_chunk_J2KTV5FP();
48533
48783
  init_chunk_M6YHY2EZ();
@@ -53929,7 +54179,7 @@ var require_websocket_server = __commonJS({
53929
54179
  // package.json
53930
54180
  var package_default = {
53931
54181
  name: "@alan-ai-hq/agent-manager",
53932
- version: "0.1.138",
54182
+ version: "0.1.140",
53933
54183
  private: true,
53934
54184
  type: "module",
53935
54185
  description: "Alan machine runtime (alan-agent): identity, link, reconciler, session holders, run log, uploader, local API",
@@ -53979,7 +54229,7 @@ var package_default = {
53979
54229
 
53980
54230
  // src/cli/commands/compat.ts
53981
54231
  var import_node_crypto31 = require("crypto");
53982
- var import_promises66 = require("fs/promises");
54232
+ var import_promises67 = require("fs/promises");
53983
54233
  init_runtime_v2();
53984
54234
  init_zod();
53985
54235
 
@@ -54823,7 +55073,8 @@ var openTurnResponseSchema = external_exports.object({
54823
55073
  runId: external_exports.string().min(1),
54824
55074
  userMessageId: external_exports.string().min(1),
54825
55075
  assistantMessageId: external_exports.string().min(1),
54826
- created: external_exports.boolean()
55076
+ created: external_exports.boolean(),
55077
+ turnOrdinals: external_exports.object({ user: external_exports.number().int().nonnegative(), assistant: external_exports.number().int().nonnegative() }).optional()
54827
55078
  });
54828
55079
  var errorBodySchema2 = external_exports.object({ code: external_exports.string() });
54829
55080
  function createNativeSessionsClient({
@@ -56707,9 +56958,9 @@ function isProcessAlive(pid) {
56707
56958
  }
56708
56959
  }
56709
56960
  async function linuxStartTime(pid) {
56710
- const stat21 = await (0, import_promises13.readFile)(`/proc/${pid}/stat`, "utf8").catch(() => null);
56711
- if (stat21 === null) return null;
56712
- const fields = stat21.slice(stat21.lastIndexOf(")") + 2).split(" ");
56961
+ const stat22 = await (0, import_promises13.readFile)(`/proc/${pid}/stat`, "utf8").catch(() => null);
56962
+ if (stat22 === null) return null;
56963
+ const fields = stat22.slice(stat22.lastIndexOf(")") + 2).split(" ");
56713
56964
  return fields[19] ?? null;
56714
56965
  }
56715
56966
  async function linuxCommand(pid) {
@@ -61599,9 +61850,23 @@ async function ingestTurn(ctx, worker, entry, turn) {
61599
61850
  },
61600
61851
  ctx.shutdown
61601
61852
  );
61853
+ const ordinals = opened.turnOrdinals;
61602
61854
  await ctx.publisher.publish({
61603
61855
  runId: opened.runId,
61604
61856
  conversationId: entry.conversationId,
61857
+ ...ordinals ? {
61858
+ userMessage: {
61859
+ id: opened.userMessageId,
61860
+ content: userMessage,
61861
+ turnOrdinal: ordinals.user,
61862
+ createdAt: startedAt
61863
+ },
61864
+ assistantMessage: {
61865
+ id: opened.assistantMessageId,
61866
+ turnOrdinal: ordinals.assistant,
61867
+ createdAt: startedAt
61868
+ }
61869
+ } : {},
61605
61870
  records: nativeTurnRecords({
61606
61871
  updates: withTerminalIdle(turn.updates, startedAt),
61607
61872
  startedAt,
@@ -65639,7 +65904,7 @@ async function openWorkspaces(options) {
65639
65904
 
65640
65905
  // src/cli/config.ts
65641
65906
  var import_node_os11 = require("os");
65642
- var import_node_path65 = require("path");
65907
+ var import_node_path66 = require("path");
65643
65908
  init_zod();
65644
65909
 
65645
65910
  // src/client/contract.ts
@@ -65942,14 +66207,18 @@ function applyField(pending, line) {
65942
66207
  }
65943
66208
  async function* readServerSentEvents(body) {
65944
66209
  const decoder3 = new TextDecoder();
65945
- let buffer = "";
66210
+ let partial2 = [];
65946
66211
  let pending = emptyEvent();
65947
66212
  for await (const chunk of body) {
65948
- buffer += decoder3.decode(chunk, { stream: true });
65949
- let newline = buffer.indexOf("\n");
66213
+ const text2 = decoder3.decode(chunk, { stream: true });
66214
+ let start = 0;
66215
+ let newline = text2.indexOf("\n");
65950
66216
  while (newline !== -1) {
65951
- const line = buffer.slice(0, newline).replace(/\r$/, "");
65952
- buffer = buffer.slice(newline + 1);
66217
+ partial2.push(text2.slice(start, newline));
66218
+ const line = partial2.join("").replace(/\r$/, "");
66219
+ partial2 = [];
66220
+ start = newline + 1;
66221
+ newline = text2.indexOf("\n", start);
65953
66222
  if (line.length === 0) {
65954
66223
  if (pending.data.length > 0) {
65955
66224
  yield { event: pending.event, id: pending.id, data: pending.data.join("\n") };
@@ -65958,8 +66227,8 @@ async function* readServerSentEvents(body) {
65958
66227
  } else if (!line.startsWith(":")) {
65959
66228
  applyField(pending, line);
65960
66229
  }
65961
- newline = buffer.indexOf("\n");
65962
66230
  }
66231
+ if (start < text2.length) partial2.push(text2.slice(start));
65963
66232
  }
65964
66233
  }
65965
66234
 
@@ -65996,6 +66265,23 @@ async function readDiscovery(path4) {
65996
66265
  }
65997
66266
  return parsed.data;
65998
66267
  }
66268
+ function conversationQuery(query) {
66269
+ return {
66270
+ limit: String(query.limit),
66271
+ ...query.before ? { before: query.before } : {},
66272
+ ...query.runtimeId ? { runtimeId: query.runtimeId } : {}
66273
+ };
66274
+ }
66275
+ function conversationUpdate(event) {
66276
+ const value2 = JSON.parse(event.data);
66277
+ if (event.event === "snapshot" && isConversationMessagesPage(value2))
66278
+ return { kind: "snapshot", page: value2 };
66279
+ if (event.event === "turn" && isConversationMessageTurn(value2))
66280
+ return { kind: "turn", turn: value2 };
66281
+ if (event.event === LIVE_TURN_EVENT && isLiveTurnFrame(value2))
66282
+ return { kind: "live_turn", frame: value2 };
66283
+ throw new RuntimeClientError("protocol", "Invalid local conversation update");
66284
+ }
65999
66285
  function parseWith(schema, raw, what) {
66000
66286
  const parsed = schema.safeParse(raw);
66001
66287
  if (!parsed.success) {
@@ -66141,24 +66427,17 @@ function createRuntimeClient(options) {
66141
66427
  throw new RuntimeClientError("unavailable", "The run log stream closed before the run ended");
66142
66428
  }
66143
66429
  const runs = async (signal) => (await json2({ path: LOCAL_API_ROUTES.runs }, runsResponseSchema, signal)).runs;
66144
- async function* followConversationMessages(conversationId, limit, signal) {
66430
+ async function* followConversationMessages(query, signal) {
66145
66431
  const stopped = new AbortController();
66146
66432
  try {
66147
66433
  const body = await openStream(
66148
66434
  {
66149
- path: `/v2/conversations/${encodeURIComponent(conversationId)}/messages/sse`,
66150
- query: { limit: String(limit) }
66435
+ path: `/v2/conversations/${encodeURIComponent(query.conversationId)}/messages/sse`,
66436
+ query: { ...conversationQuery(query), frames: LIVE_TURN_FRAMES }
66151
66437
  },
66152
66438
  AbortSignal.any([signal, stopped.signal])
66153
66439
  );
66154
- for await (const event of readServerSentEvents(body)) {
66155
- const value2 = JSON.parse(event.data);
66156
- if (event.event === "snapshot" && isConversationMessagesPage(value2))
66157
- yield { kind: "snapshot", page: value2 };
66158
- else if (event.event === "turn" && isConversationMessageTurn(value2))
66159
- yield { kind: "turn", turn: value2 };
66160
- else throw new RuntimeClientError("protocol", "Invalid local conversation update");
66161
- }
66440
+ for await (const event of readServerSentEvents(body)) yield conversationUpdate(event);
66162
66441
  if (!signal.aborted)
66163
66442
  throw new RuntimeClientError("unavailable", "The local conversation stream closed");
66164
66443
  } finally {
@@ -66171,11 +66450,11 @@ function createRuntimeClient(options) {
66171
66450
  followConversationMessages,
66172
66451
  runs,
66173
66452
  conversationRuns: async (conversationId, signal) => (await runs(signal)).filter((run2) => run2.conversationId === conversationId),
66174
- readConversationMessages: async (conversationId, limit, before, signal) => {
66453
+ readConversationMessages: async (query, signal) => {
66175
66454
  const response = await send2(
66176
66455
  {
66177
- path: `/v2/conversations/${encodeURIComponent(conversationId)}/messages`,
66178
- query: { limit: String(limit), ...before === null ? {} : { before } }
66456
+ path: `/v2/conversations/${encodeURIComponent(query.conversationId)}/messages`,
66457
+ query: conversationQuery(query)
66179
66458
  },
66180
66459
  signal
66181
66460
  );
@@ -66352,9 +66631,9 @@ async function sendNativeHookSignal(discoveryPath, hookSignal, signal) {
66352
66631
 
66353
66632
  // src/sessions/index.ts
66354
66633
  var import_node_crypto30 = require("crypto");
66355
- var import_promises64 = require("fs/promises");
66634
+ var import_promises65 = require("fs/promises");
66356
66635
  var import_node_os10 = require("os");
66357
- var import_node_path64 = require("path");
66636
+ var import_node_path65 = require("path");
66358
66637
  init_runtime_v2();
66359
66638
 
66360
66639
  // src/holder/control-client.ts
@@ -66770,7 +67049,7 @@ async function prepareRunInputs(spec, { source, tmpDir, signal, skills = [] }) {
66770
67049
  var import_node_crypto29 = require("crypto");
66771
67050
  var import_node_fs21 = require("fs");
66772
67051
  var import_node_net3 = require("net");
66773
- var import_node_path63 = require("path");
67052
+ var import_node_path64 = require("path");
66774
67053
  init_runtime_v2();
66775
67054
 
66776
67055
  // src/holder/admission.ts
@@ -67524,14 +67803,42 @@ function createSessionFacts(options) {
67524
67803
  // src/holder/turn.ts
67525
67804
  init_acp2();
67526
67805
 
67806
+ // src/run-log/archive.ts
67807
+ var import_promises61 = require("fs/promises");
67808
+ var import_node_path59 = require("path");
67809
+ init_runtime_v2();
67810
+ async function openRunArchive(runsDir) {
67811
+ const path4 = (0, import_node_path59.join)((0, import_node_path59.dirname)(runsDir), "archived-runs.txt");
67812
+ const text2 = await (0, import_promises61.readFile)(path4, "utf8").catch((error61) => {
67813
+ if (errnoCode(error61) === "ENOENT") return "";
67814
+ throw error61;
67815
+ });
67816
+ const archived = /* @__PURE__ */ new Set();
67817
+ for (const line of text2.split("\n")) {
67818
+ const runId = runIdSchema.safeParse(line);
67819
+ if (runId.success) archived.add(runId.data);
67820
+ }
67821
+ return {
67822
+ has: (runId) => archived.has(runId),
67823
+ add: async (runIds) => {
67824
+ const added = runIds.filter((runId) => !archived.has(runId));
67825
+ if (added.length === 0) return;
67826
+ await (0, import_promises61.appendFile)(path4, `
67827
+ ${added.join("\n")}
67828
+ `, { mode: 384 });
67829
+ for (const runId of added) archived.add(runId);
67830
+ }
67831
+ };
67832
+ }
67833
+
67527
67834
  // src/run-log/complete.ts
67528
67835
  var import_node_crypto28 = require("crypto");
67529
67836
  var import_node_fs19 = require("fs");
67530
- var import_node_path60 = require("path");
67837
+ var import_node_path61 = require("path");
67531
67838
 
67532
67839
  // src/run-log/directory.ts
67533
- var import_promises61 = require("fs/promises");
67534
- var import_node_path59 = require("path");
67840
+ var import_promises62 = require("fs/promises");
67841
+ var import_node_path60 = require("path");
67535
67842
  init_runtime_v2();
67536
67843
  init_zod();
67537
67844
  var runMetaSchema = external_exports.object({
@@ -67557,17 +67864,17 @@ async function readRunMeta(path4) {
67557
67864
  return read.kind === "ok" ? read.value : null;
67558
67865
  }
67559
67866
  function runDirectory(runsDir, runId) {
67560
- const dir = (0, import_node_path59.join)(runsDir, runId);
67867
+ const dir = (0, import_node_path60.join)(runsDir, runId);
67561
67868
  return {
67562
67869
  dir,
67563
- log: (0, import_node_path59.join)(dir, "log.jsonl"),
67564
- upload: (0, import_node_path59.join)(dir, "upload.json"),
67565
- meta: (0, import_node_path59.join)(dir, "run.json")
67870
+ log: (0, import_node_path60.join)(dir, "log.jsonl"),
67871
+ upload: (0, import_node_path60.join)(dir, "upload.json"),
67872
+ meta: (0, import_node_path60.join)(dir, "run.json")
67566
67873
  };
67567
67874
  }
67568
67875
  async function isRunClaimed(runsDir, runId) {
67569
67876
  try {
67570
- return (await (0, import_promises61.stat)(runDirectory(runsDir, runId).log)).size > 0;
67877
+ return (await (0, import_promises62.stat)(runDirectory(runsDir, runId).log)).size > 0;
67571
67878
  } catch (error61) {
67572
67879
  if (errnoCode(error61) === "ENOENT") return false;
67573
67880
  throw error61;
@@ -67576,7 +67883,7 @@ async function isRunClaimed(runsDir, runId) {
67576
67883
 
67577
67884
  // src/run-log/complete.ts
67578
67885
  function writeLogFile(path4, dir, text2) {
67579
- const temp = (0, import_node_path60.join)(dir, `.log.${(0, import_node_crypto28.randomUUID)()}.tmp`);
67886
+ const temp = (0, import_node_path61.join)(dir, `.log.${(0, import_node_crypto28.randomUUID)()}.tmp`);
67580
67887
  const fd = (0, import_node_fs19.openSync)(temp, "wx", 384);
67581
67888
  try {
67582
67889
  (0, import_node_fs19.writeSync)(fd, text2);
@@ -67605,25 +67912,31 @@ async function writeCompleteRunLog(runsDir, meta3, records) {
67605
67912
  }
67606
67913
 
67607
67914
  // src/run-log/conversation-index.ts
67608
- var import_promises62 = require("fs/promises");
67609
- var import_node_path61 = require("path");
67915
+ var import_promises63 = require("fs/promises");
67916
+ var import_node_path62 = require("path");
67610
67917
  init_runtime_v2();
67611
67918
  init_zod();
67612
67919
  var ORDINALS_PER_SHARD = 1e3;
67920
+ var REBUILD_READ_CONCURRENCY = 32;
67613
67921
  var indexRecordSchema = external_exports.object({
67614
67922
  ordinal: external_exports.number().int().nonnegative(),
67615
67923
  nextOrdinal: external_exports.number().int().positive(),
67616
67924
  runId: runIdSchema
67617
67925
  });
67618
67926
  var coverageSchema = external_exports.object({
67927
+ // Files written before ranges could start mid-conversation always started at turn 0.
67928
+ lowestOrdinal: external_exports.number().int().nonnegative().default(0),
67619
67929
  highestOrdinal: external_exports.number().int().nonnegative(),
67620
67930
  nextExpectedOrdinal: external_exports.number().int().positive()
67621
67931
  });
67932
+ function conversationsDirectory(runsDir) {
67933
+ return (0, import_node_path62.join)((0, import_node_path62.dirname)(runsDir), "conversations");
67934
+ }
67622
67935
  function indexDirectory(runsDir, conversationId) {
67623
- return (0, import_node_path61.join)((0, import_node_path61.dirname)(runsDir), "sessions", conversationId, "turn-index");
67936
+ return (0, import_node_path62.join)(conversationsDirectory(runsDir), conversationId, "turn-index");
67624
67937
  }
67625
67938
  function shardPath(runsDir, conversationId, ordinal) {
67626
- return (0, import_node_path61.join)(
67939
+ return (0, import_node_path62.join)(
67627
67940
  indexDirectory(runsDir, conversationId),
67628
67941
  `${Math.floor(ordinal / ORDINALS_PER_SHARD)}.jsonl`
67629
67942
  );
@@ -67632,26 +67945,31 @@ async function indexConversationRun(runsDir, conversationId, ordinal, assistantO
67632
67945
  const nextOrdinal = assistantOrdinal + 1;
67633
67946
  if (nextOrdinal <= ordinal) throw new Error("Assistant order must follow the prompt");
67634
67947
  const path4 = shardPath(runsDir, conversationId, ordinal);
67635
- await (0, import_promises62.mkdir)((0, import_node_path61.dirname)(path4), { recursive: true, mode: 448 });
67636
- await (0, import_promises62.appendFile)(path4, `${JSON.stringify({ ordinal, nextOrdinal, runId })}
67948
+ await (0, import_promises63.mkdir)((0, import_node_path62.dirname)(path4), { recursive: true, mode: 448 });
67949
+ await (0, import_promises63.appendFile)(path4, `${JSON.stringify({ ordinal, nextOrdinal, runId })}
67637
67950
  `, { mode: 384 });
67638
- const coveragePath = (0, import_node_path61.join)((0, import_node_path61.dirname)((0, import_node_path61.dirname)(path4)), "coverage.json");
67951
+ const coveragePath = (0, import_node_path62.join)((0, import_node_path62.dirname)((0, import_node_path62.dirname)(path4)), "coverage.json");
67639
67952
  const coverage = await readJsonFile(coveragePath, coverageSchema);
67640
67953
  const current = coverage.kind === "ok" ? coverage.value : null;
67641
- if (ordinal === 0 && current === null || current?.nextExpectedOrdinal === ordinal)
67642
- await writeJsonFileAtomic(coveragePath, {
67643
- highestOrdinal: ordinal,
67644
- nextExpectedOrdinal: nextOrdinal
67645
- });
67954
+ const next = nextCoverage(current, ordinal, nextOrdinal);
67955
+ if (next) await writeJsonFileAtomic(coveragePath, next);
67956
+ }
67957
+ function nextCoverage(current, ordinal, nextOrdinal) {
67958
+ if (current === null || ordinal > current.nextExpectedOrdinal)
67959
+ return { lowestOrdinal: ordinal, highestOrdinal: ordinal, nextExpectedOrdinal: nextOrdinal };
67960
+ if (ordinal === current.nextExpectedOrdinal)
67961
+ return { ...current, highestOrdinal: ordinal, nextExpectedOrdinal: nextOrdinal };
67962
+ if (ordinal === current.highestOrdinal) return { ...current, nextExpectedOrdinal: nextOrdinal };
67963
+ return null;
67646
67964
  }
67647
67965
  async function readConversationIndexCoverage(runsDir, conversationId) {
67648
- const path4 = (0, import_node_path61.join)((0, import_node_path61.dirname)(indexDirectory(runsDir, conversationId)), "coverage.json");
67966
+ const path4 = (0, import_node_path62.join)((0, import_node_path62.dirname)(indexDirectory(runsDir, conversationId)), "coverage.json");
67649
67967
  const result = await readJsonFile(path4, coverageSchema);
67650
67968
  return result.kind === "ok" ? result.value : null;
67651
67969
  }
67652
67970
  async function readConversationRunIndex(runsDir, conversationId, before, limit) {
67653
67971
  const directory = indexDirectory(runsDir, conversationId);
67654
- const names = await (0, import_promises62.readdir)(directory).catch((error61) => {
67972
+ const names = await (0, import_promises63.readdir)(directory).catch((error61) => {
67655
67973
  if (error61.code === "ENOENT") return [];
67656
67974
  throw error61;
67657
67975
  });
@@ -67660,7 +67978,7 @@ async function readConversationRunIndex(runsDir, conversationId, before, limit)
67660
67978
  ).sort((left, right) => right - left);
67661
67979
  const selected = [];
67662
67980
  for (const shard of shards) {
67663
- const text2 = await (0, import_promises62.readFile)((0, import_node_path61.join)(directory, `${shard}.jsonl`), "utf8");
67981
+ const text2 = await (0, import_promises63.readFile)((0, import_node_path62.join)(directory, `${shard}.jsonl`), "utf8");
67664
67982
  const records = text2.split("\n").flatMap((line) => {
67665
67983
  if (!line) return [];
67666
67984
  const parsed = indexRecordSchema.parse(JSON.parse(line));
@@ -67674,9 +67992,82 @@ async function readConversationRunIndex(runsDir, conversationId, before, limit)
67674
67992
  }
67675
67993
  return selected;
67676
67994
  }
67995
+ async function readIndexableRun(runsDir, name) {
67996
+ const runId = runIdSchema.safeParse(name);
67997
+ if (!runId.success) return null;
67998
+ const meta3 = await readRunMeta(runDirectory(runsDir, runId.data).meta);
67999
+ const ordinal = meta3?.userMessage?.turnOrdinal;
68000
+ const assistantOrdinal = meta3?.assistantMessage?.turnOrdinal;
68001
+ if (!meta3 || ordinal == null || assistantOrdinal == null || assistantOrdinal < ordinal)
68002
+ return null;
68003
+ return { conversationId: meta3.conversationId, ordinal, assistantOrdinal, runId: runId.data };
68004
+ }
68005
+ async function readIndexableRuns(runsDir) {
68006
+ const names = await (0, import_promises63.readdir)(runsDir).catch(() => []);
68007
+ const byConversation = /* @__PURE__ */ new Map();
68008
+ let next = 0;
68009
+ const worker = async () => {
68010
+ while (next < names.length) {
68011
+ const run2 = await readIndexableRun(runsDir, names[next++]);
68012
+ if (run2 === null) continue;
68013
+ const runs = byConversation.get(run2.conversationId);
68014
+ if (runs === void 0) byConversation.set(run2.conversationId, [run2]);
68015
+ else runs.push(run2);
68016
+ }
68017
+ };
68018
+ await Promise.all(Array.from({ length: REBUILD_READ_CONCURRENCY }, worker));
68019
+ return byConversation;
68020
+ }
68021
+ async function writeConversationIndex(directory, runs) {
68022
+ runs.sort(
68023
+ (left, right) => left.ordinal - right.ordinal || left.assistantOrdinal - right.assistantOrdinal
68024
+ );
68025
+ const shards = /* @__PURE__ */ new Map();
68026
+ let coverage = null;
68027
+ for (const run2 of runs) {
68028
+ const nextOrdinal = run2.assistantOrdinal + 1;
68029
+ const shard = Math.floor(run2.ordinal / ORDINALS_PER_SHARD);
68030
+ const line = JSON.stringify({ ordinal: run2.ordinal, nextOrdinal, runId: run2.runId });
68031
+ const lines2 = shards.get(shard);
68032
+ if (lines2 === void 0) shards.set(shard, [line]);
68033
+ else lines2.push(line);
68034
+ coverage = nextCoverage(coverage, run2.ordinal, nextOrdinal) ?? coverage;
68035
+ }
68036
+ await (0, import_promises63.mkdir)((0, import_node_path62.join)(directory, "turn-index"), { recursive: true, mode: 448 });
68037
+ for (const [shard, lines2] of shards) {
68038
+ await (0, import_promises63.writeFile)((0, import_node_path62.join)(directory, "turn-index", `${shard}.jsonl`), `${lines2.join("\n")}
68039
+ `, {
68040
+ mode: 384
68041
+ });
68042
+ }
68043
+ await (0, import_promises63.writeFile)((0, import_node_path62.join)(directory, "coverage.json"), `${JSON.stringify(coverage)}
68044
+ `, {
68045
+ mode: 384
68046
+ });
68047
+ }
68048
+ async function rebuildConversationIndexes(runsDir) {
68049
+ const root = conversationsDirectory(runsDir);
68050
+ const exists6 = await (0, import_promises63.stat)(root).then(
68051
+ () => true,
68052
+ (error61) => {
68053
+ if (errnoCode(error61) === "ENOENT") return false;
68054
+ throw error61;
68055
+ }
68056
+ );
68057
+ if (exists6) return 0;
68058
+ const building = `${root}.rebuilding`;
68059
+ await (0, import_promises63.rm)(building, { recursive: true, force: true });
68060
+ await (0, import_promises63.mkdir)(building, { recursive: true, mode: 448 });
68061
+ const byConversation = await readIndexableRuns(runsDir);
68062
+ for (const [conversationId, runs] of byConversation) {
68063
+ await writeConversationIndex((0, import_node_path62.join)(building, conversationId), runs);
68064
+ }
68065
+ await (0, import_promises63.rename)(building, root);
68066
+ return byConversation.size;
68067
+ }
67677
68068
 
67678
68069
  // src/run-log/reader.ts
67679
- var import_promises63 = require("fs/promises");
68070
+ var import_promises64 = require("fs/promises");
67680
68071
  init_runtime_v2();
67681
68072
 
67682
68073
  // src/run-log/tail.ts
@@ -67699,7 +68090,7 @@ function firstRecordLength(bytes) {
67699
68090
  return bytes.indexOf(RUN_LOG_RECORD_SEPARATOR) + 1;
67700
68091
  }
67701
68092
  async function openRunLogReader(path4) {
67702
- const handle = await (0, import_promises63.open)(path4, "r");
68093
+ const handle = await (0, import_promises64.open)(path4, "r");
67703
68094
  const readAt = async (position, length) => {
67704
68095
  const buffer = Buffer.alloc(length);
67705
68096
  const { bytesRead } = await handle.read(buffer, 0, length, position);
@@ -67733,7 +68124,7 @@ async function openRunLogReader(path4) {
67733
68124
  };
67734
68125
  }
67735
68126
  async function readLastRecord(path4) {
67736
- const handle = await (0, import_promises63.open)(path4, "r").catch(() => null);
68127
+ const handle = await (0, import_promises64.open)(path4, "r").catch(() => null);
67737
68128
  if (handle === null) return null;
67738
68129
  try {
67739
68130
  const { size } = await handle.stat();
@@ -67767,7 +68158,7 @@ var decoder = new TextDecoder();
67767
68158
 
67768
68159
  // src/run-log/writer.ts
67769
68160
  var import_node_fs20 = require("fs");
67770
- var import_node_path62 = require("path");
68161
+ var import_node_path63 = require("path");
67771
68162
  init_runtime_v2();
67772
68163
  function lastSeq(fd, size) {
67773
68164
  for (const length of tailWindows(size)) {
@@ -67783,7 +68174,7 @@ function lastSeq(fd, size) {
67783
68174
  throw new RuntimeFault("record_too_large", "Run log tail record is larger than any record");
67784
68175
  }
67785
68176
  function openRunLog(path4, clock) {
67786
- (0, import_node_fs20.mkdirSync)((0, import_node_path62.dirname)(path4), { recursive: true, mode: 448 });
68177
+ (0, import_node_fs20.mkdirSync)((0, import_node_path63.dirname)(path4), { recursive: true, mode: 448 });
67787
68178
  const fd = (0, import_node_fs20.openSync)(path4, "a+", 384);
67788
68179
  let size = (0, import_node_fs20.fstatSync)(fd).size;
67789
68180
  let seq = lastSeq(fd, size);
@@ -68119,7 +68510,7 @@ async function runHolder({
68119
68510
  try {
68120
68511
  const identity = await readProcessIdentity(process.pid);
68121
68512
  if (identity === null) throw new RuntimeFault("internal", "Cannot read own process identity");
68122
- const _engines = __using(_stack, recordSpawnedEngines(engineRecordsPath((0, import_node_path63.dirname)(launch.statusPath)), clock, log));
68513
+ const _engines = __using(_stack, recordSpawnedEngines(engineRecordsPath((0, import_node_path64.dirname)(launch.statusPath)), clock, log));
68123
68514
  const holder = {
68124
68515
  state: "idle",
68125
68516
  runId: null,
@@ -68413,7 +68804,7 @@ var DEFAULT_MAX_ACTIVE_RUNS = 32;
68413
68804
  var HOLDER_BUSY = "busy";
68414
68805
  async function listIds(dir, schema) {
68415
68806
  const ids = [];
68416
- for (const name of await (0, import_promises64.readdir)(dir).catch(() => [])) {
68807
+ for (const name of await (0, import_promises65.readdir)(dir).catch(() => [])) {
68417
68808
  const parsed = schema.safeParse(name);
68418
68809
  if (parsed.success) ids.push(parsed.data);
68419
68810
  }
@@ -68427,11 +68818,20 @@ function holderIdentity(status) {
68427
68818
  return command === void 0 ? { pid, startedAt } : { pid, startedAt, command };
68428
68819
  }
68429
68820
  function sessionFiles(paths, conversationId) {
68430
- const dir = (0, import_node_path64.join)(paths.sessions, conversationId);
68431
- return { dir, launch: (0, import_node_path64.join)(dir, "launch.json"), status: (0, import_node_path64.join)(dir, "holder.json") };
68821
+ const dir = (0, import_node_path65.join)(paths.sessions, conversationId);
68822
+ return { dir, launch: (0, import_node_path65.join)(dir, "launch.json"), status: (0, import_node_path65.join)(dir, "holder.json") };
68823
+ }
68824
+ async function removeHolderFiles(files) {
68825
+ for (const path4 of [files.launch, files.status, engineRecordsPath(files.dir)]) {
68826
+ await (0, import_promises65.rm)(path4, { force: true });
68827
+ }
68828
+ await (0, import_promises65.rmdir)(files.dir).catch((error61) => {
68829
+ if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(errnoCode(error61) ?? "")) throw error61;
68830
+ });
68432
68831
  }
68433
68832
  async function openSessions(deps) {
68434
68833
  const { paths, clock, log } = deps;
68834
+ const recentRunIds = async () => (await listIds(paths.runs, runIdSchema)).filter((runId) => !deps.archive?.has(runId));
68435
68835
  const connections = /* @__PURE__ */ new Map();
68436
68836
  const starting = /* @__PURE__ */ new Map();
68437
68837
  const launched = /* @__PURE__ */ new Map();
@@ -68465,11 +68865,11 @@ async function openSessions(deps) {
68465
68865
  return status.kind === "ok" && await mayBeSameProcess(holderIdentity(status.value));
68466
68866
  };
68467
68867
  const discardSession = async (conversationId) => {
68468
- const { dir } = sessionFiles(paths, conversationId);
68469
- await reapLeftoverEngines(engineRecordsPath(dir), { clock, log, conversationId }).catch(
68868
+ const files = sessionFiles(paths, conversationId);
68869
+ await reapLeftoverEngines(engineRecordsPath(files.dir), { clock, log, conversationId }).catch(
68470
68870
  (error61) => log.warn("sessions.engine_reap_failed", { conversationId, error: error61 })
68471
68871
  );
68472
- await (0, import_promises64.rm)(dir, { recursive: true, force: true });
68872
+ await removeHolderFiles(files);
68473
68873
  };
68474
68874
  const retireIfGone = async (conversationId) => {
68475
68875
  const files = sessionFiles(paths, conversationId);
@@ -68483,7 +68883,7 @@ async function openSessions(deps) {
68483
68883
  }
68484
68884
  await discardSession(conversationId);
68485
68885
  for (const [runId, owner] of launched) if (owner === conversationId) launched.delete(runId);
68486
- for (const runId of await listIds(paths.runs, runIdSchema)) {
68886
+ for (const runId of await recentRunIds()) {
68487
68887
  const meta3 = await readRunMeta(runDirectory(paths.runs, runId).meta);
68488
68888
  if (meta3?.conversationId === conversationId) await markInterrupted(runId);
68489
68889
  }
@@ -68502,7 +68902,7 @@ async function openSessions(deps) {
68502
68902
  };
68503
68903
  const runsOf = async (conversationId) => {
68504
68904
  const found = [];
68505
- for (const runId of await listIds(paths.runs, runIdSchema)) {
68905
+ for (const runId of await recentRunIds()) {
68506
68906
  const dir = runDirectory(paths.runs, runId);
68507
68907
  if ((await readRunMeta(dir.meta))?.conversationId !== conversationId) continue;
68508
68908
  const last = await readLastRecord(dir.log);
@@ -68557,7 +68957,7 @@ async function openSessions(deps) {
68557
68957
  log.info("sessions.reattached", { conversationId });
68558
68958
  return;
68559
68959
  }
68560
- if (alive) await (0, import_promises64.rm)(files.dir, { recursive: true, force: true });
68960
+ if (alive) await removeHolderFiles(files);
68561
68961
  else await discardSession(conversationId);
68562
68962
  };
68563
68963
  const busyRunIds = async () => {
@@ -68578,7 +68978,7 @@ async function openSessions(deps) {
68578
68978
  for (const conversationId of legacy.keys()) {
68579
68979
  for (const runId of await unendedRunsOf(conversationId)) busy.add(runId);
68580
68980
  }
68581
- for (const runId of await listIds(paths.runs, runIdSchema)) {
68981
+ for (const runId of await recentRunIds()) {
68582
68982
  if (!busy.has(runId)) await markInterrupted(runId);
68583
68983
  }
68584
68984
  };
@@ -68615,7 +69015,7 @@ async function openSessions(deps) {
68615
69015
  const meta3 = await readRunMeta(dir.meta);
68616
69016
  const last = await readLastRecord(dir.log);
68617
69017
  if (meta3 === null || last === null) return null;
68618
- const logged = await (0, import_promises64.stat)(dir.log).catch((error61) => {
69018
+ const logged = await (0, import_promises65.stat)(dir.log).catch((error61) => {
68619
69019
  if (errnoCode(error61) === "ENOENT") return null;
68620
69020
  throw error61;
68621
69021
  });
@@ -68642,7 +69042,7 @@ async function openSessions(deps) {
68642
69042
  ({ run: run2 }) => notLoggedRun(run2.runId, run2.conversationId)
68643
69043
  );
68644
69044
  const logged = /* @__PURE__ */ new Set();
68645
- const onDisk = new Set(await listIds(paths.runs, runIdSchema));
69045
+ const onDisk = new Set(await recentRunIds());
68646
69046
  for (const runId of endedRuns.keys()) if (!onDisk.has(runId)) endedRuns.delete(runId);
68647
69047
  for (const runId of onDisk) {
68648
69048
  const run2 = starting.has(runId) ? null : await loggedRun(runId);
@@ -68925,7 +69325,7 @@ function loadRuntimeConfig(env = process.env, totalMemoryBytes = (0, import_node
68925
69325
  providerProbes: ALAN_RUNTIME_PROVIDER_PROBES === "on",
68926
69326
  providerToolchain: ALAN_RUNTIME_PROVIDER_NODE !== void 0 && ALAN_RUNTIME_PROVIDER_NPM_CLI !== void 0 ? { node: ALAN_RUNTIME_PROVIDER_NODE, npmCli: ALAN_RUNTIME_PROVIDER_NPM_CLI } : null,
68927
69327
  home,
68928
- configHome: XDG_CONFIG_HOME ?? (0, import_node_path65.join)(home, ".config"),
69328
+ configHome: XDG_CONFIG_HOME ?? (0, import_node_path66.join)(home, ".config"),
68929
69329
  ...githubProxyConfig({ ALAN_RUNTIME_GITHUB_PROXY, XDG_CONFIG_HOME, GH_CONFIG_DIR }, home),
68930
69330
  gitGatewayUrl: ALAN_RUNTIME_GIT_GATEWAY_URL ?? null,
68931
69331
  workspaceRoot: ALAN_RUNTIME_WORKSPACE_ROOT ?? null,
@@ -68934,10 +69334,10 @@ function loadRuntimeConfig(env = process.env, totalMemoryBytes = (0, import_node
68934
69334
  };
68935
69335
  }
68936
69336
  function githubProxyConfig(env, home) {
68937
- const configHome = env.XDG_CONFIG_HOME ?? (0, import_node_path65.join)(home, ".config");
69337
+ const configHome = env.XDG_CONFIG_HOME ?? (0, import_node_path66.join)(home, ".config");
68938
69338
  return {
68939
69339
  githubProxy: env.ALAN_RUNTIME_GITHUB_PROXY === "on",
68940
- ghConfigDir: env.GH_CONFIG_DIR ?? (0, import_node_path65.join)(configHome, "gh")
69340
+ ghConfigDir: env.GH_CONFIG_DIR ?? (0, import_node_path66.join)(configHome, "gh")
68941
69341
  };
68942
69342
  }
68943
69343
  function serviceEnvironment2(env, profile) {
@@ -68995,9 +69395,9 @@ function takeEnrollmentCodeFromEnv(env = process.env) {
68995
69395
  }
68996
69396
 
68997
69397
  // src/cli/context.ts
68998
- var import_promises65 = require("fs/promises");
69398
+ var import_promises66 = require("fs/promises");
68999
69399
  var import_node_os12 = require("os");
69000
- var import_node_path66 = require("path");
69400
+ var import_node_path67 = require("path");
69001
69401
  var DESKTOP_BUNDLE_IDS = {
69002
69402
  production: ["com.alan-ai.desktop"],
69003
69403
  staging: ["com.alan-ai.desktop.staging"],
@@ -69037,7 +69437,7 @@ function serviceSpec({ config: config2, paths, self }) {
69037
69437
  profile: config2.profile,
69038
69438
  program: serviceCommand(config2.host, self, launcher),
69039
69439
  environment: config2.serviceEnvironment,
69040
- logPath: (0, import_node_path66.join)(paths.logs, "service.log"),
69440
+ logPath: (0, import_node_path67.join)(paths.logs, "service.log"),
69041
69441
  associatedBundleIds: DESKTOP_BUNDLE_IDS[config2.profile]
69042
69442
  };
69043
69443
  }
@@ -69045,7 +69445,7 @@ async function installedServiceSpec(ctx) {
69045
69445
  const spec = serviceSpec(ctx);
69046
69446
  if (ctx.config.host === "app") return spec;
69047
69447
  const layout = installLayout(ctx.config.installDir, ctx.config.profile);
69048
- const installed = await (0, import_promises65.access)(layout.launcher).then(
69448
+ const installed = await (0, import_promises66.access)(layout.launcher).then(
69049
69449
  () => true,
69050
69450
  () => false
69051
69451
  );
@@ -69173,7 +69573,7 @@ var manifestRevisionSchema = external_exports.object({ revision: external_export
69173
69573
  async function manifestRevision(path4) {
69174
69574
  let raw;
69175
69575
  try {
69176
- raw = JSON.parse(await (0, import_promises66.readFile)(path4, "utf8"));
69576
+ raw = JSON.parse(await (0, import_promises67.readFile)(path4, "utf8"));
69177
69577
  } catch (error61) {
69178
69578
  throw new RuntimeFault("invalid_file", `Cannot read the skill manifest at ${path4}`, {
69179
69579
  cause: error61
@@ -69227,8 +69627,8 @@ async function runSkills(argv) {
69227
69627
  }
69228
69628
 
69229
69629
  // src/cli/commands/doctor.ts
69230
- var import_promises69 = require("fs/promises");
69231
- var import_node_path70 = require("path");
69630
+ var import_promises70 = require("fs/promises");
69631
+ var import_node_path71 = require("path");
69232
69632
  init_runtime_v2();
69233
69633
 
69234
69634
  // src/identity/credential.ts
@@ -69405,18 +69805,18 @@ async function authorizeDevice(input2) {
69405
69805
  }
69406
69806
 
69407
69807
  // src/identity/enroll.ts
69408
- var import_promises67 = require("fs/promises");
69808
+ var import_promises68 = require("fs/promises");
69409
69809
  init_runtime_v2();
69410
69810
 
69411
69811
  // src/identity/installation.ts
69412
69812
  var import_node_crypto32 = require("crypto");
69413
- var import_node_path67 = require("path");
69813
+ var import_node_path68 = require("path");
69414
69814
  init_zod();
69415
69815
  var installationFileSchema = external_exports.object({
69416
69816
  installationId: external_exports.uuid()
69417
69817
  });
69418
69818
  function installationPath(paths) {
69419
- return (0, import_node_path67.join)(paths.stateDir, "installation.json");
69819
+ return (0, import_node_path68.join)(paths.stateDir, "installation.json");
69420
69820
  }
69421
69821
  async function ensureInstallationId(paths) {
69422
69822
  const path4 = installationPath(paths);
@@ -69509,13 +69909,13 @@ async function enrollFromGrantFile(input2) {
69509
69909
  clock: input2.clock,
69510
69910
  access: input2.access
69511
69911
  });
69512
- await (0, import_promises67.rm)(input2.grantPath, { force: true });
69912
+ await (0, import_promises68.rm)(input2.grantPath, { force: true });
69513
69913
  return machine;
69514
69914
  }
69515
69915
 
69516
69916
  // src/identity/migrate-v1.ts
69517
- var import_promises68 = require("fs/promises");
69518
- var import_node_path68 = require("path");
69917
+ var import_promises69 = require("fs/promises");
69918
+ var import_node_path69 = require("path");
69519
69919
  init_runtime_v2();
69520
69920
  init_zod();
69521
69921
  var EXIT_POLL_MS = 200;
@@ -69536,11 +69936,11 @@ var ownerLeaseSchema = external_exports.looseObject({ pid: external_exports.numb
69536
69936
  function legacyConfigPath(home, profile) {
69537
69937
  switch (profile) {
69538
69938
  case "production":
69539
- return (0, import_node_path68.join)(home, ".alan", "agent", "config.json");
69939
+ return (0, import_node_path69.join)(home, ".alan", "agent", "config.json");
69540
69940
  case "staging":
69541
- return (0, import_node_path68.join)(home, ".alan-staging", "agent", "config.json");
69941
+ return (0, import_node_path69.join)(home, ".alan-staging", "agent", "config.json");
69542
69942
  default:
69543
- return (0, import_node_path68.join)(home, ".alan-dev", "agent", "config.json");
69943
+ return (0, import_node_path69.join)(home, ".alan-dev", "agent", "config.json");
69544
69944
  }
69545
69945
  }
69546
69946
  async function findLegacyInstall(home, profile) {
@@ -69565,8 +69965,8 @@ async function scrubLegacyInstall(install2) {
69565
69965
  const scrubbed = { ...install2.config, migratedToRuntimeV2: true };
69566
69966
  for (const key of SCRUBBED_KEYS) delete scrubbed[key];
69567
69967
  await writeJsonFileAtomic(`${install2.configPath}.migrated-v1`, scrubbed);
69568
- await (0, import_promises68.rm)(install2.configPath, { force: true });
69569
- await (0, import_promises68.rm)(install2.ownerLeasePath, { force: true });
69968
+ await (0, import_promises69.rm)(install2.configPath, { force: true });
69969
+ await (0, import_promises69.rm)(install2.ownerLeasePath, { force: true });
69570
69970
  }
69571
69971
  async function exchangeCredential(deps) {
69572
69972
  const { config: config2 } = deps.install;
@@ -69675,7 +70075,7 @@ async function loadIdentity(paths, options = {}) {
69675
70075
  }
69676
70076
 
69677
70077
  // src/cli/commands/status.ts
69678
- var import_node_path69 = require("path");
70078
+ var import_node_path70 = require("path");
69679
70079
  async function serviceStatus(ctx) {
69680
70080
  try {
69681
70081
  return await createServiceManager(ctx.host, ctx.config.profile).status();
@@ -69702,7 +70102,7 @@ async function runtimeState(ctx) {
69702
70102
  const running = await readRunningRuntime(ctx.paths.lock);
69703
70103
  if (running === null) return { state: "offline", pid: null, localApi: null };
69704
70104
  const discovery = await readJsonFile(
69705
- (0, import_node_path69.join)(ctx.paths.stateDir, LOCAL_API_DISCOVERY_FILE),
70105
+ (0, import_node_path70.join)(ctx.paths.stateDir, LOCAL_API_DISCOVERY_FILE),
69706
70106
  localApiDiscoverySchema
69707
70107
  );
69708
70108
  const localApi = discovery.kind === "ok" && discovery.value.pid === running.pid ? {
@@ -69923,7 +70323,7 @@ async function runtimeCheck(ctx, status) {
69923
70323
  return check2("runtime", "warn", "No runtime is running for this profile");
69924
70324
  }
69925
70325
  const client = createRuntimeClient({
69926
- discoveryPath: (0, import_node_path70.join)(ctx.paths.stateDir, LOCAL_API_DISCOVERY_FILE)
70326
+ discoveryPath: (0, import_node_path71.join)(ctx.paths.stateDir, LOCAL_API_DISCOVERY_FILE)
69927
70327
  });
69928
70328
  try {
69929
70329
  const live = await client.status(AbortSignal.timeout(LOCAL_TIMEOUT_MS));
@@ -69950,7 +70350,7 @@ async function runtimeCheck(ctx, status) {
69950
70350
  }
69951
70351
  }
69952
70352
  async function probeHolder(dir, conversationId) {
69953
- const launch = await readJsonFile((0, import_node_path70.join)(dir, "launch.json"), holderLaunchSchema);
70353
+ const launch = await readJsonFile((0, import_node_path71.join)(dir, "launch.json"), holderLaunchSchema);
69954
70354
  if (launch.kind !== "ok") return null;
69955
70355
  try {
69956
70356
  const reply2 = await withTimeout(
@@ -69975,8 +70375,8 @@ async function probeHolder(dir, conversationId) {
69975
70375
  }
69976
70376
  }
69977
70377
  async function holdersCheck(ctx) {
69978
- const names = await (0, import_promises69.readdir)(ctx.paths.sessions).catch(() => []);
69979
- const holders = (await Promise.all(names.map((name) => probeHolder((0, import_node_path70.join)(ctx.paths.sessions, name), name)))).filter((facts) => facts !== null);
70378
+ const names = await (0, import_promises70.readdir)(ctx.paths.sessions).catch(() => []);
70379
+ const holders = (await Promise.all(names.map((name) => probeHolder((0, import_node_path71.join)(ctx.paths.sessions, name), name)))).filter((facts) => facts !== null);
69980
70380
  const dead = holders.filter((holder) => !holder.alive).length;
69981
70381
  return check2(
69982
70382
  "holders",
@@ -69987,10 +70387,10 @@ async function holdersCheck(ctx) {
69987
70387
  }
69988
70388
  async function freeBytesAt(path4) {
69989
70389
  try {
69990
- const stats = await (0, import_promises69.statfs)(path4);
70390
+ const stats = await (0, import_promises70.statfs)(path4);
69991
70391
  return { path: path4, freeBytes: stats.bavail * stats.bsize };
69992
70392
  } catch (error61) {
69993
- const parent = (0, import_node_path70.dirname)(path4);
70393
+ const parent = (0, import_node_path71.dirname)(path4);
69994
70394
  if (parent === path4) throw error61;
69995
70395
  return freeBytesAt(parent);
69996
70396
  }
@@ -70126,7 +70526,7 @@ async function runDoctor(argv, context = cliContext) {
70126
70526
  }
70127
70527
 
70128
70528
  // src/cli/commands/git-credential.ts
70129
- var import_promises70 = require("fs/promises");
70529
+ var import_promises71 = require("fs/promises");
70130
70530
  var import_node_net4 = require("net");
70131
70531
  var MAX_RESPONSE_BYTES = 64 * 1024;
70132
70532
  async function readAll(stream) {
@@ -70236,7 +70636,7 @@ async function configure(argv) {
70236
70636
  }
70237
70637
  async function configureGitGateway(config2, gatewayUrl, signal) {
70238
70638
  const { launcher } = installLayout(config2.installDir, config2.profile);
70239
- const installed = await (0, import_promises70.access)(launcher).then(
70639
+ const installed = await (0, import_promises71.access)(launcher).then(
70240
70640
  () => true,
70241
70641
  () => false
70242
70642
  );
@@ -70263,7 +70663,7 @@ async function runGitCredential(argv) {
70263
70663
  }
70264
70664
 
70265
70665
  // src/cli/commands/hold.ts
70266
- var import_node_path71 = require("path");
70666
+ var import_node_path72 = require("path");
70267
70667
  init_agent2();
70268
70668
  init_runtime_v2();
70269
70669
  async function machineAccess(paths, log, conversationId, transport) {
@@ -70321,7 +70721,7 @@ async function runHold(argv) {
70321
70721
  const config2 = loadRuntimeConfig();
70322
70722
  const paths = runtimePaths(config2.stateDir);
70323
70723
  const log = __using(_stack, openFileLog(
70324
- (0, import_node_path71.join)(paths.logs, `holder-${launch.value.conversationId}.jsonl`),
70724
+ (0, import_node_path72.join)(paths.logs, `holder-${launch.value.conversationId}.jsonl`),
70325
70725
  config2.logLevel,
70326
70726
  systemClock
70327
70727
  ));
@@ -70332,7 +70732,7 @@ async function runHold(argv) {
70332
70732
  );
70333
70733
  const transport = __using(_stack, createHttpTransport());
70334
70734
  const access7 = await machineAccess(paths, log, launch.value.conversationId, transport);
70335
- const credentialPath = (0, import_node_path71.join)(paths.tmp, "mcp", `${launch.value.conversationId}.json`);
70735
+ const credentialPath = (0, import_node_path72.join)(paths.tmp, "mcp", `${launch.value.conversationId}.json`);
70336
70736
  const managedMcp = __using(_stack, access7.managedMcp === void 0 ? void 0 : createHelperMcpAccess({
70337
70737
  managedMcp: access7.managedMcp,
70338
70738
  conversationId: launch.value.conversationId,
@@ -70372,7 +70772,7 @@ async function runHold(argv) {
70372
70772
  }
70373
70773
 
70374
70774
  // src/cli/commands/hook.ts
70375
- var import_node_path72 = require("path");
70775
+ var import_node_path73 = require("path");
70376
70776
  var RUNTIME_ANSWER_MS = 2e3;
70377
70777
  var DEBUG_VARIABLE = "ALAN_HOOK_DEBUG";
70378
70778
  function flag(argv, name) {
@@ -70404,7 +70804,7 @@ async function forwardHook(argv, io) {
70404
70804
  return "transcript outside provider root";
70405
70805
  }
70406
70806
  const verdict = await io.send(
70407
- (0, import_node_path72.join)(io.stateDir, LOCAL_API_DISCOVERY_FILE),
70807
+ (0, import_node_path73.join)(io.stateDir, LOCAL_API_DISCOVERY_FILE),
70408
70808
  hookSignal,
70409
70809
  AbortSignal.timeout(RUNTIME_ANSWER_MS)
70410
70810
  );
@@ -70440,7 +70840,7 @@ async function runHook(argv, overrides = {}) {
70440
70840
  }
70441
70841
 
70442
70842
  // src/cli/commands/ingestion-hooks.ts
70443
- var import_promises71 = require("fs/promises");
70843
+ var import_promises72 = require("fs/promises");
70444
70844
  var CODEX_TRUST_NOTE = "Codex runs new hooks only after you review them: open /hooks in Codex.";
70445
70845
  function isAction(value2) {
70446
70846
  return value2 === "enable" || value2 === "disable" || value2 === "status";
@@ -70463,7 +70863,7 @@ function errorMessage2(error61) {
70463
70863
  return error61 instanceof Error ? error61.message : String(error61);
70464
70864
  }
70465
70865
  async function exists5(path4) {
70466
- return (0, import_promises71.access)(path4).then(
70866
+ return (0, import_promises72.access)(path4).then(
70467
70867
  () => true,
70468
70868
  () => false
70469
70869
  );
@@ -70566,10 +70966,10 @@ async function runIntegrationsCommand(argv) {
70566
70966
  }
70567
70967
 
70568
70968
  // src/cli/commands/legacy.ts
70569
- var import_node_path74 = require("path");
70969
+ var import_node_path75 = require("path");
70570
70970
 
70571
70971
  // src/cli/commands/setup.ts
70572
- var import_node_path73 = require("path");
70972
+ var import_node_path74 = require("path");
70573
70973
  init_zod();
70574
70974
 
70575
70975
  // src/cli/legacy.ts
@@ -70651,7 +71051,7 @@ async function grantFileCredential(argv, grantPath, ctx, deps) {
70651
71051
  return enrollFromGrantFile({
70652
71052
  paths: ctx.paths,
70653
71053
  storeKind: credentialStoreFlag(argv) ?? ctx.config.credentialStore,
70654
- grantPath: (0, import_node_path73.resolve)(grantPath),
71054
+ grantPath: (0, import_node_path74.resolve)(grantPath),
70655
71055
  clock: deps.clock,
70656
71056
  access: ctx.access
70657
71057
  });
@@ -70727,7 +71127,7 @@ async function runSetup(argv, signal) {
70727
71127
  var _stack = [];
70728
71128
  try {
70729
71129
  const ctx = cliContext();
70730
- const log = __using(_stack, openFileLog((0, import_node_path73.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
71130
+ const log = __using(_stack, openFileLog((0, import_node_path74.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
70731
71131
  const result = await setupMachine(argv, ctx, {
70732
71132
  enrollment: (apiUrl) => createEnrollmentClient({ apiUrl }),
70733
71133
  isProcessAlive,
@@ -70810,7 +71210,7 @@ async function runToken(argv, signal) {
70810
71210
  );
70811
71211
  }
70812
71212
  const ctx = cliContext();
70813
- const log = __using(_stack, openFileLog((0, import_node_path74.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
71213
+ const log = __using(_stack, openFileLog((0, import_node_path75.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
70814
71214
  const result = await rotateMachineCredential(ctx, { clock: systemClock, log, signal });
70815
71215
  process.stdout.write(`${rotationMessage(result)}
70816
71216
  `);
@@ -70822,8 +71222,8 @@ async function runToken(argv, signal) {
70822
71222
  }
70823
71223
 
70824
71224
  // src/cli/commands/logout.ts
70825
- var import_promises72 = require("fs/promises");
70826
- var import_node_path75 = require("path");
71225
+ var import_promises73 = require("fs/promises");
71226
+ var import_node_path76 = require("path");
70827
71227
  init_runtime_v2();
70828
71228
  var RUNTIME_EXIT_WAIT_MS = 35e3;
70829
71229
  var TURN_END_WAIT_MS = 3e4;
@@ -70882,9 +71282,9 @@ async function stopHolder(launch, deps, outcome2) {
70882
71282
  }
70883
71283
  async function stopHeldRuns(ctx, deps, outcome2 = "aborted") {
70884
71284
  const stopped = [];
70885
- for (const name of await (0, import_promises72.readdir)(ctx.paths.sessions).catch(() => [])) {
71285
+ for (const name of await (0, import_promises73.readdir)(ctx.paths.sessions).catch(() => [])) {
70886
71286
  const launch = await readJsonFile(
70887
- (0, import_node_path75.join)(ctx.paths.sessions, name, "launch.json"),
71287
+ (0, import_node_path76.join)(ctx.paths.sessions, name, "launch.json"),
70888
71288
  holderLaunchSchema
70889
71289
  );
70890
71290
  if (launch.kind !== "ok") continue;
@@ -70921,13 +71321,13 @@ async function forgetMachineLocally(ctx) {
70921
71321
  const machine = await readMachineFile(ctx.paths);
70922
71322
  if (machine === null) return;
70923
71323
  await credentialStoreFor(ctx.paths, machine.credentialStore, ctx.access).clear();
70924
- await (0, import_promises72.rm)(ctx.paths.machine, { force: true });
71324
+ await (0, import_promises73.rm)(ctx.paths.machine, { force: true });
70925
71325
  }
70926
71326
  async function runLogout(argv, signal) {
70927
71327
  var _stack = [];
70928
71328
  try {
70929
71329
  const ctx = cliContext();
70930
- const log = __using(_stack, openFileLog((0, import_node_path75.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
71330
+ const log = __using(_stack, openFileLog((0, import_node_path76.join)(ctx.paths.logs, "cli.jsonl"), ctx.config.logLevel, systemClock));
70931
71331
  const result = await logoutMachine(argv, ctx, {
70932
71332
  api: (apiUrl, accessToken) => createApiClient({ apiUrl, accessToken }),
70933
71333
  stopHeldRuns,
@@ -70945,7 +71345,7 @@ async function runLogout(argv, signal) {
70945
71345
 
70946
71346
  // src/cli/commands/run.ts
70947
71347
  var import_node_fs23 = require("fs");
70948
- var import_node_path79 = require("path");
71348
+ var import_node_path80 = require("path");
70949
71349
 
70950
71350
  // src/local-api/app-attachments.ts
70951
71351
  function createAppAttachments(clock) {
@@ -71022,9 +71422,9 @@ function createRunAppends() {
71022
71422
 
71023
71423
  // src/local-api/server.ts
71024
71424
  var import_node_crypto34 = require("crypto");
71025
- var import_promises73 = require("fs/promises");
71425
+ var import_promises74 = require("fs/promises");
71026
71426
  var import_node_http4 = require("http");
71027
- var import_node_path76 = require("path");
71427
+ var import_node_path77 = require("path");
71028
71428
 
71029
71429
  // src/local-api/guard.ts
71030
71430
  var import_node_crypto33 = require("crypto");
@@ -71211,22 +71611,34 @@ async function openLocalTurnProjection(runsDir, runId, conversationId, ordinal)
71211
71611
  if (!reader) return null;
71212
71612
  let offset = toByteOffset(0);
71213
71613
  let ended = false;
71614
+ let snapshot2;
71214
71615
  let prepared;
71616
+ const merge2 = /* @__PURE__ */ new Map();
71215
71617
  const decoder3 = new TextDecoder();
71618
+ const readState = async () => {
71619
+ const priorOffset = offset;
71620
+ for (; ; ) {
71621
+ const chunk = await reader.readFrom(offset, DEFAULT_RUN_LOG_LIMIT);
71622
+ if (chunk.bytes.length === 0) break;
71623
+ if (applyLogChunk(decoder3.decode(chunk.bytes), assistantMessageId, state)) ended = true;
71624
+ offset = chunk.to;
71625
+ }
71626
+ if (offset === priorOffset && snapshot2) return snapshot2;
71627
+ if (ended) state.state = "idle";
71628
+ snapshot2 = mergeTranscriptMessages(
71629
+ [{ messageId: assistantMessageId, turnOrdinal: ordinal, role: "assistant", state }],
71630
+ merge2
71631
+ );
71632
+ return snapshot2;
71633
+ };
71216
71634
  return {
71217
71635
  runId,
71218
71636
  ordinal,
71637
+ readState,
71219
71638
  read: async () => {
71220
- const priorOffset = offset;
71221
- for (; ; ) {
71222
- const chunk = await reader.readFrom(offset, DEFAULT_RUN_LOG_LIMIT);
71223
- if (chunk.bytes.length === 0) break;
71224
- if (applyLogChunk(decoder3.decode(chunk.bytes), assistantMessageId, state)) ended = true;
71225
- offset = chunk.to;
71226
- }
71227
- if (offset === priorOffset && prepared) return prepared;
71228
- if (ended) state.state = "idle";
71229
- prepared = { ...conversationTurnView(ordinal, snapshotTranscriptState(state)), markdown: "" };
71639
+ const current = await readState();
71640
+ if (prepared?.state !== current)
71641
+ prepared = { ...conversationTurnView(ordinal, current, prepared?.display), markdown: "" };
71230
71642
  return prepared;
71231
71643
  },
71232
71644
  [Symbol.asyncDispose]: async () => {
@@ -71247,14 +71659,14 @@ async function projectLocalRun(runsDir, runId, conversationId, ordinal) {
71247
71659
  }
71248
71660
  }
71249
71661
  async function readLocalConversationMessages(runsDir, conversationId, limit, before, projection) {
71250
- const indexed = await readConversationRunIndex(runsDir, conversationId, before, limit + 1);
71251
71662
  const coverage = await readConversationIndexCoverage(runsDir, conversationId);
71252
- if (coverage === null || before === void 0 && indexed[0]?.ordinal !== coverage.highestOrdinal)
71253
- return null;
71663
+ if (coverage === null || before !== void 0 && before <= coverage.lowestOrdinal) return null;
71664
+ const indexed = (await readConversationRunIndex(runsDir, conversationId, before, limit + 1)).filter((entry) => entry.ordinal >= coverage.lowestOrdinal);
71665
+ if (before === void 0 && indexed[0]?.ordinal !== coverage.highestOrdinal) return null;
71254
71666
  if (before !== void 0 && indexed[0]?.nextOrdinal !== before) return null;
71255
71667
  if (indexed.some((entry, index) => index > 0 && entry.nextOrdinal !== indexed[index - 1].ordinal))
71256
71668
  return null;
71257
- if (indexed.length < limit && indexed.at(-1)?.ordinal !== 0) return null;
71669
+ if (indexed.length < limit && indexed.at(-1)?.ordinal !== coverage.lowestOrdinal) return null;
71258
71670
  const selected = indexed.slice(0, limit);
71259
71671
  if (selected.length === 0) return null;
71260
71672
  const turns = await Promise.all(
@@ -71262,17 +71674,22 @@ async function readLocalConversationMessages(runsDir, conversationId, limit, bef
71262
71674
  (entry) => entry.runId === projection?.runId ? projection.read() : projectLocalRun(runsDir, entry.runId, conversationId, entry.ordinal)
71263
71675
  )
71264
71676
  );
71265
- if (turns.some((turn) => turn === null)) return null;
71266
- const completeTurns = turns.filter((turn) => turn !== null);
71677
+ const missing = turns.indexOf(null);
71678
+ const completeTurns = (missing === -1 ? turns : turns.slice(0, missing)).filter(
71679
+ (turn) => turn !== null
71680
+ );
71681
+ if (completeTurns.length === 0) return null;
71682
+ const oldestOrdinal = selected[completeTurns.length - 1].ordinal;
71267
71683
  return {
71268
71684
  turns: compactConversationMessageTurns(completeTurns, before === void 0),
71269
- before: selected.at(-1)?.ordinal === 0 ? null : String(selected.at(-1)?.ordinal),
71685
+ before: oldestOrdinal === 0 ? null : String(oldestOrdinal),
71270
71686
  revision: `local-${selected[0].runId}`,
71271
71687
  streamCursor: ""
71272
71688
  };
71273
71689
  }
71274
71690
 
71275
71691
  // src/local-api/conversation-messages-stream.ts
71692
+ init_acp();
71276
71693
  async function readChangedTurn(deps, conversationId, runId, slot) {
71277
71694
  const meta3 = await readRunMeta(runDirectory(deps.runsDir, runId).meta);
71278
71695
  if (meta3?.conversationId !== conversationId || meta3.userMessage?.turnOrdinal == null) return null;
@@ -71286,21 +71703,17 @@ async function readChangedTurn(deps, conversationId, runId, slot) {
71286
71703
  if (latest?.runId !== runId) return null;
71287
71704
  }
71288
71705
  if (slot.current && meta3.userMessage.turnOrdinal < slot.current.ordinal) {
71289
- var _stack = [];
71290
- try {
71291
- const previous = __using(_stack, await openLocalTurnProjection(
71292
- deps.runsDir,
71293
- runId,
71294
- conversationId,
71295
- meta3.userMessage.turnOrdinal
71296
- ), true);
71297
- return previous ? await previous.read() : null;
71298
- } catch (_) {
71299
- var _error = _, _hasError = true;
71300
- } finally {
71301
- var _promise2 = __callDispose(_stack, _error, _hasError);
71302
- _promise2 && await _promise2;
71303
- }
71706
+ const previous = await openLocalTurnProjection(
71707
+ deps.runsDir,
71708
+ runId,
71709
+ conversationId,
71710
+ meta3.userMessage.turnOrdinal
71711
+ );
71712
+ if (!previous) return null;
71713
+ return {
71714
+ projection: previous,
71715
+ changed: { ordinal: previous.ordinal, state: await previous.readState() }
71716
+ };
71304
71717
  }
71305
71718
  if (slot.current?.runId !== runId) {
71306
71719
  const next = await openLocalTurnProjection(
@@ -71313,20 +71726,48 @@ async function readChangedTurn(deps, conversationId, runId, slot) {
71313
71726
  slot.current = next;
71314
71727
  }
71315
71728
  if (!slot.current) throw new Error("Local transcript metadata is incomplete");
71316
- return slot.current.read();
71729
+ return {
71730
+ projection: slot.current,
71731
+ changed: { ordinal: slot.current.ordinal, state: await slot.current.readState() }
71732
+ };
71733
+ }
71734
+ async function nextChangedRuns(bell, signal) {
71735
+ if (bell.pending.size === 0) {
71736
+ await new Promise((resolve12) => {
71737
+ bell.wake = resolve12;
71738
+ if (signal.aborted || bell.pending.size > 0) resolve12();
71739
+ });
71740
+ bell.wake = void 0;
71741
+ }
71742
+ if (signal.aborted) return [];
71743
+ await systemClock.sleep(50, signal);
71744
+ const changed = [...bell.pending];
71745
+ bell.pending.clear();
71746
+ return changed;
71747
+ }
71748
+ async function writeChangedTurn(writer, runId, read) {
71749
+ const { ordinal, state } = read.changed;
71750
+ if (state === writer.lastState) return;
71751
+ writer.lastState = state;
71752
+ const patch = writer.frames === "patch";
71753
+ const data = patch ? JSON.stringify(writer.encode(ordinal, state)) : JSON.stringify(await read.projection.read());
71754
+ await writeEvent(writer.res, {
71755
+ name: patch ? LIVE_TURN_EVENT : "turn",
71756
+ id: `${runId}`,
71757
+ dataLines: [data]
71758
+ });
71317
71759
  }
71318
- async function streamLocalConversationMessages(deps, conversationId, limit, res, signal) {
71760
+ async function streamLocalConversationMessages(deps, conversationId, limit, frames, res, signal) {
71319
71761
  var _stack = [];
71320
71762
  try {
71321
- const pending = /* @__PURE__ */ new Set();
71322
- let wake;
71763
+ const bell = { pending: /* @__PURE__ */ new Set(), wake: void 0 };
71323
71764
  const slot = { current: null };
71324
71765
  const _subscription = __using(_stack, deps.appends.subscribe((runId) => {
71325
71766
  const changed = runId ?? slot.current?.runId;
71326
- if (changed) pending.add(changed);
71327
- wake?.();
71767
+ if (changed) bell.pending.add(changed);
71768
+ bell.wake?.();
71328
71769
  }));
71329
- signal.addEventListener("abort", () => wake?.(), { once: true });
71770
+ signal.addEventListener("abort", () => bell.wake?.(), { once: true });
71330
71771
  try {
71331
71772
  const [newest] = await readConversationRunIndex(deps.runsDir, conversationId, void 0, 1);
71332
71773
  if (newest)
@@ -71336,7 +71777,12 @@ async function streamLocalConversationMessages(deps, conversationId, limit, res,
71336
71777
  conversationId,
71337
71778
  newest.ordinal
71338
71779
  );
71339
- let lastTurn = await slot.current?.read();
71780
+ const writer = {
71781
+ frames,
71782
+ encode: createLiveTurnFrameEncoder(),
71783
+ res,
71784
+ lastState: await slot.current?.readState()
71785
+ };
71340
71786
  const page = await readLocalConversationMessages(
71341
71787
  deps.runsDir,
71342
71788
  conversationId,
@@ -71355,22 +71801,14 @@ async function streamLocalConversationMessages(deps, conversationId, limit, res,
71355
71801
  dataLines: [JSON.stringify(page)]
71356
71802
  });
71357
71803
  while (!signal.aborted) {
71358
- if (pending.size === 0) {
71359
- await new Promise((resolve12) => {
71360
- wake = resolve12;
71361
- if (signal.aborted || pending.size > 0) resolve12();
71362
- });
71363
- wake = void 0;
71364
- }
71365
- if (signal.aborted) return;
71366
- await systemClock.sleep(50, signal);
71367
- const changed = [...pending];
71368
- pending.clear();
71369
- for (const runId of changed) {
71370
- const turn = await readChangedTurn(deps, conversationId, runId, slot);
71371
- if (!turn || turn === lastTurn) continue;
71372
- lastTurn = turn;
71373
- await writeEvent(res, { name: "turn", id: `${runId}`, dataLines: [JSON.stringify(turn)] });
71804
+ for (const runId of await nextChangedRuns(bell, signal)) {
71805
+ const read = await readChangedTurn(deps, conversationId, runId, slot);
71806
+ if (!read) continue;
71807
+ try {
71808
+ await writeChangedTurn(writer, runId, read);
71809
+ } finally {
71810
+ if (read.projection !== slot.current) await read.projection[Symbol.asyncDispose]();
71811
+ }
71374
71812
  }
71375
71813
  }
71376
71814
  } finally {
@@ -71584,7 +72022,9 @@ var RUN_PATH = /^\/v2\/runs\/([^/]+)\/(log|log\/stream|abort)$/;
71584
72022
  var CONVERSATION_MESSAGES_PATH = /^\/v2\/conversations\/([^/]+)\/messages(\/sse)?$/;
71585
72023
  var conversationMessagesQuerySchema = external_exports.object({
71586
72024
  limit: external_exports.coerce.number().int().min(1).max(100).default(10),
71587
- before: external_exports.coerce.number().int().nonnegative().optional()
72025
+ before: external_exports.coerce.number().int().nonnegative().optional(),
72026
+ runtimeId: external_exports.string().uuid().optional(),
72027
+ frames: external_exports.enum(["turn", "patch"]).default("turn")
71588
72028
  });
71589
72029
  var emptyBodySchema = external_exports.object({});
71590
72030
  function activeRunIds(runs) {
@@ -71805,6 +72245,44 @@ var FIXED_ROUTES = new Map([
71805
72245
  [LOCAL_API_ROUTES.providerExternal, { method: "POST", handle: providerExternal }],
71806
72246
  ...machineFeatureRoutes
71807
72247
  ]);
72248
+ async function routeConversationMessages(deps, request2, conversationMatch) {
72249
+ if (request2.req.method !== "GET") {
72250
+ sendError(request2.res, 405, "method_not_allowed", "Use GET");
72251
+ return;
72252
+ }
72253
+ const conversationId = conversationIdSchema.safeParse(conversationMatch[1]);
72254
+ const query = conversationMessagesQuerySchema.safeParse(
72255
+ Object.fromEntries(request2.url.searchParams)
72256
+ );
72257
+ if (!conversationId.success || !query.success) {
72258
+ sendError(request2.res, 400, "invalid_request", "Invalid conversation messages request");
72259
+ return;
72260
+ }
72261
+ if (query.data.runtimeId && query.data.runtimeId !== deps.readFacts().machineId) {
72262
+ sendError(request2.res, 404, "not_found", "This conversation runs on another computer");
72263
+ return;
72264
+ }
72265
+ if (conversationMatch[2])
72266
+ return streamLocalConversationMessages(
72267
+ deps,
72268
+ conversationId.data,
72269
+ query.data.limit,
72270
+ query.data.frames,
72271
+ request2.res,
72272
+ request2.signal
72273
+ );
72274
+ const page = await readLocalConversationMessages(
72275
+ deps.runsDir,
72276
+ conversationId.data,
72277
+ query.data.limit,
72278
+ query.data.before
72279
+ );
72280
+ if (page === null) {
72281
+ sendError(request2.res, 404, "not_found", "This computer has no complete local page");
72282
+ return;
72283
+ }
72284
+ sendJson(request2.res, 200, page);
72285
+ }
71808
72286
  async function routeRun(deps, request2, match) {
71809
72287
  const runId = runIdSchema.safeParse(match[1]);
71810
72288
  const action = match[2];
@@ -71833,40 +72311,8 @@ async function route(deps, request2) {
71833
72311
  const match = RUN_PATH.exec(request2.url.pathname);
71834
72312
  if (match !== null) return routeRun(deps, request2, match);
71835
72313
  const conversationMatch = CONVERSATION_MESSAGES_PATH.exec(request2.url.pathname);
71836
- if (conversationMatch !== null) {
71837
- if (request2.req.method !== "GET") {
71838
- sendError(request2.res, 405, "method_not_allowed", "Use GET");
71839
- return;
71840
- }
71841
- const conversationId = conversationIdSchema.safeParse(conversationMatch[1]);
71842
- const query = conversationMessagesQuerySchema.safeParse(
71843
- Object.fromEntries(request2.url.searchParams)
71844
- );
71845
- if (!conversationId.success || !query.success) {
71846
- sendError(request2.res, 400, "invalid_request", "Invalid conversation messages request");
71847
- return;
71848
- }
71849
- if (conversationMatch[2])
71850
- return streamLocalConversationMessages(
71851
- deps,
71852
- conversationId.data,
71853
- query.data.limit,
71854
- request2.res,
71855
- request2.signal
71856
- );
71857
- const page = await readLocalConversationMessages(
71858
- deps.runsDir,
71859
- conversationId.data,
71860
- query.data.limit,
71861
- query.data.before
71862
- );
71863
- if (page === null) {
71864
- sendError(request2.res, 404, "not_found", "This computer has no complete local page");
71865
- return;
71866
- }
71867
- sendJson(request2.res, 200, page);
71868
- return;
71869
- }
72314
+ if (conversationMatch !== null)
72315
+ return routeConversationMessages(deps, request2, conversationMatch);
71870
72316
  sendError(request2.res, 404, "not_found", "Not found");
71871
72317
  }
71872
72318
 
@@ -71974,6 +72420,7 @@ async function serveLocalApi(deps) {
71974
72420
  const appAttachments = createAppAttachments(clock);
71975
72421
  const routeDeps = {
71976
72422
  feed,
72423
+ readFacts: deps.readFacts,
71977
72424
  appAttachments,
71978
72425
  actions: deps.actions,
71979
72426
  runsDir: deps.runsDir,
@@ -72015,7 +72462,7 @@ async function serveLocalApi(deps) {
72015
72462
  startedAtMs,
72016
72463
  runtimeVersion: deps.runtimeVersion
72017
72464
  };
72018
- const discoveryPath = (0, import_node_path76.join)(deps.stateDir, LOCAL_API_DISCOVERY_FILE);
72465
+ const discoveryPath = (0, import_node_path77.join)(deps.stateDir, LOCAL_API_DISCOVERY_FILE);
72019
72466
  await writeJsonFileAtomic(discoveryPath, discovery);
72020
72467
  const followers = startMaintenance({
72021
72468
  everyMs: limits.refreshEveryMs,
@@ -72049,7 +72496,7 @@ async function serveLocalApi(deps) {
72049
72496
  await watchedStatus[Symbol.asyncDispose]();
72050
72497
  const current = await readJsonFile(discoveryPath, localApiDiscoverySchema);
72051
72498
  if (current.kind === "ok" && current.value.token === token) {
72052
- await (0, import_promises73.rm)(discoveryPath, { force: true });
72499
+ await (0, import_promises74.rm)(discoveryPath, { force: true });
72053
72500
  }
72054
72501
  await closeServer(server);
72055
72502
  log.info("local_api.closed", {});
@@ -72134,7 +72581,7 @@ function machineFeatureActions(deps) {
72134
72581
  }
72135
72582
 
72136
72583
  // src/cli/commands/machine-plane.ts
72137
- var import_node_path78 = require("path");
72584
+ var import_node_path79 = require("path");
72138
72585
 
72139
72586
  // src/link/index.ts
72140
72587
  init_runtime_v2();
@@ -75802,7 +76249,7 @@ function refusalFailure(refusal2) {
75802
76249
  }
75803
76250
 
75804
76251
  // src/link/probe.ts
75805
- var import_promises74 = require("dns/promises");
76252
+ var import_promises75 = require("dns/promises");
75806
76253
  var import_node_net5 = require("net");
75807
76254
  var import_node_tls2 = require("tls");
75808
76255
  var PROBE_TIMEOUT_MS4 = 5e3;
@@ -75838,7 +76285,7 @@ async function connectOnce(url3, clock) {
75838
76285
  }
75839
76286
  async function probeEndpoint(url3, clock) {
75840
76287
  try {
75841
- await (0, import_promises74.lookup)(url3.hostname);
76288
+ await (0, import_promises75.lookup)(url3.hostname);
75842
76289
  } catch (error61) {
75843
76290
  const reason = classifyTransportFailure(error61);
75844
76291
  return reason === "other" ? "dns" : reason;
@@ -76287,7 +76734,7 @@ function createReconciler(host, lifecycle, log, signal) {
76287
76734
  }
76288
76735
 
76289
76736
  // src/uploader/index.ts
76290
- var import_promises75 = require("fs/promises");
76737
+ var import_promises76 = require("fs/promises");
76291
76738
  init_runtime_v2();
76292
76739
  init_zod();
76293
76740
  var RETRY_DELAYS_MS = [250, 500, 1e3, 2e3, 5e3, 1e4, 3e4];
@@ -76302,10 +76749,11 @@ var uploadProgressSchema = external_exports.object({
76302
76749
  function progressFromReceipt(receipt) {
76303
76750
  return { admittedOffset: receipt?.admittedOffset ?? 0, sealed: receipt?.finalized ?? false };
76304
76751
  }
76305
- function startUploader({ api, runsDir, clock, log }) {
76752
+ function startUploader({ api, runsDir, clock, log, archive }) {
76306
76753
  const controller = new AbortController();
76307
76754
  const active = /* @__PURE__ */ new Map();
76308
76755
  const again = /* @__PURE__ */ new Set();
76756
+ const sealed = /* @__PURE__ */ new Set();
76309
76757
  const reject = async (runId, progressPath, progress, rejection2) => {
76310
76758
  log.error("upload.rejected", { runId, status: rejection2.status, message: rejection2.message });
76311
76759
  if (rejection2.status === UNAUTHORIZED) return;
@@ -76318,12 +76766,15 @@ function startUploader({ api, runsDir, clock, log }) {
76318
76766
  if (stored.kind === "ok") return stored.value;
76319
76767
  const receipt = await api.readReceipt(target, controller.signal);
76320
76768
  switch (receipt.kind) {
76321
- case "read":
76769
+ case "read": {
76322
76770
  log.debug("upload.resumed", {
76323
76771
  runId,
76324
76772
  admittedOffset: receipt.receipt?.admittedOffset ?? 0
76325
76773
  });
76326
- return progressFromReceipt(receipt.receipt);
76774
+ const progress = progressFromReceipt(receipt.receipt);
76775
+ if (progress.sealed) await writeJsonFileAtomic(path4, progress);
76776
+ return progress;
76777
+ }
76327
76778
  case "rejected":
76328
76779
  await reject(runId, path4, progressFromReceipt(null), receipt);
76329
76780
  return null;
@@ -76390,6 +76841,7 @@ function startUploader({ api, runsDir, clock, log }) {
76390
76841
  failures = 0;
76391
76842
  progress = step.progress;
76392
76843
  if (progress.sealed) {
76844
+ sealed.add(runId);
76393
76845
  log.info("upload.sealed", { runId, bytes: progress.admittedOffset });
76394
76846
  return;
76395
76847
  }
@@ -76403,6 +76855,7 @@ function startUploader({ api, runsDir, clock, log }) {
76403
76855
  if (meta3 === null) return;
76404
76856
  const target = { conversationId: meta3.conversationId, runId };
76405
76857
  const progress = await progressOf(runId, target, dir.upload);
76858
+ if (progress?.sealed) sealed.add(runId);
76406
76859
  if (progress === null || progress.sealed) return;
76407
76860
  if (progress.parkedUntil !== void 0 && progress.parkedUntil > clock.now()) return;
76408
76861
  const reader = __using(_stack, await openRunLogReader(dir.log), true);
@@ -76427,40 +76880,44 @@ function startUploader({ api, runsDir, clock, log }) {
76427
76880
  });
76428
76881
  active.set(runId, task);
76429
76882
  };
76430
- const sweep2 = async () => {
76431
- for (const name of await (0, import_promises75.readdir)(runsDir).catch(() => [])) {
76883
+ const unsealedRunIds = async () => {
76884
+ const runIds = [];
76885
+ for (const name of await (0, import_promises76.readdir)(runsDir).catch(() => [])) {
76432
76886
  const runId = runIdSchema.safeParse(name);
76433
- if (runId.success) run2(runId.data);
76887
+ if (runId.success && !sealed.has(runId.data) && !archive?.has(runId.data))
76888
+ runIds.push(runId.data);
76434
76889
  }
76890
+ return runIds;
76891
+ };
76892
+ const sweep2 = async () => {
76893
+ for (const runId of await unsealedRunIds()) run2(runId);
76435
76894
  };
76436
- const isPrunable = async (runId, options) => {
76895
+ const isArchivable = async (runId, options) => {
76437
76896
  if (options.keep.has(runId) || active.has(runId)) return false;
76438
76897
  const dir = runDirectory(runsDir, runId);
76439
76898
  const progress = await readJsonFile(dir.upload, uploadProgressSchema);
76440
76899
  if (progress.kind !== "ok" || !progress.value.sealed) return false;
76441
- const sealedAt = (await (0, import_promises75.stat)(dir.upload)).mtimeMs;
76900
+ const sealedAt = (await (0, import_promises76.stat)(dir.upload)).mtimeMs;
76442
76901
  if (clock.now() - sealedAt < options.sealedForMs) return false;
76443
76902
  return (await readLastRecord(dir.log))?.update.sessionUpdate === "_alan/run.ended";
76444
76903
  };
76445
- const prune = async (options) => {
76446
- let removed = 0;
76447
- for (const name of await (0, import_promises75.readdir)(runsDir).catch(() => [])) {
76904
+ const archivable = async (options) => {
76905
+ const found = [];
76906
+ for (const name of await (0, import_promises76.readdir)(runsDir).catch(() => [])) {
76448
76907
  const runId = runIdSchema.safeParse(name);
76449
- if (!runId.success) continue;
76908
+ if (!runId.success || archive?.has(runId.data)) continue;
76450
76909
  try {
76451
- if (!await isPrunable(runId.data, options)) continue;
76452
- await (0, import_promises75.rm)(runDirectory(runsDir, runId.data).dir, { recursive: true, force: true });
76453
- removed += 1;
76910
+ if (await isArchivable(runId.data, options)) found.push(runId.data);
76454
76911
  } catch (error61) {
76455
- log.warn("upload.prune_failed", { runId: runId.data, error: error61 });
76912
+ log.warn("upload.archive_check_failed", { runId: runId.data, error: error61 });
76456
76913
  }
76457
76914
  }
76458
- return removed;
76915
+ return found;
76459
76916
  };
76460
76917
  return {
76461
76918
  notify: run2,
76462
- prune,
76463
76919
  sweep: sweep2,
76920
+ archivable,
76464
76921
  flush: async () => {
76465
76922
  await sweep2();
76466
76923
  while (active.size > 0 && !controller.signal.aborted) {
@@ -76573,6 +77030,28 @@ function unwrap(outcome2, what) {
76573
77030
  outcome2.code
76574
77031
  );
76575
77032
  }
77033
+ async function writeNativeTurnRun(runsDir, run2, log) {
77034
+ const runId = runIdSchema.parse(run2.runId);
77035
+ const conversationId = conversationIdSchema.parse(run2.conversationId);
77036
+ const { userMessage, assistantMessage } = run2;
77037
+ await writeCompleteRunLog(
77038
+ runsDir,
77039
+ { runId, conversationId, userMessage, assistantMessage },
77040
+ run2.records
77041
+ );
77042
+ if (userMessage?.turnOrdinal != null && assistantMessage?.turnOrdinal != null) {
77043
+ await indexConversationRun(
77044
+ runsDir,
77045
+ conversationId,
77046
+ userMessage.turnOrdinal,
77047
+ assistantMessage.turnOrdinal,
77048
+ runId
77049
+ ).catch(
77050
+ (error61) => log.warn("native_ingest.conversation_index_failed", { runId, error: error61 })
77051
+ );
77052
+ }
77053
+ return runId;
77054
+ }
76576
77055
  async function startMachineNativeIngest(deps) {
76577
77056
  const client = createNativeSessionsClient({
76578
77057
  apiUrl: deps.apiUrl,
@@ -76589,13 +77068,7 @@ async function startMachineNativeIngest(deps) {
76589
77068
  api,
76590
77069
  publisher: {
76591
77070
  publish: async (run2) => {
76592
- const runId = runIdSchema.parse(run2.runId);
76593
- await writeCompleteRunLog(
76594
- deps.runsDir,
76595
- { runId, conversationId: conversationIdSchema.parse(run2.conversationId) },
76596
- run2.records
76597
- );
76598
- deps.onPublished(runId);
77071
+ deps.onPublished(await writeNativeTurnRun(deps.runsDir, run2, deps.log));
76599
77072
  }
76600
77073
  },
76601
77074
  clock: deps.clock,
@@ -76631,12 +77104,12 @@ async function startMachineNativeIngest(deps) {
76631
77104
  }
76632
77105
 
76633
77106
  // src/cli/commands/run-updates.ts
76634
- var import_node_path77 = require("path");
77107
+ var import_node_path78 = require("path");
76635
77108
  init_runtime_v2();
76636
77109
  var UPDATE_CHECK_EVERY_MS = 6 * 60 * 60 * 1e3;
76637
77110
  var DEFERRED_RETRY_MS = 5 * 60 * 1e3;
76638
77111
  function isInstalledBundle(layout, bundlePath) {
76639
- return (0, import_node_path77.resolve)((0, import_node_path77.dirname)((0, import_node_path77.dirname)(bundlePath))) === (0, import_node_path77.resolve)(layout.versions);
77112
+ return (0, import_node_path78.resolve)((0, import_node_path78.dirname)((0, import_node_path78.dirname)(bundlePath))) === (0, import_node_path78.resolve)(layout.versions);
76640
77113
  }
76641
77114
  async function settleUpgradeOnStart({
76642
77115
  layout,
@@ -76743,7 +77216,7 @@ function startRuntimeUpdates(options) {
76743
77216
  layout,
76744
77217
  release: npmRelease,
76745
77218
  tarball: await options.downloader.download(npmRelease.dist.tarball, signal),
76746
- tmpDir: (0, import_node_path77.join)(layout.root, ".downloads")
77219
+ tmpDir: (0, import_node_path78.join)(layout.root, ".downloads")
76747
77220
  });
76748
77221
  await lifecycle.exclusive("upgrade", async () => {
76749
77222
  await recordPendingUpgrade(layout, currentVersion2, version2, clock.now());
@@ -76789,10 +77262,10 @@ var MAINTENANCE_EVERY_MS = 3e3;
76789
77262
  var CAPABILITY_RESCAN_MS = 15 * 6e4;
76790
77263
  var LOCAL_SKILLS_RESCAN_MS = 6e4;
76791
77264
  var CAPABILITY_MAX_AGE_MS = 6e4;
77265
+ var RUN_ARCHIVE_EVERY_MS = 6 * 60 * 6e4;
77266
+ var SEALED_RUN_ARCHIVE_MS = 7 * 24 * 60 * 6e4;
76792
77267
  var DESIRED_RESYNC_TICK_MS = 5e3;
76793
77268
  var UPLOAD_SWEEP_EVERY_MS = 3e4;
76794
- var RUN_PRUNE_EVERY_MS = 6 * 60 * 6e4;
76795
- var SEALED_RUN_RETENTION_MS = 7 * 24 * 60 * 6e4;
76796
77269
  function setupFor(state) {
76797
77270
  if (state.kind !== "stopped") return "ready";
76798
77271
  switch (state.failure.reason) {
@@ -76928,7 +77401,12 @@ async function startMachinePlane(deps) {
76928
77401
  return null;
76929
77402
  };
76930
77403
  const cliEnvironment = providerEnvironment2();
76931
- const uploader = stack.use(startUploader({ api, runsDir: paths.runs, clock, log }));
77404
+ await rebuildConversationIndexes(paths.runs).then(
77405
+ (rebuilt) => rebuilt > 0 && log.info("conversation_index.rebuilt", { conversations: rebuilt }),
77406
+ (error61) => log.warn("conversation_index.rebuild_failed", { error: error61 })
77407
+ );
77408
+ const archive = await openRunArchive(paths.runs);
77409
+ const uploader = stack.use(startUploader({ api, runsDir: paths.runs, clock, log, archive }));
76932
77410
  const nativeIngest = stack.use(
76933
77411
  await startMachineNativeIngest({
76934
77412
  stateDir: paths.stateDir,
@@ -76956,6 +77434,7 @@ async function startMachinePlane(deps) {
76956
77434
  maxActiveRuns: config2.maxActiveRuns,
76957
77435
  suspendPolicy: config2.sessionSuspend,
76958
77436
  openedConversation: () => openedConversation,
77437
+ archive,
76959
77438
  spawnHolder: (launchPath) => {
76960
77439
  spawnDetached(
76961
77440
  {
@@ -76968,7 +77447,7 @@ async function startMachinePlane(deps) {
76968
77447
  [ALAN_MANAGED_SESSION_ENV]: "1"
76969
77448
  },
76970
77449
  cwd: paths.stateDir,
76971
- outputPath: (0, import_node_path78.join)(paths.logs, "holders.log")
77450
+ outputPath: (0, import_node_path79.join)(paths.logs, "holders.log")
76972
77451
  },
76973
77452
  deps.holderIsolation
76974
77453
  );
@@ -77106,19 +77585,20 @@ async function startMachinePlane(deps) {
77106
77585
  })
77107
77586
  );
77108
77587
  await uploader.sweep();
77109
- const runsPrune = stack.use(
77588
+ const runsArchive = stack.use(
77110
77589
  startMaintenance({
77111
- everyMs: RUN_PRUNE_EVERY_MS,
77590
+ everyMs: RUN_ARCHIVE_EVERY_MS,
77112
77591
  jobs: [
77113
77592
  {
77114
- name: "runs.prune",
77593
+ name: "runs.archive",
77115
77594
  run: async (signal) => {
77116
77595
  const desired = await api.fetchDesired(signal);
77117
- const removed = await uploader.prune({
77118
- sealedForMs: SEALED_RUN_RETENTION_MS,
77596
+ const archived = await uploader.archivable({
77597
+ sealedForMs: SEALED_RUN_ARCHIVE_MS,
77119
77598
  keep: new Set(desired.runs.map((run2) => run2.runId))
77120
77599
  });
77121
- if (removed > 0) log.info("runs.pruned", { removed });
77600
+ await archive.add(archived);
77601
+ if (archived.length > 0) log.info("runs.archived", { archived: archived.length });
77122
77602
  }
77123
77603
  }
77124
77604
  ],
@@ -77126,10 +77606,11 @@ async function startMachinePlane(deps) {
77126
77606
  log
77127
77607
  })
77128
77608
  );
77129
- const pruneAtStart = async () => {
77130
- if ((await sessions.heldRuns()).some((run2) => run2.state === "ended")) await runsPrune.runNow();
77609
+ const archiveAtStart = async () => {
77610
+ if ((await sessions.heldRuns()).some((run2) => run2.state === "ended"))
77611
+ await runsArchive.runNow();
77131
77612
  };
77132
- pruneAtStart().catch((error61) => log.warn("runs.prune_failed", { error: error61 }));
77613
+ archiveAtStart().catch((error61) => log.warn("runs.archive_failed", { error: error61 }));
77133
77614
  const capabilities = createCapabilityPublisher({
77134
77615
  inventory: createCapabilityInventory({
77135
77616
  env: providerEnvironment2,
@@ -77199,7 +77680,7 @@ async function startMachinePlane(deps) {
77199
77680
  git: createGitRunner({ env: cliEnvironment }),
77200
77681
  clock,
77201
77682
  log,
77202
- dir: (0, import_node_path78.join)(paths.stateDir, "checkout-freshness")
77683
+ dir: (0, import_node_path79.join)(paths.stateDir, "checkout-freshness")
77203
77684
  },
77204
77685
  stopped.signal
77205
77686
  );
@@ -77493,7 +77974,7 @@ function lockWaitMs(argv) {
77493
77974
  }
77494
77975
  async function openManagedProviders(config2, paths) {
77495
77976
  const providerEnv = readCliEnvironment();
77496
- const bundledNpm = (0, import_node_path79.join)((0, import_node_path79.dirname)(process.execPath), "npm", "bin", "npm-cli.js");
77977
+ const bundledNpm = (0, import_node_path80.join)((0, import_node_path80.dirname)(process.execPath), "npm", "bin", "npm-cli.js");
77497
77978
  const providerToolchain = config2.providerToolchain ?? (process.platform === "win32" && (0, import_node_fs23.existsSync)(bundledNpm) ? { node: process.execPath, npmCli: bundledNpm } : null);
77498
77979
  const npmPath = providerToolchain?.node ?? await resolveCommandOnPath("npm", providerEnv, process.platform);
77499
77980
  const npmOptions = npmPath === null || process.platform === "win32" && providerToolchain === null ? null : {
@@ -77501,7 +77982,7 @@ async function openManagedProviders(config2, paths) {
77501
77982
  ...providerToolchain === null ? {} : { argsBeforeNpm: [providerToolchain.npmCli] },
77502
77983
  env: providerEnv
77503
77984
  };
77504
- const providerNodeDir = providerToolchain?.node === void 0 ? void 0 : (0, import_node_path79.dirname)(providerToolchain.node);
77985
+ const providerNodeDir = providerToolchain?.node === void 0 ? void 0 : (0, import_node_path80.dirname)(providerToolchain.node);
77505
77986
  const probeEnv = providerNodeDir === void 0 ? providerEnv : {
77506
77987
  ...providerEnv,
77507
77988
  PATH: `${providerNodeDir}${pathDelimiter(process.platform)}${envValue(providerEnv, "PATH")}`
@@ -77511,7 +77992,7 @@ async function openManagedProviders(config2, paths) {
77511
77992
  throw new Error("Provider installer is unavailable on this computer");
77512
77993
  };
77513
77994
  const managed = createManagedProviderClis({
77514
- root: (0, import_node_path79.join)(paths.stateDir, "provider-clis"),
77995
+ root: (0, import_node_path80.join)(paths.stateDir, "provider-clis"),
77515
77996
  resolveVersion: npmOptions === null ? unavailable : createNpmVersionResolver(npmOptions),
77516
77997
  installPackage: npmOptions === null ? unavailable : createNpmPackageInstaller(npmOptions),
77517
77998
  probe: (executable, backendKind) => probeManagedProvider(executable, backendKind, canonicalProbeEnv)
@@ -77543,7 +78024,7 @@ async function runService(argv, stop, restart = new AbortController().signal) {
77543
78024
  waitMs: lockWaitMs(argv),
77544
78025
  signal: stop
77545
78026
  }));
77546
- const log = __using(_stack, openFileLog((0, import_node_path79.join)(paths.logs, "runtime.jsonl"), config2.logLevel, clock));
78027
+ const log = __using(_stack, openFileLog((0, import_node_path80.join)(paths.logs, "runtime.jsonl"), config2.logLevel, clock));
77547
78028
  const lifecycle = createLifecycleQueue({ clock, log });
77548
78029
  const install2 = installLayout(config2.installDir, config2.profile);
77549
78030
  const bundlePath = process.argv[1] ?? "";
@@ -77577,7 +78058,7 @@ async function runService(argv, stop, restart = new AbortController().signal) {
77577
78058
  openCliEnvironment({
77578
78059
  env: readCliEnvironment(),
77579
78060
  platform: process.platform,
77580
- lastKnownGoodFile: (0, import_node_path79.join)(paths.stateDir, "login-path.json"),
78061
+ lastKnownGoodFile: (0, import_node_path80.join)(paths.stateDir, "login-path.json"),
77581
78062
  clock,
77582
78063
  decorate: (env) => withPackagedAlanCodeEngine(env, bundlePath, process.platform)
77583
78064
  })
@@ -77754,17 +78235,17 @@ async function runServiceCommand(argv, ctx = cliContext()) {
77754
78235
  }
77755
78236
 
77756
78237
  // src/cli/commands/upgrade.ts
77757
- var import_promises76 = require("fs/promises");
77758
- var import_node_path80 = require("path");
78238
+ var import_promises77 = require("fs/promises");
78239
+ var import_node_path81 = require("path");
77759
78240
  function isNotNewer(version2, installed) {
77760
78241
  return installed !== null && isReleaseVersion(version2) && isReleaseVersion(installed) && compareVersions(version2, installed) <= 0;
77761
78242
  }
77762
78243
  async function installFromSource(source) {
77763
78244
  const { layout, from, ifNewer } = source;
77764
- const isTarball = (await (0, import_promises76.stat)(from)).isFile();
77765
- const downloads = (0, import_node_path80.join)(layout.root, ".downloads");
77766
- if (isTarball) await (0, import_promises76.mkdir)(downloads, { recursive: true, mode: 448 });
77767
- const scratch = isTarball ? await (0, import_promises76.mkdtemp)((0, import_node_path80.join)(downloads, "upgrade-")) : null;
78245
+ const isTarball = (await (0, import_promises77.stat)(from)).isFile();
78246
+ const downloads = (0, import_node_path81.join)(layout.root, ".downloads");
78247
+ if (isTarball) await (0, import_promises77.mkdir)(downloads, { recursive: true, mode: 448 });
78248
+ const scratch = isTarball ? await (0, import_promises77.mkdtemp)((0, import_node_path81.join)(downloads, "upgrade-")) : null;
77768
78249
  try {
77769
78250
  const sourceDir = scratch === null ? from : await extractPackageTarball(from, scratch);
77770
78251
  const version2 = await readPackageVersion(sourceDir);
@@ -77772,7 +78253,7 @@ async function installFromSource(source) {
77772
78253
  if (ifNewer && isNotNewer(version2, installed)) return { kind: "skipped", version: version2, installed };
77773
78254
  return { kind: "installed", ...await installVersion(layout, sourceDir) };
77774
78255
  } finally {
77775
- if (scratch !== null) await (0, import_promises76.rm)(scratch, { recursive: true, force: true });
78256
+ if (scratch !== null) await (0, import_promises77.rm)(scratch, { recursive: true, force: true });
77776
78257
  }
77777
78258
  }
77778
78259
  async function runUpgrade(argv) {
@@ -77784,7 +78265,7 @@ async function runUpgrade(argv) {
77784
78265
  const layout = installLayout(config2.installDir, config2.profile);
77785
78266
  const outcome2 = await installFromSource({
77786
78267
  layout,
77787
- from: (0, import_node_path80.resolve)(from),
78268
+ from: (0, import_node_path81.resolve)(from),
77788
78269
  ifNewer: hasFlag(argv, "--if-newer")
77789
78270
  });
77790
78271
  if (outcome2.kind === "skipped") {