@dcode-dev/dcode-cli 1.0.0

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.
Files changed (70) hide show
  1. package/NPM_README.md +78 -0
  2. package/README.md +341 -0
  3. package/bin/dcode-bin +0 -0
  4. package/bin/dcode.js +44 -0
  5. package/cmd/agent_v2.go +448 -0
  6. package/cmd/analyze.go +97 -0
  7. package/cmd/auth.go +338 -0
  8. package/cmd/compose.go +284 -0
  9. package/cmd/context.go +111 -0
  10. package/cmd/edit.go +116 -0
  11. package/cmd/env.go +10 -0
  12. package/cmd/fix.go +145 -0
  13. package/cmd/gemini.go +20 -0
  14. package/cmd/generate.go +47 -0
  15. package/cmd/interactive.go +33 -0
  16. package/cmd/mcp.go +196 -0
  17. package/cmd/patch.go +19 -0
  18. package/cmd/providers.go +67 -0
  19. package/cmd/root.go +41 -0
  20. package/cmd/search.go +61 -0
  21. package/cmd/server.go +36 -0
  22. package/cmd/switch.go +122 -0
  23. package/cmd/terminal.go +277 -0
  24. package/go.mod +42 -0
  25. package/go.sum +86 -0
  26. package/internal/agent/agent.go +332 -0
  27. package/internal/agent/parse.go +25 -0
  28. package/internal/agents/base.go +154 -0
  29. package/internal/agents/documenter.go +77 -0
  30. package/internal/agents/generalist.go +266 -0
  31. package/internal/agents/investigator.go +60 -0
  32. package/internal/agents/registry.go +34 -0
  33. package/internal/agents/reviewer.go +67 -0
  34. package/internal/agents/tester.go +73 -0
  35. package/internal/ai/client.go +634 -0
  36. package/internal/ai/tools.go +332 -0
  37. package/internal/auth/adc.go +108 -0
  38. package/internal/auth/apikey.go +67 -0
  39. package/internal/auth/factory.go +145 -0
  40. package/internal/auth/oauth2.go +227 -0
  41. package/internal/auth/store.go +216 -0
  42. package/internal/auth/types.go +79 -0
  43. package/internal/auth/vertex.go +138 -0
  44. package/internal/config/config.go +428 -0
  45. package/internal/config/policy.go +251 -0
  46. package/internal/context/builder.go +312 -0
  47. package/internal/detector/detector.go +204 -0
  48. package/internal/diffutil/diffutil.go +30 -0
  49. package/internal/fsutil/fsutil.go +35 -0
  50. package/internal/mcp/client.go +314 -0
  51. package/internal/mcp/manager.go +221 -0
  52. package/internal/policy/policy.go +89 -0
  53. package/internal/prompt/interactive.go +338 -0
  54. package/internal/registry/agent.go +201 -0
  55. package/internal/registry/tool.go +181 -0
  56. package/internal/scheduler/scheduler.go +250 -0
  57. package/internal/server/server.go +167 -0
  58. package/internal/tools/file.go +183 -0
  59. package/internal/tools/filesystem.go +286 -0
  60. package/internal/tools/git.go +355 -0
  61. package/internal/tools/memory.go +269 -0
  62. package/internal/tools/registry.go +49 -0
  63. package/internal/tools/search.go +230 -0
  64. package/internal/tools/shell.go +84 -0
  65. package/internal/websearch/search.go +40 -0
  66. package/internal/websearch/tavily.go +79 -0
  67. package/main.go +19 -0
  68. package/package.json +57 -0
  69. package/scripts/install.js +59 -0
  70. package/scripts/uninstall.js +28 -0
@@ -0,0 +1,266 @@
1
+ package agents
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+
7
+ "github.com/ddhanush1/dcode/internal/ai"
8
+ "github.com/ddhanush1/dcode/internal/config"
9
+ "github.com/ddhanush1/dcode/internal/registry"
10
+ )
11
+
12
+ // GeneralistAgent is the main conversational agent
13
+ type GeneralistAgent struct {
14
+ aiClient *ai.Client
15
+ config *config.Config
16
+ }
17
+
18
+ // NewGeneralistAgent creates a new generalist agent
19
+ func NewGeneralistAgent(cfg *config.Config, aiClient *ai.Client) *registry.AgentDefinition {
20
+ agent := &GeneralistAgent{
21
+ aiClient: aiClient,
22
+ config: cfg,
23
+ }
24
+
25
+ return &registry.AgentDefinition{
26
+ ID: "generalist",
27
+ Name: "Generalist Agent",
28
+ Description: "A general-purpose conversational agent that can help with various tasks",
29
+ Version: "1.0.0",
30
+ Tools: []string{
31
+ "read_file",
32
+ "write_file",
33
+ "ls",
34
+ "shell",
35
+ "grep",
36
+ "glob",
37
+ "git_status",
38
+ "git_diff",
39
+ "git_log",
40
+ "save_memory",
41
+ "recall_memory",
42
+ },
43
+ SystemPrompt: `You are a helpful AI assistant with access to tools for working with code and files.
44
+
45
+ CORE MANDATES:
46
+ • Security: Never expose credentials or API keys in responses
47
+ • Standards: Follow existing code conventions and project patterns
48
+ • Expertise: Use tools proactively to get information before responding
49
+
50
+ AVAILABLE TOOLS:
51
+ • read_file: Read file contents
52
+ • write_file: Write to files
53
+ • ls: List directory contents
54
+ • shell: Execute shell commands
55
+ • grep: Search for patterns in files
56
+ • glob: Find files by pattern
57
+ • git_status, git_diff, git_log: Git operations
58
+ • save_memory, recall_memory: Persistent memory
59
+
60
+ WORKFLOW:
61
+ 1. For file/code questions: Use read_file or grep to examine code first
62
+ 2. For system questions: Use shell to gather information
63
+ 3. For modifications: Confirm changes before using write_file
64
+ 4. For analysis: Start broad (ls, git_log), then deep dive (read_file, grep)
65
+
66
+ Always explain what you're doing and why. Be concise but thorough.`,
67
+ AllowSubAgents: true,
68
+ MaxTurns: 50,
69
+ Config: make(map[string]interface{}),
70
+ Executor: agent.Execute,
71
+ Instance: agent, // Store the actual agent instance
72
+ }
73
+ }
74
+
75
+ // Execute executes the generalist agent with tool support
76
+ func (a *GeneralistAgent) Execute(input *registry.AgentInput) (*registry.AgentOutput, error) {
77
+ return a.execute(input, nil)
78
+ }
79
+
80
+ // ExecuteStream executes with streaming callback
81
+ func (a *GeneralistAgent) ExecuteStream(input *registry.AgentInput, onChunk func(string)) (*registry.AgentOutput, error) {
82
+ return a.execute(input, onChunk)
83
+ }
84
+
85
+ // execute is the internal implementation
86
+ func (a *GeneralistAgent) execute(input *registry.AgentInput, onChunk func(string)) (*registry.AgentOutput, error) {
87
+ // Build messages from history
88
+ messages := []ai.Message{}
89
+
90
+ // Add system prompt as first message
91
+ if input.SystemPrompt != "" {
92
+ messages = append(messages, ai.Message{
93
+ Role: "system",
94
+ Content: input.SystemPrompt,
95
+ })
96
+ }
97
+
98
+ // Add history
99
+ for _, msg := range input.History {
100
+ messages = append(messages, ai.Message{
101
+ Role: msg.Role,
102
+ Content: msg.Content,
103
+ })
104
+ }
105
+
106
+ // Add current query (only if not empty)
107
+ if input.Query != "" {
108
+ messages = append(messages, ai.Message{
109
+ Role: "user",
110
+ Content: input.Query,
111
+ })
112
+ }
113
+
114
+ // Convert tools to Gemini function declarations
115
+ tools := convertToolsToGeminiFormat(input.ToolRegistry)
116
+
117
+ // Call AI with tools (streaming if callback provided)
118
+ ctx := context.Background()
119
+ var response *ai.ToolResponse
120
+ var err error
121
+
122
+ if onChunk != nil {
123
+ response, err = a.aiClient.ChatWithToolsStream(ctx, messages, tools, onChunk)
124
+ } else {
125
+ response, err = a.aiClient.ChatWithTools(ctx, messages, tools)
126
+ }
127
+
128
+ if err != nil {
129
+ return nil, fmt.Errorf("AI call failed: %w", err)
130
+ }
131
+
132
+ // Convert function calls to tool calls
133
+ toolCalls := []registry.ToolCall{}
134
+ for _, fc := range response.FunctionCalls {
135
+ toolCalls = append(toolCalls, registry.ToolCall{
136
+ ID: fc.Name, // Use function name as ID
137
+ ToolName: fc.Name,
138
+ Parameters: fc.Args,
139
+ Status: "pending",
140
+ })
141
+ }
142
+
143
+ return &registry.AgentOutput{
144
+ Message: response.Text,
145
+ ToolCalls: toolCalls,
146
+ Data: make(map[string]interface{}),
147
+ TerminationReason: response.FinishReason,
148
+ Metadata: map[string]interface{}{
149
+ "model": a.aiClient.Model,
150
+ "provider": a.aiClient.Provider,
151
+ "tool_count": len(toolCalls),
152
+ },
153
+ }, nil
154
+ }
155
+
156
+ // convertToolsToGeminiFormat converts registry tools to Gemini function declarations
157
+ func convertToolsToGeminiFormat(toolRegistry *registry.ToolRegistry) []ai.Tool {
158
+ if toolRegistry == nil {
159
+ return nil
160
+ }
161
+
162
+ tools := []ai.Tool{}
163
+ declarations := []ai.FunctionDeclaration{}
164
+
165
+ for _, tool := range toolRegistry.List() {
166
+ // Use the tool's actual InputSchema if available
167
+ params := tool.InputSchema
168
+ if params == nil {
169
+ // Fallback to generic input
170
+ params = map[string]interface{}{
171
+ "type": "object",
172
+ "properties": map[string]interface{}{
173
+ "input": map[string]interface{}{
174
+ "type": "string",
175
+ "description": "Input to the tool",
176
+ },
177
+ },
178
+ "required": []string{},
179
+ }
180
+ }
181
+
182
+ declarations = append(declarations, ai.FunctionDeclaration{
183
+ Name: tool.ID,
184
+ Description: fmt.Sprintf("%s - %s (Risk: %s)", tool.Name, tool.Description, tool.RiskLevel),
185
+ Parameters: params,
186
+ })
187
+ }
188
+
189
+ if len(declarations) > 0 {
190
+ tools = append(tools, ai.Tool{
191
+ FunctionDeclarations: declarations,
192
+ })
193
+ }
194
+
195
+ return tools
196
+ }
197
+
198
+ // CreateGeneralistExecutor creates an executor for generalist-style agents
199
+ func CreateGeneralistExecutor(aiClient *ai.Client) func(*registry.AgentInput) (*registry.AgentOutput, error) {
200
+ return func(input *registry.AgentInput) (*registry.AgentOutput, error) {
201
+ // Build messages from history
202
+ messages := []ai.Message{}
203
+
204
+ // Add system prompt
205
+ if input.SystemPrompt != "" {
206
+ messages = append(messages, ai.Message{
207
+ Role: "system",
208
+ Content: input.SystemPrompt,
209
+ })
210
+ }
211
+
212
+ // Add history
213
+ for _, msg := range input.History {
214
+ messages = append(messages, ai.Message{
215
+ Role: msg.Role,
216
+ Content: msg.Content,
217
+ })
218
+ }
219
+
220
+ // Add current query
221
+ messages = append(messages, ai.Message{
222
+ Role: "user",
223
+ Content: input.Query,
224
+ })
225
+
226
+ // Convert tools to Gemini format
227
+ tools := convertToolsToGeminiFormat(input.ToolRegistry)
228
+
229
+ // Call AI with tools
230
+ ctx := context.Background()
231
+ response, err := aiClient.ChatWithTools(ctx, messages, tools)
232
+ if err != nil {
233
+ return nil, fmt.Errorf("AI call failed: %w", err)
234
+ }
235
+
236
+ // Convert function calls to tool calls
237
+ toolCalls := []registry.ToolCall{}
238
+ for _, fc := range response.FunctionCalls {
239
+ toolCalls = append(toolCalls, registry.ToolCall{
240
+ ID: fc.Name,
241
+ ToolName: fc.Name,
242
+ Parameters: fc.Args,
243
+ Status: "pending",
244
+ })
245
+ }
246
+
247
+ return &registry.AgentOutput{
248
+ Message: response.Text,
249
+ ToolCalls: toolCalls,
250
+ Data: make(map[string]interface{}),
251
+ TerminationReason: response.FinishReason,
252
+ Metadata: map[string]interface{}{
253
+ "model": aiClient.Model,
254
+ "provider": aiClient.Provider,
255
+ "tool_count": len(toolCalls),
256
+ },
257
+ }, nil
258
+ }
259
+ }
260
+
261
+ // RegisterGeneralistAgent registers the generalist agent
262
+ func RegisterGeneralistAgent(agentRegistry *registry.AgentRegistry, cfg *config.Config, aiClient *ai.Client) error {
263
+ agent := NewGeneralistAgent(cfg, aiClient)
264
+ return agentRegistry.Register(agent)
265
+ }
266
+
@@ -0,0 +1,60 @@
1
+ package agents
2
+
3
+ import (
4
+ "github.com/ddhanush1/dcode/internal/ai"
5
+ "github.com/ddhanush1/dcode/internal/registry"
6
+ )
7
+
8
+ const investigatorSystemPrompt = `You are a Codebase Investigator, an AI agent specialized in analyzing and understanding code repositories.
9
+
10
+ Your capabilities:
11
+ - Analyze project architecture and structure
12
+ - Map dependencies and relationships between components
13
+ - Identify design patterns and architectural decisions
14
+ - Understand code organization and conventions
15
+ - Provide insights on codebase health and maintainability
16
+ - Answer questions about how the codebase works
17
+
18
+ When analyzing code:
19
+ 1. Start with high-level structure (directories, modules)
20
+ 2. Identify entry points and main components
21
+ 3. Map data flow and dependencies
22
+ 4. Document key architectural decisions
23
+ 5. Provide clear, actionable insights
24
+
25
+ Use available tools to:
26
+ - grep: Search for patterns, imports, function definitions
27
+ - glob: Find files by pattern
28
+ - read_file: Read source files and configs
29
+ - git_log: Understand project history
30
+ - save_memory: Store important findings
31
+ - recall_memory: Retrieve previous analysis
32
+
33
+ Be thorough but concise. Focus on understanding "how" and "why" the code works.`
34
+
35
+ // GetInvestigatorTools returns tools best suited for investigation
36
+ func GetInvestigatorTools() []string {
37
+ return []string{
38
+ "grep",
39
+ "glob",
40
+ "read_file",
41
+ "ls",
42
+ "git_log",
43
+ "git_status",
44
+ "save_memory",
45
+ "recall_memory",
46
+ "list_memories",
47
+ }
48
+ }
49
+
50
+ // RegisterInvestigatorAgent registers the investigator agent
51
+ func RegisterInvestigatorAgent(agentRegistry *registry.AgentRegistry, aiClient *ai.Client) error {
52
+ return agentRegistry.Register(&registry.AgentDefinition{
53
+ ID: "investigator",
54
+ Name: "Codebase Investigator",
55
+ Description: "Specialized in analyzing and understanding code repositories",
56
+ SystemPrompt: investigatorSystemPrompt,
57
+ Tools: GetInvestigatorTools(),
58
+ Executor: CreateGeneralistExecutor(aiClient),
59
+ })
60
+ }
@@ -0,0 +1,34 @@
1
+ package agents
2
+
3
+ import (
4
+ "github.com/ddhanush1/dcode/internal/ai"
5
+ "github.com/ddhanush1/dcode/internal/config"
6
+ "github.com/ddhanush1/dcode/internal/registry"
7
+ )
8
+
9
+ // RegisterAllAgents registers all built-in agents
10
+ func RegisterAllAgents(agentRegistry *registry.AgentRegistry, cfg *config.Config, aiClient *ai.Client) error {
11
+ // Register all agents
12
+ agents := []func(*registry.AgentRegistry, *ai.Client) error{
13
+ RegisterGeneralistAgent2,
14
+ RegisterInvestigatorAgent,
15
+ RegisterReviewerAgent,
16
+ RegisterTesterAgent,
17
+ RegisterDocumenterAgent,
18
+ }
19
+
20
+ for _, registerFn := range agents {
21
+ if err := registerFn(agentRegistry, aiClient); err != nil {
22
+ return err
23
+ }
24
+ }
25
+
26
+ return nil
27
+ }
28
+
29
+ // RegisterGeneralistAgent2 is a wrapper for the new signature
30
+ func RegisterGeneralistAgent2(agentRegistry *registry.AgentRegistry, aiClient *ai.Client) error {
31
+ // Get config from a default location or pass nil
32
+ return RegisterGeneralistAgent(agentRegistry, nil, aiClient)
33
+ }
34
+
@@ -0,0 +1,67 @@
1
+ package agents
2
+
3
+ import (
4
+ "github.com/ddhanush1/dcode/internal/ai"
5
+ "github.com/ddhanush1/dcode/internal/registry"
6
+ )
7
+
8
+ const reviewerSystemPrompt = `You are a Code Reviewer, an AI agent specialized in reviewing code quality and providing actionable feedback.
9
+
10
+ Your focus areas:
11
+ - Code quality and best practices
12
+ - Potential bugs and edge cases
13
+ - Security vulnerabilities
14
+ - Performance issues
15
+ - Code maintainability and readability
16
+ - Test coverage gaps
17
+ - Documentation quality
18
+
19
+ When reviewing code:
20
+ 1. Start by understanding the context and purpose
21
+ 2. Check for common issues (null checks, error handling, edge cases)
22
+ 3. Look for security vulnerabilities (SQL injection, XSS, etc.)
23
+ 4. Evaluate code structure and organization
24
+ 5. Suggest concrete improvements
25
+ 6. Prioritize issues by severity (critical, major, minor)
26
+
27
+ Review principles:
28
+ - Be constructive and specific
29
+ - Explain WHY something is an issue
30
+ - Provide code examples for fixes
31
+ - Consider the broader context
32
+ - Balance perfectionism with pragmatism
33
+
34
+ Use available tools to:
35
+ - git_diff: Review changes
36
+ - read_file: Read full context
37
+ - grep: Search for patterns or anti-patterns
38
+ - confirm: Ask before making suggestions
39
+ - write_file: Apply fixes (with permission)
40
+
41
+ Focus on substance over style. Prioritize correctness, security, and maintainability.`
42
+
43
+ // GetReviewerTools returns tools best suited for code review
44
+ func GetReviewerTools() []string {
45
+ return []string{
46
+ "git_diff",
47
+ "git_status",
48
+ "read_file",
49
+ "write_file",
50
+ "grep",
51
+ "glob",
52
+ "confirm",
53
+ "ask_user",
54
+ }
55
+ }
56
+
57
+ // RegisterReviewerAgent registers the reviewer agent
58
+ func RegisterReviewerAgent(agentRegistry *registry.AgentRegistry, aiClient *ai.Client) error {
59
+ return agentRegistry.Register(&registry.AgentDefinition{
60
+ ID: "reviewer",
61
+ Name: "Code Reviewer",
62
+ Description: "Specialized in reviewing code quality and providing feedback",
63
+ SystemPrompt: reviewerSystemPrompt,
64
+ Tools: GetReviewerTools(),
65
+ Executor: CreateGeneralistExecutor(aiClient),
66
+ })
67
+ }
@@ -0,0 +1,73 @@
1
+ package agents
2
+
3
+ import (
4
+ "github.com/ddhanush1/dcode/internal/ai"
5
+ "github.com/ddhanush1/dcode/internal/registry"
6
+ )
7
+
8
+ const testerSystemPrompt = `You are a Test Generator, an AI agent specialized in creating comprehensive test suites.
9
+
10
+ Your expertise:
11
+ - Unit test generation with high coverage
12
+ - Integration test design
13
+ - Edge case identification
14
+ - Test data generation
15
+ - Mocking and stubbing strategies
16
+ - Test organization and structure
17
+ - Test-driven development (TDD) practices
18
+
19
+ When generating tests:
20
+ 1. Understand the code under test thoroughly
21
+ 2. Identify all code paths and branches
22
+ 3. Generate tests for:
23
+ - Happy path scenarios
24
+ - Edge cases and boundary conditions
25
+ - Error handling and exceptions
26
+ - Invalid inputs and states
27
+ 4. Use appropriate testing patterns
28
+ 5. Include descriptive test names and comments
29
+ 6. Follow language-specific conventions
30
+
31
+ Test quality guidelines:
32
+ - Tests should be independent and isolated
33
+ - Use meaningful assertions
34
+ - Keep tests simple and focused
35
+ - Test behavior, not implementation
36
+ - Ensure tests are maintainable
37
+ - Aim for high coverage but prioritize meaningful tests
38
+
39
+ Use available tools to:
40
+ - read_file: Read code to test
41
+ - write_file: Create test files
42
+ - shell: Run tests
43
+ - grep: Find existing tests
44
+ - glob: Locate test files
45
+ - git_status: Check test changes
46
+
47
+ Generate practical, maintainable tests that provide real value.`
48
+
49
+ // GetTesterTools returns tools best suited for test generation
50
+ func GetTesterTools() []string {
51
+ return []string{
52
+ "read_file",
53
+ "write_file",
54
+ "shell",
55
+ "grep",
56
+ "glob",
57
+ "git_status",
58
+ "ls",
59
+ "confirm",
60
+ }
61
+ }
62
+
63
+ // RegisterTesterAgent registers the tester agent
64
+ func RegisterTesterAgent(agentRegistry *registry.AgentRegistry, aiClient *ai.Client) error {
65
+ return agentRegistry.Register(&registry.AgentDefinition{
66
+ ID: "tester",
67
+ Name: "Test Generator",
68
+ Description: "Specialized in generating comprehensive test suites",
69
+ SystemPrompt: testerSystemPrompt,
70
+ Tools: GetTesterTools(),
71
+ Executor: CreateGeneralistExecutor(aiClient),
72
+ })
73
+ }