Fix all linting issues in internal/p9

- Replace interface{} with any
- Use strings.CutPrefix instead of HasPrefix+TrimPrefix
- Use strings.SplitSeq for efficiency
- Use slices.Contains instead of manual loops
- Use tagged switches for clarity
- Remove debug logging
This commit is contained in:
Levi Neely 2026-02-26 23:12:15 +01:00
parent 83c9136bdf
commit 5b567ba5b3
4 changed files with 69 additions and 89 deletions

View File

@ -446,8 +446,8 @@ func (b *BeadsFS) executeCtl(cmd string) error {
for _, a := range args {
if a == "--no-lint" {
noLint = true
} else if strings.HasPrefix(a, "capability=") {
capLevel = strings.TrimPrefix(a, "capability=")
} else if level, ok := strings.CutPrefix(a, "capability="); ok {
capLevel = level
} else {
filtered = append(filtered, a)
}
@ -506,7 +506,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) > 1 {
assignee = args[1]
}
updates := map[string]interface{}{
updates := map[string]any{
"assignee": assignee,
"status": bd.StatusInProgress,
}
@ -519,7 +519,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if err := b.store.CloseIssue(b.ctx, args[0], "completed", actor, ""); err != nil {
return err
}
return b.store.UpdateIssue(b.ctx, args[0], map[string]interface{}{"assignee": ""}, actor)
return b.store.UpdateIssue(b.ctx, args[0], map[string]any{"assignee": ""}, actor)
case "fail":
if len(args) < 2 {
@ -528,7 +528,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if err := b.store.CloseIssue(b.ctx, args[0], args[1], actor, ""); err != nil {
return err
}
return b.store.UpdateIssue(b.ctx, args[0], map[string]interface{}{"assignee": ""}, actor)
return b.store.UpdateIssue(b.ctx, args[0], map[string]any{"assignee": ""}, actor)
case "dep", "add-dep":
if len(args) < 2 {
@ -551,7 +551,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) < 3 {
return fmt.Errorf("usage: update <bead-id> <field> 'value'")
}
updates := map[string]interface{}{
updates := map[string]any{
args[1]: args[2],
}
return b.store.UpdateIssue(b.ctx, args[0], updates, actor)
@ -599,7 +599,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
return err
}
for _, lbl := range existing {
if _, ok := strings.CutPrefix(lbl, capabilityPrefix); ok {
if level, ok := strings.CutPrefix(lbl, capabilityPrefix); ok && level != "" {
_ = b.store.RemoveLabel(b.ctx, beadID, lbl, actor)
}
}
@ -635,7 +635,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) > 1 {
assignee = args[1]
}
updates := map[string]interface{}{
updates := map[string]any{
"status": StatusPendingApproval,
"assignee": assignee,
}
@ -656,7 +656,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) > 1 {
assignee = args[1]
}
updates := map[string]interface{}{
updates := map[string]any{
"status": StatusPendingReview,
"assignee": assignee,
}
@ -674,7 +674,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) > 1 {
assignee = args[1]
}
updates := map[string]interface{}{
updates := map[string]any{
"status": bd.StatusInProgress,
"assignee": assignee,
}
@ -686,7 +686,7 @@ func (b *BeadsFS) executeCtl(cmd string) error {
if len(args) < 1 {
return fmt.Errorf("usage: unclaim <bead-id>")
}
updates := map[string]interface{}{
updates := map[string]any{
"assignee": "",
"status": bd.StatusOpen,
}
@ -957,8 +957,7 @@ func (b *BeadsFS) createSubtask(parentID, title, description, actor string) (str
nextChild := 1
prefix := parentID + "."
for _, issue := range children {
if strings.HasPrefix(issue.ID, prefix) {
suffix := strings.TrimPrefix(issue.ID, prefix)
if suffix, ok := strings.CutPrefix(issue.ID, prefix); ok {
if !strings.Contains(suffix, ".") {
if n, err := strconv.Atoi(suffix); err == nil && n >= nextChild {
nextChild = n + 1

View File

@ -15,6 +15,7 @@ import (
"os"
"path/filepath"
"regexp"
"slices"
"sort"
"strconv"
"strings"
@ -464,18 +465,11 @@ func (s *Server) walk(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
qid = plan9.Qid{Type: QTFile, Path: qidToolsBase}
if name == "help" {
newPath = "/tools/help"
} else if slices.Contains(caps, name) {
qid = plan9.Qid{Type: QTDir, Path: qidToolsBase + hashID(name)}
newPath = "/tools/" + name
} else {
// Check if it's a capability
for _, cap := range caps {
if cap == name {
qid = plan9.Qid{Type: QTDir, Path: qidToolsBase + hashID(name)}
newPath = "/tools/" + name
break
}
}
if newPath == "" {
return errFcall(fc, "not found")
}
return errFcall(fc, "not found")
}
} else {
return errFcall(fc, "not found")
@ -491,17 +485,11 @@ func (s *Server) walk(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
qid = plan9.Qid{Type: QTFile, Path: qidSkillsBase}
if name == "help" {
newPath = "/skills/help"
} else if slices.Contains(intents, name) {
qid = plan9.Qid{Type: QTDir, Path: qidSkillsBase + hashID(name)}
newPath = "/skills/" + name
} else {
for _, intent := range intents {
if intent == name {
qid = plan9.Qid{Type: QTDir, Path: qidSkillsBase + hashID(name)}
newPath = "/skills/" + name
break
}
}
if newPath == "" {
return errFcall(fc, "not found")
}
return errFcall(fc, "not found")
}
} else {
return errFcall(fc, "not found")
@ -531,16 +519,17 @@ func (s *Server) walk(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
}
// Check if it's a mailbox directory
if name == "inbox" {
switch name {
case "inbox":
qid = plan9.Qid{Type: QTDir, Path: qidInboxBase + hashID(sessID)}
newPath = path + "/inbox"
} else if name == "outbox" {
case "outbox":
qid = plan9.Qid{Type: QTDir, Path: qidOutboxBase + hashID(sessID)}
newPath = path + "/outbox"
} else if name == "completed" {
case "completed":
qid = plan9.Qid{Type: QTDir, Path: qidCompletedBase + hashID(sessID)}
newPath = path + "/completed"
} else {
default:
// Regular session file
idx := fileIndex(name)
if idx < 0 {
@ -656,15 +645,13 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
input := strings.TrimSpace(string(fc.Data))
parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
fmt.Fprintf(os.Stderr, "[DEBUG] write: path=%q parts=%v len=%d\n", path, parts, len(parts))
// Handle beads writes
if strings.HasPrefix(path, "/beads/") {
if beadsPath, ok := strings.CutPrefix(path, "/beads/"); ok {
if s.beads != nil {
cs.mu.Lock()
sessionID := cs.sessionID
cs.mu.Unlock()
if err := s.beads.Write(strings.TrimPrefix(path, "/beads/"), fc.Data, sessionID); err != nil {
if err := s.beads.Write(beadsPath, fc.Data, sessionID); err != nil {
return errFcall(fc, err.Error())
}
return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))}
@ -675,8 +662,6 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
// /ctl - create new session
if path == "/ctl" {
args := strings.Fields(input)
fmt.Fprintf(os.Stderr, "[DEBUG] ctl write: input=%q args=%v len=%d fc.Count=%d len(fc.Data)=%d\n",
input, args, len(args), fc.Count, len(fc.Data))
if len(args) < 2 || args[0] != "new" {
return errFcall(fc, "usage: new <backend> <cwd> [role=<role>] [tasks=<task1,task2>]")
}
@ -694,15 +679,14 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
cwdSet := false
for i := 2; i < len(args); i++ {
arg := args[i]
if strings.HasPrefix(arg, "role=") {
role = strings.TrimPrefix(arg, "role=")
} else if strings.HasPrefix(arg, "tasks=") {
taskStr := strings.TrimPrefix(arg, "tasks=")
if taskStr != "" {
tasks = strings.Split(taskStr, ",")
if r, ok := strings.CutPrefix(arg, "role="); ok {
role = r
} else if t, ok := strings.CutPrefix(arg, "tasks="); ok {
if t != "" {
tasks = strings.Split(t, ",")
}
} else if strings.HasPrefix(arg, "model=") {
model = strings.TrimPrefix(arg, "model=")
} else if m, ok := strings.CutPrefix(arg, "model="); ok {
model = m
} else if !cwdSet {
// First positional argument is cwd
cwd = strings.Trim(arg, `"`)
@ -741,7 +725,6 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
if err != nil {
return errFcall(fc, err.Error())
}
fmt.Fprintf(os.Stderr, "[DEBUG] ctl write: session created, returning Count=%d\n", uint32(len(fc.Data)))
return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))}
}
@ -1146,11 +1129,12 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte {
mailMgr := s.mgr.GetMailManager()
if mailMgr != nil {
var messages []*mailbox.Message
if mailboxType == "inbox" {
switch mailboxType {
case "inbox":
messages = mailMgr.GetInbox("user")
} else if mailboxType == "outbox" {
case "outbox":
messages = mailMgr.GetOutbox("user")
} else if mailboxType == "completed" {
case "completed":
messages = mailMgr.GetCompleted("user")
}
@ -1180,9 +1164,10 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte {
// Add regular files
for i, name := range fileNames {
mode := uint32(0444)
if name == "ctl" || name == "in" || name == "out" {
switch name {
case "ctl", "in", "out":
mode = 0222
} else if name == "alias" || name == "context" || name == "state" {
case "alias", "context", "state":
mode = 0644
}
content := s.getSessionFile(sess, i)
@ -1198,13 +1183,14 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte {
for _, dirName := range dirNames {
var qidBase uint64
var mode uint32
if dirName == "inbox" {
switch dirName {
case "inbox":
qidBase = qidInboxBase
mode = 0555 // read-only (can list and read files)
} else if dirName == "outbox" {
case "outbox":
qidBase = qidOutboxBase
mode = 0555 // read-only (can list and read files)
} else {
default:
qidBase = qidCompletedBase
mode = 0555 // read-only (can list and read files)
}
@ -1226,11 +1212,12 @@ func (s *Server) readDir(path string, offset uint64, count uint32) []byte {
}
var messages []*mailbox.Message
if mailboxType == "inbox" {
switch mailboxType {
case "inbox":
messages = mailMgr.GetInbox(sessID)
} else if mailboxType == "outbox" {
case "outbox":
messages = mailMgr.GetOutbox(sessID)
} else if mailboxType == "completed" {
case "completed":
messages = mailMgr.GetCompleted(sessID)
}
@ -1289,9 +1276,9 @@ func (s *Server) readFile(path string) string {
}
// Handle beads paths
if strings.HasPrefix(path, "/beads/") {
if beadsPath, ok := strings.CutPrefix(path, "/beads/"); ok {
if s.beads != nil {
data, err := s.beads.Read(strings.TrimPrefix(path, "/beads/"))
data, err := s.beads.Read(beadsPath)
if err != nil {
return ""
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"9fans.net/go/plan9"
@ -72,16 +73,15 @@ func parseSkillFrontMatter(skillDir string) (*SkillMeta, error) {
continue
}
if strings.HasPrefix(line, "intent:") {
intents := strings.TrimPrefix(line, "intent:")
for _, i := range strings.Split(intents, ",") {
if intents, ok := strings.CutPrefix(line, "intent:"); ok {
for i := range strings.SplitSeq(intents, ",") {
i = strings.TrimSpace(i)
if i != "" {
meta.Intents = append(meta.Intents, i)
}
}
} else if strings.HasPrefix(line, "description:") {
meta.Description = strings.TrimSpace(strings.TrimPrefix(line, "description:"))
} else if desc, ok := strings.CutPrefix(line, "description:"); ok {
meta.Description = strings.TrimSpace(desc)
}
}
@ -155,11 +155,8 @@ func (s *SkillsFS) listSkillsInIntent(intent string) ([]*SkillMeta, error) {
result = append(result, skill)
continue
}
for _, i := range skill.Intents {
if i == intent {
result = append(result, skill)
break
}
if slices.Contains(skill.Intents, intent) {
result = append(result, skill)
}
}
return result, nil

View File

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"9fans.net/go/plan9"
@ -70,22 +71,21 @@ func parseFrontMatter(path string) (*ToolMeta, error) {
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "#") {
if comment, ok := strings.CutPrefix(line, "#"); ok {
line = strings.TrimSpace(comment)
} else {
break
}
line = strings.TrimPrefix(line, "#")
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "capabilities:") {
caps := strings.TrimPrefix(line, "capabilities:")
for _, c := range strings.Split(caps, ",") {
if caps, ok := strings.CutPrefix(line, "capabilities:"); ok {
for c := range strings.SplitSeq(caps, ",") {
c = strings.TrimSpace(c)
if c != "" {
meta.Capabilities = append(meta.Capabilities, c)
}
}
} else if strings.HasPrefix(line, "description:") {
meta.Description = strings.TrimSpace(strings.TrimPrefix(line, "description:"))
} else if desc, ok := strings.CutPrefix(line, "description:"); ok {
meta.Description = strings.TrimSpace(desc)
}
}
return meta, nil
@ -142,11 +142,8 @@ func (t *ToolsFS) listToolsInCapability(capability string) ([]*ToolMeta, error)
var result []*ToolMeta
for _, tool := range tools {
for _, cap := range tool.Capabilities {
if cap == capability {
result = append(result, tool)
break
}
if slices.Contains(tool.Capabilities, capability) {
result = append(result, tool)
}
}
return result, nil