gator-command 1.0.0__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.
Files changed (110) hide show
  1. gator_command/__init__.py +2 -0
  2. gator_command/cli.py +137 -0
  3. gator_command/scripts/crawler.py +633 -0
  4. gator_command/scripts/dashboard/dashboard.css +982 -0
  5. gator_command/scripts/dashboard/dashboard.html +84 -0
  6. gator_command/scripts/dashboard/dashboard.js +419 -0
  7. gator_command/scripts/dashboard/views/audit.js +270 -0
  8. gator_command/scripts/dashboard/views/fleet.js +307 -0
  9. gator_command/scripts/dashboard/views/repo.js +599 -0
  10. gator_command/scripts/dashboard/views/settings.js +173 -0
  11. gator_command/scripts/dashboard/views/updates.js +308 -0
  12. gator_command/scripts/enforcer-prompt.md +22 -0
  13. gator_command/scripts/extract-claude-sessions.py +489 -0
  14. gator_command/scripts/extract-codex-sessions.py +477 -0
  15. gator_command/scripts/extract-gemini-sessions.py +410 -0
  16. gator_command/scripts/gator-audit.py +956 -0
  17. gator_command/scripts/gator-charter-draft.py +919 -0
  18. gator_command/scripts/gator-charter-lint.py +427 -0
  19. gator_command/scripts/gator-charter-verify.py +606 -0
  20. gator_command/scripts/gator-dashboard.py +1271 -0
  21. gator_command/scripts/gator-deploy.py +916 -0
  22. gator_command/scripts/gator-drift.py +569 -0
  23. gator_command/scripts/gator-enforce.py +82 -0
  24. gator_command/scripts/gator-fleet-intel.py +460 -0
  25. gator_command/scripts/gator-fleet-report.py +615 -0
  26. gator_command/scripts/gator-init-command-post.py +315 -0
  27. gator_command/scripts/gator-init.py +434 -0
  28. gator_command/scripts/gator-machine-id.py +153 -0
  29. gator_command/scripts/gator-policy-status.py +631 -0
  30. gator_command/scripts/gator-pulse.py +459 -0
  31. gator_command/scripts/gator-repo-status.py +649 -0
  32. gator_command/scripts/gator-session-common.py +372 -0
  33. gator_command/scripts/gator-session-sink.py +831 -0
  34. gator_command/scripts/gator-sessions.py +1244 -0
  35. gator_command/scripts/gator-update.py +615 -0
  36. gator_command/scripts/gator-version.py +38 -0
  37. gator_command/scripts/gator_core.py +489 -0
  38. gator_command/scripts/gator_remote.py +381 -0
  39. gator_command/scripts/gator_runtime.py +142 -0
  40. gator_command/scripts/gatorize-actions.sh +989 -0
  41. gator_command/scripts/gatorize-lib.sh +166 -0
  42. gator_command/scripts/gatorize-post.sh +394 -0
  43. gator_command/scripts/gatorize.py +1163 -0
  44. gator_command/scripts/gatorize.sh +185 -0
  45. gator_command/scripts/generate_markdown.py +212 -0
  46. gator_command/scripts/generate_wiki.py +424 -0
  47. gator_command/scripts/graph_health.py +780 -0
  48. gator_command/scripts/memex-lint.py +286 -0
  49. gator_command/scripts/memex-lint.sh +205 -0
  50. gator_command/scripts/memex.py +1472 -0
  51. gator_command/scripts/memex_formatters.py +191 -0
  52. gator_command/scripts/memex_state.py +236 -0
  53. gator_command/scripts/spawn.py +650 -0
  54. gator_command/templates/gator-starter/blueprints/README.md +32 -0
  55. gator_command/templates/gator-starter/charterignore +53 -0
  56. gator_command/templates/gator-starter/charters/README.md +178 -0
  57. gator_command/templates/gator-starter/charters/_template.md +31 -0
  58. gator_command/templates/gator-starter/commands/commit.md +33 -0
  59. gator_command/templates/gator-starter/commands/init.md +11 -0
  60. gator_command/templates/gator-starter/commands/update.md +5 -0
  61. gator_command/templates/gator-starter/constitution.md +165 -0
  62. gator_command/templates/gator-starter/field-guides/README.md +25 -0
  63. gator_command/templates/gator-starter/gator-start-up.md +119 -0
  64. gator_command/templates/gator-starter/procedures/charter-alignment.md +83 -0
  65. gator_command/templates/gator-starter/procedures/enforcer-review.md +317 -0
  66. gator_command/templates/gator-starter/procedures/field-guide-generation.md +176 -0
  67. gator_command/templates/gator-starter/procedures/knowledge-capture.md +57 -0
  68. gator_command/templates/gator-starter/procedures/significance-check.md +69 -0
  69. gator_command/templates/gator-starter/reference-notes/concierge-responses.md +535 -0
  70. gator_command/templates/gator-starter/reference-notes/dangerous-patterns.md +91 -0
  71. gator_command/templates/gator-starter/reference-notes/dashboard-operations.md +22 -0
  72. gator_command/templates/gator-starter/reference-notes/enforcer-configuration.md +232 -0
  73. gator_command/templates/gator-starter/reference-notes/example-project.md +289 -0
  74. gator_command/templates/gator-starter/reference-notes/failure-modes-and-self-correction.md +72 -0
  75. gator_command/templates/gator-starter/reference-notes/git-workflow.md +60 -0
  76. gator_command/templates/gator-starter/reference-notes/identity-and-ownership.md +37 -0
  77. gator_command/templates/gator-starter/reference-notes/refactor-approach.md +155 -0
  78. gator_command/templates/gator-starter/reference-notes/what-gator-requires-from-a-model.md +108 -0
  79. gator_command/templates/gator-starter/reference-notes/why-navigation-coding-feels-different.md +99 -0
  80. gator_command/templates/gator-starter/reference-notes/workflow-profiles.md +155 -0
  81. gator_command/templates/gator-starter/scripts/__pycache__/enforcer-review.cpython-313.pyc +0 -0
  82. gator_command/templates/gator-starter/scripts/__pycache__/gator-approve.cpython-313.pyc +0 -0
  83. gator_command/templates/gator-starter/scripts/__pycache__/gator-init.cpython-313.pyc +0 -0
  84. gator_command/templates/gator-starter/scripts/__pycache__/gator-pre-commit.cpython-313.pyc +0 -0
  85. gator_command/templates/gator-starter/scripts/__pycache__/gator-update.cpython-313.pyc +0 -0
  86. gator_command/templates/gator-starter/scripts/enforcer-prompt.md +55 -0
  87. gator_command/templates/gator-starter/scripts/enforcer-review.py +1551 -0
  88. gator_command/templates/gator-starter/scripts/gator-approve.py +139 -0
  89. gator_command/templates/gator-starter/scripts/gator-enforce.py +82 -0
  90. gator_command/templates/gator-starter/scripts/gator-init.py +434 -0
  91. gator_command/templates/gator-starter/scripts/gator-pre-commit.py +2670 -0
  92. gator_command/templates/gator-starter/scripts/gator-pulse.py +459 -0
  93. gator_command/templates/gator-starter/scripts/gator-update.py +615 -0
  94. gator_command/templates/gator-starter/scripts/gator-version.py +38 -0
  95. gator_command/templates/gator-starter/scripts/gator_core.py +487 -0
  96. gator_command/templates/gator-starter/scripts/hooks/__pycache__/commit-msgcpython-313.pyc +0 -0
  97. gator_command/templates/gator-starter/scripts/hooks/__pycache__/post-commitcpython-313.pyc +0 -0
  98. gator_command/templates/gator-starter/scripts/hooks/__pycache__/pre-commitcpython-313.pyc +0 -0
  99. gator_command/templates/gator-starter/scripts/hooks/commit-msg +5 -0
  100. gator_command/templates/gator-starter/scripts/hooks/post-commit +7 -0
  101. gator_command/templates/gator-starter/scripts/hooks/pre-commit +5 -0
  102. gator_command/templates/gator-starter/sessions/.gitignore +7 -0
  103. gator_command/templates/gator-starter/vault/.gitkeep +0 -0
  104. gator_command/templates/gator-starter/whiteboard.md +5 -0
  105. gator_command-1.0.0.dist-info/METADATA +122 -0
  106. gator_command-1.0.0.dist-info/RECORD +110 -0
  107. gator_command-1.0.0.dist-info/WHEEL +5 -0
  108. gator_command-1.0.0.dist-info/entry_points.txt +2 -0
  109. gator_command-1.0.0.dist-info/licenses/LICENSE +21 -0
  110. gator_command-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * settings.js — Settings view for Gator Dashboard.
3
+ *
4
+ * Per-repo settings: enforcement level and governance topology.
5
+ * No dashboard-wide mode toggle — topology is per-repo.
6
+ */
7
+
8
+ (function () {
9
+ "use strict";
10
+
11
+ window.GatorViews = window.GatorViews || {};
12
+
13
+ function escHtml(str) {
14
+ return String(str)
15
+ .replace(/&/g, "&")
16
+ .replace(/</g, "&lt;")
17
+ .replace(/>/g, "&gt;")
18
+ .replace(/"/g, "&quot;");
19
+ }
20
+
21
+ window.GatorViews.settings = function (data, container, opts) {
22
+ const standalone = opts.standalone || false;
23
+ const repos = data.standalone ? (data.repos || []) : ((data.fleet || {}).repos || []);
24
+
25
+ let html = `
26
+ <div class="view-header">
27
+ <span class="view-title">Settings</span>
28
+ <span class="view-subtitle">Per-repo governance configuration</span>
29
+ </div>
30
+ `;
31
+
32
+ if (repos.length > 0) {
33
+ html += `
34
+ <div class="section">
35
+ <h3 style="margin:0 0 12px 0;font-size:14px;font-weight:600">Repo Governance</h3>
36
+ <p class="muted" style="font-size:12px;margin:0 0 12px 0">
37
+ <strong>Enforcement</strong>: controls whether the pre-commit hook blocks commits (strict), warns only (warn), or skips checks (off).<br>
38
+ <strong>Topology</strong>: controls whether the repo syncs org policy from the command post (policy-synced) or operates independently (standalone).
39
+ </p>
40
+ <table class="data-table">
41
+ <thead>
42
+ <tr>
43
+ <th>Repo</th>
44
+ <th>Enforcement</th>
45
+ <th>Topology</th>
46
+ </tr>
47
+ </thead>
48
+ <tbody>
49
+ `;
50
+
51
+ for (const repo of repos) {
52
+ const name = repo.name || "";
53
+ const accessible = repo.accessible !== false;
54
+ html += `
55
+ <tr>
56
+ <td>${escHtml(name)}</td>
57
+ <td>
58
+ <select class="enforce-select" data-repo="${escHtml(name)}" ${accessible ? "" : "disabled"}>
59
+ <option value="strict">strict</option>
60
+ <option value="warn">warn</option>
61
+ <option value="off">off</option>
62
+ </select>
63
+ <span class="enforce-status"></span>
64
+ ${accessible ? "" : '<span class="muted" style="font-size:11px"> (not accessible)</span>'}
65
+ </td>
66
+ <td>
67
+ <select class="topology-select" data-repo="${escHtml(name)}" ${accessible ? "" : "disabled"}>
68
+ <option value="policy-synced">policy-synced</option>
69
+ <option value="standalone">standalone</option>
70
+ <option value="inconsistent" disabled>inconsistent (needs repair)</option>
71
+ </select>
72
+ <span class="topology-status"></span>
73
+ ${standalone ? '<span class="muted" style="font-size:11px"> (no command post)</span>' : ""}
74
+ </td>
75
+ </tr>
76
+ `;
77
+ }
78
+
79
+ html += `</tbody></table></div>`;
80
+ } else {
81
+ html += `<div class="section"><p class="muted">No repos registered.</p></div>`;
82
+ }
83
+
84
+ container.innerHTML = html;
85
+
86
+ // Load current values from each repo
87
+ container.querySelectorAll(".enforce-select").forEach(select => {
88
+ const repoName = select.dataset.repo;
89
+ fetch(`/api/repo/${encodeURIComponent(repoName)}`)
90
+ .then(r => r.json())
91
+ .then(repoData => {
92
+ const level = (repoData.config || {}).enforcement_level || "strict";
93
+ select.value = level;
94
+ // Set topology — show inconsistent if that's the actual state
95
+ const topoSelect = container.querySelector(`.topology-select[data-repo="${repoName}"]`);
96
+ if (topoSelect && repoData.topology) {
97
+ if (repoData.topology === "inconsistent") {
98
+ // Enable the inconsistent option so it can be displayed
99
+ const inconsistentOpt = topoSelect.querySelector('option[value="inconsistent"]');
100
+ if (inconsistentOpt) inconsistentOpt.disabled = false;
101
+ topoSelect.value = "inconsistent";
102
+ const statusSpan = topoSelect.nextElementSibling;
103
+ if (statusSpan) {
104
+ statusSpan.textContent = " needs repair";
105
+ statusSpan.style.color = "var(--color-drifted, orange)";
106
+ }
107
+ } else {
108
+ topoSelect.value = repoData.topology;
109
+ }
110
+ }
111
+ })
112
+ .catch(() => {});
113
+
114
+ select.addEventListener("change", async function () {
115
+ const statusSpan = this.nextElementSibling;
116
+ try {
117
+ const resp = await fetch(`/api/repo/${encodeURIComponent(repoName)}/config`, {
118
+ method: "POST",
119
+ headers: { "Content-Type": "application/json", "X-Gator-Dashboard": "1" },
120
+ body: JSON.stringify({ enforcement_level: this.value }),
121
+ });
122
+ const result = await resp.json();
123
+ statusSpan.textContent = result.status === "ok" ? " saved" : " error";
124
+ statusSpan.style.color = result.status === "ok" ? "var(--color-healthy)" : "var(--color-critical)";
125
+ setTimeout(() => { statusSpan.textContent = ""; }, 2000);
126
+ } catch (err) {
127
+ statusSpan.textContent = " error";
128
+ statusSpan.style.color = "var(--color-critical)";
129
+ }
130
+ });
131
+ });
132
+
133
+ // Topology toggle handler
134
+ container.querySelectorAll(".topology-select").forEach(select => {
135
+ const repoName = select.dataset.repo;
136
+ select.addEventListener("change", async function () {
137
+ const statusSpan = this.nextElementSibling;
138
+ const newTopology = this.value;
139
+
140
+ if (newTopology === "standalone") {
141
+ if (!confirm(`Switch ${repoName} to standalone? This will remove the command post link and policy sync.`)) {
142
+ // Revert select
143
+ this.value = "policy-synced";
144
+ return;
145
+ }
146
+ }
147
+
148
+ try {
149
+ const resp = await fetch(`/api/repo/${encodeURIComponent(repoName)}/topology`, {
150
+ method: "POST",
151
+ headers: { "Content-Type": "application/json", "X-Gator-Dashboard": "1" },
152
+ body: JSON.stringify({ topology: newTopology }),
153
+ });
154
+ const result = await resp.json();
155
+ if (result.status === "ok") {
156
+ statusSpan.textContent = ` ${result.topology}`;
157
+ statusSpan.style.color = "var(--color-healthy)";
158
+ setTimeout(() => { statusSpan.textContent = ""; }, 3000);
159
+ } else {
160
+ statusSpan.textContent = ` ${result.error || "error"}`;
161
+ statusSpan.style.color = "var(--color-critical)";
162
+ // Revert select on failure
163
+ this.value = newTopology === "standalone" ? "policy-synced" : "standalone";
164
+ }
165
+ } catch (err) {
166
+ statusSpan.textContent = " error";
167
+ statusSpan.style.color = "var(--color-critical)";
168
+ this.value = newTopology === "standalone" ? "policy-synced" : "standalone";
169
+ }
170
+ });
171
+ });
172
+ };
173
+ })();
@@ -0,0 +1,308 @@
1
+ /**
2
+ * updates.js — Updates view for Gator Dashboard.
3
+ *
4
+ * Self-update control for the local gator-command repo.
5
+ * Checks upstream (GitHub) for new commits and pulls them down.
6
+ *
7
+ * Data sources:
8
+ * GET /api/updates/check — read-only local ref comparison (no network)
9
+ * POST /api/updates/fetch — git fetch origin (network, state-changing)
10
+ * POST /api/updates/pull — git pull to apply upstream changes
11
+ *
12
+ * Primary question answered: is the local gator-command up to date?
13
+ */
14
+
15
+ (function () {
16
+ "use strict";
17
+
18
+ window.GatorViews = window.GatorViews || {};
19
+
20
+ function escHtml(str) {
21
+ return String(str)
22
+ .replace(/&/g, "&amp;")
23
+ .replace(/</g, "&lt;")
24
+ .replace(/>/g, "&gt;")
25
+ .replace(/"/g, "&quot;");
26
+ }
27
+
28
+ window.GatorViews.updates = function (data, container) {
29
+ // Snapshot mode — no server, no updates possible
30
+ if (window.GATOR_SNAPSHOT) {
31
+ container.innerHTML = `
32
+ <div class="view-header">
33
+ <span class="view-title">Updates</span>
34
+ </div>
35
+ <p class="muted" style="padding:24px; text-align:center;">
36
+ Updates are not available in snapshot mode.
37
+ </p>`;
38
+ return;
39
+ }
40
+
41
+ container.innerHTML = `
42
+ <div class="view-header">
43
+ <span class="view-title">Updates</span>
44
+ <span class="view-subtitle">Gator command post self-update</span>
45
+ <button class="update-btn" id="upd-restart-btn" style="margin-left:auto; padding:6px 16px; font-size:13px;">
46
+ Restart Dashboard
47
+ </button>
48
+ </div>
49
+
50
+ <div class="card-row">
51
+ <div class="card">
52
+ <div class="card-label">Local version</div>
53
+ <div class="card-value" id="upd-local-version">…</div>
54
+ <div class="card-note" id="upd-local-hash"></div>
55
+ </div>
56
+ <div class="card">
57
+ <div class="card-label">Available upstream</div>
58
+ <div class="card-value" id="upd-upstream-count">…</div>
59
+ <div class="card-note" id="upd-upstream-note"></div>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="section" id="upd-actions">
64
+ <button class="update-btn" id="upd-check-btn" style="padding:6px 16px; font-size:13px;">
65
+ Check for updates
66
+ </button>
67
+ <button class="update-btn" id="upd-pull-btn" style="padding:6px 16px; font-size:13px; margin-left:8px; display:none;">
68
+ Pull &amp; apply
69
+ </button>
70
+ <span id="upd-status" style="margin-left:12px; font-size:13px;"></span>
71
+ </div>
72
+
73
+ <div class="section" id="upd-commits-section" style="display:none;">
74
+ <div class="section-title">Available commits</div>
75
+ <div id="upd-commits-list"></div>
76
+ </div>
77
+
78
+ <div class="section" id="upd-result-section" style="display:none;">
79
+ <div class="section-title">Pull result</div>
80
+ <div id="upd-result"></div>
81
+ </div>
82
+
83
+ <div id="upd-restart-banner" style="display:none;" class="snapshot-note">
84
+ Dashboard server files were updated. Click <strong>Restart Dashboard</strong> above to apply server changes, or restart manually.<br>
85
+ <span class="muted" style="font-size:11px;">Frontend changes (CSS/JS/HTML) are already live — refresh the browser to see them.</span>
86
+ </div>
87
+
88
+ <div id="upd-restart-overlay" style="display:none; position:fixed; inset:0; background:rgba(255,255,255,0.92); z-index:9999; display:none; align-items:center; justify-content:center;">
89
+ <div style="text-align:center; font-family:var(--mono); font-size:14px; color:var(--color-muted);">
90
+ <div style="font-size:18px; margin-bottom:8px;">Restarting Dashboard…</div>
91
+ <div id="upd-restart-status">Waiting for server</div>
92
+ </div>
93
+ </div>
94
+ `;
95
+
96
+ const checkBtn = document.getElementById("upd-check-btn");
97
+ const pullBtn = document.getElementById("upd-pull-btn");
98
+ const statusSpan = document.getElementById("upd-status");
99
+ const localVer = document.getElementById("upd-local-version");
100
+ const localHash = document.getElementById("upd-local-hash");
101
+ const upCount = document.getElementById("upd-upstream-count");
102
+ const upNote = document.getElementById("upd-upstream-note");
103
+ const commitsSection = document.getElementById("upd-commits-section");
104
+ const commitsList = document.getElementById("upd-commits-list");
105
+ const resultSection = document.getElementById("upd-result-section");
106
+ const resultDiv = document.getElementById("upd-result");
107
+ const restartBanner = document.getElementById("upd-restart-banner");
108
+
109
+ // ── check for updates ────────────────────────────────────────────────────
110
+
111
+ async function loadLocalStatus() {
112
+ // Read-only GET — no network, no state change
113
+ const resp = await fetch("/api/updates/check");
114
+ return resp.json();
115
+ }
116
+
117
+ async function checkForUpdates() {
118
+ checkBtn.disabled = true;
119
+ checkBtn.textContent = "Fetching…";
120
+ statusSpan.textContent = "";
121
+ pullBtn.style.display = "none";
122
+ commitsSection.style.display = "none";
123
+ resultSection.style.display = "none";
124
+
125
+ try {
126
+ // POST to fetch from upstream (state-changing, requires auth header)
127
+ const fetchResp = await fetch("/api/updates/fetch", {
128
+ method: "POST",
129
+ headers: { "X-Gator-Dashboard": "1" },
130
+ });
131
+ const info = await fetchResp.json();
132
+
133
+ if (info.error) {
134
+ statusSpan.textContent = "✗ " + info.error;
135
+ statusSpan.style.color = "var(--color-critical)";
136
+ return;
137
+ }
138
+
139
+ // Populate cards
140
+ localVer.textContent = info.version || "—";
141
+ localHash.textContent = info.local_hash ? info.local_hash.substring(0, 8) : "";
142
+ const ahead = info.commits_available || 0;
143
+ upCount.textContent = ahead;
144
+ upNote.textContent = ahead > 0
145
+ ? `commit${ahead > 1 ? "s" : ""} behind upstream`
146
+ : "up to date";
147
+
148
+ if (ahead > 0) {
149
+ // Show available commits
150
+ commitsSection.style.display = "block";
151
+ commitsList.innerHTML = renderCommitList(info.commit_log || []);
152
+ pullBtn.style.display = "inline-block";
153
+ statusSpan.textContent = "";
154
+ } else {
155
+ statusSpan.textContent = "✓ Already up to date";
156
+ statusSpan.style.color = "var(--color-healthy)";
157
+ }
158
+ } catch (err) {
159
+ statusSpan.textContent = "✗ " + err.message;
160
+ statusSpan.style.color = "var(--color-critical)";
161
+ } finally {
162
+ checkBtn.disabled = false;
163
+ checkBtn.textContent = "Check for updates";
164
+ }
165
+ }
166
+
167
+ function renderCommitList(commits) {
168
+ if (!commits.length) return '<span class="muted">No details available.</span>';
169
+ let html = '<table class="data-table"><thead><tr><th>Hash</th><th>Message</th></tr></thead><tbody>';
170
+ for (const c of commits) {
171
+ html += `<tr>
172
+ <td class="mono" style="width:80px">${escHtml((c.hash || "").substring(0, 8))}</td>
173
+ <td>${escHtml(c.message || "")}</td>
174
+ </tr>`;
175
+ }
176
+ html += "</tbody></table>";
177
+ return html;
178
+ }
179
+
180
+ // ── pull & apply ─────────────────────────────────────────────────────────
181
+
182
+ async function pullUpdates() {
183
+ pullBtn.disabled = true;
184
+ pullBtn.textContent = "Pulling…";
185
+ statusSpan.textContent = "";
186
+ statusSpan.style.color = "";
187
+
188
+ try {
189
+ const resp = await fetch("/api/updates/pull", {
190
+ method: "POST",
191
+ headers: { "X-Gator-Dashboard": "1" },
192
+ });
193
+ const info = await resp.json();
194
+
195
+ resultSection.style.display = "block";
196
+
197
+ if (info.error) {
198
+ resultDiv.innerHTML = `<div class="error-block">${escHtml(info.error)}</div>`;
199
+ statusSpan.textContent = "✗ Pull failed";
200
+ statusSpan.style.color = "var(--color-critical)";
201
+ return;
202
+ }
203
+
204
+ resultDiv.innerHTML = `<pre style="font-size:12px; font-family:var(--mono); white-space:pre-wrap; padding:12px; background:#f8f8f6; border:1px solid var(--color-border); border-radius:4px;">${escHtml(info.output || "Done")}</pre>`;
205
+
206
+ if (info.restart_needed) {
207
+ restartBanner.style.display = "block";
208
+ statusSpan.textContent = "✓ Updated — restart required";
209
+ statusSpan.style.color = "var(--color-drifted)";
210
+ } else {
211
+ statusSpan.textContent = "✓ Updated";
212
+ statusSpan.style.color = "var(--color-healthy)";
213
+ }
214
+
215
+ // Hide pull button, refresh cards
216
+ pullBtn.style.display = "none";
217
+ commitsSection.style.display = "none";
218
+ upCount.textContent = "0";
219
+ upNote.textContent = "up to date";
220
+ if (info.new_hash) {
221
+ localHash.textContent = info.new_hash.substring(0, 8);
222
+ }
223
+
224
+ } catch (err) {
225
+ statusSpan.textContent = "✗ " + err.message;
226
+ statusSpan.style.color = "var(--color-critical)";
227
+ } finally {
228
+ pullBtn.disabled = false;
229
+ pullBtn.textContent = "Pull & apply";
230
+ }
231
+ }
232
+
233
+ // ── restart dashboard ───────────────────────────────────────────────────
234
+
235
+ const restartBtn = document.getElementById("upd-restart-btn");
236
+ const restartOverlay = document.getElementById("upd-restart-overlay");
237
+ const restartStatus = document.getElementById("upd-restart-status");
238
+
239
+ async function restartDashboard() {
240
+ restartBtn.disabled = true;
241
+ restartBtn.textContent = "Restarting…";
242
+
243
+ // Show overlay
244
+ restartOverlay.style.display = "flex";
245
+ restartStatus.textContent = "Sending restart signal…";
246
+
247
+ try {
248
+ await fetch("/api/restart", {
249
+ method: "POST",
250
+ headers: { "X-Gator-Dashboard": "1" },
251
+ });
252
+ } catch (_) {
253
+ // Expected — server dies before response completes
254
+ }
255
+
256
+ // Poll until new server is ready
257
+ restartStatus.textContent = "Waiting for server…";
258
+ let attempts = 0;
259
+ const maxAttempts = 30; // 30 seconds max
260
+
261
+ const poll = setInterval(async () => {
262
+ attempts++;
263
+ try {
264
+ const resp = await fetch("/api/updates/check");
265
+ if (resp.ok) {
266
+ clearInterval(poll);
267
+ restartStatus.textContent = "Server is back. Reloading…";
268
+ setTimeout(() => window.location.reload(), 500);
269
+ }
270
+ } catch (_) {
271
+ // Server not ready yet
272
+ restartStatus.textContent = `Waiting for server… (${attempts}s)`;
273
+ }
274
+ if (attempts >= maxAttempts) {
275
+ clearInterval(poll);
276
+ restartOverlay.style.display = "none";
277
+ restartBtn.disabled = false;
278
+ restartBtn.textContent = "Restart Dashboard";
279
+ statusSpan.textContent = "✗ Restart timed out — restart manually";
280
+ statusSpan.style.color = "var(--color-critical)";
281
+ }
282
+ }, 1000);
283
+ }
284
+
285
+ // ── wire up ──────────────────────────────────────────────────────────────
286
+
287
+ checkBtn.addEventListener("click", checkForUpdates);
288
+ pullBtn.addEventListener("click", pullUpdates);
289
+ restartBtn.addEventListener("click", restartDashboard);
290
+
291
+ // Auto-load: read-only local status only (no network fetch)
292
+ loadLocalStatus().then(info => {
293
+ if (info.error) return;
294
+ localVer.textContent = info.version || "—";
295
+ localHash.textContent = info.local_hash ? info.local_hash.substring(0, 8) : "";
296
+ const ahead = info.commits_available || 0;
297
+ upCount.textContent = ahead;
298
+ upNote.textContent = ahead > 0
299
+ ? `commit${ahead > 1 ? "s" : ""} behind upstream (last fetch)`
300
+ : "up to date (last fetch)";
301
+ if (ahead > 0) {
302
+ commitsSection.style.display = "block";
303
+ commitsList.innerHTML = renderCommitList(info.commit_log || []);
304
+ pullBtn.style.display = "inline-block";
305
+ }
306
+ }).catch(() => {});
307
+ };
308
+ })();
@@ -0,0 +1,22 @@
1
+ # Memex Enforcer Audit
2
+
3
+ You are the **enforcer** for this Memex audit. You are **read-only**. Do not edit files. Produce a report.
4
+
5
+ ## What to Read
6
+
7
+ 1. [`constitution.md`](../../constitution.md)
8
+ 3. The current `gator-command/` knowledge graph
9
+ 4. Any referenced artifacts needed to verify claims or links
10
+
11
+ ## What to Check
12
+
13
+ - thread staleness
14
+ - cross-reference integrity
15
+ - contradictions between threads, identity, mission, roadmap, and issues
16
+ - charter accuracy and drift (if this Memex includes code charters)
17
+ - constitutional compliance
18
+ - graph-health / compression risks
19
+
20
+ ## Output
21
+
22
+ Produce a structured audit report with clear findings and severity. Do not modify the Memex. The primary agent and PI decide what to act on.