Function bodies 92 total
getSystemStats function · go · L28-L109 (82 LOC)commands.go
func getSystemStats() string {
var sb strings.Builder
hostname, _ := os.Hostname()
sb.WriteString(fmt.Sprintf("🖥 %s\n\n", hostname))
// Uptime
if out, err := exec.Command("uptime").Output(); err == nil {
sb.WriteString(fmt.Sprintf("⏱ %s\n", strings.TrimSpace(string(out))))
}
// CPU info
if out, err := exec.Command("uname", "-m").Output(); err == nil {
arch := strings.TrimSpace(string(out))
// Count cores: nproc on Linux, sysctl on macOS
var cores string
if c, err := exec.Command("nproc").Output(); err == nil {
cores = strings.TrimSpace(string(c))
} else if c, err := exec.Command("sysctl", "-n", "hw.ncpu").Output(); err == nil {
cores = strings.TrimSpace(string(c))
}
sb.WriteString(fmt.Sprintf("🧠 CPU: %s cores (%s)\n", cores, arch))
}
// Memory: Linux uses free, macOS uses vm_stat + sysctl
if out, err := exec.Command("free", "-h").Output(); err == nil {
// Linux
lines := strings.Split(string(out), "\n")
for _, l := range lines {
if strings.HaexecuteCommand function · go · L112-L146 (35 LOC)commands.go
func executeCommand(cmdStr string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
shell := "bash"
if _, err := exec.LookPath("zsh"); err == nil {
shell = "zsh"
}
cmd := exec.CommandContext(ctx, shell, "-l", "-c", cmdStr)
cmd.Dir, _ = os.UserHomeDir()
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
output := stdout.String()
if stderr.Len() > 0 {
if output != "" {
output += "\n"
}
output += stderr.String()
}
if output == "" {
if err != nil {
output = fmt.Sprintf("Error: %v", err)
} else {
output = "(no output)"
}
}
return strings.TrimSpace(output), err
}runClaude function · go · L149-L198 (50 LOC)commands.go
func runClaude(prompt string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
home, _ := os.UserHomeDir()
workDir := home
words := strings.Fields(prompt)
if len(words) > 0 {
firstWord := words[0]
potentialDir := filepath.Join(home, firstWord)
if info, err := os.Stat(potentialDir); err == nil && info.IsDir() {
workDir = potentialDir
prompt = strings.TrimSpace(strings.TrimPrefix(prompt, firstWord))
if prompt == "" {
return "Error: no prompt provided after directory name", nil
}
}
}
if claudePath == "" {
return "Error: claude binary not found", fmt.Errorf("claude not found")
}
cmd := exec.CommandContext(ctx, claudePath, "--dangerously-skip-permissions", "-p", prompt)
cmd.Dir = workDir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
output := stdout.String()
if stderr.Len() > 0 {
if output != "" {
output += "\n"
}
output += stderr.StstopListenerService function · go · L200-L219 (20 LOC)commands.go
func stopListenerService() {
home, _ := os.UserHomeDir()
if _, err := os.Stat("/Library"); err == nil {
// macOS - launchd
plistPath := filepath.Join(home, "Library", "LaunchAgents", "com.ccc.plist")
exec.Command("launchctl", "unload", plistPath).Run()
} else {
// Linux - systemd
exec.Command("systemctl", "--user", "stop", "ccc").Run()
}
// Also kill any manual listener via lock file PID
lockPath := filepath.Join(home, ".ccc.lock")
if data, err := os.ReadFile(lockPath); err == nil {
pidStr := strings.TrimSpace(string(data))
if pidStr != "" {
exec.Command("kill", pidStr).Run()
}
}
time.Sleep(500 * time.Millisecond)
}startListenerService function · go · L221-L229 (9 LOC)commands.go
func startListenerService() {
home, _ := os.UserHomeDir()
if _, err := os.Stat("/Library"); err == nil {
plistPath := filepath.Join(home, "Library", "LaunchAgents", "com.ccc.plist")
exec.Command("launchctl", "load", plistPath).Run()
} else {
exec.Command("systemctl", "--user", "start", "ccc").Run()
}
}setup function · go · L231-L420 (190 LOC)commands.go
func setup(botToken string) error {
fmt.Println("🚀 Claude Code Companion Setup")
fmt.Println("==============================")
fmt.Println()
// Load existing config if present (preserve sessions, group, etc.)
config, _ := loadConfig()
if config == nil {
config = &Config{Sessions: make(map[string]*SessionInfo)}
}
config.BotToken = botToken
// Stop listener to avoid getUpdates conflict (409 Conflict)
fmt.Println("Stopping listener...")
stopListenerService()
// Step 1: Permission mode
fmt.Println("Step 1/6: Permission mode")
var permMode string
err := huh.NewSelect[string]().
Title("How should remote sessions handle permissions?").
Description("This controls what happens when Claude Code needs\npermission to run tools in Telegram-controlled sessions.").
Options(
huh.NewOption[string](
"Auto-approve\n"+
" All permissions granted automatically. Claude works without\n"+
" interruptions. Best for trusted environments where you control\n"+
" pdoctor function · go · L460-L641 (182 LOC)commands.go
func doctor() {
fmt.Println("🩺 ccc doctor")
fmt.Println("=============")
fmt.Println()
allGood := true
// Check tmux
fmt.Print("tmux.............. ")
if tmuxPath != "" {
fmt.Printf("✅ %s\n", tmuxPath)
} else {
fmt.Println("❌ not found")
fmt.Println(" Install: brew install tmux (macOS) or apt install tmux (Linux)")
allGood = false
}
// Check claude
fmt.Print("claude............ ")
if claudePath != "" {
fmt.Printf("✅ %s\n", claudePath)
} else {
fmt.Println("❌ not found")
fmt.Println(" Install: npm install -g @anthropic-ai/claude-code")
allGood = false
}
// Check ccc is in PATH (for hooks)
fmt.Print("ccc in PATH....... ")
home, _ := os.UserHomeDir()
cccPaths := []string{
filepath.Join(home, "bin", "ccc"),
filepath.Join(home, "go", "bin", "ccc"),
}
foundCccPath := ""
for _, p := range cccPaths {
if _, err := os.Stat(p); err == nil {
foundCccPath = p
break
}
}
if foundCccPath != "" {
fmt.Printf("✅ %s\n", foundCccPath)
} else {
All rows above produced by Repobility · https://repobility.com
send function · go · L644-L671 (28 LOC)commands.go
func send(message string) error {
config, err := loadConfig()
if err != nil {
return fmt.Errorf("not configured. Run: ccc setup <bot_token>")
}
if !config.Away {
fmt.Println("Away mode off, skipping notification.")
return nil
}
// Try to send to session topic if we're in a session directory
if config.GroupID != 0 {
cwd, _ := os.Getwd()
for name, info := range config.Sessions {
if info == nil {
continue
}
// Match against saved path, subdirectories of saved path, or suffix
if cwd == info.Path || strings.HasPrefix(cwd, info.Path+"/") || strings.HasSuffix(cwd, "/"+name) {
return sendMessage(config, config.GroupID, info.TopicID, message)
}
}
}
// Fallback to private chat
return sendMessage(config, config.ChatID, 0, message)
}printHelp function · go · L1237-L1279 (43 LOC)commands.go
func printHelp() {
fmt.Printf(`ccc - Claude Code Companion v%s
Your companion for Claude Code - control sessions remotely via Telegram and tmux.
USAGE:
ccc Start/attach tmux session in current directory
ccc -c Continue previous session
ccc <message> Send notification (if away mode is on)
COMMANDS:
setup <token> Complete setup (bot, hook, service - all in one!)
doctor Check all dependencies and configuration
config Show/set configuration values
config projects-dir <path> Set base directory for projects
config oauth-token <token> Set OAuth token
setgroup Configure Telegram group for topics (if skipped during setup)
listen Start the Telegram bot listener manually
install Install Claude hook manually
send <file> Send file to current session's Telegram topic
relay [port] StahandleAuthCode function · go · L1349-L1394 (46 LOC)commands.go
func handleAuthCode(config *Config, chatID, threadID int64, code string) {
authWaitingCode = false
code = strings.TrimSpace(code)
sendMessage(config, chatID, threadID, "🔄 Sending code to Claude...")
exec.Command(tmuxPath, "send-keys", "-t", authTmuxSession, "-l", code).Run()
time.Sleep(200 * time.Millisecond)
exec.Command(tmuxPath, "send-keys", "-t", authTmuxSession, "C-m").Run()
for i := 0; i < 10; i++ {
time.Sleep(2 * time.Second)
out, _ := exec.Command(tmuxPath, "capture-pane", "-t", authTmuxSession, "-p").Output()
pane := string(out)
if strings.Contains(pane, "Yes, I accept") {
exec.Command(tmuxPath, "send-keys", "-t", authTmuxSession, "Down").Run()
time.Sleep(200 * time.Millisecond)
exec.Command(tmuxPath, "send-keys", "-t", authTmuxSession, "C-m").Run()
continue
}
if strings.Contains(pane, "Press Enter") || strings.Contains(pane, "Enter to confirm") {
exec.Command(tmuxPath, "send-keys", "-t", authTmuxSession, "C-m").Run()
continue
}
igetConfigPath function · go · L10-L13 (4 LOC)config.go
func getConfigPath() string {
home, _ := os.UserHomeDir()
return filepath.Join(home, ".ccc.json")
}loadConfig function · go · L15-L103 (89 LOC)config.go
func loadConfig() (*Config, error) {
data, err := os.ReadFile(getConfigPath())
if err != nil {
return nil, err
}
// First check if this is old format (sessions as map[string]int64)
var rawConfig map[string]json.RawMessage
if err := json.Unmarshal(data, &rawConfig); err != nil {
return nil, err
}
// Try to detect old sessions format
var needsMigration bool
var oldSessions map[string]int64
if sessionsRaw, ok := rawConfig["sessions"]; ok {
// Try to parse as old format (map of topic IDs)
if json.Unmarshal(sessionsRaw, &oldSessions) == nil && len(oldSessions) > 0 {
// Check if values are positive numbers (old format)
for _, v := range oldSessions {
if v > 0 {
needsMigration = true
break
}
}
}
}
var config Config
if needsMigration {
// Parse everything except sessions first
type ConfigWithoutSessions struct {
BotToken string `json:"bot_token"`
ChatID int64 `json:"chat_id"`
GroupID int64 `json:"group_id"`
ProsaveConfig function · go · L105-L111 (7 LOC)config.go
func saveConfig(config *Config) error {
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return err
}
return os.WriteFile(getConfigPath(), data, 0600)
}getProjectsDir function · go · L114-L125 (12 LOC)config.go
func getProjectsDir(config *Config) string {
if config.ProjectsDir != "" {
// Expand ~ to home directory
if strings.HasPrefix(config.ProjectsDir, "~/") {
home, _ := os.UserHomeDir()
return filepath.Join(home, config.ProjectsDir[2:])
}
return config.ProjectsDir
}
home, _ := os.UserHomeDir()
return home
}resolveProjectPath function · go · L130-L145 (16 LOC)config.go
func resolveProjectPath(config *Config, name string) string {
// Absolute path
if strings.HasPrefix(name, "/") {
return name
}
// Home-relative path (~/something or just ~)
if strings.HasPrefix(name, "~/") || name == "~" {
home, _ := os.UserHomeDir()
if name == "~" {
return home
}
return filepath.Join(home, name[2:])
}
// Relative to projects_dir
return filepath.Join(getProjectsDir(config), name)
}Repobility — same analyzer, your code, free for public repos · /scan/
expandPath function · go · L148-L154 (7 LOC)config.go
func expandPath(path string) string {
if strings.HasPrefix(path, "~/") {
home, _ := os.UserHomeDir()
return filepath.Join(home, path[2:])
}
return path
}telegramActiveFlag function · go · L16-L18 (3 LOC)hooks.go
func telegramActiveFlag(tmuxName string) string {
return "/tmp/ccc-telegram-active-" + tmuxName
}readHookStdin function · go · L21-L35 (15 LOC)hooks.go
func readHookStdin() ([]byte, error) {
stdinData := make(chan []byte, 1)
go func() {
defer func() { recover() }()
data, _ := io.ReadAll(os.Stdin)
stdinData <- data
}()
select {
case rawData := <-stdinData:
return rawData, nil
case <-time.After(2 * time.Second):
return nil, nil
}
}findSession function · go · L38-L48 (11 LOC)hooks.go
func findSession(config *Config, cwd string) (string, int64) {
for name, info := range config.Sessions {
if name == "" || info == nil {
continue
}
if cwd == info.Path || strings.HasPrefix(cwd, info.Path+"/") || strings.HasSuffix(cwd, "/"+name) {
return name, info.TopicID
}
}
return "", 0
}handleStopHook function · go · L50-L95 (46 LOC)hooks.go
func handleStopHook() error {
defer func() { recover() }()
rawData, _ := readHookStdin()
if len(rawData) == 0 {
return nil
}
hookData, err := parseHookData(rawData)
if err != nil {
return nil
}
config, err := loadConfig()
if err != nil || config == nil {
return nil
}
sessName, topicID := findSession(config, hookData.Cwd)
if sessName == "" || config.GroupID == 0 || topicID == 0 {
return nil
}
hookLog("stop-hook: session=%s transcript=%s", sessName, hookData.TranscriptPath)
// Clear Telegram active flag when Claude stops
tmuxName := "claude-" + strings.ReplaceAll(sessName, ".", "_")
os.Remove(telegramActiveFlag(tmuxName))
blocks := extractLastTurn(hookData.TranscriptPath)
if len(blocks) == 0 {
// No text blocks found, just send completion marker
sendMessage(config, config.GroupID, topicID, fmt.Sprintf("✅ %s", sessName))
return nil
}
for i, block := range blocks {
text := block
if i == len(blocks)-1 {
text = fmt.Sprintf("✅ %s\n\n%s", sessNextractLastTurn function · go · L99-L241 (143 LOC)hooks.go
func extractLastTurn(transcriptPath string) []string {
if transcriptPath == "" {
return nil
}
f, err := os.Open(transcriptPath)
if err != nil {
return nil
}
defer f.Close()
type contentBlock struct {
Type string `json:"type"`
Text string `json:"text"`
Name string `json:"name,omitempty"`
Content string `json:"content,omitempty"`
}
// transcriptLine handles both nested (message.content) and flat (root-level
// content) JSONL formats. Claude Code v2.1.45+ may emit either.
type transcriptLine struct {
Type string `json:"type"`
RequestID string `json:"requestId,omitempty"`
Role string `json:"role,omitempty"`
Content json.RawMessage `json:"content,omitempty"`
Message struct {
Role string `json:"role"`
Content json.RawMessage `json:"content"`
} `json:"message"`
}
// Parse all lines
type parsedEntry struct {
ttype string
requestID string
role string
content json.RawMisToolResult function · go · L244-L260 (17 LOC)hooks.go
func isToolResult(content json.RawMessage) bool {
if len(content) == 0 {
return false
}
// Try as array of objects
var blocks []struct {
Type string `json:"type"`
}
if json.Unmarshal(content, &blocks) == nil {
for _, b := range blocks {
if b.Type == "tool_result" {
return true
}
}
}
return false
}handlePermissionHook function · go · L262-L408 (147 LOC)hooks.go
func handlePermissionHook() error {
defer func() { recover() }()
rawData, _ := readHookStdin()
if len(rawData) == 0 {
return nil
}
hookData, err := parseHookData(rawData)
if err != nil {
return nil
}
config, err := loadConfig()
if err != nil || config == nil {
return nil
}
sessName, topicID := findSession(config, hookData.Cwd)
if sessName == "" || config.GroupID == 0 {
return nil
}
// Handle AskUserQuestion - forward to Telegram with buttons
if hookData.ToolName == "AskUserQuestion" && len(hookData.ToolInput.Questions) > 0 {
for qIdx, q := range hookData.ToolInput.Questions {
if q.Question == "" {
continue
}
msg := fmt.Sprintf("❓ %s\n\n%s", q.Header, q.Question)
var buttons [][]InlineKeyboardButton
for i, opt := range q.Options {
if opt.Label == "" {
continue
}
totalQuestions := len(hookData.ToolInput.Questions)
callbackData := fmt.Sprintf("%s:%d:%d:%d", sessName, qIdx, totalQuestions, i)
if len(callbackData) > Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
outputPermissionDecision function · go · L411-L421 (11 LOC)hooks.go
func outputPermissionDecision(decision, reason string) {
response := map[string]interface{}{
"hookSpecificOutput": map[string]interface{}{
"hookEventName": "PreToolUse",
"permissionDecision": decision,
"permissionDecisionReason": reason,
},
}
data, _ := json.Marshal(response)
fmt.Println(string(data))
}handleNotificationHook function · go · L423-L425 (3 LOC)hooks.go
func handleNotificationHook() error {
return nil
}isCccHook function · go · L428-L446 (19 LOC)hooks.go
func isCccHook(entry interface{}) bool {
if m, ok := entry.(map[string]interface{}); ok {
if cmd, ok := m["command"].(string); ok {
return strings.Contains(cmd, "ccc hook")
}
if hooks, ok := m["hooks"].([]interface{}); ok {
for _, h := range hooks {
if hm, ok := h.(map[string]interface{}); ok {
if cmd, ok := hm["command"].(string); ok {
if strings.Contains(cmd, "ccc hook") {
return true
}
}
}
}
}
}
return false
}installHook function · go · L458-L537 (80 LOC)hooks.go
func installHook() error {
home, _ := os.UserHomeDir()
settingsPath := filepath.Join(home, ".claude", "settings.json")
data, err := os.ReadFile(settingsPath)
if err != nil {
return fmt.Errorf("failed to read settings.json: %w", err)
}
var settings map[string]interface{}
if err := json.Unmarshal(data, &settings); err != nil {
return fmt.Errorf("failed to parse settings.json: %w", err)
}
hooks, ok := settings["hooks"].(map[string]interface{})
if !ok {
hooks = make(map[string]interface{})
}
cccHooks := map[string][]interface{}{
"PreToolUse": {
map[string]interface{}{
"hooks": []interface{}{
map[string]interface{}{
"command": cccPath + " hook-permission",
"type": "command",
"timeout": 300000,
},
},
"matcher": "",
},
},
"Stop": {
map[string]interface{}{
"hooks": []interface{}{
map[string]interface{}{
"command": cccPath + " hook-stop",
"type": "command",
},
},
},
},
}
// RuninstallHook function · go · L539-L584 (46 LOC)hooks.go
func uninstallHook() error {
home, _ := os.UserHomeDir()
settingsPath := filepath.Join(home, ".claude", "settings.json")
data, err := os.ReadFile(settingsPath)
if err != nil {
return fmt.Errorf("failed to read settings.json: %w", err)
}
var settings map[string]interface{}
if err := json.Unmarshal(data, &settings); err != nil {
return fmt.Errorf("failed to parse settings.json: %w", err)
}
hooks, ok := settings["hooks"].(map[string]interface{})
if !ok {
fmt.Println("No hooks found")
return nil
}
hookTypes := []string{"Stop", "Notification", "PermissionRequest", "PostToolUse", "PreToolUse", "UserPromptSubmit"}
for _, hookType := range hookTypes {
if existing, ok := hooks[hookType].([]interface{}); ok {
filtered := removeCccHooks(existing)
if len(filtered) == 0 {
delete(hooks, hookType)
} else {
hooks[hookType] = filtered
}
}
}
settings["hooks"] = hooks
newData, err := json.MarshalIndent(settings, "", " ")
if err != nil {
return fmtinstallSkill function · go · L586-L641 (56 LOC)hooks.go
func installSkill() error {
home, _ := os.UserHomeDir()
skillDir := filepath.Join(home, ".claude", "skills")
skillPath := filepath.Join(skillDir, "ccc-send.md")
if err := os.MkdirAll(skillDir, 0755); err != nil {
return fmt.Errorf("failed to create skills directory: %w", err)
}
skillContent := `# CCC Send - File Transfer Skill
## Description
Send files to the user via Telegram using the ccc send command.
## Usage
When the user asks you to send them a file, or when you have generated/built a file that the user needs (like an APK, binary, or any other file), use this command:
` + "```bash" + `
ccc send <file_path>
` + "```" + `
## How it works
- **Small files (< 50MB)**: Sent directly via Telegram
- **Large files (≥ 50MB)**: Streamed via relay server with a one-time download link
## Examples
### Send a built APK
` + "```bash" + `
ccc send ./build/app.apk
` + "```" + `
### Send a generated file
` + "```bash" + `
ccc send ./output/report.pdf
` + "```" + `
### Send from suuninstallSkill function · go · L643-L648 (6 LOC)hooks.go
func uninstallSkill() error {
home, _ := os.UserHomeDir()
skillPath := filepath.Join(home, ".claude", "skills", "ccc-send.md")
os.Remove(skillPath)
return nil
}truncate function · go · L651-L656 (6 LOC)hooks.go
func truncate(s string, n int) string {
if len(s) <= n {
return s
}
return s[:n] + "..."
}Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
hookLog function · go · L659-L666 (8 LOC)hooks.go
func hookLog(format string, args ...interface{}) {
f, err := os.OpenFile("/tmp/ccc-hook-debug.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return
}
defer f.Close()
fmt.Fprintf(f, "[%s] %s\n", time.Now().Format("15:04:05"), fmt.Sprintf(format, args...))
}parseHookData function · go · L138-L147 (10 LOC)main.go
func parseHookData(data []byte) (HookData, error) {
var hd HookData
if err := json.Unmarshal(data, &hd); err != nil {
return hd, err
}
if len(hd.ToolInputRaw) > 0 {
json.Unmarshal(hd.ToolInputRaw, &hd.ToolInput)
}
return hd, nil
}init function · go · L155-L157 (3 LOC)main.go
func init() {
initPaths()
}main function · go · L159-L411 (253 LOC)main.go
func main() {
// Handle flags
if len(os.Args) > 1 {
switch os.Args[1] {
case "-h", "--help", "help":
printHelp()
return
case "-v", "--version", "version":
fmt.Printf("ccc version %s\n", version)
return
}
}
if len(os.Args) < 2 {
// No args: start/attach tmux session with topic
if err := startSession(false); err != nil {
os.Exit(1)
}
return
}
// Check for -c flag (continue) as first arg
if os.Args[1] == "-c" {
if err := startSession(true); err != nil {
os.Exit(1)
}
return
}
switch os.Args[1] {
case "run":
// Run claude directly (used inside tmux sessions)
continueSession := len(os.Args) > 2 && os.Args[2] == "-c"
if err := runClaudeRaw(continueSession); err != nil {
os.Exit(1)
}
return
case "setup":
if len(os.Args) < 3 {
fmt.Println("Usage: ccc setup <bot_token>")
os.Exit(1)
}
if err := setup(os.Args[2]); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
case "doctor":
doctor()
generateOTPSecret function · go · L38-L50 (13 LOC)otp.go
func generateOTPSecret() (secret string, provisioningURI string, err error) {
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "CCC",
AccountName: "claude-code-companion",
Algorithm: otp.AlgorithmSHA1,
Digits: otp.DigitsSix,
Period: 30,
})
if err != nil {
return "", "", fmt.Errorf("failed to generate TOTP key: %w", err)
}
return key.Secret(), key.URL(), nil
}validateOTP function · go · L53-L56 (4 LOC)otp.go
func validateOTP(secret, code string) bool {
code = strings.TrimSpace(code)
return totp.Validate(code, secret)
}isOTPEnabled function · go · L59-L61 (3 LOC)otp.go
func isOTPEnabled(config *Config) bool {
return config.OTPSecret != ""
}setupOTP function · go · L64-L82 (19 LOC)otp.go
func setupOTP(config *Config) (string, error) {
secret, uri, err := generateOTPSecret()
if err != nil {
return "", err
}
config.OTPSecret = secret
if err := saveConfig(config); err != nil {
return "", fmt.Errorf("failed to save config: %w", err)
}
// Print QR code to terminal
fmt.Println("\nScan this QR code with your authenticator app:")
fmt.Println()
qrterminal.GenerateHalfBlock(uri, qrterminal.L, os.Stdout)
msg := fmt.Sprintf("Or enter the secret manually: %s", secret)
return msg, nil
}All rows above produced by Repobility · https://repobility.com
writeOTPRequest function · go · L85-L91 (7 LOC)otp.go
func writeOTPRequest(sessionID string, req *OTPPermissionRequest) error {
data, err := json.Marshal(req)
if err != nil {
return err
}
return os.WriteFile(otpRequestPrefix+sessionID, data, 0600)
}writeOTPResponse function · go · L94-L104 (11 LOC)otp.go
func writeOTPResponse(sessionID string, approved bool) error {
resp := OTPPermissionResponse{
Approved: approved,
Timestamp: time.Now().Unix(),
}
data, err := json.Marshal(resp)
if err != nil {
return err
}
return os.WriteFile(otpResponsePrefix+sessionID, data, 0600)
}waitForOTPResponse function · go · L108-L137 (30 LOC)otp.go
func waitForOTPResponse(sessionID, tmuxName string, timeout time.Duration) (bool, error) {
responsePath := otpResponsePrefix + sessionID
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
// Check if another parallel hook already got approved and wrote a grant
if hasValidOTPGrant(tmuxName) {
os.Remove(otpRequestPrefix + sessionID)
return true, nil
}
data, err := os.ReadFile(responsePath)
if err == nil {
// Clean up files
os.Remove(responsePath)
os.Remove(otpRequestPrefix + sessionID)
var resp OTPPermissionResponse
if err := json.Unmarshal(data, &resp); err != nil {
return false, err
}
return resp.Approved, nil
}
time.Sleep(500 * time.Millisecond)
}
// Clean up on timeout
os.Remove(otpRequestPrefix + sessionID)
return false, fmt.Errorf("OTP timeout")
}getPendingOTPRequest function · go · L140-L150 (11 LOC)otp.go
func getPendingOTPRequest(sessionID string) (*OTPPermissionRequest, error) {
data, err := os.ReadFile(otpRequestPrefix + sessionID)
if err != nil {
return nil, err
}
var req OTPPermissionRequest
if err := json.Unmarshal(data, &req); err != nil {
return nil, err
}
return &req, nil
}findPendingOTPSession function · go · L153-L163 (11 LOC)otp.go
func findPendingOTPSession() string {
matches, err := filepath.Glob(otpRequestPrefix + "*")
if err != nil || len(matches) == 0 {
return ""
}
for _, match := range matches {
sessionID := strings.TrimPrefix(match, otpRequestPrefix)
return sessionID
}
return ""
}hasValidOTPGrant function · go · L166-L172 (7 LOC)otp.go
func hasValidOTPGrant(tmuxName string) bool {
info, err := os.Stat(otpGrantPrefix + tmuxName)
if err != nil {
return false
}
return time.Since(info.ModTime()) < otpGrantDuration
}writeOTPGrant function · go · L175-L177 (3 LOC)otp.go
func writeOTPGrant(tmuxName string) {
os.WriteFile(otpGrantPrefix+tmuxName, []byte("1"), 0600)
}handleSendFile function · go · L21-L105 (85 LOC)relay.go
func handleSendFile(filePath string) error {
config, err := loadConfig()
if err != nil {
return fmt.Errorf("no config found: %w", err)
}
// Get absolute path
if !filepath.IsAbs(filePath) {
cwd, _ := os.Getwd()
filePath = filepath.Join(cwd, filePath)
}
// Check file exists
fileInfo, err := os.Stat(filePath)
if err != nil {
return fmt.Errorf("file not found: %w", err)
}
// Find session from current directory
cwd, _ := os.Getwd()
var sessionName string
var topicID int64
for name, info := range config.Sessions {
if info == nil {
continue
}
if cwd == info.Path || strings.HasPrefix(cwd, info.Path+"/") {
sessionName = name
topicID = info.TopicID
break
}
}
if topicID == 0 || config.GroupID == 0 {
return fmt.Errorf("no session found for current directory")
}
fileName := filepath.Base(filePath)
fileSize := fileInfo.Size()
// Small file: send directly via Telegram
if fileSize < maxTelegramFileSize {
fmt.Printf("📤 Sending %s (%d MB) via TRepobility — same analyzer, your code, free for public repos · /scan/
streamFileToRelay function · go · L107-L170 (64 LOC)relay.go
func streamFileToRelay(relayURL, token, filePath, fileName string, fileSize int64) error {
// Poll for download requests - loop to allow multiple downloads
timeout := time.After(10 * time.Minute)
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
downloadCount := 0
for {
select {
case <-timeout:
http.Get(relayURL + "/cancel/" + token)
if downloadCount > 0 {
fmt.Printf("⏰ Session expired after %d download(s)\n", downloadCount)
return nil
}
return fmt.Errorf("download timed out (10 min)")
case <-ticker.C:
resp, err := http.Get(relayURL + "/status/" + token)
if err != nil {
continue
}
body, _ := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize))
resp.Body.Close()
status := string(body)
if status == "waiting" {
continue
} else if status == "ready" {
// Someone requested download, start streaming
downloadCount++
fmt.Printf("📤 Streaming %s (download #%d)...\n", fileName, downloadCount)
file, errunRelayServer function · go · L188-L429 (242 LOC)relay.go
func runRelayServer(port string) {
// Clean up old transfers periodically
go func() {
for {
time.Sleep(1 * time.Minute)
relayTransfers.Lock()
for token, t := range relayTransfers.transfers {
if time.Since(t.Created) > 15*time.Minute {
t.Status = "cancelled"
select {
case <-t.DoneChan:
default:
close(t.DoneChan)
}
delete(relayTransfers.transfers, token)
}
}
relayTransfers.Unlock()
}
}()
// Register a new transfer
http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var data struct {
Token string `json:"token"`
Filename string `json:"filename"`
Size int64 `json:"size"`
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
relayTransfers.Lock()
relayTransfers.transfers[data.ToinstallService function · go · L10-L20 (11 LOC)service.go
func installService() error {
home, _ := os.UserHomeDir()
// Detect OS and install appropriate service
if _, err := os.Stat("/Library"); err == nil {
// macOS - use launchd
return installLaunchdService(home)
}
// Linux - use systemd
return installSystemdService(home)
}page 1 / 2next ›