@hung319/opencode-hive 1.3.9 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -232,7 +232,7 @@ var init_context_compression = __esm(() => {
232
232
 
233
233
  // src/index.ts
234
234
  import * as path8 from "path";
235
- import * as os from "os";
235
+ import * as os2 from "os";
236
236
 
237
237
  // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
238
238
  var exports_external = {};
@@ -15845,6 +15845,428 @@ mcp:
15845
15845
  }
15846
15846
  });
15847
15847
 
15848
+ // src/tools/memory.ts
15849
+ import * as fs2 from "fs";
15850
+ import * as path2 from "path";
15851
+ import * as os from "os";
15852
+ function getGlobalMemoryDir() {
15853
+ return path2.join(os.homedir(), ".config", "opencode", "hive", "memory", "global");
15854
+ }
15855
+ function getProjectMemoryDir(projectRoot) {
15856
+ return path2.join(projectRoot, ".hive", "memory", "project");
15857
+ }
15858
+ function getJournalDir() {
15859
+ return path2.join(os.homedir(), ".config", "opencode", "hive", "journal");
15860
+ }
15861
+ function parseFrontmatter2(content) {
15862
+ if (!content.startsWith(`---
15863
+ `)) {
15864
+ return { frontmatter: {}, body: content };
15865
+ }
15866
+ const endIndex = content.indexOf(`
15867
+ ---
15868
+ `, 4);
15869
+ if (endIndex === -1) {
15870
+ return { frontmatter: {}, body: content };
15871
+ }
15872
+ const fmText = content.slice(4, endIndex);
15873
+ const body = content.slice(endIndex + 5);
15874
+ const frontmatter = {};
15875
+ for (const line of fmText.split(`
15876
+ `)) {
15877
+ const colonIdx = line.indexOf(":");
15878
+ if (colonIdx > 0) {
15879
+ const key = line.slice(0, colonIdx).trim();
15880
+ const value = line.slice(colonIdx + 1).trim();
15881
+ if (value === "true")
15882
+ frontmatter[key] = true;
15883
+ else if (value === "false")
15884
+ frontmatter[key] = false;
15885
+ else if (!isNaN(Number(value)))
15886
+ frontmatter[key] = Number(value);
15887
+ else
15888
+ frontmatter[key] = value;
15889
+ }
15890
+ }
15891
+ return { frontmatter, body };
15892
+ }
15893
+ function buildFrontmatter(frontmatter) {
15894
+ const lines = [];
15895
+ for (const [key, value] of Object.entries(frontmatter)) {
15896
+ if (typeof value === "boolean" || typeof value === "number") {
15897
+ lines.push(`${key}: ${value}`);
15898
+ } else if (Array.isArray(value)) {
15899
+ lines.push(`${key}:`);
15900
+ for (const item of value) {
15901
+ lines.push(` - ${item}`);
15902
+ }
15903
+ } else {
15904
+ lines.push(`${key}: ${value}`);
15905
+ }
15906
+ }
15907
+ return lines.length > 0 ? `---
15908
+ ${lines.join(`
15909
+ `)}
15910
+ ---
15911
+ ` : "";
15912
+ }
15913
+ function readMemoryBlock(filePath, scope) {
15914
+ const content = fs2.readFileSync(filePath, "utf-8");
15915
+ const { frontmatter, body } = parseFrontmatter2(content);
15916
+ const label = frontmatter.label || path2.basename(filePath, path2.extname(filePath));
15917
+ const description = frontmatter.description || "Memory block";
15918
+ const limit = frontmatter.limit || 5000;
15919
+ const readOnly = frontmatter.read_only === true;
15920
+ const stats = fs2.statSync(filePath);
15921
+ return {
15922
+ scope,
15923
+ label,
15924
+ description,
15925
+ limit,
15926
+ readOnly,
15927
+ value: body.trim(),
15928
+ filePath,
15929
+ lastModified: stats.mtime.toISOString(),
15930
+ charsCurrent: body.trim().length
15931
+ };
15932
+ }
15933
+ function listMemoryBlocks(scope, projectRoot) {
15934
+ const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
15935
+ if (!fs2.existsSync(dir)) {
15936
+ return [];
15937
+ }
15938
+ const blocks = [];
15939
+ for (const file2 of fs2.readdirSync(dir)) {
15940
+ if (file2.endsWith(".md")) {
15941
+ const filePath = path2.join(dir, file2);
15942
+ try {
15943
+ blocks.push(readMemoryBlock(filePath, scope));
15944
+ } catch {}
15945
+ }
15946
+ }
15947
+ return blocks.sort((a, b) => {
15948
+ const priority = { persona: 0, human: 1, project: 2 };
15949
+ const pa = priority[a.label] ?? 10;
15950
+ const pb = priority[b.label] ?? 10;
15951
+ if (pa !== pb)
15952
+ return pa - pb;
15953
+ return a.label.localeCompare(b.label);
15954
+ });
15955
+ }
15956
+ var SEED_BLOCKS = [
15957
+ { scope: "global", label: "persona", description: "How the agent should behave and respond. Personality, communication style, constraints." },
15958
+ { scope: "global", label: "human", description: "Key details about the user: preferences, habits, constraints, working style." },
15959
+ { scope: "project", label: "project", description: "Project-specific knowledge: commands, architecture, conventions, gotchas." }
15960
+ ];
15961
+ async function ensureMemorySeeded(projectRoot) {
15962
+ for (const seed of SEED_BLOCKS) {
15963
+ const dir = seed.scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
15964
+ fs2.mkdirSync(dir, { recursive: true });
15965
+ const filePath = path2.join(dir, `${seed.label}.md`);
15966
+ if (!fs2.existsSync(filePath)) {
15967
+ const content = buildFrontmatter({
15968
+ label: seed.label,
15969
+ description: seed.description,
15970
+ limit: 5000,
15971
+ read_only: false
15972
+ });
15973
+ fs2.writeFileSync(filePath, content + `
15974
+ `, "utf-8");
15975
+ }
15976
+ }
15977
+ }
15978
+ function writeJournalEntry(title, body, project, tags = []) {
15979
+ const journalDir = getJournalDir();
15980
+ fs2.mkdirSync(journalDir, { recursive: true });
15981
+ const now = new Date;
15982
+ const id2 = `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}-${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")}-${String(now.getUTCMilliseconds()).padStart(3, "0")}`;
15983
+ const filePath = path2.join(journalDir, `${id2}.md`);
15984
+ const frontmatter = buildFrontmatter({
15985
+ title,
15986
+ project: project || "",
15987
+ tags,
15988
+ created: now.toISOString()
15989
+ });
15990
+ fs2.writeFileSync(filePath, frontmatter + body + `
15991
+ `, "utf-8");
15992
+ return {
15993
+ id: id2,
15994
+ title,
15995
+ body,
15996
+ project,
15997
+ tags,
15998
+ created: now.toISOString(),
15999
+ filePath
16000
+ };
16001
+ }
16002
+ function searchJournalEntries(query, project, limit = 20) {
16003
+ const journalDir = getJournalDir();
16004
+ if (!fs2.existsSync(journalDir)) {
16005
+ return { entries: [], total: 0 };
16006
+ }
16007
+ const entries = [];
16008
+ const files = fs2.readdirSync(journalDir).filter((f) => f.endsWith(".md")).sort().reverse();
16009
+ for (const file2 of files) {
16010
+ const filePath = path2.join(journalDir, file2);
16011
+ const content = fs2.readFileSync(filePath, "utf-8");
16012
+ const { frontmatter, body } = parseFrontmatter2(content);
16013
+ const entry = {
16014
+ id: file2.replace(".md", ""),
16015
+ title: frontmatter.title || "Untitled",
16016
+ body: body.trim(),
16017
+ project: frontmatter.project,
16018
+ tags: frontmatter.tags || [],
16019
+ created: frontmatter.created || "",
16020
+ filePath
16021
+ };
16022
+ if (project && entry.project !== project)
16023
+ continue;
16024
+ if (query) {
16025
+ const searchText = `${entry.title} ${entry.body}`.toLowerCase();
16026
+ if (!searchText.includes(query.toLowerCase()))
16027
+ continue;
16028
+ }
16029
+ entries.push(entry);
16030
+ if (entries.length >= limit)
16031
+ break;
16032
+ }
16033
+ return { entries, total: files.length };
16034
+ }
16035
+ var hiveMemoryListTool = tool({
16036
+ description: "List all memory blocks. Shows global (cross-project) and project-scoped blocks with descriptions and sizes.",
16037
+ args: {
16038
+ scope: tool.schema.enum(["global", "project", "all"]).optional().describe("Scope to list: global, project, or all (default: all)")
16039
+ },
16040
+ async execute({ scope = "all" }) {
16041
+ const projectRoot = process.cwd();
16042
+ const blocks = [];
16043
+ if (scope === "global" || scope === "all") {
16044
+ blocks.push(...listMemoryBlocks("global", projectRoot));
16045
+ }
16046
+ if (scope === "project" || scope === "all") {
16047
+ blocks.push(...listMemoryBlocks("project", projectRoot));
16048
+ }
16049
+ if (blocks.length === 0) {
16050
+ return JSON.stringify({
16051
+ message: "No memory blocks found. Use hive_memory_set to create one.",
16052
+ global: [],
16053
+ project: []
16054
+ }, null, 2);
16055
+ }
16056
+ const grouped = {
16057
+ global: blocks.filter((b) => b.scope === "global"),
16058
+ project: blocks.filter((b) => b.scope === "project")
16059
+ };
16060
+ return JSON.stringify({
16061
+ total: blocks.length,
16062
+ global: grouped.global.map((b) => ({
16063
+ label: b.label,
16064
+ description: b.description,
16065
+ charsCurrent: b.charsCurrent,
16066
+ charsLimit: b.limit,
16067
+ readOnly: b.readOnly,
16068
+ lastModified: b.lastModified
16069
+ })),
16070
+ project: grouped.project.map((b) => ({
16071
+ label: b.label,
16072
+ description: b.description,
16073
+ charsCurrent: b.charsCurrent,
16074
+ charsLimit: b.limit,
16075
+ readOnly: b.readOnly,
16076
+ lastModified: b.lastModified
16077
+ }))
16078
+ }, null, 2);
16079
+ }
16080
+ });
16081
+ var hiveMemorySetTool = tool({
16082
+ description: "Create or overwrite a memory block. Use for full updates.",
16083
+ args: {
16084
+ scope: tool.schema.enum(["global", "project"]).describe("Scope: global (cross-project) or project (project-scoped)"),
16085
+ label: tool.schema.string().describe("Label for the memory block (e.g., persona, human, project, conventions)"),
16086
+ value: tool.schema.string().describe("Content to store in the memory block"),
16087
+ description: tool.schema.string().optional().describe("Description of how this block should be used"),
16088
+ limit: tool.schema.number().optional().describe("Maximum characters allowed (default: 5000)"),
16089
+ readOnly: tool.schema.boolean().optional().describe("Make block read-only (default: false)")
16090
+ },
16091
+ async execute({ scope, label, value, description, limit = 5000, readOnly = false }) {
16092
+ const projectRoot = process.cwd();
16093
+ if (!/^[a-z0-9][a-z0-9-_]{1,60}$/i.test(label)) {
16094
+ return JSON.stringify({
16095
+ success: false,
16096
+ error: `Invalid label "${label}". Use letters/numbers/dash/underscore (2-61 chars).`
16097
+ }, null, 2);
16098
+ }
16099
+ if (value.length > limit) {
16100
+ return JSON.stringify({
16101
+ success: false,
16102
+ error: `Value too large (${value.length} chars, limit: ${limit})`,
16103
+ hint: "Use hive_memory_replace for surgical edits, or increase the limit."
16104
+ }, null, 2);
16105
+ }
16106
+ const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16107
+ fs2.mkdirSync(dir, { recursive: true });
16108
+ const filePath = path2.join(dir, `${label}.md`);
16109
+ if (fs2.existsSync(filePath)) {
16110
+ const existing = readMemoryBlock(filePath, scope);
16111
+ if (existing.readOnly) {
16112
+ return JSON.stringify({
16113
+ success: false,
16114
+ error: `Memory block "${scope}:${label}" is read-only`
16115
+ }, null, 2);
16116
+ }
16117
+ }
16118
+ const content = buildFrontmatter({
16119
+ label,
16120
+ description: description || `Memory block: ${label}`,
16121
+ limit,
16122
+ read_only: readOnly
16123
+ });
16124
+ fs2.writeFileSync(filePath, content + value + `
16125
+ `, "utf-8");
16126
+ return JSON.stringify({
16127
+ success: true,
16128
+ scope,
16129
+ label,
16130
+ charsWritten: value.length,
16131
+ charsLimit: limit
16132
+ }, null, 2);
16133
+ }
16134
+ });
16135
+ var hiveMemoryReplaceTool = tool({
16136
+ description: "Replace a substring within a memory block. Use for surgical edits.",
16137
+ args: {
16138
+ scope: tool.schema.enum(["global", "project"]).describe("Scope of the memory block"),
16139
+ label: tool.schema.string().describe("Label of the memory block"),
16140
+ oldText: tool.schema.string().describe("Text to find and replace"),
16141
+ newText: tool.schema.string().describe("Replacement text")
16142
+ },
16143
+ async execute({ scope, label, oldText, newText }) {
16144
+ const projectRoot = process.cwd();
16145
+ const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16146
+ const filePath = path2.join(dir, `${label}.md`);
16147
+ if (!fs2.existsSync(filePath)) {
16148
+ return JSON.stringify({
16149
+ success: false,
16150
+ error: `Memory block not found: ${scope}:${label}`
16151
+ }, null, 2);
16152
+ }
16153
+ const block = readMemoryBlock(filePath, scope);
16154
+ if (block.readOnly) {
16155
+ return JSON.stringify({
16156
+ success: false,
16157
+ error: `Memory block "${scope}:${label}" is read-only`
16158
+ }, null, 2);
16159
+ }
16160
+ if (!block.value.includes(oldText)) {
16161
+ return JSON.stringify({
16162
+ success: false,
16163
+ error: `Text not found in "${scope}:${label}"`,
16164
+ hint: "The oldText must match exactly. Try copying from hive_memory_list output."
16165
+ }, null, 2);
16166
+ }
16167
+ const newValue = block.value.replace(oldText, newText);
16168
+ if (newValue.length > block.limit) {
16169
+ return JSON.stringify({
16170
+ success: false,
16171
+ error: `Replacement would exceed limit (${newValue.length} > ${block.limit})`
16172
+ }, null, 2);
16173
+ }
16174
+ const content = buildFrontmatter({
16175
+ label: block.label,
16176
+ description: block.description,
16177
+ limit: block.limit,
16178
+ read_only: block.readOnly
16179
+ });
16180
+ fs2.writeFileSync(filePath, content + newValue + `
16181
+ `, "utf-8");
16182
+ return JSON.stringify({
16183
+ success: true,
16184
+ scope,
16185
+ label,
16186
+ charsReplaced: newValue.length
16187
+ }, null, 2);
16188
+ }
16189
+ });
16190
+ var hiveJournalWriteTool = tool({
16191
+ description: "Write a journal entry. Journal is append-only for capturing insights, decisions, and discoveries.",
16192
+ args: {
16193
+ title: tool.schema.string().describe("Title of the journal entry"),
16194
+ body: tool.schema.string().describe("Content of the journal entry"),
16195
+ tags: tool.schema.array(tool.schema.string()).optional().describe("Tags to categorize the entry")
16196
+ },
16197
+ async execute({ title, body, tags = [] }) {
16198
+ const projectRoot = process.cwd();
16199
+ const entry = writeJournalEntry(title, body, projectRoot, tags);
16200
+ return JSON.stringify({
16201
+ success: true,
16202
+ id: entry.id,
16203
+ title: entry.title,
16204
+ created: entry.created,
16205
+ message: "Journal entry written successfully"
16206
+ }, null, 2);
16207
+ }
16208
+ });
16209
+ var hiveJournalSearchTool = tool({
16210
+ description: "Search journal entries. Filter by text query, project, or tags.",
16211
+ args: {
16212
+ query: tool.schema.string().optional().describe("Text to search for in title and body"),
16213
+ project: tool.schema.string().optional().describe("Filter by project path"),
16214
+ tags: tool.schema.array(tool.schema.string()).optional().describe("Filter by tags"),
16215
+ limit: tool.schema.number().optional().describe("Maximum entries to return (default: 20)")
16216
+ },
16217
+ async execute({ query, project, tags, limit = 20 }) {
16218
+ const result = searchJournalEntries(query, project, limit);
16219
+ return JSON.stringify({
16220
+ total: result.total,
16221
+ returned: result.entries.length,
16222
+ entries: result.entries.map((e) => ({
16223
+ id: e.id,
16224
+ title: e.title,
16225
+ project: e.project,
16226
+ tags: e.tags,
16227
+ created: e.created,
16228
+ preview: e.body.slice(0, 200) + (e.body.length > 200 ? "..." : "")
16229
+ }))
16230
+ }, null, 2);
16231
+ }
16232
+ });
16233
+ async function buildMemoryInjection(projectRoot) {
16234
+ await ensureMemorySeeded(projectRoot);
16235
+ const globalBlocks = listMemoryBlocks("global", projectRoot);
16236
+ const projectBlocks = listMemoryBlocks("project", projectRoot);
16237
+ if (globalBlocks.length === 0 && projectBlocks.length === 0) {
16238
+ return "";
16239
+ }
16240
+ const sections = [];
16241
+ sections.push("<memory_instructions>");
16242
+ sections.push("You have access to persistent memory blocks that survive across sessions.");
16243
+ sections.push(`Use memory tools to store important information, decisions, and preferences.
16244
+ `);
16245
+ if (globalBlocks.length > 0) {
16246
+ sections.push("## Global Memory (cross-project)");
16247
+ for (const block of globalBlocks) {
16248
+ sections.push(`
16249
+ ### ${block.label} (${block.charsCurrent}/${block.limit} chars)`);
16250
+ sections.push(`_${block.description}_`);
16251
+ sections.push(block.value || "(empty)");
16252
+ }
16253
+ }
16254
+ if (projectBlocks.length > 0) {
16255
+ sections.push(`
16256
+ ## Project Memory`);
16257
+ for (const block of projectBlocks) {
16258
+ sections.push(`
16259
+ ### ${block.label} (${block.charsCurrent}/${block.limit} chars)`);
16260
+ sections.push(`_${block.description}_`);
16261
+ sections.push(block.value || "(empty)");
16262
+ }
16263
+ }
16264
+ sections.push(`
16265
+ </memory_instructions>`);
16266
+ return sections.join(`
16267
+ `);
16268
+ }
16269
+
15848
16270
  // src/agents/hive.ts
15849
16271
  var QUEEN_BEE_PROMPT = `# Zetta (Hybrid)
15850
16272
 
@@ -16700,6 +17122,426 @@ Before verdict, mentally execute 2-3 tasks:
16700
17122
  - Focus on worker success, not perfection
16701
17123
  `;
16702
17124
 
17125
+ // src/agents/code-reviewer.ts
17126
+ var CODE_REVIEWER_PROMPT = `# Code Review Agent
17127
+
17128
+ You are in code review mode. Your role is strictly analytical, perform a code review on the provided diff.
17129
+
17130
+ ## Guidelines
17131
+
17132
+ - **Pragmatic over pedantic**: Flag real problems, not style preferences
17133
+ - **Evidence-based**: Every issue must be traceable to specific diff lines
17134
+ - **Actionable**: Every issue must have a clear path to resolution
17135
+ - **Production-minded**: Assume this code ships to users
17136
+
17137
+ ## Scope
17138
+
17139
+ ### CRITICAL FOCUS AREAS:
17140
+ 1. **Discipline:** Only review code that is part of the diff. Do not flag pre-existing issues in unchanged code.
17141
+ 2. **Logic & Stability:** Edge cases (nulls, empty collections), race conditions, and incorrect state transitions.
17142
+ 3. **Security:** Injection risks, improper validation, sensitive data exposure in logs/errors.
17143
+ 4. **Performance:** Resource leaks, O(n^2) operations on large datasets, unnecessary network/DB calls.
17144
+ 5. **Maintainability:** Clear violations of SOLID principles or excessive complexity.
17145
+ 6. **Convention:** AGENTS.md violation (only if AGENTS.md content is available)
17146
+
17147
+ ### SIMPLIFICATION FOCUS:
17148
+ Identify opportunities to simplify while preserving exact functionality:
17149
+ - Reduce unnecessary complexity and nesting
17150
+ - Remove redundant code/abstractions introduced by the change
17151
+ - Improve naming only when it prevents misunderstanding (not for preference)
17152
+ - Consolidate related logic when it increases readability
17153
+ - Avoid nested ternary operators; prefer if/else or switch
17154
+ - Remove comments that restate obvious code
17155
+ - Prefer explicit code over dense one-liners
17156
+
17157
+ ### OPERATIONAL RULES:
17158
+ - **No scope creep:** Do not propose refactors outside the diff unless required to fix a blocking issue.
17159
+ - **Evidence-Based Only:** Never flag "potential" issues without explaining *why* they would occur based on the code provided.
17160
+ - **AGENTS.md Protocol:** If \`AGENTS.md\` exists in the repo, check it for project-specific rules. If not found, ignore all AGENTS.md instructions.
17161
+ - **Zero-Noise Policy:** Do not comment on stylistic preferences (naming, formatting) unless they explicitly violate a rule in \`AGENTS.md\`.
17162
+ - **Safety First:** Every suggestion must be provably behavior-preserving. When in doubt, omit it.
17163
+ - **Non-stylistic simplification:** Simplification candidates must be justified by reduced complexity/duplication/nesting in the diff, not stylistic preference.
17164
+
17165
+ ## Output Format
17166
+
17167
+ ## Code review
17168
+
17169
+ ### Issues
17170
+ - A numbered list of blocking issues
17171
+ - Each issue MUST include:
17172
+ - reason: "bug" | "security" | "correctness" | "AGENTS.md adherence"
17173
+ - location: \`<path>::<symbol>\` or \`<path>::<global>\` + \`<lines>\` if available
17174
+ - evidence: quote the exact diff hunk lines
17175
+ - fix:
17176
+ - either a committable patch (max 5 lines per file)
17177
+ - or a concise, explicit instruction if a patch would exceed this limit
17178
+
17179
+ If no blocking issues are found, explicitly state:
17180
+ - "No blocking issues found."
17181
+
17182
+ ### Simplification candidates (optional)
17183
+ Include this section only if there are meaningful refactors that are clearly behavior-preserving.
17184
+ - A numbered list of candidates.
17185
+ - Each candidate MUST include:
17186
+ - goal: what clarity/maintainability improves
17187
+ - constraints: "no behavior change", and any diff-specific invariants (e.g., "preserve error messages", "keep API shape")
17188
+ - evidence: quote the exact diff hunk lines
17189
+ - location: \`<path>::<symbol>\` or \`<path>::<global>\` + \`<lines>\` if available
17190
+ - suggested change:
17191
+ - either a committable patch (max 5 lines per file)
17192
+ - or a concise refactor plan (if patch would exceed this limit)
17193
+ `;
17194
+
17195
+ // src/agents/code-simplifier.ts
17196
+ var CODE_SIMPLIFIER_PROMPT = `# Code Simplifier Agent
17197
+
17198
+ You are a code simplification agent. Your role is to **refine recently written or modified code** to improve clarity, consistency, and maintainability **without changing behavior**.
17199
+
17200
+ This agent is intended to be triggered automatically **after a logical chunk of code has been written or modified** (feature implementation, bug fix, refactor, optimization).
17201
+
17202
+ You do not introduce new features, fix bugs, or change logic. You only improve how the code is expressed.
17203
+
17204
+ ## Core principles
17205
+
17206
+ ### 1. Behavior preservation (absolute rule)
17207
+ - Do **not** change observable behavior.
17208
+ - Do **not** change public APIs, function signatures, return values, error messages, or execution order.
17209
+ - Do **not** alter async behavior, side effects, or performance characteristics unless explicitly instructed.
17210
+ - If behavior preservation cannot be proven, **do not apply the change**.
17211
+
17212
+ ### 2. Scope discipline
17213
+ - Only simplify code that was **modified or introduced in the current session**.
17214
+ - This includes **untracked files** (new files not yet committed) listed in the working tree.
17215
+ - Do not refactor adjacent or pre-existing code unless strictly required to simplify the modified section.
17216
+ - No cross-file refactors unless the change itself spans multiple files.
17217
+
17218
+ ### 3. Clarity over cleverness
17219
+ Favor explicit, readable code over compact or "clever" solutions.
17220
+ - Prefer simple control flow over dense expressions.
17221
+ - Prefer explicit variable names over implicit meaning.
17222
+ - Prefer straightforward logic over abstractions introduced solely to reduce line count.
17223
+
17224
+ ## Simplification focus
17225
+
17226
+ Apply simplifications only when they clearly improve readability or maintainability:
17227
+
17228
+ - Reduce unnecessary nesting and branching.
17229
+ - Remove redundant checks, conversions, or temporary variables introduced by the change.
17230
+ - Consolidate closely related logic when it improves readability **without merging concerns**.
17231
+ - Avoid nested ternary operators; use \`if/else\` or \`switch\` for multi-branch logic.
17232
+ - Remove comments that restate obvious code; keep comments that explain intent or non-obvious decisions.
17233
+ - Improve naming **only** when current names cause ambiguity or misunderstanding (not for preference).
17234
+
17235
+ ## Project standards
17236
+
17237
+ - If a project standards file exists (e.g. \`CLAUDE.md\`, \`AGENTS.md\`), follow it.
17238
+ - If standards are not accessible, do **not** enforce stylistic conventions as rules.
17239
+ - Standards may guide simplification only when they clearly improve maintainability of the modified code.
17240
+
17241
+ ## Non-goals (do NOT do these)
17242
+ - Do not optimize performance unless simplification naturally preserves it.
17243
+ - Do not introduce new abstractions unless they clearly reduce complexity.
17244
+ - Do not refactor for consistency across the whole codebase.
17245
+ - Do not reformat code purely for style or aesthetics.
17246
+ - Do not rewrite working code "because it could be nicer".
17247
+
17248
+ ## Execution process
17249
+
17250
+ 1. Identify code that was added or modified in the current session, **including untracked files listed in the diff**.
17251
+ 2. **Read the content of untracked files** using the Read tool before analyzing them.
17252
+ 3. Analyze the code for unnecessary complexity, redundancy, or unclear structure.
17253
+ 4. Apply minimal, behavior-preserving refinements.
17254
+ 5. Re-check that functionality, outputs, and side effects are unchanged.
17255
+ 6. Produce the simplified code.
17256
+
17257
+ ## Output requirements
17258
+
17259
+ - Apply changes directly to the code.
17260
+ - Keep changes minimal and localized.
17261
+ - If no meaningful simplification is possible, make no changes.
17262
+ - If a change could be controversial or borderline, prefer omission.
17263
+
17264
+ Your goal is not to "clean everything", but to ensure that **newly written code enters the codebase at a high standard of clarity and maintainability**, without risk.
17265
+ `;
17266
+
17267
+ // src/agents/codebase-locator.ts
17268
+ var CODEBASE_LOCATOR_PROMPT = `# Codebase Locator Agent
17269
+
17270
+ You are a SUBAGENT for finding file locations in the codebase.
17271
+
17272
+ ## Purpose
17273
+ Find WHERE files live. No content analysis, no suggestions, no opinions, just locations.
17274
+
17275
+ ## Rules
17276
+
17277
+ - Return file paths only
17278
+ - Organize results by logical category
17279
+ - Be exhaustive - find ALL relevant files
17280
+ - Include test files when relevant
17281
+ - Include config files when relevant
17282
+
17283
+ ## Search Strategies
17284
+
17285
+ - **by-name**: Glob for file names
17286
+ - **by-content**: Grep for specific terms, imports, usage
17287
+ - **by-convention**: Check standard locations (src/, lib/, tests/, config/)
17288
+ - **by-extension**: Filter by file type
17289
+ - **by-import**: Find files that import/export a symbol
17290
+
17291
+ ## Categories
17292
+
17293
+ - Source files
17294
+ - Test files
17295
+ - Type definitions
17296
+ - Configuration
17297
+ - Documentation
17298
+ - Scripts
17299
+
17300
+ ## Output Format
17301
+
17302
+ ## Source Files
17303
+ - path/to/file.ts
17304
+ - path/to/another.ts
17305
+
17306
+ ## Tests
17307
+ - path/to/file.test.ts
17308
+ - path/to/another.spec.ts
17309
+
17310
+ ## Config
17311
+ - path/to/config.json
17312
+ - path/to/tsconfig.json
17313
+ `;
17314
+
17315
+ // src/agents/codebase-analyzer.ts
17316
+ var CODEBASE_ANALYZER_PROMPT = `# Codebase Analyzer Agent
17317
+
17318
+ You are a SUBAGENT for analyzing and explaining code behavior.
17319
+
17320
+ ## Purpose
17321
+ Explain HOW code works. Document what IS, not what SHOULD BE.
17322
+
17323
+ ## Rules
17324
+
17325
+ - Always include file:line references
17326
+ - Read files COMPLETELY - never use limit/offset
17327
+ - Describe behavior, not quality
17328
+ - No suggestions, no improvements, no opinions
17329
+ - Trace actual execution paths, not assumptions
17330
+ - Include error handling paths
17331
+ - Document side effects explicitly
17332
+ - Note any external dependencies called
17333
+
17334
+ ## Process
17335
+
17336
+ 1. Identify entry points
17337
+ 2. Read all relevant files completely
17338
+ 3. Trace data flow step by step
17339
+ 4. Trace control flow (conditionals, loops, early returns)
17340
+ 5. Document function calls with their locations
17341
+ 6. Note state mutations and side effects
17342
+ 7. Map error propagation paths
17343
+
17344
+ ## Output Format
17345
+
17346
+ ## [Component/Feature]
17347
+
17348
+ **Purpose**: [One sentence]
17349
+
17350
+ **Entry point**: \`file:line\`
17351
+
17352
+ **Data flow**:
17353
+ 1. \`file:line\` - [what happens]
17354
+ 2. \`file:line\` - [next step]
17355
+ 3. \`file:line\` - [continues...]
17356
+
17357
+ **Key functions**:
17358
+ - \`functionName\` at \`file:line\` - [what it does]
17359
+ - \`anotherFn\` at \`file:line\` - [what it does]
17360
+
17361
+ **State mutations**:
17362
+ - \`file:line\` - [what changes]
17363
+
17364
+ **Error paths**:
17365
+ - \`file:line\` - [error condition] → [handling]
17366
+
17367
+ **External calls**:
17368
+ - \`file:line\` - calls [external service/API]
17369
+
17370
+ ## Tracing Rules
17371
+
17372
+ - Follow imports to their source
17373
+ - Expand function calls inline when relevant
17374
+ - Note async boundaries explicitly
17375
+ - Track data transformations step by step
17376
+ - Document callback and event flows
17377
+ - Include middleware/interceptor chains
17378
+ `;
17379
+
17380
+ // src/agents/pattern-finder.ts
17381
+ var PATTERN_FINDER_PROMPT = `# Pattern Finder Agent
17382
+
17383
+ You are a SUBAGENT for finding coding patterns and conventions.
17384
+
17385
+ ## Purpose
17386
+ Find existing patterns in the codebase to model after. Show, don't tell.
17387
+
17388
+ ## Rules
17389
+
17390
+ - Provide concrete code examples, not abstract descriptions
17391
+ - Always include file:line references
17392
+ - Show 2-3 best examples, not exhaustive lists
17393
+ - Include enough context to understand usage
17394
+ - Prioritize recent/maintained code over legacy
17395
+ - Include test examples when available
17396
+ - Note any variations of the pattern
17397
+
17398
+ ## What to Find
17399
+
17400
+ - How similar features are implemented
17401
+ - Naming conventions used
17402
+ - Error handling patterns
17403
+ - Testing patterns
17404
+ - File organization patterns
17405
+ - Import/export patterns
17406
+ - Configuration patterns
17407
+ - API patterns (routes, handlers, responses)
17408
+
17409
+ ## Search Process
17410
+
17411
+ 1. Grep for similar implementations
17412
+ 2. Check test files for usage examples
17413
+ 3. Look for documentation or comments
17414
+ 4. Find the most representative example
17415
+ 5. Find variations if they exist
17416
+
17417
+ ## Output Format
17418
+
17419
+ ## Pattern: [Name]
17420
+
17421
+ **Best example**: \`file:line-line\`
17422
+ \`\`\`language
17423
+ [code snippet]
17424
+ \`\`\`
17425
+
17426
+ **Also see**:
17427
+ - \`file:line\` - [variation/alternative]
17428
+
17429
+ **Usage notes**: [when/how to apply]
17430
+
17431
+ ## Quality Criteria
17432
+
17433
+ - Prefer patterns with tests
17434
+ - Prefer patterns that are widely used
17435
+ - Prefer recent over old
17436
+ - Prefer simple over complex
17437
+ - Note if pattern seems inconsistent across codebase
17438
+ `;
17439
+
17440
+ // src/agents/project-initializer.ts
17441
+ var PROJECT_INITIALIZER_PROMPT = `# Project Initializer Agent
17442
+
17443
+ You are a SUBAGENT - use task tool to spawn other subagents for parallel execution.
17444
+
17445
+ ## Purpose
17446
+ Rapidly analyze any project and generate ARCHITECTURE.md and CODE_STYLE.md
17447
+
17448
+ ## Critical Rule
17449
+ MAXIMIZE PARALLELISM. Speed is critical.
17450
+ - Call multiple task tools in ONE message for parallel execution
17451
+ - Never wait for one thing when you can do many
17452
+
17453
+ ## Task
17454
+ Generate two documentation files that help AI agents understand this codebase:
17455
+ - ARCHITECTURE.md - Project structure, components, and data flow
17456
+ - CODE_STYLE.md - Coding conventions, patterns, and guidelines
17457
+
17458
+ ## Parallel Execution Strategy
17459
+
17460
+ ### Phase 1: Discovery
17461
+ Launch ALL discovery in ONE message:
17462
+ - Glob for entry points, configs, main modules
17463
+ - Glob for test files and test patterns
17464
+ - Glob for linter, formatter, CI configs
17465
+ - Use grep to find key patterns
17466
+
17467
+ ### Phase 2: Deep Analysis
17468
+ Based on discovery:
17469
+ - Read 5 core source files simultaneously
17470
+ - Read 3 test files simultaneously
17471
+ - Read config files simultaneously
17472
+
17473
+ ### Phase 3: Write Output Files
17474
+ - Write ARCHITECTURE.md
17475
+ - Write CODE_STYLE.md
17476
+
17477
+ ## Available Subagents
17478
+
17479
+ Use task tool to spawn subagents:
17480
+ - **codebase-locator**: Fast file/pattern finder
17481
+ - **codebase-analyzer**: Deep module analyzer
17482
+ - **pattern-finder**: Pattern extractor
17483
+
17484
+ ## Language Detection
17485
+
17486
+ Identify language(s) by examining file extensions and config files:
17487
+ - Python: pyproject.toml, setup.py, requirements.txt, *.py
17488
+ - JavaScript/TypeScript: package.json, tsconfig.json, *.js, *.ts, *.tsx
17489
+ - Go: go.mod, go.sum, *.go
17490
+ - Rust: Cargo.toml, *.rs
17491
+ - Java: pom.xml, build.gradle, *.java
17492
+
17493
+ ## Architecture Analysis
17494
+
17495
+ Answer these questions:
17496
+ - What does this project do? (purpose)
17497
+ - What are the main entry points?
17498
+ - How is the code organized? (modules, packages, layers)
17499
+ - What are the core abstractions?
17500
+ - How does data flow through the system?
17501
+ - What external services does it integrate with?
17502
+ - How is configuration managed?
17503
+ - What's the deployment model?
17504
+
17505
+ ## Code Style Analysis
17506
+
17507
+ Answer these questions:
17508
+ - How are files and directories named?
17509
+ - How are functions, classes, variables named?
17510
+ - What patterns are used consistently?
17511
+ - How are errors handled?
17512
+ - How is logging done?
17513
+ - What testing patterns are used?
17514
+ - Are there linter/formatter configs to reference?
17515
+
17516
+ ## Output Requirements
17517
+
17518
+ - ARCHITECTURE.md should let someone understand the system in 5 minutes
17519
+ - CODE_STYLE.md should let someone write conforming code immediately
17520
+ - Keep total size under 500 lines per file
17521
+ - Use bullet points and tables over prose
17522
+ - Include file paths for everything you reference
17523
+
17524
+ ## Execution Steps
17525
+
17526
+ 1. **Discovery** (parallel):
17527
+ - Glob for package.json, pyproject.toml, go.mod, Cargo.toml
17528
+ - Glob for *.config.*, .eslintrc*, .prettierrc*
17529
+ - Glob for README*, CONTRIBUTING*
17530
+ - Read root directory listing
17531
+ - Use task to spawn codebase-locator for entry points
17532
+ - Use task to spawn codebase-locator for test files
17533
+ - Use task to spawn codebase-locator for config files
17534
+
17535
+ 2. **Deep Analysis** (parallel):
17536
+ - Read multiple source files
17537
+ - Use task to spawn codebase-analyzer for core modules
17538
+ - Use task to spawn pattern-finder for conventions
17539
+
17540
+ 3. **Write output files**:
17541
+ - Write ARCHITECTURE.md
17542
+ - Write CODE_STYLE.md
17543
+ `;
17544
+
16703
17545
  // src/agents/custom-agents.ts
16704
17546
  function buildCustomSubagents({
16705
17547
  customAgents,
@@ -16772,15 +17614,15 @@ var createBuiltinMcps = (disabledMcps = []) => {
16772
17614
 
16773
17615
  // ../hive-core/dist/index.js
16774
17616
  import { createRequire as createRequire2 } from "node:module";
16775
- import * as path2 from "path";
16776
- import * as fs2 from "fs";
17617
+ import * as path3 from "path";
17618
+ import * as fs3 from "fs";
16777
17619
  import * as path22 from "path";
16778
17620
  import * as fs22 from "fs";
16779
- import * as fs3 from "fs";
17621
+ import * as fs32 from "fs";
16780
17622
  import * as fs4 from "fs";
16781
17623
  import * as fs5 from "fs";
16782
17624
  import * as fs7 from "fs/promises";
16783
- import * as path3 from "path";
17625
+ import * as path32 from "path";
16784
17626
  import { Buffer as Buffer2 } from "node:buffer";
16785
17627
  import { spawn } from "child_process";
16786
17628
  import { normalize } from "node:path";
@@ -16792,7 +17634,7 @@ import * as path6 from "path";
16792
17634
  import * as fs11 from "fs";
16793
17635
  import * as path7 from "path";
16794
17636
  import { existsSync as existsSync5 } from "fs";
16795
- import { join as join8, sep } from "path";
17637
+ import { join as join82, sep } from "path";
16796
17638
  import { execSync } from "child_process";
16797
17639
  var __create = Object.create;
16798
17640
  var __getProtoOf = Object.getPrototypeOf;
@@ -17451,10 +18293,10 @@ var require_src2 = __commonJS((exports) => {
17451
18293
  var fs_1 = __require2("fs");
17452
18294
  var debug_1 = __importDefault(require_src());
17453
18295
  var log = debug_1.default("@kwsites/file-exists");
17454
- function check2(path32, isFile, isDirectory) {
17455
- log(`checking %s`, path32);
18296
+ function check2(path33, isFile, isDirectory) {
18297
+ log(`checking %s`, path33);
17456
18298
  try {
17457
- const stat2 = fs_1.statSync(path32);
18299
+ const stat2 = fs_1.statSync(path33);
17458
18300
  if (stat2.isFile() && isFile) {
17459
18301
  log(`[OK] path represents a file`);
17460
18302
  return true;
@@ -17474,8 +18316,8 @@ var require_src2 = __commonJS((exports) => {
17474
18316
  throw e;
17475
18317
  }
17476
18318
  }
17477
- function exists(path32, type = exports.READABLE) {
17478
- return check2(path32, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
18319
+ function exists(path33, type = exports.READABLE) {
18320
+ return check2(path33, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
17479
18321
  }
17480
18322
  exports.exists = exists;
17481
18323
  exports.FILE = 1;
@@ -17616,6 +18458,19 @@ var DEFAULT_HIVE_CONFIG = {
17616
18458
  skills: [],
17617
18459
  autoLoadSkills: []
17618
18460
  }
18461
+ },
18462
+ tokenTruncation: {
18463
+ enabled: true,
18464
+ maxChars: 30000,
18465
+ keepFirstPercent: 40,
18466
+ keepLastPercent: 40
18467
+ },
18468
+ sessionSnapshot: {
18469
+ enabled: true,
18470
+ maxSnapshotChars: 2048,
18471
+ includeActiveFeature: true,
18472
+ includePendingTasks: true,
18473
+ includeModifiedFiles: false
17619
18474
  }
17620
18475
  };
17621
18476
  var HIVE_DIR = ".hive";
@@ -17632,78 +18487,78 @@ function normalizePath(filePath) {
17632
18487
  return filePath.replace(/\\/g, "/");
17633
18488
  }
17634
18489
  function getHivePath(projectRoot) {
17635
- return path2.join(projectRoot, HIVE_DIR);
18490
+ return path3.join(projectRoot, HIVE_DIR);
17636
18491
  }
17637
18492
  function getFeaturesPath(projectRoot) {
17638
- return path2.join(getHivePath(projectRoot), FEATURES_DIR);
18493
+ return path3.join(getHivePath(projectRoot), FEATURES_DIR);
17639
18494
  }
17640
18495
  function getFeaturePath(projectRoot, featureName) {
17641
- return path2.join(getFeaturesPath(projectRoot), featureName);
18496
+ return path3.join(getFeaturesPath(projectRoot), featureName);
17642
18497
  }
17643
18498
  function getPlanPath(projectRoot, featureName) {
17644
- return path2.join(getFeaturePath(projectRoot, featureName), PLAN_FILE);
18499
+ return path3.join(getFeaturePath(projectRoot, featureName), PLAN_FILE);
17645
18500
  }
17646
18501
  function getCommentsPath(projectRoot, featureName) {
17647
- return path2.join(getFeaturePath(projectRoot, featureName), COMMENTS_FILE);
18502
+ return path3.join(getFeaturePath(projectRoot, featureName), COMMENTS_FILE);
17648
18503
  }
17649
18504
  function getFeatureJsonPath(projectRoot, featureName) {
17650
- return path2.join(getFeaturePath(projectRoot, featureName), FEATURE_FILE);
18505
+ return path3.join(getFeaturePath(projectRoot, featureName), FEATURE_FILE);
17651
18506
  }
17652
18507
  function getContextPath(projectRoot, featureName) {
17653
- return path2.join(getFeaturePath(projectRoot, featureName), CONTEXT_DIR);
18508
+ return path3.join(getFeaturePath(projectRoot, featureName), CONTEXT_DIR);
17654
18509
  }
17655
18510
  function getTasksPath(projectRoot, featureName) {
17656
- return path2.join(getFeaturePath(projectRoot, featureName), TASKS_DIR);
18511
+ return path3.join(getFeaturePath(projectRoot, featureName), TASKS_DIR);
17657
18512
  }
17658
18513
  function getTaskPath(projectRoot, featureName, taskFolder) {
17659
- return path2.join(getTasksPath(projectRoot, featureName), taskFolder);
18514
+ return path3.join(getTasksPath(projectRoot, featureName), taskFolder);
17660
18515
  }
17661
18516
  function getTaskStatusPath(projectRoot, featureName, taskFolder) {
17662
- return path2.join(getTaskPath(projectRoot, featureName, taskFolder), STATUS_FILE);
18517
+ return path3.join(getTaskPath(projectRoot, featureName, taskFolder), STATUS_FILE);
17663
18518
  }
17664
18519
  function getTaskReportPath(projectRoot, featureName, taskFolder) {
17665
- return path2.join(getTaskPath(projectRoot, featureName, taskFolder), REPORT_FILE);
18520
+ return path3.join(getTaskPath(projectRoot, featureName, taskFolder), REPORT_FILE);
17666
18521
  }
17667
18522
  function getTaskSpecPath(projectRoot, featureName, taskFolder) {
17668
- return path2.join(getTaskPath(projectRoot, featureName, taskFolder), "spec.md");
18523
+ return path3.join(getTaskPath(projectRoot, featureName, taskFolder), "spec.md");
17669
18524
  }
17670
18525
  function getApprovedPath(projectRoot, featureName) {
17671
- return path2.join(getFeaturePath(projectRoot, featureName), APPROVED_FILE);
18526
+ return path3.join(getFeaturePath(projectRoot, featureName), APPROVED_FILE);
17672
18527
  }
17673
18528
  var SUBTASKS_DIR = "subtasks";
17674
18529
  var SPEC_FILE = "spec.md";
17675
18530
  function getSubtasksPath(projectRoot, featureName, taskFolder) {
17676
- return path2.join(getTaskPath(projectRoot, featureName, taskFolder), SUBTASKS_DIR);
18531
+ return path3.join(getTaskPath(projectRoot, featureName, taskFolder), SUBTASKS_DIR);
17677
18532
  }
17678
18533
  function getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder) {
17679
- return path2.join(getSubtasksPath(projectRoot, featureName, taskFolder), subtaskFolder);
18534
+ return path3.join(getSubtasksPath(projectRoot, featureName, taskFolder), subtaskFolder);
17680
18535
  }
17681
18536
  function getSubtaskStatusPath(projectRoot, featureName, taskFolder, subtaskFolder) {
17682
- return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), STATUS_FILE);
18537
+ return path3.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), STATUS_FILE);
17683
18538
  }
17684
18539
  function getSubtaskSpecPath(projectRoot, featureName, taskFolder, subtaskFolder) {
17685
- return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), SPEC_FILE);
18540
+ return path3.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), SPEC_FILE);
17686
18541
  }
17687
18542
  function getSubtaskReportPath(projectRoot, featureName, taskFolder, subtaskFolder) {
17688
- return path2.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
18543
+ return path3.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
17689
18544
  }
17690
18545
  function ensureDir(dirPath) {
17691
- if (!fs2.existsSync(dirPath)) {
17692
- fs2.mkdirSync(dirPath, { recursive: true });
18546
+ if (!fs3.existsSync(dirPath)) {
18547
+ fs3.mkdirSync(dirPath, { recursive: true });
17693
18548
  }
17694
18549
  }
17695
18550
  function fileExists(filePath) {
17696
- return fs2.existsSync(filePath);
18551
+ return fs3.existsSync(filePath);
17697
18552
  }
17698
18553
  function readJson(filePath) {
17699
- if (!fs2.existsSync(filePath))
18554
+ if (!fs3.existsSync(filePath))
17700
18555
  return null;
17701
- const content = fs2.readFileSync(filePath, "utf-8");
18556
+ const content = fs3.readFileSync(filePath, "utf-8");
17702
18557
  return JSON.parse(content);
17703
18558
  }
17704
18559
  function writeJson(filePath, data) {
17705
- ensureDir(path2.dirname(filePath));
17706
- fs2.writeFileSync(filePath, JSON.stringify(data, null, 2));
18560
+ ensureDir(path3.dirname(filePath));
18561
+ fs3.writeFileSync(filePath, JSON.stringify(data, null, 2));
17707
18562
  }
17708
18563
  var DEFAULT_LOCK_OPTIONS = {
17709
18564
  timeout: 5000,
@@ -17715,7 +18570,7 @@ function getLockPath(filePath) {
17715
18570
  }
17716
18571
  function isLockStale(lockPath, staleTTL) {
17717
18572
  try {
17718
- const stat2 = fs2.statSync(lockPath);
18573
+ const stat2 = fs3.statSync(lockPath);
17719
18574
  const age = Date.now() - stat2.mtimeMs;
17720
18575
  return age > staleTTL;
17721
18576
  } catch {
@@ -17725,7 +18580,7 @@ function isLockStale(lockPath, staleTTL) {
17725
18580
  function acquireLockSync(filePath, options = {}) {
17726
18581
  const opts = { ...DEFAULT_LOCK_OPTIONS, ...options };
17727
18582
  const lockPath = getLockPath(filePath);
17728
- const lockDir = path2.dirname(lockPath);
18583
+ const lockDir = path3.dirname(lockPath);
17729
18584
  const startTime = Date.now();
17730
18585
  const lockContent = JSON.stringify({
17731
18586
  pid: process.pid,
@@ -17735,12 +18590,12 @@ function acquireLockSync(filePath, options = {}) {
17735
18590
  ensureDir(lockDir);
17736
18591
  while (true) {
17737
18592
  try {
17738
- const fd = fs2.openSync(lockPath, fs2.constants.O_CREAT | fs2.constants.O_EXCL | fs2.constants.O_WRONLY);
17739
- fs2.writeSync(fd, lockContent);
17740
- fs2.closeSync(fd);
18593
+ const fd = fs3.openSync(lockPath, fs3.constants.O_CREAT | fs3.constants.O_EXCL | fs3.constants.O_WRONLY);
18594
+ fs3.writeSync(fd, lockContent);
18595
+ fs3.closeSync(fd);
17741
18596
  return () => {
17742
18597
  try {
17743
- fs2.unlinkSync(lockPath);
18598
+ fs3.unlinkSync(lockPath);
17744
18599
  } catch {}
17745
18600
  };
17746
18601
  } catch (err) {
@@ -17750,7 +18605,7 @@ function acquireLockSync(filePath, options = {}) {
17750
18605
  } else if (error45.code === "EEXIST") {
17751
18606
  if (isLockStale(lockPath, opts.staleLockTTL)) {
17752
18607
  try {
17753
- fs2.unlinkSync(lockPath);
18608
+ fs3.unlinkSync(lockPath);
17754
18609
  continue;
17755
18610
  } catch {}
17756
18611
  }
@@ -17766,14 +18621,14 @@ function acquireLockSync(filePath, options = {}) {
17766
18621
  }
17767
18622
  }
17768
18623
  function writeAtomic(filePath, content) {
17769
- ensureDir(path2.dirname(filePath));
18624
+ ensureDir(path3.dirname(filePath));
17770
18625
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
17771
18626
  try {
17772
- fs2.writeFileSync(tempPath, content);
17773
- fs2.renameSync(tempPath, filePath);
18627
+ fs3.writeFileSync(tempPath, content);
18628
+ fs3.renameSync(tempPath, filePath);
17774
18629
  } catch (error45) {
17775
18630
  try {
17776
- fs2.unlinkSync(tempPath);
18631
+ fs3.unlinkSync(tempPath);
17777
18632
  } catch {}
17778
18633
  throw error45;
17779
18634
  }
@@ -17808,13 +18663,13 @@ function patchJsonLockedSync(filePath, patch, options = {}) {
17808
18663
  }
17809
18664
  }
17810
18665
  function readText(filePath) {
17811
- if (!fs2.existsSync(filePath))
18666
+ if (!fs3.existsSync(filePath))
17812
18667
  return null;
17813
- return fs2.readFileSync(filePath, "utf-8");
18668
+ return fs3.readFileSync(filePath, "utf-8");
17814
18669
  }
17815
18670
  function writeText(filePath, content) {
17816
- ensureDir(path2.dirname(filePath));
17817
- fs2.writeFileSync(filePath, content);
18671
+ ensureDir(path3.dirname(filePath));
18672
+ fs3.writeFileSync(filePath, content);
17818
18673
  }
17819
18674
  function detectContext(cwd) {
17820
18675
  const result = {
@@ -17896,7 +18751,7 @@ class FeatureService {
17896
18751
  const featuresPath = getFeaturesPath(this.projectRoot);
17897
18752
  if (!fileExists(featuresPath))
17898
18753
  return [];
17899
- return fs3.readdirSync(featuresPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
18754
+ return fs32.readdirSync(featuresPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
17900
18755
  }
17901
18756
  getActive() {
17902
18757
  const features = this.list();
@@ -17942,7 +18797,7 @@ class FeatureService {
17942
18797
  const tasksPath = getTasksPath(this.projectRoot, featureName);
17943
18798
  if (!fileExists(tasksPath))
17944
18799
  return [];
17945
- const folders = fs3.readdirSync(tasksPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
18800
+ const folders = fs32.readdirSync(tasksPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
17946
18801
  return folders.map((folder) => {
17947
18802
  const statusPath = `${tasksPath}/${folder}/status.json`;
17948
18803
  const status = readJson(statusPath);
@@ -18272,20 +19127,20 @@ ${f.content}`).join(`
18272
19127
  return [task.order - 1];
18273
19128
  };
18274
19129
  const visited = new Map;
18275
- const path32 = [];
19130
+ const path33 = [];
18276
19131
  const dfs = (taskOrder) => {
18277
19132
  const state = visited.get(taskOrder);
18278
19133
  if (state === 2) {
18279
19134
  return;
18280
19135
  }
18281
19136
  if (state === 1) {
18282
- const cycleStart = path32.indexOf(taskOrder);
18283
- const cyclePath = [...path32.slice(cycleStart), taskOrder];
19137
+ const cycleStart = path33.indexOf(taskOrder);
19138
+ const cyclePath = [...path33.slice(cycleStart), taskOrder];
18284
19139
  const cycleDesc = cyclePath.join(" -> ");
18285
19140
  throw new Error(`Invalid dependency graph in plan.md: Cycle detected in task dependencies: ${cycleDesc}. ` + `Tasks cannot have circular dependencies. Please fix the "Depends on:" lines in plan.md.`);
18286
19141
  }
18287
19142
  visited.set(taskOrder, 1);
18288
- path32.push(taskOrder);
19143
+ path33.push(taskOrder);
18289
19144
  const task = taskByOrder.get(taskOrder);
18290
19145
  if (task) {
18291
19146
  const deps = getDependencies(task);
@@ -18293,7 +19148,7 @@ ${f.content}`).join(`
18293
19148
  dfs(depOrder);
18294
19149
  }
18295
19150
  }
18296
- path32.pop();
19151
+ path33.pop();
18297
19152
  visited.set(taskOrder, 2);
18298
19153
  };
18299
19154
  for (const task of tasks) {
@@ -18639,8 +19494,8 @@ function pathspec(...paths) {
18639
19494
  cache.set(key, paths);
18640
19495
  return key;
18641
19496
  }
18642
- function isPathSpec(path32) {
18643
- return path32 instanceof String && cache.has(path32);
19497
+ function isPathSpec(path33) {
19498
+ return path33 instanceof String && cache.has(path33);
18644
19499
  }
18645
19500
  function toPaths(pathSpec) {
18646
19501
  return cache.get(pathSpec) || [];
@@ -18726,8 +19581,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = `
18726
19581
  function forEachLineWithContent(input, callback) {
18727
19582
  return toLinesWithContent(input, true).map((line) => callback(line));
18728
19583
  }
18729
- function folderExists(path32) {
18730
- return import_file_exists.exists(path32, import_file_exists.FOLDER);
19584
+ function folderExists(path33) {
19585
+ return import_file_exists.exists(path33, import_file_exists.FOLDER);
18731
19586
  }
18732
19587
  function append(target, item) {
18733
19588
  if (Array.isArray(target)) {
@@ -19118,8 +19973,8 @@ function checkIsRepoRootTask() {
19118
19973
  commands,
19119
19974
  format: "utf-8",
19120
19975
  onError,
19121
- parser(path32) {
19122
- return /^\.(git)?$/.test(path32.trim());
19976
+ parser(path33) {
19977
+ return /^\.(git)?$/.test(path33.trim());
19123
19978
  }
19124
19979
  };
19125
19980
  }
@@ -19530,11 +20385,11 @@ function parseGrep(grep) {
19530
20385
  const paths = /* @__PURE__ */ new Set;
19531
20386
  const results = {};
19532
20387
  forEachLineWithContent(grep, (input) => {
19533
- const [path32, line, preview] = input.split(NULL);
19534
- paths.add(path32);
19535
- (results[path32] = results[path32] || []).push({
20388
+ const [path33, line, preview] = input.split(NULL);
20389
+ paths.add(path33);
20390
+ (results[path33] = results[path33] || []).push({
19536
20391
  line: asNumber(line),
19537
- path: path32,
20392
+ path: path33,
19538
20393
  preview
19539
20394
  });
19540
20395
  });
@@ -20200,14 +21055,14 @@ var init_hash_object = __esm2({
20200
21055
  init_task();
20201
21056
  }
20202
21057
  });
20203
- function parseInit(bare, path32, text) {
21058
+ function parseInit(bare, path33, text) {
20204
21059
  const response = String(text).trim();
20205
21060
  let result;
20206
21061
  if (result = initResponseRegex.exec(response)) {
20207
- return new InitSummary(bare, path32, false, result[1]);
21062
+ return new InitSummary(bare, path33, false, result[1]);
20208
21063
  }
20209
21064
  if (result = reInitResponseRegex.exec(response)) {
20210
- return new InitSummary(bare, path32, true, result[1]);
21065
+ return new InitSummary(bare, path33, true, result[1]);
20211
21066
  }
20212
21067
  let gitDir = "";
20213
21068
  const tokens = response.split(" ");
@@ -20218,7 +21073,7 @@ function parseInit(bare, path32, text) {
20218
21073
  break;
20219
21074
  }
20220
21075
  }
20221
- return new InitSummary(bare, path32, /^re/i.test(response), gitDir);
21076
+ return new InitSummary(bare, path33, /^re/i.test(response), gitDir);
20222
21077
  }
20223
21078
  var InitSummary;
20224
21079
  var initResponseRegex;
@@ -20226,9 +21081,9 @@ var reInitResponseRegex;
20226
21081
  var init_InitSummary = __esm2({
20227
21082
  "src/lib/responses/InitSummary.ts"() {
20228
21083
  InitSummary = class {
20229
- constructor(bare, path32, existing, gitDir) {
21084
+ constructor(bare, path33, existing, gitDir) {
20230
21085
  this.bare = bare;
20231
- this.path = path32;
21086
+ this.path = path33;
20232
21087
  this.existing = existing;
20233
21088
  this.gitDir = gitDir;
20234
21089
  }
@@ -20240,7 +21095,7 @@ var init_InitSummary = __esm2({
20240
21095
  function hasBareCommand(command) {
20241
21096
  return command.includes(bareCommand);
20242
21097
  }
20243
- function initTask(bare = false, path32, customArgs) {
21098
+ function initTask(bare = false, path33, customArgs) {
20244
21099
  const commands = ["init", ...customArgs];
20245
21100
  if (bare && !hasBareCommand(commands)) {
20246
21101
  commands.splice(1, 0, bareCommand);
@@ -20249,7 +21104,7 @@ function initTask(bare = false, path32, customArgs) {
20249
21104
  commands,
20250
21105
  format: "utf-8",
20251
21106
  parser(text) {
20252
- return parseInit(commands.includes("--bare"), path32, text);
21107
+ return parseInit(commands.includes("--bare"), path33, text);
20253
21108
  }
20254
21109
  };
20255
21110
  }
@@ -20964,12 +21819,12 @@ var init_FileStatusSummary = __esm2({
20964
21819
  "src/lib/responses/FileStatusSummary.ts"() {
20965
21820
  fromPathRegex = /^(.+)\0(.+)$/;
20966
21821
  FileStatusSummary = class {
20967
- constructor(path32, index, working_dir) {
20968
- this.path = path32;
21822
+ constructor(path33, index, working_dir) {
21823
+ this.path = path33;
20969
21824
  this.index = index;
20970
21825
  this.working_dir = working_dir;
20971
21826
  if (index === "R" || working_dir === "R") {
20972
- const detail = fromPathRegex.exec(path32) || [null, path32, path32];
21827
+ const detail = fromPathRegex.exec(path33) || [null, path33, path33];
20973
21828
  this.from = detail[2] || "";
20974
21829
  this.path = detail[1] || "";
20975
21830
  }
@@ -21000,14 +21855,14 @@ function splitLine(result, lineStr) {
21000
21855
  default:
21001
21856
  return;
21002
21857
  }
21003
- function data(index, workingDir, path32) {
21858
+ function data(index, workingDir, path33) {
21004
21859
  const raw = `${index}${workingDir}`;
21005
21860
  const handler = parsers6.get(raw);
21006
21861
  if (handler) {
21007
- handler(result, path32);
21862
+ handler(result, path33);
21008
21863
  }
21009
21864
  if (raw !== "##" && raw !== "!!") {
21010
- result.files.push(new FileStatusSummary(path32, index, workingDir));
21865
+ result.files.push(new FileStatusSummary(path33, index, workingDir));
21011
21866
  }
21012
21867
  }
21013
21868
  }
@@ -21291,8 +22146,8 @@ var init_simple_git_api = __esm2({
21291
22146
  }
21292
22147
  return this._runTask(configurationErrorTask("Git.cwd: workingDirectory must be supplied as a string"), next);
21293
22148
  }
21294
- hashObject(path32, write) {
21295
- return this._runTask(hashObjectTask(path32, write === true), trailingFunctionArgument(arguments));
22149
+ hashObject(path33, write) {
22150
+ return this._runTask(hashObjectTask(path33, write === true), trailingFunctionArgument(arguments));
21296
22151
  }
21297
22152
  init(bare) {
21298
22153
  return this._runTask(initTask(bare === true, this._executor.cwd, getTrailingOptions(arguments)), trailingFunctionArgument(arguments));
@@ -21585,8 +22440,8 @@ var init_branch = __esm2({
21585
22440
  }
21586
22441
  });
21587
22442
  function toPath(input) {
21588
- const path32 = input.trim().replace(/^["']|["']$/g, "");
21589
- return path32 && normalize(path32);
22443
+ const path33 = input.trim().replace(/^["']|["']$/g, "");
22444
+ return path33 && normalize(path33);
21590
22445
  }
21591
22446
  var parseCheckIgnore;
21592
22447
  var init_CheckIgnore = __esm2({
@@ -21851,8 +22706,8 @@ __export2(sub_module_exports, {
21851
22706
  subModuleTask: () => subModuleTask,
21852
22707
  updateSubModuleTask: () => updateSubModuleTask
21853
22708
  });
21854
- function addSubModuleTask(repo, path32) {
21855
- return subModuleTask(["add", repo, path32]);
22709
+ function addSubModuleTask(repo, path33) {
22710
+ return subModuleTask(["add", repo, path33]);
21856
22711
  }
21857
22712
  function initSubModuleTask(customArgs) {
21858
22713
  return subModuleTask(["init", ...customArgs]);
@@ -22106,8 +22961,8 @@ var require_git = __commonJS2({
22106
22961
  }
22107
22962
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
22108
22963
  };
22109
- Git2.prototype.submoduleAdd = function(repo, path32, then) {
22110
- return this._runTask(addSubModuleTask2(repo, path32), trailingFunctionArgument2(arguments));
22964
+ Git2.prototype.submoduleAdd = function(repo, path33, then) {
22965
+ return this._runTask(addSubModuleTask2(repo, path33), trailingFunctionArgument2(arguments));
22111
22966
  };
22112
22967
  Git2.prototype.submoduleUpdate = function(args2, then) {
22113
22968
  return this._runTask(updateSubModuleTask2(getTrailingOptions2(arguments, true)), trailingFunctionArgument2(arguments));
@@ -22640,19 +23495,19 @@ class WorktreeService {
22640
23495
  return esm_default(cwd || this.config.baseDir);
22641
23496
  }
22642
23497
  getWorktreesDir() {
22643
- return path3.join(this.config.hiveDir, ".worktrees");
23498
+ return path32.join(this.config.hiveDir, ".worktrees");
22644
23499
  }
22645
23500
  getWorktreePath(feature, step) {
22646
- return path3.join(this.getWorktreesDir(), feature, step);
23501
+ return path32.join(this.getWorktreesDir(), feature, step);
22647
23502
  }
22648
23503
  async getStepStatusPath(feature, step) {
22649
- const featurePath = path3.join(this.config.hiveDir, "features", feature);
22650
- const tasksPath = path3.join(featurePath, "tasks", step, "status.json");
23504
+ const featurePath = path32.join(this.config.hiveDir, "features", feature);
23505
+ const tasksPath = path32.join(featurePath, "tasks", step, "status.json");
22651
23506
  try {
22652
23507
  await fs7.access(tasksPath);
22653
23508
  return tasksPath;
22654
23509
  } catch {}
22655
- return path3.join(featurePath, "execution", step, "status.json");
23510
+ return path32.join(featurePath, "execution", step, "status.json");
22656
23511
  }
22657
23512
  getBranchName(feature, step) {
22658
23513
  return `hive/${feature}/${step}`;
@@ -22661,7 +23516,7 @@ class WorktreeService {
22661
23516
  const worktreePath = this.getWorktreePath(feature, step);
22662
23517
  const branchName = this.getBranchName(feature, step);
22663
23518
  const git = this.getGit();
22664
- await fs7.mkdir(path3.dirname(worktreePath), { recursive: true });
23519
+ await fs7.mkdir(path32.dirname(worktreePath), { recursive: true });
22665
23520
  const base = baseBranch || (await git.revparse(["HEAD"])).trim();
22666
23521
  const existing = await this.get(feature, step);
22667
23522
  if (existing) {
@@ -22756,7 +23611,7 @@ class WorktreeService {
22756
23611
  }
22757
23612
  async exportPatch(feature, step, baseBranch) {
22758
23613
  const worktreePath = this.getWorktreePath(feature, step);
22759
- const patchPath = path3.join(worktreePath, "..", `${step}.patch`);
23614
+ const patchPath = path32.join(worktreePath, "..", `${step}.patch`);
22760
23615
  const base = baseBranch || "HEAD~1";
22761
23616
  const worktreeGit = this.getGit(worktreePath);
22762
23617
  const diff = await worktreeGit.diff([`${base}...HEAD`]);
@@ -22768,7 +23623,7 @@ class WorktreeService {
22768
23623
  if (!hasDiff) {
22769
23624
  return { success: true, filesAffected: [] };
22770
23625
  }
22771
- const patchPath = path3.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
23626
+ const patchPath = path32.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
22772
23627
  try {
22773
23628
  await fs7.writeFile(patchPath, diffContent);
22774
23629
  const git = this.getGit();
@@ -22790,7 +23645,7 @@ class WorktreeService {
22790
23645
  if (!hasDiff) {
22791
23646
  return { success: true, filesAffected: [] };
22792
23647
  }
22793
- const patchPath = path3.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
23648
+ const patchPath = path32.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
22794
23649
  try {
22795
23650
  await fs7.writeFile(patchPath, diffContent);
22796
23651
  const git = this.getGit();
@@ -22859,7 +23714,7 @@ class WorktreeService {
22859
23714
  try {
22860
23715
  const features = feature ? [feature] : await fs7.readdir(worktreesDir);
22861
23716
  for (const feat of features) {
22862
- const featurePath = path3.join(worktreesDir, feat);
23717
+ const featurePath = path32.join(worktreesDir, feat);
22863
23718
  const stat2 = await fs7.stat(featurePath).catch(() => null);
22864
23719
  if (!stat2?.isDirectory())
22865
23720
  continue;
@@ -22883,13 +23738,13 @@ class WorktreeService {
22883
23738
  const worktreesDir = this.getWorktreesDir();
22884
23739
  const features = feature ? [feature] : await fs7.readdir(worktreesDir).catch(() => []);
22885
23740
  for (const feat of features) {
22886
- const featurePath = path3.join(worktreesDir, feat);
23741
+ const featurePath = path32.join(worktreesDir, feat);
22887
23742
  const stat2 = await fs7.stat(featurePath).catch(() => null);
22888
23743
  if (!stat2?.isDirectory())
22889
23744
  continue;
22890
23745
  const steps = await fs7.readdir(featurePath).catch(() => []);
22891
23746
  for (const step of steps) {
22892
- const worktreePath = path3.join(featurePath, step);
23747
+ const worktreePath = path32.join(featurePath, step);
22893
23748
  const stepStat = await fs7.stat(worktreePath).catch(() => null);
22894
23749
  if (!stepStat?.isDirectory())
22895
23750
  continue;
@@ -22909,7 +23764,7 @@ class WorktreeService {
22909
23764
  if (!hasDiff) {
22910
23765
  return [];
22911
23766
  }
22912
- const patchPath = path3.join(this.config.hiveDir, ".worktrees", feature, `${step}-check.patch`);
23767
+ const patchPath = path32.join(this.config.hiveDir, ".worktrees", feature, `${step}-check.patch`);
22913
23768
  try {
22914
23769
  await fs7.writeFile(patchPath, diffContent);
22915
23770
  const git = this.getGit();
@@ -23592,19 +24447,19 @@ class AgentsMdService {
23592
24447
 
23593
24448
  class DockerSandboxService {
23594
24449
  static detectImage(worktreePath) {
23595
- if (existsSync5(join8(worktreePath, "Dockerfile"))) {
24450
+ if (existsSync5(join82(worktreePath, "Dockerfile"))) {
23596
24451
  return null;
23597
24452
  }
23598
- if (existsSync5(join8(worktreePath, "package.json"))) {
24453
+ if (existsSync5(join82(worktreePath, "package.json"))) {
23599
24454
  return "node:22-slim";
23600
24455
  }
23601
- if (existsSync5(join8(worktreePath, "requirements.txt")) || existsSync5(join8(worktreePath, "pyproject.toml"))) {
24456
+ if (existsSync5(join82(worktreePath, "requirements.txt")) || existsSync5(join82(worktreePath, "pyproject.toml"))) {
23602
24457
  return "python:3.12-slim";
23603
24458
  }
23604
- if (existsSync5(join8(worktreePath, "go.mod"))) {
24459
+ if (existsSync5(join82(worktreePath, "go.mod"))) {
23605
24460
  return "golang:1.22-slim";
23606
24461
  }
23607
- if (existsSync5(join8(worktreePath, "Cargo.toml"))) {
24462
+ if (existsSync5(join82(worktreePath, "Cargo.toml"))) {
23608
24463
  return "rust:1.77-slim";
23609
24464
  }
23610
24465
  return "ubuntu:24.04";
@@ -24251,7 +25106,7 @@ async function buildAutoLoadedSkillsContent(agentName, configService, projectRoo
24251
25106
  if (autoLoadSkills.length === 0) {
24252
25107
  return "";
24253
25108
  }
24254
- const homeDir = process.env.HOME || os.homedir();
25109
+ const homeDir = process.env.HOME || os2.homedir();
24255
25110
  const skillTemplates = [];
24256
25111
  for (const skillId of autoLoadSkills) {
24257
25112
  const builtinSkill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
@@ -24794,6 +25649,10 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
24794
25649
  return;
24795
25650
  }
24796
25651
  output.system.push(HIVE_SYSTEM_PROMPT);
25652
+ const memoryInjection = await buildMemoryInjection(directory);
25653
+ if (memoryInjection) {
25654
+ output.system.push(memoryInjection);
25655
+ }
24797
25656
  const activeFeature = resolveFeature();
24798
25657
  if (activeFeature) {
24799
25658
  const info = featureService.getInfo(activeFeature);
@@ -24814,16 +25673,64 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
24814
25673
  }
24815
25674
  },
24816
25675
  "experimental.session.compacting": async (input, output) => {
25676
+ const snapshotConfig = configService.get().sessionSnapshot;
25677
+ const compressionConfig = configService.get().contextCompression;
25678
+ if (snapshotConfig?.enabled !== false) {
25679
+ const snapshotParts = [];
25680
+ const maxChars = snapshotConfig?.maxSnapshotChars ?? 2048;
25681
+ if (snapshotConfig?.includeActiveFeature !== false) {
25682
+ try {
25683
+ const active = featureService.getActive();
25684
+ if (active) {
25685
+ snapshotParts.push(`## Active Feature: ${active.name}`);
25686
+ snapshotParts.push(`Status: ${active.status}`);
25687
+ }
25688
+ } catch {}
25689
+ }
25690
+ if (snapshotConfig?.includePendingTasks !== false) {
25691
+ try {
25692
+ const featureNames = featureService.list();
25693
+ const pendingTasks = [];
25694
+ for (const name of featureNames) {
25695
+ const info = featureService.getInfo(name);
25696
+ if (info && info.status !== "completed") {
25697
+ const pending = info.tasks.filter((t) => t.status === "pending" || t.status === "in_progress");
25698
+ for (const task of pending) {
25699
+ pendingTasks.push(`- [${task.status}] ${task.name}`);
25700
+ }
25701
+ }
25702
+ }
25703
+ if (pendingTasks.length > 0) {
25704
+ snapshotParts.push(`
25705
+ ## Pending Tasks (${pendingTasks.length})`);
25706
+ snapshotParts.push(...pendingTasks.slice(0, 20));
25707
+ }
25708
+ } catch {}
25709
+ }
25710
+ if (snapshotParts.length > 0) {
25711
+ const snapshot = snapshotParts.join(`
25712
+ `).slice(0, maxChars);
25713
+ output.context.push(`
25714
+ ## Session Snapshot (before compaction)
25715
+
25716
+ ${snapshot}
25717
+
25718
+ **Important:** After compaction, resume from where you left off. Check the pending tasks above and continue working.
25719
+ `);
25720
+ }
25721
+ }
24817
25722
  const contextLimit = input.contextLimit || 200000;
24818
25723
  const messages = input.messages || [];
24819
25724
  if (messages.length > 0) {
24820
- const { estimateTokens: estimateTokens2, needsCompression: needsCompression2, compressContext: compressContext2, buildCompressionHint: buildCompressionHint2 } = await Promise.resolve().then(() => (init_context_compression(), exports_context_compression));
24821
- if (needsCompression2(messages, contextLimit, { threshold: 0.5, enabled: true })) {
24822
- const { compressed, stats } = compressContext2(messages, {
24823
- threshold: 0.5,
24824
- enabled: true,
24825
- maxToolCalls: 50,
24826
- protectedTools: [
25725
+ const { needsCompression: needsCompression2, compressContext: compressContext2, buildCompressionHint: buildCompressionHint2 } = await Promise.resolve().then(() => (init_context_compression(), exports_context_compression));
25726
+ const threshold = compressionConfig?.threshold ?? 0.5;
25727
+ const enabled = compressionConfig?.enabled ?? true;
25728
+ if (needsCompression2(messages, contextLimit, { threshold, enabled })) {
25729
+ const { stats } = compressContext2(messages, {
25730
+ threshold,
25731
+ enabled,
25732
+ maxToolCalls: compressionConfig?.maxToolCalls ?? 50,
25733
+ protectedTools: compressionConfig?.protectedTools ?? [
24827
25734
  "hive_feature_create",
24828
25735
  "hive_plan_write",
24829
25736
  "hive_worktree_commit",
@@ -24868,6 +25775,27 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
24868
25775
  output.args.command = wrapped;
24869
25776
  output.args.workdir = undefined;
24870
25777
  },
25778
+ "tool.execute.after": async (input, output) => {
25779
+ const truncationConfig = configService.get().tokenTruncation;
25780
+ if (!truncationConfig?.enabled)
25781
+ return;
25782
+ const result = output.output;
25783
+ if (!result)
25784
+ return;
25785
+ const maxChars = truncationConfig.maxChars ?? 30000;
25786
+ if (result.length <= maxChars)
25787
+ return;
25788
+ const keepFirst = truncationConfig.keepFirstPercent ?? 40;
25789
+ const keepLast = truncationConfig.keepLastPercent ?? 40;
25790
+ const firstChars = Math.floor(result.length * keepFirst / 100);
25791
+ const lastChars = Math.floor(result.length * keepLast / 100);
25792
+ const truncated = result.slice(0, firstChars) + `
25793
+
25794
+ [... ${result.length - firstChars - lastChars} characters truncated ...]
25795
+
25796
+ ` + result.slice(-lastChars);
25797
+ output.output = truncated;
25798
+ },
24871
25799
  mcp: builtinMcps,
24872
25800
  tool: {
24873
25801
  gitingest: gitingestTool,
@@ -24887,6 +25815,11 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
24887
25815
  lsp_code_actions: lspCodeActionsTool,
24888
25816
  skill_mcp: skillMcpTool,
24889
25817
  list_skill_mcps: listSkillMcpsTool,
25818
+ hive_memory_list: hiveMemoryListTool,
25819
+ hive_memory_set: hiveMemorySetTool,
25820
+ hive_memory_replace: hiveMemoryReplaceTool,
25821
+ hive_journal_write: hiveJournalWriteTool,
25822
+ hive_journal_search: hiveJournalSearchTool,
24890
25823
  hive_skill: createHiveSkillTool(filteredSkills),
24891
25824
  hive_feature_create: tool({
24892
25825
  description: "Create a new feature and set it as active",
@@ -25661,13 +26594,111 @@ ${Object.entries(customAgentConfigs).sort(([left], [right]) => left.localeCompar
25661
26594
  skill: "allow"
25662
26595
  }
25663
26596
  };
26597
+ const micodeUserConfig = configService.getAgentConfig("codebase-locator");
26598
+ const codebaseLocatorConfig = {
26599
+ model: micodeUserConfig.model,
26600
+ variant: micodeUserConfig.variant,
26601
+ temperature: micodeUserConfig.temperature ?? 0.3,
26602
+ mode: "subagent",
26603
+ description: "Codebase Locator - Finds WHERE files live in the codebase. No analysis, just locations.",
26604
+ prompt: CODEBASE_LOCATOR_PROMPT,
26605
+ tools: agentTools(["hive_plan_read", "hive_skill"]),
26606
+ permission: {
26607
+ edit: "deny",
26608
+ task: "deny",
26609
+ delegate: "deny",
26610
+ skill: "allow"
26611
+ }
26612
+ };
26613
+ const codebaseAnalyzerConfig = {
26614
+ model: micodeUserConfig.model,
26615
+ variant: micodeUserConfig.variant,
26616
+ temperature: micodeUserConfig.temperature ?? 0.3,
26617
+ mode: "subagent",
26618
+ description: "Codebase Analyzer - Explains HOW code works. Deep module analysis.",
26619
+ prompt: CODEBASE_ANALYZER_PROMPT,
26620
+ tools: agentTools(["hive_plan_read", "hive_skill"]),
26621
+ permission: {
26622
+ edit: "deny",
26623
+ task: "deny",
26624
+ delegate: "deny",
26625
+ skill: "allow"
26626
+ }
26627
+ };
26628
+ const patternFinderConfig = {
26629
+ model: micodeUserConfig.model,
26630
+ variant: micodeUserConfig.variant,
26631
+ temperature: micodeUserConfig.temperature ?? 0.3,
26632
+ mode: "subagent",
26633
+ description: "Pattern Finder - Finds patterns to model after. Extracts conventions.",
26634
+ prompt: PATTERN_FINDER_PROMPT,
26635
+ tools: agentTools(["hive_plan_read", "hive_skill"]),
26636
+ permission: {
26637
+ edit: "deny",
26638
+ task: "deny",
26639
+ delegate: "deny",
26640
+ skill: "allow"
26641
+ }
26642
+ };
26643
+ const projectInitializerConfig = {
26644
+ model: micodeUserConfig.model,
26645
+ variant: micodeUserConfig.variant,
26646
+ temperature: micodeUserConfig.temperature ?? 0.5,
26647
+ mode: "subagent",
26648
+ description: "Project Initializer - Generates project documentation from codebase analysis.",
26649
+ prompt: PROJECT_INITIALIZER_PROMPT,
26650
+ tools: agentTools(["hive_plan_read", "hive_context_write", "hive_skill"]),
26651
+ permission: {
26652
+ edit: "deny",
26653
+ task: "deny",
26654
+ delegate: "deny",
26655
+ skill: "allow"
26656
+ }
26657
+ };
26658
+ const froggyUserConfig = configService.getAgentConfig("code-reviewer");
26659
+ const codeReviewerConfig = {
26660
+ model: froggyUserConfig.model,
26661
+ variant: froggyUserConfig.variant,
26662
+ temperature: froggyUserConfig.temperature ?? 0.3,
26663
+ mode: "subagent",
26664
+ description: "Code Reviewer - Reviews code for quality, correctness, security, and maintainability.",
26665
+ prompt: CODE_REVIEWER_PROMPT,
26666
+ tools: agentTools(["hive_plan_read", "hive_skill"]),
26667
+ permission: {
26668
+ edit: "deny",
26669
+ task: "deny",
26670
+ delegate: "deny",
26671
+ skill: "allow"
26672
+ }
26673
+ };
26674
+ const codeSimplifierConfig = {
26675
+ model: froggyUserConfig.model,
26676
+ variant: froggyUserConfig.variant,
26677
+ temperature: froggyUserConfig.temperature ?? 0.3,
26678
+ mode: "subagent",
26679
+ description: "Code Simplifier - Simplifies recently modified code for clarity while preserving behavior.",
26680
+ prompt: CODE_SIMPLIFIER_PROMPT,
26681
+ tools: agentTools(["hive_plan_read", "hive_skill"]),
26682
+ permission: {
26683
+ edit: "deny",
26684
+ task: "deny",
26685
+ delegate: "deny",
26686
+ skill: "allow"
26687
+ }
26688
+ };
25664
26689
  const builtInAgentConfigs = {
25665
26690
  zetta: zettaConfig,
25666
26691
  "architect-planner": architectConfig,
25667
26692
  "swarm-orchestrator": swarmConfig,
25668
26693
  "scout-researcher": scoutConfig,
25669
26694
  "forager-worker": foragerConfig,
25670
- "hygienic-reviewer": hygienicConfig
26695
+ "hygienic-reviewer": hygienicConfig,
26696
+ "code-reviewer": codeReviewerConfig,
26697
+ "code-simplifier": codeSimplifierConfig,
26698
+ "codebase-locator": codebaseLocatorConfig,
26699
+ "codebase-analyzer": codebaseAnalyzerConfig,
26700
+ "pattern-finder": patternFinderConfig,
26701
+ "project-initializer": projectInitializerConfig
25671
26702
  };
25672
26703
  const customAutoLoadedSkills = Object.fromEntries(await Promise.all(Object.entries(customAgentConfigs).map(async ([customAgentName, customAgentConfig]) => {
25673
26704
  const inheritedBaseSkills = customAgentConfig.baseAgent === "forager-worker" ? foragerUserConfig.autoLoadSkills ?? [] : hygienicUserConfig.autoLoadSkills ?? [];
@@ -25691,12 +26722,24 @@ ${Object.entries(customAgentConfigs).sort(([left], [right]) => left.localeCompar
25691
26722
  allAgents["scout-researcher"] = builtInAgentConfigs["scout-researcher"];
25692
26723
  allAgents["forager-worker"] = builtInAgentConfigs["forager-worker"];
25693
26724
  allAgents["hygienic-reviewer"] = builtInAgentConfigs["hygienic-reviewer"];
26725
+ allAgents["codebase-locator"] = builtInAgentConfigs["codebase-locator"];
26726
+ allAgents["codebase-analyzer"] = builtInAgentConfigs["codebase-analyzer"];
26727
+ allAgents["pattern-finder"] = builtInAgentConfigs["pattern-finder"];
26728
+ allAgents["project-initializer"] = builtInAgentConfigs["project-initializer"];
26729
+ allAgents["code-reviewer"] = builtInAgentConfigs["code-reviewer"];
26730
+ allAgents["code-simplifier"] = builtInAgentConfigs["code-simplifier"];
25694
26731
  } else {
25695
26732
  allAgents["architect-planner"] = builtInAgentConfigs["architect-planner"];
25696
26733
  allAgents["swarm-orchestrator"] = builtInAgentConfigs["swarm-orchestrator"];
25697
26734
  allAgents["scout-researcher"] = builtInAgentConfigs["scout-researcher"];
25698
26735
  allAgents["forager-worker"] = builtInAgentConfigs["forager-worker"];
25699
26736
  allAgents["hygienic-reviewer"] = builtInAgentConfigs["hygienic-reviewer"];
26737
+ allAgents["codebase-locator"] = builtInAgentConfigs["codebase-locator"];
26738
+ allAgents["codebase-analyzer"] = builtInAgentConfigs["codebase-analyzer"];
26739
+ allAgents["pattern-finder"] = builtInAgentConfigs["pattern-finder"];
26740
+ allAgents["project-initializer"] = builtInAgentConfigs["project-initializer"];
26741
+ allAgents["code-reviewer"] = builtInAgentConfigs["code-reviewer"];
26742
+ allAgents["code-simplifier"] = builtInAgentConfigs["code-simplifier"];
25700
26743
  }
25701
26744
  Object.assign(allAgents, customSubagents);
25702
26745
  const primaryAgent = agentMode === "unified" ? "zetta" : "architect-planner";