gator-command 1.2.2__tar.gz → 1.4.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.
- {gator_command-1.2.2/src/gator_command.egg-info → gator_command-1.4.0}/PKG-INFO +1 -1
- {gator_command-1.2.2 → gator_command-1.4.0}/pyproject.toml +1 -1
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/cli.py +8 -7
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-deploy.py +4 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-session-aggregator.py +79 -26
- gator_command-1.4.0/src/gator_command/scripts/gator-session-block.py +680 -0
- {gator_command-1.2.2/src/gator_command/templates/gator-starter → gator_command-1.4.0/src/gator_command}/scripts/gator-update.py +213 -103
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gatorize.py +105 -20
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-pre-commit.py +57 -7
- gator_command-1.4.0/src/gator_command/templates/gator-starter/scripts/gator-session-start.py +273 -0
- {gator_command-1.2.2/src/gator_command → gator_command-1.4.0/src/gator_command/templates/gator-starter}/scripts/gator-update.py +116 -103
- gator_command-1.4.0/src/gator_command/templates/gator-starter/vendor-hooks/claude-settings.json +15 -0
- gator_command-1.4.0/src/gator_command/templates/gator-starter/vendor-hooks/codex-hooks.json +15 -0
- gator_command-1.4.0/src/gator_command/templates/gator-starter/vendor-hooks/gemini-settings.json +15 -0
- {gator_command-1.2.2 → gator_command-1.4.0/src/gator_command.egg-info}/PKG-INFO +1 -1
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command.egg-info/SOURCES.txt +9 -1
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_pre_commit.py +135 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_session_aggregator.py +105 -0
- gator_command-1.4.0/tests/test_session_block.py +605 -0
- gator_command-1.4.0/tests/test_session_start.py +360 -0
- gator_command-1.4.0/tests/test_vendor_hooks.py +292 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/LICENSE +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/PYPI_README.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/README.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/setup.cfg +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/__init__.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/crawler.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/dashboard.css +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/dashboard.html +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/dashboard.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/views/audit.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/views/fleet.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/views/repo.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/views/settings.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/dashboard/views/updates.js +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/enforcer-prompt.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/extract-claude-sessions.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/extract-codex-sessions.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/extract-gemini-sessions.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-audit-renderers.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-audit.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-charter-draft.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-charter-lint.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-charter-verify.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-dashboard.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-drift.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-enforce.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-fleet-intel.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-fleet-report.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-init-command-post.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-init.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-machine-id.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-policy-status.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-pulse.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-repo-status.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-session-common.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-session-sink.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-sessions.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-version.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator_core.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator_remote.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator_runtime.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gatorize-actions.sh +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gatorize-lib.sh +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gatorize-post.sh +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gatorize.sh +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/generate_markdown.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/generate_wiki.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/graph_health.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/memex-lint.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/memex-lint.sh +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/memex.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/memex_formatters.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/memex_state.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/spawn.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/blueprints/README.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/charterignore +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/charters/README.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/charters/_template.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/commands/commit.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/commands/init.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/commands/update.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/constitution.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/field-guides/README.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/gator-start-up.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/procedures/charter-alignment.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/procedures/enforcer-review.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/procedures/field-guide-generation.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/procedures/knowledge-capture.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/procedures/significance-check.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/concierge-responses.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/dangerous-patterns.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/dashboard-operations.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/enforcer-configuration.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/example-project.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/failure-modes-and-self-correction.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/git-workflow.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/identity-and-ownership.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/refactor-approach.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/what-gator-requires-from-a-model.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/why-navigation-coding-feels-different.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/reference-notes/workflow-profiles.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/__pycache__/enforcer-review.cpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/__pycache__/gator-approve.cpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/__pycache__/gator-init.cpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/__pycache__/gator-pre-commit.cpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/__pycache__/gator-update.cpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/enforcer-prompt.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/enforcer-review.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-approve.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-enforce.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-init.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-pulse.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator-version.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/gator_core.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/__pycache__/commit-msgcpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/__pycache__/post-commitcpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/__pycache__/pre-commitcpython-313.pyc +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/commit-msg +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/post-commit +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/scripts/hooks/pre-commit +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/sessions/.gitignore +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/vault/.gitkeep +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/templates/gator-starter/whiteboard.md +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command.egg-info/dependency_links.txt +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command.egg-info/entry_points.txt +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command.egg-info/top_level.txt +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_audit.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_audit_integration.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_charter_lint.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_dashboard_sessions.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_deploy.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_drift.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_fleet_intel.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_fleet_report.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_gator_core.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_gatorize.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_hooks.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_init.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_memex_state.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_packaging.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_remote.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_session_sink.py +0 -0
- {gator_command-1.2.2 → gator_command-1.4.0}/tests/test_sessions.py +0 -0
|
@@ -75,6 +75,7 @@ COMMANDS = {
|
|
|
75
75
|
"audit": ("gator-audit.py", "Run governance audit"),
|
|
76
76
|
"drift": ("gator-drift.py", "Check fleet for governance drift"),
|
|
77
77
|
"fleet": ("gator-fleet-report.py", "Fleet status report"),
|
|
78
|
+
"session-blocks": ("gator-session-block.py", "Generate session-block companions"),
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
|
|
@@ -121,13 +122,13 @@ def main():
|
|
|
121
122
|
_run_script(scripts_dir, script_name, remaining)
|
|
122
123
|
|
|
123
124
|
|
|
124
|
-
def _get_version():
|
|
125
|
-
"""Get version from the package's single-source version resolver."""
|
|
126
|
-
try:
|
|
127
|
-
from gator_command import __version__
|
|
128
|
-
return __version__
|
|
129
|
-
except ImportError:
|
|
130
|
-
return "unknown"
|
|
125
|
+
def _get_version():
|
|
126
|
+
"""Get version from the package's single-source version resolver."""
|
|
127
|
+
try:
|
|
128
|
+
from gator_command import __version__
|
|
129
|
+
return __version__
|
|
130
|
+
except ImportError:
|
|
131
|
+
return "unknown"
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
if __name__ == "__main__":
|
|
@@ -158,8 +158,12 @@ ROOT_GITIGNORE = (
|
|
|
158
158
|
"# Session snippets — contain machine-id, not for public repos\n"
|
|
159
159
|
".gator/session-snippets/\n"
|
|
160
160
|
"\n"
|
|
161
|
+
"# Session blocks — local-only transcript evidence\n"
|
|
162
|
+
".gator/session-blocks/\n"
|
|
163
|
+
"\n"
|
|
161
164
|
"# Machine-local state (not portable)\n"
|
|
162
165
|
".gator/product-source.json\n"
|
|
166
|
+
".gator/active-vendor-session.json\n"
|
|
163
167
|
)
|
|
164
168
|
|
|
165
169
|
|
{gator_command-1.2.2 → gator_command-1.4.0}/src/gator_command/scripts/gator-session-aggregator.py
RENAMED
|
@@ -8,7 +8,7 @@ entry point. Dashboard and CLI scripts import this.
|
|
|
8
8
|
|
|
9
9
|
@reads: .gator/session-snippets/*.json (per repo)
|
|
10
10
|
@reads: ~/.gator/dashboard-repos.json (fleet queries)
|
|
11
|
-
@writes: ~/.gator/sessions/<path-hash>/<
|
|
11
|
+
@writes: ~/.gator/sessions/<path-hash>/<esk-hash>.json (cached summaries)
|
|
12
12
|
@writes: ~/.gator/sessions/<path-hash>/_repo.json (repo metadata)
|
|
13
13
|
"""
|
|
14
14
|
|
|
@@ -33,6 +33,28 @@ SIGNIFICANCE_ORDER = {"routine": 0, "minor": 1, "high": 2}
|
|
|
33
33
|
SKIP_CHANGE_TYPES_FOR_GOAL = {"release", "merge", "cleanup"}
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Session Identity
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
def effective_session_key(snippet):
|
|
41
|
+
"""Return the canonical grouping key for a snippet.
|
|
42
|
+
|
|
43
|
+
Uses vendor session identity when available, falls back to legacy
|
|
44
|
+
Gator session_id. The returned string is used for aggregation grouping,
|
|
45
|
+
cache filenames, and fingerprint lookups.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
"group:<repo>:<session_group_key>" when session_group_key is truthy
|
|
49
|
+
"legacy:<repo>:<session_id>" otherwise
|
|
50
|
+
"""
|
|
51
|
+
repo = snippet.get("repo", "")
|
|
52
|
+
sgk = snippet.get("session_group_key")
|
|
53
|
+
if sgk:
|
|
54
|
+
return f"group:{repo}:{sgk}"
|
|
55
|
+
return f"legacy:{repo}:{snippet.get('session_id', '')}"
|
|
56
|
+
|
|
57
|
+
|
|
36
58
|
# ---------------------------------------------------------------------------
|
|
37
59
|
# 1a. Snippet Reader
|
|
38
60
|
# ---------------------------------------------------------------------------
|
|
@@ -75,7 +97,11 @@ def read_snippets(repo_path):
|
|
|
75
97
|
# ---------------------------------------------------------------------------
|
|
76
98
|
|
|
77
99
|
def aggregate_sessions(snippets, repo_path):
|
|
78
|
-
"""Group snippets by (
|
|
100
|
+
"""Group snippets by effective_session_key() and aggregate into summaries.
|
|
101
|
+
|
|
102
|
+
Uses vendor session_group_key when present, falls back to legacy
|
|
103
|
+
Gator session_id. Snippets with different effective keys are never
|
|
104
|
+
merged, even if timestamps or transcript IDs look similar.
|
|
79
105
|
|
|
80
106
|
Args:
|
|
81
107
|
snippets: list of parsed snippet dicts (the "data" from SnippetRecords)
|
|
@@ -83,10 +109,10 @@ def aggregate_sessions(snippets, repo_path):
|
|
|
83
109
|
|
|
84
110
|
Returns list of summary dicts matching gator-session-summary-v1 schema.
|
|
85
111
|
"""
|
|
86
|
-
# Group by
|
|
112
|
+
# Group by effective_session_key
|
|
87
113
|
groups = {}
|
|
88
114
|
for s in snippets:
|
|
89
|
-
key = (s
|
|
115
|
+
key = effective_session_key(s)
|
|
90
116
|
if key not in groups:
|
|
91
117
|
groups[key] = []
|
|
92
118
|
groups[key].append(s)
|
|
@@ -94,7 +120,7 @@ def aggregate_sessions(snippets, repo_path):
|
|
|
94
120
|
repo_key = session_cache_key(repo_path)
|
|
95
121
|
summaries = []
|
|
96
122
|
|
|
97
|
-
for
|
|
123
|
+
for esk, group in groups.items():
|
|
98
124
|
# Sort within group
|
|
99
125
|
group.sort(key=lambda s: (
|
|
100
126
|
s.get("started_at", ""),
|
|
@@ -110,6 +136,7 @@ def aggregate_sessions(snippets, repo_path):
|
|
|
110
136
|
all_intents = []
|
|
111
137
|
all_notes = []
|
|
112
138
|
all_change_types = set()
|
|
139
|
+
all_models = set()
|
|
113
140
|
max_sig = "routine"
|
|
114
141
|
architect = ""
|
|
115
142
|
transcript_session_id = None
|
|
@@ -150,6 +177,11 @@ def aggregate_sessions(snippets, repo_path):
|
|
|
150
177
|
if ct:
|
|
151
178
|
all_change_types.add(ct)
|
|
152
179
|
|
|
180
|
+
# Models — distinct
|
|
181
|
+
model = s.get("model_inferred", "")
|
|
182
|
+
if model:
|
|
183
|
+
all_models.add(model)
|
|
184
|
+
|
|
153
185
|
# Max significance
|
|
154
186
|
sig = s.get("significance", "routine")
|
|
155
187
|
if SIGNIFICANCE_ORDER.get(sig, 0) > SIGNIFICANCE_ORDER.get(max_sig, 0):
|
|
@@ -165,14 +197,24 @@ def aggregate_sessions(snippets, repo_path):
|
|
|
165
197
|
if not transcript_ref:
|
|
166
198
|
transcript_ref = s.get("transcript_ref")
|
|
167
199
|
|
|
200
|
+
# session_group_key: first non-null from the group (all should agree)
|
|
201
|
+
session_group_key = None
|
|
202
|
+
for s in group:
|
|
203
|
+
sgk = s.get("session_group_key")
|
|
204
|
+
if sgk:
|
|
205
|
+
session_group_key = sgk
|
|
206
|
+
break
|
|
207
|
+
|
|
168
208
|
summary = {
|
|
169
209
|
"schema": "gator-session-summary-v1",
|
|
170
|
-
"session_id": session_id,
|
|
171
|
-
"
|
|
210
|
+
"session_id": first.get("session_id", ""),
|
|
211
|
+
"session_group_key": session_group_key,
|
|
212
|
+
"repo": first.get("repo", ""),
|
|
172
213
|
"repo_key": repo_key,
|
|
173
214
|
"branch": first.get("branch", ""),
|
|
174
215
|
"vendor": first.get("vendor_inferred", ""),
|
|
175
216
|
"model": first.get("model_inferred", ""),
|
|
217
|
+
"models": sorted(all_models),
|
|
176
218
|
"agent": first.get("agent", ""),
|
|
177
219
|
"architect": architect,
|
|
178
220
|
"started_at": min(s.get("started_at", "") for s in group),
|
|
@@ -273,21 +315,32 @@ def write_repo_metadata(cache_path, repo_name, repo_path):
|
|
|
273
315
|
_atomic_write(meta_path, json.dumps(meta, indent=2) + "\n")
|
|
274
316
|
|
|
275
317
|
|
|
276
|
-
def
|
|
277
|
-
"""
|
|
318
|
+
def _esk_from_summary(summary):
|
|
319
|
+
"""Reconstruct the effective session key from a summary dict.
|
|
320
|
+
|
|
321
|
+
Mirrors effective_session_key() but reads from summary fields
|
|
322
|
+
instead of snippet fields.
|
|
323
|
+
"""
|
|
324
|
+
repo = summary.get("repo", "")
|
|
325
|
+
sgk = summary.get("session_group_key")
|
|
326
|
+
if sgk:
|
|
327
|
+
return f"group:{repo}:{sgk}"
|
|
328
|
+
return f"legacy:{repo}:{summary.get('session_id', '')}"
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _summary_cache_filename(esk):
|
|
332
|
+
"""Build a cache filename from the effective session key.
|
|
278
333
|
|
|
279
|
-
|
|
280
|
-
|
|
334
|
+
Hashes the full effective_session_key string to produce a stable,
|
|
335
|
+
filesystem-safe filename. The key already encodes repo + identity.
|
|
281
336
|
"""
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return f"{repo_prefix}-{session_id}.json"
|
|
285
|
-
return f"{session_id}.json"
|
|
337
|
+
h = hashlib.sha256(esk.encode()).hexdigest()[:16]
|
|
338
|
+
return f"{h}.json"
|
|
286
339
|
|
|
287
340
|
|
|
288
|
-
def read_cached_summary(cache_path,
|
|
341
|
+
def read_cached_summary(cache_path, esk):
|
|
289
342
|
"""Read a cached session summary, or return None."""
|
|
290
|
-
summary_path = cache_path / _summary_cache_filename(
|
|
343
|
+
summary_path = cache_path / _summary_cache_filename(esk)
|
|
291
344
|
if not summary_path.exists():
|
|
292
345
|
return None
|
|
293
346
|
try:
|
|
@@ -296,10 +349,10 @@ def read_cached_summary(cache_path, repo, session_id):
|
|
|
296
349
|
return None
|
|
297
350
|
|
|
298
351
|
|
|
299
|
-
def write_cached_summary(cache_path, summary):
|
|
352
|
+
def write_cached_summary(cache_path, summary, esk):
|
|
300
353
|
"""Write a session summary to cache."""
|
|
301
354
|
cache_path.mkdir(parents=True, exist_ok=True)
|
|
302
|
-
filename = _summary_cache_filename(
|
|
355
|
+
filename = _summary_cache_filename(esk)
|
|
303
356
|
summary_path = cache_path / filename
|
|
304
357
|
_atomic_write(summary_path, json.dumps(summary, indent=2) + "\n")
|
|
305
358
|
|
|
@@ -349,10 +402,10 @@ def get_session_summaries(repo_path, force_refresh=False):
|
|
|
349
402
|
snippets_data = [r["data"] for r in records]
|
|
350
403
|
sessions = aggregate_sessions(snippets_data, repo_path)
|
|
351
404
|
|
|
352
|
-
# Build a lookup:
|
|
405
|
+
# Build a lookup: effective_session_key -> list of records (for fingerprinting)
|
|
353
406
|
session_records = {}
|
|
354
407
|
for r in records:
|
|
355
|
-
key = (r["data"]
|
|
408
|
+
key = effective_session_key(r["data"])
|
|
356
409
|
if key not in session_records:
|
|
357
410
|
session_records[key] = []
|
|
358
411
|
session_records[key].append(r)
|
|
@@ -362,13 +415,13 @@ def get_session_summaries(repo_path, force_refresh=False):
|
|
|
362
415
|
wrote_any = False
|
|
363
416
|
|
|
364
417
|
for summary in sessions:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
recs = session_records.get(
|
|
418
|
+
# Reconstruct the effective key from the summary's first snippet identity
|
|
419
|
+
esk = _esk_from_summary(summary)
|
|
420
|
+
recs = session_records.get(esk, [])
|
|
368
421
|
fp = snippet_fingerprint(recs)
|
|
369
422
|
|
|
370
423
|
if not force_refresh:
|
|
371
|
-
cached = read_cached_summary(cpath,
|
|
424
|
+
cached = read_cached_summary(cpath, esk)
|
|
372
425
|
if cached and is_fresh(cached, fp):
|
|
373
426
|
results.append(cached)
|
|
374
427
|
continue
|
|
@@ -376,7 +429,7 @@ def get_session_summaries(repo_path, force_refresh=False):
|
|
|
376
429
|
# Generate and cache
|
|
377
430
|
summary["generated_at"] = datetime.now(timezone.utc).isoformat()
|
|
378
431
|
summary["snippet_fingerprint"] = fp
|
|
379
|
-
write_cached_summary(cpath, summary)
|
|
432
|
+
write_cached_summary(cpath, summary, esk)
|
|
380
433
|
results.append(summary)
|
|
381
434
|
wrote_any = True
|
|
382
435
|
|