Compare commits

..
7 Commits
Author SHA1 Message Date
Dax Raad a8b4aed446 fix bash tool rendering
publish / publish (push) Has been cancelled
2025-07-19 22:25:15 -04:00
Aiden Cline 03de0c406d fix: title generation for certain providers (#1159) 2025-07-19 20:01:55 -05:00
Aiden Cline faf8da8743 fix: adjust editor parsing to handle flags like --wait (#1160) 2025-07-19 20:01:25 -05:00
Dax Raad 3386908fd6 ci: ignore
publish / publish (push) Has been cancelled
2025-07-19 19:30:12 -04:00
Dax Raad 5a8847952a ci: ignore
publish / publish (push) Has been cancelled
2025-07-19 19:29:05 -04:00
Dax Raad 87d21ebf2b Revert "fix: prevent sparse spacing in hyphenated words (#1102)"
publish / publish (push) Has been cancelled
This reverts commit 2b44dbdbf1.
2025-07-19 19:25:15 -04:00
Timo Clasen a524fc545c fix(hooks): prevent session_complete hook from firing on subagent sessions (#1149)
publish / publish (push) Has been cancelled
2025-07-19 18:20:07 -05:00
8 changed files with 39 additions and 44 deletions
+15 -14
View File
@@ -97,20 +97,21 @@ if (!snapshot) {
.then((res) => res.json()) .then((res) => res.json())
.then((data) => data.commits || []) .then((data) => data.commits || [])
const notes = commits const notes =
.map((commit: any) => `- ${commit.commit.message.split("\n")[0]}`) commits
.filter((x: string) => { .map((commit: any) => `- ${commit.commit.message.split("\n")[0]}`)
const lower = x.toLowerCase() .filter((x: string) => {
return ( const lower = x.toLowerCase()
!lower.includes("ignore:") && return (
!lower.includes("chore:") && !lower.includes("ignore:") &&
!lower.includes("ci:") && !lower.includes("chore:") &&
!lower.includes("wip:") && !lower.includes("ci:") &&
!lower.includes("docs:") && !lower.includes("wip:") &&
!lower.includes("doc:") !lower.includes("docs:") &&
) !lower.includes("doc:")
}) )
.join("\n") })
.join("\n") || "No notable changes"
if (!dry) await $`gh release create v${version} --title "v${version}" --notes ${notes} ./dist/*.zip` if (!dry) await $`gh release create v${version} --title "v${version}" --notes ${notes} ./dist/*.zip`
+5 -1
View File
@@ -31,9 +31,13 @@ export namespace ConfigHooks {
} }
}) })
Bus.subscribe(Session.Event.Idle, async () => { Bus.subscribe(Session.Event.Idle, async (payload) => {
const cfg = await Config.get() const cfg = await Config.get()
if (cfg.experimental?.hook?.session_completed) { if (cfg.experimental?.hook?.session_completed) {
const session = await Session.get(payload.properties.sessionID)
// Only fire hook for top-level sessions (not subagent sessions)
if (session.parentID) return
for (const item of cfg.experimental.hook.session_completed) { for (const item of cfg.experimental.hook.session_completed) {
log.info("session_completed", { log.info("session_completed", {
command: item.command, command: item.command,
+1 -1
View File
@@ -540,7 +540,7 @@ export namespace Session {
if (msgs.length === 0 && !session.parentID) { if (msgs.length === 0 && !session.parentID) {
const small = (await Provider.getSmallModel(input.providerID)) ?? model const small = (await Provider.getSmallModel(input.providerID)) ?? model
generateText({ generateText({
maxOutputTokens: input.providerID === "google" ? 1024 : 20, maxOutputTokens: small.info.reasoning ? 1024 : 20,
providerOptions: { providerOptions: {
[input.providerID]: small.info.options, [input.providerID]: small.info.options,
}, },
@@ -196,8 +196,6 @@ func renderText(
case opencode.UserMessage: case opencode.UserMessage:
ts = time.UnixMilli(int64(casted.Time.Created)) ts = time.UnixMilli(int64(casted.Time.Created))
base := styles.NewStyle().Foreground(t.Text()).Background(backgroundColor) base := styles.NewStyle().Foreground(t.Text()).Background(backgroundColor)
// Process @ mentions and styling with hyphen preservation
words := strings.Fields(text) words := strings.Fields(text)
for i, word := range words { for i, word := range words {
if strings.HasPrefix(word, "@") { if strings.HasPrefix(word, "@") {
@@ -206,14 +204,9 @@ func renderText(
words[i] = base.Render(word + " ") words[i] = base.Render(word + " ")
} }
} }
styledText := strings.Join(words, "") text = strings.Join(words, "")
text = ansi.WordwrapWc(text, width-6, " -")
// Apply word wrapping with hyphen preservation content = base.Width(width - 6).Render(text)
frameSize := util.GetMessageContainerFrame()
wrappedText := util.ProcessTextWithHyphens(styledText, func(t string) string {
return ansi.WordwrapWc(t, width-frameSize, " ")
})
content = base.Width(width - frameSize).Render(wrappedText)
} }
timestamp := ts. timestamp := ts.
@@ -271,6 +264,8 @@ func renderToolDetails(
toolCall opencode.ToolPart, toolCall opencode.ToolPart,
width int, width int,
) string { ) string {
measure := util.Measure("chat.renderToolDetails")
defer measure("tool", toolCall.Tool)
ignoredTools := []string{"todoread"} ignoredTools := []string{"todoread"}
if slices.Contains(ignoredTools, toolCall.Tool) { if slices.Contains(ignoredTools, toolCall.Tool) {
return "" return ""
@@ -375,13 +370,14 @@ func renderToolDetails(
} }
} }
case "bash": case "bash":
command := toolInputMap["command"].(string)
body = fmt.Sprintf("```console\n$ %s\n", command)
stdout := metadata["stdout"] stdout := metadata["stdout"]
if stdout != nil { if stdout != nil {
command := toolInputMap["command"].(string) body += ansi.Strip(fmt.Sprintf("%s", stdout))
out := ansi.Strip(fmt.Sprintf("%s", stdout))
body = fmt.Sprintf("```console\n> %s\n%s```", command, out)
body = util.ToMarkdown(body, width, backgroundColor)
} }
body += "```"
body = util.ToMarkdown(body, width, backgroundColor)
case "webfetch": case "webfetch":
if format, ok := toolInputMap["format"].(string); ok && result != nil { if format, ok := toolInputMap["format"].(string); ok && result != nil {
body = *result body = *result
@@ -715,4 +711,5 @@ func renderDiagnostics(
// if !ok { // if !ok {
// return "" // return ""
// } // }
} }
@@ -234,6 +234,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
} }
case opencode.AssistantMessage: case opencode.AssistantMessage:
messageMeasure := util.Measure("messages.Render")
hasTextPart := false hasTextPart := false
for partIndex, p := range message.Parts { for partIndex, p := range message.Parts {
switch part := p.(type) { switch part := p.(type) {
@@ -365,6 +366,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
} }
} }
} }
messageMeasure()
} }
error := "" error := ""
@@ -2051,10 +2051,6 @@ func wrapInterfaces(content []any, width int) [][]any {
if unicode.IsSpace(r) { if unicode.IsSpace(r) {
isSpace = true isSpace = true
} }
// Use hyphen-aware word boundary detection
if r == '-' {
isSpace = false
}
itemW = rw.RuneWidth(r) itemW = rw.RuneWidth(r)
} else if att, ok := item.(*Attachment); ok { } else if att, ok := item.(*Attachment); ok {
itemW = uniseg.StringWidth(att.Display) itemW = uniseg.StringWidth(att.Display)
+2 -1
View File
@@ -782,7 +782,8 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
return a, toast.NewErrorToast("Something went wrong, couldn't open editor") return a, toast.NewErrorToast("Something went wrong, couldn't open editor")
} }
tmpfile.Close() tmpfile.Close()
c := exec.Command(editor, tmpfile.Name()) //nolint:gosec parts := strings.Fields(editor)
c := exec.Command(parts[0], append(parts[1:], tmpfile.Name())...) //nolint:gosec
c.Stdin = os.Stdin c.Stdin = os.Stdin
c.Stdout = os.Stdout c.Stdout = os.Stdout
c.Stderr = os.Stderr c.Stderr = os.Stderr
+3 -9
View File
@@ -83,17 +83,11 @@ func Extension(path string) string {
} }
func ToMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string { func ToMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string {
renderWidth := width - GetMarkdownContainerFrame() r := styles.GetMarkdownRenderer(width-6, backgroundColor)
r := styles.GetMarkdownRenderer(renderWidth, backgroundColor)
content = strings.ReplaceAll(content, RootPath+"/", "") content = strings.ReplaceAll(content, RootPath+"/", "")
rendered, _ := r.Render(content)
// Apply hyphen preservation during markdown rendering
rendered := ProcessTextWithHyphens(content, func(t string) string {
result, _ := r.Render(t)
return result
})
lines := strings.Split(rendered, "\n") lines := strings.Split(rendered, "\n")
// Clean up empty lines at start/end
if len(lines) > 0 { if len(lines) > 0 {
firstLine := lines[0] firstLine := lines[0]
cleaned := ansi.Strip(firstLine) cleaned := ansi.Strip(firstLine)