Skip to content

Commit d594338

Browse files
authored
Merge pull request #224 from shelltime/feat/session-project-path-cache
feat(daemon): send session-project path mapping to server
2 parents 80026a9 + d299bf4 commit d594338

5 files changed

Lines changed: 104 additions & 4 deletions

File tree

commands/cc_statusline.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,24 @@ func commandCCStatusline(c *cli.Context) error {
6767
var result ccStatuslineResult
6868
config, err := configService.ReadConfigFile(ctx)
6969
if err == nil {
70+
// Send session-project mapping via daemon socket (fire-and-forget, ~1ms)
71+
if data.SessionID != "" {
72+
projectPath := ""
73+
if data.Workspace != nil {
74+
projectPath = data.Workspace.CurrentDir
75+
if projectPath == "" {
76+
projectPath = data.Workspace.ProjectDir
77+
}
78+
}
79+
if projectPath != "" {
80+
socketPath := config.SocketPath
81+
if socketPath == "" {
82+
socketPath = model.DefaultSocketPath
83+
}
84+
daemon.SendSessionProject(socketPath, data.SessionID, projectPath)
85+
}
86+
}
87+
7088
result = getDaemonInfoWithFallback(ctx, config, data.Cwd)
7189
}
7290

daemon/client.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@ func SendLocalDataToSocket(
5151
return nil
5252
}
5353

54+
// SendSessionProject sends a session-to-project mapping to the daemon (fire-and-forget)
55+
func SendSessionProject(socketPath string, sessionID, projectPath string) {
56+
conn, err := net.DialTimeout("unix", socketPath, 10*time.Millisecond)
57+
if err != nil {
58+
return
59+
}
60+
defer conn.Close()
61+
62+
msg := SocketMessage{
63+
Type: SocketMessageTypeSessionProject,
64+
Payload: SessionProjectRequest{
65+
SessionID: sessionID,
66+
ProjectPath: projectPath,
67+
},
68+
}
69+
70+
json.NewEncoder(conn).Encode(msg)
71+
}
72+
5473
// RequestCCInfo requests CC info (cost data and git info) from the daemon
5574
func RequestCCInfo(socketPath string, timeRange CCInfoTimeRange, workingDir string, timeout time.Duration) (*CCInfoResponse, error) {
5675
conn, err := net.DialTimeout("unix", socketPath, timeout)

daemon/socket.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package daemon
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"log/slog"
@@ -17,12 +18,18 @@ import (
1718
type SocketMessageType string
1819

1920
const (
20-
SocketMessageTypeSync SocketMessageType = "sync"
21-
SocketMessageTypeHeartbeat SocketMessageType = "heartbeat"
22-
SocketMessageTypeStatus SocketMessageType = "status"
23-
SocketMessageTypeCCInfo SocketMessageType = "cc_info"
21+
SocketMessageTypeSync SocketMessageType = "sync"
22+
SocketMessageTypeHeartbeat SocketMessageType = "heartbeat"
23+
SocketMessageTypeStatus SocketMessageType = "status"
24+
SocketMessageTypeCCInfo SocketMessageType = "cc_info"
25+
SocketMessageTypeSessionProject SocketMessageType = "session_project"
2426
)
2527

28+
type SessionProjectRequest struct {
29+
SessionID string `json:"sessionId"`
30+
ProjectPath string `json:"projectPath"`
31+
}
32+
2633
type CCInfoTimeRange string
2734

2835
const (
@@ -179,6 +186,15 @@ func (p *SocketHandler) handleConnection(conn net.Conn) {
179186
encoder.Encode(map[string]string{"status": "ok"})
180187
case SocketMessageTypeCCInfo:
181188
p.handleCCInfo(conn, msg)
189+
case SocketMessageTypeSessionProject:
190+
if payload, ok := msg.Payload.(map[string]interface{}); ok {
191+
sessionID, _ := payload["sessionId"].(string)
192+
projectPath, _ := payload["projectPath"].(string)
193+
if sessionID != "" && projectPath != "" {
194+
go model.SendSessionProjectUpdate(context.Background(), *p.config, sessionID, projectPath)
195+
slog.Debug("session_project update dispatched", slog.String("sessionId", sessionID))
196+
}
197+
}
182198
default:
183199
slog.Error("Unknown message type:", slog.String("messageType", string(msg.Type)))
184200
}

model/api_session_project.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package model
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
)
8+
9+
type sessionProjectRequest struct {
10+
SessionID string `json:"session_id"`
11+
ProjectPath string `json:"project_path"`
12+
}
13+
14+
type sessionProjectResponse struct{}
15+
16+
// SendSessionProjectUpdate sends a session-to-project path mapping to the server
17+
func SendSessionProjectUpdate(ctx context.Context, config ShellTimeConfig, sessionID, projectPath string) error {
18+
ctx, span := modelTracer.Start(ctx, "session_project.send")
19+
defer span.End()
20+
21+
var resp sessionProjectResponse
22+
err := SendHTTPRequestJSON(HTTPRequestOptions[*sessionProjectRequest, sessionProjectResponse]{
23+
Context: ctx,
24+
Endpoint: Endpoint{
25+
APIEndpoint: config.APIEndpoint,
26+
Token: config.Token,
27+
},
28+
Method: http.MethodPost,
29+
Path: "/api/v1/cc/session-project",
30+
Payload: &sessionProjectRequest{
31+
SessionID: sessionID,
32+
ProjectPath: projectPath,
33+
},
34+
Response: &resp,
35+
Timeout: 5 * time.Second,
36+
})
37+
38+
return err
39+
}

model/cc_statusline_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ type CCStatuslineInput struct {
99
ContextWindow CCStatuslineContextWindow `json:"context_window"`
1010
Cwd string `json:"cwd"`
1111
Version string `json:"version"`
12+
SessionID string `json:"session_id"`
13+
Workspace *CCStatuslineWorkspace `json:"workspace"`
14+
}
15+
16+
// CCStatuslineWorkspace represents workspace information from Claude Code
17+
type CCStatuslineWorkspace struct {
18+
CurrentDir string `json:"current_dir"`
19+
ProjectDir string `json:"project_dir"`
1220
}
1321

1422
// CCStatuslineModel represents model information

0 commit comments

Comments
 (0)