Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit 3a6a269

Browse files
committed
init command
1 parent d7569d7 commit 3a6a269

File tree

14 files changed

+753
-35
lines changed

14 files changed

+753
-35
lines changed

README.md

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ You can configure OpenCode using environment variables:
104104
OpenCode supports a variety of AI models from different providers:
105105

106106
### OpenAI
107+
107108
- GPT-4.1 family (gpt-4.1, gpt-4.1-mini, gpt-4.1-nano)
108109
- GPT-4.5 Preview
109110
- GPT-4o family (gpt-4o, gpt-4o-mini)
@@ -112,19 +113,22 @@ OpenCode supports a variety of AI models from different providers:
112113
- O4 Mini
113114

114115
### Anthropic
116+
115117
- Claude 3.5 Sonnet
116118
- Claude 3.5 Haiku
117119
- Claude 3.7 Sonnet
118120
- Claude 3 Haiku
119121
- Claude 3 Opus
120122

121123
### Google
124+
122125
- Gemini 2.5
123126
- Gemini 2.5 Flash
124127
- Gemini 2.0 Flash
125128
- Gemini 2.0 Flash Lite
126129

127130
### AWS Bedrock
131+
128132
- Claude 3.7 Sonnet
129133

130134
## Usage
@@ -152,14 +156,15 @@ opencode -c /path/to/project
152156

153157
### Global Shortcuts
154158

155-
| Shortcut | Action |
156-
| --------- | ------------------------------------------------------- |
157-
| `Ctrl+C` | Quit application |
158-
| `Ctrl+?` | Toggle help dialog |
159-
| `?` | Toggle help dialog (when not in editing mode) |
160-
| `Ctrl+L` | View logs |
161-
| `Ctrl+A` | Switch session |
162-
| `Esc` | Close current overlay/dialog or return to previous mode |
159+
| Shortcut | Action |
160+
| -------- | ------------------------------------------------------- |
161+
| `Ctrl+C` | Quit application |
162+
| `Ctrl+?` | Toggle help dialog |
163+
| `?` | Toggle help dialog (when not in editing mode) |
164+
| `Ctrl+L` | View logs |
165+
| `Ctrl+A` | Switch session |
166+
| `Ctrl+K` | Command dialog |
167+
| `Esc` | Close current overlay/dialog or return to previous mode |
163168

164169
### Chat Page Shortcuts
165170

@@ -181,28 +186,28 @@ opencode -c /path/to/project
181186

182187
### Session Dialog Shortcuts
183188

184-
| Shortcut | Action |
185-
| ------------- | ---------------- |
186-
| `` or `k` | Previous session |
187-
| `` or `j` | Next session |
188-
| `Enter` | Select session |
189-
| `Esc` | Close dialog |
189+
| Shortcut | Action |
190+
| ---------- | ---------------- |
191+
| `` or `k` | Previous session |
192+
| `` or `j` | Next session |
193+
| `Enter` | Select session |
194+
| `Esc` | Close dialog |
190195

191196
### Permission Dialog Shortcuts
192197

193-
| Shortcut | Action |
194-
| ------------------------- | ----------------------- |
195-
| `` or `left` | Switch options left |
196-
| `` or `right` or `tab` | Switch options right |
197-
| `Enter` or `space` | Confirm selection |
198-
| `a` | Allow permission |
199-
| `A` | Allow permission for session |
200-
| `d` | Deny permission |
198+
| Shortcut | Action |
199+
| ----------------------- | ---------------------------- |
200+
| `` or `left` | Switch options left |
201+
| `` or `right` or `tab` | Switch options right |
202+
| `Enter` or `space` | Confirm selection |
203+
| `a` | Allow permission |
204+
| `A` | Allow permission for session |
205+
| `d` | Deny permission |
201206

202207
### Logs Page Shortcuts
203208

204-
| Shortcut | Action |
205-
| ---------------- | ------------------- |
209+
| Shortcut | Action |
210+
| ------------------ | ------------------- |
206211
| `Backspace` or `q` | Return to chat page |
207212

208213
## AI Assistant Tools
@@ -369,4 +374,4 @@ Contributions are welcome! Here's how you can contribute:
369374
4. Push to the branch (`git push origin feature/amazing-feature`)
370375
5. Open a Pull Request
371376

372-
Please make sure to update tests as appropriate and follow the existing code style.
377+
Please make sure to update tests as appropriate and follow the existing code style.

internal/config/init.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
const (
10+
// InitFlagFilename is the name of the file that indicates whether the project has been initialized
11+
InitFlagFilename = "init"
12+
)
13+
14+
// ProjectInitFlag represents the initialization status for a project directory
15+
type ProjectInitFlag struct {
16+
Initialized bool `json:"initialized"`
17+
}
18+
19+
// ShouldShowInitDialog checks if the initialization dialog should be shown for the current directory
20+
func ShouldShowInitDialog() (bool, error) {
21+
if cfg == nil {
22+
return false, fmt.Errorf("config not loaded")
23+
}
24+
25+
// Create the flag file path
26+
flagFilePath := filepath.Join(cfg.Data.Directory, InitFlagFilename)
27+
28+
// Check if the flag file exists
29+
_, err := os.Stat(flagFilePath)
30+
if err == nil {
31+
// File exists, don't show the dialog
32+
return false, nil
33+
}
34+
35+
// If the error is not "file not found", return the error
36+
if !os.IsNotExist(err) {
37+
return false, fmt.Errorf("failed to check init flag file: %w", err)
38+
}
39+
40+
// File doesn't exist, show the dialog
41+
return true, nil
42+
}
43+
44+
// MarkProjectInitialized marks the current project as initialized
45+
func MarkProjectInitialized() error {
46+
if cfg == nil {
47+
return fmt.Errorf("config not loaded")
48+
}
49+
// Create the flag file path
50+
flagFilePath := filepath.Join(cfg.Data.Directory, InitFlagFilename)
51+
52+
// Create an empty file to mark the project as initialized
53+
file, err := os.Create(flagFilePath)
54+
if err != nil {
55+
return fmt.Errorf("failed to create init flag file: %w", err)
56+
}
57+
defer file.Close()
58+
59+
return nil
60+
}
61+

internal/llm/agent/mcp-tools.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,14 @@ func runTool(ctx context.Context, c MCPClient, toolName string, input string) (t
8080
}
8181

8282
func (b *mcpTool) Run(ctx context.Context, params tools.ToolCall) (tools.ToolResponse, error) {
83+
sessionID, messageID := tools.GetContextValues(ctx)
84+
if sessionID == "" || messageID == "" {
85+
return tools.ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
86+
}
8387
permissionDescription := fmt.Sprintf("execute %s with the following parameters: %s", b.Info().Name, params.Input)
8488
p := b.permissions.Request(
8589
permission.CreatePermissionRequest{
90+
SessionID: sessionID,
8691
Path: config.WorkingDirectory(),
8792
ToolName: b.Info().Name,
8893
Action: "execute",

internal/llm/prompt/prompt.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ var contextFiles = []string{
1414
".github/copilot-instructions.md",
1515
".cursorrules",
1616
"CLAUDE.md",
17+
"CLAUDE.local.md",
1718
"opencode.md",
19+
"opencode.local.md",
1820
"OpenCode.md",
21+
"OpenCode.local.md",
22+
"OPENCODE.md",
23+
"OPENCODE.local.md",
1924
}
2025

2126
func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) string {
@@ -31,12 +36,13 @@ func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) s
3136
basePrompt = "You are a helpful assistant"
3237
}
3338

34-
// Add context from project-specific instruction files if they exist
35-
contextContent := getContextFromFiles()
36-
if contextContent != "" {
37-
return fmt.Sprintf("%s\n\n# Project-Specific Context\n%s", basePrompt, contextContent)
39+
if agentName == config.AgentCoder || agentName == config.AgentTask {
40+
// Add context from project-specific instruction files if they exist
41+
contextContent := getContextFromFiles()
42+
if contextContent != "" {
43+
return fmt.Sprintf("%s\n\n# Project-Specific Context\n%s", basePrompt, contextContent)
44+
}
3845
}
39-
4046
return basePrompt
4147
}
4248

internal/llm/prompt/title.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ func TitlePrompt(_ models.ModelProvider) string {
66
return `you will generate a short title based on the first message a user begins a conversation with
77
- ensure it is not more than 50 characters long
88
- the title should be a summary of the user's message
9+
- it should be one line long
910
- do not use quotes or colons
1011
- the entire text you return will be used as the title`
1112
}

internal/llm/tools/bash.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ var safeReadOnlyCommands = []string{
5151
"git status", "git log", "git diff", "git show", "git branch", "git tag", "git remote", "git ls-files", "git ls-remote",
5252
"git rev-parse", "git config --get", "git config --list", "git describe", "git blame", "git grep", "git shortlog",
5353

54-
"go version", "go list", "go env", "go doc", "go vet", "go fmt", "go mod", "go test", "go build", "go run", "go install", "go clean",
54+
"go version", "go help", "go list", "go env", "go doc", "go vet", "go fmt", "go mod", "go test", "go build", "go run", "go install", "go clean",
5555
}
5656

5757
func bashDescription() string {
@@ -261,9 +261,15 @@ func (b *bashTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error)
261261
}
262262
}
263263
}
264+
265+
sessionID, messageID := GetContextValues(ctx)
266+
if sessionID == "" || messageID == "" {
267+
return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
268+
}
264269
if !isSafeReadOnly {
265270
p := b.permissions.Request(
266271
permission.CreatePermissionRequest{
272+
SessionID: sessionID,
267273
Path: config.WorkingDirectory(),
268274
ToolName: BashToolName,
269275
Action: "execute",

internal/llm/tools/edit.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ func (e *editTool) createNewFile(ctx context.Context, filePath, content string)
203203
}
204204
p := e.permissions.Request(
205205
permission.CreatePermissionRequest{
206+
SessionID: sessionID,
206207
Path: permissionPath,
207208
ToolName: EditToolName,
208209
Action: "write",
@@ -313,6 +314,7 @@ func (e *editTool) deleteContent(ctx context.Context, filePath, oldString string
313314
}
314315
p := e.permissions.Request(
315316
permission.CreatePermissionRequest{
317+
SessionID: sessionID,
316318
Path: permissionPath,
317319
ToolName: EditToolName,
318320
Action: "write",
@@ -432,6 +434,7 @@ func (e *editTool) replaceContent(ctx context.Context, filePath, oldString, newS
432434
}
433435
p := e.permissions.Request(
434436
permission.CreatePermissionRequest{
437+
SessionID: sessionID,
435438
Path: permissionPath,
436439
ToolName: EditToolName,
437440
Action: "write",

internal/llm/tools/fetch.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,14 @@ func (t *fetchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
116116
return NewTextErrorResponse("URL must start with http:// or https://"), nil
117117
}
118118

119+
sessionID, messageID := GetContextValues(ctx)
120+
if sessionID == "" || messageID == "" {
121+
return ToolResponse{}, fmt.Errorf("session ID and message ID are required for creating a new file")
122+
}
123+
119124
p := t.permissions.Request(
120125
permission.CreatePermissionRequest{
126+
SessionID: sessionID,
121127
Path: config.WorkingDirectory(),
122128
ToolName: FetchToolName,
123129
Action: "fetch",

internal/llm/tools/patch.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ func (p *patchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
194194
patchDiff, _, _ := diff.GenerateDiff("", *change.NewContent, path)
195195
p := p.permissions.Request(
196196
permission.CreatePermissionRequest{
197+
SessionID: sessionID,
197198
Path: dir,
198199
ToolName: PatchToolName,
199200
Action: "create",
@@ -220,6 +221,7 @@ func (p *patchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
220221
dir := filepath.Dir(path)
221222
p := p.permissions.Request(
222223
permission.CreatePermissionRequest{
224+
SessionID: sessionID,
223225
Path: dir,
224226
ToolName: PatchToolName,
225227
Action: "update",
@@ -238,6 +240,7 @@ func (p *patchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
238240
patchDiff, _, _ := diff.GenerateDiff(*change.OldContent, "", path)
239241
p := p.permissions.Request(
240242
permission.CreatePermissionRequest{
243+
SessionID: sessionID,
241244
Path: dir,
242245
ToolName: PatchToolName,
243246
Action: "delete",

internal/llm/tools/write.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
168168
}
169169
p := w.permissions.Request(
170170
permission.CreatePermissionRequest{
171+
SessionID: sessionID,
171172
Path: permissionPath,
172173
ToolName: WriteToolName,
173174
Action: "write",

0 commit comments

Comments
 (0)