Skip to content

Commit b7e9f78

Browse files
author
SqlRush
committed
Accept prompt history project aliases
1 parent 4c02885 commit b7e9f78

4 files changed

Lines changed: 45 additions & 4 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,8 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
472472

473473
本轮补充:prompt/history pasted-content 引用解析现在接受大小写差异和 `pasted image`/`input-image`/`input_text` 等占位符别名,文本展开、图片引用过滤和 next pasted ID seed 共用同一识别面。
474474

475+
本轮补充:prompt history `LogEntry` 读取现在接受 `projectPath`/`cwd`/`workingDirectory`/`workspacePath` 等 project 别名,以及 `createdAt`/`unixTimestamp` 等 timestamp 别名;RFC3339 时间会归一为毫秒时间戳,避免旧 history 因字段名不同被 project/session 过滤漏掉。
476+
475477
本轮补充:snapshot corpus 支持 `.ansi` only baselines,方便复用真实终端输出 corpus,而不必预先生成 `.txt` companion 文件。
476478

477479
本轮补充:terminal lifecycle 增加可选 extended-key mode,按官方 `CSI >1u`/`CSI >4;2m` 启用 kitty keyboard protocol 和 modifyOtherKeys,退出时重置 modifyOtherKeys 并 pop kitty stack,reassert 时先 pop 再 push,避免长期会话 stack 泄漏。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ M7 progress now includes:
320320
- `internal/session`/`internal/tui`: pasted-content ID decoding now accepts aliases such as `pastedContentId`/`attachmentID`/`contentID`/`imageID` and numeric strings for runtime/stored history and script attachments.
321321
- `internal/session`: prompt-history `pastedContents`/`pasted_contents` now accepts map, list, and single-object shapes for runtime and stored history, rebuilding maps from content IDs and aliases.
322322
- `internal/session`/`internal/tui`: pasted-content reference parsing now accepts case differences and placeholders such as `pasted image`/`input-image`/`input_text`, sharing that recognition across text expansion, image filtering, and next pasted ID seeding.
323+
- `internal/session`: prompt-history `LogEntry` loading now accepts project aliases such as `projectPath`/`cwd`/`workingDirectory`/`workspacePath` and timestamp aliases such as `createdAt`/`unixTimestamp`, including RFC3339 timestamp normalization to Unix milliseconds.
323324

324325
Still missing for full M6/M7 parity:
325326

internal/session/history_aliases.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"strconv"
77
"strings"
8+
"time"
89

910
"ccgo/internal/contracts"
1011
)
@@ -192,7 +193,7 @@ func historyIDJSONField(fields map[string]json.RawMessage, names ...string) cont
192193
return ""
193194
}
194195

195-
func historyInt64JSONField(fields map[string]json.RawMessage, names ...string) int64 {
196+
func historyTimestampJSONField(fields map[string]json.RawMessage, names ...string) int64 {
196197
for _, name := range names {
197198
raw, ok := fields[name]
198199
if !ok {
@@ -204,10 +205,19 @@ func historyInt64JSONField(fields map[string]json.RawMessage, names ...string) i
204205
}
205206
var text string
206207
if err := json.Unmarshal(raw, &text); err == nil {
207-
parsed, err := strconv.ParseInt(strings.TrimSpace(text), 10, 64)
208+
trimmed := strings.TrimSpace(text)
209+
parsed, err := strconv.ParseInt(trimmed, 10, 64)
208210
if err == nil {
209211
return parsed
210212
}
213+
when, err := time.Parse(time.RFC3339Nano, trimmed)
214+
if err == nil {
215+
return when.UnixMilli()
216+
}
217+
when, err = time.Parse(time.RFC3339, trimmed)
218+
if err == nil {
219+
return when.UnixMilli()
220+
}
211221
}
212222
}
213223
return 0
@@ -327,8 +337,8 @@ func (e *LogEntry) UnmarshalJSON(data []byte) error {
327337
*e = LogEntry{
328338
Display: historyStringJSONField(fields, "display"),
329339
PastedContents: historyStoredPastedContentsJSONField(fields, "pastedContents", "pasted_contents"),
330-
Timestamp: historyInt64JSONField(fields, "timestamp"),
331-
Project: historyStringJSONField(fields, "project"),
340+
Timestamp: historyTimestampJSONField(fields, "timestamp", "createdAt", "created_at", "time", "unixTimestamp", "unix_timestamp"),
341+
Project: historyStringJSONField(fields, "project", "projectPath", "project_path", "cwd", "cwdPath", "cwd_path", "workingDirectory", "working_directory", "workspacePath", "workspace_path", "workspace"),
332342
SessionID: firstHistoryID(
333343
historyIDJSONField(fields, "sessionId"),
334344
historyIDJSONField(fields, "sessionID"),

internal/session/history_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,34 @@ func TestLoadPromptHistoryAcceptsFieldAliases(t *testing.T) {
158158
}
159159
}
160160

161+
func TestLoadPromptHistoryAcceptsProjectAndTimestampAliases(t *testing.T) {
162+
path := filepath.Join(t.TempDir(), "history.jsonl")
163+
lines := []string{
164+
`{"display":"project path","pasted_contents":{},"createdAt":"1970-01-01T00:00:01Z","projectPath":"/repo","sessionUUID":"session"}`,
165+
`{"display":"cwd path","pasted_contents":{},"unixTimestamp":"2000","cwd":"/repo","sessionID":"other"}`,
166+
`{"display":"wrong project","pasted_contents":{},"timestamp":3000,"workingDirectory":"/else","sessionID":"session"}`,
167+
}
168+
if err := os.WriteFile(path, []byte(strings.Join(lines, "\n")+"\n"), 0o600); err != nil {
169+
t.Fatal(err)
170+
}
171+
172+
history, err := LoadHistory(path, "/repo", "session", MaxHistoryItems, nil)
173+
if err != nil {
174+
t.Fatal(err)
175+
}
176+
if got := displays(history); strings.Join(got, ",") != "project path,cwd path" {
177+
t.Fatalf("history = %#v", got)
178+
}
179+
180+
timestamped, err := LoadTimestampedHistory(path, "/repo", MaxHistoryItems, nil)
181+
if err != nil {
182+
t.Fatal(err)
183+
}
184+
if len(timestamped) != 2 || timestamped[0].Display != "cwd path" || timestamped[0].Timestamp != 2000 || timestamped[1].Display != "project path" || timestamped[1].Timestamp != 1000 {
185+
t.Fatalf("timestamped history = %#v", timestamped)
186+
}
187+
}
188+
161189
func TestHistoryEntryAcceptsPastedContentFieldAliases(t *testing.T) {
162190
var entry HistoryEntry
163191
err := json.Unmarshal([]byte(`{"display":"restore [Image #1] [Pasted text #2]","pasted_contents":{"1":{"pastedContentId":"1","kind":"inputImage","base64":"AAAA","mimeType":"image/png","name":"chart.png","path":"/tmp/chart.png","dimensions":{"width":4000,"height":2000}},"2":{"attachmentID":"2","pastedType":"pasted-text","value":"memo","contentType":"text/plain"}}}`), &entry)

0 commit comments

Comments
 (0)