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") }
|
return { output: text, atLineStart: text.endsWith("\n") }
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = ""
|
const parts: string[] = []
|
||||||
let lineStart = atLineStart
|
let lineStart = atLineStart
|
||||||
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
for (let i = 0; i < text.length; i++) {
|
||||||
const ch = text[i]
|
const ch = text[i]
|
||||||
if (lineStart) {
|
if (lineStart) {
|
||||||
output += " "
|
parts.push(" ")
|
||||||
lineStart = false
|
lineStart = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch === "\n") {
|
if (ch === "\n") {
|
||||||
output += " \n"
|
parts.push(" \n")
|
||||||
lineStart = true
|
lineStart = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
output += ch
|
parts.push(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { output, atLineStart: lineStart }
|
return { output: parts.join(""), atLineStart: lineStart }
|
||||||
}
|
}
|
||||||
|
|
||||||
function colorizeWithProfileColor(text: string, hexColor?: string): string {
|
function colorizeWithProfileColor(text: string, hexColor?: string): string {
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ function getLastAgentFromMessageDir(messageDir: string): string | null {
|
|||||||
const files = readdirSync(messageDir)
|
const files = readdirSync(messageDir)
|
||||||
.filter((fileName) => fileName.endsWith(".json"))
|
.filter((fileName) => fileName.endsWith(".json"))
|
||||||
.sort()
|
.sort()
|
||||||
.reverse()
|
|
||||||
|
|
||||||
for (const fileName of files) {
|
for (let i = files.length - 1; i >= 0; i--) {
|
||||||
|
const fileName = files[i]
|
||||||
try {
|
try {
|
||||||
const content = readFileSync(join(messageDir, fileName), "utf-8")
|
const content = readFileSync(join(messageDir, fileName), "utf-8")
|
||||||
const parsed = JSON.parse(content) as { agent?: unknown }
|
const parsed = JSON.parse(content) as { agent?: unknown }
|
||||||
|
|||||||
@@ -44,12 +44,6 @@ export interface ExecutorOptions {
|
|||||||
agent?: string
|
agent?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterDiscoveredCommandsByScope(
|
|
||||||
commands: DiscoveredCommandInfo[],
|
|
||||||
scope: DiscoveredCommandInfo["scope"],
|
|
||||||
): DiscoveredCommandInfo[] {
|
|
||||||
return commands.filter(command => command.scope === scope)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandInfo[]> {
|
async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandInfo[]> {
|
||||||
const discoveredCommands = discoverCommandsSync(process.cwd(), {
|
const discoveredCommands = discoverCommandsSync(process.cwd(), {
|
||||||
@@ -60,14 +54,18 @@ async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandIn
|
|||||||
const skills = options?.skills ?? await discoverAllSkills()
|
const skills = options?.skills ?? await discoverAllSkills()
|
||||||
const skillCommands = skills.map(skillToCommandInfo)
|
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 [
|
return [
|
||||||
...skillCommands,
|
...skillCommands,
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "project"),
|
...orderedCommands,
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "user"),
|
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "opencode-project"),
|
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "opencode"),
|
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "builtin"),
|
|
||||||
...filterDiscoveredCommandsByScope(discoveredCommands, "plugin"),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,18 @@ import type { CommentCheckerConfig } from "../../config/schema"
|
|||||||
|
|
||||||
import z from "zod"
|
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 {
|
import {
|
||||||
initializeCommentCheckerCli,
|
initializeCommentCheckerCli,
|
||||||
getCommentCheckerCliPathPromise,
|
getCommentCheckerCliPathPromise,
|
||||||
@@ -104,17 +116,6 @@ export function createCommentCheckerHooks(config?: CommentCheckerConfig) {
|
|||||||
return
|
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") {
|
if (toolLower === "apply_patch") {
|
||||||
const parsed = ApplyPatchMetadataSchema.safeParse(output.metadata)
|
const parsed = ApplyPatchMetadataSchema.safeParse(output.metadata)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export function generateHashlineDiff(oldContent: string, newContent: string, fil
|
|||||||
const oldLines = oldContent.split("\n")
|
const oldLines = oldContent.split("\n")
|
||||||
const newLines = newContent.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)
|
const maxLines = Math.max(oldLines.length, newLines.length)
|
||||||
|
|
||||||
for (let i = 0; i < maxLines; i += 1) {
|
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)
|
const hash = computeLineHash(lineNum, newLine)
|
||||||
|
|
||||||
if (i >= oldLines.length) {
|
if (i >= oldLines.length) {
|
||||||
diff += `+ ${lineNum}#${hash}|${newLine}\n`
|
parts.push(`+ ${lineNum}#${hash}|${newLine}\n`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (i >= newLines.length) {
|
if (i >= newLines.length) {
|
||||||
diff += `- ${lineNum}# |${oldLine}\n`
|
parts.push(`- ${lineNum}# |${oldLine}\n`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (oldLine !== newLine) {
|
if (oldLine !== newLine) {
|
||||||
diff += `- ${lineNum}# |${oldLine}\n`
|
parts.push(`- ${lineNum}# |${oldLine}\n`)
|
||||||
diff += `+ ${lineNum}#${hash}|${newLine}\n`
|
parts.push(`+ ${lineNum}#${hash}|${newLine}\n`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff
|
return parts.join("")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user