headlesscode 1.0.2
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/ATTRIBUTION.md +53 -0
- package/CODE_OF_CONDUCT.md +130 -0
- package/CONTRIBUTING.md +107 -0
- package/LICENSE +202 -0
- package/README.md +486 -0
- package/SECURITY.md +211 -0
- package/bin/headlesscode.mjs +83 -0
- package/package.json +63 -0
- package/shared/prompts/review-mode-prompt-short.md +93 -0
- package/shared/prompts/review-mode-prompt.md +281 -0
- package/shared/rules-code/rules.md +22 -0
- package/shared/stacks/cpp/rules.md +30 -0
- package/shared/stacks/fastapi/rules.md +30 -0
- package/shared/stacks/javascript/rules.md +37 -0
- package/shared/stacks/postgresql/rules.md +31 -0
- package/shared/stacks/python/rules.md +35 -0
- package/shared/stacks/react/rules.md +11 -0
- package/shared/stacks/typescript/rules.md +10 -0
- package/src/budget/budget.ts +221 -0
- package/src/budget/concurrency.ts +126 -0
- package/src/budget/cost.ts +309 -0
- package/src/budget/index.ts +8 -0
- package/src/checkpoints/cli.ts +256 -0
- package/src/checkpoints/service.ts +227 -0
- package/src/cli.ts +1535 -0
- package/src/cloud/docker-provider.ts +334 -0
- package/src/cloud/provider.ts +300 -0
- package/src/codeintel/call-graph.ts +78 -0
- package/src/codeintel/find-references.ts +123 -0
- package/src/codeintel/go-to-definition.ts +193 -0
- package/src/codeintel/handlers.ts +190 -0
- package/src/codeintel/import-graph.ts +173 -0
- package/src/codeintel/outline.ts +180 -0
- package/src/codeintel/position.ts +77 -0
- package/src/codeintel/program.ts +350 -0
- package/src/codeintel/rename-symbol.ts +213 -0
- package/src/codeintel/tools.ts +280 -0
- package/src/codemap/build.ts +135 -0
- package/src/codemap/cli.ts +190 -0
- package/src/codemap/extract.ts +339 -0
- package/src/codemap/files.ts +236 -0
- package/src/codemap/fingerprint.ts +65 -0
- package/src/codemap/flows.ts +62 -0
- package/src/codemap/html.ts +451 -0
- package/src/codemap/lock.ts +80 -0
- package/src/codemap/types.ts +101 -0
- package/src/codesearch/airunner-embedder.ts +185 -0
- package/src/codesearch/chunk.ts +339 -0
- package/src/codesearch/cli.ts +223 -0
- package/src/codesearch/embedder.ts +332 -0
- package/src/codesearch/files.ts +280 -0
- package/src/codesearch/index.ts +469 -0
- package/src/codesearch/ollama-embedder.ts +205 -0
- package/src/codesearch/search.ts +141 -0
- package/src/codesearch/types.ts +100 -0
- package/src/config/mode-models.ts +218 -0
- package/src/dashboard/aggregate.ts +364 -0
- package/src/dashboard/chat-thread.ts +141 -0
- package/src/dashboard/checkpoints.ts +124 -0
- package/src/dashboard/cli.ts +193 -0
- package/src/dashboard/codemap.ts +44 -0
- package/src/dashboard/files.ts +121 -0
- package/src/dashboard/page.ts +2803 -0
- package/src/dashboard/self-improvement-metrics.ts +282 -0
- package/src/dashboard/server.ts +1103 -0
- package/src/dashboard/session-launch.ts +310 -0
- package/src/dashboard/timeline.ts +273 -0
- package/src/dashboard/tool-exec.ts +107 -0
- package/src/dashboard/trend-cli.ts +141 -0
- package/src/dashboard/trend.ts +413 -0
- package/src/decision-proxy/cli.ts +261 -0
- package/src/decision-proxy/proxy.ts +569 -0
- package/src/deploy/gate-cli.ts +147 -0
- package/src/deploy/gate.ts +254 -0
- package/src/engine/condense.ts +512 -0
- package/src/engine/events.ts +428 -0
- package/src/engine/handoff.ts +71 -0
- package/src/engine/lazy-tools.ts +160 -0
- package/src/engine/local-explore.ts +653 -0
- package/src/engine/logger.ts +96 -0
- package/src/engine/loop.ts +5517 -0
- package/src/engine/parser.ts +347 -0
- package/src/engine/prompt.ts +860 -0
- package/src/engine/reports.ts +47 -0
- package/src/engine/stacks.ts +448 -0
- package/src/engine/types.ts +291 -0
- package/src/engine/usage.ts +186 -0
- package/src/github/app-auth.ts +161 -0
- package/src/github/cli.ts +448 -0
- package/src/github/installations.ts +133 -0
- package/src/github/pr.ts +321 -0
- package/src/github/provision.ts +118 -0
- package/src/github/push.ts +122 -0
- package/src/index-util.ts +50 -0
- package/src/index.ts +81 -0
- package/src/init/cli.ts +248 -0
- package/src/init/gitignore.ts +74 -0
- package/src/llm/ollama.ts +308 -0
- package/src/llm/openrouter.ts +868 -0
- package/src/llm/preflight.ts +367 -0
- package/src/llm/transcript-capture.ts +84 -0
- package/src/memory/embed.ts +110 -0
- package/src/memory/index.ts +22 -0
- package/src/memory/local.ts +259 -0
- package/src/memory/summarizer.ts +283 -0
- package/src/memory/types.ts +153 -0
- package/src/memory/uwuchat.ts +157 -0
- package/src/migrate/cli.ts +115 -0
- package/src/orchestrator/analyze-cli.ts +104 -0
- package/src/orchestrator/auto-split.ts +206 -0
- package/src/orchestrator/cleanup.ts +1003 -0
- package/src/orchestrator/cli.ts +3571 -0
- package/src/orchestrator/cost-estimate.ts +564 -0
- package/src/orchestrator/cost-history-cli.ts +242 -0
- package/src/orchestrator/cost-history.ts +397 -0
- package/src/orchestrator/git-sync.ts +250 -0
- package/src/orchestrator/index.ts +153 -0
- package/src/orchestrator/log-analysis.ts +0 -0
- package/src/orchestrator/merge-check.ts +108 -0
- package/src/orchestrator/pipeline.ts +411 -0
- package/src/orchestrator/resume.ts +1940 -0
- package/src/orchestrator/reviewer.ts +503 -0
- package/src/orchestrator/split.ts +296 -0
- package/src/orchestrator/state.ts +542 -0
- package/src/orchestrator/status.ts +697 -0
- package/src/orchestrator/verification-gate.ts +134 -0
- package/src/orchestrator/watch.ts +898 -0
- package/src/permissions/commands.ts +1083 -0
- package/src/permissions/config.ts +241 -0
- package/src/permissions/index.ts +12 -0
- package/src/permissions/protected-files.ts +96 -0
- package/src/permissions/store-protection.ts +272 -0
- package/src/project-store.ts +648 -0
- package/src/projects/cli.ts +382 -0
- package/src/qa/qa.ts +487 -0
- package/src/tools/browser/handler.ts +346 -0
- package/src/tools/browser/service.ts +406 -0
- package/src/tools/browser/smoke.ts +78 -0
- package/src/tools/browser/tool.ts +99 -0
- package/src/tools/executor.ts +2575 -0
- package/src/tools/language-detect.ts +183 -0
- package/src/tools/output-summarizer.ts +369 -0
- package/src/tools/run-tests.ts +302 -0
- package/src/tools/set-indentation-tool.ts +49 -0
- package/src/tools/test-selection.ts +160 -0
- package/src/vendor/tests/smoke.ts +103 -0
- package/src/vendor/zoo-code/VENDOR-NOTES.md +213 -0
- package/src/vendor/zoo-code/shim/anthropic.ts +71 -0
- package/src/vendor/zoo-code/shim/openai.d.ts +60 -0
- package/src/vendor/zoo-code/shim/os-name.ts +18 -0
- package/src/vendor/zoo-code/shim/strip-bom.ts +14 -0
- package/src/vendor/zoo-code/shim/vscode.ts +76 -0
- package/src/vendor/zoo-code/src/core/config/CustomModesManager.ts +1015 -0
- package/src/vendor/zoo-code/src/core/diff/strategies/multi-search-replace.ts +670 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/capabilities.ts +46 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/custom-instructions.ts +559 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/index.ts +10 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/markdown-formatting.ts +7 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/modes.ts +35 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/objective.ts +13 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/rules.ts +95 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/skills.ts +105 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/system-info.ts +30 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/tool-use-guidelines.ts +9 -0
- package/src/vendor/zoo-code/src/core/prompts/sections/tool-use.ts +7 -0
- package/src/vendor/zoo-code/src/core/prompts/system.ts +176 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/access_mcp_resource.ts +41 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_diff.ts +40 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_patch.ts +61 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/ask_followup_question.ts +62 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/attempt_completion.ts +33 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/codebase_search.ts +43 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/converters.ts +109 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit.ts +48 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit_file.ts +72 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/execute_command.ts +54 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/generate_image.ts +51 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/index.ts +75 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/list_files.ts +41 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/mcp_server.ts +75 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/new_task.ts +39 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_command_output.ts +81 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_file.ts +169 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/run_slash_command.ts +31 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_files.ts +50 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_replace.ts +51 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/skill.ts +33 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/switch_mode.ts +31 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/update_todo_list.ts +54 -0
- package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/write_to_file.ts +40 -0
- package/src/vendor/zoo-code/src/core/prompts/types.ts +12 -0
- package/src/vendor/zoo-code/src/i18n/index.ts +19 -0
- package/src/vendor/zoo-code/src/integrations/misc/extract-text.ts +81 -0
- package/src/vendor/zoo-code/src/services/checkpoints/RepoPerTaskCheckpointService.ts +15 -0
- package/src/vendor/zoo-code/src/services/checkpoints/ShadowCheckpointService.ts +553 -0
- package/src/vendor/zoo-code/src/services/checkpoints/excludes.ts +212 -0
- package/src/vendor/zoo-code/src/services/checkpoints/index.ts +3 -0
- package/src/vendor/zoo-code/src/services/checkpoints/types.ts +35 -0
- package/src/vendor/zoo-code/src/services/code-index/manager.ts +19 -0
- package/src/vendor/zoo-code/src/services/mcp/McpHub.ts +36 -0
- package/src/vendor/zoo-code/src/services/roo-config/index.ts +441 -0
- package/src/vendor/zoo-code/src/services/search/file-search.ts +143 -0
- package/src/vendor/zoo-code/src/services/skills/SkillsManager.ts +20 -0
- package/src/vendor/zoo-code/src/shared/globalFileNames.ts +9 -0
- package/src/vendor/zoo-code/src/shared/language.ts +43 -0
- package/src/vendor/zoo-code/src/shared/modes.ts +257 -0
- package/src/vendor/zoo-code/src/shared/tools.ts +385 -0
- package/src/vendor/zoo-code/src/utils/fs.ts +39 -0
- package/src/vendor/zoo-code/src/utils/globalContext.ts +22 -0
- package/src/vendor/zoo-code/src/utils/json-schema.ts +16 -0
- package/src/vendor/zoo-code/src/utils/logging.ts +21 -0
- package/src/vendor/zoo-code/src/utils/mcp-name.ts +190 -0
- package/src/vendor/zoo-code/src/utils/object.ts +18 -0
- package/src/vendor/zoo-code/src/utils/path.ts +94 -0
- package/src/vendor/zoo-code/src/utils/shell.ts +376 -0
- package/src/vendor/zoo-code/src/utils/text-normalization.ts +99 -0
- package/src/vendor/zoo-code/types/global-settings.ts +19 -0
- package/src/vendor/zoo-code/types/index.ts +22 -0
- package/src/vendor/zoo-code/types/message.ts +375 -0
- package/src/vendor/zoo-code/types/mode.ts +241 -0
- package/src/vendor/zoo-code/types/todo.ts +19 -0
- package/src/vendor/zoo-code/types/tool-params.ts +116 -0
- package/src/vendor/zoo-code/types/tool.ts +67 -0
- package/src/vendor/zoo-code/types/vscode.ts +84 -0
- package/src/vision/describe.ts +242 -0
- package/src/vision/tool.ts +91 -0
- package/src/watcher/cli.ts +369 -0
- package/src/watcher/github.ts +304 -0
- package/src/watcher/index.ts +59 -0
- package/src/watcher/state.ts +254 -0
- package/src/watcher/watch.ts +562 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { McpHub } from "../../../services/mcp/McpHub"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds the CAPABILITIES section of the system prompt.
|
|
5
|
+
*
|
|
6
|
+
* The MCP availability line is only emitted when at least one MCP server is actually
|
|
7
|
+
* exposed to the current mode. When `allowedMcpServers` is provided, the hub's server
|
|
8
|
+
* list is filtered by that allowlist BEFORE deciding whether to advertise MCP, so the
|
|
9
|
+
* capability text matches the per-mode tool exposure:
|
|
10
|
+
* - `undefined` allowlist → all connected servers count (backward compatible)
|
|
11
|
+
* - empty `[]` allowlist → no servers count ⇒ MCP line omitted
|
|
12
|
+
* - populated allowlist → only listed servers count
|
|
13
|
+
*
|
|
14
|
+
* @param cwd Current working directory used in the prompt text.
|
|
15
|
+
* @param mcpHub Optional MCP hub. When omitted, the MCP line is never emitted.
|
|
16
|
+
* @param allowedMcpServers Optional per-mode allowlist of MCP server names. When provided,
|
|
17
|
+
* the hub's servers are filtered to this set before determining MCP availability.
|
|
18
|
+
*/
|
|
19
|
+
export function getCapabilitiesSection(cwd: string, mcpHub?: McpHub, allowedMcpServers?: string[]): string {
|
|
20
|
+
// Determine whether any MCP server is actually available to the current mode.
|
|
21
|
+
// Filtering the hub's servers by the allowlist (when provided) keeps the capability
|
|
22
|
+
// text consistent with the tools that are exposed for the mode.
|
|
23
|
+
let hasMcpServers = false
|
|
24
|
+
if (mcpHub) {
|
|
25
|
+
let servers = mcpHub.getServers()
|
|
26
|
+
if (allowedMcpServers) {
|
|
27
|
+
const allowSet = new Set(allowedMcpServers)
|
|
28
|
+
servers = servers.filter((server) => allowSet.has(server.name))
|
|
29
|
+
}
|
|
30
|
+
hasMcpServers = servers.length > 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `====
|
|
34
|
+
|
|
35
|
+
CAPABILITIES
|
|
36
|
+
|
|
37
|
+
- You have access to tools that let you execute CLI commands on the user's computer, list files, view source code definitions, regex search, read and write files, and ask follow-up questions. These tools help you effectively accomplish a wide range of tasks, such as writing code, making edits or improvements to existing files, understanding the current state of a project, performing system operations, and much more.
|
|
38
|
+
- When the user initially gives you a task, a recursive list of all filepaths in the current workspace directory ('${cwd}') will be included in environment_details. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you need to further explore directories such as outside the current workspace directory, you can use the list_files tool. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
|
|
39
|
+
- You can use the execute_command tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.${
|
|
40
|
+
hasMcpServers
|
|
41
|
+
? `
|
|
42
|
+
- You have access to MCP servers that may provide additional tools and resources. Each server may provide different capabilities that you can use to accomplish tasks more effectively.
|
|
43
|
+
`
|
|
44
|
+
: ""
|
|
45
|
+
}`
|
|
46
|
+
}
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import fs from "fs/promises"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import * as os from "os"
|
|
4
|
+
import { Dirent } from "fs"
|
|
5
|
+
|
|
6
|
+
import { isLanguage } from "../../../../types"
|
|
7
|
+
|
|
8
|
+
import type { SystemPromptSettings } from "../types"
|
|
9
|
+
|
|
10
|
+
import { LANGUAGES } from "../../../shared/language"
|
|
11
|
+
import {
|
|
12
|
+
getRooDirectoriesForCwd,
|
|
13
|
+
getAllRooDirectoriesForCwd,
|
|
14
|
+
getAgentsDirectoriesForCwd,
|
|
15
|
+
getGlobalRooDirectory,
|
|
16
|
+
} from "../../../services/roo-config"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Safely read a file and return its trimmed content
|
|
20
|
+
*/
|
|
21
|
+
async function safeReadFile(filePath: string): Promise<string> {
|
|
22
|
+
try {
|
|
23
|
+
const content = await fs.readFile(filePath, "utf-8")
|
|
24
|
+
return content.trim()
|
|
25
|
+
} catch (err) {
|
|
26
|
+
const errorCode = (err as NodeJS.ErrnoException).code
|
|
27
|
+
if (!errorCode || !["ENOENT", "EISDIR"].includes(errorCode)) {
|
|
28
|
+
throw err
|
|
29
|
+
}
|
|
30
|
+
return ""
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if a directory exists
|
|
36
|
+
*/
|
|
37
|
+
async function directoryExists(dirPath: string): Promise<boolean> {
|
|
38
|
+
try {
|
|
39
|
+
const stats = await fs.stat(dirPath)
|
|
40
|
+
return stats.isDirectory()
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const MAX_DEPTH = 5
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Recursively resolve directory entries and collect file paths
|
|
50
|
+
*/
|
|
51
|
+
async function resolveDirectoryEntry(
|
|
52
|
+
entry: Dirent,
|
|
53
|
+
dirPath: string,
|
|
54
|
+
fileInfo: Array<{ originalPath: string; resolvedPath: string }>,
|
|
55
|
+
depth: number,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
// Avoid cyclic symlinks
|
|
58
|
+
if (depth > MAX_DEPTH) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const fullPath = path.resolve(entry.parentPath || dirPath, entry.name)
|
|
63
|
+
if (entry.isFile()) {
|
|
64
|
+
// Regular file - both original and resolved paths are the same
|
|
65
|
+
fileInfo.push({ originalPath: fullPath, resolvedPath: fullPath })
|
|
66
|
+
} else if (entry.isSymbolicLink()) {
|
|
67
|
+
// Await the resolution of the symbolic link
|
|
68
|
+
await resolveSymLink(fullPath, fileInfo, depth + 1)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Recursively resolve a symbolic link and collect file paths
|
|
74
|
+
*/
|
|
75
|
+
async function resolveSymLink(
|
|
76
|
+
symlinkPath: string,
|
|
77
|
+
fileInfo: Array<{ originalPath: string; resolvedPath: string }>,
|
|
78
|
+
depth: number,
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
// Avoid cyclic symlinks
|
|
81
|
+
if (depth > MAX_DEPTH) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Get the symlink target
|
|
86
|
+
const linkTarget = await fs.readlink(symlinkPath)
|
|
87
|
+
// Resolve the target path relative to the symlink's real parent directory.
|
|
88
|
+
// We must use realpath on the parent directory because the symlink itself
|
|
89
|
+
// may be inside a symlinked directory. Relative symlink targets are resolved
|
|
90
|
+
// by the filesystem relative to the symlink's actual location, not the path
|
|
91
|
+
// used to access it.
|
|
92
|
+
const symlinkDir = path.dirname(symlinkPath)
|
|
93
|
+
let realSymlinkDir: string
|
|
94
|
+
try {
|
|
95
|
+
realSymlinkDir = await fs.realpath(symlinkDir)
|
|
96
|
+
} catch {
|
|
97
|
+
realSymlinkDir = symlinkDir
|
|
98
|
+
}
|
|
99
|
+
const resolvedTarget = path.resolve(realSymlinkDir, linkTarget)
|
|
100
|
+
|
|
101
|
+
// Check if the target is a file
|
|
102
|
+
const stats = await fs.stat(resolvedTarget)
|
|
103
|
+
if (stats.isFile()) {
|
|
104
|
+
// For symlinks to files, store the symlink path as original and target as resolved
|
|
105
|
+
fileInfo.push({
|
|
106
|
+
originalPath: symlinkPath,
|
|
107
|
+
resolvedPath: resolvedTarget,
|
|
108
|
+
})
|
|
109
|
+
} else if (stats.isDirectory()) {
|
|
110
|
+
const anotherEntries = await fs.readdir(resolvedTarget, {
|
|
111
|
+
withFileTypes: true,
|
|
112
|
+
recursive: true,
|
|
113
|
+
})
|
|
114
|
+
// Collect promises for recursive calls within the directory
|
|
115
|
+
const directoryPromises: Promise<void>[] = []
|
|
116
|
+
for (const anotherEntry of anotherEntries) {
|
|
117
|
+
directoryPromises.push(resolveDirectoryEntry(anotherEntry, resolvedTarget, fileInfo, depth + 1))
|
|
118
|
+
}
|
|
119
|
+
// Wait for all entries in the resolved directory to be processed
|
|
120
|
+
await Promise.all(directoryPromises)
|
|
121
|
+
} else if (stats.isSymbolicLink()) {
|
|
122
|
+
// Handle nested symlinks by awaiting the recursive call
|
|
123
|
+
await resolveSymLink(resolvedTarget, fileInfo, depth + 1)
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
// Skip invalid symlinks
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Read all text files from a directory in alphabetical order
|
|
132
|
+
*/
|
|
133
|
+
async function readTextFilesFromDirectory(dirPath: string): Promise<Array<{ filename: string; content: string }>> {
|
|
134
|
+
try {
|
|
135
|
+
const entries = await fs.readdir(dirPath, {
|
|
136
|
+
withFileTypes: true,
|
|
137
|
+
recursive: true,
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// Process all entries - regular files and symlinks that might point to files
|
|
141
|
+
// Store both original path (for sorting) and resolved path (for reading)
|
|
142
|
+
const fileInfo: Array<{ originalPath: string; resolvedPath: string }> = []
|
|
143
|
+
// Collect promises for the initial resolution calls
|
|
144
|
+
const initialPromises: Promise<void>[] = []
|
|
145
|
+
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
initialPromises.push(resolveDirectoryEntry(entry, dirPath, fileInfo, 0))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Wait for all asynchronous operations (including recursive ones) to complete
|
|
151
|
+
await Promise.all(initialPromises)
|
|
152
|
+
|
|
153
|
+
const fileContents = await Promise.all(
|
|
154
|
+
fileInfo.map(async ({ originalPath, resolvedPath }) => {
|
|
155
|
+
try {
|
|
156
|
+
// Check if it's a file (not a directory)
|
|
157
|
+
const stats = await fs.stat(resolvedPath)
|
|
158
|
+
if (stats.isFile()) {
|
|
159
|
+
// Filter out cache files and system files that shouldn't be in rules
|
|
160
|
+
if (!shouldIncludeRuleFile(resolvedPath)) {
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
const content = await safeReadFile(resolvedPath)
|
|
164
|
+
// Use resolvedPath for display to maintain existing behavior
|
|
165
|
+
return { filename: resolvedPath, content, sortKey: originalPath }
|
|
166
|
+
}
|
|
167
|
+
return null
|
|
168
|
+
} catch (err) {
|
|
169
|
+
return null
|
|
170
|
+
}
|
|
171
|
+
}),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
// Filter out null values (directories, failed reads, or excluded files)
|
|
175
|
+
const filteredFiles = fileContents.filter(
|
|
176
|
+
(item): item is { filename: string; content: string; sortKey: string } => item !== null,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
// Sort files alphabetically by the original filename (case-insensitive) to ensure consistent order
|
|
180
|
+
// For symlinks, this will use the symlink name, not the target name
|
|
181
|
+
return filteredFiles
|
|
182
|
+
.sort((a, b) => {
|
|
183
|
+
const filenameA = path.basename(a.sortKey).toLowerCase()
|
|
184
|
+
const filenameB = path.basename(b.sortKey).toLowerCase()
|
|
185
|
+
return filenameA.localeCompare(filenameB)
|
|
186
|
+
})
|
|
187
|
+
.map(({ filename, content }) => ({ filename, content }))
|
|
188
|
+
} catch (err) {
|
|
189
|
+
return []
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Format content from multiple files with filenames as headers
|
|
195
|
+
* @param files - Array of files with filename (absolute path) and content
|
|
196
|
+
* @param cwd - Current working directory for computing relative paths
|
|
197
|
+
*/
|
|
198
|
+
function formatDirectoryContent(files: Array<{ filename: string; content: string }>, cwd: string): string {
|
|
199
|
+
if (files.length === 0) return ""
|
|
200
|
+
|
|
201
|
+
return files
|
|
202
|
+
.map((file) => {
|
|
203
|
+
// Compute relative path for display
|
|
204
|
+
const displayPath = path.relative(cwd, file.filename)
|
|
205
|
+
return `# Rules from ${displayPath}:\n${file.content}`
|
|
206
|
+
})
|
|
207
|
+
.join("\n\n")
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Load rule files from global, project-local, and optionally subfolder directories
|
|
212
|
+
* Rules are loaded in order: global first, then project-local, then subfolders (alphabetically)
|
|
213
|
+
*
|
|
214
|
+
* @param cwd - Current working directory (project root)
|
|
215
|
+
* @param enableSubfolderRules - Whether to include rules from subdirectories (default: false)
|
|
216
|
+
*/
|
|
217
|
+
export async function loadRuleFiles(cwd: string, enableSubfolderRules: boolean = false): Promise<string> {
|
|
218
|
+
const rules: string[] = []
|
|
219
|
+
// Use recursive discovery only if enableSubfolderRules is true
|
|
220
|
+
const rooDirectories = enableSubfolderRules ? await getAllRooDirectoriesForCwd(cwd) : getRooDirectoriesForCwd(cwd)
|
|
221
|
+
|
|
222
|
+
// Check for .roo/rules/ directories in order (global, project-local, and optionally subfolders)
|
|
223
|
+
for (const rooDir of rooDirectories) {
|
|
224
|
+
const rulesDir = path.join(rooDir, "rules")
|
|
225
|
+
if (await directoryExists(rulesDir)) {
|
|
226
|
+
const files = await readTextFilesFromDirectory(rulesDir)
|
|
227
|
+
if (files.length > 0) {
|
|
228
|
+
const content = formatDirectoryContent(files, cwd)
|
|
229
|
+
rules.push(content)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// If we found rules in .roo/rules/ directories, return them
|
|
235
|
+
if (rules.length > 0) {
|
|
236
|
+
return "\n# Rules from .roo directories:\n\n" + rules.join("\n\n")
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Fall back to existing behavior for legacy .roorules/.clinerules files
|
|
240
|
+
const ruleFiles = [".roorules", ".clinerules"]
|
|
241
|
+
|
|
242
|
+
for (const file of ruleFiles) {
|
|
243
|
+
const content = await safeReadFile(path.join(cwd, file))
|
|
244
|
+
if (content) {
|
|
245
|
+
return `\n# Rules from ${file}:\n${content}\n`
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return ""
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Read content from an agent rules file (AGENTS.md, AGENT.md, etc.)
|
|
254
|
+
* Handles symlink resolution.
|
|
255
|
+
*
|
|
256
|
+
* @param filePath - Full path to the agent rules file
|
|
257
|
+
* @returns File content or empty string if file doesn't exist
|
|
258
|
+
*/
|
|
259
|
+
async function readAgentRulesFile(filePath: string): Promise<string> {
|
|
260
|
+
let resolvedPath = filePath
|
|
261
|
+
|
|
262
|
+
// Check if file exists and handle symlinks
|
|
263
|
+
try {
|
|
264
|
+
const stats = await fs.lstat(filePath)
|
|
265
|
+
if (stats.isSymbolicLink()) {
|
|
266
|
+
// Create a temporary fileInfo array to use with resolveSymLink
|
|
267
|
+
const fileInfo: Array<{
|
|
268
|
+
originalPath: string
|
|
269
|
+
resolvedPath: string
|
|
270
|
+
}> = []
|
|
271
|
+
|
|
272
|
+
// Use the existing resolveSymLink function to handle symlink resolution
|
|
273
|
+
await resolveSymLink(filePath, fileInfo, 0)
|
|
274
|
+
|
|
275
|
+
// Extract the resolved path from fileInfo
|
|
276
|
+
if (fileInfo.length > 0) {
|
|
277
|
+
resolvedPath = fileInfo[0].resolvedPath
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
// If lstat fails (file doesn't exist), return empty
|
|
282
|
+
return ""
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Read the content from the resolved path
|
|
286
|
+
return safeReadFile(resolvedPath)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Load AGENTS.md or AGENT.md file from a specific directory
|
|
291
|
+
* Checks for both AGENTS.md (standard) and AGENT.md (alternative) for compatibility
|
|
292
|
+
* Also loads AGENTS.local.md for personal overrides (not checked in to version control)
|
|
293
|
+
* AGENTS.local.md can be loaded even if AGENTS.md doesn't exist
|
|
294
|
+
*
|
|
295
|
+
* @param directory - Directory to check for AGENTS.md
|
|
296
|
+
* @param showPath - Whether to include the directory path in the header
|
|
297
|
+
* @param cwd - Current working directory for computing relative paths (optional)
|
|
298
|
+
*/
|
|
299
|
+
async function loadAgentRulesFileFromDirectory(
|
|
300
|
+
directory: string,
|
|
301
|
+
showPath: boolean = false,
|
|
302
|
+
cwd?: string,
|
|
303
|
+
): Promise<string> {
|
|
304
|
+
// Try both filenames - AGENTS.md (standard) first, then AGENT.md (alternative)
|
|
305
|
+
const filenames = ["AGENTS.md", "AGENT.md"]
|
|
306
|
+
const results: string[] = []
|
|
307
|
+
const displayPath = cwd ? path.relative(cwd, directory) : directory
|
|
308
|
+
|
|
309
|
+
for (const filename of filenames) {
|
|
310
|
+
try {
|
|
311
|
+
const agentPath = path.join(directory, filename)
|
|
312
|
+
const content = await readAgentRulesFile(agentPath)
|
|
313
|
+
|
|
314
|
+
if (content) {
|
|
315
|
+
// Compute relative path for display if cwd is provided
|
|
316
|
+
const header = showPath
|
|
317
|
+
? `# Agent Rules Standard (${filename}) from ${displayPath}:`
|
|
318
|
+
: `# Agent Rules Standard (${filename}):`
|
|
319
|
+
results.push(`${header}\n${content}`)
|
|
320
|
+
|
|
321
|
+
// Found a standard file, don't check alternative
|
|
322
|
+
break
|
|
323
|
+
}
|
|
324
|
+
} catch (err) {
|
|
325
|
+
// Silently ignore errors - agent rules files are optional
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Always try to load AGENTS.local.md for personal overrides (even if AGENTS.md doesn't exist)
|
|
330
|
+
try {
|
|
331
|
+
const localFilename = "AGENTS.local.md"
|
|
332
|
+
const localPath = path.join(directory, localFilename)
|
|
333
|
+
const localContent = await readAgentRulesFile(localPath)
|
|
334
|
+
|
|
335
|
+
if (localContent) {
|
|
336
|
+
const localHeader = showPath
|
|
337
|
+
? `# Agent Rules Local (${localFilename}) from ${displayPath}:`
|
|
338
|
+
: `# Agent Rules Local (${localFilename}):`
|
|
339
|
+
results.push(`${localHeader}\n${localContent}`)
|
|
340
|
+
}
|
|
341
|
+
} catch (err) {
|
|
342
|
+
// Silently ignore errors - local agent rules file is optional
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return results.join("\n\n")
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Load AGENTS.md or AGENT.md file from the project root if it exists
|
|
350
|
+
* Checks for both AGENTS.md (standard) and AGENT.md (alternative) for compatibility
|
|
351
|
+
*
|
|
352
|
+
* @deprecated Use loadAllAgentRulesFiles for loading from all directories
|
|
353
|
+
*/
|
|
354
|
+
async function loadAgentRulesFile(cwd: string): Promise<string> {
|
|
355
|
+
return loadAgentRulesFileFromDirectory(cwd, false, cwd)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Load all AGENTS.md files from project root and optionally subdirectories with .roo folders
|
|
360
|
+
* Returns combined content with clear path headers for each file
|
|
361
|
+
*
|
|
362
|
+
* @param cwd - Current working directory (project root)
|
|
363
|
+
* @param enableSubfolderRules - Whether to include AGENTS.md from subdirectories (default: false)
|
|
364
|
+
* @returns Combined AGENTS.md content from all locations
|
|
365
|
+
*/
|
|
366
|
+
async function loadAllAgentRulesFiles(cwd: string, enableSubfolderRules: boolean = false): Promise<string> {
|
|
367
|
+
const agentRules: string[] = []
|
|
368
|
+
|
|
369
|
+
// When subfolder rules are disabled, only load from root
|
|
370
|
+
if (!enableSubfolderRules) {
|
|
371
|
+
const content = await loadAgentRulesFileFromDirectory(cwd, false, cwd)
|
|
372
|
+
if (content && content.trim()) {
|
|
373
|
+
agentRules.push(content.trim())
|
|
374
|
+
}
|
|
375
|
+
return agentRules.join("\n\n")
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// When enabled, load from root and all subdirectories with .roo folders
|
|
379
|
+
const directories = await getAgentsDirectoriesForCwd(cwd)
|
|
380
|
+
|
|
381
|
+
for (const directory of directories) {
|
|
382
|
+
// Show path for all directories except the root
|
|
383
|
+
const showPath = directory !== cwd
|
|
384
|
+
const content = await loadAgentRulesFileFromDirectory(directory, showPath, cwd)
|
|
385
|
+
if (content && content.trim()) {
|
|
386
|
+
agentRules.push(content.trim())
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return agentRules.join("\n\n")
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export async function addCustomInstructions(
|
|
394
|
+
modeCustomInstructions: string,
|
|
395
|
+
globalCustomInstructions: string,
|
|
396
|
+
cwd: string,
|
|
397
|
+
mode: string,
|
|
398
|
+
options: {
|
|
399
|
+
language?: string
|
|
400
|
+
rooIgnoreInstructions?: string
|
|
401
|
+
settings?: SystemPromptSettings
|
|
402
|
+
} = {},
|
|
403
|
+
): Promise<string> {
|
|
404
|
+
const sections = []
|
|
405
|
+
|
|
406
|
+
// Get the enableSubfolderRules setting (default: false)
|
|
407
|
+
const enableSubfolderRules = options.settings?.enableSubfolderRules ?? false
|
|
408
|
+
|
|
409
|
+
// Load mode-specific rules if mode is provided
|
|
410
|
+
let modeRuleContent = ""
|
|
411
|
+
let usedRuleFile = ""
|
|
412
|
+
|
|
413
|
+
if (mode) {
|
|
414
|
+
const modeRules: string[] = []
|
|
415
|
+
// Use recursive discovery only if enableSubfolderRules is true
|
|
416
|
+
const rooDirectories = enableSubfolderRules
|
|
417
|
+
? await getAllRooDirectoriesForCwd(cwd)
|
|
418
|
+
: getRooDirectoriesForCwd(cwd)
|
|
419
|
+
|
|
420
|
+
// Check for .roo/rules-${mode}/ directories in order (global, project-local, and optionally subfolders)
|
|
421
|
+
for (const rooDir of rooDirectories) {
|
|
422
|
+
const modeRulesDir = path.join(rooDir, `rules-${mode}`)
|
|
423
|
+
if (await directoryExists(modeRulesDir)) {
|
|
424
|
+
const files = await readTextFilesFromDirectory(modeRulesDir)
|
|
425
|
+
if (files.length > 0) {
|
|
426
|
+
const content = formatDirectoryContent(files, cwd)
|
|
427
|
+
modeRules.push(content)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// If we found mode-specific rules in .roo/rules-${mode}/ directories, use them
|
|
433
|
+
if (modeRules.length > 0) {
|
|
434
|
+
modeRuleContent = "\n" + modeRules.join("\n\n")
|
|
435
|
+
usedRuleFile = `rules-${mode} directories`
|
|
436
|
+
} else {
|
|
437
|
+
// Fall back to existing behavior for legacy files
|
|
438
|
+
const rooModeRuleFile = `.roorules-${mode}`
|
|
439
|
+
modeRuleContent = await safeReadFile(path.join(cwd, rooModeRuleFile))
|
|
440
|
+
if (modeRuleContent) {
|
|
441
|
+
usedRuleFile = rooModeRuleFile
|
|
442
|
+
} else {
|
|
443
|
+
const clineModeRuleFile = `.clinerules-${mode}`
|
|
444
|
+
modeRuleContent = await safeReadFile(path.join(cwd, clineModeRuleFile))
|
|
445
|
+
if (modeRuleContent) {
|
|
446
|
+
usedRuleFile = clineModeRuleFile
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Add language preference if provided
|
|
453
|
+
if (options.language) {
|
|
454
|
+
const languageName = isLanguage(options.language) ? LANGUAGES[options.language] : options.language
|
|
455
|
+
sections.push(
|
|
456
|
+
`Language Preference:\nYou should always speak and think in the "${languageName}" (${options.language}) language unless the user gives you instructions below to do otherwise.`,
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Add global instructions first
|
|
461
|
+
if (typeof globalCustomInstructions === "string" && globalCustomInstructions.trim()) {
|
|
462
|
+
sections.push(`Global Instructions:\n${globalCustomInstructions.trim()}`)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Add mode-specific instructions after
|
|
466
|
+
if (typeof modeCustomInstructions === "string" && modeCustomInstructions.trim()) {
|
|
467
|
+
sections.push(`Mode-specific Instructions:\n${modeCustomInstructions.trim()}`)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Add rules - include both mode-specific and generic rules if they exist
|
|
471
|
+
const rules = []
|
|
472
|
+
|
|
473
|
+
// Add mode-specific rules first if they exist
|
|
474
|
+
if (modeRuleContent && modeRuleContent.trim()) {
|
|
475
|
+
if (usedRuleFile.includes(path.join(".roo", `rules-${mode}`))) {
|
|
476
|
+
rules.push(modeRuleContent.trim())
|
|
477
|
+
} else {
|
|
478
|
+
rules.push(`# Rules from ${usedRuleFile}:\n${modeRuleContent}`)
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (options.rooIgnoreInstructions) {
|
|
483
|
+
rules.push(options.rooIgnoreInstructions)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Add AGENTS.md content if enabled (default: true)
|
|
487
|
+
// Load from root and optionally subdirectories with .roo folders based on enableSubfolderRules setting
|
|
488
|
+
if (options.settings?.useAgentRules !== false) {
|
|
489
|
+
const agentRulesContent = await loadAllAgentRulesFiles(cwd, enableSubfolderRules)
|
|
490
|
+
if (agentRulesContent && agentRulesContent.trim()) {
|
|
491
|
+
rules.push(agentRulesContent.trim())
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Add generic rules
|
|
496
|
+
const genericRuleContent = await loadRuleFiles(cwd, enableSubfolderRules)
|
|
497
|
+
if (genericRuleContent && genericRuleContent.trim()) {
|
|
498
|
+
rules.push(genericRuleContent.trim())
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (rules.length > 0) {
|
|
502
|
+
sections.push(`Rules:\n\n${rules.join("\n\n")}`)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const joinedSections = sections.join("\n\n")
|
|
506
|
+
|
|
507
|
+
return joinedSections
|
|
508
|
+
? `
|
|
509
|
+
====
|
|
510
|
+
|
|
511
|
+
USER'S CUSTOM INSTRUCTIONS
|
|
512
|
+
|
|
513
|
+
The following additional instructions are provided by the user, and should be followed to the best of your ability.
|
|
514
|
+
|
|
515
|
+
${joinedSections}
|
|
516
|
+
`
|
|
517
|
+
: ""
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Check if a file should be included in rule compilation.
|
|
522
|
+
* Excludes cache files and system files that shouldn't be processed as rules.
|
|
523
|
+
*/
|
|
524
|
+
function shouldIncludeRuleFile(filename: string): boolean {
|
|
525
|
+
const basename = path.basename(filename)
|
|
526
|
+
|
|
527
|
+
const cachePatterns = [
|
|
528
|
+
"*.DS_Store",
|
|
529
|
+
"*.bak",
|
|
530
|
+
"*.cache",
|
|
531
|
+
"*.crdownload",
|
|
532
|
+
"*.db",
|
|
533
|
+
"*.dmp",
|
|
534
|
+
"*.dump",
|
|
535
|
+
"*.eslintcache",
|
|
536
|
+
"*.lock",
|
|
537
|
+
"*.log",
|
|
538
|
+
"*.old",
|
|
539
|
+
"*.part",
|
|
540
|
+
"*.partial",
|
|
541
|
+
"*.pyc",
|
|
542
|
+
"*.pyo",
|
|
543
|
+
"*.stackdump",
|
|
544
|
+
"*.swo",
|
|
545
|
+
"*.swp",
|
|
546
|
+
"*.temp",
|
|
547
|
+
"*.tmp",
|
|
548
|
+
"Thumbs.db",
|
|
549
|
+
]
|
|
550
|
+
|
|
551
|
+
return !cachePatterns.some((pattern) => {
|
|
552
|
+
if (pattern.startsWith("*.")) {
|
|
553
|
+
const extension = pattern.slice(1)
|
|
554
|
+
return basename.endsWith(extension)
|
|
555
|
+
} else {
|
|
556
|
+
return basename === pattern
|
|
557
|
+
}
|
|
558
|
+
})
|
|
559
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { getRulesSection } from "./rules"
|
|
2
|
+
export { getSystemInfoSection } from "./system-info"
|
|
3
|
+
export { getObjectiveSection } from "./objective"
|
|
4
|
+
export { addCustomInstructions } from "./custom-instructions"
|
|
5
|
+
export { getSharedToolUseSection } from "./tool-use"
|
|
6
|
+
export { getToolUseGuidelinesSection } from "./tool-use-guidelines"
|
|
7
|
+
export { getCapabilitiesSection } from "./capabilities"
|
|
8
|
+
export { getModesSection } from "./modes"
|
|
9
|
+
export { markdownFormattingSection } from "./markdown-formatting"
|
|
10
|
+
export { getSkillsSection } from "./skills"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function markdownFormattingSection(): string {
|
|
2
|
+
return `====
|
|
3
|
+
|
|
4
|
+
MARKDOWN RULES
|
|
5
|
+
|
|
6
|
+
ALL responses MUST show ANY \`language construct\` OR filename reference as clickable, exactly as [\`filename OR language.declaration()\`](relative/file/path.ext:line); line is required for \`syntax\` and optional for filename links. This applies to ALL markdown responses and ALSO those in attempt_completion`
|
|
7
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as vscode from "../../../../shim/vscode"
|
|
2
|
+
|
|
3
|
+
import type { ModeConfig } from "../../../../types"
|
|
4
|
+
|
|
5
|
+
import { getAllModesWithPrompts } from "../../../shared/modes"
|
|
6
|
+
import { ensureSettingsDirectoryExists } from "../../../utils/globalContext"
|
|
7
|
+
|
|
8
|
+
export async function getModesSection(context: vscode.ExtensionContext): Promise<string> {
|
|
9
|
+
// Make sure path gets created
|
|
10
|
+
await ensureSettingsDirectoryExists(context)
|
|
11
|
+
|
|
12
|
+
// Get all modes with their overrides from extension state
|
|
13
|
+
const allModes = await getAllModesWithPrompts(context)
|
|
14
|
+
|
|
15
|
+
const modesContent = `====
|
|
16
|
+
|
|
17
|
+
MODES
|
|
18
|
+
|
|
19
|
+
- These are the currently available modes:
|
|
20
|
+
${allModes
|
|
21
|
+
.map((mode: ModeConfig) => {
|
|
22
|
+
let description: string
|
|
23
|
+
if (mode.whenToUse && mode.whenToUse.trim() !== "") {
|
|
24
|
+
// Use whenToUse as the primary description, indenting subsequent lines for readability
|
|
25
|
+
description = mode.whenToUse.replace(/\n/g, "\n ")
|
|
26
|
+
} else {
|
|
27
|
+
// Fallback to the first sentence of roleDefinition if whenToUse is not available
|
|
28
|
+
description = mode.roleDefinition.split(".")[0]
|
|
29
|
+
}
|
|
30
|
+
return ` * "${mode.name}" mode (${mode.slug}) - ${description}`
|
|
31
|
+
})
|
|
32
|
+
.join("\n")}`
|
|
33
|
+
|
|
34
|
+
return modesContent
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function getObjectiveSection(): string {
|
|
2
|
+
return `====
|
|
3
|
+
|
|
4
|
+
OBJECTIVE
|
|
5
|
+
|
|
6
|
+
You accomplish a given task iteratively, breaking it down into clear steps and working through them methodically.
|
|
7
|
+
|
|
8
|
+
1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
|
|
9
|
+
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
|
|
10
|
+
3. Remember, you have extensive capabilities with access to a wide range of tools that can be used in powerful and clever ways as necessary to accomplish each goal. Before calling a tool, do some analysis. First, analyze the file structure provided in environment_details to gain context and insights for proceeding effectively. Next, think about which of the provided tools is the most relevant tool to accomplish the user's task. Go through each of the required parameters of the relevant tool and determine if the user has directly provided or given enough information to infer a value. When deciding if the parameter can be inferred, carefully consider all the context to see if it supports a specific value. If all of the required parameters are present or can be reasonably inferred, proceed with the tool use. BUT, if one of the values for a required parameter is missing, DO NOT invoke the tool (not even with fillers for the missing params) and instead, ask the user to provide the missing parameters using the ask_followup_question tool. DO NOT ask for more information on optional parameters if it is not provided.
|
|
11
|
+
4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user.
|
|
12
|
+
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`
|
|
13
|
+
}
|