@revealui/ai 0.1.3 → 0.2.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/LICENSE.commercial +2 -3
- package/README.md +3 -0
- package/dist/a2a/card.d.ts.map +1 -1
- package/dist/a2a/handler.d.ts +1 -1
- package/dist/a2a/handler.d.ts.map +1 -1
- package/dist/a2a/handler.js +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/audit/emitter.d.ts.map +1 -1
- package/dist/audit/index.d.ts.map +1 -1
- package/dist/audit/observer.d.ts.map +1 -1
- package/dist/audit/policy.d.ts.map +1 -1
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/client/hooks/index.d.ts.map +1 -1
- package/dist/client/hooks/useAgentContext.d.ts.map +1 -1
- package/dist/client/hooks/useAgentEvents.d.ts.map +1 -1
- package/dist/client/hooks/useAgentStream.d.ts.map +1 -1
- package/dist/client/hooks/useEpisodicMemory.d.ts.map +1 -1
- package/dist/client/hooks/useWorkingMemory.d.ts.map +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/embeddings/index.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/inference/context-assembly.d.ts.map +1 -1
- package/dist/inference/context-budget.d.ts +46 -0
- package/dist/inference/context-budget.d.ts.map +1 -0
- package/dist/inference/context-budget.js +113 -0
- package/dist/inference/index.d.ts +8 -0
- package/dist/inference/index.d.ts.map +1 -0
- package/dist/inference/index.js +7 -0
- package/dist/inference/overflow-compressor.d.ts.map +1 -1
- package/dist/inference/runRag.d.ts.map +1 -1
- package/dist/inference/task-decomposer.d.ts +75 -0
- package/dist/inference/task-decomposer.d.ts.map +1 -0
- package/dist/inference/task-decomposer.js +190 -0
- package/dist/inference/tool-result-compressor.d.ts +39 -0
- package/dist/inference/tool-result-compressor.d.ts.map +1 -0
- package/dist/inference/tool-result-compressor.js +180 -0
- package/dist/ingestion/bm25.d.ts.map +1 -1
- package/dist/ingestion/cms-indexer.d.ts.map +1 -1
- package/dist/ingestion/file-parsers.d.ts.map +1 -1
- package/dist/ingestion/hybrid-search.d.ts.map +1 -1
- package/dist/ingestion/index.d.ts.map +1 -1
- package/dist/ingestion/pipeline.d.ts +2 -1
- package/dist/ingestion/pipeline.d.ts.map +1 -1
- package/dist/ingestion/pipeline.js +10 -5
- package/dist/ingestion/rag-vector-service.d.ts.map +1 -1
- package/dist/ingestion/reranker.d.ts.map +1 -1
- package/dist/ingestion/text-splitter.d.ts.map +1 -1
- package/dist/llm/cache-utils.d.ts.map +1 -1
- package/dist/llm/client.d.ts +12 -2
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +38 -7
- package/dist/llm/key-validator.d.ts.map +1 -1
- package/dist/llm/provider-health.d.ts.map +1 -1
- package/dist/llm/providers/anthropic.d.ts.map +1 -1
- package/dist/llm/providers/anthropic.js +3 -1
- package/dist/llm/providers/base.d.ts.map +1 -1
- package/dist/llm/providers/bitnet.d.ts +28 -0
- package/dist/llm/providers/bitnet.d.ts.map +1 -0
- package/dist/llm/providers/bitnet.js +36 -0
- package/dist/llm/providers/groq.d.ts.map +1 -1
- package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
- package/dist/llm/providers/ollama.d.ts.map +1 -1
- package/dist/llm/providers/openai.d.ts.map +1 -1
- package/dist/llm/providers/vultr.d.ts.map +1 -1
- package/dist/llm/response-cache.d.ts.map +1 -1
- package/dist/llm/semantic-cache.d.ts.map +1 -1
- package/dist/llm/semantic-cache.js +4 -4
- package/dist/llm/server.d.ts +1 -0
- package/dist/llm/server.d.ts.map +1 -1
- package/dist/llm/server.js +1 -0
- package/dist/llm/token-counter.d.ts.map +1 -1
- package/dist/llm/workspace-provider-config.d.ts.map +1 -1
- package/dist/memory/agent/context-manager.d.ts.map +1 -1
- package/dist/memory/agent/index.d.ts.map +1 -1
- package/dist/memory/crdt/index.d.ts.map +1 -1
- package/dist/memory/crdt/lww-register.d.ts.map +1 -1
- package/dist/memory/crdt/or-set.d.ts.map +1 -1
- package/dist/memory/crdt/pn-counter.d.ts.map +1 -1
- package/dist/memory/crdt/vector-clock.d.ts.map +1 -1
- package/dist/memory/errors/index.d.ts.map +1 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/persistence/crdt-persistence.d.ts.map +1 -1
- package/dist/memory/persistence/crdt-persistence.js +2 -5
- package/dist/memory/persistence/index.d.ts.map +1 -1
- package/dist/memory/preferences/index.d.ts.map +1 -1
- package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -1
- package/dist/memory/preferences/user-preferences-manager.js +10 -10
- package/dist/memory/services/index.d.ts.map +1 -1
- package/dist/memory/services/node-id-service.d.ts.map +1 -1
- package/dist/memory/stores/episodic-memory.d.ts.map +1 -1
- package/dist/memory/stores/episodic-memory.js +2 -1
- package/dist/memory/stores/index.d.ts.map +1 -1
- package/dist/memory/stores/procedural-memory.d.ts.map +1 -1
- package/dist/memory/stores/semantic-memory.d.ts.map +1 -1
- package/dist/memory/stores/working-memory.d.ts.map +1 -1
- package/dist/memory/utils/deep-clone.d.ts.map +1 -1
- package/dist/memory/utils/index.d.ts +0 -1
- package/dist/memory/utils/index.d.ts.map +1 -1
- package/dist/memory/utils/index.js +0 -1
- package/dist/memory/utils/sql-helpers.d.ts.map +1 -1
- package/dist/memory/utils/validation.d.ts.map +1 -1
- package/dist/memory/utils/validation.js +3 -1
- package/dist/memory/vector/index.d.ts.map +1 -1
- package/dist/memory/vector/vector-memory-service.d.ts +3 -0
- package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
- package/dist/memory/vector/vector-memory-service.js +18 -5
- package/dist/observability/logger.d.ts.map +1 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/query.d.ts.map +1 -1
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/orchestration/agent.d.ts.map +1 -1
- package/dist/orchestration/defaults.d.ts.map +1 -1
- package/dist/orchestration/memory-integration.d.ts.map +1 -1
- package/dist/orchestration/orchestrator.d.ts.map +1 -1
- package/dist/orchestration/runtime.d.ts +24 -0
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +67 -1
- package/dist/orchestration/streaming-runtime.d.ts.map +1 -1
- package/dist/orchestration/streaming-runtime.js +11 -4
- package/dist/orchestration/ticket-agent.d.ts.map +1 -1
- package/dist/orchestration/ticket-agent.js +3 -1
- package/dist/skills/activation/index.d.ts.map +1 -1
- package/dist/skills/activation/skill-activator.d.ts.map +1 -1
- package/dist/skills/catalog/catalog-search.d.ts.map +1 -1
- package/dist/skills/catalog/catalog-types.d.ts.map +1 -1
- package/dist/skills/catalog/index.d.ts.map +1 -1
- package/dist/skills/catalog/vercel-catalog.d.ts.map +1 -1
- package/dist/skills/compat/index.d.ts.map +1 -1
- package/dist/skills/compat/skill-enhancer.d.ts.map +1 -1
- package/dist/skills/compat/tool-mapper.d.ts.map +1 -1
- package/dist/skills/compat/vercel-compat.d.ts.map +1 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/integration/agent-skill-provider.d.ts.map +1 -1
- package/dist/skills/integration/index.d.ts.map +1 -1
- package/dist/skills/loader/github-loader.d.ts.map +1 -1
- package/dist/skills/loader/github-loader.js +36 -17
- package/dist/skills/loader/index.d.ts.map +1 -1
- package/dist/skills/loader/local-loader.d.ts.map +1 -1
- package/dist/skills/loader/vercel-loader.d.ts.map +1 -1
- package/dist/skills/loader/vercel-loader.js +35 -17
- package/dist/skills/loader/vercel-types.d.ts.map +1 -1
- package/dist/skills/parser/index.d.ts.map +1 -1
- package/dist/skills/parser/skill-md-parser.d.ts.map +1 -1
- package/dist/skills/parser/skill-md-parser.js +2 -2
- package/dist/skills/registry/index.d.ts.map +1 -1
- package/dist/skills/registry/skill-registry.d.ts.map +1 -1
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/templates/agent-spec.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/prompt-spec.d.ts.map +1 -1
- package/dist/templates/skill-spec.d.ts.map +1 -1
- package/dist/tools/base.d.ts +33 -0
- package/dist/tools/base.d.ts.map +1 -1
- package/dist/tools/cms/collection-tools.d.ts.map +1 -1
- package/dist/tools/cms/factory.d.ts.map +1 -1
- package/dist/tools/cms/global-tools.d.ts.map +1 -1
- package/dist/tools/cms/index.d.ts.map +1 -1
- package/dist/tools/cms/media-tools.d.ts.map +1 -1
- package/dist/tools/cms/user-tools.d.ts.map +1 -1
- package/dist/tools/coding/file-edit.d.ts +6 -0
- package/dist/tools/coding/file-edit.d.ts.map +1 -0
- package/dist/tools/coding/file-edit.js +73 -0
- package/dist/tools/coding/file-glob.d.ts +6 -0
- package/dist/tools/coding/file-glob.d.ts.map +1 -0
- package/dist/tools/coding/file-glob.js +120 -0
- package/dist/tools/coding/file-grep.d.ts +6 -0
- package/dist/tools/coding/file-grep.d.ts.map +1 -0
- package/dist/tools/coding/file-grep.js +194 -0
- package/dist/tools/coding/file-read.d.ts +6 -0
- package/dist/tools/coding/file-read.d.ts.map +1 -0
- package/dist/tools/coding/file-read.js +69 -0
- package/dist/tools/coding/file-write.d.ts +6 -0
- package/dist/tools/coding/file-write.d.ts.map +1 -0
- package/dist/tools/coding/file-write.js +49 -0
- package/dist/tools/coding/git-ops.d.ts +6 -0
- package/dist/tools/coding/git-ops.d.ts.map +1 -0
- package/dist/tools/coding/git-ops.js +102 -0
- package/dist/tools/coding/index.d.ts +40 -0
- package/dist/tools/coding/index.d.ts.map +1 -0
- package/dist/tools/coding/index.js +62 -0
- package/dist/tools/coding/lint-fix.d.ts +9 -0
- package/dist/tools/coding/lint-fix.d.ts.map +1 -0
- package/dist/tools/coding/lint-fix.js +256 -0
- package/dist/tools/coding/project-context.d.ts +6 -0
- package/dist/tools/coding/project-context.d.ts.map +1 -0
- package/dist/tools/coding/project-context.js +126 -0
- package/dist/tools/coding/safety.d.ts +26 -0
- package/dist/tools/coding/safety.d.ts.map +1 -0
- package/dist/tools/coding/safety.js +104 -0
- package/dist/tools/coding/shell-exec.d.ts +6 -0
- package/dist/tools/coding/shell-exec.d.ts.map +1 -0
- package/dist/tools/coding/shell-exec.js +79 -0
- package/dist/tools/coding/test-runner.d.ts +10 -0
- package/dist/tools/coding/test-runner.d.ts.map +1 -0
- package/dist/tools/coding/test-runner.js +214 -0
- package/dist/tools/deduplicator.d.ts.map +1 -1
- package/dist/tools/document-summarizer.d.ts.map +1 -1
- package/dist/tools/mcp-adapter.d.ts.map +1 -1
- package/dist/tools/memory/index.d.ts.map +1 -1
- package/dist/tools/memory/store-memory.d.ts.map +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/ticket-tools.d.ts.map +1 -1
- package/dist/tools/web/duck-duck-go.d.ts.map +1 -1
- package/dist/tools/web/exa.d.ts.map +1 -1
- package/dist/tools/web/index.d.ts.map +1 -1
- package/dist/tools/web/scraper.d.ts.map +1 -1
- package/dist/tools/web/tavily.d.ts.map +1 -1
- package/dist/tools/web/types.d.ts.map +1 -1
- package/package.json +38 -11
- package/dist/memory/utils/logger.d.ts +0 -21
- package/dist/memory/utils/logger.d.ts.map +0 -1
- package/dist/memory/utils/logger.js +0 -62
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* git_ops — Git operations wrapper (status, diff, log, blame)
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import { z } from 'zod/v4';
|
|
6
|
+
import { getSafetyConfig } from './safety.js';
|
|
7
|
+
const GIT_OPERATIONS = ['status', 'diff', 'diff_full', 'log', 'blame', 'show', 'branch'];
|
|
8
|
+
/** Max output per git command */
|
|
9
|
+
const MAX_OUTPUT = 50_000;
|
|
10
|
+
function runGit(args, cwd) {
|
|
11
|
+
const cmd = `git ${args.join(' ')}`;
|
|
12
|
+
return execSync(cmd, {
|
|
13
|
+
cwd,
|
|
14
|
+
timeout: 15_000,
|
|
15
|
+
maxBuffer: MAX_OUTPUT,
|
|
16
|
+
encoding: 'utf8',
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
20
|
+
// Prevent pager from blocking
|
|
21
|
+
GIT_PAGER: 'cat',
|
|
22
|
+
},
|
|
23
|
+
}).trim();
|
|
24
|
+
}
|
|
25
|
+
export const gitOpsTool = {
|
|
26
|
+
name: 'git_ops',
|
|
27
|
+
label: 'Git Operations',
|
|
28
|
+
description: 'Run read-only git operations: status, diff (summary), diff_full (full patch), log, blame, show, branch. Safe operations only — no push, commit, reset, or checkout.',
|
|
29
|
+
parameters: z.object({
|
|
30
|
+
operation: z.enum(GIT_OPERATIONS).describe('Git operation to perform'),
|
|
31
|
+
args: z
|
|
32
|
+
.array(z.string())
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Additional arguments (e.g., ["--oneline", "-n", "10"] for log)'),
|
|
35
|
+
}),
|
|
36
|
+
async execute(params) {
|
|
37
|
+
const { operation, args = [] } = params;
|
|
38
|
+
const config = getSafetyConfig();
|
|
39
|
+
// Block any sneaky write operations passed as args
|
|
40
|
+
const joinedArgs = args.join(' ');
|
|
41
|
+
const dangerousFlags = ['--force', '--hard', '--delete', '-D', '--push'];
|
|
42
|
+
for (const flag of dangerousFlags) {
|
|
43
|
+
if (joinedArgs.toLowerCase().includes(flag.toLowerCase())) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: `Dangerous flag "${flag}" not allowed in git_ops. This tool is read-only.`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
let output;
|
|
52
|
+
switch (operation) {
|
|
53
|
+
case 'status':
|
|
54
|
+
output = runGit(['status', '--short', ...args], config.projectRoot);
|
|
55
|
+
break;
|
|
56
|
+
case 'diff':
|
|
57
|
+
output = runGit(['diff', '--stat', ...args], config.projectRoot);
|
|
58
|
+
break;
|
|
59
|
+
case 'diff_full':
|
|
60
|
+
// Full patch content for code review — hunks per file
|
|
61
|
+
output = runGit(['diff', '--no-color', '-U3', ...args], config.projectRoot);
|
|
62
|
+
break;
|
|
63
|
+
case 'log':
|
|
64
|
+
// Default: last 20 commits, oneline
|
|
65
|
+
if (args.length === 0) {
|
|
66
|
+
output = runGit(['log', '--oneline', '--decorate', '-n', '20'], config.projectRoot);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
output = runGit(['log', ...args], config.projectRoot);
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case 'blame':
|
|
73
|
+
if (args.length === 0) {
|
|
74
|
+
return { success: false, error: 'blame requires a file path argument' };
|
|
75
|
+
}
|
|
76
|
+
output = runGit(['blame', '--line-porcelain', ...args], config.projectRoot);
|
|
77
|
+
break;
|
|
78
|
+
case 'show':
|
|
79
|
+
output = runGit(['show', '--stat', ...args], config.projectRoot);
|
|
80
|
+
break;
|
|
81
|
+
case 'branch':
|
|
82
|
+
output = runGit(['branch', '-a', '--no-color', ...args], config.projectRoot);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
const lines = output.split('\n').length;
|
|
86
|
+
return {
|
|
87
|
+
success: true,
|
|
88
|
+
data: { operation, output },
|
|
89
|
+
content: output.length > 3000
|
|
90
|
+
? `git ${operation} (${lines} lines, truncated):\n${output.slice(0, 3000)}…`
|
|
91
|
+
: `git ${operation}:\n${output}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error: `git ${operation} failed: ${message.slice(0, 500)}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding Tools Package
|
|
3
|
+
* File operations, search, shell, git, and project context tools
|
|
4
|
+
* for the RevealUI standalone coding agent.
|
|
5
|
+
*/
|
|
6
|
+
import type { Tool } from '../base.js';
|
|
7
|
+
export { fileEditTool } from './file-edit.js';
|
|
8
|
+
export { fileGlobTool } from './file-glob.js';
|
|
9
|
+
export { fileGrepTool } from './file-grep.js';
|
|
10
|
+
export { fileReadTool } from './file-read.js';
|
|
11
|
+
export { fileWriteTool } from './file-write.js';
|
|
12
|
+
export { gitOpsTool } from './git-ops.js';
|
|
13
|
+
export { lintFixTool } from './lint-fix.js';
|
|
14
|
+
export { projectContextTool } from './project-context.js';
|
|
15
|
+
export type { SafetyConfig } from './safety.js';
|
|
16
|
+
export { configureSafety, getSafetyConfig, resolveSafePath, validateCommand, validatePath, } from './safety.js';
|
|
17
|
+
export { shellExecTool } from './shell-exec.js';
|
|
18
|
+
export { testRunnerTool } from './test-runner.js';
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for the coding tools factory
|
|
21
|
+
*/
|
|
22
|
+
export interface CodingToolsConfig {
|
|
23
|
+
/** Project root directory — all file operations sandboxed here */
|
|
24
|
+
projectRoot: string;
|
|
25
|
+
/** Additional directories to allow (e.g., /tmp for scratch files) */
|
|
26
|
+
allowedPaths?: string[];
|
|
27
|
+
/** Extra commands to deny beyond the built-in denylist */
|
|
28
|
+
extraDeniedCommands?: string[];
|
|
29
|
+
/** Extra path patterns to deny */
|
|
30
|
+
deniedPathPatterns?: RegExp[];
|
|
31
|
+
/** Which tools to include (default: all) */
|
|
32
|
+
include?: Array<'file_read' | 'file_write' | 'file_edit' | 'file_glob' | 'file_grep' | 'shell_exec' | 'git_ops' | 'project_context' | 'test_runner' | 'lint_fix'>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create coding tools with safety configuration applied.
|
|
36
|
+
*
|
|
37
|
+
* Must be called before any tool execution to establish the project root sandbox.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createCodingTools(config: CodingToolsConfig): Tool[];
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/coding/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAevC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,4CAA4C;IAC5C,OAAO,CAAC,EAAE,KAAK,CACX,WAAW,GACX,YAAY,GACZ,WAAW,GACX,WAAW,GACX,WAAW,GACX,YAAY,GACZ,SAAS,GACT,iBAAiB,GACjB,aAAa,GACb,UAAU,CACb,CAAC;CACH;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAAE,CAmBnE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding Tools Package
|
|
3
|
+
* File operations, search, shell, git, and project context tools
|
|
4
|
+
* for the RevealUI standalone coding agent.
|
|
5
|
+
*/
|
|
6
|
+
import { fileEditTool } from './file-edit.js';
|
|
7
|
+
import { fileGlobTool } from './file-glob.js';
|
|
8
|
+
import { fileGrepTool } from './file-grep.js';
|
|
9
|
+
import { fileReadTool } from './file-read.js';
|
|
10
|
+
import { fileWriteTool } from './file-write.js';
|
|
11
|
+
import { gitOpsTool } from './git-ops.js';
|
|
12
|
+
import { lintFixTool } from './lint-fix.js';
|
|
13
|
+
import { projectContextTool } from './project-context.js';
|
|
14
|
+
import { configureSafety } from './safety.js';
|
|
15
|
+
import { shellExecTool } from './shell-exec.js';
|
|
16
|
+
import { testRunnerTool } from './test-runner.js';
|
|
17
|
+
// Re-export individual tools
|
|
18
|
+
export { fileEditTool } from './file-edit.js';
|
|
19
|
+
export { fileGlobTool } from './file-glob.js';
|
|
20
|
+
export { fileGrepTool } from './file-grep.js';
|
|
21
|
+
export { fileReadTool } from './file-read.js';
|
|
22
|
+
export { fileWriteTool } from './file-write.js';
|
|
23
|
+
export { gitOpsTool } from './git-ops.js';
|
|
24
|
+
export { lintFixTool } from './lint-fix.js';
|
|
25
|
+
export { projectContextTool } from './project-context.js';
|
|
26
|
+
export { configureSafety, getSafetyConfig, resolveSafePath, validateCommand, validatePath, } from './safety.js';
|
|
27
|
+
export { shellExecTool } from './shell-exec.js';
|
|
28
|
+
export { testRunnerTool } from './test-runner.js';
|
|
29
|
+
/** All coding tools in registration order */
|
|
30
|
+
const ALL_CODING_TOOLS = [
|
|
31
|
+
fileReadTool,
|
|
32
|
+
fileWriteTool,
|
|
33
|
+
fileEditTool,
|
|
34
|
+
fileGlobTool,
|
|
35
|
+
fileGrepTool,
|
|
36
|
+
shellExecTool,
|
|
37
|
+
gitOpsTool,
|
|
38
|
+
projectContextTool,
|
|
39
|
+
testRunnerTool,
|
|
40
|
+
lintFixTool,
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* Create coding tools with safety configuration applied.
|
|
44
|
+
*
|
|
45
|
+
* Must be called before any tool execution to establish the project root sandbox.
|
|
46
|
+
*/
|
|
47
|
+
export function createCodingTools(config) {
|
|
48
|
+
// Configure the safety module
|
|
49
|
+
const safetyConfig = {
|
|
50
|
+
projectRoot: config.projectRoot,
|
|
51
|
+
allowedPaths: config.allowedPaths,
|
|
52
|
+
extraDeniedCommands: config.extraDeniedCommands,
|
|
53
|
+
deniedPathPatterns: config.deniedPathPatterns,
|
|
54
|
+
};
|
|
55
|
+
configureSafety(safetyConfig);
|
|
56
|
+
// Filter tools if include list is provided
|
|
57
|
+
if (config.include) {
|
|
58
|
+
const includeSet = new Set(config.include);
|
|
59
|
+
return ALL_CODING_TOOLS.filter((t) => includeSet.has(t.name));
|
|
60
|
+
}
|
|
61
|
+
return [...ALL_CODING_TOOLS];
|
|
62
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lint_fix — Run linter and optionally auto-fix issues
|
|
3
|
+
*
|
|
4
|
+
* Detects the linter (Biome, ESLint) and runs it with machine-parseable
|
|
5
|
+
* output. Returns structured diagnostic counts and details.
|
|
6
|
+
*/
|
|
7
|
+
import type { Tool } from '../base.js';
|
|
8
|
+
export declare const lintFixTool: Tool;
|
|
9
|
+
//# sourceMappingURL=lint-fix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint-fix.d.ts","sourceRoot":"","sources":["../../../src/tools/coding/lint-fix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AAwMnD,eAAO,MAAM,WAAW,EAAE,IAqHzB,CAAC"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lint_fix — Run linter and optionally auto-fix issues
|
|
3
|
+
*
|
|
4
|
+
* Detects the linter (Biome, ESLint) and runs it with machine-parseable
|
|
5
|
+
* output. Returns structured diagnostic counts and details.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { z } from 'zod/v4';
|
|
11
|
+
import { getSafetyConfig } from './safety.js';
|
|
12
|
+
/** Default timeout: 60 seconds */
|
|
13
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
14
|
+
/** Max output: 200KB */
|
|
15
|
+
const MAX_OUTPUT_BYTES = 200 * 1024;
|
|
16
|
+
function detectLinter(projectRoot) {
|
|
17
|
+
// Check for Biome config
|
|
18
|
+
if (existsSync(join(projectRoot, 'biome.json')) || existsSync(join(projectRoot, 'biome.jsonc'))) {
|
|
19
|
+
return 'biome';
|
|
20
|
+
}
|
|
21
|
+
// Check package.json devDependencies
|
|
22
|
+
const pkgPath = join(projectRoot, 'package.json');
|
|
23
|
+
if (existsSync(pkgPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const pkg = JSON.parse(execSync(`cat "${pkgPath}"`, { encoding: 'utf8', timeout: 5000 }));
|
|
26
|
+
const deps = {
|
|
27
|
+
...pkg.dependencies,
|
|
28
|
+
...pkg.devDependencies,
|
|
29
|
+
};
|
|
30
|
+
if (deps['@biomejs/biome'])
|
|
31
|
+
return 'biome';
|
|
32
|
+
if (deps.eslint)
|
|
33
|
+
return 'eslint';
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Fall through
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return 'unknown';
|
|
40
|
+
}
|
|
41
|
+
function buildCommand(linter, file, fix) {
|
|
42
|
+
const target = file ?? '.';
|
|
43
|
+
switch (linter) {
|
|
44
|
+
case 'biome':
|
|
45
|
+
return fix ? `npx biome check --write ${target}` : `npx biome check ${target}`;
|
|
46
|
+
case 'eslint':
|
|
47
|
+
return fix
|
|
48
|
+
? `npx eslint ${target} --fix --format json`
|
|
49
|
+
: `npx eslint ${target} --format json`;
|
|
50
|
+
default:
|
|
51
|
+
// Try pnpm lint as fallback
|
|
52
|
+
return fix ? 'pnpm lint:fix' : 'pnpm lint';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function parseBiomeOutput(output) {
|
|
56
|
+
const diagnostics = [];
|
|
57
|
+
// Parse Biome diagnostic lines: "path/file.ts:line:col lint/rule ━━━"
|
|
58
|
+
// and "path/file.ts:line:col organize_imports ━━━"
|
|
59
|
+
const diagRegex = /^(.+?):(\d+):(\d+)\s+(\S+)/gm;
|
|
60
|
+
let match = diagRegex.exec(output);
|
|
61
|
+
while (match !== null) {
|
|
62
|
+
const file = match[1] ?? '';
|
|
63
|
+
const line = Number.parseInt(match[2] ?? '0', 10);
|
|
64
|
+
const column = Number.parseInt(match[3] ?? '0', 10);
|
|
65
|
+
const rule = match[4];
|
|
66
|
+
// Extract message from the next meaningful line
|
|
67
|
+
const afterMatch = output.slice((match.index ?? 0) + match[0].length);
|
|
68
|
+
const msgMatch = afterMatch.match(/\n\s*[×✖!⚠ℹ]\s*(.+)/);
|
|
69
|
+
const message = msgMatch?.[1]?.trim() ?? rule ?? '';
|
|
70
|
+
const severity = /error|×|✖/.test(afterMatch.slice(0, 100))
|
|
71
|
+
? 'error'
|
|
72
|
+
: 'warning';
|
|
73
|
+
diagnostics.push({
|
|
74
|
+
file,
|
|
75
|
+
line,
|
|
76
|
+
column,
|
|
77
|
+
severity,
|
|
78
|
+
rule,
|
|
79
|
+
message: message.slice(0, 200),
|
|
80
|
+
});
|
|
81
|
+
match = diagRegex.exec(output);
|
|
82
|
+
}
|
|
83
|
+
// Parse summary: "Found N errors." or "Checked N file(s). No errors found."
|
|
84
|
+
const errorCountMatch = output.match(/Found\s+(\d+)\s+error/i);
|
|
85
|
+
const warningCountMatch = output.match(/Found\s+(\d+)\s+warning/i);
|
|
86
|
+
const fixableMatch = output.match(/(\d+)\s+(?:fixable|fix(?:ed)?)/i);
|
|
87
|
+
const errors = errorCountMatch
|
|
88
|
+
? Number.parseInt(errorCountMatch[1] ?? '0', 10)
|
|
89
|
+
: diagnostics.filter((d) => d.severity === 'error').length;
|
|
90
|
+
const warnings = warningCountMatch
|
|
91
|
+
? Number.parseInt(warningCountMatch[1] ?? '0', 10)
|
|
92
|
+
: diagnostics.filter((d) => d.severity === 'warning').length;
|
|
93
|
+
const fixable = fixableMatch ? Number.parseInt(fixableMatch[1] ?? '0', 10) : 0;
|
|
94
|
+
return {
|
|
95
|
+
errors,
|
|
96
|
+
warnings,
|
|
97
|
+
fixable,
|
|
98
|
+
total: errors + warnings,
|
|
99
|
+
diagnostics,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function parseEslintOutput(output) {
|
|
103
|
+
const diagnostics = [];
|
|
104
|
+
let errors = 0;
|
|
105
|
+
let warnings = 0;
|
|
106
|
+
let fixable = 0;
|
|
107
|
+
try {
|
|
108
|
+
// ESLint JSON format
|
|
109
|
+
const results = JSON.parse(output);
|
|
110
|
+
for (const result of results) {
|
|
111
|
+
errors += result.errorCount;
|
|
112
|
+
warnings += result.warningCount;
|
|
113
|
+
fixable += result.fixableErrorCount + result.fixableWarningCount;
|
|
114
|
+
for (const msg of result.messages.slice(0, 20)) {
|
|
115
|
+
diagnostics.push({
|
|
116
|
+
file: result.filePath,
|
|
117
|
+
line: msg.line,
|
|
118
|
+
column: msg.column,
|
|
119
|
+
severity: msg.severity === 2 ? 'error' : 'warning',
|
|
120
|
+
rule: msg.ruleId ?? undefined,
|
|
121
|
+
message: msg.message.slice(0, 200),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Fall back to generic parsing
|
|
128
|
+
return parseGenericOutput(output);
|
|
129
|
+
}
|
|
130
|
+
return { errors, warnings, fixable, total: errors + warnings, diagnostics };
|
|
131
|
+
}
|
|
132
|
+
function parseGenericOutput(output) {
|
|
133
|
+
const diagnostics = [];
|
|
134
|
+
// Generic pattern: file:line:col: severity message
|
|
135
|
+
const lineRegex = /^(.+?):(\d+):(\d+):\s*(error|warning|info)\s+(.+)/gm;
|
|
136
|
+
let match = lineRegex.exec(output);
|
|
137
|
+
while (match !== null) {
|
|
138
|
+
diagnostics.push({
|
|
139
|
+
file: match[1] ?? '',
|
|
140
|
+
line: Number.parseInt(match[2] ?? '0', 10),
|
|
141
|
+
column: Number.parseInt(match[3] ?? '0', 10),
|
|
142
|
+
severity: (match[4] ?? 'error'),
|
|
143
|
+
message: (match[5] ?? '').slice(0, 200),
|
|
144
|
+
});
|
|
145
|
+
match = lineRegex.exec(output);
|
|
146
|
+
}
|
|
147
|
+
const errors = diagnostics.filter((d) => d.severity === 'error').length;
|
|
148
|
+
const warnings = diagnostics.filter((d) => d.severity === 'warning').length;
|
|
149
|
+
return {
|
|
150
|
+
errors,
|
|
151
|
+
warnings,
|
|
152
|
+
fixable: 0,
|
|
153
|
+
total: errors + warnings,
|
|
154
|
+
diagnostics,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export const lintFixTool = {
|
|
158
|
+
name: 'lint_fix',
|
|
159
|
+
label: 'Lint & Fix',
|
|
160
|
+
description: 'Run the project linter and return structured diagnostics. Auto-detects Biome or ESLint. Can optionally auto-fix issues. Returns error/warning counts and individual diagnostic details.',
|
|
161
|
+
parameters: z.object({
|
|
162
|
+
file: z
|
|
163
|
+
.string()
|
|
164
|
+
.optional()
|
|
165
|
+
.describe('Specific file or directory to lint (default: entire project)'),
|
|
166
|
+
fix: z.boolean().optional().describe('Auto-fix fixable issues (default: false)'),
|
|
167
|
+
timeout: z
|
|
168
|
+
.number()
|
|
169
|
+
.optional()
|
|
170
|
+
.describe(`Timeout in milliseconds (default: ${DEFAULT_TIMEOUT_MS}, max: 300000)`),
|
|
171
|
+
}),
|
|
172
|
+
async execute(params) {
|
|
173
|
+
const { file, fix, timeout } = params;
|
|
174
|
+
const config = getSafetyConfig();
|
|
175
|
+
const timeoutMs = Math.min(timeout ?? DEFAULT_TIMEOUT_MS, 300_000);
|
|
176
|
+
const linter = detectLinter(config.projectRoot);
|
|
177
|
+
const command = buildCommand(linter, file, fix);
|
|
178
|
+
let stdout = '';
|
|
179
|
+
let stderr = '';
|
|
180
|
+
let exitCode = 0;
|
|
181
|
+
try {
|
|
182
|
+
stdout = execSync(command, {
|
|
183
|
+
cwd: config.projectRoot,
|
|
184
|
+
timeout: timeoutMs,
|
|
185
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
186
|
+
encoding: 'utf8',
|
|
187
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
188
|
+
env: {
|
|
189
|
+
...process.env,
|
|
190
|
+
FORCE_COLOR: '0',
|
|
191
|
+
NO_COLOR: '1',
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
const execErr = err;
|
|
197
|
+
if (execErr.killed || execErr.signal === 'SIGTERM') {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: `Linting timed out after ${timeoutMs}ms`,
|
|
201
|
+
data: {
|
|
202
|
+
linter,
|
|
203
|
+
command,
|
|
204
|
+
exitCode: -1,
|
|
205
|
+
summary: { errors: 0, warnings: 0, fixable: 0, total: 0, diagnostics: [] },
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
exitCode = execErr.status ?? 1;
|
|
210
|
+
stdout = (execErr.stdout ?? '').toString();
|
|
211
|
+
stderr = (execErr.stderr ?? '').toString();
|
|
212
|
+
}
|
|
213
|
+
const combined = [stdout, stderr].filter(Boolean).join('\n');
|
|
214
|
+
// Parse results
|
|
215
|
+
let summary;
|
|
216
|
+
switch (linter) {
|
|
217
|
+
case 'biome':
|
|
218
|
+
summary = parseBiomeOutput(combined);
|
|
219
|
+
break;
|
|
220
|
+
case 'eslint':
|
|
221
|
+
summary = parseEslintOutput(combined);
|
|
222
|
+
break;
|
|
223
|
+
default:
|
|
224
|
+
summary = parseGenericOutput(combined);
|
|
225
|
+
}
|
|
226
|
+
// Build token-efficient content
|
|
227
|
+
const statusIcon = summary.errors > 0 ? '✗' : summary.warnings > 0 ? '⚠' : '✓';
|
|
228
|
+
const lines = [
|
|
229
|
+
`${statusIcon} Lint: ${summary.errors} errors, ${summary.warnings} warnings (${summary.total} total)`,
|
|
230
|
+
];
|
|
231
|
+
if (summary.fixable > 0)
|
|
232
|
+
lines.push(`Fixable: ${summary.fixable}`);
|
|
233
|
+
if (fix)
|
|
234
|
+
lines.push('Mode: auto-fix applied');
|
|
235
|
+
if (file)
|
|
236
|
+
lines.push(`Target: ${file}`);
|
|
237
|
+
lines.push(`Linter: ${linter}`);
|
|
238
|
+
if (summary.diagnostics.length > 0) {
|
|
239
|
+
lines.push('', 'Diagnostics:');
|
|
240
|
+
for (const d of summary.diagnostics.slice(0, 15)) {
|
|
241
|
+
const loc = d.line ? `:${d.line}${d.column ? `:${d.column}` : ''}` : '';
|
|
242
|
+
const rule = d.rule ? ` [${d.rule}]` : '';
|
|
243
|
+
lines.push(` ${d.severity === 'error' ? '✗' : '⚠'} ${d.file}${loc}${rule}`);
|
|
244
|
+
lines.push(` ${d.message}`);
|
|
245
|
+
}
|
|
246
|
+
if (summary.diagnostics.length > 15) {
|
|
247
|
+
lines.push(` ... and ${summary.diagnostics.length - 15} more`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
success: summary.errors === 0,
|
|
252
|
+
data: { linter, command, exitCode, summary },
|
|
253
|
+
content: lines.join('\n'),
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-context.d.ts","sourceRoot":"","sources":["../../../src/tools/coding/project-context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AAuFnD,eAAO,MAAM,kBAAkB,EAAE,IAkDhC,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* project_context — Query the harness content layer for relevant project rules and skills
|
|
3
|
+
*/
|
|
4
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
import { getSafetyConfig } from './safety.js';
|
|
8
|
+
/** Search content definitions for relevant context */
|
|
9
|
+
function searchContent(projectRoot, query, scope) {
|
|
10
|
+
const results = [];
|
|
11
|
+
const queryLower = query.toLowerCase();
|
|
12
|
+
const queryTerms = queryLower.split(/\s+/);
|
|
13
|
+
// Content directories to search (harness content layer paths)
|
|
14
|
+
const searchDirs = [
|
|
15
|
+
{ dir: join(projectRoot, '.claude', 'rules'), type: 'rule' },
|
|
16
|
+
{ dir: join(projectRoot, '.claude', 'agents'), type: 'agent' },
|
|
17
|
+
{ dir: join(projectRoot, '.claude', 'commands'), type: 'command' },
|
|
18
|
+
];
|
|
19
|
+
// If scope is specified, filter to that type
|
|
20
|
+
const filteredDirs = scope ? searchDirs.filter((d) => d.type === scope) : searchDirs;
|
|
21
|
+
for (const { dir, type } of filteredDirs) {
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = readdirSync(dir);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const fullPath = join(dir, entry);
|
|
31
|
+
try {
|
|
32
|
+
const stat = statSync(fullPath);
|
|
33
|
+
if (stat.isDirectory()) {
|
|
34
|
+
// Check for skill directories with SKILL.md
|
|
35
|
+
const skillPath = join(fullPath, 'SKILL.md');
|
|
36
|
+
try {
|
|
37
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
38
|
+
if (matchesQuery(content, queryTerms)) {
|
|
39
|
+
results.push({
|
|
40
|
+
id: entry,
|
|
41
|
+
type: 'skill',
|
|
42
|
+
path: skillPath.replace(`${projectRoot}/`, ''),
|
|
43
|
+
content,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Not a skill directory, skip
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (entry.endsWith('.md')) {
|
|
52
|
+
const content = readFileSync(fullPath, 'utf8');
|
|
53
|
+
if (matchesQuery(content, queryTerms)) {
|
|
54
|
+
results.push({
|
|
55
|
+
id: entry.replace('.md', ''),
|
|
56
|
+
type,
|
|
57
|
+
path: fullPath.replace(`${projectRoot}/`, ''),
|
|
58
|
+
content,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Directory not readable or does not exist — skip silently
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Score by relevance (number of query terms found)
|
|
69
|
+
results.sort((a, b) => {
|
|
70
|
+
const scoreA = queryTerms.filter((t) => a.content.toLowerCase().includes(t)).length;
|
|
71
|
+
const scoreB = queryTerms.filter((t) => b.content.toLowerCase().includes(t)).length;
|
|
72
|
+
return scoreB - scoreA;
|
|
73
|
+
});
|
|
74
|
+
return results;
|
|
75
|
+
}
|
|
76
|
+
function matchesQuery(content, terms) {
|
|
77
|
+
const lower = content.toLowerCase();
|
|
78
|
+
// Match if at least one term is found
|
|
79
|
+
return terms.some((term) => lower.includes(term));
|
|
80
|
+
}
|
|
81
|
+
export const projectContextTool = {
|
|
82
|
+
name: 'project_context',
|
|
83
|
+
label: 'Project Context',
|
|
84
|
+
description: "Query the project's harness content layer for relevant rules, agents, commands, and skills. Use this to understand project conventions, coding standards, and available tools before making changes.",
|
|
85
|
+
parameters: z.object({
|
|
86
|
+
query: z
|
|
87
|
+
.string()
|
|
88
|
+
.describe('Search query (e.g., "database conventions", "testing patterns", "auth")'),
|
|
89
|
+
scope: z
|
|
90
|
+
.enum(['rule', 'agent', 'command', 'skill'])
|
|
91
|
+
.optional()
|
|
92
|
+
.describe('Limit search to a specific content type'),
|
|
93
|
+
}),
|
|
94
|
+
async execute(params) {
|
|
95
|
+
const { query, scope } = params;
|
|
96
|
+
const config = getSafetyConfig();
|
|
97
|
+
try {
|
|
98
|
+
const results = searchContent(config.projectRoot, query, scope);
|
|
99
|
+
if (results.length === 0) {
|
|
100
|
+
return {
|
|
101
|
+
success: true,
|
|
102
|
+
data: { query, results: [] },
|
|
103
|
+
content: `No project context found for "${query}"`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Return top 5 most relevant results
|
|
107
|
+
const top = results.slice(0, 5);
|
|
108
|
+
const summaries = top.map((item) => {
|
|
109
|
+
// Truncate content for token efficiency
|
|
110
|
+
const preview = item.content.length > 500 ? `${item.content.slice(0, 500)}…` : item.content;
|
|
111
|
+
return `[${item.type}] ${item.id} (${item.path}):\n${preview}`;
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
data: { query, resultCount: results.length, results: top },
|
|
116
|
+
content: `Found ${results.length} results for "${query}" (showing top ${top.length}):\n\n${summaries.join('\n\n---\n\n')}`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
error: `Context query failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding Tools Safety Module
|
|
3
|
+
* Path sandboxing and command denylist for secure tool execution
|
|
4
|
+
*/
|
|
5
|
+
export interface SafetyConfig {
|
|
6
|
+
/** Project root directory — all file operations are sandboxed here */
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
/** Additional directories to allow (e.g., /tmp for scratch files) */
|
|
9
|
+
allowedPaths?: string[];
|
|
10
|
+
/** Extra commands to deny beyond the built-in denylist */
|
|
11
|
+
extraDeniedCommands?: string[];
|
|
12
|
+
/** Extra path patterns to deny (e.g., '.env', 'credentials') */
|
|
13
|
+
deniedPathPatterns?: RegExp[];
|
|
14
|
+
}
|
|
15
|
+
export declare function validatePath(filePath: string, config: SafetyConfig): {
|
|
16
|
+
safe: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function resolveSafePath(filePath: string, config: SafetyConfig): string;
|
|
20
|
+
export declare function validateCommand(command: string, config: SafetyConfig): {
|
|
21
|
+
safe: boolean;
|
|
22
|
+
reason?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function configureSafety(config: SafetyConfig): void;
|
|
25
|
+
export declare function getSafetyConfig(): SafetyConfig;
|
|
26
|
+
//# sourceMappingURL=safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/tools/coding/safety.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAiDD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA0BpC;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9E;AAMD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAapC;AAQD,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED,wBAAgB,eAAe,IAAI,YAAY,CAK9C"}
|