closer-code 1.0.0 → 1.0.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/.closer-code.example.json +32 -0
- package/DUAL_OPTIMIZATION_COMPLETE.md +293 -0
- package/README.md +167 -557
- package/README_OPENAI.md +163 -0
- package/THINKING_THROTTLING_OPTIMIZATION.md +244 -0
- package/THROTTLING_1_5S_OPTIMIZATION.md +401 -0
- package/TOOLS_IMPROVEMENTS_SUMMARY.md +273 -0
- package/cloco.md +5 -1
- package/config.example.json +15 -94
- package/config.mcp.example.json +81 -0
- package/dist/bash-runner.js +5 -126
- package/dist/batch-cli.js +286 -20658
- package/dist/closer-cli.js +329 -21135
- package/dist/index.js +308 -31036
- package/docs/ANTHROPIC_TOOL_ERROR_HANDLING.md +220 -0
- package/docs/BUILD_COMMANDS.md +79 -0
- package/docs/CTRL_Z_SUPPORT.md +189 -0
- package/docs/DEEPSEEK_R1_INTEGRATION.md +427 -0
- package/docs/FIX_OPENAI_TOOL_ERROR_HANDLING.md +375 -0
- package/docs/FIX_OPENAI_TOOL_RESULT.md +198 -0
- package/docs/INPUT_ENHANCEMENTS.md +192 -0
- package/docs/MCP_IMPLEMENTATION_SUMMARY.md +428 -0
- package/docs/MCP_INTEGRATION.md +418 -0
- package/docs/MCP_QUICKSTART.md +299 -0
- package/docs/MCP_README.md +166 -0
- package/docs/MINIFY_BUILD.md +180 -0
- package/docs/MULTILINE_INPUT_FEATURE.md +119 -0
- package/docs/OPENAI_CLIENT.md +258 -0
- package/docs/PROJECT_LOCAL_CONFIG.md +471 -0
- package/docs/PROJECT_LOCAL_CONFIG_SUMMARY.md +407 -0
- package/docs/REFACTOR_CONVERSATION.md +306 -0
- package/docs/REGION_EDIT_DESIGN.md +475 -0
- package/docs/SIGNAL_HANDLING.md +171 -0
- package/docs/STREAM_UPDATE_THROTTLE.md +273 -0
- package/docs/TOOLS_REFACTOR_PLAN.md +520 -0
- package/ds_r1.md +249 -0
- package/examples/abort-fence-example.js +294 -0
- package/package.json +18 -4
- package/src/ai-client-legacy.js +6 -1
- package/src/ai-client-openai.js +672 -0
- package/src/ai-client.js +30 -13
- package/src/closer-cli.jsx +450 -162
- package/src/components/fullscreen-conversation.jsx +157 -0
- package/src/components/ink-text-input/index.jsx +324 -0
- package/src/components/multiline-text-input.jsx +614 -0
- package/src/components/progress-bar.jsx +135 -0
- package/src/components/tool-detail-view.jsx +82 -0
- package/src/components/tool-renderers/bash-renderer.jsx +197 -0
- package/src/components/tool-renderers/file-edit-renderer.jsx +247 -0
- package/src/components/tool-renderers/file-read-renderer.jsx +261 -0
- package/src/components/tool-renderers/file-write-renderer.jsx +222 -0
- package/src/components/tool-renderers/index.jsx +178 -0
- package/src/components/tool-renderers/list-renderer.jsx +274 -0
- package/src/components/tool-renderers/search-renderer.jsx +248 -0
- package/src/config.js +182 -20
- package/src/conversation/abort-fence.js +158 -0
- package/src/conversation/core.js +377 -0
- package/src/conversation/index.js +33 -0
- package/src/conversation/mcp-integration.js +96 -0
- package/src/conversation/plan-manager.js +295 -0
- package/src/conversation/stream-handler.js +154 -0
- package/src/conversation/tool-executor.js +264 -0
- package/src/conversation.js +23 -958
- package/src/hooks/use-throttled-state.js +158 -0
- package/src/input/enhanced-input.jsx +268 -0
- package/src/input/history.js +342 -0
- package/src/logger.js +20 -0
- package/src/mcp/client.js +275 -0
- package/src/mcp/tools-adapter.js +149 -0
- package/src/planner.js +18 -5
- package/src/prompt-builder.js +159 -0
- package/src/tools.js +457 -25
- package/src/utils/json-parser.js +231 -0
- package/src/utils/json-repair.js +146 -0
- package/src/utils/platform.js +259 -0
- package/test/test-ctrl-bf.js +121 -0
- package/test/test-deepseek-reasoning.js +118 -0
- package/test/test-history-navigation.js +80 -0
- package/test/test-input-fix.js +105 -0
- package/test/test-input-history.js +98 -0
- package/test/test-mcp.js +115 -0
- package/test/test-openai-client.js +152 -0
- package/test/test-openai-tool-result.js +199 -0
- package/test/test-project-config.js +106 -0
- package/test/test-shortcuts.js +79 -0
- package/test/test-stream-throttle.js +124 -0
- package/test/test-tool-error-handling.js +95 -0
- package/test/verify-input-fix.sh +35 -0
- package/test-abort-fence.js +263 -0
- package/test-abort-fix.js +54 -0
- package/test-abort-new-conversation.js +75 -0
- package/test-ctrl-z.js +54 -0
- package/test-file-read.js +105 -0
- package/test-tool-display.js +127 -0
- package/src/closer-cli.jsx.backup +0 -948
- package/test/workflows/longtalk/cloco.md +0 -19
- package/test/workflows/longtalk/emoji_500.txt +0 -63
- package/test/workflows/longtalk/emoji_list.txt +0 -20
- package/test-ctrl-c.jsx +0 -126
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP 工具适配器
|
|
3
|
+
*
|
|
4
|
+
* 将 MCP 工具转换为 betaZodTool 格式,以便与现有工具系统集成
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
|
|
9
|
+
import { getMCPClientManager } from './client.js';
|
|
10
|
+
import { logger } from '../logger.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 将 MCP 工具的 JSON Schema 转换为 Zod Schema
|
|
14
|
+
* @param {Object} jsonSchema - MCP 工具的 inputSchema (JSON Schema)
|
|
15
|
+
* @returns {z.ZodTypeAny} Zod Schema
|
|
16
|
+
*/
|
|
17
|
+
function jsonSchemaToZod(jsonSchema) {
|
|
18
|
+
// 简化版本:处理常见的 JSON Schema 类型
|
|
19
|
+
// 实际项目中可能需要更完整的转换
|
|
20
|
+
|
|
21
|
+
if (!jsonSchema || !jsonSchema.type) {
|
|
22
|
+
return z.object({});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { type, properties, required } = jsonSchema;
|
|
26
|
+
|
|
27
|
+
if (type === 'object' && properties) {
|
|
28
|
+
const shape = {};
|
|
29
|
+
|
|
30
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
31
|
+
let zodType;
|
|
32
|
+
|
|
33
|
+
switch (propSchema.type) {
|
|
34
|
+
case 'string':
|
|
35
|
+
zodType = z.string();
|
|
36
|
+
break;
|
|
37
|
+
case 'number':
|
|
38
|
+
case 'integer':
|
|
39
|
+
zodType = z.number();
|
|
40
|
+
break;
|
|
41
|
+
case 'boolean':
|
|
42
|
+
zodType = z.boolean();
|
|
43
|
+
break;
|
|
44
|
+
case 'array':
|
|
45
|
+
zodType = z.array(z.any());
|
|
46
|
+
break;
|
|
47
|
+
case 'object':
|
|
48
|
+
zodType = z.object({});
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
zodType = z.any();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 处理可选字段
|
|
55
|
+
const isRequired = Array.isArray(required) && required.includes(propName);
|
|
56
|
+
shape[propName] = isRequired ? zodType : zodType.optional();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return z.object(shape);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 其他类型作为 any 处理
|
|
63
|
+
return z.any();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 为 MCP 工具创建描述文本(包含服务器信息)
|
|
68
|
+
* @param {string} serverName - 服务器名称
|
|
69
|
+
* @param {Object} mcpTool - MCP 工具定义
|
|
70
|
+
* @returns {string} 增强的描述
|
|
71
|
+
*/
|
|
72
|
+
function enhanceDescription(serverName, mcpTool) {
|
|
73
|
+
const baseDesc = mcpTool.description || mcpTool.name;
|
|
74
|
+
return `[MCP: ${serverName}] ${baseDesc}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 将 MCP 工具列表转换为 betaZodTool 列表
|
|
79
|
+
* @param {Array} mcpTools - MCP 工具列表
|
|
80
|
+
* @returns {Array} betaZodTool 列表
|
|
81
|
+
*/
|
|
82
|
+
export function convertMCPToolsToBetaZod(mcpTools) {
|
|
83
|
+
const converted = [];
|
|
84
|
+
|
|
85
|
+
for (const mcpTool of mcpTools) {
|
|
86
|
+
try {
|
|
87
|
+
const { name, originalName, serverName, description, inputSchema } = mcpTool;
|
|
88
|
+
|
|
89
|
+
// 转换 JSON Schema 为 Zod Schema
|
|
90
|
+
const zodSchema = jsonSchemaToZod(inputSchema);
|
|
91
|
+
|
|
92
|
+
// 创建 betaZodTool
|
|
93
|
+
const betaTool = betaZodTool({
|
|
94
|
+
name: name,
|
|
95
|
+
description: enhanceDescription(serverName, { name: originalName, description }),
|
|
96
|
+
inputSchema: zodSchema,
|
|
97
|
+
run: async (input) => {
|
|
98
|
+
const manager = getMCPClientManager();
|
|
99
|
+
|
|
100
|
+
logger.debug(`执行 MCP 工具: ${serverName}.${originalName}`);
|
|
101
|
+
|
|
102
|
+
const result = await manager.callTool(serverName, originalName, input);
|
|
103
|
+
|
|
104
|
+
// 返回 JSON 字符串(与现有工具保持一致)
|
|
105
|
+
return JSON.stringify(result);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
converted.push(betaTool);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
logger.error(`转换 MCP 工具失败 (${mcpTool.name}): ${error.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return converted;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 获取所有 MCP 工具的 betaZodTool 格式
|
|
120
|
+
* @returns {Promise<Array>} betaZodTool 列表
|
|
121
|
+
*/
|
|
122
|
+
export async function getAllMCPToolsAsBetaZod() {
|
|
123
|
+
const manager = getMCPClientManager();
|
|
124
|
+
const mcpTools = manager.getAllTools();
|
|
125
|
+
|
|
126
|
+
return convertMCPToolsToBetaZod(mcpTools);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 生成 MCP 工具的简短摘要
|
|
131
|
+
* @param {string} toolName - 工具名称
|
|
132
|
+
* @param {Object} input - 工具输入
|
|
133
|
+
* @param {Object} result - 工具结果
|
|
134
|
+
* @returns {string} 简短摘要
|
|
135
|
+
*/
|
|
136
|
+
export function generateMCPToolSummary(toolName, input, result) {
|
|
137
|
+
// 解析工具名称(格式:serverName_toolName)
|
|
138
|
+
const parts = toolName.split('_');
|
|
139
|
+
const serverName = parts[0];
|
|
140
|
+
const shortToolName = parts.slice(1).join('_');
|
|
141
|
+
|
|
142
|
+
const success = result?.success;
|
|
143
|
+
|
|
144
|
+
if (success) {
|
|
145
|
+
return `✓ [${serverName}] ${shortToolName}`;
|
|
146
|
+
} else {
|
|
147
|
+
return `✗ [${serverName}] ${shortToolName}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
package/src/planner.js
CHANGED
|
@@ -80,11 +80,16 @@ export class TaskPlan {
|
|
|
80
80
|
export class TaskPlanner {
|
|
81
81
|
constructor(config) {
|
|
82
82
|
this.config = config;
|
|
83
|
-
this.
|
|
83
|
+
this._aiClientPromise = createAIClient(config);
|
|
84
84
|
this.toolExecutor = new ToolExecutor(config);
|
|
85
85
|
this.memory = loadMemory();
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
// 延迟初始化的 getter
|
|
89
|
+
async getAIClient() {
|
|
90
|
+
return await this._aiClientPromise;
|
|
91
|
+
}
|
|
92
|
+
|
|
88
93
|
/**
|
|
89
94
|
* 为用户请求创建任务计划
|
|
90
95
|
*/
|
|
@@ -128,7 +133,8 @@ Respond with only the JSON plan, no additional text.`
|
|
|
128
133
|
];
|
|
129
134
|
|
|
130
135
|
try {
|
|
131
|
-
const
|
|
136
|
+
const aiClient = await this.getAIClient();
|
|
137
|
+
const response = await aiClient.chat(messages, { systemPrompt });
|
|
132
138
|
const text = response.content.find(c => c.type === 'text')?.text || '{}';
|
|
133
139
|
const planData = JSON.parse(text);
|
|
134
140
|
|
|
@@ -309,7 +315,8 @@ Respond with a JSON object describing the patterns found.`;
|
|
|
309
315
|
];
|
|
310
316
|
|
|
311
317
|
try {
|
|
312
|
-
const
|
|
318
|
+
const aiClient = await this.getAIClient();
|
|
319
|
+
const response = await aiClient.chat(messages, { systemPrompt });
|
|
313
320
|
const text = response.content.find(c => c.type === 'text')?.text || '{}';
|
|
314
321
|
const patterns = JSON.parse(text);
|
|
315
322
|
|
|
@@ -335,10 +342,15 @@ Respond with a JSON object describing the patterns found.`;
|
|
|
335
342
|
export class ProblemDiagnoser {
|
|
336
343
|
constructor(config) {
|
|
337
344
|
this.config = config;
|
|
338
|
-
this.
|
|
345
|
+
this._aiClientPromise = createAIClient(config);
|
|
339
346
|
this.toolExecutor = new ToolExecutor(config);
|
|
340
347
|
}
|
|
341
348
|
|
|
349
|
+
// 延迟初始化的 getter
|
|
350
|
+
async getAIClient() {
|
|
351
|
+
return await this._aiClientPromise;
|
|
352
|
+
}
|
|
353
|
+
|
|
342
354
|
/**
|
|
343
355
|
* 诊断错误
|
|
344
356
|
*/
|
|
@@ -365,7 +377,8 @@ ${contextInfo ? `\nContext:\n${contextInfo}` : ''}`
|
|
|
365
377
|
}
|
|
366
378
|
];
|
|
367
379
|
|
|
368
|
-
const
|
|
380
|
+
const aiClient = await this.getAIClient();
|
|
381
|
+
const response = await aiClient.chat(messages, { systemPrompt });
|
|
369
382
|
return response.content.find(c => c.type === 'text')?.text;
|
|
370
383
|
}
|
|
371
384
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 系统提示词构建器
|
|
3
|
+
*
|
|
4
|
+
* 提供灵活的方式来构建和优化 AI 助手的系统提示词
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { loadMemory } from './config.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 读取全局 cloco.md 文件内容
|
|
11
|
+
*/
|
|
12
|
+
async function readGlobalCloco() {
|
|
13
|
+
try {
|
|
14
|
+
const fs = await import('fs/promises');
|
|
15
|
+
const path = await import('path');
|
|
16
|
+
const os = await import('os');
|
|
17
|
+
const homeDir = os.homedir();
|
|
18
|
+
const globalClocoPath = path.join(homeDir, '.closer-code', 'cloco.md');
|
|
19
|
+
return await fs.readFile(globalClocoPath, 'utf-8');
|
|
20
|
+
} catch (error) {
|
|
21
|
+
// 全局配置不存在是正常情况,不报错
|
|
22
|
+
if (error.code !== 'ENOENT') {
|
|
23
|
+
console.error('读取全局 cloco.md 失败:', error.message);
|
|
24
|
+
}
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 读取项目级 cloco.md 文件内容
|
|
31
|
+
*/
|
|
32
|
+
async function readProjectCloco() {
|
|
33
|
+
try {
|
|
34
|
+
const fs = await import('fs/promises');
|
|
35
|
+
const path = await import('path');
|
|
36
|
+
const clocoPath = path.join(process.cwd(), 'cloco.md');
|
|
37
|
+
return await fs.readFile(clocoPath, 'utf-8');
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// 项目配置不存在是正常情况,不报错
|
|
40
|
+
if (error.code !== 'ENOENT') {
|
|
41
|
+
console.error('读取项目 cloco.md 失败:', error.message);
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 构建系统提示词(优化后的版本)
|
|
49
|
+
*/
|
|
50
|
+
export async function getSystemPrompt(config, workflowTest = false) {
|
|
51
|
+
const memory = loadMemory();
|
|
52
|
+
const projectKey = config.behavior.workingDir || 'default';
|
|
53
|
+
const projectInfo = memory.projects?.[projectKey];
|
|
54
|
+
|
|
55
|
+
// 读取全局和项目级 cloco.md
|
|
56
|
+
const globalClocoContent = await readGlobalCloco();
|
|
57
|
+
const projectClocoContent = await readProjectCloco();
|
|
58
|
+
|
|
59
|
+
// 读取 WORKFLOW_SYSTEM_PROMPT(如果需要)
|
|
60
|
+
let workflowPrompt = '';
|
|
61
|
+
if (workflowTest) {
|
|
62
|
+
// 这里需要从 conversation.js 导入 WORKFLOW_SYSTEM_PROMPT
|
|
63
|
+
// 暂时留空,后面会处理
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 构建完整的系统提示词
|
|
67
|
+
const prompt = `You are Closer, an AI programming assistant designed to help developers with coding tasks, debugging, and project management.
|
|
68
|
+
|
|
69
|
+
## Tool Usage (CRITICAL - Read Carefully)
|
|
70
|
+
|
|
71
|
+
**PRIORITY ORDER: Use specialized tools FIRST, bash LAST**
|
|
72
|
+
|
|
73
|
+
### File Operations - ALWAYS use tools first:
|
|
74
|
+
1. **Read file**: Use \`readFile\` tool (NOT \`cat\`)
|
|
75
|
+
2. **Read specific lines**: Use \`readFileLines\` tool (NOT \`sed -e '2,3p'\`)
|
|
76
|
+
- Example: \`readFileLines({ filePath: "app.js", startLine: 10, endLine: 20 })\`
|
|
77
|
+
3. **Read from end**: Use \`readFileTail\` tool (NOT \`tail -n 100\`)
|
|
78
|
+
- Example: \`readFileTail({ filePath: "log.txt", lines: 100 })\`
|
|
79
|
+
4. **Write file**: Use \`writeFile\` tool (NOT \`echo > file\`)
|
|
80
|
+
5. **Edit file**: Use \`editFile\` or \`regionConstrainedEdit\` tool (NOT \`sed -i\`)
|
|
81
|
+
|
|
82
|
+
### When to use bash:
|
|
83
|
+
- Running tests (\`npm test\`, \`pytest\`)
|
|
84
|
+
- Git operations (\`git status\`, \`git commit\`)
|
|
85
|
+
- Build commands (\`npm run build\`)
|
|
86
|
+
- List directory (\`ls -la\`)
|
|
87
|
+
- Install dependencies (\`npm install\`)
|
|
88
|
+
|
|
89
|
+
### Why use tools?
|
|
90
|
+
- More efficient (less token usage)
|
|
91
|
+
- Better error handling
|
|
92
|
+
- Structured output
|
|
93
|
+
- Automatic file size optimization
|
|
94
|
+
|
|
95
|
+
**Key principle**: Use tools proactively - show, don't just talk about it.
|
|
96
|
+
|
|
97
|
+
## Error Handling (IMPORTANT)
|
|
98
|
+
|
|
99
|
+
When a tool returns an error:
|
|
100
|
+
1. **Identify** the error type (ENOENT, EACCES, etc.)
|
|
101
|
+
2. **Fix** the issue (create directory, fix permissions, etc.)
|
|
102
|
+
3. **Retry** the operation
|
|
103
|
+
|
|
104
|
+
**Retry strategy**: 2-3 attempts maximum. If still failing, explain to the user.
|
|
105
|
+
|
|
106
|
+
Common fixes:
|
|
107
|
+
- Missing directory → \`mkdir -p path/to/dir\`
|
|
108
|
+
- Wrong content → Read file first, then edit
|
|
109
|
+
|
|
110
|
+
## Task Execution Guide
|
|
111
|
+
When asked to analyze or review code:
|
|
112
|
+
- Start by searching for relevant files
|
|
113
|
+
- Read the key files to understand the codebase
|
|
114
|
+
- Focus on files that are most relevant to the task
|
|
115
|
+
- Provide specific findings with file names and line numbers
|
|
116
|
+
|
|
117
|
+
**NOTE**: Only perform comprehensive analysis when explicitly requested. For specific questions, focus on the relevant parts.
|
|
118
|
+
|
|
119
|
+
## Current Context
|
|
120
|
+
Working Directory: ${config.behavior.workingDir}
|
|
121
|
+
Available Tools: ${config.tools.enabled.join(', ')}
|
|
122
|
+
${projectInfo ? `
|
|
123
|
+
## Project Patterns
|
|
124
|
+
This is a familiar project. Remember these patterns:
|
|
125
|
+
${JSON.stringify(projectInfo.patterns, null, 2)}
|
|
126
|
+
` : ''}
|
|
127
|
+
|
|
128
|
+
## Behavior Configuration
|
|
129
|
+
- Auto Plan: ${config.behavior.autoPlan ? 'Enabled' : 'Disabled'}
|
|
130
|
+
- Auto Execute: ${config.behavior.autoExecute ? 'Enabled (low-risk operations only)' : 'Disabled'}
|
|
131
|
+
- Confirm Destructive: ${config.behavior.confirmDestructive ? 'Enabled' : 'Disabled'}
|
|
132
|
+
|
|
133
|
+
${globalClocoContent ? `
|
|
134
|
+
## 📋 Global Behavior Guidelines (CRITICAL)
|
|
135
|
+
**The following global guidelines from ~/.closer-code/cloco.md are EXTREMELY IMPORTANT and MUST be followed:**
|
|
136
|
+
|
|
137
|
+
${globalClocoContent}
|
|
138
|
+
|
|
139
|
+
**These global guidelines take precedence over general instructions. Follow them carefully**
|
|
140
|
+
` : ''}
|
|
141
|
+
|
|
142
|
+
${projectClocoContent ? `
|
|
143
|
+
## 📋 Project Behavior Guidelines (CRITICAL)
|
|
144
|
+
**The following project-specific guidelines from ./cloco.md are EXTREMELY IMPORTANT and MUST be followed:**
|
|
145
|
+
|
|
146
|
+
${projectClocoContent}
|
|
147
|
+
|
|
148
|
+
**These project guidelines take precedence over general instructions. Follow them carefully**
|
|
149
|
+
` : ''}
|
|
150
|
+
|
|
151
|
+
${!globalClocoContent && !projectClocoContent ? `
|
|
152
|
+
## 📋 Behavior Guidelines
|
|
153
|
+
No custom behavior guidelines found. You can add them by:
|
|
154
|
+
- Creating ~/.closer-code/cloco.md for global guidelines
|
|
155
|
+
- Creating ./cloco.md for project-specific guidelines
|
|
156
|
+
` : ''}${workflowPrompt}`;
|
|
157
|
+
|
|
158
|
+
return prompt;
|
|
159
|
+
}
|