agent-resurrect-btw 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Entire Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-resurrect-btw
3
+ Version: 0.1.0
4
+ Summary: Agent Resurrect SDK
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: typer>=0.9.0
9
+ Requires-Dist: rich>=13.0.0
10
+ Requires-Dist: requests>=2.31.0
11
+ Dynamic: license-file
12
+
13
+ # Agent Resurrect SDK
14
+
15
+ Agent Resurrect is a real-time loop-breaker and telemetry co-pilot for agentic workflows. It is designed to sit alongside a Databricks-backed failure trap table, observe agent activity, and provide the control surface needed to inspect, diagnose, and recover from runaway loops.
16
+
17
+ This repository currently contains the foundational SDK scaffold only. The business logic, Databricks integration, and runtime loop-breaking behavior will be added incrementally on top of this structure.
18
+
19
+ ## Project Layout
20
+
21
+ ```text
22
+ resurrect/
23
+ __init__.py
24
+ cli.py
25
+ config.py
26
+ core/
27
+ __init__.py
28
+ entire_bridge.py
29
+ databricks_client.py
30
+ ui/
31
+ __init__.py
32
+ console.py
33
+ tests/
34
+ __init__.py
35
+ test_config.py
36
+ test_connectivity.py
37
+ ```
38
+
39
+ ## Planned CLI
40
+
41
+ The `resurrect` command will eventually expose these entry points:
42
+
43
+ - `resurrect init`
44
+ - `resurrect doctor`
45
+ - `resurrect run`
46
+
47
+ Those commands are not implemented yet. The current CLI module only provides a minimal Typer application stub so the package can be installed and extended safely.
48
+
49
+ ## Environment Variables
50
+
51
+ Copy `.env.example` to `.env` and populate the Databricks connection settings:
52
+
53
+ - `DATABRICKS_HOST`
54
+ - `DATABRICKS_TOKEN`
55
+ - `DATABRICKS_WAREHOUSE_ID`
56
+ - `DELTA_TABLE_NAME`
57
+
58
+ ## Build Metadata
59
+
60
+ - Package name: `agent-resurrect`
61
+ - Version: `0.1.0`
62
+ - Entry point: `resurrect`
63
+
@@ -0,0 +1,51 @@
1
+ # Agent Resurrect SDK
2
+
3
+ Agent Resurrect is a real-time loop-breaker and telemetry co-pilot for agentic workflows. It is designed to sit alongside a Databricks-backed failure trap table, observe agent activity, and provide the control surface needed to inspect, diagnose, and recover from runaway loops.
4
+
5
+ This repository currently contains the foundational SDK scaffold only. The business logic, Databricks integration, and runtime loop-breaking behavior will be added incrementally on top of this structure.
6
+
7
+ ## Project Layout
8
+
9
+ ```text
10
+ resurrect/
11
+ __init__.py
12
+ cli.py
13
+ config.py
14
+ core/
15
+ __init__.py
16
+ entire_bridge.py
17
+ databricks_client.py
18
+ ui/
19
+ __init__.py
20
+ console.py
21
+ tests/
22
+ __init__.py
23
+ test_config.py
24
+ test_connectivity.py
25
+ ```
26
+
27
+ ## Planned CLI
28
+
29
+ The `resurrect` command will eventually expose these entry points:
30
+
31
+ - `resurrect init`
32
+ - `resurrect doctor`
33
+ - `resurrect run`
34
+
35
+ Those commands are not implemented yet. The current CLI module only provides a minimal Typer application stub so the package can be installed and extended safely.
36
+
37
+ ## Environment Variables
38
+
39
+ Copy `.env.example` to `.env` and populate the Databricks connection settings:
40
+
41
+ - `DATABRICKS_HOST`
42
+ - `DATABRICKS_TOKEN`
43
+ - `DATABRICKS_WAREHOUSE_ID`
44
+ - `DELTA_TABLE_NAME`
45
+
46
+ ## Build Metadata
47
+
48
+ - Package name: `agent-resurrect`
49
+ - Version: `0.1.0`
50
+ - Entry point: `resurrect`
51
+
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-resurrect-btw
3
+ Version: 0.1.0
4
+ Summary: Agent Resurrect SDK
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: typer>=0.9.0
9
+ Requires-Dist: rich>=13.0.0
10
+ Requires-Dist: requests>=2.31.0
11
+ Dynamic: license-file
12
+
13
+ # Agent Resurrect SDK
14
+
15
+ Agent Resurrect is a real-time loop-breaker and telemetry co-pilot for agentic workflows. It is designed to sit alongside a Databricks-backed failure trap table, observe agent activity, and provide the control surface needed to inspect, diagnose, and recover from runaway loops.
16
+
17
+ This repository currently contains the foundational SDK scaffold only. The business logic, Databricks integration, and runtime loop-breaking behavior will be added incrementally on top of this structure.
18
+
19
+ ## Project Layout
20
+
21
+ ```text
22
+ resurrect/
23
+ __init__.py
24
+ cli.py
25
+ config.py
26
+ core/
27
+ __init__.py
28
+ entire_bridge.py
29
+ databricks_client.py
30
+ ui/
31
+ __init__.py
32
+ console.py
33
+ tests/
34
+ __init__.py
35
+ test_config.py
36
+ test_connectivity.py
37
+ ```
38
+
39
+ ## Planned CLI
40
+
41
+ The `resurrect` command will eventually expose these entry points:
42
+
43
+ - `resurrect init`
44
+ - `resurrect doctor`
45
+ - `resurrect run`
46
+
47
+ Those commands are not implemented yet. The current CLI module only provides a minimal Typer application stub so the package can be installed and extended safely.
48
+
49
+ ## Environment Variables
50
+
51
+ Copy `.env.example` to `.env` and populate the Databricks connection settings:
52
+
53
+ - `DATABRICKS_HOST`
54
+ - `DATABRICKS_TOKEN`
55
+ - `DATABRICKS_WAREHOUSE_ID`
56
+ - `DELTA_TABLE_NAME`
57
+
58
+ ## Build Metadata
59
+
60
+ - Package name: `agent-resurrect`
61
+ - Version: `0.1.0`
62
+ - Entry point: `resurrect`
63
+
@@ -0,0 +1,22 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ agent_resurrect_btw.egg-info/PKG-INFO
5
+ agent_resurrect_btw.egg-info/SOURCES.txt
6
+ agent_resurrect_btw.egg-info/dependency_links.txt
7
+ agent_resurrect_btw.egg-info/entry_points.txt
8
+ agent_resurrect_btw.egg-info/requires.txt
9
+ agent_resurrect_btw.egg-info/top_level.txt
10
+ resurrect/__init__.py
11
+ resurrect/cli.py
12
+ resurrect/config.py
13
+ resurrect/handoff.py
14
+ resurrect/parser.py
15
+ resurrect/core/__init__.py
16
+ resurrect/core/databricks_client.py
17
+ resurrect/core/entire_bridge.py
18
+ resurrect/ui/__init__.py
19
+ resurrect/ui/console.py
20
+ tests/test_config.py
21
+ tests/test_connectivity.py
22
+ tests/test_privacy_boundary.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ resurrect = resurrect.cli:app
@@ -0,0 +1,3 @@
1
+ typer>=0.9.0
2
+ rich>=13.0.0
3
+ requests>=2.31.0
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "agent-resurrect-btw"
7
+ version = "0.1.0"
8
+ description = "Agent Resurrect SDK"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "typer>=0.9.0",
13
+ "rich>=13.0.0",
14
+ "requests>=2.31.0",
15
+ ]
16
+
17
+ [project.scripts]
18
+ resurrect = "resurrect.cli:app"
19
+
20
+ [tool.setuptools]
21
+ include-package-data = true
22
+
23
+ [tool.setuptools.packages.find]
24
+ include = ["resurrect*"]
25
+
@@ -0,0 +1,2 @@
1
+ __version__ = "0.1.0"
2
+
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.text import Text
9
+
10
+ from resurrect.config import ResurrectConfig
11
+ from resurrect.core.databricks_client import DatabricksClient
12
+ from resurrect.core.entire_bridge import CommandResult, check_entire_status, setup_entire
13
+ from resurrect.handoff import build_handoff_manifest, write_handoff_manifest
14
+ from resurrect.parser import ParsedTelemetry, parse_telemetry
15
+ from resurrect.ui.console import StatusItem, render_status_board
16
+
17
+
18
+ app = typer.Typer(help="Agent Resurrect command-line interface.")
19
+ console = Console()
20
+
21
+
22
+ @app.callback(invoke_without_command=True)
23
+ def main() -> None:
24
+ """Entry point for the resurrect CLI."""
25
+ return None
26
+
27
+
28
+ @app.command()
29
+ def init(
30
+ agent: str = "codex",
31
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Show debug details."),
32
+ cwd: Path = typer.Argument(Path.cwd(), exists=True, file_okay=False, dir_okay=True, resolve_path=True),
33
+ ) -> None:
34
+ result = setup_entire(agent=agent, cwd=cwd)
35
+ config = ResurrectConfig().save(cwd)
36
+ if verbose or not result.ok:
37
+ _render_debug("entire enable", result, cwd)
38
+ if result.ok:
39
+ typer.echo(f"Initialized Entire hooks and created {config}")
40
+ else:
41
+ raise typer.Exit(code=1)
42
+
43
+
44
+ @app.command()
45
+ def doctor(
46
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Show debug details."),
47
+ cwd: Path = typer.Argument(Path.cwd(), exists=True, file_okay=False, dir_okay=True, resolve_path=True),
48
+ ) -> None:
49
+ config = ResurrectConfig.load(cwd)
50
+ items: list[StatusItem] = []
51
+
52
+ missing = config.missing_fields()
53
+ items.append(StatusItem("Config", not missing, "All required values loaded." if not missing else f"Missing: {', '.join(missing)}"))
54
+
55
+ entire_status = check_entire_status(cwd)
56
+ items.append(StatusItem("Entire", entire_status.ok, entire_status.stderr or entire_status.stdout))
57
+ if verbose or not entire_status.ok:
58
+ _render_debug("entire status", entire_status, cwd)
59
+
60
+ client = DatabricksClient(config.databricks_host, config.databricks_token, config.databricks_warehouse_id)
61
+ ping = client.ping_connection()
62
+ items.append(StatusItem("Databricks ping", ping.ok, ping.error or (f"{ping.latency_ms:.1f} ms" if ping.latency_ms is not None else "")))
63
+
64
+ table = client.verify_table_exists(config.delta_table_name)
65
+ items.append(StatusItem("Delta table", table.ok, table.error or f"{config.delta_table_name} is queryable"))
66
+
67
+ telemetry = parse_telemetry(cwd / "refs" / "entire" / "checkpoints")
68
+ query_result = client.query_failure_traps(telemetry, config.delta_table_name)
69
+ context_label = "[PARTIAL / REDACTED CONTEXT]" if not telemetry.status.is_complete else "[COMPLETE CONTEXT]"
70
+ items.append(StatusItem("Failure traps", query_result.ok, query_result.error or telemetry.error_signature, context_label=context_label))
71
+
72
+ render_status_board(items)
73
+ manifest_dir = cwd / ".resurrect"
74
+ manifest_dir.mkdir(parents=True, exist_ok=True)
75
+ write_handoff_manifest(manifest_dir / "handoff_manifest.json", telemetry, verified_match=query_result.ok and telemetry.status.is_complete)
76
+ if not all(item.ok for item in items):
77
+ raise typer.Exit(code=1)
78
+
79
+
80
+ def _render_debug(label: str, result: CommandResult, cwd: Path) -> None:
81
+ body = Text()
82
+ body.append(f"Running: {result.command}\n", style="dim")
83
+ body.append(f"cwd: {cwd}\n", style="dim")
84
+ body.append(f"returncode: {result.returncode}\n", style="dim")
85
+ body.append("stdout:\n", style="bold")
86
+ body.append(f"{result.stdout or '<empty>'}\n")
87
+ body.append("stderr:\n", style="bold")
88
+ body.append(f"{result.stderr or '<empty>'}")
89
+ console.print(Panel(body, title=f"Debug: {label}", border_style="yellow"))
@@ -0,0 +1,51 @@
1
+ """Configuration loading and persistence for Agent Resurrect."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from dataclasses import dataclass, asdict
8
+ from pathlib import Path
9
+ from typing import Any, Mapping
10
+
11
+
12
+ DEFAULT_DELTA_TABLE_NAME = "dev_failure_traps"
13
+
14
+
15
+ @dataclass(slots=True)
16
+ class ResurrectConfig:
17
+ databricks_host: str | None = None
18
+ databricks_token: str | None = None
19
+ databricks_warehouse_id: str | None = None
20
+ delta_table_name: str = DEFAULT_DELTA_TABLE_NAME
21
+
22
+ @classmethod
23
+ def load(cls, base_dir: Path | str = Path.cwd(), env: Mapping[str, str] | None = None) -> "ResurrectConfig":
24
+ env_map = os.environ if env is None else env
25
+ config_path = Path(base_dir) / ".resurrect" / "config.json"
26
+ data: dict[str, Any] = {}
27
+ if config_path.exists():
28
+ data = json.loads(config_path.read_text(encoding="utf-8"))
29
+ return cls(
30
+ databricks_host=data.get("databricks_host") or env_map.get("DATABRICKS_HOST"),
31
+ databricks_token=data.get("databricks_token") or env_map.get("DATABRICKS_TOKEN"),
32
+ databricks_warehouse_id=data.get("databricks_warehouse_id") or env_map.get("DATABRICKS_WAREHOUSE_ID"),
33
+ delta_table_name=data.get("delta_table_name") or env_map.get("DELTA_TABLE_NAME") or DEFAULT_DELTA_TABLE_NAME,
34
+ )
35
+
36
+ def save(self, base_dir: Path | str = Path.cwd()) -> Path:
37
+ config_dir = Path(base_dir) / ".resurrect"
38
+ config_dir.mkdir(parents=True, exist_ok=True)
39
+ config_path = config_dir / "config.json"
40
+ config_path.write_text(json.dumps(asdict(self), indent=2, sort_keys=True) + "\n", encoding="utf-8")
41
+ return config_path
42
+
43
+ def missing_fields(self) -> list[str]:
44
+ missing = []
45
+ if not self.databricks_host:
46
+ missing.append("databricks_host")
47
+ if not self.databricks_token:
48
+ missing.append("databricks_token")
49
+ if not self.databricks_warehouse_id:
50
+ missing.append("databricks_warehouse_id")
51
+ return missing
@@ -0,0 +1,2 @@
1
+ """Core integration layer for Agent Resurrect."""
2
+
@@ -0,0 +1,100 @@
1
+ """Databricks connectivity helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from time import perf_counter
7
+ from typing import Any
8
+
9
+ import requests
10
+
11
+ from resurrect.parser import ParsedTelemetry
12
+
13
+
14
+ @dataclass(slots=True)
15
+ class DiagnosticResult:
16
+ ok: bool
17
+ latency_ms: float | None = None
18
+ error: str | None = None
19
+
20
+
21
+ class DatabricksClient:
22
+ def __init__(self, host: str | None, token: str | None, warehouse_id: str | None, session: requests.Session | None = None) -> None:
23
+ self.host = host.rstrip("/") if host else None
24
+ self.token = token
25
+ self.warehouse_id = warehouse_id
26
+ self.session = session or requests.Session()
27
+
28
+ def _headers(self) -> dict[str, str]:
29
+ return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
30
+
31
+ def _post_statement(self, sql: str, parameters: list[dict[str, Any]] | None = None) -> requests.Response:
32
+ url = f"{self.host}/api/2.0/sql/statements"
33
+ payload: dict[str, Any] = {
34
+ "warehouse_id": self.warehouse_id,
35
+ "statement": sql,
36
+ "wait_timeout": "10s",
37
+ }
38
+ if parameters:
39
+ payload["parameters"] = parameters
40
+ return self.session.post(url, json=payload, headers=self._headers(), timeout=15)
41
+
42
+ def ping_connection(self) -> DiagnosticResult:
43
+ if not self.host:
44
+ return DiagnosticResult(ok=False, error="Missing DATABRICKS_HOST.")
45
+ if not self.token:
46
+ return DiagnosticResult(ok=False, error="Missing DATABRICKS_TOKEN.")
47
+ if not self.warehouse_id:
48
+ return DiagnosticResult(ok=False, error="Missing DATABRICKS_WAREHOUSE_ID.")
49
+
50
+ start = perf_counter()
51
+ try:
52
+ response = self._post_statement("SELECT 1")
53
+ response.raise_for_status()
54
+ except requests.RequestException as exc:
55
+ return DiagnosticResult(ok=False, error=str(exc))
56
+ latency_ms = (perf_counter() - start) * 1000
57
+ return DiagnosticResult(ok=True, latency_ms=latency_ms)
58
+
59
+ def verify_table_exists(self, table_name: str = "dev_failure_traps") -> DiagnosticResult:
60
+ if not self.host or not self.token or not self.warehouse_id:
61
+ return DiagnosticResult(ok=False, error="Databricks configuration is incomplete.")
62
+ query = f"SELECT 1 FROM {table_name} LIMIT 1"
63
+ try:
64
+ response = self._post_statement(query)
65
+ response.raise_for_status()
66
+ except requests.RequestException as exc:
67
+ return DiagnosticResult(ok=False, error=str(exc))
68
+ return DiagnosticResult(ok=True)
69
+
70
+ def query_failure_traps(self, telemetry: ParsedTelemetry, table_name: str = "dev_failure_traps") -> DiagnosticResult:
71
+ if not self.host or not self.token or not self.warehouse_id:
72
+ return DiagnosticResult(ok=False, error="Databricks configuration is incomplete.")
73
+ if not telemetry.error_signature:
74
+ return DiagnosticResult(ok=False, error="Missing sanitized error signature.")
75
+
76
+ if telemetry.status.is_complete:
77
+ statement = (
78
+ f"SELECT * FROM {table_name} "
79
+ "WHERE error_signature = :error_signature "
80
+ "AND module_name IN (:module_0, :module_1, :module_2) "
81
+ "LIMIT 5"
82
+ )
83
+ parameters = [{"name": "error_signature", "value": telemetry.error_signature}]
84
+ parameters.extend({"name": f"module_{idx}", "value": module} for idx, module in enumerate(telemetry.module_names[:3]))
85
+ else:
86
+ statement = (
87
+ f"SELECT * FROM {table_name} "
88
+ "WHERE error_signature LIKE :error_signature "
89
+ "OR module_name IN (:module_0, :module_1, :module_2) "
90
+ "LIMIT 5"
91
+ )
92
+ parameters = [{"name": "error_signature", "value": f"%{telemetry.error_signature.split(':', 1)[0]}%"}]
93
+ parameters.extend({"name": f"module_{idx}", "value": module} for idx, module in enumerate(telemetry.module_names[:3]))
94
+ try:
95
+ response = self._post_statement(statement, parameters=parameters)
96
+ response.raise_for_status()
97
+ except requests.RequestException as exc:
98
+ return DiagnosticResult(ok=False, error=str(exc))
99
+ suffix = "heuristic/partial" if not telemetry.status.is_complete else "verified"
100
+ return DiagnosticResult(ok=True, error=suffix)
@@ -0,0 +1,110 @@
1
+ """Helpers for Entire CLI integration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+
9
+
10
+ @dataclass(slots=True)
11
+ class CommandResult:
12
+ ok: bool
13
+ command: str
14
+ stdout: str = ""
15
+ stderr: str = ""
16
+ returncode: int | None = None
17
+
18
+
19
+ def _run(command: list[str], cwd: Path | str | None = None) -> CommandResult:
20
+ try:
21
+ completed = subprocess.run(
22
+ command,
23
+ cwd=cwd,
24
+ stdin=subprocess.DEVNULL,
25
+ capture_output=True,
26
+ text=True,
27
+ encoding="utf-8",
28
+ errors="replace",
29
+ check=False,
30
+ timeout=15,
31
+ )
32
+ stdout = (completed.stdout or "").strip()
33
+ stderr = (completed.stderr or "").strip()
34
+ return CommandResult(
35
+ ok=completed.returncode == 0,
36
+ command=" ".join(command),
37
+ stdout=stdout,
38
+ stderr=stderr,
39
+ returncode=completed.returncode,
40
+ )
41
+ except subprocess.TimeoutExpired as exc:
42
+ return CommandResult(
43
+ ok=False,
44
+ command=" ".join(command),
45
+ stdout=(exc.stdout or "").strip() if isinstance(exc.stdout, str) else "",
46
+ stderr=f"Command timed out after 15 seconds while running: {' '.join(command)}",
47
+ returncode=None,
48
+ )
49
+ except FileNotFoundError as exc:
50
+ return CommandResult(
51
+ ok=False,
52
+ command=" ".join(command),
53
+ stderr=f"Command not found: {command[0]}. Install it and ensure it is on PATH. Details: {exc}",
54
+ returncode=None,
55
+ )
56
+ except Exception as exc:
57
+ return CommandResult(
58
+ ok=False,
59
+ command=" ".join(command),
60
+ stderr=f"Failed to run {' '.join(command)} in {cwd}: {exc}",
61
+ returncode=None,
62
+ )
63
+
64
+
65
+ def setup_entire(agent: str = "codex", cwd: Path | str = Path.cwd()) -> CommandResult:
66
+ git_dir = Path(cwd) / ".git"
67
+ if not git_dir.exists():
68
+ return CommandResult(ok=False, command="git rev-parse --is-inside-work-tree", stderr="Git repository not initialized.")
69
+
70
+ enable = _run(["entire", "enable", "--force"], cwd=cwd)
71
+ if not enable.ok:
72
+ return enable
73
+
74
+ hooks = _run(["entire", "hooks", "configure", "--agent", agent], cwd=cwd)
75
+ if not hooks.ok:
76
+ return hooks
77
+
78
+ return CommandResult(
79
+ ok=True,
80
+ command=f"entire enable --force && entire hooks configure --agent {agent}",
81
+ stdout="\n".join(part for part in [enable.stdout, hooks.stdout] if part),
82
+ stderr="\n".join(part for part in [enable.stderr, hooks.stderr] if part),
83
+ returncode=0,
84
+ )
85
+
86
+
87
+ def check_entire_status(cwd: Path | str = Path.cwd()) -> CommandResult:
88
+ status = _run(["entire", "status"], cwd=cwd)
89
+ text = f"{status.stdout}\n{status.stderr}".lower()
90
+ if status.returncode == 0 and ("enabled" in text or "checkpoints active" in text):
91
+ first_line = (status.stdout or "").splitlines()[0] if (status.stdout or "").splitlines() else ""
92
+ detail = f"Entire active ({first_line})" if first_line else "Entire active"
93
+ return CommandResult(
94
+ ok=True,
95
+ command=status.command,
96
+ stdout=status.stdout,
97
+ stderr=detail,
98
+ returncode=status.returncode,
99
+ )
100
+ if not status.ok:
101
+ return status
102
+ if "checkpoint" not in text or ("active" not in text and "enabled" not in text):
103
+ return CommandResult(
104
+ ok=False,
105
+ command=status.command,
106
+ stdout=status.stdout,
107
+ stderr=status.stderr or "Entire is not enabled on this repository.",
108
+ returncode=status.returncode,
109
+ )
110
+ return status
@@ -0,0 +1,47 @@
1
+ """Handoff manifest assembly for privacy-aware checkpoint resolution."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import asdict, dataclass, field
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from resurrect.parser import ParsedTelemetry
11
+
12
+
13
+ @dataclass(slots=True)
14
+ class HandoffManifest:
15
+ status_label: str
16
+ resolution_kind: str
17
+ privacy_provenance: str
18
+ confidence: str
19
+ error_signature: str
20
+ module_names: list[str] = field(default_factory=list)
21
+ is_complete: bool = False
22
+ metadata: dict[str, Any] = field(default_factory=dict)
23
+
24
+ def to_json(self) -> str:
25
+ return json.dumps(asdict(self), indent=2, sort_keys=True) + "\n"
26
+
27
+
28
+ def build_handoff_manifest(telemetry: ParsedTelemetry, verified_match: bool) -> HandoffManifest:
29
+ partial = not telemetry.status.is_complete or telemetry.status.confidence != "complete" or not verified_match
30
+ return HandoffManifest(
31
+ status_label="[PARTIAL / REDACTED CONTEXT]" if partial else "[COMPLETE CONTEXT]",
32
+ resolution_kind="heuristic" if partial else "verified",
33
+ privacy_provenance=telemetry.privacy_provenance,
34
+ confidence=telemetry.status.confidence,
35
+ error_signature=telemetry.error_signature,
36
+ module_names=telemetry.module_names,
37
+ is_complete=telemetry.status.is_complete and verified_match,
38
+ metadata={
39
+ "missing_fields": telemetry.status.missing_fields,
40
+ "source_path": str(telemetry.source_path) if telemetry.source_path else None,
41
+ },
42
+ )
43
+
44
+
45
+ def write_handoff_manifest(path: Path, telemetry: ParsedTelemetry, verified_match: bool) -> Path:
46
+ path.write_text(build_handoff_manifest(telemetry, verified_match).to_json(), encoding="utf-8")
47
+ return path
@@ -0,0 +1,132 @@
1
+ """Telemetry parsing and privacy sanitization for checkpoint context."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from pathlib import Path
7
+ import json
8
+ import re
9
+ from typing import Any
10
+
11
+
12
+ REDACTION_MARKERS = ("[REDACTED]", "***")
13
+ DEFAULT_CHECKPOINT_DIR = Path("refs/entire/checkpoints")
14
+
15
+
16
+ @dataclass(slots=True)
17
+ class ContextStatus:
18
+ is_complete: bool
19
+ confidence: str
20
+ missing_fields: list[str] = field(default_factory=list)
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class ParsedTelemetry:
25
+ error_signature: str = ""
26
+ module_names: list[str] = field(default_factory=list)
27
+ privacy_provenance: str = "sanitized"
28
+ status: ContextStatus = field(default_factory=lambda: ContextStatus(is_complete=False, confidence="partial"))
29
+ source_path: Path | None = None
30
+
31
+
32
+ def _looks_redacted(text: str) -> bool:
33
+ return any(marker in text for marker in REDACTION_MARKERS)
34
+
35
+
36
+ def _sanitize_text(text: str) -> str:
37
+ text = re.sub(r"(?i)\b[A-Z]:\\[^ \n\r\t]+|/[^ \n\r\t]+", "<path>", text)
38
+ text = re.sub(r"(?i)\b(token|password|secret|api[_-]?key)\s*[:=]\s*[^ \n\r\t]+", r"\1=<redacted>", text)
39
+ text = re.sub(r"(?i)\b[0-9a-f]{16,}\b", "<token>", text)
40
+ text = re.sub(r"`[^`]+`", "<redacted>", text)
41
+ return text.strip()
42
+
43
+
44
+ def _extract_exception_signature(text: str) -> str:
45
+ if not text:
46
+ return "UnknownError: missing checkpoint content"
47
+ lines = [line.strip() for line in text.splitlines() if line.strip()]
48
+ if not lines:
49
+ return "UnknownError: empty checkpoint content"
50
+ for line in reversed(lines):
51
+ if ":" in line:
52
+ return _sanitize_text(line)
53
+ return _sanitize_text(lines[-1])
54
+
55
+
56
+ def _extract_module_names(events: list[dict[str, Any]]) -> list[str]:
57
+ modules: set[str] = set()
58
+ for event in events:
59
+ module = event.get("module") or event.get("tool") or event.get("source")
60
+ if isinstance(module, str) and module:
61
+ modules.add(module.split(".")[0])
62
+ return sorted(modules)
63
+
64
+
65
+ def _read_checkpoint_records(checkpoint_dir: Path) -> tuple[list[dict[str, Any]], list[str]]:
66
+ records: list[dict[str, Any]] = []
67
+ missing_fields: list[str] = []
68
+ if not checkpoint_dir.exists():
69
+ missing_fields.append("checkpoint_dir")
70
+ return records, missing_fields
71
+ for path in sorted(checkpoint_dir.glob("**/*.jsonl")):
72
+ try:
73
+ for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
74
+ if not line.strip():
75
+ continue
76
+ try:
77
+ record = json.loads(line)
78
+ except json.JSONDecodeError:
79
+ missing_fields.append(f"truncated_line:{path.name}")
80
+ continue
81
+ if isinstance(record, dict):
82
+ records.append(record)
83
+ except OSError:
84
+ missing_fields.append(f"unreadable:{path.name}")
85
+ return records, missing_fields
86
+
87
+
88
+ def parse_telemetry(checkpoint_dir: Path | None = None, fixture_path: Path | None = None) -> ParsedTelemetry:
89
+ checkpoint_root = checkpoint_dir or DEFAULT_CHECKPOINT_DIR
90
+ records, missing_fields = _read_checkpoint_records(checkpoint_root)
91
+ source_path: Path | None = checkpoint_root if records else None
92
+
93
+ if not records and fixture_path and fixture_path.exists():
94
+ source_path = fixture_path
95
+ try:
96
+ for line in fixture_path.read_text(encoding="utf-8", errors="replace").splitlines():
97
+ if line.strip():
98
+ obj = json.loads(line)
99
+ if isinstance(obj, dict):
100
+ records.append(obj)
101
+ except (OSError, json.JSONDecodeError):
102
+ missing_fields.append("fixture_parse_failed")
103
+
104
+ transcript_parts: list[str] = []
105
+ redacted = False
106
+ for record in records:
107
+ if "prompt" not in record:
108
+ missing_fields.append("prompt")
109
+ if "stderr" not in record and "stdout" not in record:
110
+ missing_fields.append("tool_output")
111
+ for field in ("prompt", "transcript", "stderr", "stdout", "error", "message"):
112
+ value = record.get(field)
113
+ if isinstance(value, str) and value:
114
+ if _looks_redacted(value):
115
+ redacted = True
116
+ transcript_parts.append(value)
117
+ transcript = "\n".join(transcript_parts)
118
+ if _looks_redacted(transcript):
119
+ redacted = True
120
+ signature = _extract_exception_signature(transcript)
121
+ status = ContextStatus(
122
+ is_complete=not redacted and not missing_fields,
123
+ confidence="complete" if not redacted and not missing_fields else "partial",
124
+ missing_fields=sorted(set(missing_fields)),
125
+ )
126
+ return ParsedTelemetry(
127
+ error_signature=signature,
128
+ module_names=_extract_module_names(records),
129
+ privacy_provenance="checkpoint" if source_path == checkpoint_root else "fixture",
130
+ status=status,
131
+ source_path=source_path,
132
+ )
@@ -0,0 +1,2 @@
1
+ """UI helpers for Agent Resurrect."""
2
+
@@ -0,0 +1,34 @@
1
+ """Rich console rendering for diagnostics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.table import Table
10
+
11
+
12
+ @dataclass(slots=True)
13
+ class StatusItem:
14
+ name: str
15
+ ok: bool
16
+ detail: str = ""
17
+ context_label: str = ""
18
+
19
+
20
+ def render_status_board(items: list[StatusItem], title: str = "Resurrect Doctor") -> Console:
21
+ console = Console()
22
+ table = Table(show_header=True, header_style="bold")
23
+ table.add_column("Check")
24
+ table.add_column("Status")
25
+ table.add_column("Details")
26
+ for item in items:
27
+ status = "[green]PASS[/green]" if item.ok else "[red]FAIL[/red]"
28
+ check = "[green]✓[/green]" if item.ok else "[yellow]![/yellow]"
29
+ detail = item.detail or ""
30
+ if item.context_label:
31
+ detail = f"{item.context_label} {detail}".strip()
32
+ table.add_row(f"{check} {item.name}", status, detail)
33
+ console.print(Panel(table, title=title, border_style="blue"))
34
+ return console
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ from resurrect.config import DEFAULT_DELTA_TABLE_NAME, ResurrectConfig
7
+
8
+
9
+ def test_loads_from_env_when_config_missing(tmp_path: Path) -> None:
10
+ env = {
11
+ "DATABRICKS_HOST": "https://example.databricks.com",
12
+ "DATABRICKS_TOKEN": "token",
13
+ "DATABRICKS_WAREHOUSE_ID": "wh-1",
14
+ }
15
+ config = ResurrectConfig.load(tmp_path, env=env)
16
+ assert config.databricks_host == env["DATABRICKS_HOST"]
17
+ assert config.databricks_token == env["DATABRICKS_TOKEN"]
18
+ assert config.databricks_warehouse_id == env["DATABRICKS_WAREHOUSE_ID"]
19
+ assert config.delta_table_name == DEFAULT_DELTA_TABLE_NAME
20
+
21
+
22
+ def test_save_and_load_round_trip(tmp_path: Path) -> None:
23
+ config = ResurrectConfig(
24
+ databricks_host="https://example.databricks.com",
25
+ databricks_token="token",
26
+ databricks_warehouse_id="wh-1",
27
+ delta_table_name="custom_table",
28
+ )
29
+ path = config.save(tmp_path)
30
+ assert path.exists()
31
+ saved = json.loads(path.read_text(encoding="utf-8"))
32
+ assert saved["delta_table_name"] == "custom_table"
33
+
34
+ loaded = ResurrectConfig.load(tmp_path, env={})
35
+ assert loaded == config
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from types import SimpleNamespace
5
+ from unittest.mock import Mock
6
+
7
+ import requests
8
+
9
+ from resurrect.core.databricks_client import DatabricksClient
10
+ from resurrect.core.entire_bridge import _run, check_entire_status, setup_entire
11
+
12
+
13
+ def test_setup_entire_runs_commands(monkeypatch, tmp_path: Path) -> None:
14
+ (tmp_path / ".git").mkdir()
15
+ calls: list[list[str]] = []
16
+
17
+ def fake_run(command, cwd=None, stdin=None, capture_output=None, text=None, encoding=None, errors=None, check=None, timeout=None):
18
+ calls.append(command)
19
+ return SimpleNamespace(returncode=0, stdout="ok", stderr="")
20
+
21
+ monkeypatch.setattr("resurrect.core.entire_bridge.subprocess.run", fake_run)
22
+ result = setup_entire(cwd=tmp_path)
23
+ assert result.ok
24
+ assert calls == [["entire", "enable", "--force"], ["entire", "hooks", "configure", "--agent", "codex"]]
25
+
26
+
27
+ def test_check_entire_status_detects_active_checkpoints(monkeypatch, tmp_path: Path) -> None:
28
+ def fake_run(command, cwd=None, stdin=None, capture_output=None, text=None, encoding=None, errors=None, check=None, timeout=None):
29
+ return SimpleNamespace(returncode=0, stdout="checkpoints active", stderr="")
30
+
31
+ monkeypatch.setattr("resurrect.core.entire_bridge.subprocess.run", fake_run)
32
+ result = check_entire_status(cwd=tmp_path)
33
+ assert result.ok
34
+
35
+
36
+ def test_ping_connection_and_table_query(monkeypatch) -> None:
37
+ session = Mock(spec=requests.Session)
38
+ response = Mock()
39
+ response.raise_for_status.return_value = None
40
+ session.post.return_value = response
41
+ client = DatabricksClient("https://example.databricks.com", "token", "wh-1", session=session)
42
+
43
+ ping = client.ping_connection()
44
+ table = client.verify_table_exists()
45
+
46
+ assert ping.ok
47
+ assert table.ok
48
+ assert session.post.call_count == 2
49
+ assert session.post.call_args_list[0].args[0].endswith("/api/2.0/sql/statements")
50
+
51
+
52
+ def test_ping_connection_reports_missing_fields() -> None:
53
+ client = DatabricksClient(None, None, None)
54
+ result = client.ping_connection()
55
+ assert not result.ok
56
+ assert "Missing DATABRICKS_HOST" in result.error
57
+
58
+
59
+ def test_run_handles_none_output(monkeypatch, tmp_path: Path) -> None:
60
+ def fake_run(command, cwd=None, stdin=None, capture_output=None, text=None, encoding=None, errors=None, check=None, timeout=None):
61
+ return SimpleNamespace(returncode=0, stdout=None, stderr=None)
62
+
63
+ monkeypatch.setattr("resurrect.core.entire_bridge.subprocess.run", fake_run)
64
+ result = _run(["entire", "status"], cwd=tmp_path)
65
+ assert result.ok
66
+ assert result.stdout == ""
67
+ assert result.stderr == ""
68
+
69
+
70
+ def test_run_decodes_non_ascii_output(monkeypatch, tmp_path: Path) -> None:
71
+ def fake_run(command, cwd=None, stdin=None, capture_output=None, text=None, encoding=None, errors=None, check=None, timeout=None):
72
+ return SimpleNamespace(returncode=0, stdout="naïve ✓", stderr="错误")
73
+
74
+ monkeypatch.setattr("resurrect.core.entire_bridge.subprocess.run", fake_run)
75
+ result = _run(["entire", "status"], cwd=tmp_path)
76
+ assert result.ok
77
+ assert result.stdout == "naïve ✓"
78
+ assert result.stderr == "错误"
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from types import SimpleNamespace
5
+ from unittest.mock import Mock
6
+
7
+ import requests
8
+
9
+ from resurrect.core.databricks_client import DatabricksClient
10
+ from resurrect.handoff import build_handoff_manifest
11
+ from resurrect.parser import parse_telemetry
12
+ from resurrect.ui.console import StatusItem
13
+
14
+
15
+ def test_privacy_boundary_with_redacted_checkpoint(monkeypatch, tmp_path: Path) -> None:
16
+ checkpoint_dir = tmp_path / "refs" / "entire" / "checkpoints"
17
+ checkpoint_dir.mkdir(parents=True)
18
+ fixture = Path(__file__).parent / "fixtures" / "redacted_checkpoint.jsonl"
19
+ (checkpoint_dir / "checkpoint.jsonl").write_text(fixture.read_text(encoding="utf-8"), encoding="utf-8")
20
+
21
+ telemetry = parse_telemetry(checkpoint_dir)
22
+ assert telemetry.error_signature
23
+ assert not telemetry.status.is_complete
24
+ assert telemetry.status.confidence == "partial"
25
+ assert "prompt" in telemetry.status.missing_fields
26
+
27
+ session = Mock(spec=requests.Session)
28
+ response = Mock()
29
+ response.raise_for_status.return_value = None
30
+ session.post.return_value = response
31
+ client = DatabricksClient("https://example.databricks.com", "token", "wh-1", session=session)
32
+
33
+ result = client.query_failure_traps(telemetry)
34
+ assert result.ok
35
+
36
+ payload = session.post.call_args.kwargs["json"]
37
+ assert "prompt" not in str(payload).lower()
38
+ assert "[redacted]" not in str(payload).lower()
39
+ assert "***" not in str(payload)
40
+ assert "statement" in payload
41
+ assert payload["statement"].startswith("SELECT * FROM dev_failure_traps")
42
+ assert "parameters" in payload
43
+
44
+ manifest = build_handoff_manifest(telemetry, verified_match=result.ok)
45
+ assert manifest.status_label == "[PARTIAL / REDACTED CONTEXT]"
46
+ assert manifest.confidence == "partial"
47
+ assert manifest.is_complete is False
48
+
49
+ item = StatusItem("Failure traps", result.ok, result.error or "", context_label=manifest.status_label)
50
+ assert item.context_label == "[PARTIAL / REDACTED CONTEXT]"