perf(hooks,tools): optimize string operations and reduce redundant iterations
- output-renderer, hashline-edit-diff: replace str += with array join (H2) - auto-slash-command: single-pass Map grouping instead of 6x filter (M1) - comment-checker: hoist Zod schema to module scope (M2) - session-last-agent: reverse iterate sorted array instead of sort+reverse (L2)
This commit is contained in:
@@ -45,26 +45,26 @@ export function writePaddedText(
|
||||
return { output: text, atLineStart: text.endsWith("\n") }
|
||||
}
|
||||
|
||||
let output = ""
|
||||
const parts: string[] = []
|
||||
let lineStart = atLineStart
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const ch = text[i]
|
||||
if (lineStart) {
|
||||
output += " "
|
||||
parts.push(" ")
|
||||
lineStart = false
|
||||
}
|
||||
|
||||
if (ch === "\n") {
|
||||
output += " \n"
|
||||
parts.push(" \n")
|
||||
lineStart = true
|
||||
continue
|
||||
}
|
||||
|
||||
output += ch
|
||||
parts.push(ch)
|
||||
}
|
||||
|
||||
return { output, atLineStart: lineStart }
|
||||
return { output: parts.join(""), atLineStart: lineStart }
|
||||
}
|
||||
|
||||
function colorizeWithProfileColor(text: string, hexColor?: string): string {
|
||||
|
||||
@@ -18,9 +18,9 @@ function getLastAgentFromMessageDir(messageDir: string): string | null {
|
||||
const files = readdirSync(messageDir)
|
||||
.filter((fileName) => fileName.endsWith(".json"))
|
||||
.sort()
|
||||
.reverse()
|
||||
|
||||
for (const fileName of files) {
|
||||
for (let i = files.length - 1; i >= 0; i--) {
|
||||
const fileName = files[i]
|
||||
try {
|
||||
const content = readFileSync(join(messageDir, fileName), "utf-8")
|
||||
const parsed = JSON.parse(content) as { agent?: unknown }
|
||||
|
||||
@@ -44,12 +44,6 @@ export interface ExecutorOptions {
|
||||
agent?: string
|
||||
}
|
||||
|
||||
function filterDiscoveredCommandsByScope(
|
||||
commands: DiscoveredCommandInfo[],
|
||||
scope: DiscoveredCommandInfo["scope"],
|
||||
): DiscoveredCommandInfo[] {
|
||||
return commands.filter(command => command.scope === scope)
|
||||
}
|
||||
|
||||
async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandInfo[]> {
|
||||
const discoveredCommands = discoverCommandsSync(process.cwd(), {
|
||||
@@ -60,14 +54,18 @@ async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandIn
|
||||
const skills = options?.skills ?? await discoverAllSkills()
|
||||
const skillCommands = skills.map(skillToCommandInfo)
|
||||
|
||||
const scopeOrder: DiscoveredCommandInfo["scope"][] = ["project", "user", "opencode-project", "opencode", "builtin", "plugin"]
|
||||
const grouped = new Map<string, DiscoveredCommandInfo[]>()
|
||||
for (const cmd of discoveredCommands) {
|
||||
const list = grouped.get(cmd.scope) ?? []
|
||||
list.push(cmd)
|
||||
grouped.set(cmd.scope, list)
|
||||
}
|
||||
const orderedCommands = scopeOrder.flatMap((scope) => grouped.get(scope) ?? [])
|
||||
|
||||
return [
|
||||
...skillCommands,
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "project"),
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "user"),
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "opencode-project"),
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "opencode"),
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "builtin"),
|
||||
...filterDiscoveredCommandsByScope(discoveredCommands, "plugin"),
|
||||
...orderedCommands,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@ import type { CommentCheckerConfig } from "../../config/schema"
|
||||
|
||||
import z from "zod"
|
||||
|
||||
const ApplyPatchMetadataSchema = z.object({
|
||||
files: z.array(
|
||||
z.object({
|
||||
filePath: z.string(),
|
||||
movePath: z.string().optional(),
|
||||
before: z.string(),
|
||||
after: z.string(),
|
||||
type: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
import {
|
||||
initializeCommentCheckerCli,
|
||||
getCommentCheckerCliPathPromise,
|
||||
@@ -104,17 +116,6 @@ export function createCommentCheckerHooks(config?: CommentCheckerConfig) {
|
||||
return
|
||||
}
|
||||
|
||||
const ApplyPatchMetadataSchema = z.object({
|
||||
files: z.array(
|
||||
z.object({
|
||||
filePath: z.string(),
|
||||
movePath: z.string().optional(),
|
||||
before: z.string(),
|
||||
after: z.string(),
|
||||
type: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
if (toolLower === "apply_patch") {
|
||||
const parsed = ApplyPatchMetadataSchema.safeParse(output.metadata)
|
||||
|
||||
@@ -4,7 +4,7 @@ export function generateHashlineDiff(oldContent: string, newContent: string, fil
|
||||
const oldLines = oldContent.split("\n")
|
||||
const newLines = newContent.split("\n")
|
||||
|
||||
let diff = `--- ${filePath}\n+++ ${filePath}\n`
|
||||
const parts: string[] = [`--- ${filePath}\n+++ ${filePath}\n`]
|
||||
const maxLines = Math.max(oldLines.length, newLines.length)
|
||||
|
||||
for (let i = 0; i < maxLines; i += 1) {
|
||||
@@ -14,18 +14,18 @@ export function generateHashlineDiff(oldContent: string, newContent: string, fil
|
||||
const hash = computeLineHash(lineNum, newLine)
|
||||
|
||||
if (i >= oldLines.length) {
|
||||
diff += `+ ${lineNum}#${hash}|${newLine}\n`
|
||||
parts.push(`+ ${lineNum}#${hash}|${newLine}\n`)
|
||||
continue
|
||||
}
|
||||
if (i >= newLines.length) {
|
||||
diff += `- ${lineNum}# |${oldLine}\n`
|
||||
parts.push(`- ${lineNum}# |${oldLine}\n`)
|
||||
continue
|
||||
}
|
||||
if (oldLine !== newLine) {
|
||||
diff += `- ${lineNum}# |${oldLine}\n`
|
||||
diff += `+ ${lineNum}#${hash}|${newLine}\n`
|
||||
parts.push(`- ${lineNum}# |${oldLine}\n`)
|
||||
parts.push(`+ ${lineNum}#${hash}|${newLine}\n`)
|
||||
}
|
||||
}
|
||||
|
||||
return diff
|
||||
return parts.join("")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user