agent-skill-installer 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -7,45 +7,56 @@ Produce a daily report from local Codex sessions.
|
|
|
7
7
|
|
|
8
8
|
## Workflow
|
|
9
9
|
|
|
10
|
-
1. Resolve target date
|
|
11
|
-
- If user says `today`,
|
|
10
|
+
1. Resolve target date to absolute date `YYYY-MM-DD`.
|
|
11
|
+
- If user says `today`, convert explicitly (for example `2026-03-02`).
|
|
12
|
+
- If user says relative dates (`yesterday`, `tomorrow`), convert to concrete dates first.
|
|
12
13
|
|
|
13
|
-
2.
|
|
14
|
+
2. Extract `assistant final_answer` entries with bundled script.
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
|
|
17
|
+
python3 skills/codex-session-daily-report/scripts/extract_final_answers.py --date 2026-03-02
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
3.
|
|
20
|
+
3. If user asks for a custom session root, pass `--root`.
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
| map(select(.type=="output_text") | .text)
|
|
26
|
-
| join(" ") | gsub("[\n\r\t]+";" ") | gsub(" +";" "))' "$f"
|
|
27
|
-
done
|
|
23
|
+
python3 skills/codex-session-daily-report/scripts/extract_final_answers.py \
|
|
24
|
+
--date 2026-03-02 \
|
|
25
|
+
--root ~/.codex/sessions
|
|
28
26
|
```
|
|
29
27
|
|
|
30
|
-
4. Summarize
|
|
31
|
-
- Merge similar tasks into one topic
|
|
32
|
-
- Keep
|
|
33
|
-
- Keep neutral
|
|
28
|
+
4. Summarize only completed outcomes from extracted lines.
|
|
29
|
+
- Merge similar tasks into one topic.
|
|
30
|
+
- Keep concrete evidence when present: file paths, test commands/results, commit hashes.
|
|
31
|
+
- Keep neutral wording and avoid guessing missing facts.
|
|
34
32
|
|
|
35
|
-
5. Output
|
|
33
|
+
5. Output report only, not raw logs, unless user explicitly asks for raw lines.
|
|
36
34
|
|
|
37
35
|
## Output Format
|
|
38
36
|
|
|
39
37
|
Use this structure:
|
|
40
38
|
|
|
41
39
|
1. 日期:`YYYY-MM-DD`
|
|
42
|
-
2.
|
|
43
|
-
3.
|
|
44
|
-
4.
|
|
40
|
+
2. 统计快照:`会话文件 N`、`final_answer N`、`覆盖时段 HH:mm-HH:mm`
|
|
41
|
+
3. 今日业务事项:按主题列 2-6 条,每条包含 `动作`、`结果`、`证据`
|
|
42
|
+
4. 关键产出:按类型分组输出
|
|
43
|
+
- 代码改动:关键文件路径
|
|
44
|
+
- 验证结果:命令与结论
|
|
45
|
+
- 提交记录:提交哈希与提交说明
|
|
46
|
+
5. 风险与待办:每条包含 `风险/阻塞`、`影响`、`下一步`
|
|
47
|
+
6. 数据缺口说明:若无会话文件、无 final_answer 或证据不足,明确说明影响范围
|
|
45
48
|
|
|
46
49
|
## Constraints
|
|
47
50
|
|
|
48
|
-
-
|
|
51
|
+
- Use `assistant final_answer` only; do not use `commentary` as completion evidence.
|
|
49
52
|
- Do not output raw JSONL unless user explicitly asks.
|
|
50
53
|
- Keep report concise and factual.
|
|
51
|
-
- If no
|
|
54
|
+
- If no session files or no `final_answer` are found, state that clearly in the report.
|
|
55
|
+
- Prefer explicit evidence fields over narrative paragraphs.
|
|
56
|
+
- If evidence is missing for a topic, mark it as `证据不足` instead of guessing.
|
|
57
|
+
|
|
58
|
+
## Resource
|
|
59
|
+
|
|
60
|
+
- `skills/codex-session-daily-report/scripts/extract_final_answers.py`
|
|
61
|
+
- Input: `--date YYYY-MM-DD`, optional `--root`.
|
|
62
|
+
- Output: `timestamp<TAB>session_file<TAB>text`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "codex-session-daily-report"
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "Use $codex-session-daily-report to
|
|
3
|
+
short_description: "Summarize Codex final answers into a daily report"
|
|
4
|
+
default_prompt: "Use $codex-session-daily-report to resolve a concrete target date, extract assistant final_answer entries from ~/.codex/sessions, and output a concise factual daily report."
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Extract assistant final answers from Codex session JSONL files."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import glob
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
WHITESPACE_RE = re.compile(r"\s+")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def normalize_text(text: str) -> str:
|
|
18
|
+
return WHITESPACE_RE.sub(" ", text).strip()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_date(value: str) -> tuple[str, str, str]:
|
|
22
|
+
parts = value.split("-")
|
|
23
|
+
if len(parts) != 3 or not all(part.isdigit() for part in parts):
|
|
24
|
+
raise ValueError("日期格式必须为 YYYY-MM-DD")
|
|
25
|
+
|
|
26
|
+
year, month, day = parts
|
|
27
|
+
if len(year) != 4 or len(month) != 2 or len(day) != 2:
|
|
28
|
+
raise ValueError("日期格式必须为 YYYY-MM-DD")
|
|
29
|
+
|
|
30
|
+
return year, month, day
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def collect_session_files(root: str, date_value: str) -> list[str]:
|
|
34
|
+
year, month, day = parse_date(date_value)
|
|
35
|
+
pattern = os.path.join(root, year, month, day, "*.jsonl")
|
|
36
|
+
return sorted(glob.glob(pattern))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def extract_records(file_path: str) -> list[str]:
|
|
40
|
+
records: list[str] = []
|
|
41
|
+
with Path(file_path).open("r", encoding="utf-8") as handle:
|
|
42
|
+
for line in handle:
|
|
43
|
+
if not line.strip():
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
item = json.loads(line)
|
|
48
|
+
except json.JSONDecodeError:
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
if item.get("type") != "response_item":
|
|
52
|
+
continue
|
|
53
|
+
|
|
54
|
+
payload = item.get("payload") or {}
|
|
55
|
+
if payload.get("type") != "message":
|
|
56
|
+
continue
|
|
57
|
+
if payload.get("role") != "assistant":
|
|
58
|
+
continue
|
|
59
|
+
if payload.get("phase") != "final_answer":
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
content = payload.get("content") or []
|
|
63
|
+
text_parts = [
|
|
64
|
+
part.get("text", "")
|
|
65
|
+
for part in content
|
|
66
|
+
if isinstance(part, dict) and part.get("type") == "output_text"
|
|
67
|
+
]
|
|
68
|
+
text = normalize_text(" ".join(text_parts))
|
|
69
|
+
if not text:
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
timestamp = item.get("timestamp", "")
|
|
73
|
+
session_file = os.path.basename(file_path)
|
|
74
|
+
records.append(f"{timestamp}\t{session_file}\t{text}")
|
|
75
|
+
|
|
76
|
+
return records
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main() -> int:
|
|
80
|
+
parser = argparse.ArgumentParser(
|
|
81
|
+
description="提取指定日期的 assistant final_answer 内容",
|
|
82
|
+
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"--date",
|
|
85
|
+
required=True,
|
|
86
|
+
help="目标日期,格式 YYYY-MM-DD",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--root",
|
|
90
|
+
default="~/.codex/sessions",
|
|
91
|
+
help="sessions 根目录,默认 ~/.codex/sessions",
|
|
92
|
+
)
|
|
93
|
+
args = parser.parse_args()
|
|
94
|
+
|
|
95
|
+
root = os.path.expanduser(args.root)
|
|
96
|
+
files = collect_session_files(root, args.date)
|
|
97
|
+
|
|
98
|
+
if not files:
|
|
99
|
+
print(f"未找到会话文件: {args.date}", file=sys.stderr)
|
|
100
|
+
return 1
|
|
101
|
+
|
|
102
|
+
wrote = False
|
|
103
|
+
for file_path in files:
|
|
104
|
+
for record in extract_records(file_path):
|
|
105
|
+
print(record)
|
|
106
|
+
wrote = True
|
|
107
|
+
|
|
108
|
+
if not wrote:
|
|
109
|
+
print(f"未找到 final_answer: {args.date}", file=sys.stderr)
|
|
110
|
+
return 2
|
|
111
|
+
|
|
112
|
+
return 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
sys.exit(main())
|