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.
- gator_command/__init__.py +2 -0
- gator_command/cli.py +137 -0
- gator_command/scripts/crawler.py +633 -0
- gator_command/scripts/dashboard/dashboard.css +982 -0
- gator_command/scripts/dashboard/dashboard.html +84 -0
- gator_command/scripts/dashboard/dashboard.js +419 -0
- gator_command/scripts/dashboard/views/audit.js +270 -0
- gator_command/scripts/dashboard/views/fleet.js +307 -0
- gator_command/scripts/dashboard/views/repo.js +599 -0
- gator_command/scripts/dashboard/views/settings.js +173 -0
- gator_command/scripts/dashboard/views/updates.js +308 -0
- gator_command/scripts/enforcer-prompt.md +22 -0
- gator_command/scripts/extract-claude-sessions.py +489 -0
- gator_command/scripts/extract-codex-sessions.py +477 -0
- gator_command/scripts/extract-gemini-sessions.py +410 -0
- gator_command/scripts/gator-audit.py +956 -0
- gator_command/scripts/gator-charter-draft.py +919 -0
- gator_command/scripts/gator-charter-lint.py +427 -0
- gator_command/scripts/gator-charter-verify.py +606 -0
- gator_command/scripts/gator-dashboard.py +1271 -0
- gator_command/scripts/gator-deploy.py +916 -0
- gator_command/scripts/gator-drift.py +569 -0
- gator_command/scripts/gator-enforce.py +82 -0
- gator_command/scripts/gator-fleet-intel.py +460 -0
- gator_command/scripts/gator-fleet-report.py +615 -0
- gator_command/scripts/gator-init-command-post.py +315 -0
- gator_command/scripts/gator-init.py +434 -0
- gator_command/scripts/gator-machine-id.py +153 -0
- gator_command/scripts/gator-policy-status.py +631 -0
- gator_command/scripts/gator-pulse.py +459 -0
- gator_command/scripts/gator-repo-status.py +649 -0
- gator_command/scripts/gator-session-common.py +372 -0
- gator_command/scripts/gator-session-sink.py +831 -0
- gator_command/scripts/gator-sessions.py +1244 -0
- gator_command/scripts/gator-update.py +615 -0
- gator_command/scripts/gator-version.py +38 -0
- gator_command/scripts/gator_core.py +489 -0
- gator_command/scripts/gator_remote.py +381 -0
- gator_command/scripts/gator_runtime.py +142 -0
- gator_command/scripts/gatorize-actions.sh +989 -0
- gator_command/scripts/gatorize-lib.sh +166 -0
- gator_command/scripts/gatorize-post.sh +394 -0
- gator_command/scripts/gatorize.py +1163 -0
- gator_command/scripts/gatorize.sh +185 -0
- gator_command/scripts/generate_markdown.py +212 -0
- gator_command/scripts/generate_wiki.py +424 -0
- gator_command/scripts/graph_health.py +780 -0
- gator_command/scripts/memex-lint.py +286 -0
- gator_command/scripts/memex-lint.sh +205 -0
- gator_command/scripts/memex.py +1472 -0
- gator_command/scripts/memex_formatters.py +191 -0
- gator_command/scripts/memex_state.py +236 -0
- gator_command/scripts/spawn.py +650 -0
- gator_command/templates/gator-starter/blueprints/README.md +32 -0
- gator_command/templates/gator-starter/charterignore +53 -0
- gator_command/templates/gator-starter/charters/README.md +178 -0
- gator_command/templates/gator-starter/charters/_template.md +31 -0
- gator_command/templates/gator-starter/commands/commit.md +33 -0
- gator_command/templates/gator-starter/commands/init.md +11 -0
- gator_command/templates/gator-starter/commands/update.md +5 -0
- gator_command/templates/gator-starter/constitution.md +165 -0
- gator_command/templates/gator-starter/field-guides/README.md +25 -0
- gator_command/templates/gator-starter/gator-start-up.md +119 -0
- gator_command/templates/gator-starter/procedures/charter-alignment.md +83 -0
- gator_command/templates/gator-starter/procedures/enforcer-review.md +317 -0
- gator_command/templates/gator-starter/procedures/field-guide-generation.md +176 -0
- gator_command/templates/gator-starter/procedures/knowledge-capture.md +57 -0
- gator_command/templates/gator-starter/procedures/significance-check.md +69 -0
- gator_command/templates/gator-starter/reference-notes/concierge-responses.md +535 -0
- gator_command/templates/gator-starter/reference-notes/dangerous-patterns.md +91 -0
- gator_command/templates/gator-starter/reference-notes/dashboard-operations.md +22 -0
- gator_command/templates/gator-starter/reference-notes/enforcer-configuration.md +232 -0
- gator_command/templates/gator-starter/reference-notes/example-project.md +289 -0
- gator_command/templates/gator-starter/reference-notes/failure-modes-and-self-correction.md +72 -0
- gator_command/templates/gator-starter/reference-notes/git-workflow.md +60 -0
- gator_command/templates/gator-starter/reference-notes/identity-and-ownership.md +37 -0
- gator_command/templates/gator-starter/reference-notes/refactor-approach.md +155 -0
- gator_command/templates/gator-starter/reference-notes/what-gator-requires-from-a-model.md +108 -0
- gator_command/templates/gator-starter/reference-notes/why-navigation-coding-feels-different.md +99 -0
- gator_command/templates/gator-starter/reference-notes/workflow-profiles.md +155 -0
- gator_command/templates/gator-starter/scripts/__pycache__/enforcer-review.cpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/__pycache__/gator-approve.cpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/__pycache__/gator-init.cpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/__pycache__/gator-pre-commit.cpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/__pycache__/gator-update.cpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/enforcer-prompt.md +55 -0
- gator_command/templates/gator-starter/scripts/enforcer-review.py +1551 -0
- gator_command/templates/gator-starter/scripts/gator-approve.py +139 -0
- gator_command/templates/gator-starter/scripts/gator-enforce.py +82 -0
- gator_command/templates/gator-starter/scripts/gator-init.py +434 -0
- gator_command/templates/gator-starter/scripts/gator-pre-commit.py +2670 -0
- gator_command/templates/gator-starter/scripts/gator-pulse.py +459 -0
- gator_command/templates/gator-starter/scripts/gator-update.py +615 -0
- gator_command/templates/gator-starter/scripts/gator-version.py +38 -0
- gator_command/templates/gator-starter/scripts/gator_core.py +487 -0
- gator_command/templates/gator-starter/scripts/hooks/__pycache__/commit-msgcpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/hooks/__pycache__/post-commitcpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/hooks/__pycache__/pre-commitcpython-313.pyc +0 -0
- gator_command/templates/gator-starter/scripts/hooks/commit-msg +5 -0
- gator_command/templates/gator-starter/scripts/hooks/post-commit +7 -0
- gator_command/templates/gator-starter/scripts/hooks/pre-commit +5 -0
- gator_command/templates/gator-starter/sessions/.gitignore +7 -0
- gator_command/templates/gator-starter/vault/.gitkeep +0 -0
- gator_command/templates/gator-starter/whiteboard.md +5 -0
- gator_command-1.0.0.dist-info/METADATA +122 -0
- gator_command-1.0.0.dist-info/RECORD +110 -0
- gator_command-1.0.0.dist-info/WHEEL +5 -0
- gator_command-1.0.0.dist-info/entry_points.txt +2 -0
- gator_command-1.0.0.dist-info/licenses/LICENSE +21 -0
- 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, "<")
|
|
17
|
+
.replace(/>/g, ">")
|
|
18
|
+
.replace(/"/g, """);
|
|
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, "&")
|
|
23
|
+
.replace(/</g, "<")
|
|
24
|
+
.replace(/>/g, ">")
|
|
25
|
+
.replace(/"/g, """);
|
|
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 & 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.
|