gobby 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl
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.
- gobby/__init__.py +1 -1
- gobby/adapters/__init__.py +2 -1
- gobby/adapters/claude_code.py +13 -4
- gobby/adapters/codex_impl/__init__.py +28 -0
- gobby/adapters/codex_impl/adapter.py +722 -0
- gobby/adapters/codex_impl/client.py +679 -0
- gobby/adapters/codex_impl/protocol.py +20 -0
- gobby/adapters/codex_impl/types.py +68 -0
- gobby/agents/definitions.py +11 -1
- gobby/agents/isolation.py +395 -0
- gobby/agents/runner.py +8 -0
- gobby/agents/sandbox.py +261 -0
- gobby/agents/spawn.py +42 -287
- gobby/agents/spawn_executor.py +385 -0
- gobby/agents/spawners/__init__.py +24 -0
- gobby/agents/spawners/command_builder.py +189 -0
- gobby/agents/spawners/embedded.py +21 -2
- gobby/agents/spawners/headless.py +21 -2
- gobby/agents/spawners/prompt_manager.py +125 -0
- gobby/cli/__init__.py +6 -0
- gobby/cli/clones.py +419 -0
- gobby/cli/conductor.py +266 -0
- gobby/cli/install.py +4 -4
- gobby/cli/installers/antigravity.py +3 -9
- gobby/cli/installers/claude.py +15 -9
- gobby/cli/installers/codex.py +2 -8
- gobby/cli/installers/gemini.py +8 -8
- gobby/cli/installers/shared.py +175 -13
- gobby/cli/sessions.py +1 -1
- gobby/cli/skills.py +858 -0
- gobby/cli/tasks/ai.py +0 -440
- gobby/cli/tasks/crud.py +44 -6
- gobby/cli/tasks/main.py +0 -4
- gobby/cli/tui.py +2 -2
- gobby/cli/utils.py +12 -5
- gobby/clones/__init__.py +13 -0
- gobby/clones/git.py +547 -0
- gobby/conductor/__init__.py +16 -0
- gobby/conductor/alerts.py +135 -0
- gobby/conductor/loop.py +164 -0
- gobby/conductor/monitors/__init__.py +11 -0
- gobby/conductor/monitors/agents.py +116 -0
- gobby/conductor/monitors/tasks.py +155 -0
- gobby/conductor/pricing.py +234 -0
- gobby/conductor/token_tracker.py +160 -0
- gobby/config/__init__.py +12 -97
- gobby/config/app.py +69 -91
- gobby/config/extensions.py +2 -2
- gobby/config/features.py +7 -130
- gobby/config/search.py +110 -0
- gobby/config/servers.py +1 -1
- gobby/config/skills.py +43 -0
- gobby/config/tasks.py +9 -41
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +188 -2
- gobby/hooks/hook_manager.py +50 -4
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/skill_manager.py +130 -0
- gobby/hooks/webhooks.py +1 -1
- gobby/install/claude/hooks/hook_dispatcher.py +4 -4
- gobby/install/codex/hooks/hook_dispatcher.py +1 -1
- gobby/install/gemini/hooks/hook_dispatcher.py +87 -12
- gobby/llm/claude.py +22 -34
- gobby/llm/claude_executor.py +46 -256
- gobby/llm/codex_executor.py +59 -291
- gobby/llm/executor.py +21 -0
- gobby/llm/gemini.py +134 -110
- gobby/llm/litellm_executor.py +143 -6
- gobby/llm/resolver.py +98 -35
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +56 -0
- gobby/mcp_proxy/models.py +15 -0
- gobby/mcp_proxy/registries.py +68 -8
- gobby/mcp_proxy/server.py +33 -3
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/services/tool_proxy.py +81 -1
- gobby/mcp_proxy/stdio.py +2 -1
- gobby/mcp_proxy/tools/__init__.py +0 -2
- gobby/mcp_proxy/tools/agent_messaging.py +317 -0
- gobby/mcp_proxy/tools/agents.py +31 -731
- gobby/mcp_proxy/tools/clones.py +518 -0
- gobby/mcp_proxy/tools/memory.py +3 -26
- gobby/mcp_proxy/tools/metrics.py +65 -1
- gobby/mcp_proxy/tools/orchestration/__init__.py +3 -0
- gobby/mcp_proxy/tools/orchestration/cleanup.py +151 -0
- gobby/mcp_proxy/tools/orchestration/wait.py +467 -0
- gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
- gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
- gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
- gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
- gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
- gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
- gobby/mcp_proxy/tools/skills/__init__.py +616 -0
- gobby/mcp_proxy/tools/spawn_agent.py +417 -0
- gobby/mcp_proxy/tools/task_orchestration.py +7 -0
- gobby/mcp_proxy/tools/task_readiness.py +14 -0
- gobby/mcp_proxy/tools/task_sync.py +1 -1
- gobby/mcp_proxy/tools/tasks/_context.py +0 -20
- gobby/mcp_proxy/tools/tasks/_crud.py +91 -4
- gobby/mcp_proxy/tools/tasks/_expansion.py +348 -0
- gobby/mcp_proxy/tools/tasks/_factory.py +6 -16
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +110 -45
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +18 -29
- gobby/mcp_proxy/tools/workflows.py +1 -1
- gobby/mcp_proxy/tools/worktrees.py +0 -338
- gobby/memory/backends/__init__.py +6 -1
- gobby/memory/backends/mem0.py +6 -1
- gobby/memory/extractor.py +477 -0
- gobby/memory/ingestion/__init__.py +5 -0
- gobby/memory/ingestion/multimodal.py +221 -0
- gobby/memory/manager.py +73 -285
- gobby/memory/search/__init__.py +10 -0
- gobby/memory/search/coordinator.py +248 -0
- gobby/memory/services/__init__.py +5 -0
- gobby/memory/services/crossref.py +142 -0
- gobby/prompts/loader.py +5 -2
- gobby/runner.py +37 -16
- gobby/search/__init__.py +48 -6
- gobby/search/backends/__init__.py +159 -0
- gobby/search/backends/embedding.py +225 -0
- gobby/search/embeddings.py +238 -0
- gobby/search/models.py +148 -0
- gobby/search/unified.py +496 -0
- gobby/servers/http.py +24 -12
- gobby/servers/routes/admin.py +294 -0
- gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
- gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
- gobby/servers/routes/mcp/endpoints/execution.py +568 -0
- gobby/servers/routes/mcp/endpoints/registry.py +378 -0
- gobby/servers/routes/mcp/endpoints/server.py +304 -0
- gobby/servers/routes/mcp/hooks.py +1 -1
- gobby/servers/routes/mcp/tools.py +48 -1317
- gobby/servers/websocket.py +2 -2
- gobby/sessions/analyzer.py +2 -0
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +2 -0
- gobby/sessions/transcripts/claude.py +79 -10
- gobby/skills/__init__.py +91 -0
- gobby/skills/loader.py +685 -0
- gobby/skills/manager.py +384 -0
- gobby/skills/parser.py +286 -0
- gobby/skills/search.py +463 -0
- gobby/skills/sync.py +119 -0
- gobby/skills/updater.py +385 -0
- gobby/skills/validator.py +368 -0
- gobby/storage/clones.py +378 -0
- gobby/storage/database.py +1 -1
- gobby/storage/memories.py +43 -13
- gobby/storage/migrations.py +162 -201
- gobby/storage/sessions.py +116 -7
- gobby/storage/skills.py +782 -0
- gobby/storage/tasks/_crud.py +4 -4
- gobby/storage/tasks/_lifecycle.py +57 -7
- gobby/storage/tasks/_manager.py +14 -5
- gobby/storage/tasks/_models.py +8 -3
- gobby/sync/memories.py +40 -5
- gobby/sync/tasks.py +83 -6
- gobby/tasks/__init__.py +1 -2
- gobby/tasks/external_validator.py +1 -1
- gobby/tasks/validation.py +46 -35
- gobby/tools/summarizer.py +91 -10
- gobby/tui/api_client.py +4 -7
- gobby/tui/app.py +5 -3
- gobby/tui/screens/orchestrator.py +1 -2
- gobby/tui/screens/tasks.py +2 -4
- gobby/tui/ws_client.py +1 -1
- gobby/utils/daemon_client.py +2 -2
- gobby/utils/project_context.py +2 -3
- gobby/utils/status.py +13 -0
- gobby/workflows/actions.py +221 -1135
- gobby/workflows/artifact_actions.py +31 -0
- gobby/workflows/autonomous_actions.py +11 -0
- gobby/workflows/context_actions.py +93 -1
- gobby/workflows/detection_helpers.py +115 -31
- gobby/workflows/enforcement/__init__.py +47 -0
- gobby/workflows/enforcement/blocking.py +269 -0
- gobby/workflows/enforcement/commit_policy.py +283 -0
- gobby/workflows/enforcement/handlers.py +269 -0
- gobby/workflows/{task_enforcement_actions.py → enforcement/task_policy.py} +29 -388
- gobby/workflows/engine.py +13 -2
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/lifecycle_evaluator.py +29 -1
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/loader.py +19 -6
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +154 -0
- gobby/workflows/safe_evaluator.py +183 -0
- gobby/workflows/session_actions.py +44 -0
- gobby/workflows/state_actions.py +60 -1
- gobby/workflows/stop_signal_actions.py +55 -0
- gobby/workflows/summary_actions.py +111 -1
- gobby/workflows/task_sync_actions.py +347 -0
- gobby/workflows/todo_actions.py +34 -1
- gobby/workflows/webhook_actions.py +185 -0
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/METADATA +87 -21
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/RECORD +201 -172
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1292
- gobby/install/claude/commands/gobby/bug.md +0 -51
- gobby/install/claude/commands/gobby/chore.md +0 -51
- gobby/install/claude/commands/gobby/epic.md +0 -52
- gobby/install/claude/commands/gobby/eval.md +0 -235
- gobby/install/claude/commands/gobby/feat.md +0 -49
- gobby/install/claude/commands/gobby/nit.md +0 -52
- gobby/install/claude/commands/gobby/ref.md +0 -52
- gobby/install/codex/prompts/forget.md +0 -7
- gobby/install/codex/prompts/memories.md +0 -7
- gobby/install/codex/prompts/recall.md +0 -7
- gobby/install/codex/prompts/remember.md +0 -13
- gobby/llm/gemini_executor.py +0 -339
- gobby/mcp_proxy/tools/session_messages.py +0 -1056
- gobby/mcp_proxy/tools/task_expansion.py +0 -591
- gobby/prompts/defaults/expansion/system.md +0 -119
- gobby/prompts/defaults/expansion/user.md +0 -48
- gobby/prompts/defaults/external_validation/agent.md +0 -72
- gobby/prompts/defaults/external_validation/external.md +0 -63
- gobby/prompts/defaults/external_validation/spawn.md +0 -83
- gobby/prompts/defaults/external_validation/system.md +0 -6
- gobby/prompts/defaults/features/import_mcp.md +0 -22
- gobby/prompts/defaults/features/import_mcp_github.md +0 -17
- gobby/prompts/defaults/features/import_mcp_search.md +0 -16
- gobby/prompts/defaults/features/recommend_tools.md +0 -32
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
- gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
- gobby/prompts/defaults/features/server_description.md +0 -20
- gobby/prompts/defaults/features/server_description_system.md +0 -6
- gobby/prompts/defaults/features/task_description.md +0 -31
- gobby/prompts/defaults/features/task_description_system.md +0 -6
- gobby/prompts/defaults/features/tool_summary.md +0 -17
- gobby/prompts/defaults/features/tool_summary_system.md +0 -6
- gobby/prompts/defaults/research/step.md +0 -58
- gobby/prompts/defaults/validation/criteria.md +0 -47
- gobby/prompts/defaults/validation/validate.md +0 -38
- gobby/storage/migrations_legacy.py +0 -1359
- gobby/tasks/context.py +0 -747
- gobby/tasks/criteria.py +0 -342
- gobby/tasks/expansion.py +0 -626
- gobby/tasks/prompts/expand.py +0 -327
- gobby/tasks/research.py +0 -421
- gobby/tasks/tdd.py +0 -352
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
gobby/storage/sessions.py
CHANGED
|
@@ -47,10 +47,13 @@ class Session:
|
|
|
47
47
|
usage_cache_creation_tokens: int = 0
|
|
48
48
|
usage_cache_read_tokens: int = 0
|
|
49
49
|
usage_total_cost_usd: float = 0.0
|
|
50
|
+
model: str | None = None # LLM model used (e.g., "claude-3-5-sonnet-20241022")
|
|
50
51
|
# Terminal context (JSON blob with tty, parent_pid, term_session_id, etc.)
|
|
51
52
|
terminal_context: dict[str, Any] | None = None
|
|
52
53
|
# Global sequence number
|
|
53
54
|
seq_num: int | None = None
|
|
55
|
+
# Edit history tracking
|
|
56
|
+
had_edits: bool = False
|
|
54
57
|
|
|
55
58
|
@classmethod
|
|
56
59
|
def from_row(cls, row: Any) -> Session:
|
|
@@ -82,8 +85,10 @@ class Session:
|
|
|
82
85
|
usage_cache_creation_tokens=row["usage_cache_creation_tokens"] or 0,
|
|
83
86
|
usage_cache_read_tokens=row["usage_cache_read_tokens"] or 0,
|
|
84
87
|
usage_total_cost_usd=row["usage_total_cost_usd"] or 0.0,
|
|
88
|
+
model=row["model"] if "model" in row.keys() else None,
|
|
85
89
|
terminal_context=cls._parse_terminal_context(row["terminal_context"]),
|
|
86
90
|
seq_num=row["seq_num"] if "seq_num" in row.keys() else None,
|
|
91
|
+
had_edits=bool(row["had_edits"]) if "had_edits" in row.keys() else False,
|
|
87
92
|
)
|
|
88
93
|
|
|
89
94
|
@classmethod
|
|
@@ -133,6 +138,7 @@ class Session:
|
|
|
133
138
|
"usage_cache_read_tokens": self.usage_cache_read_tokens,
|
|
134
139
|
"usage_total_cost_usd": self.usage_total_cost_usd,
|
|
135
140
|
"terminal_context": self.terminal_context,
|
|
141
|
+
"had_edits": self.had_edits,
|
|
136
142
|
"created_at": self.created_at,
|
|
137
143
|
"updated_at": self.updated_at,
|
|
138
144
|
"seq_num": self.seq_num,
|
|
@@ -222,8 +228,11 @@ class LocalSessionManager:
|
|
|
222
228
|
max_retries = 3
|
|
223
229
|
for attempt in range(max_retries):
|
|
224
230
|
try:
|
|
225
|
-
# Get next seq_num (
|
|
226
|
-
max_seq_row = self.db.fetchone(
|
|
231
|
+
# Get next seq_num (per-project)
|
|
232
|
+
max_seq_row = self.db.fetchone(
|
|
233
|
+
"SELECT MAX(seq_num) as max_seq FROM sessions WHERE project_id = ?",
|
|
234
|
+
(project_id,),
|
|
235
|
+
)
|
|
227
236
|
next_seq_num = ((max_seq_row["max_seq"] if max_seq_row else None) or 0) + 1
|
|
228
237
|
|
|
229
238
|
self.db.execute(
|
|
@@ -232,9 +241,9 @@ class LocalSessionManager:
|
|
|
232
241
|
id, external_id, machine_id, source, project_id, title,
|
|
233
242
|
jsonl_path, git_branch, parent_session_id,
|
|
234
243
|
agent_depth, spawned_by_agent_id, terminal_context,
|
|
235
|
-
status, created_at, updated_at, seq_num
|
|
244
|
+
status, created_at, updated_at, seq_num, had_edits
|
|
236
245
|
)
|
|
237
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?,
|
|
246
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?, ?, 0)
|
|
238
247
|
""",
|
|
239
248
|
(
|
|
240
249
|
session_id,
|
|
@@ -277,18 +286,20 @@ class LocalSessionManager:
|
|
|
277
286
|
row = self.db.fetchone("SELECT * FROM sessions WHERE id = ?", (session_id,))
|
|
278
287
|
return Session.from_row(row) if row else None
|
|
279
288
|
|
|
280
|
-
def resolve_session_reference(self, ref: str) -> str:
|
|
289
|
+
def resolve_session_reference(self, ref: str, project_id: str | None = None) -> str:
|
|
281
290
|
"""
|
|
282
291
|
Resolve a session reference to a UUID.
|
|
283
292
|
|
|
284
293
|
Supports:
|
|
285
|
-
- #N:
|
|
294
|
+
- #N: Project-scoped Sequence Number (e.g., #1) - requires project_id
|
|
286
295
|
- N: Integer string treated as #N (e.g., "1")
|
|
287
296
|
- UUID: Full UUID
|
|
288
297
|
- Prefix: UUID prefix (must be unambiguous)
|
|
289
298
|
|
|
290
299
|
Args:
|
|
291
300
|
ref: Session reference string
|
|
301
|
+
project_id: Project ID for project-scoped #N lookup.
|
|
302
|
+
If not provided, falls back to global lookup for backwards compat.
|
|
292
303
|
|
|
293
304
|
Returns:
|
|
294
305
|
Resolved Session UUID
|
|
@@ -306,7 +317,15 @@ class LocalSessionManager:
|
|
|
306
317
|
|
|
307
318
|
if seq_num_ref.isdigit():
|
|
308
319
|
seq_num = int(seq_num_ref)
|
|
309
|
-
|
|
320
|
+
if project_id:
|
|
321
|
+
# Project-scoped lookup
|
|
322
|
+
row = self.db.fetchone(
|
|
323
|
+
"SELECT id FROM sessions WHERE project_id = ? AND seq_num = ?",
|
|
324
|
+
(project_id, seq_num),
|
|
325
|
+
)
|
|
326
|
+
else:
|
|
327
|
+
# Fallback to global lookup for backwards compat
|
|
328
|
+
row = self.db.fetchone("SELECT id FROM sessions WHERE seq_num = ?", (seq_num,))
|
|
310
329
|
if not row:
|
|
311
330
|
raise ValueError(f"Session #{seq_num} not found")
|
|
312
331
|
return str(row["id"])
|
|
@@ -424,6 +443,15 @@ class LocalSessionManager:
|
|
|
424
443
|
)
|
|
425
444
|
return self.get(session_id)
|
|
426
445
|
|
|
446
|
+
def mark_had_edits(self, session_id: str) -> Session | None:
|
|
447
|
+
"""Mark session as having edits."""
|
|
448
|
+
now = datetime.now(UTC).isoformat()
|
|
449
|
+
self.db.execute(
|
|
450
|
+
"UPDATE sessions SET had_edits = 1, updated_at = ? WHERE id = ?",
|
|
451
|
+
(now, session_id),
|
|
452
|
+
)
|
|
453
|
+
return self.get(session_id)
|
|
454
|
+
|
|
427
455
|
def update_title(self, session_id: str, title: str) -> Session | None:
|
|
428
456
|
"""Update session title."""
|
|
429
457
|
now = datetime.now(UTC).isoformat()
|
|
@@ -433,6 +461,16 @@ class LocalSessionManager:
|
|
|
433
461
|
)
|
|
434
462
|
return self.get(session_id)
|
|
435
463
|
|
|
464
|
+
def update_model(self, session_id: str, model: str) -> Session | None:
|
|
465
|
+
"""Update session model (LLM model used)."""
|
|
466
|
+
now = datetime.now(UTC).isoformat()
|
|
467
|
+
with self.db.transaction():
|
|
468
|
+
self.db.execute(
|
|
469
|
+
"UPDATE sessions SET model = ?, updated_at = ? WHERE id = ?",
|
|
470
|
+
(model, now, session_id),
|
|
471
|
+
)
|
|
472
|
+
return self.get(session_id)
|
|
473
|
+
|
|
436
474
|
def update_summary(
|
|
437
475
|
self,
|
|
438
476
|
session_id: str,
|
|
@@ -773,6 +811,77 @@ class LocalSessionManager:
|
|
|
773
811
|
logger.error(f"Failed to update session usage {session_id}: {e}")
|
|
774
812
|
return False
|
|
775
813
|
|
|
814
|
+
def add_cost(self, session_id: str, cost_usd: float) -> bool:
|
|
815
|
+
"""
|
|
816
|
+
Add cost to the session's usage_total_cost_usd.
|
|
817
|
+
|
|
818
|
+
This is used for internal agent runs that track cost via CostInfo.
|
|
819
|
+
Unlike update_usage which overwrites, this method adds to the existing cost.
|
|
820
|
+
|
|
821
|
+
Args:
|
|
822
|
+
session_id: Session ID to update.
|
|
823
|
+
cost_usd: Cost in USD to add.
|
|
824
|
+
|
|
825
|
+
Returns:
|
|
826
|
+
True if update succeeded, False otherwise.
|
|
827
|
+
"""
|
|
828
|
+
if cost_usd <= 0:
|
|
829
|
+
return True # Nothing to add
|
|
830
|
+
|
|
831
|
+
query = """
|
|
832
|
+
UPDATE sessions
|
|
833
|
+
SET
|
|
834
|
+
usage_total_cost_usd = COALESCE(usage_total_cost_usd, 0) + ?,
|
|
835
|
+
updated_at = datetime('now')
|
|
836
|
+
WHERE id = ?
|
|
837
|
+
"""
|
|
838
|
+
try:
|
|
839
|
+
with self.db.transaction():
|
|
840
|
+
cursor = self.db.execute(query, (cost_usd, session_id))
|
|
841
|
+
return cursor.rowcount > 0
|
|
842
|
+
except Exception as e:
|
|
843
|
+
logger.error(f"Failed to add cost to session {session_id}: {e}")
|
|
844
|
+
return False
|
|
845
|
+
|
|
846
|
+
def get_sessions_since(
|
|
847
|
+
self, since: datetime, project_id: str | None = None
|
|
848
|
+
) -> builtins.list[Session]:
|
|
849
|
+
"""
|
|
850
|
+
Get sessions created since a given timestamp.
|
|
851
|
+
|
|
852
|
+
Used for aggregating usage over a time period (e.g., daily budget tracking).
|
|
853
|
+
|
|
854
|
+
Args:
|
|
855
|
+
since: Datetime to query from (sessions created after this time)
|
|
856
|
+
project_id: Optional project ID to filter by
|
|
857
|
+
|
|
858
|
+
Returns:
|
|
859
|
+
List of sessions created since the given timestamp
|
|
860
|
+
"""
|
|
861
|
+
since_str = since.isoformat()
|
|
862
|
+
|
|
863
|
+
if project_id:
|
|
864
|
+
rows = self.db.fetchall(
|
|
865
|
+
"""
|
|
866
|
+
SELECT * FROM sessions
|
|
867
|
+
WHERE created_at >= ?
|
|
868
|
+
AND project_id = ?
|
|
869
|
+
ORDER BY created_at DESC
|
|
870
|
+
""",
|
|
871
|
+
(since_str, project_id),
|
|
872
|
+
)
|
|
873
|
+
else:
|
|
874
|
+
rows = self.db.fetchall(
|
|
875
|
+
"""
|
|
876
|
+
SELECT * FROM sessions
|
|
877
|
+
WHERE created_at >= ?
|
|
878
|
+
ORDER BY created_at DESC
|
|
879
|
+
""",
|
|
880
|
+
(since_str,),
|
|
881
|
+
)
|
|
882
|
+
|
|
883
|
+
return [Session.from_row(row) for row in rows]
|
|
884
|
+
|
|
776
885
|
def update_terminal_pickup_metadata(
|
|
777
886
|
self,
|
|
778
887
|
session_id: str,
|