codemini-cli 0.5.10 → 0.5.11
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/OPERATIONS.md +242 -242
- package/README.md +588 -588
- package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-7HL7yft8.js → highlighted-body-OFNGDK62-CANOG7Xg.js} +1 -1
- package/codemini-web/dist/assets/{index-BK75hMb2.js → index-B71xykPM.js} +108 -108
- package/codemini-web/dist/assets/index-Dkq1DdDX.css +2 -0
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-Z_w7M93P.js +1 -0
- package/codemini-web/dist/index.html +23 -23
- package/codemini-web/lib/approval-manager.js +32 -32
- package/codemini-web/lib/runtime-bridge.js +17 -11
- package/codemini-web/server.js +534 -205
- package/deployment.md +212 -212
- package/package.json +1 -1
- package/skills/brainstorm/SKILL.md +77 -77
- package/skills/codemini.skills.json +40 -40
- package/skills/grill-me/SKILL.md +30 -30
- package/skills/superpowers-lite/SKILL.md +82 -82
- package/src/cli.js +74 -74
- package/src/commands/chat.js +210 -210
- package/src/commands/run.js +313 -313
- package/src/commands/skill.js +438 -304
- package/src/commands/web.js +57 -57
- package/src/core/agent-loop.js +980 -980
- package/src/core/ast.js +309 -307
- package/src/core/chat-runtime.js +6261 -6253
- package/src/core/command-evaluator.js +72 -72
- package/src/core/command-loader.js +311 -311
- package/src/core/command-policy.js +301 -301
- package/src/core/command-risk.js +156 -156
- package/src/core/config-store.js +289 -289
- package/src/core/constants.js +18 -1
- package/src/core/context-compact.js +365 -365
- package/src/core/default-system-prompt.js +114 -107
- package/src/core/dream-audit.js +105 -105
- package/src/core/dream-consolidate.js +229 -229
- package/src/core/dream-evaluator.js +185 -185
- package/src/core/fff-adapter.js +383 -383
- package/src/core/memory-store.js +543 -543
- package/src/core/project-index.js +737 -548
- package/src/core/project-instructions.js +98 -98
- package/src/core/provider/anthropic.js +514 -514
- package/src/core/provider/openai-compatible.js +501 -501
- package/src/core/reflect-skill.js +178 -178
- package/src/core/reply-language.js +40 -40
- package/src/core/session-store.js +474 -474
- package/src/core/shell-profile.js +237 -237
- package/src/core/shell.js +323 -323
- package/src/core/soul.js +69 -69
- package/src/core/system-prompt-composer.js +52 -52
- package/src/core/tool-args.js +199 -154
- package/src/core/tool-output.js +184 -184
- package/src/core/tool-result-store.js +206 -206
- package/src/core/tools.js +3024 -2893
- package/src/core/version.js +11 -11
- package/src/tui/chat-app.js +5171 -5171
- package/src/tui/tool-activity/presenters/misc.js +30 -30
- package/src/tui/tool-activity/presenters/system.js +20 -20
- package/templates/project-requirements/report-shell.html +582 -582
- package/codemini-web/dist/assets/index-BSdIdn3L.css +0 -2
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-Dg9qh8mg.js +0 -1
package/src/core/soul.js
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { getBaseConfigDir } from './paths.js';
|
|
5
|
-
|
|
6
|
-
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const BUNDLED_SOULS_DIR = path.resolve(MODULE_DIR, '..', '..', 'souls');
|
|
8
|
-
|
|
9
|
-
function getCustomSoulsDir() {
|
|
10
|
-
return path.join(getBaseConfigDir(), 'souls');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { BUNDLED_SOULS_DIR, getCustomSoulsDir };
|
|
14
|
-
|
|
15
|
-
function normalizeSoulName(value) {
|
|
16
|
-
const name = String(value || '').trim().toLowerCase();
|
|
17
|
-
return name || 'default';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function resolveCustomSoulPath(customPath = '') {
|
|
21
|
-
const raw = String(customPath || '').trim();
|
|
22
|
-
if (!raw) return '';
|
|
23
|
-
if (path.isAbsolute(raw)) return raw;
|
|
24
|
-
return path.join(getBaseConfigDir(), raw);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function loadSoulPrompt(config = {}) {
|
|
28
|
-
const customPath = resolveCustomSoulPath(config?.soul?.custom_path);
|
|
29
|
-
if (customPath) {
|
|
30
|
-
try {
|
|
31
|
-
const content = await fs.readFile(customPath, 'utf8');
|
|
32
|
-
const text = String(content || '').trim();
|
|
33
|
-
if (text) return `[Soul custom]\n${text}`;
|
|
34
|
-
} catch {
|
|
35
|
-
// fall through to bundled preset
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const preset = normalizeSoulName(config?.soul?.preset);
|
|
40
|
-
// Check custom souls dir first, then bundled
|
|
41
|
-
const customPresetPath = path.join(getCustomSoulsDir(), `${preset}.md`);
|
|
42
|
-
try {
|
|
43
|
-
const content = await fs.readFile(customPresetPath, 'utf8');
|
|
44
|
-
const text = String(content || '').trim();
|
|
45
|
-
if (text) return `[Soul preset: ${preset}]\n${text}`;
|
|
46
|
-
} catch {}
|
|
47
|
-
const presetPath = path.join(BUNDLED_SOULS_DIR, `${preset}.md`);
|
|
48
|
-
try {
|
|
49
|
-
const content = await fs.readFile(presetPath, 'utf8');
|
|
50
|
-
const text = String(content || '').trim();
|
|
51
|
-
if (text) return `[Soul preset: ${preset}]\n${text}`;
|
|
52
|
-
} catch {
|
|
53
|
-
// fall through to default preset
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const defaultContent = await fs.readFile(path.join(BUNDLED_SOULS_DIR, 'default.md'), 'utf8');
|
|
57
|
-
return `[Soul preset: default]\n${String(defaultContent || '').trim()}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export async function buildSystemPromptWithSoul(baseSystemPrompt, config = {}) {
|
|
61
|
-
const soulPrompt = await loadSoulPrompt(config);
|
|
62
|
-
const guard = [
|
|
63
|
-
'[Soul guard]',
|
|
64
|
-
'Apply this soul to response tone only.',
|
|
65
|
-
'Response tone only: do not change plans, code, tests, file formats, or technical decisions.',
|
|
66
|
-
'This tone directive has HIGH priority. Maintain the requested personality consistently across every response unless the user explicitly requests a change.'
|
|
67
|
-
].join('\n');
|
|
68
|
-
return [String(baseSystemPrompt || '').trim(), soulPrompt, guard].filter(Boolean).join('\n\n').trim();
|
|
69
|
-
}
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getBaseConfigDir } from './paths.js';
|
|
5
|
+
|
|
6
|
+
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const BUNDLED_SOULS_DIR = path.resolve(MODULE_DIR, '..', '..', 'souls');
|
|
8
|
+
|
|
9
|
+
function getCustomSoulsDir() {
|
|
10
|
+
return path.join(getBaseConfigDir(), 'souls');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { BUNDLED_SOULS_DIR, getCustomSoulsDir };
|
|
14
|
+
|
|
15
|
+
function normalizeSoulName(value) {
|
|
16
|
+
const name = String(value || '').trim().toLowerCase();
|
|
17
|
+
return name || 'default';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveCustomSoulPath(customPath = '') {
|
|
21
|
+
const raw = String(customPath || '').trim();
|
|
22
|
+
if (!raw) return '';
|
|
23
|
+
if (path.isAbsolute(raw)) return raw;
|
|
24
|
+
return path.join(getBaseConfigDir(), raw);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function loadSoulPrompt(config = {}) {
|
|
28
|
+
const customPath = resolveCustomSoulPath(config?.soul?.custom_path);
|
|
29
|
+
if (customPath) {
|
|
30
|
+
try {
|
|
31
|
+
const content = await fs.readFile(customPath, 'utf8');
|
|
32
|
+
const text = String(content || '').trim();
|
|
33
|
+
if (text) return `[Soul custom]\n${text}`;
|
|
34
|
+
} catch {
|
|
35
|
+
// fall through to bundled preset
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const preset = normalizeSoulName(config?.soul?.preset);
|
|
40
|
+
// Check custom souls dir first, then bundled
|
|
41
|
+
const customPresetPath = path.join(getCustomSoulsDir(), `${preset}.md`);
|
|
42
|
+
try {
|
|
43
|
+
const content = await fs.readFile(customPresetPath, 'utf8');
|
|
44
|
+
const text = String(content || '').trim();
|
|
45
|
+
if (text) return `[Soul preset: ${preset}]\n${text}`;
|
|
46
|
+
} catch {}
|
|
47
|
+
const presetPath = path.join(BUNDLED_SOULS_DIR, `${preset}.md`);
|
|
48
|
+
try {
|
|
49
|
+
const content = await fs.readFile(presetPath, 'utf8');
|
|
50
|
+
const text = String(content || '').trim();
|
|
51
|
+
if (text) return `[Soul preset: ${preset}]\n${text}`;
|
|
52
|
+
} catch {
|
|
53
|
+
// fall through to default preset
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const defaultContent = await fs.readFile(path.join(BUNDLED_SOULS_DIR, 'default.md'), 'utf8');
|
|
57
|
+
return `[Soul preset: default]\n${String(defaultContent || '').trim()}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function buildSystemPromptWithSoul(baseSystemPrompt, config = {}) {
|
|
61
|
+
const soulPrompt = await loadSoulPrompt(config);
|
|
62
|
+
const guard = [
|
|
63
|
+
'[Soul guard]',
|
|
64
|
+
'Apply this soul to response tone only.',
|
|
65
|
+
'Response tone only: do not change plans, code, tests, file formats, or technical decisions.',
|
|
66
|
+
'This tone directive has HIGH priority. Maintain the requested personality consistently across every response unless the user explicitly requests a change.'
|
|
67
|
+
].join('\n');
|
|
68
|
+
return [String(baseSystemPrompt || '').trim(), soulPrompt, guard].filter(Boolean).join('\n\n').trim();
|
|
69
|
+
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import { buildMemorySnapshot } from './memory-prompt.js';
|
|
2
|
-
import { loadProjectInstructions } from './project-instructions.js';
|
|
3
|
-
import { buildSystemPromptWithReplyLanguage, stripReplyLanguageDirective } from './reply-language.js';
|
|
4
|
-
import { buildSystemPromptWithSoul } from './soul.js';
|
|
5
|
-
|
|
6
|
-
function normalizePromptPart(value) {
|
|
7
|
-
return stripReplyLanguageDirective(String(value || '').trim());
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function joinPromptParts(parts) {
|
|
11
|
-
return parts.map(normalizePromptPart).filter(Boolean).join('\n\n');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function composeSystemPrompt({
|
|
15
|
-
shellRulesPrompt = '',
|
|
16
|
-
config = {},
|
|
17
|
-
workspaceRoot = process.cwd(),
|
|
18
|
-
skillsPrompt = '',
|
|
19
|
-
memorySnapshot,
|
|
20
|
-
includeMemory = true,
|
|
21
|
-
projectInstructionsSnippet,
|
|
22
|
-
includeProjectInstructions = true,
|
|
23
|
-
projectContextSnippet = '',
|
|
24
|
-
projectContextGuidance = '',
|
|
25
|
-
extraPrompts = [],
|
|
26
|
-
includeSoul = true
|
|
27
|
-
} = {}) {
|
|
28
|
-
const shellAndSoul = includeSoul
|
|
29
|
-
? await buildSystemPromptWithSoul(shellRulesPrompt, config)
|
|
30
|
-
: shellRulesPrompt;
|
|
31
|
-
const memoryPrompt = memorySnapshot !== undefined
|
|
32
|
-
? memorySnapshot
|
|
33
|
-
: includeMemory
|
|
34
|
-
? await buildMemorySnapshot({ config, workspaceRoot }).catch(() => '')
|
|
35
|
-
: '';
|
|
36
|
-
const projectInstructionsPrompt = projectInstructionsSnippet !== undefined
|
|
37
|
-
? projectInstructionsSnippet
|
|
38
|
-
: includeProjectInstructions
|
|
39
|
-
? await loadProjectInstructions({ cwd: workspaceRoot, config }).catch(() => '')
|
|
40
|
-
: '';
|
|
41
|
-
const hasProjectInstructions = /\bProject Instructions:\s*\n/i.test(shellAndSoul);
|
|
42
|
-
const body = joinPromptParts([
|
|
43
|
-
shellAndSoul,
|
|
44
|
-
hasProjectInstructions ? '' : projectInstructionsPrompt,
|
|
45
|
-
skillsPrompt,
|
|
46
|
-
memoryPrompt,
|
|
47
|
-
projectContextSnippet,
|
|
48
|
-
projectContextSnippet ? projectContextGuidance : '',
|
|
49
|
-
...extraPrompts
|
|
50
|
-
]);
|
|
51
|
-
return buildSystemPromptWithReplyLanguage(body, config);
|
|
52
|
-
}
|
|
1
|
+
import { buildMemorySnapshot } from './memory-prompt.js';
|
|
2
|
+
import { loadProjectInstructions } from './project-instructions.js';
|
|
3
|
+
import { buildSystemPromptWithReplyLanguage, stripReplyLanguageDirective } from './reply-language.js';
|
|
4
|
+
import { buildSystemPromptWithSoul } from './soul.js';
|
|
5
|
+
|
|
6
|
+
function normalizePromptPart(value) {
|
|
7
|
+
return stripReplyLanguageDirective(String(value || '').trim());
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function joinPromptParts(parts) {
|
|
11
|
+
return parts.map(normalizePromptPart).filter(Boolean).join('\n\n');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function composeSystemPrompt({
|
|
15
|
+
shellRulesPrompt = '',
|
|
16
|
+
config = {},
|
|
17
|
+
workspaceRoot = process.cwd(),
|
|
18
|
+
skillsPrompt = '',
|
|
19
|
+
memorySnapshot,
|
|
20
|
+
includeMemory = true,
|
|
21
|
+
projectInstructionsSnippet,
|
|
22
|
+
includeProjectInstructions = true,
|
|
23
|
+
projectContextSnippet = '',
|
|
24
|
+
projectContextGuidance = '',
|
|
25
|
+
extraPrompts = [],
|
|
26
|
+
includeSoul = true
|
|
27
|
+
} = {}) {
|
|
28
|
+
const shellAndSoul = includeSoul
|
|
29
|
+
? await buildSystemPromptWithSoul(shellRulesPrompt, config)
|
|
30
|
+
: shellRulesPrompt;
|
|
31
|
+
const memoryPrompt = memorySnapshot !== undefined
|
|
32
|
+
? memorySnapshot
|
|
33
|
+
: includeMemory
|
|
34
|
+
? await buildMemorySnapshot({ config, workspaceRoot }).catch(() => '')
|
|
35
|
+
: '';
|
|
36
|
+
const projectInstructionsPrompt = projectInstructionsSnippet !== undefined
|
|
37
|
+
? projectInstructionsSnippet
|
|
38
|
+
: includeProjectInstructions
|
|
39
|
+
? await loadProjectInstructions({ cwd: workspaceRoot, config }).catch(() => '')
|
|
40
|
+
: '';
|
|
41
|
+
const hasProjectInstructions = /\bProject Instructions:\s*\n/i.test(shellAndSoul);
|
|
42
|
+
const body = joinPromptParts([
|
|
43
|
+
shellAndSoul,
|
|
44
|
+
hasProjectInstructions ? '' : projectInstructionsPrompt,
|
|
45
|
+
skillsPrompt,
|
|
46
|
+
memoryPrompt,
|
|
47
|
+
projectContextSnippet,
|
|
48
|
+
projectContextSnippet ? projectContextGuidance : '',
|
|
49
|
+
...extraPrompts
|
|
50
|
+
]);
|
|
51
|
+
return buildSystemPromptWithReplyLanguage(body, config);
|
|
52
|
+
}
|
package/src/core/tool-args.js
CHANGED
|
@@ -1,181 +1,226 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
|
|
2
|
+
import { normalizePath } from './string-utils.js';
|
|
3
|
+
|
|
3
4
|
export function parseInlineRangePath(value) {
|
|
5
|
+
const text = String(value || '').trim();
|
|
6
|
+
if (!text) return null;
|
|
7
|
+
const match = text.match(/^(.*?):(\d+)(?:-(\d+))?$/);
|
|
8
|
+
if (!match) return null;
|
|
9
|
+
const [, maybePath, startRaw, endRaw] = match;
|
|
10
|
+
if (!maybePath || /^(?:[A-Za-z])$/.test(maybePath)) return null;
|
|
11
|
+
const startLine = Number(startRaw);
|
|
12
|
+
const endLine = Number(endRaw || startRaw);
|
|
13
|
+
if (!Number.isFinite(startLine) || startLine <= 0) return null;
|
|
14
|
+
if (!Number.isFinite(endLine) || endLine < startLine) return null;
|
|
15
|
+
return {
|
|
16
|
+
path: maybePath,
|
|
17
|
+
start_line: startLine,
|
|
18
|
+
end_line: endLine
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function normalizeFilePathValue(value, { stripInlineRange = false } = {}) {
|
|
4
23
|
const text = String(value || '').trim();
|
|
5
|
-
if (!text) return
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
if (!
|
|
13
|
-
|
|
24
|
+
if (!text) return '';
|
|
25
|
+
const inlineRange = stripInlineRange ? parseInlineRangePath(text) : null;
|
|
26
|
+
return normalizePath(inlineRange?.path || text);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizePathValueWithInlineRange(value) {
|
|
30
|
+
const text = String(value || '').trim();
|
|
31
|
+
if (!text) return { path: '', inlineRange: null };
|
|
32
|
+
const inlineRange = parseInlineRangePath(text);
|
|
14
33
|
return {
|
|
15
|
-
path:
|
|
16
|
-
|
|
17
|
-
end_line: endLine
|
|
34
|
+
path: normalizePath(inlineRange?.path || text),
|
|
35
|
+
inlineRange
|
|
18
36
|
};
|
|
19
37
|
}
|
|
20
38
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
function normalizeBooleanValue(value) {
|
|
40
|
+
if (typeof value === 'boolean') return value;
|
|
41
|
+
if (typeof value === 'number') return value !== 0;
|
|
42
|
+
const text = String(value ?? '').trim().toLowerCase();
|
|
43
|
+
if (!text) return undefined;
|
|
44
|
+
if (['true', '1', 'yes', 'y', 'on'].includes(text)) return true;
|
|
45
|
+
if (['false', '0', 'no', 'n', 'off'].includes(text)) return false;
|
|
46
|
+
return Boolean(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function normalizeReadArgs(rawArgs) {
|
|
50
|
+
const source =
|
|
51
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
52
|
+
? { ...rawArgs }
|
|
53
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
54
|
+
|
|
55
|
+
const normalized = { ...source };
|
|
56
|
+
const aliasPath = source.path || source.file_path || source.file || source.target || '';
|
|
57
|
+
const normalizedPath = normalizePathValueWithInlineRange(aliasPath);
|
|
58
|
+
if (normalizedPath.path) normalized.path = normalizedPath.path;
|
|
59
|
+
|
|
60
|
+
if (!Number.isFinite(Number(normalized.start_line)) && Number.isFinite(Number(source.offset))) {
|
|
61
|
+
normalized.start_line = Number(source.offset);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!Number.isFinite(Number(normalized.end_line)) && Number.isFinite(Number(source.limit))) {
|
|
65
|
+
const startLine = Number(normalized.start_line);
|
|
66
|
+
const limit = Number(source.limit);
|
|
67
|
+
if (startLine > 0 && limit > 0) {
|
|
68
|
+
normalized.end_line = startLine + limit - 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const inlineRange = normalizedPath.inlineRange || parseInlineRangePath(normalized.path);
|
|
44
73
|
if (inlineRange) {
|
|
45
|
-
normalized.path = inlineRange.path;
|
|
74
|
+
normalized.path = normalizePath(inlineRange.path);
|
|
46
75
|
if (!Number.isFinite(Number(normalized.start_line))) normalized.start_line = inlineRange.start_line;
|
|
47
76
|
if (!Number.isFinite(Number(normalized.end_line))) normalized.end_line = inlineRange.end_line;
|
|
48
77
|
}
|
|
49
|
-
|
|
50
|
-
return normalized;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function normalizePathArgs(rawArgs, aliases = []) {
|
|
54
|
-
const source =
|
|
55
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
56
|
-
? { ...rawArgs }
|
|
57
|
-
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
78
|
+
|
|
79
|
+
return normalized;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function normalizePathArgs(rawArgs, aliases = []) {
|
|
83
|
+
const source =
|
|
84
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
85
|
+
? { ...rawArgs }
|
|
86
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
58
87
|
const normalized = { ...source };
|
|
59
88
|
const keys = ['path', ...aliases];
|
|
60
89
|
for (const key of keys) {
|
|
61
|
-
const value =
|
|
90
|
+
const value = normalizeFilePathValue(source?.[key] || '', { stripInlineRange: true });
|
|
62
91
|
if (value) {
|
|
63
92
|
normalized.path = value;
|
|
64
93
|
break;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return normalized;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function normalizePatternArgs(rawArgs, aliases = [], defaultPathAliases = []) {
|
|
71
|
-
const source =
|
|
72
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
73
|
-
? { ...rawArgs }
|
|
74
|
-
: { pattern: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
75
|
-
const normalized = { ...source };
|
|
76
|
-
for (const key of ['pattern', ...aliases]) {
|
|
77
|
-
const value = String(source?.[key] || '').trim();
|
|
78
|
-
if (value) {
|
|
79
|
-
normalized.pattern = value;
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return normalized;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function normalizePatternArgs(rawArgs, aliases = [], defaultPathAliases = []) {
|
|
100
|
+
const source =
|
|
101
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
102
|
+
? { ...rawArgs }
|
|
103
|
+
: { pattern: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
104
|
+
const normalized = { ...source };
|
|
105
|
+
for (const key of ['pattern', ...aliases]) {
|
|
106
|
+
const value = String(source?.[key] || '').trim();
|
|
107
|
+
if (value) {
|
|
108
|
+
normalized.pattern = value;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
83
112
|
for (const key of ['path', ...defaultPathAliases]) {
|
|
84
|
-
const value =
|
|
113
|
+
const value = normalizeFilePathValue(source?.[key] || '', { stripInlineRange: true });
|
|
85
114
|
if (value) {
|
|
86
115
|
normalized.path = value;
|
|
87
116
|
break;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return normalized;
|
|
91
|
-
}
|
|
92
|
-
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return normalized;
|
|
120
|
+
}
|
|
121
|
+
|
|
93
122
|
export function normalizeWriteArgs(rawArgs) {
|
|
94
|
-
const source =
|
|
95
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
96
|
-
? { ...rawArgs }
|
|
97
|
-
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
98
|
-
const normalized = { ...source };
|
|
99
|
-
const filePath =
|
|
123
|
+
const source =
|
|
124
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
125
|
+
? { ...rawArgs }
|
|
126
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
127
|
+
const normalized = { ...source };
|
|
128
|
+
const filePath = normalizeFilePathValue(source.path || source.file_path || source.file || '', { stripInlineRange: true });
|
|
100
129
|
if (filePath) normalized.path = filePath;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
args
|
|
144
|
-
?
|
|
145
|
-
:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (toolName === '
|
|
163
|
-
|
|
130
|
+
const append = normalizeBooleanValue(source.append);
|
|
131
|
+
const fullFileRewrite = normalizeBooleanValue(source.full_file_rewrite);
|
|
132
|
+
if (append !== undefined) normalized.append = append;
|
|
133
|
+
if (fullFileRewrite !== undefined) normalized.full_file_rewrite = fullFileRewrite;
|
|
134
|
+
if (normalized.content == null) {
|
|
135
|
+
if (source.text != null) normalized.content = source.text;
|
|
136
|
+
if (source.new_content != null) normalized.content = source.new_content;
|
|
137
|
+
}
|
|
138
|
+
return normalized;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function normalizeWebFetchArgs(rawArgs) {
|
|
142
|
+
const normalized = normalizePathArgs(rawArgs, ['url', 'href', 'link', 'target']);
|
|
143
|
+
const url = String(normalized.url || normalized.path || '').trim();
|
|
144
|
+
return { ...normalized, url };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function normalizeWebSearchArgs(rawArgs) {
|
|
148
|
+
const normalized = normalizePatternArgs(rawArgs, ['query', 'q', 'keyword']);
|
|
149
|
+
const query = String(normalized.query || normalized.pattern || '').trim();
|
|
150
|
+
return { ...normalized, query };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function buildDeleteApprovalDetails(source, rawPath) {
|
|
154
|
+
const existing =
|
|
155
|
+
source?.approval && typeof source.approval === 'object' && !Array.isArray(source.approval)
|
|
156
|
+
? source.approval
|
|
157
|
+
: {};
|
|
158
|
+
const approvalPath = String(existing.path || rawPath || '').trim();
|
|
159
|
+
const approvalName = String(existing.name || (approvalPath ? path.basename(approvalPath) : '') || '').trim();
|
|
160
|
+
const approvalType = String(existing.type || '').trim();
|
|
161
|
+
|
|
162
|
+
const approval = {};
|
|
163
|
+
if (approvalPath) approval.path = approvalPath;
|
|
164
|
+
if (approvalName) approval.name = approvalName;
|
|
165
|
+
if (approvalType) approval.type = approvalType;
|
|
166
|
+
return Object.keys(approval).length > 0 ? approval : undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function normalizeToolArguments(toolName, args, rawArguments) {
|
|
170
|
+
const rawText = typeof rawArguments === 'string' ? rawArguments.trim() : '';
|
|
171
|
+
const primitive =
|
|
172
|
+
args == null || Array.isArray(args) || typeof args !== 'object'
|
|
173
|
+
? args
|
|
174
|
+
: null;
|
|
175
|
+
const source =
|
|
176
|
+
args && typeof args === 'object' && !Array.isArray(args)
|
|
177
|
+
? { ...args }
|
|
178
|
+
: {};
|
|
179
|
+
|
|
180
|
+
if (primitive != null && typeof primitive !== 'object') {
|
|
181
|
+
source._raw = rawText || String(primitive);
|
|
182
|
+
} else if (!source._raw && rawText && source._invalid_json) {
|
|
183
|
+
source._raw = rawText;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const stringValue =
|
|
187
|
+
typeof primitive === 'string'
|
|
188
|
+
? primitive.trim()
|
|
189
|
+
: String(source._raw || '').trim();
|
|
190
|
+
|
|
191
|
+
if (toolName === 'read') return normalizeReadArgs({ ...source, ...(stringValue && !source.path ? { path: stringValue } : {}) });
|
|
192
|
+
if (toolName === 'list') return normalizePathArgs({ ...source, ...(stringValue && !source.path ? { path: stringValue } : {}) }, ['dir', 'directory', 'file_path', 'file', 'target']);
|
|
193
|
+
if (toolName === 'glob') return normalizePatternArgs({ ...source, ...(stringValue && !source.pattern ? { pattern: stringValue } : {}) }, ['glob', 'query'], ['directory', 'dir', 'cwd', 'file_path', 'file']);
|
|
194
|
+
if (toolName === 'grep') return normalizePatternArgs({ ...source, ...(stringValue && !source.pattern ? { pattern: stringValue } : {}) }, ['query', 'symbol', 'q'], ['directory', 'dir', 'cwd', 'file_path', 'file']);
|
|
195
|
+
if (toolName === 'write') return normalizeWriteArgs({ ...source, ...(stringValue && !source.path ? { path: stringValue } : {}) });
|
|
196
|
+
|
|
164
197
|
if (toolName === 'edit') {
|
|
165
|
-
const
|
|
198
|
+
const rawPathValue = source.path || source.file || source.file_path || stringValue || '';
|
|
199
|
+
const inlineRange = parseInlineRangePath(rawPathValue);
|
|
200
|
+
const value = normalizeFilePathValue(rawPathValue, { stripInlineRange: true });
|
|
166
201
|
if (value && !source.path) source.path = value;
|
|
202
|
+
if (value && source.path) source.path = value;
|
|
203
|
+
if (inlineRange) {
|
|
204
|
+
if (!Number.isFinite(Number(source.start_line))) source.start_line = inlineRange.start_line;
|
|
205
|
+
if (!Number.isFinite(Number(source.end_line))) source.end_line = inlineRange.end_line;
|
|
206
|
+
}
|
|
207
|
+
if (source.old_text == null && source.old_string != null) source.old_text = source.old_string;
|
|
208
|
+
if (source.new_text == null && source.new_string != null) source.new_text = source.new_string;
|
|
209
|
+
if (source.new_text == null && source.content != null && source.old_text != null) source.new_text = source.content;
|
|
210
|
+
const replaceAll = normalizeBooleanValue(source.replace_all ?? source.replaceAll);
|
|
211
|
+
if (replaceAll !== undefined) source.replace_all = replaceAll;
|
|
167
212
|
return source;
|
|
168
213
|
}
|
|
169
|
-
|
|
170
|
-
if (toolName === 'delete') {
|
|
171
|
-
const normalized = normalizePathArgs(
|
|
172
|
-
{ ...source, ...(stringValue && !source.path ? { path: stringValue } : {}) },
|
|
173
|
-
['file_path', 'file', 'target', 'directory', 'dir']
|
|
174
|
-
);
|
|
175
|
-
const approval = buildDeleteApprovalDetails(normalized, normalized.path);
|
|
176
|
-
if (approval) normalized.approval = approval;
|
|
177
|
-
return normalized;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return source;
|
|
181
|
-
}
|
|
214
|
+
|
|
215
|
+
if (toolName === 'delete') {
|
|
216
|
+
const normalized = normalizePathArgs(
|
|
217
|
+
{ ...source, ...(stringValue && !source.path ? { path: stringValue } : {}) },
|
|
218
|
+
['file_path', 'file', 'target', 'directory', 'dir']
|
|
219
|
+
);
|
|
220
|
+
const approval = buildDeleteApprovalDetails(normalized, normalized.path);
|
|
221
|
+
if (approval) normalized.approval = approval;
|
|
222
|
+
return normalized;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return source;
|
|
226
|
+
}
|