v0.33.0 653c635

time_context.go RawHistoryFolder

1package core
2
3import (
4	"fmt"
5	"strconv"
6	"strings"
7	"time"
8)
9
10type agentTimeContext struct {
11	started  time.Time
12	location *time.Location
13	zone     string
14	offset   string
15}
16
17func newAgentTimeContext(now time.Time) agentTimeContext {
18	zoneName, offset := localTimeMetadata(now)
19	return agentTimeContext{
20		started:  now,
21		location: now.Location(),
22		zone:     zoneName,
23		offset:   offset,
24	}
25}
26
27func localTimeMetadata(now time.Time) (string, string) {
28	zone, seconds := now.Zone()
29	zoneName := now.Location().String()
30	if zoneName == "" || zoneName == "Local" {
31		zoneName = zone
32	}
33	return zoneName, formatUTCOffset(seconds)
34}
35
36func (a *Agent) SetSessionTimeContext(started time.Time, timezone, offset string) {
37	if started.IsZero() {
38		return
39	}
40	location := time.Local
41	loadedTimezone := false
42	if timezone != "" && timezone != "Local" {
43		if loaded, err := time.LoadLocation(timezone); err == nil {
44			location = loaded
45			loadedTimezone = true
46		}
47	}
48	if !loadedTimezone && offset != "" {
49		if fixed := parseUTCOffset(offset); fixed != nil {
50			location = fixed
51		}
52	}
53	if timezone == "" {
54		timezone = location.String()
55	}
56	if offset == "" {
57		_, seconds := started.In(location).Zone()
58		offset = formatUTCOffset(seconds)
59	}
60
61	a.mu.Lock()
62	a.timeContext = agentTimeContext{
63		started:  started,
64		location: location,
65		zone:     timezone,
66		offset:   offset,
67	}
68	a.hasSessionTimeContext = true
69	a.mu.Unlock()
70}
71
72func (a *Agent) providerTimeContext() agentTimeContext {
73	a.mu.Lock()
74	defer a.mu.Unlock()
75	if !a.hasSessionTimeContext {
76		return agentTimeContext{}
77	}
78	return a.timeContext
79}
80
81func (c agentTimeContext) systemText() string {
82	return c.developerText()
83}
84
85// developerText returns host context projected after stable instructions.
86// Minute precision is sufficient for coordination and avoids generating a
87// unique timestamp solely to distinguish otherwise-equal agents.
88func (c agentTimeContext) developerText() string {
89	if c.started.IsZero() {
90		return ""
91	}
92	location := c.location
93	if location == nil {
94		location = time.UTC
95	}
96	zone := c.zone
97	if zone == "" {
98		zone = location.String()
99	}
100	offset := c.offset
101	if offset == "" {
102		_, seconds := c.started.In(location).Zone()
103		offset = formatUTCOffset(seconds)
104	}
105	return fmt.Sprintf("[Session time context]\nsession_started: %s\nlocal_timezone: %s (UTC%s)", c.started.In(location).Format("2006-01-02 15:04"), zone, offset)
106}
107
108func formatUTCOffset(seconds int) string {
109	sign := "+"
110	if seconds < 0 {
111		sign = "-"
112		seconds = -seconds
113	}
114	return fmt.Sprintf("%s%02d:%02d", sign, seconds/3600, (seconds%3600)/60)
115}
116
117func parseUTCOffset(value string) *time.Location {
118	if len(value) != len("+00:00") || (value[0] != '+' && value[0] != '-') || value[3] != ':' {
119		return nil
120	}
121	hours, errHours := strconv.Atoi(value[1:3])
122	minutes, errMinutes := strconv.Atoi(value[4:6])
123	if errHours != nil || errMinutes != nil || hours > 23 || minutes > 59 {
124		return nil
125	}
126	seconds := hours*3600 + minutes*60
127	if strings.HasPrefix(value, "-") {
128		seconds = -seconds
129	}
130	return time.FixedZone(value, seconds)
131}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close