{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AAG9E,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA8K3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { type AgentDefinition, TASK_TOOL_NAME } from \"./agent-frontmatter.js\";\nimport { formatAgentsForPrompt } from \"./agent-registry.js\";\nimport { formatSelfDocsForPrompt } from \"./self-docs.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write, search] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. */\n\tcwd: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n\t/**\n\t * Available agents for delegation, emitted as `<available_agents>` XML.\n\t * Only populated when the Task tool is active so the model knows which\n\t * agents exist without re-reading the agent registry each turn.\n\t */\n\tagents?: AgentDefinition[];\n\t/**\n\t * Point the model at hoocode's own shipped docs so it can answer questions\n\t * about hoocode itself.\n\t *\n\t * Defaults to true for the built-in prompt and false when `customPrompt`\n\t * replaces it. Every other appended section (context files, skills, agents)\n\t * only appears because the caller passed the content in; this one\n\t * materializes on its own, so a caller who has taken over the system prompt\n\t * gets it only by asking. That also keeps it out of light mode, whose whole\n\t * point is a minimal fixed per-turn surface. Needs the read tool either way.\n\t */\n\tincludeSelfDocs?: boolean;\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t\tagents: providedAgents,\n\t\tincludeSelfDocs,\n\t} = options;\n\tconst resolvedCwd = cwd;\n\tconst promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n\tconst now = new Date();\n\tconst year = now.getFullYear();\n\tconst month = String(now.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(now.getDate()).padStart(2, \"0\");\n\tconst date = `${year}-${month}-${day}`;\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\tconst wantSelfDocs = includeSelfDocs ?? !customPrompt;\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\tconst agents = providedAgents ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst hasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (hasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Append agents section (only when Task tool is active)\n\t\tconst hasTask = !selectedTools || selectedTools.includes(TASK_TOOL_NAME);\n\t\tif (hasTask && agents.length > 0) {\n\t\t\tprompt += formatAgentsForPrompt(agents);\n\t\t}\n\n\t\t// Append hoocode's own docs (only if read tool is available)\n\t\tif (wantSelfDocs && hasRead) {\n\t\t\tprompt += formatSelfDocsForPrompt();\n\t\t}\n\n\t\t// Add date and working directory last\n\t\tprompt += `\\n\\nCurrent date: ${date}`;\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\", \"SearchCodebase\"];\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasSearch = tools.includes(\"SearchCodebase\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines. `SearchCodebase` is the only dedicated discovery tool\n\t// left, so name it when it is registered and fall back to the shell\n\t// otherwise — never advertise a tool that isn't in the bundle.\n\tif (hasSearch) {\n\t\t// One bullet, not two. The split version stated the same preference twice —\n\t\t// \"use SearchCodebase instead of bash\" and then the fuller contrast — which\n\t\t// cost ~45 tokens every turn to say it again.\n\t\taddGuideline(\n\t\t\thasBash\n\t\t\t\t? \"SearchCodebase finds where code lives by concept, behavior, or half-known name (ranked, respects .gitignore); shell out to rg/find/ls only for exact matching lines, counts, or a raw listing\"\n\t\t\t\t: \"For code discovery use SearchCodebase — it finds where code lives by concept, behavior, or half-known name, and respects .gitignore\",\n\t\t);\n\t} else if (hasBash) {\n\t\taddGuideline(\"Use bash for file exploration (ls, rg/grep, find)\");\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\n\t\t\"Put independent tool calls in one message — they execute in parallel; only split them across turns when a call needs an earlier call's result\",\n\t);\n\taddGuideline(\n\t\t'Be concise: no preamble or postamble, no restating the task or summarizing what you just did, no closers like \"Let me know\"',\n\t);\n\taddGuideline(\n\t\t\"Do not narrate routine tool calls or results — the permission gate already shows them; speak when you have the answer or need a decision\",\n\t);\n\taddGuideline(\n\t\t\"Match the surrounding code's conventions for comments, docstrings, and types — do not add or strip them by default\",\n\t);\n\taddGuideline(\"Cite path:line when referring to code\");\n\taddGuideline(\"If a command failed, a test is still red, or you did not verify something, say so plainly\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside hoocode, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nGuidelines:\n${guidelines}`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Append agents section (only when Task tool is active)\n\tconst hasTask = tools.includes(TASK_TOOL_NAME);\n\tif (hasTask && agents.length > 0) {\n\t\tprompt += formatAgentsForPrompt(agents);\n\t}\n\n\t// Append hoocode's own docs (only if read tool is available)\n\tif (wantSelfDocs && hasRead) {\n\t\tprompt += formatSelfDocsForPrompt();\n\t}\n\n\t// Add date and working directory last\n\tprompt += `\\n\\nCurrent date: ${date}`;\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}