{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAGhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,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,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,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;CACjB;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAGhF;AAED,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,wBAA6B,GAAG,mBAAmB,CA2PpG","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { APP_NAME, getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { buildExecutionEnvironment } from \"./footer-data-provider.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\nimport { getToolDescription } from \"./tools/tools-prompt-data.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] */\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. Default: process.cwd() */\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}\n\nexport interface SystemPromptRegions {\n\tstablePrefix: string;\n\tdynamicSuffix: string;\n}\n\n/** Build the complete system prompt for compatibility with direct SDK consumers. */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst regions = buildSystemPromptRegions(options);\n\treturn regions.dynamicSuffix ? `${regions.stablePrefix}\\n\\n${regions.dynamicSuffix}` : regions.stablePrefix;\n}\n\n/** Build cache-stable instructions separately from volatile host context. */\nexport function buildSystemPromptRegions(options: BuildSystemPromptOptions = {}): SystemPromptRegions {\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} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = [...(providedSkills ?? [])].sort((a, b) => a.name.localeCompare(b.name));\n\tconst date = new Date().toISOString().slice(0, 10);\n\tconst hostContextLines = customPrompt\n\t\t? [`Current date: ${date}`, `Current working directory: ${promptCwd}`]\n\t\t: [`Current date: ${date}`];\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 customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\treturn { stablePrefix: prompt, dynamicSuffix: hostContextLines.join(\"\\n\") };\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// Built-ins use getToolDescription. Custom tools can provide one-line snippets.\n\tconst tools = [...(selectedTools || [\"read\", \"bash\", \"edit\", \"write\"])].sort((a, b) => a.localeCompare(b));\n\tconst visibleTools = tools.filter((name) => getToolDescription(name) || toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0\n\t\t\t? visibleTools\n\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\tconst snippet = toolSnippets?.[name] ?? getToolDescription(name) ?? name;\n\t\t\t\t\t\treturn `- ${name}: ${snippet}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\t\t\t: \"(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 hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\taddGuideline(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\taddGuideline(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\taddGuideline(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing or executing)\n\tif (hasEdit || hasWrite) {\n\t\taddGuideline(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\t// Evidence discipline (when bash or powershell is available)\n\tif (hasBash) {\n\t\taddGuideline(\n\t\t\t\"Never declare a command succeeded without inspecting its exit code or structured result. A non-zero exit code is a failure even if stdout looks positive. Text on stderr alone does not mean failure when exit code is 0.\",\n\t\t);\n\t\taddGuideline(\n\t\t\t\"Treat stdout, stderr, exit code, timeout, cancellation, and truncation as separate pieces of evidence. Do not conflate a proposed command with an executed one, or a started command with a completed one.\",\n\t\t);\n\t\taddGuideline(\n\t\t\t\"A Bash exit code represents the final status returned by Bash for the supplied source. For compound shell source (sequences, functions, subshells), exit code 0 does not prove every internal command succeeded. When internal_command_statuses_known is false, describe only the final shell status — do not claim all internal commands passed.\",\n\t\t);\n\t\taddGuideline(\n\t\t\t'Prefer direct single-command validation. Avoid combining setup, validation, filtering, cleanup, and status persistence into one command. When later commands are required after the target process, preserve its exit code with an explicit final `exit \"$RC\"`.',\n\t\t);\n\t\taddGuideline(\n\t\t\t\"When validation_evidence_authoritative is false, do not declare validation success, do not infer earlier stage status, and rerun the check without a pipeline. Filter retained output in a separate execution.\",\n\t\t);\n\t}\n\n\t// Command classification (when bash or powershell is available)\n\tif (hasBash) {\n\t\taddGuideline(\n\t\t\t\"Classify commands before execution: SHORT (foreground, immediate result), LONG_RUNNING (needs explicit timeout, preserve full log), or PERSISTENT (servers/watchers — use start/stop scripts or process_manager, never run in foreground).\",\n\t\t);\n\t}\n\n\t// Platform policies\n\tif (hasBash) {\n\t\tconst isWindows = process.platform === \"win32\";\n\t\tif (isWindows) {\n\t\t\taddGuideline(\n\t\t\t\t\"You are on Windows. Use the powershell tool for Windows-native workflows. Use bash only for Git Bash or cross-platform operations. Prefer PowerShell cmdlets and proper path quoting with spaces.\",\n\t\t\t);\n\t\t} else {\n\t\t\taddGuideline(\n\t\t\t\t\"You are on Linux. Use the bash tool for all shell operations. Do not use PowerShell syntax even if pwsh is installed — it is not the correct shell for this environment.\",\n\t\t\t);\n\t\t}\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(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\t// Build execution environment block\n\tconst env = buildExecutionEnvironment(resolvedCwd);\n\thostContextLines.push(\"\", \"Execution environment:\");\n\thostContextLines.push(`- host: ${env.host}`);\n\thostContextLines.push(`- operating system: ${env.os}`);\n\thostContextLines.push(`- login shell: ${env.loginShell}`);\n\t// The bash tool uses its own shell (/bin/bash on Linux, Git Bash on Windows);\n\t// the login shell may differ. The powershell tool uses pwsh or powershell.exe.\n\thostContextLines.push(`- working directory: ${env.initialCwd}`);\n\tif (env.effectiveCwd !== env.initialCwd) {\n\t\thostContextLines.push(`- effective working directory: ${env.effectiveCwd}`);\n\t}\n\thostContextLines.push(`- git repository: ${env.gitRoot || \"none\"}`);\n\tif (env.controllerGitRoot) {\n\t\thostContextLines.push(`- controller repository: ${env.controllerGitRoot}`);\n\t}\n\tif (env.gitRoot) {\n\t\tconst branchLabel = env.isDetachedHead ? \"detached HEAD\" : env.gitBranch || \"unknown\";\n\t\thostContextLines.push(`- git branch: ${branchLabel}`);\n\t\tif (env.worktreeCount > 1) {\n\t\t\thostContextLines.push(\n\t\t\t\t`- git worktrees: ${env.worktreeCount} total (this worktree: ${env.gitWorktree || \"unknown\"})`,\n\t\t\t);\n\t\t}\n\t}\n\thostContextLines.push(\n\t\t\"\",\n\t\t\"Local Jensen documentation paths:\",\n\t\t`- Main documentation: ${readmePath}`,\n\t\t`- Additional docs: ${docsPath}`,\n\t\t`- Examples: ${examplesPath}`,\n\t);\n\n\tlet prompt = `You are Jensen, the orchestration intelligence operating inside ${APP_NAME}, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nYou are the primary project operator for this workspace: precise, calm, highly competent, and execution-focused.\n\nCore behavior:\n- Think like an orchestrator first: understand the goal, constraints, architecture, and execution path before acting.\n- Break work into clean, verifiable steps.\n- Prefer correctness, maintainability, and architectural alignment over flashy output.\n- Be proactive about identifying risks, missing dependencies, migration needs, and validation steps.\n- When acting on repository work, preserve project structure, conventions, and existing abstractions.\n- When appropriate, explain not only what to do, but why it is the correct architectural move.\n\nOperator State Discipline:\n- For substantial repository work, establish visible task or todo state before or alongside delegation. Keep it updated as work progresses.\n- Use task_create for multi-step work requiring explicit tracking with subject/description. Use todo_write for ephemeral step-by-step progress tracking.\n- Do not delegate until you have captured what needs tracking. After results arrive, update state before next delegation.\n- If you have active delegated work, there should be corresponding task or todo entries visible to the operator.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI; local paths are provided in host context):\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\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\treturn { stablePrefix: prompt, dynamicSuffix: hostContextLines.join(\"\\n\") };\n}\n"]}