Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8b4aed446 | ||
|
|
03de0c406d | ||
|
|
faf8da8743 | ||
|
|
3386908fd6 | ||
|
|
5a8847952a | ||
|
|
87d21ebf2b | ||
|
|
a524fc545c |
@@ -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`
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user