spooling 0.2.3__tar.gz → 0.2.5__tar.gz

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.
Files changed (66) hide show
  1. {spooling-0.2.3/spooling.egg-info → spooling-0.2.5}/PKG-INFO +1 -1
  2. {spooling-0.2.3 → spooling-0.2.5}/pyproject.toml +1 -1
  3. {spooling-0.2.3 → spooling-0.2.5}/spooling/cloud.py +30 -10
  4. {spooling-0.2.3 → spooling-0.2.5/spooling.egg-info}/PKG-INFO +1 -1
  5. {spooling-0.2.3 → spooling-0.2.5}/LICENSE +0 -0
  6. {spooling-0.2.3 → spooling-0.2.5}/README.md +0 -0
  7. {spooling-0.2.3 → spooling-0.2.5}/setup.cfg +0 -0
  8. {spooling-0.2.3 → spooling-0.2.5}/spooling/__init__.py +0 -0
  9. {spooling-0.2.3 → spooling-0.2.5}/spooling/agent.py +0 -0
  10. {spooling-0.2.3 → spooling-0.2.5}/spooling/classifiers.py +0 -0
  11. {spooling-0.2.3 → spooling-0.2.5}/spooling/cli.py +0 -0
  12. {spooling-0.2.3 → spooling-0.2.5}/spooling/config.py +0 -0
  13. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/__init__.py +0 -0
  14. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/base.py +0 -0
  15. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/bigquery.py +0 -0
  16. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/clickhouse.py +0 -0
  17. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/factory.py +0 -0
  18. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/mongodb.py +0 -0
  19. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/mysql.py +0 -0
  20. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/postgresql.py +0 -0
  21. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/rest/__init__.py +0 -0
  22. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/rest/base.py +0 -0
  23. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/rest/shopify_connectors.py +0 -0
  24. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/snowflake.py +0 -0
  25. {spooling-0.2.3 → spooling-0.2.5}/spooling/connectors/types.py +0 -0
  26. {spooling-0.2.3 → spooling-0.2.5}/spooling/db.py +0 -0
  27. {spooling-0.2.3 → spooling-0.2.5}/spooling/embeddings.py +0 -0
  28. {spooling-0.2.3 → spooling-0.2.5}/spooling/evals.py +0 -0
  29. {spooling-0.2.3 → spooling-0.2.5}/spooling/experiments.py +0 -0
  30. {spooling-0.2.3 → spooling-0.2.5}/spooling/ingest.py +0 -0
  31. {spooling-0.2.3 → spooling-0.2.5}/spooling/mcp_server.py +0 -0
  32. {spooling-0.2.3 → spooling-0.2.5}/spooling/parser.py +0 -0
  33. {spooling-0.2.3 → spooling-0.2.5}/spooling/pricing.py +0 -0
  34. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/__init__.py +0 -0
  35. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/antigravity.py +0 -0
  36. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/base.py +0 -0
  37. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/codex.py +0 -0
  38. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/copilot.py +0 -0
  39. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/cortex_code.py +0 -0
  40. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/cursor.py +0 -0
  41. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/gemini.py +0 -0
  42. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/github.py +0 -0
  43. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/gitlab.py +0 -0
  44. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/kiro.py +0 -0
  45. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/opencode.py +0 -0
  46. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/session_file.py +0 -0
  47. {spooling-0.2.3 → spooling-0.2.5}/spooling/providers/windsurf.py +0 -0
  48. {spooling-0.2.3 → spooling-0.2.5}/spooling/redact.py +0 -0
  49. {spooling-0.2.3 → spooling-0.2.5}/spooling/remote_otel.py +0 -0
  50. {spooling-0.2.3 → spooling-0.2.5}/spooling/schema.py +0 -0
  51. {spooling-0.2.3 → spooling-0.2.5}/spooling/sdk.py +0 -0
  52. {spooling-0.2.3 → spooling-0.2.5}/spooling/search.py +0 -0
  53. {spooling-0.2.3 → spooling-0.2.5}/spooling/server.py +0 -0
  54. {spooling-0.2.3 → spooling-0.2.5}/spooling/stats.py +0 -0
  55. {spooling-0.2.3 → spooling-0.2.5}/spooling/subscription_pricing.py +0 -0
  56. {spooling-0.2.3 → spooling-0.2.5}/spooling/tracing.py +0 -0
  57. {spooling-0.2.3 → spooling-0.2.5}/spooling/tunnel.py +0 -0
  58. {spooling-0.2.3 → spooling-0.2.5}/spooling/tunnel_auth.py +0 -0
  59. {spooling-0.2.3 → spooling-0.2.5}/spooling/watcher.py +0 -0
  60. {spooling-0.2.3 → spooling-0.2.5}/spooling.egg-info/SOURCES.txt +0 -0
  61. {spooling-0.2.3 → spooling-0.2.5}/spooling.egg-info/dependency_links.txt +0 -0
  62. {spooling-0.2.3 → spooling-0.2.5}/spooling.egg-info/entry_points.txt +0 -0
  63. {spooling-0.2.3 → spooling-0.2.5}/spooling.egg-info/requires.txt +0 -0
  64. {spooling-0.2.3 → spooling-0.2.5}/spooling.egg-info/top_level.txt +0 -0
  65. {spooling-0.2.3 → spooling-0.2.5}/tests/test_mcp_auth_middleware.py +0 -0
  66. {spooling-0.2.3 → spooling-0.2.5}/tests/test_tunnel_auth.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spooling
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Local session tracker and semantic search for AI coding assistants
5
5
  Author: Parsed Analytics, Inc.
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "spooling"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Local session tracker and semantic search for AI coding assistants"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Parsed Analytics, Inc." }]
@@ -221,6 +221,26 @@ def _collect_traces(session_ids: list[str]) -> list[dict]:
221
221
  """
222
222
  if not session_ids:
223
223
  return []
224
+
225
+ def _ts(v) -> str | None:
226
+ """Return an ISO-8601 string regardless of whether v is a datetime or str."""
227
+ if v is None:
228
+ return None
229
+ if isinstance(v, str):
230
+ return v
231
+ return v.isoformat()
232
+
233
+ def _json(v, default):
234
+ """Return a parsed object regardless of whether v is already parsed or a JSON string."""
235
+ if v is None:
236
+ return default
237
+ if isinstance(v, str):
238
+ import json as _json_mod
239
+ try:
240
+ return _json_mod.loads(v)
241
+ except Exception:
242
+ return default
243
+ return v
224
244
  conn = get_connection()
225
245
  try:
226
246
  placeholders = ", ".join(["%s"] * len(session_ids))
@@ -262,8 +282,8 @@ def _collect_traces(session_ids: list[str]) -> list[dict]:
262
282
  "kind": s["kind"],
263
283
  "name": _clean_str(s["name"], _MAX_SPAN_NAME),
264
284
  "status": s["status"] or "ok",
265
- "started_at": s["started_at"].isoformat() if s["started_at"] else None,
266
- "ended_at": s["ended_at"].isoformat() if s["ended_at"] else None,
285
+ "started_at": _ts(s["started_at"]),
286
+ "ended_at": _ts(s["ended_at"]),
267
287
  "duration_ms": int(s["duration_ms"] or 0),
268
288
  "depth": int(s["depth"] or 0),
269
289
  "sequence": int(s["sequence"] or 0),
@@ -274,19 +294,19 @@ def _collect_traces(session_ids: list[str]) -> list[dict]:
274
294
  "cost_usd": float(s["cost_usd"] or 0),
275
295
  "model": s["model"],
276
296
  "tool_name": s["tool_name"],
277
- "tool_input": s["tool_input"],
297
+ "tool_input": _json(s["tool_input"], None),
278
298
  "tool_output": (s["tool_output"] or "")[:200000] if s["tool_output"] else None,
279
299
  "tool_is_error": bool(s["tool_is_error"]),
280
300
  "agent_type": s["agent_type"],
281
301
  "agent_prompt": (s["agent_prompt"] or "")[:200000] if s["agent_prompt"] else None,
282
302
  "vendor": s["vendor"],
283
303
  "category": s["category"],
284
- "attrs": s["attrs"] or {},
304
+ "attrs": _json(s["attrs"], {}),
285
305
  "events": [
286
306
  {
287
307
  "name": e["name"],
288
- "timestamp": e["timestamp"].isoformat() if e["timestamp"] else None,
289
- "attrs": e["attrs"] or {},
308
+ "timestamp": _ts(e["timestamp"]),
309
+ "attrs": _json(e["attrs"], {}),
290
310
  }
291
311
  for e in events
292
312
  ],
@@ -298,8 +318,8 @@ def _collect_traces(session_ids: list[str]) -> list[dict]:
298
318
  "provider_id": t["provider_id"],
299
319
  "project": t["project"],
300
320
  "title": _clean_str(t["title"], _MAX_TITLE),
301
- "started_at": t["started_at"].isoformat() if t["started_at"] else None,
302
- "ended_at": t["ended_at"].isoformat() if t["ended_at"] else None,
321
+ "started_at": _ts(t["started_at"]),
322
+ "ended_at": _ts(t["ended_at"]),
303
323
  "duration_ms": int(t["duration_ms"] or 0),
304
324
  "span_count": int(t["span_count"] or 0),
305
325
  "agent_count": int(t["agent_count"] or 0),
@@ -315,8 +335,8 @@ def _collect_traces(session_ids: list[str]) -> list[dict]:
315
335
  "git_branch": t["git_branch"],
316
336
  "model": t["model"],
317
337
  "vendor_count": int(t["vendor_count"] or 0),
318
- "top_vendors": t["top_vendors"] or [],
319
- "attrs": t["attrs"] or {},
338
+ "top_vendors": _json(t["top_vendors"], []),
339
+ "attrs": _json(t["attrs"], {}),
320
340
  "spans": spans_payload,
321
341
  })
322
342
  return out
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spooling
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Local session tracker and semantic search for AI coding assistants
5
5
  Author: Parsed Analytics, Inc.
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes