{"repo": "chengjilai/seek", "files": {"main.go": {"a675e63ee75f37f4c817fd7dd3099be28af46fa3": {"t": 1786068298.025543, "n": 21330, "h": "b1ec769df63b1069", "c": "package main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"golang.org/x/crypto/pbkdf2\"\n\t\"golang.org/x/sys/unix\"\n\t\"golang.org/x/term\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\t\"unsafe\"\n)\n\nfunc parseBool(s string) bool {\n\tswitch strings.ToLower(s) {\n\tcase \"true\", \"1\", \"yes\":\n\t\treturn true\n\t}\n\treturn false\n}\n\nvar Cfg = &struct {\n\tThinking string `json:\"THINKING\"`\n\tModel string `json:\"MODEL\"`\n\tReasoningEffort string `json:\"REASONING_EFFORT\"`\n\tTemperature float64 `json:\"TEMPERATURE\"`\n\tTopP float64 `json:\"TOP_P\"`\n\tMaxTokens int `json:\"MAX_TOKENS\"`\n\tStream bool `json:\"STREAM\"`\n\tDangerousAllow bool `json:\"DANGEROUS_ALLOW\"`\n\tSkills map[string]string `json:\"SKILLS\"`\n}{\n\tThinking: \"enabled\",\n\tModel: \"deepseek-v4-pro\",\n\tReasoningEffort: \"max\",\n\tTemperature: 1.0,\n\tTopP: 1.0,\n\tMaxTokens: 8192,\n\tStream: true,\n\tDangerousAllow: false,\n\tSkills: map[string]string{},\n}\n\nfunc showConfig() {\n\tfmt.Printf(`MODEL: %s\nREASONING_EFFORT: %s\nTHINKING: %s\nMAX_TOKENS: %d\nTEMPERATURE: %.1f\nTOP_P: %.1f\nDANGEROUS_ALLOW: %v\nSTREAM: %v\nSKILLS: %v\n`, Cfg.Model, Cfg.ReasoningEffort, Cfg.Thinking, Cfg.MaxTokens,\n\t\tCfg.Temperature, Cfg.TopP, Cfg.DangerousAllow, Cfg.Stream, Cfg.Skills)\n}\n\nvar sh = &struct {\n\tmu sync.Mutex\n\tptmx *os.File\n\tpid int\n\tgen atomic.Int64\n\tbuf []byte\n\treadErr error\n\tdataCh chan struct{}\n\tdone chan struct{}\n}{}\n\nfunc Expect(timeout time.Duration) (output string, err error) {\n\tif timeout <= 0 {\n\t\tpanic(\"expect timeout should be larger than 0\")\n\t}\n\tdeadline := time.Now().Add(timeout)\n\tfor {\n\t\tsh.mu.Lock()\n\t\toutput += string(sh.buf)\n\t\treadErr := sh.readErr\n\t\tsh.buf = sh.buf[:0]\n\t\tsh.mu.Unlock()\n\t\tif readErr != nil {\n\t\t\treturn output, readErr\n\t\t}\n\t\tif re := regexp.MustCompile(\n\t\t\t`(?m)^\\$\\s|` +\n\t\t\t\t`(?m)^#\\s|` +\n\t\t\t\t`(?m)^>>>\\s|` +\n\t\t\t\t`(?m)^\\.\\.\\.\\s|` +\n\t\t\t\t`(?:\\[y/N\\])|` +\n\t\t\t\t`(?:\\[Y/n\\])|` +\n\t\t\t\t`(?:\\(yes/no\\))|` +\n\t\t\t\t`(?:[Pp]assword:)|` +\n\t\t\t\t`(?:[Pp]assword\\sfor\\s)|` +\n\t\t\t\t`(?m)^>\\s|` +\n\t\t\t\t`(?:\\[y/N/e\\])`,\n\t\t); re.MatchString(output) {\n\t\t\tfor end := time.Now().Add(100 * time.Millisecond); ; {\n\t\t\t\tselect {\n\t\t\t\tcase <-sh.dataCh:\n\t\t\t\t\tsh.mu.Lock()\n\t\t\t\t\toutput += string(sh.buf)\n\t\t\t\t\tsh.buf = sh.buf[:0]\n\t\t\t\t\tsh.mu.Unlock()\n\t\t\t\tcase <-time.After(time.Until(end)):\n\t\t\t\t\tsh.mu.Lock()\n\t\t\t\t\toutput += string(sh.buf)\n\t\t\t\t\tsh.buf = sh.buf[:0]\n\t\t\t\t\tsh.mu.Unlock()\n\t\t\t\t\treturn output, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvar timeoutCh <-chan time.Time\n\t\tremaining := time.Until(deadline)\n\t\tif remaining <= 0 {\n\t\t\treturn output + \"\\n(timed out)\", nil\n\t\t}\n\t\ttimeoutCh = time.After(remaining)\n\t\tselect {\n\t\tcase <-sh.dataCh:\n\t\tcase <-sh.done:\n\t\t\tsh.mu.Lock()\n\t\t\toutput += string(sh.buf)\n\t\t\treadErr = sh.readErr\n\t\t\tsh.buf = sh.buf[:0]\n\t\t\tsh.mu.Unlock()\n\t\t\treturn output, readErr\n\t\tcase <-timeoutCh:\n\t\t\treturn output + \"\\n(timed out)\", nil\n\t\t}\n\t}\n}\nfunc ExecuteTerminal(command string, skipConfirm bool) string {\n\t{\n\t\tsh.mu.Lock()\n\t\t_dead := sh.ptmx == nil || sh.pid == 0\n\t\tif !_dead {\n\t\t\tvar status unix.WaitStatus\n\t\t\tif pid, err := unix.Wait4(sh.pid, &status, unix.WNOHANG, nil); err != nil || pid == sh.pid {\n\t\t\t\t_dead = true\n\t\t\t}\n\t\t}\n\t\tsh.mu.Unlock()\n\t\tif _dead {\n\t\t\tsh.mu.Lock()\n\t\t\tif oldDone := sh.done; oldDone != nil {\n\t\t\t\tsh.mu.Unlock()\n\t\t\t\t<-oldDone\n\t\t\t} else {\n\t\t\t\tsh.mu.Unlock()\n\t\t\t}\n\n\t\t\tptmx, err := os.OpenFile(\"/dev/ptmx\", os.O_RDWR, 0)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", fmt.Errorf(\"open /dev/ptmx: %w\", err))\n\t\t\t}\n\n\t\t\tfd := int(ptmx.Fd())\n\t\t\tvar ptyNo int32\n\t\t\t_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.TIOCGPTN), uintptr(unsafe.Pointer(&ptyNo)))\n\t\t\tif errno != 0 {\n\t\t\t\tptmx.Close()\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", fmt.Errorf(\"TIOCGPTN: %v\", errno))\n\t\t\t}\n\t\t\tvar unlock int\n\t\t\t_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.TIOCSPTLCK), uintptr(unsafe.Pointer(&unlock)))\n\t\t\tif errno != 0 {\n\t\t\t\tptmx.Close()\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", fmt.Errorf(\"TIOCSPTLCK: %v\", errno))\n\t\t\t}\n\t\t\tif termios, err := unix.IoctlGetTermios(fd, unix.TCGETS); err == nil {\n\t\t\t\ttermios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG\n\t\t\t\ttermios.Oflag &^= unix.OPOST\n\t\t\t\t_ = unix.IoctlSetTermios(fd, unix.TCSETS, termios)\n\t\t\t}\n\n\t\t\tptsName := fmt.Sprintf(\"/dev/pts/%d\", ptyNo)\n\t\t\tbashCmd := exec.Command(\"bash\", \"--norc\")\n\t\t\tbashCmd.Env = append(os.Environ(),\n\t\t\t\t\"PS1=\\\\$ \", \"PS2=\", \"TERM=dumb\", \"PAGER=cat\", \"HISTFILE=/dev/null\",\n\t\t\t)\n\t\t\tbashCmd.SysProcAttr = &unix.SysProcAttr{Setsid: true, Setctty: true}\n\n\t\t\tptsFile, err := os.OpenFile(ptsName, os.O_RDWR, 0)\n\t\t\tif err != nil {\n\t\t\t\tptmx.Close()\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", fmt.Errorf(\"open pts: %w\", err))\n\t\t\t}\n\t\t\tbashCmd.Stdin = ptsFile\n\t\t\tbashCmd.Stdout = ptsFile\n\t\t\tbashCmd.Stderr = ptsFile\n\n\t\t\tif err := bashCmd.Start(); err != nil {\n\t\t\t\tptsFile.Close()\n\t\t\t\tptmx.Close()\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", fmt.Errorf(\"start bash: %w\", err))\n\t\t\t}\n\t\t\tptsFile.Close()\n\n\t\t\tdone := make(chan struct{})\n\t\t\tdataCh := make(chan struct{}, 1)\n\n\t\t\tsh.mu.Lock()\n\t\t\tsh.gen.Add(1)\n\t\t\tsh.done = done\n\t\t\tsh.dataCh = dataCh\n\t\t\tsh.buf = nil\n\t\t\tsh.readErr = nil\n\t\t\tsh.ptmx = ptmx\n\t\t\tsh.pid = bashCmd.Process.Pid\n\t\t\tgen := sh.gen.Load()\n\t\t\tsh.mu.Unlock()\n\n\t\t\tgo func() {\n\t\t\t\tdefer close(done)\n\t\t\t\t_ = bashCmd.Wait()\n\t\t\t\tsh.mu.Lock()\n\t\t\t\tif sh.gen.Load() == gen {\n\t\t\t\t\tsh.ptmx.Close()\n\t\t\t\t\tsh.ptmx = nil\n\t\t\t\t\tsh.pid = 0\n\t\t\t\t}\n\t\t\t\tsh.mu.Unlock()\n\t\t\t}()\n\n\t\t\tgo func() {\n\t\t\t\tfor rdBuf := make([]byte, 4096); ; {\n\t\t\t\t\tn, err := ptmx.Read(rdBuf)\n\t\t\t\t\tsh.mu.Lock()\n\t\t\t\t\tif sh.gen.Load() != gen {\n\t\t\t\t\t\tsh.mu.Unlock()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif n > 0 {\n\t\t\t\t\t\tsh.buf = append(sh.buf, rdBuf[:n]...)\n\t\t\t\t\t}\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tsh.readErr = err\n\t\t\t\t\t}\n\t\t\t\t\tsh.mu.Unlock()\n\t\t\t\t\tselect {\n\t\t\t\t\tcase dataCh <- struct{}{}:\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t\tif _, err := Expect(2 * time.Second); err != nil {\n\t\t\t\treturn fmt.Sprintf(\"shell start error: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\ttrimmed := strings.TrimSpace(command)\n\tif trimmed == \"^C\" {\n\t\tsh.mu.Lock()\n\t\tif sh.ptmx != nil {\n\t\t\t_, _ = sh.ptmx.Write([]byte{0x03})\n\t\t}\n\t\tsh.mu.Unlock()\n\t\traw, _ := Expect(5 * time.Second)\n\t\treturn raw\n\t}\n\tif trimmed == \"\" {\n\t\traw, _ := Expect(30 * time.Second)\n\t\treturn raw\n\t}\n\tvar cmd string\n\tif skipConfirm {\n\t\tcmd = strings.TrimSpace(command)\n\t} else if Cfg.DangerousAllow {\n\t\tfmt.Printf(\"\\n%s\\n\", command)\n\t\tcmd = command\n\t} else {\n\t\tfmt.Printf(\"\\n%s\\n[y/N/e] \", command)\n\t\tvar choice string\n\t\t_, _ = fmt.Scanln(&choice)\n\t\tswitch strings.ToLower(strings.TrimSpace(choice)) {\n\t\tcase \"y\":\n\t\t\tcmd = command\n\t\tcase \"e\":\n\t\t\tfmt.Print(\"command:\\n\")\n\t\t\t_, _ = fmt.Scanln(&cmd)\n\t\t}\n\t}\n\tif cmd == \"\" {\n\t\treturn \"user denied\"\n\t}\n\tsh.mu.Lock()\n\tif sh.ptmx != nil {\n\t\t_, _ = sh.ptmx.Write([]byte(cmd + \"\\n\"))\n\t}\n\tsh.mu.Unlock()\n\traw, _ := Expect(30 * time.Second)\n\treturn strings.TrimPrefix(raw, cmd+\"\\r\\n\")\n}\nfunc KillShell() {\n\tsh.mu.Lock()\n\tdone := sh.done\n\tptmx := sh.ptmx\n\tpid := sh.pid\n\tsh.ptmx = nil\n\tsh.pid = 0\n\tsh.mu.Unlock()\n\tif ptmx != nil {\n\t\tptmx.Close()\n\t}\n\tif pid != 0 {\n\t\t_ = unix.Kill(pid, unix.SIGKILL)\n\t\t_, _ = unix.Wait4(pid, nil, 0, nil)\n\t}\n\tif done != nil {\n\t\t<-done\n\t}\n}\n\ntype ToolCall struct {\n\tID string `json:\"id\"`\n\tType string `json:\"type\"`\n\tFunction struct {\n\t\tName string `json:\"name\"`\n\t\tArguments string `json:\"arguments\"`\n\t} `json:\"function\"`\n}\ntype AssistantMessage struct {\n\tRole string `json:\"role\"`\n\tContent string `json:\"content\"`\n\tReasoning string `json:\"reasoning_content\"`\n\tToolCalls []ToolCall `json:\"tool_calls,omitempty\"`\n}\ntype SystemMessage struct {\n\tRole string `json:\"role\"`\n\tContent string `json:\"content\"`\n}\ntype UserMessage struct {\n\tRole string `json:\"role\"`\n\tContent string `json:\"content\"`\n}\ntype ToolMessage struct {\n\tRole string `json:\"role\"`\n\tContent string `json:\"content\"`\n\tToolCallID string `json:\"tool_call_id\"`\n}\ntype streamToolCall struct {\n\tIndex int `json:\"index\"`\n\tID string `json:\"id\"`\n\tType string `json:\"type\"`\n\tFunction struct {\n\t\tName string `json:\"name\"`\n\t\tArguments string `json:\"arguments\"`\n\t} `json:\"function\"`\n}\ntype streamDelta struct {\n\tContent *string `json:\"content\"`\n\tReasoningContent *string `json:\"reasoning_content\"`\n\tToolCalls []streamToolCall `json:\"tool_calls\"`\n}\ntype streamChunk struct {\n\tChoices []struct {\n\t\tDelta streamDelta `json:\"delta\"`\n\t} `json:\"choices\"`\n}\n\nvar Tools = []map[string]any{\n\t{\n\t\t\"type\": \"function\",\n\t\t\"function\": map[string]any{\n\t\t\t\"name\": \"terminal\",\n\t\t\t\"description\": \"run a command in a persistent shell session. The session survives across calls: working directory, environment variables, and subprocesses (Python REPL, ssh, etc.) all persist. If the prompt is missing or output ends with '(timed out)', send an empty command to continue draining output, or send ^C to interrupt the running process and get back to a prompt.\",\n\t\t\t\"parameters\": map[string]any{\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": map[string]any{\"command\": map[string]any{\"type\": \"string\", \"description\": \"Command text to send. Empty string to drain a timed-out session. '^C' to send SIGINT.\"}},\n\t\t\t\t\"required\": []string{\"command\"},\n\t\t\t},\n\t\t},\n\t},\n}\n\nfunc StreamChat(messages []map[string]any) *AssistantMessage {\n\tbody := map[string]any{\n\t\t\"model\": Cfg.Model,\n\t\t\"messages\": messages,\n\t\t\"stream\": Cfg.Stream,\n\t\t\"tools\": Tools,\n\t\t\"temperature\": Cfg.Temperature,\n\t\t\"top_p\": Cfg.TopP,\n\t\t\"max_tokens\": Cfg.MaxTokens,\n\t\t\"thinking\": map[string]string{\"type\": Cfg.Thinking},\n\t\t\"reasoning_effort\": Cfg.ReasoningEffort,\n\t}\n\tpayload, err := json.Marshal(body)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq, err := http.NewRequest(\"POST\", \"https://api.deepseek.com/chat/completions\", bytes.NewReader(payload))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"DEEPSEEK_API_KEY\"))\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != 200 {\n\t\tb, _ := io.ReadAll(resp.Body)\n\t\tfmt.Fprintf(os.Stderr, \"API error %d: %s\\n\", resp.StatusCode, string(b))\n\t\treturn nil\n\t}\n\tmsg := &AssistantMessage{Role: \"assistant\"}\n\tscanner := bufio.NewScanner(resp.Body)\n\tscanner.Buffer(make([]byte, 64*1024), 1024*1024)\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif !strings.HasPrefix(line, \"data: \") {\n\t\t\tcontinue\n\t\t}\n\t\tdata := line[6:]\n\t\tif data == \"[DONE]\" {\n\t\t\tbreak\n\t\t}\n\t\tvar chunk streamChunk\n\t\tif json.Unmarshal([]byte(data), &chunk) != nil || len(chunk.Choices) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\td := chunk.Choices[0].Delta\n\t\tif d.ReasoningContent != nil && *d.ReasoningContent != \"\" {\n\t\t\tfmt.Print(*d.ReasoningContent)\n\t\t\tmsg.Reasoning += *d.ReasoningContent\n\t\t}\n\t\tif d.Content != nil && *d.Content != \"\" {\n\t\t\tfmt.Print(*d.Content)\n\t\t\tmsg.Content += *d.Content\n\t\t}\n\t\tfor _, stc := range d.ToolCalls {\n\t\t\tfor len(msg.ToolCalls) <= stc.Index {\n\t\t\t\tmsg.ToolCalls = append(msg.ToolCalls, ToolCall{\n\t\t\t\t\tID: fmt.Sprintf(\"call_%d\", len(msg.ToolCalls)), Type: \"function\",\n\t\t\t\t})\n\t\t\t}\n\t\t\ttc := &msg.ToolCalls[stc.Index]\n\t\t\tif stc.ID != \"\" {\n\t\t\t\ttc.ID = stc.ID\n\t\t\t}\n\t\t\tif stc.Function.Name != \"\" {\n\t\t\t\ttc.Function.Name += stc.Function.Name\n\t\t\t}\n\t\t\tif stc.Function.Arguments != \"\" {\n\t\t\t\ttc.Function.Arguments += stc.Function.Arguments\n\t\t\t}\n\t\t}\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"stream read error: %v\\n\", err)\n\t}\n\tfmt.Println()\n\treturn msg\n}\n\nfunc (msg *AssistantMessage) ToMap() map[string]any {\n\tm := map[string]any{\n\t\t\"role\": \"assistant\",\n\t\t\"content\": msg.Content,\n\t\t\"reasoning_content\": \"\",\n\t}\n\tif len(msg.ToolCalls) > 0 {\n\t\tm[\"tool_calls\"] = msg.ToolCalls\n\t}\n\treturn m\n}\n\nfunc (msg *SystemMessage) ToMap() map[string]any {\n\treturn map[string]any{\n\t\t\"role\": \"system\",\n\t\t\"content\": msg.Content,\n\t}\n}\n\nfunc (msg *UserMessage) ToMap() map[string]any {\n\treturn map[string]any{\n\t\t\"role\": \"user\",\n\t\t\"content\": msg.Content,\n\t}\n}\n\nfunc (msg *ToolMessage) ToMap() map[string]any {\n\treturn map[string]any{\n\t\t\"role\": \"tool\",\n\t\t\"content\": msg.Content,\n\t\t\"tool_call_id\": msg.ToolCallID,\n\t}\n}\n\nfunc newSystemMsg(content string) *SystemMessage {\n\treturn &SystemMessage{Content: content}\n}\n\nfunc newToolMsg(content, toolCallID string) *ToolMessage {\n\treturn &ToolMessage{Content: content, ToolCallID: toolCallID}\n}\n\nfunc Health() {\n\thealth := true\n\tapiKey := os.Getenv(\"DEEPSEEK_API_KEY\")\n\tif apiKey == \"\" {\n\t\tfmt.Printf(\"DEEPSEEK_API_KEY environment variable not found\")\n\t\thealth = false\n\t}\n\treq, _ := http.NewRequest(\"GET\", \"https://api.deepseek.com/user/balance\", nil)\n\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\treq.Header.Set(\"Accept\", \"application/json\")\n\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\tfmt.Printf(\"%s\\n\", err)\n\t\thealth = false\n\t}\n\tdefer resp.Body.Close()\n\n\tvar balance struct {\n\t\tIsAvailable bool `json:\"is_available\"`\n\t}\n\t_ = json.NewDecoder(resp.Body).Decode(&balance)\n\tif !balance.IsAvailable {\n\t\tfmt.Printf(\"balance not available\")\n\t\thealth = false\n\t}\n\tfor path := range Cfg.Skills {\n\t\tif _, err := os.Stat(path); os.IsNotExist(err) {\n\t\t\tfmt.Printf(\"no such file: %s\\n\", path)\n\t\t\thealth = false\n\t\t}\n\t}\n\tif !health {\n\t\tpanic(\"\")\n\t}\n}\n\nvar errBadPassword = errors.New(\"wrong password or corrupted file\")\n\nfunc readPassword(prompt string) string {\n\tfmt.Print(prompt)\n\tb, _ := term.ReadPassword(int(os.Stdin.Fd()))\n\tfmt.Println()\n\treturn string(b)\n}\n\nfunc main() {\n\tcfgPath := \"seek.json\"\n\tif data, err := os.ReadFile(cfgPath); err == nil {\n\t\tif err := json.Unmarshal(data, Cfg); err != nil {\n\t\t\tfmt.Printf(\"config load warning: %v\\n\", err)\n\t\t}\n\t} else if !os.IsNotExist(err) {\n\t\tfmt.Printf(\"config load warning: %v\\n\", err)\n\t}\n\tHealth()\n\tsigCh := make(chan os.Signal, 1)\n\tsignal.Notify(sigCh, unix.SIGINT, unix.SIGTERM)\n\tgo func() {\n\t\t<-sigCh\n\t\tKillShell()\n\t\tos.Exit(0)\n\t}()\n\n\tshowConfig()\n\tfmt.Println(\"/save /load /health /parameter_show /config_show /parameter_save /exit\\n:parameter value\\n!command\")\n\n\tsysPrompt := \"check these files when needed\"\n\tif len(Cfg.Skills) > 0 {\n\t\tvar sb strings.Builder\n\t\tsb.WriteString(\"check these files when needed\\n\")\n\t\tfor path, desc := range Cfg.Skills {\n\t\t\tif desc != \"\" {\n\t\t\t\tfmt.Fprintf(&sb, \"%s: %s\\n\", path, desc)\n\t\t\t} else {\n\t\t\t\tsb.WriteString(path)\n\t\t\t\tsb.WriteByte('\\n')\n\t\t\t}\n\t\t}\n\t\tsysPrompt = sb.String()\n\t}\n\n\tfor messages, scanner := []map[string]any{\n\t\tnewSystemMsg(sysPrompt).ToMap(),\n\t}, bufio.NewScanner(os.Stdin); ; {\n\t\tfmt.Print(\"\\n> \")\n\t\tif !scanner.Scan() {\n\t\t\tif err := scanner.Err(); err != nil {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"input error: %v\\n\", err)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tinput := strings.TrimSpace(scanner.Text())\n\t\tif input == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch {\n\t\tcase strings.HasPrefix(input, \"/\"):\n\t\t\tswitch parts := strings.SplitN(input, \" \", 2); parts[0] {\n\t\t\tcase \"/exit\":\n\t\t\t\tKillShell()\n\t\t\t\tos.Exit(0)\n\t\t\tcase \"/save\":\n\t\t\t\tif len(parts) < 2 {\n\t\t\t\t\tfmt.Println(\"usage: /save \")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tpw := readPassword(\"password (min 8 chars): \")\n\t\t\t\tif len(pw) < 8 {\n\t\t\t\t\tfmt.Println(\"password too short\")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tplain, err := json.Marshal(messages)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"encrypt failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tsalt := make([]byte, 16)\n\t\t\t\tif _, err := rand.Read(salt); err != nil {\n\t\t\t\t\tfmt.Printf(\"encrypt failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tkey := pbkdf2.Key([]byte(pw), salt, 100000, 32, sha256.New)\n\t\t\t\tblock, err := aes.NewCipher(key)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"encrypt failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tgcm, err := cipher.NewGCM(block)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"encrypt failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tnonce := make([]byte, gcm.NonceSize())\n\t\t\t\tif _, err := rand.Read(nonce); err != nil {\n\t\t\t\t\tfmt.Printf(\"encrypt failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tciphertext := gcm.Seal(nil, nonce, plain, nil)\n\t\t\t\tdata := make([]byte, 0, 16+len(nonce)+len(ciphertext))\n\t\t\t\tdata = append(data, salt...)\n\t\t\t\tdata = append(data, nonce...)\n\t\t\t\tdata = append(data, ciphertext...)\n\t\t\t\tif err := os.WriteFile(parts[1], data, 0600); err != nil {\n\t\t\t\t\tfmt.Printf(\"save failed: %v\\n\", err)\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Printf(\"saved to %s\\n\", parts[1])\n\t\t\t\t}\n\t\t\tcase \"/load\":\n\t\t\t\tif len(parts) < 2 {\n\t\t\t\t\tfmt.Println(\"usage: /load \")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tpw := readPassword(\"password: \")\n\t\t\t\tdata, err := os.ReadFile(parts[1])\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"read failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif len(data) < 16+12+16 {\n\t\t\t\t\tfmt.Printf(\"load failed: %v\\n\", errBadPassword)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tsalt := data[:16]\n\t\t\t\tkey := pbkdf2.Key([]byte(pw), salt, 100000, 32, sha256.New)\n\t\t\t\tblock, err := aes.NewCipher(key)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"load failed: %v\\n\", errBadPassword)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tgcm, err := cipher.NewGCM(block)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"load failed: %v\\n\", errBadPassword)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tnonce := data[16 : 16+gcm.NonceSize()]\n\t\t\t\tciphertext := data[16+gcm.NonceSize():]\n\t\t\t\tplain, err := gcm.Open(nil, nonce, ciphertext, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\tfmt.Printf(\"load failed: %v\\n\", errBadPassword)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tvar loaded []map[string]any\n\t\t\t\tif err := json.Unmarshal(plain, &loaded); err != nil {\n\t\t\t\t\tfmt.Printf(\"load failed: %v\\n\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tmessages = loaded\n\t\t\t\tmessages = append(messages, newSystemMsg(\"Previous shell session has ended. A new one will start on the next command.\").ToMap())\n\t\t\t\tKillShell()\n\t\t\t\tfmt.Println(\"session loaded\")\n\t\t\tcase \"/health\":\n\t\t\t\tHealth()\n\t\t\tcase \"/parameter_show\":\n\t\t\t\tshowConfig()\n\t\t\tcase \"/config_show\":\n\t\t\t\tdata, _ := os.ReadFile(cfgPath)\n\t\t\t\tfmt.Print(strings.TrimRight(string(data), \"\\n\"))\n\t\t\t\tfmt.Println()\n\t\t\tcase \"/parameter_save\":\n\t\t\t\tfmt.Print(\"save config? (y/N): \")\n\t\t\t\tvar yn string\n\t\t\t\t_, _ = fmt.Scanln(&yn)\n\t\t\t\tif strings.ToLower(strings.TrimSpace(yn)) == \"y\" {\n\t\t\t\t\tdata, _ := json.MarshalIndent(Cfg, \"\", \" \")\n\t\t\t\t\t_ = os.WriteFile(cfgPath, data, 0644)\n\t\t\t\t\tfmt.Printf(\"config saved to %s\\n\", cfgPath)\n\t\t\t\t}\n\t\t\t}\n\t\tcase strings.HasPrefix(input, \":\"):\n\t\t\tparts := strings.SplitN(input[1:], \" \", 2)\n\t\t\tif len(parts) < 2 {\n\t\t\t\tfmt.Println(\"usage: :parameter value\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tvar setErr error\n\t\t\tswitch strings.ToUpper(parts[0]) {\n\t\t\tcase \"MODEL\":\n\t\t\t\tCfg.Model = parts[1]\n\t\t\tcase \"THINKING\":\n\t\t\t\tif parts[1] != \"enabled\" && parts[1] != \"disabled\" {\n\t\t\t\t\tsetErr = fmt.Errorf(\"THINKING must be 'enabled' or 'disabled'\")\n\t\t\t\t} else {\n\t\t\t\t\tCfg.Thinking = parts[1]\n\t\t\t\t}\n\t\t\tcase \"REASONING_EFFORT\":\n\t\t\t\tCfg.ReasoningEffort = parts[1]\n\t\t\tcase \"TEMPERATURE\":\n\t\t\t\tif f, err := strconv.ParseFloat(parts[1], 64); err != nil {\n\t\t\t\t\tsetErr = fmt.Errorf(\"invalid float for TEMPERATURE: %s\", parts[1])\n\t\t\t\t} else {\n\t\t\t\t\tCfg.Temperature = f\n\t\t\t\t}\n\t\t\tcase \"TOP_P\":\n\t\t\t\tif f, err := strconv.ParseFloat(parts[1], 64); err != nil {\n\t\t\t\t\tsetErr = fmt.Errorf(\"invalid float for TOP_P: %s\", parts[1])\n\t\t\t\t} else {\n\t\t\t\t\tCfg.TopP = f\n\t\t\t\t}\n\t\t\tcase \"MAX_TOKENS\":\n\t\t\t\tif n, convErr := strconv.Atoi(parts[1]); convErr != nil {\n\t\t\t\t\tsetErr = fmt.Errorf(\"invalid int for %s: %s\", parts[0], parts[1])\n\t\t\t\t} else {\n\t\t\t\t\tCfg.MaxTokens = n\n\t\t\t\t}\n\t\t\tcase \"STREAM\":\n\t\t\t\tCfg.Stream = parseBool(parts[1])\n\t\t\tcase \"DANGEROUS_ALLOW\":\n\t\t\t\tCfg.DangerousAllow = parseBool(parts[1])\n\t\t\tdefault:\n\t\t\t\tsetErr = fmt.Errorf(\"unknown config key: %s\", parts[0])\n\t\t\t}\n\t\t\tif setErr != nil {\n\t\t\t\tfmt.Printf(\"set failed: %v\\n\", setErr)\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\"%s = %s\\n\", parts[0], parts[1])\n\t\t\t}\n\t\tcase strings.HasPrefix(input, \"!\"):\n\t\t\tcommand := input[1:]\n\t\t\tfakeID := fmt.Sprintf(\"user_direct_%d\", time.Now().Unix())\n\t\t\targs, _ := json.Marshal(map[string]string{\"command\": command})\n\t\t\tfake := &AssistantMessage{\n\t\t\t\tRole: \"assistant\",\n\t\t\t\tToolCalls: []ToolCall{{\n\t\t\t\t\tID: fakeID, Type: \"function\",\n\t\t\t\t\tFunction: struct {\n\t\t\t\t\t\tName string `json:\"name\"`\n\t\t\t\t\t\tArguments string `json:\"arguments\"`\n\t\t\t\t\t}{Name: \"terminal\", Arguments: string(args)},\n\t\t\t\t}},\n\t\t\t}\n\t\t\tmessages = append(messages, fake.ToMap())\n\t\t\tresult := ExecuteTerminal(command, true)\n\t\t\tfmt.Printf(\"\\n%s\\n\", result)\n\t\t\tmessages = append(messages, newToolMsg(result, fakeID).ToMap())\n\t\tdefault:\n\t\t\tmessages = append(messages, (&UserMessage{Content: input}).ToMap())\n\t\t\tresp := StreamChat(messages)\n\t\t\tif resp == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmessages = append(messages, resp.ToMap())\n\t\t\tfor resp != nil && len(resp.ToolCalls) > 0 {\n\t\t\t\tfor _, tc := range resp.ToolCalls {\n\t\t\t\t\tvar args struct {\n\t\t\t\t\t\tCommand string `json:\"command\"`\n\t\t\t\t\t}\n\t\t\t\t\t_ = json.Unmarshal([]byte(tc.Function.Arguments), &args)\n\t\t\t\t\tvar result string\n\t\t\t\t\tif tc.Function.Name == \"terminal\" {\n\t\t\t\t\t\tresult = ExecuteTerminal(args.Command, false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = fmt.Sprintf(\"unknown tool: %s\", tc.Function.Name)\n\t\t\t\t\t}\n\t\t\t\t\tfmt.Printf(\"\\n%s\\n\", result)\n\t\t\t\t\tmessages = append(messages, newToolMsg(result, tc.ID).ToMap())\n\t\t\t\t}\n\t\t\t\tresp = StreamChat(messages)\n\t\t\t\tif resp == nil {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tmessages = append(messages, resp.ToMap())\n\t\t\t}\n\t\t}\n\t}\n\n\tKillShell()\n}\n"}}}}