feat(datastore): support --since in stop command, trigger website update from render_views, update docs
This commit is contained in:
@@ -594,10 +594,14 @@ class DatastoreEngine:
|
||||
kind: str,
|
||||
subject: str,
|
||||
end_time: Optional[str] = None,
|
||||
since: Optional[str] = None,
|
||||
event_id: Optional[str] = None,
|
||||
actor: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Finds the open event (end IS NULL) for kind and subject, and closes it."""
|
||||
if since and end_time:
|
||||
raise ValueError("Cannot specify both 'since' and 'end_time'. Use 'since' for relative times or 'end_time' for absolute times.")
|
||||
|
||||
if event_id:
|
||||
row = self.con.execute(
|
||||
"""
|
||||
@@ -622,13 +626,22 @@ class DatastoreEngine:
|
||||
|
||||
resolved_event_id, start_str = row[0], str(row[1])
|
||||
now_dt = datetime.datetime.now(datetime.timezone.utc)
|
||||
if end_time:
|
||||
if since:
|
||||
delta = parse_duration(since)
|
||||
end_dt = (now_dt - delta).astimezone(BERLIN_TZ)
|
||||
elif end_time:
|
||||
end_dt = datetime.datetime.fromisoformat(end_time)
|
||||
if end_dt.tzinfo is None:
|
||||
end_dt = end_dt.replace(tzinfo=BERLIN_TZ)
|
||||
else:
|
||||
end_dt = now_dt.astimezone(BERLIN_TZ)
|
||||
|
||||
start_dt = datetime.datetime.fromisoformat(start_str.replace("Z", "+00:00"))
|
||||
if start_dt.tzinfo is None:
|
||||
start_dt = start_dt.replace(tzinfo=BERLIN_TZ)
|
||||
if end_dt < start_dt:
|
||||
raise ValueError(f"End time {end_dt.isoformat()} cannot be earlier than start time {start_dt.isoformat()}")
|
||||
|
||||
end_iso = end_dt.isoformat()
|
||||
now_iso = now_dt.isoformat()
|
||||
|
||||
@@ -985,6 +998,8 @@ def run_mcp_server():
|
||||
"kind": {"type": "string", "description": "e.g. 'sleep.session'"},
|
||||
"subject": {"type": "string", "description": "'mila', 'moritz', 'amelie'"},
|
||||
"end_time": {"type": "string", "description": "ISO timestamp (optional, defaults to now)"},
|
||||
"since": {"type": "string", "description": "Relative end offset backwards from now (e.g. '5m', '15m')"},
|
||||
"event_id": {"type": "string", "description": "Specific open event ID to close (optional)"},
|
||||
},
|
||||
"required": ["kind", "subject"],
|
||||
},
|
||||
@@ -1100,6 +1115,8 @@ def run_mcp_server():
|
||||
kind=args["kind"],
|
||||
subject=args["subject"],
|
||||
end_time=args.get("end_time"),
|
||||
since=args.get("since"),
|
||||
event_id=args.get("event_id"),
|
||||
)
|
||||
elif name == "datastore_get_summary":
|
||||
data = engine.get_summary(subject=args["subject"], date_str=args.get("date"))
|
||||
@@ -1177,7 +1194,8 @@ def run_cli():
|
||||
p_stop.add_argument("--kind", dest="kind_flag", help="e.g. sleep.session")
|
||||
p_stop.add_argument("--subject", required=True, help="mila, moritz")
|
||||
p_stop.add_argument("--id", dest="event_id", help="Specific event ID to close")
|
||||
p_stop.add_argument("--end", help="ISO end time (defaults to now)")
|
||||
p_stop.add_argument("--end", dest="end_time", help="ISO end time (defaults to now)")
|
||||
p_stop.add_argument("--since", help="Relative end offset backwards from now (e.g. '5m', '15m')")
|
||||
|
||||
# Query
|
||||
p_query = subparsers.add_parser("query", help="Execute read-only SQL query")
|
||||
@@ -1226,7 +1244,13 @@ def run_cli():
|
||||
kind = args.kind or args.kind_flag
|
||||
if not kind:
|
||||
parser.error("the 'stop' command requires 'kind' (positional or via --kind)")
|
||||
res = engine.stop_event(kind=kind, subject=args.subject, end_time=args.end, event_id=getattr(args, "event_id", None))
|
||||
res = engine.stop_event(
|
||||
kind=kind,
|
||||
subject=args.subject,
|
||||
end_time=getattr(args, "end_time", None),
|
||||
since=getattr(args, "since", None),
|
||||
event_id=getattr(args, "event_id", None),
|
||||
)
|
||||
print(json.dumps(res, indent=2, ensure_ascii=False))
|
||||
elif args.command == "query":
|
||||
res = engine.query(args.sql)
|
||||
|
||||
@@ -579,6 +579,20 @@ def main():
|
||||
if not args.no_html:
|
||||
render_html_dashboards(engine, html_dir)
|
||||
|
||||
# Automatically trigger update_website.py for live publishing to hosting
|
||||
try:
|
||||
update_script = Path(__file__).resolve().parent / "update_website.py"
|
||||
if update_script.exists():
|
||||
import subprocess, shutil
|
||||
uv_bin = shutil.which("uv") or "/home/node/.openclaw/bin/uv"
|
||||
if Path(uv_bin).is_file():
|
||||
cmd = [str(uv_bin), "run", str(update_script)]
|
||||
else:
|
||||
cmd = [sys.executable, str(update_script)]
|
||||
subprocess.run(cmd, check=False)
|
||||
except Exception as e:
|
||||
print(f"Warning: could not trigger update_website.py from render_views: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user