@greppleai/grip-agent-core 0.1.5 → 0.1.6

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.
Files changed (61) hide show
  1. package/dist/agent-loop.d.ts.map +1 -1
  2. package/dist/agent-loop.js.map +1 -1
  3. package/dist/agent.d.ts +7 -0
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +2 -27
  6. package/dist/agent.js.map +1 -1
  7. package/dist/harness/agent-harness.d.ts.map +1 -1
  8. package/dist/harness/agent-harness.js +7 -20
  9. package/dist/harness/agent-harness.js.map +1 -1
  10. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  11. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  12. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  13. package/dist/harness/compaction/compaction.js.map +1 -1
  14. package/dist/harness/compaction/utils.d.ts.map +1 -1
  15. package/dist/harness/compaction/utils.js.map +1 -1
  16. package/dist/harness/env/nodejs.d.ts.map +1 -1
  17. package/dist/harness/env/nodejs.js +0 -3
  18. package/dist/harness/env/nodejs.js.map +1 -1
  19. package/dist/harness/messages.d.ts.map +1 -1
  20. package/dist/harness/messages.js.map +1 -1
  21. package/dist/harness/prompt-templates.d.ts.map +1 -1
  22. package/dist/harness/prompt-templates.js.map +1 -1
  23. package/dist/harness/session/jsonl-errors.d.ts.map +1 -1
  24. package/dist/harness/session/jsonl-errors.js +0 -10
  25. package/dist/harness/session/jsonl-errors.js.map +1 -1
  26. package/dist/harness/session/jsonl-repo.d.ts.map +1 -1
  27. package/dist/harness/session/jsonl-repo.js +1 -4
  28. package/dist/harness/session/jsonl-repo.js.map +1 -1
  29. package/dist/harness/session/jsonl-storage.d.ts.map +1 -1
  30. package/dist/harness/session/jsonl-storage.js +1 -11
  31. package/dist/harness/session/jsonl-storage.js.map +1 -1
  32. package/dist/harness/session/memory-repo.d.ts.map +1 -1
  33. package/dist/harness/session/memory-repo.js +3 -1
  34. package/dist/harness/session/memory-repo.js.map +1 -1
  35. package/dist/harness/session/memory-storage.d.ts.map +1 -1
  36. package/dist/harness/session/memory-storage.js +0 -5
  37. package/dist/harness/session/memory-storage.js.map +1 -1
  38. package/dist/harness/session/repo-utils.d.ts.map +1 -1
  39. package/dist/harness/session/repo-utils.js.map +1 -1
  40. package/dist/harness/session/session.d.ts.map +1 -1
  41. package/dist/harness/session/session.js +0 -1
  42. package/dist/harness/session/session.js.map +1 -1
  43. package/dist/harness/session/uuid.d.ts.map +1 -1
  44. package/dist/harness/session/uuid.js.map +1 -1
  45. package/dist/harness/skills.d.ts.map +1 -1
  46. package/dist/harness/skills.js.map +1 -1
  47. package/dist/harness/system-prompt.d.ts.map +1 -1
  48. package/dist/harness/system-prompt.js.map +1 -1
  49. package/dist/harness/types.d.ts.map +1 -1
  50. package/dist/harness/types.js +0 -13
  51. package/dist/harness/types.js.map +1 -1
  52. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  53. package/dist/harness/utils/shell-output.js.map +1 -1
  54. package/dist/harness/utils/truncate.d.ts.map +1 -1
  55. package/dist/harness/utils/truncate.js.map +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/node.d.ts.map +1 -1
  58. package/dist/proxy.d.ts.map +1 -1
  59. package/dist/proxy.js.map +1 -1
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"branch-summarization.js","sourceRoot":"","sources":["../../../src/harness/compaction/branch-summarization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Model, TextContent } from \"@greppleai/grip-ai\";\nimport { completeSimple } from \"@greppleai/grip-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport {\n\tconvertToLlm,\n\tcreateBranchSummaryMessage,\n\tcreateCompactionSummaryMessage,\n\tcreateCustomMessage,\n} from \"../messages.ts\";\nimport type { BranchSummaryResult, Session, SessionTreeEntry } from \"../types.ts\";\nimport { BranchSummaryError, err, ok, type Result, SessionError } from \"../types.ts\";\nimport { estimateTokens, SUMMARIZATION_SYSTEM_PROMPT } from \"./compaction.ts\";\nimport {\n\tcomputeFileLists,\n\tcreateFileOps,\n\textractFileOpsFromMessage,\n\ttype FileOperationLists,\n\ttype FileOperations,\n\tformatFileOperations,\n\tserializeConversation,\n} from \"./utils.ts\";\n\n/** File-operation lists stored on generated branch summary entries. */\nexport type BranchSummaryDetails = FileOperationLists;\n\nexport type { FileOperations } from \"./utils.ts\";\n\n/** Prepared branch content for summarization. */\nexport interface BranchPreparation {\n\t/** Messages selected for the branch summary. */\n\tmessages: AgentMessage[];\n\t/** File operations extracted from the branch. */\n\tfileOps: FileOperations;\n\t/** Estimated token count for selected messages. */\n\ttotalTokens: number;\n}\n\n/** Entries selected for branch summarization. */\nexport interface CollectEntriesResult {\n\t/** Entries to summarize in chronological order. */\n\tentries: SessionTreeEntry[];\n\t/** Deepest common ancestor between the previous leaf and target entry. */\n\tcommonAncestorId: string | null;\n}\n\n/** Options for generating a branch summary. */\nexport interface GenerateBranchSummaryOptions {\n\t/** Model used for summarization. */\n\tmodel: Model<any>;\n\t/** API key forwarded to the provider. */\n\tapiKey: string;\n\t/** Optional request headers forwarded to the provider. */\n\theaders?: Record<string, string>;\n\t/** Abort signal for the summarization request. */\n\tsignal: AbortSignal;\n\t/** Optional instructions appended to or replacing the default prompt. */\n\tcustomInstructions?: string;\n\t/** Replace the default prompt with custom instructions instead of appending them. */\n\treplaceInstructions?: boolean;\n\t/** Tokens reserved for prompt and model output. Defaults to 16384. */\n\treserveTokens?: number;\n}\n\n/** Collect entries that should be summarized before navigating to a different session tree entry. */\nexport async function collectEntriesForBranchSummary(\n\tsession: Session,\n\toldLeafId: string | null,\n\ttargetId: string,\n): Promise<CollectEntriesResult> {\n\tif (!oldLeafId) {\n\t\treturn { entries: [], commonAncestorId: null };\n\t}\n\tconst oldPath = new Set((await session.getBranch(oldLeafId)).map((e) => e.id));\n\tconst targetPath = await session.getBranch(targetId);\n\tlet commonAncestorId: string | null = null;\n\tfor (let i = targetPath.length - 1; i >= 0; i--) {\n\t\tif (oldPath.has(targetPath[i].id)) {\n\t\t\tcommonAncestorId = targetPath[i].id;\n\t\t\tbreak;\n\t\t}\n\t}\n\tconst entries: SessionTreeEntry[] = [];\n\tlet current: string | null = oldLeafId;\n\n\twhile (current && current !== commonAncestorId) {\n\t\tconst entry = await session.getEntry(current);\n\t\tif (!entry) throw new SessionError(\"invalid_session\", `Entry ${current} not found`);\n\t\tentries.push(entry as SessionTreeEntry);\n\t\tcurrent = entry.parentId;\n\t}\n\tentries.reverse();\n\n\treturn { entries, commonAncestorId };\n}\nfunction getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {\n\tswitch (entry.type) {\n\t\tcase \"message\":\n\t\t\tif (entry.message.role === \"toolResult\") return undefined;\n\t\t\treturn entry.message;\n\n\t\tcase \"custom_message\":\n\t\t\treturn createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp);\n\n\t\tcase \"branch_summary\":\n\t\t\treturn createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n\n\t\tcase \"compaction\":\n\t\t\treturn createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n\t\tcase \"thinking_level_change\":\n\t\tcase \"model_change\":\n\t\tcase \"custom\":\n\t\tcase \"label\":\n\t\tcase \"session_info\":\n\t\tcase \"leaf\":\n\t\t\treturn undefined;\n\t}\n}\n\nfunction mergeStoredBranchFileOperations(details: BranchSummaryDetails, fileOps: FileOperations): void {\n\tif (Array.isArray(details.readFiles)) {\n\t\tfor (const file of details.readFiles) fileOps.read.add(file);\n\t}\n\tif (Array.isArray(details.modifiedFiles)) {\n\t\tfor (const file of details.modifiedFiles) fileOps.edited.add(file);\n\t}\n}\n\nfunction collectStoredBranchFileOperations(entries: SessionTreeEntry[], fileOps: FileOperations): void {\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"branch_summary\" || entry.fromHook || !entry.details) continue;\n\t\tmergeStoredBranchFileOperations(entry.details as BranchSummaryDetails, fileOps);\n\t}\n}\n\nfunction prependBranchMessage(preparation: BranchPreparation, message: AgentMessage, tokens: number): void {\n\tpreparation.messages.unshift(message);\n\tpreparation.totalTokens += tokens;\n}\n\nfunction exceedsBranchTokenBudget(totalTokens: number, messageTokens: number, tokenBudget: number): boolean {\n\treturn tokenBudget > 0 && totalTokens + messageTokens > tokenBudget;\n}\n\nfunction canRetainOverBudgetSummary(entry: SessionTreeEntry, totalTokens: number, tokenBudget: number): boolean {\n\treturn (entry.type === \"compaction\" || entry.type === \"branch_summary\") && totalTokens < tokenBudget * 0.9;\n}\n\nfunction selectBranchMessages(entries: SessionTreeEntry[], tokenBudget: number, preparation: BranchPreparation): void {\n\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\tconst entry = entries[index];\n\t\tconst message = getMessageFromEntry(entry);\n\t\tif (!message) continue;\n\t\textractFileOpsFromMessage(message, preparation.fileOps);\n\t\tconst tokens = estimateTokens(message);\n\t\tif (!exceedsBranchTokenBudget(preparation.totalTokens, tokens, tokenBudget)) {\n\t\t\tprependBranchMessage(preparation, message, tokens);\n\t\t\tcontinue;\n\t\t}\n\t\tif (canRetainOverBudgetSummary(entry, preparation.totalTokens, tokenBudget)) {\n\t\t\tprependBranchMessage(preparation, message, tokens);\n\t\t}\n\t\tbreak;\n\t}\n}\n\n/** Prepare branch entries for summarization within an optional token budget. */\nexport function prepareBranchEntries(entries: SessionTreeEntry[], tokenBudget: number = 0): BranchPreparation {\n\tconst preparation: BranchPreparation = { messages: [], fileOps: createFileOps(), totalTokens: 0 };\n\tcollectStoredBranchFileOperations(entries, preparation.fileOps);\n\tselectBranchMessages(entries, tokenBudget, preparation);\n\treturn preparation;\n}\n\nconst BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.\nSummary of that exploration:\n\n`;\n\nconst BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.\n\nUse this EXACT format:\n\n## Goal\n[What was the user trying to accomplish in this branch?]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Work that was started but not finished]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [What should happen next to continue this work]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\n/** Generate a summary for abandoned branch entries. */\nexport async function generateBranchSummary(\n\tentries: SessionTreeEntry[],\n\toptions: GenerateBranchSummaryOptions,\n): Promise<Result<BranchSummaryResult, BranchSummaryError>> {\n\tconst { model, apiKey, headers, signal, customInstructions, replaceInstructions, reserveTokens = 16384 } = options;\n\tconst contextWindow = model.contextWindow || 128000;\n\tconst tokenBudget = contextWindow - reserveTokens;\n\n\tconst { messages, fileOps } = prepareBranchEntries(entries, tokenBudget);\n\n\tif (messages.length === 0) {\n\t\treturn ok({ summary: \"No content to summarize\", readFiles: [], modifiedFiles: [] });\n\t}\n\tconst llmMessages = convertToLlm(messages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tlet instructions: string;\n\tif (replaceInstructions && customInstructions) {\n\t\tinstructions = customInstructions;\n\t} else if (customInstructions) {\n\t\tinstructions = `${BRANCH_SUMMARY_PROMPT}\\n\\nAdditional focus: ${customInstructions}`;\n\t} else {\n\t\tinstructions = BRANCH_SUMMARY_PROMPT;\n\t}\n\tconst promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n${instructions}`;\n\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\t{ apiKey, headers, signal, maxTokens: 2048 },\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new BranchSummaryError(\"aborted\", response.errorMessage || \"Branch summary aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew BranchSummaryError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Branch summary failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\tlet summary = response.content\n\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\"\\n\");\n\tsummary = BRANCH_SUMMARY_PREAMBLE + summary;\n\tconst { readFiles, modifiedFiles } = computeFileLists(fileOps);\n\tsummary += formatFileOperations(readFiles, modifiedFiles);\n\n\treturn ok({\n\t\tsummary: summary || \"No summary generated\",\n\t\treadFiles,\n\t\tmodifiedFiles,\n\t});\n}\n"]}
1
+ {"version":3,"file":"branch-summarization.js","sourceRoot":"","sources":["../../../src/harness/compaction/branch-summarization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Model, TextContent } from \"@greppleai/grip-ai\";\nimport { completeSimple } from \"@greppleai/grip-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport {\n\tconvertToLlm,\n\tcreateBranchSummaryMessage,\n\tcreateCompactionSummaryMessage,\n\tcreateCustomMessage,\n} from \"../messages.ts\";\nimport type { BranchSummaryResult, Session, SessionTreeEntry } from \"../types.ts\";\nimport { BranchSummaryError, err, ok, type Result, SessionError } from \"../types.ts\";\nimport { estimateTokens, SUMMARIZATION_SYSTEM_PROMPT } from \"./compaction.ts\";\nimport {\n\tcomputeFileLists,\n\tcreateFileOps,\n\textractFileOpsFromMessage,\n\ttype FileOperationLists,\n\ttype FileOperations,\n\tformatFileOperations,\n\tserializeConversation,\n} from \"./utils.ts\";\n\n/** File-operation lists stored on generated branch summary entries. */\nexport type BranchSummaryDetails = FileOperationLists;\n\nexport type { FileOperations } from \"./utils.ts\";\n\n/** Prepared branch content for summarization. */\nexport interface BranchPreparation {\n\t/** Messages selected for the branch summary. */\n\tmessages: AgentMessage[];\n\t/** File operations extracted from the branch. */\n\tfileOps: FileOperations;\n\t/** Estimated token count for selected messages. */\n\ttotalTokens: number;\n}\n\n/** Entries selected for branch summarization. */\nexport interface CollectEntriesResult {\n\t/** Entries to summarize in chronological order. */\n\tentries: SessionTreeEntry[];\n\t/** Deepest common ancestor between the previous leaf and target entry. */\n\tcommonAncestorId: string | null;\n}\n\n/** Options for generating a branch summary. */\nexport interface GenerateBranchSummaryOptions {\n\t/** Model used for summarization. */\n\tmodel: Model<any>;\n\t/** API key forwarded to the provider. */\n\tapiKey: string;\n\t/** Optional request headers forwarded to the provider. */\n\theaders?: Record<string, string>;\n\t/** Abort signal for the summarization request. */\n\tsignal: AbortSignal;\n\t/** Optional instructions appended to or replacing the default prompt. */\n\tcustomInstructions?: string;\n\t/** Replace the default prompt with custom instructions instead of appending them. */\n\treplaceInstructions?: boolean;\n\t/** Tokens reserved for prompt and model output. Defaults to 16384. */\n\treserveTokens?: number;\n}\n\n/** Collect entries that should be summarized before navigating to a different session tree entry. */\nexport async function collectEntriesForBranchSummary(\n\tsession: Session,\n\toldLeafId: string | null,\n\ttargetId: string,\n): Promise<CollectEntriesResult> {\n\tif (!oldLeafId) {\n\t\treturn { entries: [], commonAncestorId: null };\n\t}\n\tconst oldPath = new Set((await session.getBranch(oldLeafId)).map((e) => e.id));\n\tconst targetPath = await session.getBranch(targetId);\n\tlet commonAncestorId: string | null = null;\n\tfor (let i = targetPath.length - 1; i >= 0; i--) {\n\t\tif (oldPath.has(targetPath[i].id)) {\n\t\t\tcommonAncestorId = targetPath[i].id;\n\t\t\tbreak;\n\t\t}\n\t}\n\tconst entries: SessionTreeEntry[] = [];\n\tlet current: string | null = oldLeafId;\n\n\twhile (current && current !== commonAncestorId) {\n\t\tconst entry = await session.getEntry(current);\n\t\tif (!entry) throw new SessionError(\"invalid_session\", `Entry ${current} not found`);\n\t\tentries.push(entry as SessionTreeEntry);\n\t\tcurrent = entry.parentId;\n\t}\n\tentries.reverse();\n\n\treturn { entries, commonAncestorId };\n}\nfunction getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {\n\tswitch (entry.type) {\n\t\tcase \"message\":\n\t\t\tif (entry.message.role === \"toolResult\") return undefined;\n\t\t\treturn entry.message;\n\n\t\tcase \"custom_message\":\n\t\t\treturn createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp);\n\n\t\tcase \"branch_summary\":\n\t\t\treturn createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n\n\t\tcase \"compaction\":\n\t\t\treturn createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n\t\tcase \"thinking_level_change\":\n\t\tcase \"model_change\":\n\t\tcase \"custom\":\n\t\tcase \"label\":\n\t\tcase \"session_info\":\n\t\tcase \"leaf\":\n\t\t\treturn undefined;\n\t}\n}\n\nfunction mergeStoredBranchFileOperations(details: BranchSummaryDetails, fileOps: FileOperations): void {\n\tif (Array.isArray(details.readFiles)) {\n\t\tfor (const file of details.readFiles) fileOps.read.add(file);\n\t}\n\tif (Array.isArray(details.modifiedFiles)) {\n\t\tfor (const file of details.modifiedFiles) fileOps.edited.add(file);\n\t}\n}\n\nfunction collectStoredBranchFileOperations(entries: SessionTreeEntry[], fileOps: FileOperations): void {\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"branch_summary\" || entry.fromHook || !entry.details) continue;\n\t\tmergeStoredBranchFileOperations(entry.details as BranchSummaryDetails, fileOps);\n\t}\n}\n\nfunction prependBranchMessage(preparation: BranchPreparation, message: AgentMessage, tokens: number): void {\n\tpreparation.messages.unshift(message);\n\tpreparation.totalTokens += tokens;\n}\n\nfunction exceedsBranchTokenBudget(totalTokens: number, messageTokens: number, tokenBudget: number): boolean {\n\treturn tokenBudget > 0 && totalTokens + messageTokens > tokenBudget;\n}\n\nfunction canRetainOverBudgetSummary(entry: SessionTreeEntry, totalTokens: number, tokenBudget: number): boolean {\n\treturn (entry.type === \"compaction\" || entry.type === \"branch_summary\") && totalTokens < tokenBudget * 0.9;\n}\n\nfunction selectBranchMessages(entries: SessionTreeEntry[], tokenBudget: number, preparation: BranchPreparation): void {\n\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\tconst entry = entries[index];\n\t\tconst message = getMessageFromEntry(entry);\n\t\tif (!message) continue;\n\t\textractFileOpsFromMessage(message, preparation.fileOps);\n\t\tconst tokens = estimateTokens(message);\n\t\tif (!exceedsBranchTokenBudget(preparation.totalTokens, tokens, tokenBudget)) {\n\t\t\tprependBranchMessage(preparation, message, tokens);\n\t\t\tcontinue;\n\t\t}\n\t\tif (canRetainOverBudgetSummary(entry, preparation.totalTokens, tokenBudget)) {\n\t\t\tprependBranchMessage(preparation, message, tokens);\n\t\t}\n\t\tbreak;\n\t}\n}\n\n/** Prepare branch entries for summarization within an optional token budget. */\nexport function prepareBranchEntries(entries: SessionTreeEntry[], tokenBudget: number = 0): BranchPreparation {\n\tconst preparation: BranchPreparation = { messages: [], fileOps: createFileOps(), totalTokens: 0 };\n\tcollectStoredBranchFileOperations(entries, preparation.fileOps);\n\tselectBranchMessages(entries, tokenBudget, preparation);\n\treturn preparation;\n}\n\nconst BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.\nSummary of that exploration:\n\n`;\n\nconst BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.\n\nUse this EXACT format:\n\n## Goal\n[What was the user trying to accomplish in this branch?]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Work that was started but not finished]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [What should happen next to continue this work]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\n/** Generate a summary for abandoned branch entries. */\nexport async function generateBranchSummary(\n\tentries: SessionTreeEntry[],\n\toptions: GenerateBranchSummaryOptions,\n): Promise<Result<BranchSummaryResult, BranchSummaryError>> {\n\tconst { model, apiKey, headers, signal, customInstructions, replaceInstructions, reserveTokens = 16384 } = options;\n\tconst contextWindow = model.contextWindow || 128000;\n\tconst tokenBudget = contextWindow - reserveTokens;\n\n\tconst { messages, fileOps } = prepareBranchEntries(entries, tokenBudget);\n\n\tif (messages.length === 0) {\n\t\treturn ok({ summary: \"No content to summarize\", readFiles: [], modifiedFiles: [] });\n\t}\n\tconst llmMessages = convertToLlm(messages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tlet instructions: string;\n\tif (replaceInstructions && customInstructions) {\n\t\tinstructions = customInstructions;\n\t} else if (customInstructions) {\n\t\tinstructions = `${BRANCH_SUMMARY_PROMPT}\\n\\nAdditional focus: ${customInstructions}`;\n\t} else {\n\t\tinstructions = BRANCH_SUMMARY_PROMPT;\n\t}\n\tconst promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n${instructions}`;\n\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\t{ apiKey, headers, signal, maxTokens: 2048 },\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new BranchSummaryError(\"aborted\", response.errorMessage || \"Branch summary aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew BranchSummaryError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Branch summary failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\tlet summary = response.content\n\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\"\\n\");\n\tsummary = BRANCH_SUMMARY_PREAMBLE + summary;\n\tconst { readFiles, modifiedFiles } = computeFileLists(fileOps);\n\tsummary += formatFileOperations(readFiles, modifiedFiles);\n\n\treturn ok({\n\t\tsummary: summary || \"No summary generated\",\n\t\treadFiles,\n\t\tmodifiedFiles,\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/harness/compaction/compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tContextUsageEstimate as AiContextUsageEstimate,\n\tAssistantMessage,\n\tAssistantUsageInfo,\n\tImageContent,\n\tModel,\n\tTextContent,\n\tToolResultMessage,\n\tUsage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport { completeSimple } from \"@greppleai/grip-ai\";\nimport type { AgentMessage, ThinkingLevel } from \"../../types.ts\";\nimport {\n\ttype BashExecutionMessage,\n\ttype BranchSummaryMessage,\n\ttype CompactionSummaryMessage,\n\ttype CustomMessage,\n\tconvertToLlm,\n\tcreateBranchSummaryMessage,\n\tcreateCompactionSummaryMessage,\n\tcreateCustomMessage,\n} from \"../messages.ts\";\nimport { buildSessionContext } from \"../session/session.ts\";\nimport { type CompactionEntry, CompactionError, err, ok, type Result, type SessionTreeEntry } from \"../types.ts\";\nimport { serializeConversation } from \"./utils.ts\";\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"message\") {\n\t\treturn entry.message as AgentMessage;\n\t}\n\tif (entry.type === \"custom_message\") {\n\t\treturn createCustomMessage(\n\t\t\tentry.customType,\n\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\tentry.display,\n\t\t\tentry.details,\n\t\t\tentry.timestamp,\n\t\t);\n\t}\n\tif (entry.type === \"branch_summary\") {\n\t\treturn createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n\t}\n\tif (entry.type === \"compaction\") {\n\t\treturn createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n\t}\n\treturn undefined;\n}\n\nfunction getMessageFromEntryForCompaction(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"compaction\") {\n\t\treturn undefined;\n\t}\n\treturn getMessageFromEntry(entry);\n}\n\n/** Generated compaction data ready to be persisted as a compaction entry. */\nexport interface CompactionResult<T = unknown> {\n\t/** Summary text that replaces compacted history in future context. */\n\tsummary: string;\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Optional implementation-specific details stored with the compaction entry. */\n\tdetails?: T;\n}\n\n/** Compaction thresholds and retention settings. */\nexport interface CompactionSettings {\n\t/** Enable automatic compaction decisions. */\n\tenabled: boolean;\n\t/** Tokens reserved for summary prompt and output. */\n\treserveTokens: number;\n\t/** Approximate recent-context tokens to keep after compaction. */\n\tkeepRecentTokens: number;\n}\n\n/** Default compaction settings used by the harness. */\nexport const DEFAULT_COMPACTION_SETTINGS: CompactionSettings = {\n\tenabled: true,\n\treserveTokens: 16384,\n\tkeepRecentTokens: 20000,\n};\n\n/** Calculate total context tokens from provider usage. */\nexport function calculateContextTokens(usage: Usage): number {\n\treturn usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction getAssistantUsage(msg: AgentMessage): Usage | undefined {\n\tif (msg.role === \"assistant\" && \"usage\" in msg) {\n\t\tconst assistantMsg = msg as AssistantMessage;\n\t\tif (assistantMsg.stopReason !== \"aborted\" && assistantMsg.stopReason !== \"error\" && assistantMsg.usage) {\n\t\t\treturn assistantMsg.usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Return usage from the last successful assistant message in session entries. */\nexport function getLastAssistantUsage(entries: SessionTreeEntry[]): Usage | undefined {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tconst usage = getAssistantUsage(entry.message as AgentMessage);\n\t\t\tif (usage) return usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Estimated context-token usage for a message list. */\nexport type ContextUsageEstimate = AiContextUsageEstimate;\n\nfunction getLastAssistantUsageInfo(messages: AgentMessage[]): AssistantUsageInfo | undefined {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst usage = getAssistantUsage(messages[i]);\n\t\tif (usage) return { usage, index: i };\n\t}\n\treturn undefined;\n}\n\n/** Estimate context tokens for messages using provider usage when available. */\nexport function estimateContextTokens(messages: AgentMessage[]): ContextUsageEstimate {\n\tconst usageInfo = getLastAssistantUsageInfo(messages);\n\n\tif (!usageInfo) {\n\t\tlet estimated = 0;\n\t\tfor (const message of messages) {\n\t\t\testimated += estimateTokens(message);\n\t\t}\n\t\treturn {\n\t\t\ttokens: estimated,\n\t\t\tusageTokens: 0,\n\t\t\ttrailingTokens: estimated,\n\t\t\tlastUsageIndex: null,\n\t\t};\n\t}\n\n\tconst usageTokens = calculateContextTokens(usageInfo.usage);\n\tlet trailingTokens = 0;\n\tfor (let i = usageInfo.index + 1; i < messages.length; i++) {\n\t\ttrailingTokens += estimateTokens(messages[i]);\n\t}\n\n\treturn {\n\t\ttokens: usageTokens + trailingTokens,\n\t\tusageTokens,\n\t\ttrailingTokens,\n\t\tlastUsageIndex: usageInfo.index,\n\t};\n}\n\n/** Return whether context usage exceeds the configured compaction threshold. */\nexport function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings): boolean {\n\tif (!settings.enabled) return false;\n\treturn contextTokens > contextWindow - settings.reserveTokens;\n}\n\nfunction estimateUserMessageTokens(message: UserMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateAssistantMessageTokens(message: AssistantMessage): number {\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\tcharacters += block.text.length;\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tcharacters += block.thinking.length;\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tcharacters += block.name.length + safeJsonStringify(block.arguments).length;\n\t\t}\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateContentMessageTokens(message: CustomMessage | ToolResultMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t\tif (block.type === \"image\") characters += 4800;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateBashExecutionTokens(message: BashExecutionMessage): number {\n\treturn Math.ceil((message.command.length + message.output.length) / 4);\n}\n\nfunction estimateSummaryTokens(message: BranchSummaryMessage | CompactionSummaryMessage): number {\n\treturn Math.ceil(message.summary.length / 4);\n}\n\n/** Estimate token count for one message using a conservative character heuristic. */\nexport function estimateTokens(message: AgentMessage): number {\n\tswitch (message.role) {\n\t\tcase \"user\":\n\t\t\treturn estimateUserMessageTokens(message);\n\t\tcase \"assistant\":\n\t\t\treturn estimateAssistantMessageTokens(message);\n\t\tcase \"custom\":\n\t\tcase \"toolResult\":\n\t\t\treturn estimateContentMessageTokens(message);\n\t\tcase \"bashExecution\":\n\t\t\treturn estimateBashExecutionTokens(message);\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\treturn estimateSummaryTokens(message);\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\nfunction findValidCutPoints(entries: SessionTreeEntry[], startIndex: number, endIndex: number): number[] {\n\tconst cutPoints: number[] = [];\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst entry = entries[i];\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\": {\n\t\t\t\tconst role = entry.message.role;\n\t\t\t\tswitch (role) {\n\t\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\tcase \"custom\":\n\t\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\tcase \"user\":\n\t\t\t\t\tcase \"assistant\":\n\t\t\t\t\t\tcutPoints.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"toolResult\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking_level_change\":\n\t\t\tcase \"model_change\":\n\t\t\tcase \"compaction\":\n\t\t\tcase \"branch_summary\":\n\t\t\tcase \"custom\":\n\t\t\tcase \"custom_message\":\n\t\t\tcase \"label\":\n\t\t\tcase \"session_info\":\n\t\t\tcase \"leaf\":\n\t\t\t\tbreak;\n\t\t}\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\tcutPoints.push(i);\n\t\t}\n\t}\n\treturn cutPoints;\n}\n\n/** Find the user-visible message that starts the turn containing an entry. */\nexport function findTurnStartIndex(entries: SessionTreeEntry[], entryIndex: number, startIndex: number): number {\n\tfor (let i = entryIndex; i >= startIndex; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\treturn i;\n\t\t}\n\t\tif (entry.type === \"message\") {\n\t\t\tconst role = entry.message.role;\n\t\t\tif (role === \"user\" || role === \"bashExecution\") {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\n/** Cut point selected for compaction. */\nexport interface CutPointResult {\n\t/** Index of the first entry retained after compaction. */\n\tfirstKeptEntryIndex: number;\n\t/** Index of the turn-start entry when the cut splits a turn, otherwise -1. */\n\tturnStartIndex: number;\n\t/** Whether the selected cut point splits an in-progress turn. */\n\tisSplitTurn: boolean;\n}\n\nfunction selectTokenBudgetCutIndex(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n\tcutPoints: number[],\n): number {\n\tconst defaultCutIndex = cutPoints[0]!;\n\tlet accumulatedTokens = 0;\n\tlet budgetIndex = -1;\n\tfor (let index = endIndex - 1; index >= startIndex; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"message\") continue;\n\t\taccumulatedTokens += estimateTokens(entry.message as AgentMessage);\n\t\tif (accumulatedTokens < keepRecentTokens) continue;\n\t\tbudgetIndex = index;\n\t\tbreak;\n\t}\n\tif (budgetIndex === -1) return defaultCutIndex;\n\treturn cutPoints.find((cutPoint) => cutPoint >= budgetIndex) ?? defaultCutIndex;\n}\n\nfunction moveCutIndexBeforeMetadata(entries: SessionTreeEntry[], cutIndex: number, startIndex: number): number {\n\twhile (cutIndex > startIndex) {\n\t\tconst previousEntry = entries[cutIndex - 1];\n\t\tif (previousEntry.type === \"compaction\" || previousEntry.type === \"message\") return cutIndex;\n\t\tcutIndex--;\n\t}\n\treturn cutIndex;\n}\n\n/** Find the compaction cut point that keeps approximately the requested recent-token budget. */\nexport function findCutPoint(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n): CutPointResult {\n\tconst cutPoints = findValidCutPoints(entries, startIndex, endIndex);\n\tif (cutPoints.length === 0) {\n\t\treturn { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };\n\t}\n\n\tconst selectedCutIndex = selectTokenBudgetCutIndex(entries, startIndex, endIndex, keepRecentTokens, cutPoints);\n\tconst cutIndex = moveCutIndexBeforeMetadata(entries, selectedCutIndex, startIndex);\n\tconst cutEntry = entries[cutIndex];\n\tconst isUserMessage = cutEntry.type === \"message\" && cutEntry.message.role === \"user\";\n\tconst turnStartIndex = isUserMessage ? -1 : findTurnStartIndex(entries, cutIndex, startIndex);\n\treturn {\n\t\tfirstKeptEntryIndex: cutIndex,\n\t\tturnStartIndex,\n\t\tisSplitTurn: !isUserMessage && turnStartIndex !== -1,\n\t};\n}\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n\nconst SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.\n\nUse this EXACT format:\n\n## Goal\n[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned by user]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Current work]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [Ordered list of what should happen next]\n\n## Critical Context\n- [Any data, examples, or references needed to continue]\n- [Or \"(none)\" if not applicable]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\nconst UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.\n\nUpdate the existing structured summary with new information. RULES:\n- PRESERVE all existing information from the previous summary\n- ADD new progress, decisions, and context from the new messages\n- UPDATE the Progress section: move items from \"In Progress\" to \"Done\" when completed\n- UPDATE \"Next Steps\" based on what was accomplished\n- PRESERVE exact file paths, function names, and error messages\n- If something is no longer relevant, you may remove it\n\nUse this EXACT format:\n\n## Goal\n[Preserve existing goals, add new ones if the task expanded]\n\n## Constraints & Preferences\n- [Preserve existing, add new ones discovered]\n\n## Progress\n### Done\n- [x] [Include previously done items AND newly completed items]\n\n### In Progress\n- [ ] [Current work - update based on progress]\n\n### Blocked\n- [Current blockers - remove if resolved]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale] (preserve all previous, add new)\n\n## Next Steps\n1. [Update based on current state]\n\n## Critical Context\n- [Preserve important context, add new if needed]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\n/** Generate or update a conversation summary for compaction. */\nexport async function generateSummary(\n\tcurrentMessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tcustomInstructions?: string,\n\tpreviousSummary?: string,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.8 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tlet basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;\n\tif (customInstructions) {\n\t\tbasePrompt = `${basePrompt}\\n\\nAdditional focus: ${customInstructions}`;\n\t}\n\tconst llmMessages = convertToLlm(currentMessages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tlet promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n`;\n\tif (previousSummary) {\n\t\tpromptText += `<previous-summary>\\n${previousSummary.replace(/\\n*<(read|modified)-files>[\\s\\S]*?<\\/\\1-files>/g, \"\")}\\n</previous-summary>\\n\\n`;\n\t}\n\tpromptText += basePrompt;\n\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst completionOptions =\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers };\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tcompletionOptions,\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\tconst textContent = response.content\n\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\"\\n\");\n\n\treturn ok(textContent);\n}\n\n/** Prepared inputs for a compaction run. */\nexport interface CompactionPreparation {\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Messages summarized into the history summary. */\n\tmessagesToSummarize: AgentMessage[];\n\t/** Prefix messages summarized separately when compaction splits a turn. */\n\tturnPrefixMessages: AgentMessage[];\n\t/** Whether compaction splits a turn. */\n\tisSplitTurn: boolean;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Previous compaction summary used for iterative updates. */\n\tpreviousSummary?: string;\n\t/** Settings used to prepare compaction. */\n\tsettings: CompactionSettings;\n}\n\ninterface PreviousCompactionBoundary {\n\tindex: number;\n\tstartIndex: number;\n\tsummary: string | undefined;\n}\n\nfunction findPreviousCompactionBoundary(pathEntries: SessionTreeEntry[]): PreviousCompactionBoundary {\n\tlet index = -1;\n\tfor (let entryIndex = pathEntries.length - 1; entryIndex >= 0; entryIndex--) {\n\t\tif (pathEntries[entryIndex].type !== \"compaction\") continue;\n\t\tindex = entryIndex;\n\t\tbreak;\n\t}\n\tif (index < 0) return { index, startIndex: 0, summary: undefined };\n\tconst compaction = pathEntries[index] as CompactionEntry;\n\tconst firstKeptEntryIndex = pathEntries.findIndex((entry) => entry.id === compaction.firstKeptEntryId);\n\treturn {\n\t\tindex,\n\t\tstartIndex: firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : index + 1,\n\t\tsummary: compaction.summary,\n\t};\n}\n\nfunction collectCompactionMessages(\n\tpathEntries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n): AgentMessage[] {\n\tconst messages: AgentMessage[] = [];\n\tfor (let index = startIndex; index < endIndex; index++) {\n\t\tconst message = getMessageFromEntryForCompaction(pathEntries[index]);\n\t\tif (message) messages.push(message);\n\t}\n\treturn messages;\n}\n\n/** Prepare session entries for compaction, or return undefined when compaction is not applicable. */\nexport function prepareCompaction(\n\tpathEntries: SessionTreeEntry[],\n\tsettings: CompactionSettings,\n): Result<CompactionPreparation | undefined, CompactionError> {\n\tif (pathEntries.length === 0 || pathEntries[pathEntries.length - 1].type === \"compaction\") {\n\t\treturn ok(undefined);\n\t}\n\n\tconst previousCompaction = findPreviousCompactionBoundary(pathEntries);\n\tconst previousSummary = previousCompaction.summary;\n\tconst boundaryStart = previousCompaction.startIndex;\n\tconst boundaryEnd = pathEntries.length;\n\n\tconst tokensBefore = estimateContextTokens(buildSessionContext(pathEntries).messages).tokens;\n\n\tconst cutPoint = findCutPoint(pathEntries, boundaryStart, boundaryEnd, settings.keepRecentTokens);\n\tconst firstKeptEntry = pathEntries[cutPoint.firstKeptEntryIndex];\n\tif (!firstKeptEntry?.id) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\tconst firstKeptEntryId = firstKeptEntry.id;\n\n\tconst historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;\n\tconst messagesToSummarize = collectCompactionMessages(pathEntries, boundaryStart, historyEnd);\n\tconst turnPrefixMessages = cutPoint.isSplitTurn\n\t\t? collectCompactionMessages(pathEntries, cutPoint.turnStartIndex, cutPoint.firstKeptEntryIndex)\n\t\t: [];\n\treturn ok({\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn: cutPoint.isSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t});\n}\n\nconst TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.\n\nSummarize the prefix to provide context for the retained suffix:\n\n## Original Request\n[What did the user ask for in this turn?]\n\n## Early Progress\n- [Key decisions and work done in the prefix]\n\n## Context for Suffix\n- [Information needed to understand the retained recent work]\n\nBe concise. Focus on what's needed to understand the kept suffix.`;\n\n/** Generate compaction summary data from prepared session history. */\nexport async function compact(\n\tpreparation: CompactionPreparation,\n\tmodel: Model<any>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tcustomInstructions?: string,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<CompactionResult, CompactionError>> {\n\tconst {\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t} = preparation;\n\n\tif (!firstKeptEntryId) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\n\tlet summary: string;\n\n\tif (isSplitTurn && turnPrefixMessages.length > 0) {\n\t\tconst historyResult =\n\t\t\tmessagesToSummarize.length > 0\n\t\t\t\t? await generateSummary(\n\t\t\t\t\t\tmessagesToSummarize,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tsettings.reserveTokens,\n\t\t\t\t\t\tapiKey,\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcustomInstructions,\n\t\t\t\t\t\tpreviousSummary,\n\t\t\t\t\t\tthinkingLevel,\n\t\t\t\t\t)\n\t\t\t\t: ok<string, CompactionError>(\"No prior history.\");\n\t\tif (!historyResult.ok) return err(historyResult.error);\n\t\tconst turnPrefixResult = await generateTurnPrefixSummary(\n\t\t\tturnPrefixMessages,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!turnPrefixResult.ok) return err(turnPrefixResult.error);\n\t\tsummary = `${historyResult.value}\\n\\n---\\n\\n**Turn Context (split turn):**\\n\\n${turnPrefixResult.value}`;\n\t} else {\n\t\tconst summaryResult = await generateSummary(\n\t\t\tmessagesToSummarize,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tcustomInstructions,\n\t\t\tpreviousSummary,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!summaryResult.ok) return err(summaryResult.error);\n\t\tsummary = summaryResult.value;\n\t}\n\n\treturn ok({\n\t\tsummary,\n\t\tfirstKeptEntryId,\n\t\ttokensBefore,\n\t});\n}\nasync function generateTurnPrefixSummary(\n\tmessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.5 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tconst llmMessages = convertToLlm(messages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tconst promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers },\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Turn prefix summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Turn prefix summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\treturn ok(\n\t\tresponse.content\n\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t.map((c) => c.text)\n\t\t\t.join(\"\\n\"),\n\t);\n}\n"]}
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/harness/compaction/compaction.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.js","sourceRoot":"","sources":["../../../src/harness/compaction/compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tContextUsageEstimate as AiContextUsageEstimate,\n\tAssistantMessage,\n\tAssistantUsageInfo,\n\tImageContent,\n\tModel,\n\tTextContent,\n\tToolResultMessage,\n\tUsage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport { completeSimple } from \"@greppleai/grip-ai\";\nimport type { AgentMessage, ThinkingLevel } from \"../../types.ts\";\nimport {\n\ttype BashExecutionMessage,\n\ttype BranchSummaryMessage,\n\ttype CompactionSummaryMessage,\n\ttype CustomMessage,\n\tconvertToLlm,\n\tcreateBranchSummaryMessage,\n\tcreateCompactionSummaryMessage,\n\tcreateCustomMessage,\n} from \"../messages.ts\";\nimport { buildSessionContext } from \"../session/session.ts\";\nimport { type CompactionEntry, CompactionError, err, ok, type Result, type SessionTreeEntry } from \"../types.ts\";\nimport { serializeConversation } from \"./utils.ts\";\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"message\") {\n\t\treturn entry.message as AgentMessage;\n\t}\n\tif (entry.type === \"custom_message\") {\n\t\treturn createCustomMessage(\n\t\t\tentry.customType,\n\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\tentry.display,\n\t\t\tentry.details,\n\t\t\tentry.timestamp,\n\t\t);\n\t}\n\tif (entry.type === \"branch_summary\") {\n\t\treturn createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n\t}\n\tif (entry.type === \"compaction\") {\n\t\treturn createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n\t}\n\treturn undefined;\n}\n\nfunction getMessageFromEntryForCompaction(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"compaction\") {\n\t\treturn undefined;\n\t}\n\treturn getMessageFromEntry(entry);\n}\n\n/** Generated compaction data ready to be persisted as a compaction entry. */\nexport interface CompactionResult<T = unknown> {\n\t/** Summary text that replaces compacted history in future context. */\n\tsummary: string;\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Optional implementation-specific details stored with the compaction entry. */\n\tdetails?: T;\n}\n\n/** Compaction thresholds and retention settings. */\nexport interface CompactionSettings {\n\t/** Enable automatic compaction decisions. */\n\tenabled: boolean;\n\t/** Tokens reserved for summary prompt and output. */\n\treserveTokens: number;\n\t/** Approximate recent-context tokens to keep after compaction. */\n\tkeepRecentTokens: number;\n}\n\n/** Default compaction settings used by the harness. */\nexport const DEFAULT_COMPACTION_SETTINGS: CompactionSettings = {\n\tenabled: true,\n\treserveTokens: 16384,\n\tkeepRecentTokens: 20000,\n};\n\n/** Calculate total context tokens from provider usage. */\nexport function calculateContextTokens(usage: Usage): number {\n\treturn usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction getAssistantUsage(msg: AgentMessage): Usage | undefined {\n\tif (msg.role === \"assistant\" && \"usage\" in msg) {\n\t\tconst assistantMsg = msg as AssistantMessage;\n\t\tif (assistantMsg.stopReason !== \"aborted\" && assistantMsg.stopReason !== \"error\" && assistantMsg.usage) {\n\t\t\treturn assistantMsg.usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Return usage from the last successful assistant message in session entries. */\nexport function getLastAssistantUsage(entries: SessionTreeEntry[]): Usage | undefined {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tconst usage = getAssistantUsage(entry.message as AgentMessage);\n\t\t\tif (usage) return usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Estimated context-token usage for a message list. */\nexport type ContextUsageEstimate = AiContextUsageEstimate;\n\nfunction getLastAssistantUsageInfo(messages: AgentMessage[]): AssistantUsageInfo | undefined {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst usage = getAssistantUsage(messages[i]);\n\t\tif (usage) return { usage, index: i };\n\t}\n\treturn undefined;\n}\n\n/** Estimate context tokens for messages using provider usage when available. */\nexport function estimateContextTokens(messages: AgentMessage[]): ContextUsageEstimate {\n\tconst usageInfo = getLastAssistantUsageInfo(messages);\n\n\tif (!usageInfo) {\n\t\tlet estimated = 0;\n\t\tfor (const message of messages) {\n\t\t\testimated += estimateTokens(message);\n\t\t}\n\t\treturn {\n\t\t\ttokens: estimated,\n\t\t\tusageTokens: 0,\n\t\t\ttrailingTokens: estimated,\n\t\t\tlastUsageIndex: null,\n\t\t};\n\t}\n\n\tconst usageTokens = calculateContextTokens(usageInfo.usage);\n\tlet trailingTokens = 0;\n\tfor (let i = usageInfo.index + 1; i < messages.length; i++) {\n\t\ttrailingTokens += estimateTokens(messages[i]);\n\t}\n\n\treturn {\n\t\ttokens: usageTokens + trailingTokens,\n\t\tusageTokens,\n\t\ttrailingTokens,\n\t\tlastUsageIndex: usageInfo.index,\n\t};\n}\n\n/** Return whether context usage exceeds the configured compaction threshold. */\nexport function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings): boolean {\n\tif (!settings.enabled) return false;\n\treturn contextTokens > contextWindow - settings.reserveTokens;\n}\n\nfunction estimateUserMessageTokens(message: UserMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateAssistantMessageTokens(message: AssistantMessage): number {\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\tcharacters += block.text.length;\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tcharacters += block.thinking.length;\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tcharacters += block.name.length + safeJsonStringify(block.arguments).length;\n\t\t}\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateContentMessageTokens(message: CustomMessage | ToolResultMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t\tif (block.type === \"image\") characters += 4800;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateBashExecutionTokens(message: BashExecutionMessage): number {\n\treturn Math.ceil((message.command.length + message.output.length) / 4);\n}\n\nfunction estimateSummaryTokens(message: BranchSummaryMessage | CompactionSummaryMessage): number {\n\treturn Math.ceil(message.summary.length / 4);\n}\n\n/** Estimate token count for one message using a conservative character heuristic. */\nexport function estimateTokens(message: AgentMessage): number {\n\tswitch (message.role) {\n\t\tcase \"user\":\n\t\t\treturn estimateUserMessageTokens(message);\n\t\tcase \"assistant\":\n\t\t\treturn estimateAssistantMessageTokens(message);\n\t\tcase \"custom\":\n\t\tcase \"toolResult\":\n\t\t\treturn estimateContentMessageTokens(message);\n\t\tcase \"bashExecution\":\n\t\t\treturn estimateBashExecutionTokens(message);\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\treturn estimateSummaryTokens(message);\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\nfunction findValidCutPoints(entries: SessionTreeEntry[], startIndex: number, endIndex: number): number[] {\n\tconst cutPoints: number[] = [];\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst entry = entries[i];\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\": {\n\t\t\t\tconst role = entry.message.role;\n\t\t\t\tswitch (role) {\n\t\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\tcase \"custom\":\n\t\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\tcase \"user\":\n\t\t\t\t\tcase \"assistant\":\n\t\t\t\t\t\tcutPoints.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"toolResult\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking_level_change\":\n\t\t\tcase \"model_change\":\n\t\t\tcase \"compaction\":\n\t\t\tcase \"branch_summary\":\n\t\t\tcase \"custom\":\n\t\t\tcase \"custom_message\":\n\t\t\tcase \"label\":\n\t\t\tcase \"session_info\":\n\t\t\tcase \"leaf\":\n\t\t\t\tbreak;\n\t\t}\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\tcutPoints.push(i);\n\t\t}\n\t}\n\treturn cutPoints;\n}\n\n/** Find the user-visible message that starts the turn containing an entry. */\nexport function findTurnStartIndex(entries: SessionTreeEntry[], entryIndex: number, startIndex: number): number {\n\tfor (let i = entryIndex; i >= startIndex; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\treturn i;\n\t\t}\n\t\tif (entry.type === \"message\") {\n\t\t\tconst role = entry.message.role;\n\t\t\tif (role === \"user\" || role === \"bashExecution\") {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\n/** Cut point selected for compaction. */\nexport interface CutPointResult {\n\t/** Index of the first entry retained after compaction. */\n\tfirstKeptEntryIndex: number;\n\t/** Index of the turn-start entry when the cut splits a turn, otherwise -1. */\n\tturnStartIndex: number;\n\t/** Whether the selected cut point splits an in-progress turn. */\n\tisSplitTurn: boolean;\n}\n\nfunction selectTokenBudgetCutIndex(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n\tcutPoints: number[],\n): number {\n\tconst defaultCutIndex = cutPoints[0]!;\n\tlet accumulatedTokens = 0;\n\tlet budgetIndex = -1;\n\tfor (let index = endIndex - 1; index >= startIndex; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"message\") continue;\n\t\taccumulatedTokens += estimateTokens(entry.message as AgentMessage);\n\t\tif (accumulatedTokens < keepRecentTokens) continue;\n\t\tbudgetIndex = index;\n\t\tbreak;\n\t}\n\tif (budgetIndex === -1) return defaultCutIndex;\n\treturn cutPoints.find((cutPoint) => cutPoint >= budgetIndex) ?? defaultCutIndex;\n}\n\nfunction moveCutIndexBeforeMetadata(entries: SessionTreeEntry[], cutIndex: number, startIndex: number): number {\n\twhile (cutIndex > startIndex) {\n\t\tconst previousEntry = entries[cutIndex - 1];\n\t\tif (previousEntry.type === \"compaction\" || previousEntry.type === \"message\") return cutIndex;\n\t\tcutIndex--;\n\t}\n\treturn cutIndex;\n}\n\n/** Find the compaction cut point that keeps approximately the requested recent-token budget. */\nexport function findCutPoint(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n): CutPointResult {\n\tconst cutPoints = findValidCutPoints(entries, startIndex, endIndex);\n\tif (cutPoints.length === 0) {\n\t\treturn { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };\n\t}\n\n\tconst selectedCutIndex = selectTokenBudgetCutIndex(entries, startIndex, endIndex, keepRecentTokens, cutPoints);\n\tconst cutIndex = moveCutIndexBeforeMetadata(entries, selectedCutIndex, startIndex);\n\tconst cutEntry = entries[cutIndex];\n\tconst isUserMessage = cutEntry.type === \"message\" && cutEntry.message.role === \"user\";\n\tconst turnStartIndex = isUserMessage ? -1 : findTurnStartIndex(entries, cutIndex, startIndex);\n\treturn {\n\t\tfirstKeptEntryIndex: cutIndex,\n\t\tturnStartIndex,\n\t\tisSplitTurn: !isUserMessage && turnStartIndex !== -1,\n\t};\n}\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n\nconst SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.\n\nUse this EXACT format:\n\n## Goal\n[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned by user]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Current work]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [Ordered list of what should happen next]\n\n## Critical Context\n- [Any data, examples, or references needed to continue]\n- [Or \"(none)\" if not applicable]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\nconst UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.\n\nUpdate the existing structured summary with new information. RULES:\n- PRESERVE all existing information from the previous summary\n- ADD new progress, decisions, and context from the new messages\n- UPDATE the Progress section: move items from \"In Progress\" to \"Done\" when completed\n- UPDATE \"Next Steps\" based on what was accomplished\n- PRESERVE exact file paths, function names, and error messages\n- If something is no longer relevant, you may remove it\n\nUse this EXACT format:\n\n## Goal\n[Preserve existing goals, add new ones if the task expanded]\n\n## Constraints & Preferences\n- [Preserve existing, add new ones discovered]\n\n## Progress\n### Done\n- [x] [Include previously done items AND newly completed items]\n\n### In Progress\n- [ ] [Current work - update based on progress]\n\n### Blocked\n- [Current blockers - remove if resolved]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale] (preserve all previous, add new)\n\n## Next Steps\n1. [Update based on current state]\n\n## Critical Context\n- [Preserve important context, add new if needed]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\n/** Generate or update a conversation summary for compaction. */\nexport async function generateSummary(\n\tcurrentMessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tcustomInstructions?: string,\n\tpreviousSummary?: string,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.8 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tlet basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;\n\tif (customInstructions) {\n\t\tbasePrompt = `${basePrompt}\\n\\nAdditional focus: ${customInstructions}`;\n\t}\n\tconst llmMessages = convertToLlm(currentMessages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tlet promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n`;\n\tif (previousSummary) {\n\t\tpromptText += `<previous-summary>\\n${previousSummary.replace(/\\n*<(read|modified)-files>[\\s\\S]*?<\\/\\1-files>/g, \"\")}\\n</previous-summary>\\n\\n`;\n\t}\n\tpromptText += basePrompt;\n\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst completionOptions =\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers };\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tcompletionOptions,\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\tconst textContent = response.content\n\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\"\\n\");\n\n\treturn ok(textContent);\n}\n\n/** Prepared inputs for a compaction run. */\nexport interface CompactionPreparation {\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Messages summarized into the history summary. */\n\tmessagesToSummarize: AgentMessage[];\n\t/** Prefix messages summarized separately when compaction splits a turn. */\n\tturnPrefixMessages: AgentMessage[];\n\t/** Whether compaction splits a turn. */\n\tisSplitTurn: boolean;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Previous compaction summary used for iterative updates. */\n\tpreviousSummary?: string;\n\t/** Settings used to prepare compaction. */\n\tsettings: CompactionSettings;\n}\n\ninterface PreviousCompactionBoundary {\n\tindex: number;\n\tstartIndex: number;\n\tsummary: string | undefined;\n}\n\nfunction findPreviousCompactionBoundary(pathEntries: SessionTreeEntry[]): PreviousCompactionBoundary {\n\tlet index = -1;\n\tfor (let entryIndex = pathEntries.length - 1; entryIndex >= 0; entryIndex--) {\n\t\tif (pathEntries[entryIndex].type !== \"compaction\") continue;\n\t\tindex = entryIndex;\n\t\tbreak;\n\t}\n\tif (index < 0) return { index, startIndex: 0, summary: undefined };\n\tconst compaction = pathEntries[index] as CompactionEntry;\n\tconst firstKeptEntryIndex = pathEntries.findIndex((entry) => entry.id === compaction.firstKeptEntryId);\n\treturn {\n\t\tindex,\n\t\tstartIndex: firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : index + 1,\n\t\tsummary: compaction.summary,\n\t};\n}\n\nfunction collectCompactionMessages(\n\tpathEntries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n): AgentMessage[] {\n\tconst messages: AgentMessage[] = [];\n\tfor (let index = startIndex; index < endIndex; index++) {\n\t\tconst message = getMessageFromEntryForCompaction(pathEntries[index]);\n\t\tif (message) messages.push(message);\n\t}\n\treturn messages;\n}\n\n/** Prepare session entries for compaction, or return undefined when compaction is not applicable. */\nexport function prepareCompaction(\n\tpathEntries: SessionTreeEntry[],\n\tsettings: CompactionSettings,\n): Result<CompactionPreparation | undefined, CompactionError> {\n\tif (pathEntries.length === 0 || pathEntries[pathEntries.length - 1].type === \"compaction\") {\n\t\treturn ok(undefined);\n\t}\n\n\tconst previousCompaction = findPreviousCompactionBoundary(pathEntries);\n\tconst previousSummary = previousCompaction.summary;\n\tconst boundaryStart = previousCompaction.startIndex;\n\tconst boundaryEnd = pathEntries.length;\n\n\tconst tokensBefore = estimateContextTokens(buildSessionContext(pathEntries).messages).tokens;\n\n\tconst cutPoint = findCutPoint(pathEntries, boundaryStart, boundaryEnd, settings.keepRecentTokens);\n\tconst firstKeptEntry = pathEntries[cutPoint.firstKeptEntryIndex];\n\tif (!firstKeptEntry?.id) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\tconst firstKeptEntryId = firstKeptEntry.id;\n\n\tconst historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;\n\tconst messagesToSummarize = collectCompactionMessages(pathEntries, boundaryStart, historyEnd);\n\tconst turnPrefixMessages = cutPoint.isSplitTurn\n\t\t? collectCompactionMessages(pathEntries, cutPoint.turnStartIndex, cutPoint.firstKeptEntryIndex)\n\t\t: [];\n\treturn ok({\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn: cutPoint.isSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t});\n}\n\nconst TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.\n\nSummarize the prefix to provide context for the retained suffix:\n\n## Original Request\n[What did the user ask for in this turn?]\n\n## Early Progress\n- [Key decisions and work done in the prefix]\n\n## Context for Suffix\n- [Information needed to understand the retained recent work]\n\nBe concise. Focus on what's needed to understand the kept suffix.`;\n\n/** Generate compaction summary data from prepared session history. */\nexport async function compact(\n\tpreparation: CompactionPreparation,\n\tmodel: Model<any>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tcustomInstructions?: string,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<CompactionResult, CompactionError>> {\n\tconst {\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t} = preparation;\n\n\tif (!firstKeptEntryId) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\n\tlet summary: string;\n\n\tif (isSplitTurn && turnPrefixMessages.length > 0) {\n\t\tconst historyResult =\n\t\t\tmessagesToSummarize.length > 0\n\t\t\t\t? await generateSummary(\n\t\t\t\t\t\tmessagesToSummarize,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tsettings.reserveTokens,\n\t\t\t\t\t\tapiKey,\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcustomInstructions,\n\t\t\t\t\t\tpreviousSummary,\n\t\t\t\t\t\tthinkingLevel,\n\t\t\t\t\t)\n\t\t\t\t: ok<string, CompactionError>(\"No prior history.\");\n\t\tif (!historyResult.ok) return err(historyResult.error);\n\t\tconst turnPrefixResult = await generateTurnPrefixSummary(\n\t\t\tturnPrefixMessages,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!turnPrefixResult.ok) return err(turnPrefixResult.error);\n\t\tsummary = `${historyResult.value}\\n\\n---\\n\\n**Turn Context (split turn):**\\n\\n${turnPrefixResult.value}`;\n\t} else {\n\t\tconst summaryResult = await generateSummary(\n\t\t\tmessagesToSummarize,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tcustomInstructions,\n\t\t\tpreviousSummary,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!summaryResult.ok) return err(summaryResult.error);\n\t\tsummary = summaryResult.value;\n\t}\n\n\treturn ok({\n\t\tsummary,\n\t\tfirstKeptEntryId,\n\t\ttokensBefore,\n\t});\n}\nasync function generateTurnPrefixSummary(\n\tmessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.5 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tconst llmMessages = convertToLlm(messages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tconst promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers },\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Turn prefix summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Turn prefix summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\treturn ok(\n\t\tresponse.content\n\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t.map((c) => c.text)\n\t\t\t.join(\"\\n\"),\n\t);\n}\n"]}
1
+ {"version":3,"file":"compaction.js","sourceRoot":"","sources":["../../../src/harness/compaction/compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tContextUsageEstimate as AiContextUsageEstimate,\n\tAssistantMessage,\n\tAssistantUsageInfo,\n\tImageContent,\n\tModel,\n\tTextContent,\n\tToolResultMessage,\n\tUsage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport { completeSimple } from \"@greppleai/grip-ai\";\nimport type { AgentMessage, ThinkingLevel } from \"../../types.ts\";\nimport {\n\ttype BashExecutionMessage,\n\ttype BranchSummaryMessage,\n\ttype CompactionSummaryMessage,\n\ttype CustomMessage,\n\tconvertToLlm,\n\tcreateBranchSummaryMessage,\n\tcreateCompactionSummaryMessage,\n\tcreateCustomMessage,\n} from \"../messages.ts\";\nimport { buildSessionContext } from \"../session/session.ts\";\nimport { type CompactionEntry, CompactionError, err, ok, type Result, type SessionTreeEntry } from \"../types.ts\";\nimport { serializeConversation } from \"./utils.ts\";\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction getMessageFromEntry(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"message\") {\n\t\treturn entry.message as AgentMessage;\n\t}\n\tif (entry.type === \"custom_message\") {\n\t\treturn createCustomMessage(\n\t\t\tentry.customType,\n\t\t\tentry.content as string | (TextContent | ImageContent)[],\n\t\t\tentry.display,\n\t\t\tentry.details,\n\t\t\tentry.timestamp,\n\t\t);\n\t}\n\tif (entry.type === \"branch_summary\") {\n\t\treturn createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp);\n\t}\n\tif (entry.type === \"compaction\") {\n\t\treturn createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp);\n\t}\n\treturn undefined;\n}\n\nfunction getMessageFromEntryForCompaction(entry: SessionTreeEntry): AgentMessage | undefined {\n\tif (entry.type === \"compaction\") {\n\t\treturn undefined;\n\t}\n\treturn getMessageFromEntry(entry);\n}\n\n/** Generated compaction data ready to be persisted as a compaction entry. */\nexport interface CompactionResult<T = unknown> {\n\t/** Summary text that replaces compacted history in future context. */\n\tsummary: string;\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Optional implementation-specific details stored with the compaction entry. */\n\tdetails?: T;\n}\n\n/** Compaction thresholds and retention settings. */\nexport interface CompactionSettings {\n\t/** Enable automatic compaction decisions. */\n\tenabled: boolean;\n\t/** Tokens reserved for summary prompt and output. */\n\treserveTokens: number;\n\t/** Approximate recent-context tokens to keep after compaction. */\n\tkeepRecentTokens: number;\n}\n\n/** Default compaction settings used by the harness. */\nexport const DEFAULT_COMPACTION_SETTINGS: CompactionSettings = {\n\tenabled: true,\n\treserveTokens: 16384,\n\tkeepRecentTokens: 20000,\n};\n\n/** Calculate total context tokens from provider usage. */\nexport function calculateContextTokens(usage: Usage): number {\n\treturn usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n}\nfunction getAssistantUsage(msg: AgentMessage): Usage | undefined {\n\tif (msg.role === \"assistant\" && \"usage\" in msg) {\n\t\tconst assistantMsg = msg as AssistantMessage;\n\t\tif (assistantMsg.stopReason !== \"aborted\" && assistantMsg.stopReason !== \"error\" && assistantMsg.usage) {\n\t\t\treturn assistantMsg.usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Return usage from the last successful assistant message in session entries. */\nexport function getLastAssistantUsage(entries: SessionTreeEntry[]): Usage | undefined {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"message\") {\n\t\t\tconst usage = getAssistantUsage(entry.message as AgentMessage);\n\t\t\tif (usage) return usage;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Estimated context-token usage for a message list. */\nexport type ContextUsageEstimate = AiContextUsageEstimate;\n\nfunction getLastAssistantUsageInfo(messages: AgentMessage[]): AssistantUsageInfo | undefined {\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst usage = getAssistantUsage(messages[i]);\n\t\tif (usage) return { usage, index: i };\n\t}\n\treturn undefined;\n}\n\n/** Estimate context tokens for messages using provider usage when available. */\nexport function estimateContextTokens(messages: AgentMessage[]): ContextUsageEstimate {\n\tconst usageInfo = getLastAssistantUsageInfo(messages);\n\n\tif (!usageInfo) {\n\t\tlet estimated = 0;\n\t\tfor (const message of messages) {\n\t\t\testimated += estimateTokens(message);\n\t\t}\n\t\treturn {\n\t\t\ttokens: estimated,\n\t\t\tusageTokens: 0,\n\t\t\ttrailingTokens: estimated,\n\t\t\tlastUsageIndex: null,\n\t\t};\n\t}\n\n\tconst usageTokens = calculateContextTokens(usageInfo.usage);\n\tlet trailingTokens = 0;\n\tfor (let i = usageInfo.index + 1; i < messages.length; i++) {\n\t\ttrailingTokens += estimateTokens(messages[i]);\n\t}\n\n\treturn {\n\t\ttokens: usageTokens + trailingTokens,\n\t\tusageTokens,\n\t\ttrailingTokens,\n\t\tlastUsageIndex: usageInfo.index,\n\t};\n}\n\n/** Return whether context usage exceeds the configured compaction threshold. */\nexport function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings): boolean {\n\tif (!settings.enabled) return false;\n\treturn contextTokens > contextWindow - settings.reserveTokens;\n}\n\nfunction estimateUserMessageTokens(message: UserMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateAssistantMessageTokens(message: AssistantMessage): number {\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\tcharacters += block.text.length;\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tcharacters += block.thinking.length;\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tcharacters += block.name.length + safeJsonStringify(block.arguments).length;\n\t\t}\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateContentMessageTokens(message: CustomMessage | ToolResultMessage): number {\n\tif (typeof message.content === \"string\") return Math.ceil(message.content.length / 4);\n\tlet characters = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\" && block.text) characters += block.text.length;\n\t\tif (block.type === \"image\") characters += 4800;\n\t}\n\treturn Math.ceil(characters / 4);\n}\n\nfunction estimateBashExecutionTokens(message: BashExecutionMessage): number {\n\treturn Math.ceil((message.command.length + message.output.length) / 4);\n}\n\nfunction estimateSummaryTokens(message: BranchSummaryMessage | CompactionSummaryMessage): number {\n\treturn Math.ceil(message.summary.length / 4);\n}\n\n/** Estimate token count for one message using a conservative character heuristic. */\nexport function estimateTokens(message: AgentMessage): number {\n\tswitch (message.role) {\n\t\tcase \"user\":\n\t\t\treturn estimateUserMessageTokens(message);\n\t\tcase \"assistant\":\n\t\t\treturn estimateAssistantMessageTokens(message);\n\t\tcase \"custom\":\n\t\tcase \"toolResult\":\n\t\t\treturn estimateContentMessageTokens(message);\n\t\tcase \"bashExecution\":\n\t\t\treturn estimateBashExecutionTokens(message);\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\treturn estimateSummaryTokens(message);\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n}\nfunction findValidCutPoints(entries: SessionTreeEntry[], startIndex: number, endIndex: number): number[] {\n\tconst cutPoints: number[] = [];\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst entry = entries[i];\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\": {\n\t\t\t\tconst role = entry.message.role;\n\t\t\t\tswitch (role) {\n\t\t\t\t\tcase \"bashExecution\":\n\t\t\t\t\tcase \"custom\":\n\t\t\t\t\tcase \"branchSummary\":\n\t\t\t\t\tcase \"compactionSummary\":\n\t\t\t\t\tcase \"user\":\n\t\t\t\t\tcase \"assistant\":\n\t\t\t\t\t\tcutPoints.push(i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"toolResult\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking_level_change\":\n\t\t\tcase \"model_change\":\n\t\t\tcase \"compaction\":\n\t\t\tcase \"branch_summary\":\n\t\t\tcase \"custom\":\n\t\t\tcase \"custom_message\":\n\t\t\tcase \"label\":\n\t\t\tcase \"session_info\":\n\t\t\tcase \"leaf\":\n\t\t\t\tbreak;\n\t\t}\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\tcutPoints.push(i);\n\t\t}\n\t}\n\treturn cutPoints;\n}\n\n/** Find the user-visible message that starts the turn containing an entry. */\nexport function findTurnStartIndex(entries: SessionTreeEntry[], entryIndex: number, startIndex: number): number {\n\tfor (let i = entryIndex; i >= startIndex; i--) {\n\t\tconst entry = entries[i];\n\t\tif (entry.type === \"branch_summary\" || entry.type === \"custom_message\") {\n\t\t\treturn i;\n\t\t}\n\t\tif (entry.type === \"message\") {\n\t\t\tconst role = entry.message.role;\n\t\t\tif (role === \"user\" || role === \"bashExecution\") {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\n/** Cut point selected for compaction. */\nexport interface CutPointResult {\n\t/** Index of the first entry retained after compaction. */\n\tfirstKeptEntryIndex: number;\n\t/** Index of the turn-start entry when the cut splits a turn, otherwise -1. */\n\tturnStartIndex: number;\n\t/** Whether the selected cut point splits an in-progress turn. */\n\tisSplitTurn: boolean;\n}\n\nfunction selectTokenBudgetCutIndex(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n\tcutPoints: number[],\n): number {\n\tconst defaultCutIndex = cutPoints[0]!;\n\tlet accumulatedTokens = 0;\n\tlet budgetIndex = -1;\n\tfor (let index = endIndex - 1; index >= startIndex; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"message\") continue;\n\t\taccumulatedTokens += estimateTokens(entry.message as AgentMessage);\n\t\tif (accumulatedTokens < keepRecentTokens) continue;\n\t\tbudgetIndex = index;\n\t\tbreak;\n\t}\n\tif (budgetIndex === -1) return defaultCutIndex;\n\treturn cutPoints.find((cutPoint) => cutPoint >= budgetIndex) ?? defaultCutIndex;\n}\n\nfunction moveCutIndexBeforeMetadata(entries: SessionTreeEntry[], cutIndex: number, startIndex: number): number {\n\twhile (cutIndex > startIndex) {\n\t\tconst previousEntry = entries[cutIndex - 1];\n\t\tif (previousEntry.type === \"compaction\" || previousEntry.type === \"message\") return cutIndex;\n\t\tcutIndex--;\n\t}\n\treturn cutIndex;\n}\n\n/** Find the compaction cut point that keeps approximately the requested recent-token budget. */\nexport function findCutPoint(\n\tentries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n\tkeepRecentTokens: number,\n): CutPointResult {\n\tconst cutPoints = findValidCutPoints(entries, startIndex, endIndex);\n\tif (cutPoints.length === 0) {\n\t\treturn { firstKeptEntryIndex: startIndex, turnStartIndex: -1, isSplitTurn: false };\n\t}\n\n\tconst selectedCutIndex = selectTokenBudgetCutIndex(entries, startIndex, endIndex, keepRecentTokens, cutPoints);\n\tconst cutIndex = moveCutIndexBeforeMetadata(entries, selectedCutIndex, startIndex);\n\tconst cutEntry = entries[cutIndex];\n\tconst isUserMessage = cutEntry.type === \"message\" && cutEntry.message.role === \"user\";\n\tconst turnStartIndex = isUserMessage ? -1 : findTurnStartIndex(entries, cutIndex, startIndex);\n\treturn {\n\t\tfirstKeptEntryIndex: cutIndex,\n\t\tturnStartIndex,\n\t\tisSplitTurn: !isUserMessage && turnStartIndex !== -1,\n\t};\n}\n\nexport const SUMMARIZATION_SYSTEM_PROMPT = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;\n\nconst SUMMARIZATION_PROMPT = `The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.\n\nUse this EXACT format:\n\n## Goal\n[What is the user trying to accomplish? Can be multiple items if the session covers different tasks.]\n\n## Constraints & Preferences\n- [Any constraints, preferences, or requirements mentioned by user]\n- [Or \"(none)\" if none were mentioned]\n\n## Progress\n### Done\n- [x] [Completed tasks/changes]\n\n### In Progress\n- [ ] [Current work]\n\n### Blocked\n- [Issues preventing progress, if any]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale]\n\n## Next Steps\n1. [Ordered list of what should happen next]\n\n## Critical Context\n- [Any data, examples, or references needed to continue]\n- [Or \"(none)\" if not applicable]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\nconst UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.\n\nUpdate the existing structured summary with new information. RULES:\n- PRESERVE all existing information from the previous summary\n- ADD new progress, decisions, and context from the new messages\n- UPDATE the Progress section: move items from \"In Progress\" to \"Done\" when completed\n- UPDATE \"Next Steps\" based on what was accomplished\n- PRESERVE exact file paths, function names, and error messages\n- If something is no longer relevant, you may remove it\n\nUse this EXACT format:\n\n## Goal\n[Preserve existing goals, add new ones if the task expanded]\n\n## Constraints & Preferences\n- [Preserve existing, add new ones discovered]\n\n## Progress\n### Done\n- [x] [Include previously done items AND newly completed items]\n\n### In Progress\n- [ ] [Current work - update based on progress]\n\n### Blocked\n- [Current blockers - remove if resolved]\n\n## Key Decisions\n- **[Decision]**: [Brief rationale] (preserve all previous, add new)\n\n## Next Steps\n1. [Update based on current state]\n\n## Critical Context\n- [Preserve important context, add new if needed]\n\nKeep each section concise. Preserve exact file paths, function names, and error messages.`;\n\n/** Generate or update a conversation summary for compaction. */\nexport async function generateSummary(\n\tcurrentMessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tcustomInstructions?: string,\n\tpreviousSummary?: string,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.8 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tlet basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;\n\tif (customInstructions) {\n\t\tbasePrompt = `${basePrompt}\\n\\nAdditional focus: ${customInstructions}`;\n\t}\n\tconst llmMessages = convertToLlm(currentMessages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tlet promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n`;\n\tif (previousSummary) {\n\t\tpromptText += `<previous-summary>\\n${previousSummary.replace(/\\n*<(read|modified)-files>[\\s\\S]*?<\\/\\1-files>/g, \"\")}\\n</previous-summary>\\n\\n`;\n\t}\n\tpromptText += basePrompt;\n\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst completionOptions =\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers };\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tcompletionOptions,\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\tconst textContent = response.content\n\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t.map((c) => c.text)\n\t\t.join(\"\\n\");\n\n\treturn ok(textContent);\n}\n\n/** Prepared inputs for a compaction run. */\nexport interface CompactionPreparation {\n\t/** Entry id where retained history starts. */\n\tfirstKeptEntryId: string;\n\t/** Messages summarized into the history summary. */\n\tmessagesToSummarize: AgentMessage[];\n\t/** Prefix messages summarized separately when compaction splits a turn. */\n\tturnPrefixMessages: AgentMessage[];\n\t/** Whether compaction splits a turn. */\n\tisSplitTurn: boolean;\n\t/** Estimated context tokens before compaction. */\n\ttokensBefore: number;\n\t/** Previous compaction summary used for iterative updates. */\n\tpreviousSummary?: string;\n\t/** Settings used to prepare compaction. */\n\tsettings: CompactionSettings;\n}\n\ninterface PreviousCompactionBoundary {\n\tindex: number;\n\tstartIndex: number;\n\tsummary: string | undefined;\n}\n\nfunction findPreviousCompactionBoundary(pathEntries: SessionTreeEntry[]): PreviousCompactionBoundary {\n\tlet index = -1;\n\tfor (let entryIndex = pathEntries.length - 1; entryIndex >= 0; entryIndex--) {\n\t\tif (pathEntries[entryIndex].type !== \"compaction\") continue;\n\t\tindex = entryIndex;\n\t\tbreak;\n\t}\n\tif (index < 0) return { index, startIndex: 0, summary: undefined };\n\tconst compaction = pathEntries[index] as CompactionEntry;\n\tconst firstKeptEntryIndex = pathEntries.findIndex((entry) => entry.id === compaction.firstKeptEntryId);\n\treturn {\n\t\tindex,\n\t\tstartIndex: firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : index + 1,\n\t\tsummary: compaction.summary,\n\t};\n}\n\nfunction collectCompactionMessages(\n\tpathEntries: SessionTreeEntry[],\n\tstartIndex: number,\n\tendIndex: number,\n): AgentMessage[] {\n\tconst messages: AgentMessage[] = [];\n\tfor (let index = startIndex; index < endIndex; index++) {\n\t\tconst message = getMessageFromEntryForCompaction(pathEntries[index]);\n\t\tif (message) messages.push(message);\n\t}\n\treturn messages;\n}\n\n/** Prepare session entries for compaction, or return undefined when compaction is not applicable. */\nexport function prepareCompaction(\n\tpathEntries: SessionTreeEntry[],\n\tsettings: CompactionSettings,\n): Result<CompactionPreparation | undefined, CompactionError> {\n\tif (pathEntries.length === 0 || pathEntries[pathEntries.length - 1].type === \"compaction\") {\n\t\treturn ok(undefined);\n\t}\n\n\tconst previousCompaction = findPreviousCompactionBoundary(pathEntries);\n\tconst previousSummary = previousCompaction.summary;\n\tconst boundaryStart = previousCompaction.startIndex;\n\tconst boundaryEnd = pathEntries.length;\n\n\tconst tokensBefore = estimateContextTokens(buildSessionContext(pathEntries).messages).tokens;\n\n\tconst cutPoint = findCutPoint(pathEntries, boundaryStart, boundaryEnd, settings.keepRecentTokens);\n\tconst firstKeptEntry = pathEntries[cutPoint.firstKeptEntryIndex];\n\tif (!firstKeptEntry?.id) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\tconst firstKeptEntryId = firstKeptEntry.id;\n\n\tconst historyEnd = cutPoint.isSplitTurn ? cutPoint.turnStartIndex : cutPoint.firstKeptEntryIndex;\n\tconst messagesToSummarize = collectCompactionMessages(pathEntries, boundaryStart, historyEnd);\n\tconst turnPrefixMessages = cutPoint.isSplitTurn\n\t\t? collectCompactionMessages(pathEntries, cutPoint.turnStartIndex, cutPoint.firstKeptEntryIndex)\n\t\t: [];\n\treturn ok({\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn: cutPoint.isSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t});\n}\n\nconst TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained.\n\nSummarize the prefix to provide context for the retained suffix:\n\n## Original Request\n[What did the user ask for in this turn?]\n\n## Early Progress\n- [Key decisions and work done in the prefix]\n\n## Context for Suffix\n- [Information needed to understand the retained recent work]\n\nBe concise. Focus on what's needed to understand the kept suffix.`;\n\n/** Generate compaction summary data from prepared session history. */\nexport async function compact(\n\tpreparation: CompactionPreparation,\n\tmodel: Model<any>,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tcustomInstructions?: string,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<CompactionResult, CompactionError>> {\n\tconst {\n\t\tfirstKeptEntryId,\n\t\tmessagesToSummarize,\n\t\tturnPrefixMessages,\n\t\tisSplitTurn,\n\t\ttokensBefore,\n\t\tpreviousSummary,\n\t\tsettings,\n\t} = preparation;\n\n\tif (!firstKeptEntryId) {\n\t\treturn err(new CompactionError(\"invalid_session\", \"First kept entry has no UUID - session may need migration\"));\n\t}\n\n\tlet summary: string;\n\n\tif (isSplitTurn && turnPrefixMessages.length > 0) {\n\t\tconst historyResult =\n\t\t\tmessagesToSummarize.length > 0\n\t\t\t\t? await generateSummary(\n\t\t\t\t\t\tmessagesToSummarize,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tsettings.reserveTokens,\n\t\t\t\t\t\tapiKey,\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcustomInstructions,\n\t\t\t\t\t\tpreviousSummary,\n\t\t\t\t\t\tthinkingLevel,\n\t\t\t\t\t)\n\t\t\t\t: ok<string, CompactionError>(\"No prior history.\");\n\t\tif (!historyResult.ok) return err(historyResult.error);\n\t\tconst turnPrefixResult = await generateTurnPrefixSummary(\n\t\t\tturnPrefixMessages,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!turnPrefixResult.ok) return err(turnPrefixResult.error);\n\t\tsummary = `${historyResult.value}\\n\\n---\\n\\n**Turn Context (split turn):**\\n\\n${turnPrefixResult.value}`;\n\t} else {\n\t\tconst summaryResult = await generateSummary(\n\t\t\tmessagesToSummarize,\n\t\t\tmodel,\n\t\t\tsettings.reserveTokens,\n\t\t\tapiKey,\n\t\t\theaders,\n\t\t\tsignal,\n\t\t\tcustomInstructions,\n\t\t\tpreviousSummary,\n\t\t\tthinkingLevel,\n\t\t);\n\t\tif (!summaryResult.ok) return err(summaryResult.error);\n\t\tsummary = summaryResult.value;\n\t}\n\n\treturn ok({\n\t\tsummary,\n\t\tfirstKeptEntryId,\n\t\ttokensBefore,\n\t});\n}\nasync function generateTurnPrefixSummary(\n\tmessages: AgentMessage[],\n\tmodel: Model<any>,\n\treserveTokens: number,\n\tapiKey: string,\n\theaders?: Record<string, string>,\n\tsignal?: AbortSignal,\n\tthinkingLevel?: ThinkingLevel,\n): Promise<Result<string, CompactionError>> {\n\tconst maxTokens = Math.min(\n\t\tMath.floor(0.5 * reserveTokens),\n\t\tmodel.maxTokens > 0 ? model.maxTokens : Number.POSITIVE_INFINITY,\n\t);\n\tconst llmMessages = convertToLlm(messages);\n\tconst conversationText = serializeConversation(llmMessages);\n\tconst promptText = `<conversation>\\n${conversationText}\\n</conversation>\\n\\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`;\n\tconst summarizationMessages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [{ type: \"text\" as const, text: promptText }],\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t];\n\n\tconst response = await completeSimple(\n\t\tmodel,\n\t\t{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },\n\t\tmodel.reasoning && thinkingLevel && thinkingLevel !== \"off\"\n\t\t\t? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }\n\t\t\t: { maxTokens, signal, apiKey, headers },\n\t);\n\tif (response.stopReason === \"aborted\") {\n\t\treturn err(new CompactionError(\"aborted\", response.errorMessage || \"Turn prefix summarization aborted\"));\n\t}\n\tif (response.stopReason === \"error\") {\n\t\treturn err(\n\t\t\tnew CompactionError(\n\t\t\t\t\"summarization_failed\",\n\t\t\t\t`Turn prefix summarization failed: ${response.errorMessage || \"Unknown error\"}`,\n\t\t\t),\n\t\t);\n\t}\n\n\treturn ok(\n\t\tresponse.content\n\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t.map((c) => c.text)\n\t\t\t.join(\"\\n\"),\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/harness/compaction/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,OAAO,EAIP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC9B,+CAA+C;IAC/C,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,mDAAmD;IACnD,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,yCAAyC;IACzC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,kDAAkD;AAClD,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAyCD,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAO9F;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAK5E;AAED,kDAAkD;AAClD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;AA4DD,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAgBjE","sourcesContent":["import type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tTextContent,\n\tToolResultMessage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\n\n/** File paths touched by a session branch or compaction range. */\nexport interface FileOperations {\n\t/** Files read but not necessarily modified. */\n\tread: Set<string>;\n\t/** Files written by full-file write operations. */\n\twritten: Set<string>;\n\t/** Files modified by edit operations. */\n\tedited: Set<string>;\n}\n\nexport interface FileOperationLists {\n\treadFiles: string[];\n\tmodifiedFiles: string[];\n}\n\n/** Create an empty file-operation accumulator. */\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\ntype FileOperationType = \"read\" | \"write\" | \"edit\";\n\ninterface ExtractedFileOperation {\n\ttype: FileOperationType;\n\tpath: string;\n}\n\nfunction parseFileOperation(block: unknown): ExtractedFileOperation | undefined {\n\tif (typeof block !== \"object\" || block === null) return undefined;\n\tif (!(\"type\" in block) || block.type !== \"toolCall\") return undefined;\n\tif (!(\"arguments\" in block) || !(\"name\" in block)) return undefined;\n\tconst args = block.arguments as Record<string, unknown> | undefined;\n\tif (!args) return undefined;\n\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\tif (!path) return undefined;\n\tswitch (block.name) {\n\t\tcase \"read\":\n\t\tcase \"write\":\n\t\tcase \"edit\":\n\t\t\treturn { type: block.name, path };\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction recordFileOperation(operation: ExtractedFileOperation, fileOps: FileOperations): void {\n\tswitch (operation.type) {\n\t\tcase \"read\":\n\t\t\tfileOps.read.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"write\":\n\t\t\tfileOps.written.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"edit\":\n\t\t\tfileOps.edited.add(operation.path);\n\t\t\tbreak;\n\t}\n}\n\n/** Add file operations from assistant tool calls to an accumulator. */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\tfor (const block of message.content) {\n\t\tconst operation = parseFileOperation(block);\n\t\tif (operation) recordFileOperation(operation, fileOps);\n\t}\n}\n\n/** Compute sorted read-only and modified file lists from accumulated operations. */\nexport function computeFileLists(fileOps: FileOperations): FileOperationLists {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/** Format file lists as summary metadata tags. */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\nfunction joinTextBlocks(content: readonly (TextContent | ImageContent)[]): string {\n\tlet text = \"\";\n\tfor (const block of content) {\n\t\tif (block.type === \"text\") text += block.text;\n\t}\n\treturn text;\n}\n\nfunction serializeUserMessage(message: UserMessage): string[] {\n\tconst content = typeof message.content === \"string\" ? message.content : joinTextBlocks(message.content);\n\treturn content ? [`[User]: ${content}`] : [];\n}\n\nfunction serializeAssistantMessage(message: AssistantMessage): string[] {\n\tconst textParts: string[] = [];\n\tconst thinkingParts: string[] = [];\n\tconst toolCalls: string[] = [];\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\ttextParts.push(block.text);\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tthinkingParts.push(block.thinking);\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\tconst argsText = Object.entries(args)\n\t\t\t\t.map(([key, value]) => `${key}=${safeJsonStringify(value)}`)\n\t\t\t\t.join(\", \");\n\t\t\ttoolCalls.push(`${block.name}(${argsText})`);\n\t\t}\n\t}\n\tconst parts: string[] = [];\n\tif (thinkingParts.length > 0) parts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\tif (textParts.length > 0) parts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\tif (toolCalls.length > 0) parts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n\treturn parts;\n}\n\nfunction serializeToolResultMessage(message: ToolResultMessage): string[] {\n\tconst content = joinTextBlocks(message.content);\n\treturn content ? [`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`] : [];\n}\n\n/** Serialize LLM messages to plain text for summarization prompts. */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\tfor (const message of messages) {\n\t\tswitch (message.role) {\n\t\t\tcase \"user\":\n\t\t\t\tparts.push(...serializeUserMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"assistant\":\n\t\t\t\tparts.push(...serializeAssistantMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"toolResult\":\n\t\t\t\tparts.push(...serializeToolResultMessage(message));\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn parts.join(\"\\n\\n\");\n}\n"]}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/harness/compaction/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,OAAO,EAIP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC9B,+CAA+C;IAC/C,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,mDAAmD;IACnD,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,yCAAyC;IACzC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,kDAAkD;AAClD,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAyCD,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAO9F;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAK5E;AAED,kDAAkD;AAClD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;AA4DD,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAgBjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/harness/compaction/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tTextContent,\n\tToolResultMessage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\n\n/** File paths touched by a session branch or compaction range. */\nexport interface FileOperations {\n\t/** Files read but not necessarily modified. */\n\tread: Set<string>;\n\t/** Files written by full-file write operations. */\n\twritten: Set<string>;\n\t/** Files modified by edit operations. */\n\tedited: Set<string>;\n}\n\nexport interface FileOperationLists {\n\treadFiles: string[];\n\tmodifiedFiles: string[];\n}\n\n/** Create an empty file-operation accumulator. */\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\ntype FileOperationType = \"read\" | \"write\" | \"edit\";\n\ninterface ExtractedFileOperation {\n\ttype: FileOperationType;\n\tpath: string;\n}\n\nfunction parseFileOperation(block: unknown): ExtractedFileOperation | undefined {\n\tif (typeof block !== \"object\" || block === null) return undefined;\n\tif (!(\"type\" in block) || block.type !== \"toolCall\") return undefined;\n\tif (!(\"arguments\" in block) || !(\"name\" in block)) return undefined;\n\tconst args = block.arguments as Record<string, unknown> | undefined;\n\tif (!args) return undefined;\n\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\tif (!path) return undefined;\n\tswitch (block.name) {\n\t\tcase \"read\":\n\t\tcase \"write\":\n\t\tcase \"edit\":\n\t\t\treturn { type: block.name, path };\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction recordFileOperation(operation: ExtractedFileOperation, fileOps: FileOperations): void {\n\tswitch (operation.type) {\n\t\tcase \"read\":\n\t\t\tfileOps.read.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"write\":\n\t\t\tfileOps.written.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"edit\":\n\t\t\tfileOps.edited.add(operation.path);\n\t\t\tbreak;\n\t}\n}\n\n/** Add file operations from assistant tool calls to an accumulator. */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\tfor (const block of message.content) {\n\t\tconst operation = parseFileOperation(block);\n\t\tif (operation) recordFileOperation(operation, fileOps);\n\t}\n}\n\n/** Compute sorted read-only and modified file lists from accumulated operations. */\nexport function computeFileLists(fileOps: FileOperations): FileOperationLists {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/** Format file lists as summary metadata tags. */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\nfunction joinTextBlocks(content: readonly (TextContent | ImageContent)[]): string {\n\tlet text = \"\";\n\tfor (const block of content) {\n\t\tif (block.type === \"text\") text += block.text;\n\t}\n\treturn text;\n}\n\nfunction serializeUserMessage(message: UserMessage): string[] {\n\tconst content = typeof message.content === \"string\" ? message.content : joinTextBlocks(message.content);\n\treturn content ? [`[User]: ${content}`] : [];\n}\n\nfunction serializeAssistantMessage(message: AssistantMessage): string[] {\n\tconst textParts: string[] = [];\n\tconst thinkingParts: string[] = [];\n\tconst toolCalls: string[] = [];\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\ttextParts.push(block.text);\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tthinkingParts.push(block.thinking);\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\tconst argsText = Object.entries(args)\n\t\t\t\t.map(([key, value]) => `${key}=${safeJsonStringify(value)}`)\n\t\t\t\t.join(\", \");\n\t\t\ttoolCalls.push(`${block.name}(${argsText})`);\n\t\t}\n\t}\n\tconst parts: string[] = [];\n\tif (thinkingParts.length > 0) parts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\tif (textParts.length > 0) parts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\tif (toolCalls.length > 0) parts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n\treturn parts;\n}\n\nfunction serializeToolResultMessage(message: ToolResultMessage): string[] {\n\tconst content = joinTextBlocks(message.content);\n\treturn content ? [`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`] : [];\n}\n\n/** Serialize LLM messages to plain text for summarization prompts. */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\tfor (const message of messages) {\n\t\tswitch (message.role) {\n\t\t\tcase \"user\":\n\t\t\t\tparts.push(...serializeUserMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"assistant\":\n\t\t\t\tparts.push(...serializeAssistantMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"toolResult\":\n\t\t\t\tparts.push(...serializeToolResultMessage(message));\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn parts.join(\"\\n\\n\");\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/harness/compaction/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tTextContent,\n\tToolResultMessage,\n\tUserMessage,\n} from \"@greppleai/grip-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\n\n/** File paths touched by a session branch or compaction range. */\nexport interface FileOperations {\n\t/** Files read but not necessarily modified. */\n\tread: Set<string>;\n\t/** Files written by full-file write operations. */\n\twritten: Set<string>;\n\t/** Files modified by edit operations. */\n\tedited: Set<string>;\n}\n\nexport interface FileOperationLists {\n\treadFiles: string[];\n\tmodifiedFiles: string[];\n}\n\n/** Create an empty file-operation accumulator. */\nexport function createFileOps(): FileOperations {\n\treturn {\n\t\tread: new Set(),\n\t\twritten: new Set(),\n\t\tedited: new Set(),\n\t};\n}\n\ntype FileOperationType = \"read\" | \"write\" | \"edit\";\n\ninterface ExtractedFileOperation {\n\ttype: FileOperationType;\n\tpath: string;\n}\n\nfunction parseFileOperation(block: unknown): ExtractedFileOperation | undefined {\n\tif (typeof block !== \"object\" || block === null) return undefined;\n\tif (!(\"type\" in block) || block.type !== \"toolCall\") return undefined;\n\tif (!(\"arguments\" in block) || !(\"name\" in block)) return undefined;\n\tconst args = block.arguments as Record<string, unknown> | undefined;\n\tif (!args) return undefined;\n\tconst path = typeof args.path === \"string\" ? args.path : undefined;\n\tif (!path) return undefined;\n\tswitch (block.name) {\n\t\tcase \"read\":\n\t\tcase \"write\":\n\t\tcase \"edit\":\n\t\t\treturn { type: block.name, path };\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction recordFileOperation(operation: ExtractedFileOperation, fileOps: FileOperations): void {\n\tswitch (operation.type) {\n\t\tcase \"read\":\n\t\t\tfileOps.read.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"write\":\n\t\t\tfileOps.written.add(operation.path);\n\t\t\tbreak;\n\t\tcase \"edit\":\n\t\t\tfileOps.edited.add(operation.path);\n\t\t\tbreak;\n\t}\n}\n\n/** Add file operations from assistant tool calls to an accumulator. */\nexport function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void {\n\tif (message.role !== \"assistant\") return;\n\tif (!(\"content\" in message) || !Array.isArray(message.content)) return;\n\tfor (const block of message.content) {\n\t\tconst operation = parseFileOperation(block);\n\t\tif (operation) recordFileOperation(operation, fileOps);\n\t}\n}\n\n/** Compute sorted read-only and modified file lists from accumulated operations. */\nexport function computeFileLists(fileOps: FileOperations): FileOperationLists {\n\tconst modified = new Set([...fileOps.edited, ...fileOps.written]);\n\tconst readOnly = [...fileOps.read].filter((f) => !modified.has(f)).sort();\n\tconst modifiedFiles = [...modified].sort();\n\treturn { readFiles: readOnly, modifiedFiles };\n}\n\n/** Format file lists as summary metadata tags. */\nexport function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string {\n\tconst sections: string[] = [];\n\tif (readFiles.length > 0) {\n\t\tsections.push(`<read-files>\\n${readFiles.join(\"\\n\")}\\n</read-files>`);\n\t}\n\tif (modifiedFiles.length > 0) {\n\t\tsections.push(`<modified-files>\\n${modifiedFiles.join(\"\\n\")}\\n</modified-files>`);\n\t}\n\tif (sections.length === 0) return \"\";\n\treturn `\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n\nconst TOOL_RESULT_MAX_CHARS = 2000;\n\nfunction safeJsonStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value) ?? \"undefined\";\n\t} catch {\n\t\treturn \"[unserializable]\";\n\t}\n}\n\nfunction truncateForSummary(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\tconst truncatedChars = text.length - maxChars;\n\treturn `${text.slice(0, maxChars)}\\n\\n[... ${truncatedChars} more characters truncated]`;\n}\n\nfunction joinTextBlocks(content: readonly (TextContent | ImageContent)[]): string {\n\tlet text = \"\";\n\tfor (const block of content) {\n\t\tif (block.type === \"text\") text += block.text;\n\t}\n\treturn text;\n}\n\nfunction serializeUserMessage(message: UserMessage): string[] {\n\tconst content = typeof message.content === \"string\" ? message.content : joinTextBlocks(message.content);\n\treturn content ? [`[User]: ${content}`] : [];\n}\n\nfunction serializeAssistantMessage(message: AssistantMessage): string[] {\n\tconst textParts: string[] = [];\n\tconst thinkingParts: string[] = [];\n\tconst toolCalls: string[] = [];\n\tfor (const block of message.content) {\n\t\tif (block.type === \"text\") {\n\t\t\ttextParts.push(block.text);\n\t\t} else if (block.type === \"thinking\") {\n\t\t\tthinkingParts.push(block.thinking);\n\t\t} else if (block.type === \"toolCall\") {\n\t\t\tconst args = block.arguments as Record<string, unknown>;\n\t\t\tconst argsText = Object.entries(args)\n\t\t\t\t.map(([key, value]) => `${key}=${safeJsonStringify(value)}`)\n\t\t\t\t.join(\", \");\n\t\t\ttoolCalls.push(`${block.name}(${argsText})`);\n\t\t}\n\t}\n\tconst parts: string[] = [];\n\tif (thinkingParts.length > 0) parts.push(`[Assistant thinking]: ${thinkingParts.join(\"\\n\")}`);\n\tif (textParts.length > 0) parts.push(`[Assistant]: ${textParts.join(\"\\n\")}`);\n\tif (toolCalls.length > 0) parts.push(`[Assistant tool calls]: ${toolCalls.join(\"; \")}`);\n\treturn parts;\n}\n\nfunction serializeToolResultMessage(message: ToolResultMessage): string[] {\n\tconst content = joinTextBlocks(message.content);\n\treturn content ? [`[Tool result]: ${truncateForSummary(content, TOOL_RESULT_MAX_CHARS)}`] : [];\n}\n\n/** Serialize LLM messages to plain text for summarization prompts. */\nexport function serializeConversation(messages: Message[]): string {\n\tconst parts: string[] = [];\n\tfor (const message of messages) {\n\t\tswitch (message.role) {\n\t\t\tcase \"user\":\n\t\t\t\tparts.push(...serializeUserMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"assistant\":\n\t\t\t\tparts.push(...serializeAssistantMessage(message));\n\t\t\t\tbreak;\n\t\t\tcase \"toolResult\":\n\t\t\t\tparts.push(...serializeToolResultMessage(message));\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn parts.join(\"\\n\\n\");\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"nodejs.d.ts","sourceRoot":"","sources":["../../../src/harness/env/nodejs.ts"],"names":[],"mappings":"AAmBA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,cAAc,EAEd,SAAS,EACT,KAAK,QAAQ,EAGb,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EAEX,MAAM,aAAa,CAAC;AAIrB,eAAO,MAAM,qBAAqB,UAAY,CAAC;AAuK/C,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AA+DD,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC7B;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAoB;IAErC,YAAY,OAAO,EAAE,uBAAuB,EAI3C;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAEnE;IAEK,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAElE;IAEK,IAAI,CACT,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC,CA4GzD;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAS9F;IAEK,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CA0BtG;IAEK,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CASpG;IAEK,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAalC;IAEK,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAS7F;IAEK,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAmBjH;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAOjE;IAEK,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,CAsB7F;IAEK,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAOpE;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAK9D;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAQ1F;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAQxF;IAEK,aAAa,CAAC,MAAM,GAAE,MAAe,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAM/E;IAEK,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAUxF;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;CACD","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { constants, createReadStream } from \"node:fs\";\nimport {\n\taccess,\n\tappendFile,\n\tlstat,\n\tmkdir,\n\tmkdtemp,\n\treaddir,\n\treadFile,\n\trealpath,\n\trename,\n\trm,\n\twriteFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport {\n\ttype CreateDirOptions,\n\ttype CreateTempFileOptions,\n\ttype ExecutionEnv,\n\ttype ExecutionEnvExecOptions,\n\ttype ExecutionEnvExecResult,\n\tExecutionError,\n\terr,\n\tFileError,\n\ttype FileInfo,\n\ttype FileKind,\n\tok,\n\ttype ReadTextLinesOptions,\n\ttype RemovePathOptions,\n\ttype Result,\n\ttoError,\n} from \"../types.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\nexport const MAX_EXEC_OUTPUT_CHARS = 1_000_000;\nconst OUTPUT_TRUNCATION_MARKER = \"[... earlier output truncated ...]\\n\";\n\nfunction appendBoundedOutput(current: string, chunk: string): string {\n\tif (current.length + chunk.length <= MAX_EXEC_OUTPUT_CHARS) return current + chunk;\n\tconst retainedChars = MAX_EXEC_OUTPUT_CHARS - OUTPUT_TRUNCATION_MARKER.length;\n\tconst tail = chunk.length >= retainedChars ? chunk.slice(-retainedChars) : (current + chunk).slice(-retainedChars);\n\treturn OUTPUT_TRUNCATION_MARKER + tail;\n}\nfunction resolveTimeoutMs(timeout: number | undefined): Result<number | undefined, ExecutionError> {\n\tif (timeout === undefined) return ok(undefined);\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\treturn err(new ExecutionError(\"timeout\", \"Invalid timeout: must be a finite number of seconds\"));\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\treturn err(new ExecutionError(\"timeout\", `Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`));\n\t}\n\treturn ok(timeoutMs);\n}\n\nfunction resolvePath(cwd: string, path: string): string {\n\treturn isAbsolute(path) ? path : resolve(cwd, path);\n}\n\ninterface FileKindStats {\n\tisFile(): boolean;\n\tisDirectory(): boolean;\n\tisSymbolicLink(): boolean;\n}\n\ninterface FileInfoStats extends FileKindStats {\n\tsize: number;\n\tmtimeMs: number;\n}\n\nfunction fileKindFromStats(stats: FileKindStats): FileKind | undefined {\n\tif (stats.isFile()) return \"file\";\n\tif (stats.isDirectory()) return \"directory\";\n\tif (stats.isSymbolicLink()) return \"symlink\";\n\treturn undefined;\n}\n\nfunction fileInfoFromStats(path: string, stats: FileInfoStats): Result<FileInfo, FileError> {\n\tconst kind = fileKindFromStats(stats);\n\tif (!kind) return err(new FileError(\"invalid\", \"Unsupported file type\", path));\n\treturn ok({\n\t\tname: path.replace(/\\/+$/, \"\").split(\"/\").pop() ?? path,\n\t\tpath,\n\t\tkind,\n\t\tsize: stats.size,\n\t\tmtimeMs: stats.mtimeMs,\n\t});\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n\treturn error instanceof Error && \"code\" in error;\n}\n\nfunction toFileError(error: unknown, path?: string): FileError {\n\tif (error instanceof FileError) return error;\n\tconst cause = toError(error);\n\tif (isNodeError(error)) {\n\t\tconst message = error.message;\n\t\tswitch (error.code) {\n\t\t\tcase \"ABORT_ERR\":\n\t\t\t\treturn new FileError(\"aborted\", message, path, cause);\n\t\t\tcase \"ENOENT\":\n\t\t\t\treturn new FileError(\"not_found\", message, path, cause);\n\t\t\tcase \"EACCES\":\n\t\t\tcase \"EPERM\":\n\t\t\t\treturn new FileError(\"permission_denied\", message, path, cause);\n\t\t\tcase \"ENOTDIR\":\n\t\t\t\treturn new FileError(\"not_directory\", message, path, cause);\n\t\t\tcase \"EISDIR\":\n\t\t\t\treturn new FileError(\"is_directory\", message, path, cause);\n\t\t\tcase \"EINVAL\":\n\t\t\t\treturn new FileError(\"invalid\", message, path, cause);\n\t\t}\n\t}\n\treturn new FileError(\"unknown\", cause.message, path, cause);\n}\n\nfunction nodeErrorPath(error: unknown, fallback: string): string {\n\tif (isNodeError(error) && typeof error.path === \"string\") return error.path;\n\treturn fallback;\n}\n\nfunction isWindowsRenameSharingError(error: unknown): boolean {\n\treturn isNodeError(error) && (error.code === \"EPERM\" || error.code === \"EACCES\" || error.code === \"EBUSY\");\n}\n\nasync function waitForRenameRetry(delayMs: number, signal?: AbortSignal): Promise<boolean> {\n\tif (signal?.aborted) return false;\n\treturn await new Promise((resolvePromise) => {\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tresolvePromise(false);\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolvePromise(true);\n\t\t}, delayMs);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\nfunction abortResult<TValue>(signal: AbortSignal | undefined, path?: string): Result<TValue, FileError> | undefined {\n\treturn signal?.aborted ? err(new FileError(\"aborted\", \"aborted\", path)) : undefined;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path, constants.F_OK);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\ninterface CommandProbeResult {\n\tstdout: string;\n\tstatus: number | null;\n}\n\nasync function runCommand(command: string, args: string[], timeoutMs: number): Promise<CommandProbeResult> {\n\treturn await new Promise((resolve) => {\n\t\tlet stdout = \"\";\n\t\tlet child: ReturnType<typeof spawn>;\n\t\ttry {\n\t\t\tchild = spawn(command, args, {\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\tresolve({ stdout: \"\", status: null });\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(() => {\n\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t}, timeoutMs);\n\t\tchild.stdout?.setEncoding(\"utf8\");\n\t\tchild.stdout?.on(\"data\", (chunk: string) => {\n\t\t\tstdout = appendBoundedOutput(stdout, chunk);\n\t\t});\n\t\tchild.on(\"error\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\tresolve({ stdout: \"\", status: null });\n\t\t});\n\t\tchild.on(\"close\", (status) => {\n\t\t\tclearTimeout(timeout);\n\t\t\tresolve({ stdout, status });\n\t\t});\n\t});\n}\n\nasync function findBashOnPath(): Promise<string | null> {\n\tconst result =\n\t\tprocess.platform === \"win32\"\n\t\t\t? await runCommand(\"where\", [\"bash.exe\"], 5000)\n\t\t\t: await runCommand(\"which\", [\"bash\"], 5000);\n\tif (result.status !== 0 || !result.stdout) return null;\n\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\treturn firstMatch && (await pathExists(firstMatch)) ? firstMatch : null;\n}\n\nexport interface ShellConfig {\n\tshell: string;\n\targs: string[];\n}\n\nasync function getWindowsShellConfig(): Promise<Result<ShellConfig, ExecutionError>> {\n\tconst candidates: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) candidates.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\tif (programFilesX86) candidates.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\tfor (const candidate of candidates) {\n\t\tif (await pathExists(candidate)) return ok({ shell: candidate, args: [\"-c\"] });\n\t}\n\tconst bashOnPath = await findBashOnPath();\n\tif (bashOnPath) return ok({ shell: bashOnPath, args: [\"-c\"] });\n\treturn err(new ExecutionError(\"shell_unavailable\", \"No bash shell found\"));\n}\n\nasync function getPosixShellConfig(): Promise<Result<ShellConfig, ExecutionError>> {\n\tif (await pathExists(\"/bin/bash\")) return ok({ shell: \"/bin/bash\", args: [\"-c\"] });\n\tconst bashOnPath = await findBashOnPath();\n\treturn ok({ shell: bashOnPath ?? \"sh\", args: [\"-c\"] });\n}\n\nasync function getShellConfig(customShellPath?: string): Promise<Result<ShellConfig, ExecutionError>> {\n\tif (customShellPath) {\n\t\tif (await pathExists(customShellPath)) return ok({ shell: customShellPath, args: [\"-c\"] });\n\t\treturn err(new ExecutionError(\"shell_unavailable\", `Custom shell path not found: ${customShellPath}`));\n\t}\n\treturn process.platform === \"win32\" ? getWindowsShellConfig() : getPosixShellConfig();\n}\n\nfunction getShellEnv(baseEnv?: NodeJS.ProcessEnv, extraEnv?: Record<string, string>): NodeJS.ProcessEnv {\n\treturn {\n\t\t...process.env,\n\t\t...baseEnv,\n\t\t...extraEnv,\n\t};\n}\n\nfunction killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors.\n\t\t}\n\t\treturn;\n\t}\n\n\ttry {\n\t\tprocess.kill(-pid, \"SIGKILL\");\n\t} catch {\n\t\ttry {\n\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Process already dead.\n\t\t}\n\t}\n}\n\nexport interface NodeExecutionEnvOptions {\n\tcwd: string;\n\tshellPath?: string;\n\tshellEnv?: NodeJS.ProcessEnv;\n}\n\nexport class NodeExecutionEnv implements ExecutionEnv {\n\tcwd: string;\n\tprivate shellPath?: string;\n\tprivate shellEnv?: NodeJS.ProcessEnv;\n\n\tconstructor(options: NodeExecutionEnvOptions) {\n\t\tthis.cwd = options.cwd;\n\t\tthis.shellPath = options.shellPath;\n\t\tthis.shellEnv = options.shellEnv;\n\t}\n\n\tasync absolutePath(path: string): Promise<Result<string, FileError>> {\n\t\treturn ok(resolvePath(this.cwd, path));\n\t}\n\n\tasync joinPath(parts: string[]): Promise<Result<string, FileError>> {\n\t\treturn ok(join(...parts));\n\t}\n\n\tasync exec(\n\t\tcommand: string,\n\t\toptions?: ExecutionEnvExecOptions,\n\t): Promise<Result<ExecutionEnvExecResult, ExecutionError>> {\n\t\tif (options?.abortSignal?.aborted) return err(new ExecutionError(\"aborted\", \"aborted\"));\n\t\tconst timeoutMsResult = resolveTimeoutMs(options?.timeout);\n\t\tif (!timeoutMsResult.ok) return err(timeoutMsResult.error);\n\t\tconst timeoutMs = timeoutMsResult.value;\n\n\t\tconst cwd = options?.cwd ? resolvePath(this.cwd, options.cwd) : this.cwd;\n\t\tconst shellConfig = await getShellConfig(this.shellPath);\n\t\tif (!shellConfig.ok) return shellConfig;\n\n\t\treturn await new Promise((resolvePromise) => {\n\t\t\tlet stdout = \"\";\n\t\t\tlet stderr = \"\";\n\t\t\tlet settled = false;\n\t\t\tlet timedOut = false;\n\t\t\tlet callbackError: ExecutionError | undefined;\n\t\t\tlet child: ReturnType<typeof spawn> | undefined;\n\t\t\tlet timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child?.pid) {\n\t\t\t\t\tkillProcessTree(child.pid);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst settle = (result: Result<ExecutionEnvExecResult, ExecutionError>) => {\n\t\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\t\tif (options?.abortSignal) options.abortSignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolvePromise(result);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tchild = spawn(shellConfig.value.shell, [...shellConfig.value.args, command], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\tenv: getShellEnv(this.shellEnv, options?.env),\n\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst cause = toError(error);\n\t\t\t\tsettle(err(new ExecutionError(\"spawn_error\", cause.message, cause)));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttimeoutId =\n\t\t\t\ttimeoutMs !== undefined\n\t\t\t\t\t? setTimeout(() => {\n\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\tif (child?.pid) {\n\t\t\t\t\t\t\t\tkillProcessTree(child.pid);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, timeoutMs)\n\t\t\t\t\t: undefined;\n\n\t\t\tif (options?.abortSignal) {\n\t\t\t\tif (options.abortSignal.aborted) {\n\t\t\t\t\tonAbort();\n\t\t\t\t} else {\n\t\t\t\t\toptions.abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchild.stdout?.setEncoding(\"utf8\");\n\t\t\tchild.stderr?.setEncoding(\"utf8\");\n\t\t\tchild.stdout?.on(\"data\", (chunk: string) => {\n\t\t\t\tstdout = appendBoundedOutput(stdout, chunk);\n\t\t\t\ttry {\n\t\t\t\t\toptions?.onStdout?.(chunk);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst cause = toError(error);\n\t\t\t\t\tcallbackError = new ExecutionError(\"callback_error\", cause.message, cause);\n\t\t\t\t\tonAbort();\n\t\t\t\t}\n\t\t\t});\n\t\t\tchild.stderr?.on(\"data\", (chunk: string) => {\n\t\t\t\tstderr = appendBoundedOutput(stderr, chunk);\n\t\t\t\ttry {\n\t\t\t\t\toptions?.onStderr?.(chunk);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst cause = toError(error);\n\t\t\t\t\tcallbackError = new ExecutionError(\"callback_error\", cause.message, cause);\n\t\t\t\t\tonAbort();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\tsettle(err(new ExecutionError(\"spawn_error\", error.message, error)));\n\t\t\t});\n\n\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\tif (callbackError) {\n\t\t\t\t\tsettle(err(callbackError));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tsettle(err(new ExecutionError(\"timeout\", `timeout:${options?.timeout}`)));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (options?.abortSignal?.aborted) {\n\t\t\t\t\tsettle(err(new ExecutionError(\"aborted\", \"aborted\")));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsettle(ok({ stdout, stderr, exitCode: code ?? 0 }));\n\t\t\t});\n\t\t});\n\t}\n\n\tasync readTextFile(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\tconst aborted = abortResult<string>(abortSignal, resolved);\n\t\tif (aborted) return aborted;\n\t\ttry {\n\t\t\treturn ok(await readFile(resolved, { encoding: \"utf8\", signal: abortSignal }));\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync readTextLines(path: string, options?: ReadTextLinesOptions): Promise<Result<string[], FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\tconst aborted = abortResult<string[]>(options?.abortSignal, resolved);\n\t\tif (aborted) return aborted;\n\t\tif (options?.maxLines !== undefined && options.maxLines <= 0) return ok([]);\n\t\tlet stream: ReturnType<typeof createReadStream> | undefined;\n\t\tlet lineReader: ReturnType<typeof createInterface> | undefined;\n\t\ttry {\n\t\t\tstream = createReadStream(resolved, { encoding: \"utf8\", signal: options?.abortSignal });\n\t\t\tlineReader = createInterface({ input: stream, crlfDelay: Infinity });\n\t\t\tconst lines: string[] = [];\n\t\t\tfor await (const line of lineReader) {\n\t\t\t\tconst loopAbort = abortResult<string[]>(options?.abortSignal, resolved);\n\t\t\t\tif (loopAbort) return loopAbort;\n\t\t\t\tlines.push(line);\n\t\t\t\tif (options?.maxLines !== undefined && lines.length >= options.maxLines) break;\n\t\t\t}\n\t\t\tconst afterReadAbort = abortResult<string[]>(options?.abortSignal, resolved);\n\t\t\tif (afterReadAbort) return afterReadAbort;\n\t\t\treturn ok(lines);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t} finally {\n\t\t\tlineReader?.close();\n\t\t\tstream?.destroy();\n\t\t}\n\t}\n\n\tasync readBinaryFile(path: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\tconst aborted = abortResult<Uint8Array>(abortSignal, resolved);\n\t\tif (aborted) return aborted;\n\t\ttry {\n\t\t\treturn ok(await readFile(resolved, { signal: abortSignal }));\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync writeFile(\n\t\tpath: string,\n\t\tcontent: string | Uint8Array,\n\t\tabortSignal?: AbortSignal,\n\t): Promise<Result<void, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\tconst aborted = abortResult<void>(abortSignal, resolved);\n\t\tif (aborted) return aborted;\n\t\ttry {\n\t\t\tawait mkdir(resolve(resolved, \"..\"), { recursive: true });\n\t\t\tconst afterMkdirAbort = abortResult<void>(abortSignal, resolved);\n\t\t\tif (afterMkdirAbort) return afterMkdirAbort;\n\t\t\tawait writeFile(resolved, content, { signal: abortSignal });\n\t\t\treturn ok(undefined);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync appendFile(path: string, content: string | Uint8Array): Promise<Result<void, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\ttry {\n\t\t\tawait mkdir(resolve(resolved, \"..\"), { recursive: true });\n\t\t\tawait appendFile(resolved, content);\n\t\t\treturn ok(undefined);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync renameFile(source: string, destination: string, abortSignal?: AbortSignal): Promise<Result<void, FileError>> {\n\t\tconst resolvedSource = resolvePath(this.cwd, source);\n\t\tconst resolvedDestination = resolvePath(this.cwd, destination);\n\t\tfor (let attempt = 0; attempt < 5; attempt++) {\n\t\t\tconst aborted = abortResult<void>(abortSignal, resolvedDestination);\n\t\t\tif (aborted) return aborted;\n\t\t\ttry {\n\t\t\t\tawait rename(resolvedSource, resolvedDestination);\n\t\t\t\treturn ok(undefined);\n\t\t\t} catch (error) {\n\t\t\t\tif (process.platform !== \"win32\" || !isWindowsRenameSharingError(error) || attempt === 4) {\n\t\t\t\t\treturn err(toFileError(error, nodeErrorPath(error, resolvedDestination)));\n\t\t\t\t}\n\t\t\t\tif (!(await waitForRenameRetry(10 * 2 ** attempt, abortSignal))) {\n\t\t\t\t\treturn err(new FileError(\"aborted\", \"aborted\", resolvedDestination));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn err(new FileError(\"unknown\", \"rename failed\", resolvedDestination));\n\t}\n\n\tasync fileInfo(path: string): Promise<Result<FileInfo, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\ttry {\n\t\t\treturn fileInfoFromStats(resolved, await lstat(resolved));\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync listDir(path: string, abortSignal?: AbortSignal): Promise<Result<FileInfo[], FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\tconst aborted = abortResult<FileInfo[]>(abortSignal, resolved);\n\t\tif (aborted) return aborted;\n\t\ttry {\n\t\t\tconst entries = await readdir(resolved, { withFileTypes: true });\n\t\t\tconst infos: FileInfo[] = [];\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst loopAbort = abortResult<FileInfo[]>(abortSignal, resolved);\n\t\t\t\tif (loopAbort) return loopAbort;\n\t\t\t\tconst entryPath = resolve(resolved, entry.name);\n\t\t\t\ttry {\n\t\t\t\t\tconst info = fileInfoFromStats(entryPath, await lstat(entryPath));\n\t\t\t\t\tif (info.ok) infos.push(info.value);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn err(toFileError(error, entryPath));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ok(infos);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync canonicalPath(path: string): Promise<Result<string, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\ttry {\n\t\t\treturn ok(await realpath(resolved));\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync exists(path: string): Promise<Result<boolean, FileError>> {\n\t\tconst result = await this.fileInfo(path);\n\t\tif (result.ok) return ok(true);\n\t\tif (result.error.code === \"not_found\") return ok(false);\n\t\treturn err(result.error);\n\t}\n\n\tasync createDir(path: string, options?: CreateDirOptions): Promise<Result<void, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\ttry {\n\t\t\tawait mkdir(resolved, { recursive: options?.recursive ?? true });\n\t\t\treturn ok(undefined);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync remove(path: string, options?: RemovePathOptions): Promise<Result<void, FileError>> {\n\t\tconst resolved = resolvePath(this.cwd, path);\n\t\ttry {\n\t\t\tawait rm(resolved, { recursive: options?.recursive ?? false, force: options?.force ?? false });\n\t\t\treturn ok(undefined);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, resolved));\n\t\t}\n\t}\n\n\tasync createTempDir(prefix: string = \"tmp-\"): Promise<Result<string, FileError>> {\n\t\ttry {\n\t\t\treturn ok(await mkdtemp(join(tmpdir(), prefix)));\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error));\n\t\t}\n\t}\n\n\tasync createTempFile(options?: CreateTempFileOptions): Promise<Result<string, FileError>> {\n\t\tconst dir = await this.createTempDir(\"tmp-\");\n\t\tif (!dir.ok) return dir;\n\t\tconst filePath = join(dir.value, `${options?.prefix ?? \"\"}${randomUUID()}${options?.suffix ?? \"\"}`);\n\t\ttry {\n\t\t\tawait writeFile(filePath, \"\");\n\t\t\treturn ok(filePath);\n\t\t} catch (error) {\n\t\t\treturn err(toFileError(error, filePath));\n\t\t}\n\t}\n\n\tasync cleanup(): Promise<void> {\n\t\t// nothing to clean up for the local node implementation\n\t}\n}\n"]}
1
+ {"version":3,"file":"nodejs.d.ts","sourceRoot":"","sources":["../../../src/harness/env/nodejs.ts"],"names":[],"mappings":"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"}
@@ -221,9 +221,6 @@ function killProcessTree(pid) {
221
221
  }
222
222
  }
223
223
  export class NodeExecutionEnv {
224
- cwd;
225
- shellPath;
226
- shellEnv;
227
224
  constructor(options) {
228
225
  this.cwd = options.cwd;
229
226
  this.shellPath = options.shellPath;