devcouncil 0.1.1 → 0.3.0
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/README.md +201 -6
- package/package.json +9 -2
- package/pyproject.toml +34 -2
- package/src/devcouncil/app/config.py +348 -12
- package/src/devcouncil/app/orchestrator.py +10 -6
- package/src/devcouncil/app/state_machine.py +4 -0
- package/src/devcouncil/artifacts/graph.py +32 -5
- package/src/devcouncil/assets/__init__.py +1 -0
- package/src/devcouncil/assets/devcouncil-logo.svg +60 -0
- package/src/devcouncil/assets/devcouncil_logo_premium.png +0 -0
- package/src/devcouncil/cli/commands/agents.py +292 -0
- package/src/devcouncil/cli/commands/artifacts.py +6 -3
- package/src/devcouncil/cli/commands/check.py +220 -0
- package/src/devcouncil/cli/commands/config.py +43 -4
- package/src/devcouncil/cli/commands/cost.py +57 -0
- package/src/devcouncil/cli/commands/dashboard.py +6 -1
- package/src/devcouncil/cli/commands/design.py +186 -0
- package/src/devcouncil/cli/commands/doctor.py +379 -22
- package/src/devcouncil/cli/commands/evidence.py +48 -0
- package/src/devcouncil/cli/commands/go.py +532 -33
- package/src/devcouncil/cli/commands/handoff.py +69 -0
- package/src/devcouncil/cli/commands/hook.py +296 -15
- package/src/devcouncil/cli/commands/init.py +161 -20
- package/src/devcouncil/cli/commands/integrate.py +1371 -124
- package/src/devcouncil/cli/commands/logs.py +106 -0
- package/src/devcouncil/cli/commands/map.py +80 -10
- package/src/devcouncil/cli/commands/okf.py +245 -0
- package/src/devcouncil/cli/commands/plan.py +256 -55
- package/src/devcouncil/cli/commands/prompt.py +18 -7
- package/src/devcouncil/cli/commands/repair.py +50 -24
- package/src/devcouncil/cli/commands/report.py +8 -0
- package/src/devcouncil/cli/commands/reset_demo_state.py +4 -2
- package/src/devcouncil/cli/commands/rollback.py +27 -28
- package/src/devcouncil/cli/commands/run.py +195 -54
- package/src/devcouncil/cli/commands/runs.py +223 -0
- package/src/devcouncil/cli/commands/scaffold.py +32 -0
- package/src/devcouncil/cli/commands/semantic.py +47 -0
- package/src/devcouncil/cli/commands/setup.py +145 -6
- package/src/devcouncil/cli/commands/shell.py +73 -0
- package/src/devcouncil/cli/commands/skills.py +267 -0
- package/src/devcouncil/cli/commands/status.py +30 -15
- package/src/devcouncil/cli/commands/trace.py +47 -3
- package/src/devcouncil/cli/commands/verify.py +144 -3
- package/src/devcouncil/cli/commands/watch.py +32 -12
- package/src/devcouncil/cli/commands/watch_fs.py +40 -0
- package/src/devcouncil/cli/main.py +91 -7
- package/src/devcouncil/domain/evidence.py +29 -2
- package/src/devcouncil/domain/gap.py +27 -1
- package/src/devcouncil/domain/task.py +31 -2
- package/src/devcouncil/execution/checkpoints.py +256 -0
- package/src/devcouncil/execution/context_builder.py +1 -1
- package/src/devcouncil/execution/fs_watcher.py +205 -0
- package/src/devcouncil/execution/handoff.py +102 -0
- package/src/devcouncil/execution/hook_policy.py +162 -74
- package/src/devcouncil/execution/patch.py +65 -10
- package/src/devcouncil/execution/permissions.py +24 -24
- package/src/devcouncil/execution/policy_engine.py +350 -0
- package/src/devcouncil/execution/prompt_builder.py +751 -23
- package/src/devcouncil/execution/shell_session.py +231 -0
- package/src/devcouncil/execution/task_runner.py +24 -9
- package/src/devcouncil/executors/agent_registry.py +596 -0
- package/src/devcouncil/executors/coding_cli.py +791 -39
- package/src/devcouncil/executors/mini_swe.py +6 -0
- package/src/devcouncil/executors/native/agent.py +135 -19
- package/src/devcouncil/executors/openhands.py +6 -0
- package/src/devcouncil/gating/checks/clean_git.py +3 -1
- package/src/devcouncil/gating/checks/secret_scan_check.py +47 -21
- package/src/devcouncil/gating/policy.py +190 -11
- package/src/devcouncil/hardware.py +184 -0
- package/src/devcouncil/indexing/ast_matcher.py +17 -7
- package/src/devcouncil/indexing/lsp.py +45 -4
- package/src/devcouncil/indexing/repo_mapper.py +1284 -15
- package/src/devcouncil/indexing/semantic_index.py +221 -0
- package/src/devcouncil/integrations/actions.py +166 -0
- package/src/devcouncil/integrations/check.py +426 -0
- package/src/devcouncil/integrations/claude_assets.py +444 -0
- package/src/devcouncil/integrations/code_review_graph.py +13 -2
- package/src/devcouncil/integrations/github_intent.py +149 -0
- package/src/devcouncil/integrations/gitnexus.py +45 -2
- package/src/devcouncil/integrations/mcp/server.py +1944 -32
- package/src/devcouncil/integrations/opencode_devcouncil_plugin.mjs +24 -0
- package/src/devcouncil/integrations/pr_comments.py +9 -0
- package/src/devcouncil/knowledge/__init__.py +23 -0
- package/src/devcouncil/knowledge/design.py +374 -0
- package/src/devcouncil/knowledge/design_conformance.py +317 -0
- package/src/devcouncil/knowledge/fetch.py +223 -0
- package/src/devcouncil/knowledge/frontmatter.py +51 -0
- package/src/devcouncil/knowledge/okf.py +202 -0
- package/src/devcouncil/knowledge/skill_bridge.py +96 -0
- package/src/devcouncil/knowledge/sources.py +239 -0
- package/src/devcouncil/live/cards.py +181 -25
- package/src/devcouncil/live/repair_prompt.py +29 -6
- package/src/devcouncil/live/reviewer.py +72 -13
- package/src/devcouncil/live/signals.py +2 -2
- package/src/devcouncil/live/summary.py +18 -8
- package/src/devcouncil/live/transcripts.py +47 -11
- package/src/devcouncil/llm/cache.py +20 -8
- package/src/devcouncil/llm/model_defaults.yaml +44 -0
- package/src/devcouncil/llm/provider.py +617 -49
- package/src/devcouncil/llm/router.py +337 -53
- package/src/devcouncil/optimization/__init__.py +1 -0
- package/src/devcouncil/optimization/gepa_agent.py +318 -0
- package/src/devcouncil/optimization/skillopt.py +673 -0
- package/src/devcouncil/planning/arbiter_service.py +10 -2
- package/src/devcouncil/planning/correction_manifest.py +346 -0
- package/src/devcouncil/planning/critique_service.py +16 -4
- package/src/devcouncil/planning/plan_service.py +86 -6
- package/src/devcouncil/planning/prompt_enhancer_service.py +206 -1
- package/src/devcouncil/planning/repair_service.py +8 -2
- package/src/devcouncil/planning/spec_service.py +37 -3
- package/src/devcouncil/repo/ci_scaffold.py +165 -0
- package/src/devcouncil/repo/gitignore.py +123 -0
- package/src/devcouncil/repo/sca.py +384 -0
- package/src/devcouncil/reporting/json_report.py +22 -1
- package/src/devcouncil/reporting/markdown_report.py +29 -1
- package/src/devcouncil/reporting/okf_bundle_writer.py +364 -0
- package/src/devcouncil/reporting/okf_html.py +323 -0
- package/src/devcouncil/reporting/report_builder.py +18 -1
- package/src/devcouncil/skills/__init__.py +19 -0
- package/src/devcouncil/skills/library/README.md +46 -0
- package/src/devcouncil/skills/library/ai-training.md +50 -0
- package/src/devcouncil/skills/library/android.md +50 -0
- package/src/devcouncil/skills/library/backend.md +52 -0
- package/src/devcouncil/skills/library/core-engineering.md +95 -0
- package/src/devcouncil/skills/library/data-engineering.md +47 -0
- package/src/devcouncil/skills/library/desktop.md +46 -0
- package/src/devcouncil/skills/library/devops.md +48 -0
- package/src/devcouncil/skills/library/game-dev.md +46 -0
- package/src/devcouncil/skills/library/ios.md +48 -0
- package/src/devcouncil/skills/library/mobile-cross-platform.md +46 -0
- package/src/devcouncil/skills/library/security.md +48 -0
- package/src/devcouncil/skills/library/systems.md +48 -0
- package/src/devcouncil/skills/library/web.md +47 -0
- package/src/devcouncil/skills/library/windows.md +47 -0
- package/src/devcouncil/skills/registry.py +408 -0
- package/src/devcouncil/storage/db.py +140 -3
- package/src/devcouncil/storage/models.py +125 -0
- package/src/devcouncil/storage/native.py +559 -0
- package/src/devcouncil/storage/repositories.py +157 -78
- package/src/devcouncil/telemetry/cost.py +123 -17
- package/src/devcouncil/telemetry/logging_setup.py +244 -0
- package/src/devcouncil/telemetry/model_pricing.yaml +48 -0
- package/src/devcouncil/telemetry/pricing.py +28 -0
- package/src/devcouncil/telemetry/stages.py +141 -0
- package/src/devcouncil/telemetry/traces.py +62 -7
- package/src/devcouncil/telemetry/tracker.py +24 -10
- package/src/devcouncil/ui/dashboard.py +393 -28
- package/src/devcouncil/utils/redaction.py +9 -3
- package/src/devcouncil/utils/subprocess_env.py +69 -0
- package/src/devcouncil/verification/acceptance_compiler.py +253 -0
- package/src/devcouncil/verification/ad_hoc_check.py +135 -0
- package/src/devcouncil/verification/diff_coverage.py +353 -0
- package/src/devcouncil/verification/implementation_reviewer.py +11 -2
- package/src/devcouncil/verification/next_actions.py +189 -0
- package/src/devcouncil/verification/sandbox.py +181 -0
- package/src/devcouncil/verification/test_resolver.py +91 -0
- package/src/devcouncil/verification/verifier.py +1549 -143
- package/uv.lock +205 -64
- package/src/devcouncil/indexing/symbol_index.py +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
1
2
|
from contextlib import contextmanager
|
|
3
|
+
from datetime import datetime, timezone
|
|
2
4
|
|
|
3
5
|
from sqlmodel import SQLModel, create_engine, Session
|
|
6
|
+
from sqlalchemy import inspect, text
|
|
4
7
|
from sqlalchemy.exc import OperationalError
|
|
5
8
|
from pathlib import Path
|
|
6
9
|
from typing import Optional
|
|
@@ -8,7 +11,41 @@ from typing import Optional
|
|
|
8
11
|
from devcouncil.storage.models import SchemaVersionModel
|
|
9
12
|
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
# v3: per-task indexes on the task/audit tables (task_id, lease status).
|
|
15
|
+
# v4: machine-routable gap columns (file, line, suggested_command,
|
|
16
|
+
# acceptance_criterion_id) so the repair contract survives a reload.
|
|
17
|
+
# v5: partial unique index enforcing one ACTIVE lease per task (single-writer).
|
|
18
|
+
# v6: gap column expected_verification_method (repair loop tells an executor-remediable
|
|
19
|
+
# "incomplete" from a manual/llm one across a reload).
|
|
20
|
+
SCHEMA_VERSION = 6
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Module-level caches keyed by *resolved* paths so distinct project roots stay
|
|
24
|
+
# independent (important for test isolation, where every test uses a fresh
|
|
25
|
+
# tmp_path). `_db_instances` returns the same Database (and its single engine)
|
|
26
|
+
# for a given project root instead of rebuilding the engine + re-running the
|
|
27
|
+
# schema check on every get_db() call. `_dedup_done` records db paths whose
|
|
28
|
+
# active-lease dedup migration has already run this process, so the one-time
|
|
29
|
+
# table scan does not repeat on subsequent opens of the same database.
|
|
30
|
+
_db_instances: dict[Path, "Database"] = {}
|
|
31
|
+
_dedup_done: set[Path] = set()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def reset_db_cache() -> None:
|
|
35
|
+
"""Drop all cached Database instances and per-path guards.
|
|
36
|
+
|
|
37
|
+
Disposes pooled engine connections so the underlying SQLite files can be
|
|
38
|
+
safely removed/recreated. Intended for tests (or long-lived processes) that
|
|
39
|
+
rebuild a project's .devcouncil database under a path already opened this
|
|
40
|
+
process; without this a cached engine could point at a stale/deleted file.
|
|
41
|
+
"""
|
|
42
|
+
for db in _db_instances.values():
|
|
43
|
+
try:
|
|
44
|
+
db.engine.dispose()
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
_db_instances.clear()
|
|
48
|
+
_dedup_done.clear()
|
|
12
49
|
|
|
13
50
|
|
|
14
51
|
class Database:
|
|
@@ -28,11 +65,17 @@ class Database:
|
|
|
28
65
|
session.add(SchemaVersionModel(id="singleton", version=SCHEMA_VERSION))
|
|
29
66
|
session.commit()
|
|
30
67
|
return
|
|
31
|
-
if current.version
|
|
68
|
+
if current.version > SCHEMA_VERSION:
|
|
32
69
|
raise RuntimeError(
|
|
33
70
|
f"Unsupported DevCouncil schema version {current.version}; "
|
|
34
71
|
f"expected {SCHEMA_VERSION}."
|
|
35
72
|
)
|
|
73
|
+
if current.version < SCHEMA_VERSION:
|
|
74
|
+
self._create_tables()
|
|
75
|
+
current.version = SCHEMA_VERSION
|
|
76
|
+
session.add(current)
|
|
77
|
+
session.commit()
|
|
78
|
+
return
|
|
36
79
|
|
|
37
80
|
def _create_tables(self):
|
|
38
81
|
try:
|
|
@@ -40,6 +83,84 @@ class Database:
|
|
|
40
83
|
except OperationalError as exc:
|
|
41
84
|
if "already exists" not in str(exc):
|
|
42
85
|
raise
|
|
86
|
+
self._create_missing_columns()
|
|
87
|
+
self._dedup_active_leases()
|
|
88
|
+
self._create_missing_indexes()
|
|
89
|
+
|
|
90
|
+
def _dedup_active_leases(self):
|
|
91
|
+
# The partial unique index (ux_task_leases_active) can only be created if no task
|
|
92
|
+
# already has two ACTIVE leases. Older databases predate the constraint, so
|
|
93
|
+
# collapse any duplicates first — keep the newest active lease per task, mark the
|
|
94
|
+
# rest stale — making index creation succeed and restoring single-writer state.
|
|
95
|
+
#
|
|
96
|
+
# This only needs to run once per database per process: after the first pass the
|
|
97
|
+
# partial unique index (created immediately after, in _create_missing_indexes)
|
|
98
|
+
# prevents any new duplicate active leases, so re-scanning on every open is wasted
|
|
99
|
+
# work. Guard on the resolved path so distinct databases remain independent.
|
|
100
|
+
key = self.db_path.resolve()
|
|
101
|
+
if key in _dedup_done:
|
|
102
|
+
return
|
|
103
|
+
inspector = inspect(self.engine)
|
|
104
|
+
if "task_leases" not in inspector.get_table_names():
|
|
105
|
+
# Table not materialized yet; don't record as done so a later open retries.
|
|
106
|
+
return
|
|
107
|
+
with self.engine.begin() as conn:
|
|
108
|
+
rows = conn.execute(
|
|
109
|
+
text("SELECT id, task_id, created_at FROM task_leases WHERE status = 'active'")
|
|
110
|
+
).fetchall()
|
|
111
|
+
by_task = defaultdict(list)
|
|
112
|
+
for row in rows:
|
|
113
|
+
by_task[row.task_id].append(((row.created_at or ""), row.id))
|
|
114
|
+
stale_ids = []
|
|
115
|
+
for items in by_task.values():
|
|
116
|
+
if len(items) <= 1:
|
|
117
|
+
continue
|
|
118
|
+
items.sort() # ascending by (created_at, id); keep the last = newest
|
|
119
|
+
stale_ids.extend(item[1] for item in items[:-1])
|
|
120
|
+
if stale_ids:
|
|
121
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
122
|
+
for lease_id in stale_ids:
|
|
123
|
+
conn.execute(
|
|
124
|
+
text("UPDATE task_leases SET status = 'stale', released_at = :ts WHERE id = :id"),
|
|
125
|
+
{"ts": now, "id": lease_id},
|
|
126
|
+
)
|
|
127
|
+
_dedup_done.add(key)
|
|
128
|
+
|
|
129
|
+
def _create_missing_columns(self):
|
|
130
|
+
# create_all never alters an existing table, so columns added to a model
|
|
131
|
+
# later (e.g. the v4 gap routing columns) are missing on databases created by
|
|
132
|
+
# an older version — and a SELECT of the model would then fail. Add any
|
|
133
|
+
# missing column as a nullable ADD COLUMN (the only shape SQLite can add in
|
|
134
|
+
# place without a table rewrite); non-nullable additions are intentionally
|
|
135
|
+
# skipped because existing rows could not satisfy them.
|
|
136
|
+
inspector = inspect(self.engine)
|
|
137
|
+
existing_tables = set(inspector.get_table_names())
|
|
138
|
+
for table in SQLModel.metadata.sorted_tables:
|
|
139
|
+
if table.name not in existing_tables:
|
|
140
|
+
continue
|
|
141
|
+
existing_cols = {col["name"] for col in inspector.get_columns(table.name)}
|
|
142
|
+
for column in table.columns:
|
|
143
|
+
if column.name in existing_cols or not column.nullable:
|
|
144
|
+
continue
|
|
145
|
+
ddl_type = column.type.compile(self.engine.dialect)
|
|
146
|
+
stmt = text(f'ALTER TABLE "{table.name}" ADD COLUMN "{column.name}" {ddl_type}')
|
|
147
|
+
try:
|
|
148
|
+
with self.engine.begin() as conn:
|
|
149
|
+
conn.execute(stmt)
|
|
150
|
+
except OperationalError as exc:
|
|
151
|
+
if "duplicate column name" not in str(exc).lower():
|
|
152
|
+
raise
|
|
153
|
+
|
|
154
|
+
def _create_missing_indexes(self):
|
|
155
|
+
# create_all skips tables that already exist, so indexes added to the
|
|
156
|
+
# model definitions later never materialize on existing databases.
|
|
157
|
+
for table in SQLModel.metadata.sorted_tables:
|
|
158
|
+
for index in table.indexes:
|
|
159
|
+
try:
|
|
160
|
+
index.create(self.engine, checkfirst=True)
|
|
161
|
+
except OperationalError as exc:
|
|
162
|
+
if "already exists" not in str(exc):
|
|
163
|
+
raise
|
|
43
164
|
|
|
44
165
|
@contextmanager
|
|
45
166
|
def get_session(self):
|
|
@@ -58,9 +179,25 @@ class Database:
|
|
|
58
179
|
def get_db(project_root: Path = Path(".")) -> Optional[Database]:
|
|
59
180
|
dev_dir = project_root / ".devcouncil"
|
|
60
181
|
if not dev_dir.exists():
|
|
182
|
+
# Checked before the cache so a not-yet-initialized (or removed) project
|
|
183
|
+
# never yields a stale cached Database.
|
|
61
184
|
return None
|
|
62
|
-
|
|
185
|
+
|
|
186
|
+
key = project_root.resolve()
|
|
63
187
|
db_path = dev_dir / "state.sqlite"
|
|
188
|
+
cached = _db_instances.get(key)
|
|
189
|
+
# Only reuse the cached instance while its underlying file still exists. If the
|
|
190
|
+
# .devcouncil dir was wiped and recreated under the same path within one process,
|
|
191
|
+
# the cached engine points at a deleted file — dispose its pool and rebuild fresh.
|
|
192
|
+
if cached is not None:
|
|
193
|
+
if db_path.exists():
|
|
194
|
+
return cached
|
|
195
|
+
try:
|
|
196
|
+
cached.engine.dispose()
|
|
197
|
+
except Exception:
|
|
198
|
+
pass
|
|
199
|
+
|
|
64
200
|
db = Database(db_path)
|
|
65
201
|
db.ensure_schema_version()
|
|
202
|
+
_db_instances[key] = db
|
|
66
203
|
return db
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from sqlmodel import SQLModel, Field
|
|
2
|
+
from sqlalchemy import Index, text
|
|
2
3
|
from typing import Optional
|
|
3
4
|
|
|
4
5
|
|
|
@@ -61,6 +62,17 @@ class GapModel(SQLModel, table=True):
|
|
|
61
62
|
evidence_json: str = Field(default="[]")
|
|
62
63
|
recommended_fix: str
|
|
63
64
|
blocking: bool
|
|
65
|
+
# Machine-routable repair hints. Persisted (v4) so the typed next-actions
|
|
66
|
+
# contract survives a reload — a reconnecting/crashed agent can read outstanding
|
|
67
|
+
# gaps without the heuristic reconstruction the loader used to fall back to.
|
|
68
|
+
file: Optional[str] = None
|
|
69
|
+
line: Optional[int] = None
|
|
70
|
+
suggested_command: Optional[str] = None
|
|
71
|
+
acceptance_criterion_id: Optional[str] = None
|
|
72
|
+
# Verification method the criterion expects (unit_test/manual/llm_review/...). Persisted
|
|
73
|
+
# so the repair loop can tell an executor-remediable "incomplete" (an automatable check
|
|
74
|
+
# that did not run) from one a human must close (manual/llm_review) after a reload.
|
|
75
|
+
expected_verification_method: Optional[str] = None
|
|
64
76
|
|
|
65
77
|
class CritiqueFindingModel(SQLModel, table=True):
|
|
66
78
|
__tablename__ = "critique_findings"
|
|
@@ -81,3 +93,116 @@ class ProjectStateModel(SQLModel, table=True):
|
|
|
81
93
|
id: str = Field(primary_key=True, default="singleton")
|
|
82
94
|
current_phase: str
|
|
83
95
|
history_json: str = Field(default="[]")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class TaskLeaseModel(SQLModel, table=True):
|
|
99
|
+
__tablename__ = "task_leases"
|
|
100
|
+
# Enforce the single-writer guarantee at the DB level: at most one ACTIVE lease per
|
|
101
|
+
# task. A partial unique index turns a concurrent double-checkout race into an
|
|
102
|
+
# IntegrityError (surfaced as lease_conflict) instead of two live leases.
|
|
103
|
+
__table_args__ = (
|
|
104
|
+
Index(
|
|
105
|
+
"ux_task_leases_active",
|
|
106
|
+
"task_id",
|
|
107
|
+
unique=True,
|
|
108
|
+
sqlite_where=text("status = 'active'"),
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
id: str = Field(primary_key=True)
|
|
112
|
+
task_id: str = Field(index=True)
|
|
113
|
+
owner: str
|
|
114
|
+
agent: Optional[str] = None
|
|
115
|
+
client_id: Optional[str] = None
|
|
116
|
+
run_id: Optional[str] = None
|
|
117
|
+
branch: Optional[str] = None
|
|
118
|
+
lease_token: str
|
|
119
|
+
status: str = Field(default="active", index=True)
|
|
120
|
+
created_at: str
|
|
121
|
+
expires_at: Optional[str] = None
|
|
122
|
+
released_at: Optional[str] = None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class ShellSessionModel(SQLModel, table=True):
|
|
126
|
+
__tablename__ = "shell_sessions"
|
|
127
|
+
id: str = Field(primary_key=True)
|
|
128
|
+
task_id: str = Field(index=True)
|
|
129
|
+
lease_id: Optional[str] = None
|
|
130
|
+
shell: str
|
|
131
|
+
cwd: str
|
|
132
|
+
status: str
|
|
133
|
+
started_at: str
|
|
134
|
+
ended_at: Optional[str] = None
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class ShellCommandEventModel(SQLModel, table=True):
|
|
138
|
+
__tablename__ = "shell_command_events"
|
|
139
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
140
|
+
task_id: str = Field(index=True)
|
|
141
|
+
session_id: Optional[str] = None
|
|
142
|
+
command: str
|
|
143
|
+
status: str
|
|
144
|
+
exit_code: Optional[int] = None
|
|
145
|
+
reason: str = ""
|
|
146
|
+
stdout_path: str = ""
|
|
147
|
+
stderr_path: str = ""
|
|
148
|
+
created_at: str
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class FileChangeEventModel(SQLModel, table=True):
|
|
152
|
+
__tablename__ = "file_change_events"
|
|
153
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
154
|
+
task_id: Optional[str] = Field(default=None, index=True)
|
|
155
|
+
lease_id: Optional[str] = None
|
|
156
|
+
session_id: Optional[str] = None
|
|
157
|
+
path: str
|
|
158
|
+
operation: str
|
|
159
|
+
allowed: bool
|
|
160
|
+
reason: str = ""
|
|
161
|
+
created_at: str
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class SemanticDiffModel(SQLModel, table=True):
|
|
165
|
+
__tablename__ = "semantic_diffs"
|
|
166
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
167
|
+
task_id: str = Field(index=True)
|
|
168
|
+
before_snapshot_path: str
|
|
169
|
+
after_snapshot_path: str
|
|
170
|
+
classifications_json: str = "[]"
|
|
171
|
+
summary: str = ""
|
|
172
|
+
created_at: str
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class AgentHandoffModel(SQLModel, table=True):
|
|
176
|
+
__tablename__ = "agent_handoffs"
|
|
177
|
+
id: str = Field(primary_key=True)
|
|
178
|
+
task_id: str = Field(index=True)
|
|
179
|
+
from_agent: str
|
|
180
|
+
to_agent: str
|
|
181
|
+
run_id: str
|
|
182
|
+
manifest_path: str
|
|
183
|
+
status: str
|
|
184
|
+
created_at: str
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class CorrectionManifestModel(SQLModel, table=True):
|
|
188
|
+
__tablename__ = "correction_manifests"
|
|
189
|
+
id: str = Field(primary_key=True)
|
|
190
|
+
task_id: str = Field(index=True)
|
|
191
|
+
run_id: Optional[str] = None
|
|
192
|
+
manifest_path: str
|
|
193
|
+
retry_budget: int = 3
|
|
194
|
+
attempt: int = 0
|
|
195
|
+
status: str
|
|
196
|
+
created_at: str
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class VerificationRunModel(SQLModel, table=True):
|
|
200
|
+
__tablename__ = "verification_runs"
|
|
201
|
+
id: str = Field(primary_key=True)
|
|
202
|
+
task_id: str = Field(index=True)
|
|
203
|
+
sandbox: str
|
|
204
|
+
environment_json: str = "{}"
|
|
205
|
+
commands_json: str = "[]"
|
|
206
|
+
status: str
|
|
207
|
+
started_at: str
|
|
208
|
+
finished_at: Optional[str] = None
|