← back to Agent Cabinet
Approve auto-commits cabinet.yaml (path-limited, local, Steve+Claude co-author); commit hash surfaced in toast
2f295b3a5e692bafe69ec0e7944e17e4fda4c493 · 2026-06-16 15:50:29 -0700 · SteveStudio2
Files touched
M pyramid.htmlM server.js
Diff
commit 2f295b3a5e692bafe69ec0e7944e17e4fda4c493
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Tue Jun 16 15:50:29 2026 -0700
Approve auto-commits cabinet.yaml (path-limited, local, Steve+Claude co-author); commit hash surfaced in toast
---
pyramid.html | 2 +-
server.js | 32 ++++++++++++++++++++++++++------
2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/pyramid.html b/pyramid.html
index 29889dd..c721e57 100644
--- a/pyramid.html
+++ b/pyramid.html
@@ -507,7 +507,7 @@ async function decide(key,action){
if(!r.ok){ toast('failed: '+(r.error||'?')); return; }
SUG_STATE=r.decisions||SUG_STATE; drawCross();
const g=SUGGEST.find(x=>sKey(x)===key)||{};
- toast(action==='approve'?(r.cabinet&&r.cabinet.already?'already in cabinet.yaml':'✓ approved — added under '+offName(g.to)+' in cabinet.yaml'):action==='remove'?'✕ suggestion removed':'↺ decision reset');
+ toast(action==='approve'?(r.cabinet&&r.cabinet.already?'already in cabinet.yaml':('✓ approved — committed '+(r.commit||'(no hash)')+' · added under '+offName(g.to))):action==='remove'?'✕ suggestion removed':'↺ decision reset');
if(document.getElementById('dr-title').textContent==='Cross-officer analysis') showAnalysis();
else if(action==='remove') closePanel();
else openSuggestion(key);
diff --git a/server.js b/server.js
index d484df7..3a54b99 100644
--- a/server.js
+++ b/server.js
@@ -95,6 +95,21 @@ function applyToCabinet(s) {
return { added: true };
}
+// Auto-commit ONLY cabinet.yaml (path-limited, so other dirty files aren't swept
+// in). Local commit, no push. Author = Steve, with Claude co-author trailer.
+function gitCommitCabinet(s, cb) {
+ const msg = 'cabinet: approve cross-officer ' + s.kind + ' ' + s.id + ' under ' + s.to +
+ ' (from ' + s.from + ') via pyramid\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>';
+ execFile('git', ['-C', ROOT, 'add', 'cabinet.yaml'], (e1) => {
+ if (e1) return cb(e1);
+ execFile('git', ['-C', ROOT, '-c', 'user.name=Steve Abrams', '-c', 'user.email=steve@designerwallcoverings.com',
+ 'commit', '-m', msg, '--', 'cabinet.yaml'], { timeout: 15000 }, (e2) => {
+ if (e2) return cb(e2);
+ execFile('git', ['-C', ROOT, 'rev-parse', '--short', 'HEAD'], (e3, out) => cb(e3, (out || '').trim()));
+ });
+ });
+}
+
function parseYaml(text) {
// Tiny YAML subset parser — good enough for cabinet.yaml's shape.
// Produces {president, cabinet:[{vp, domain, triggers:[], directors:[{skill?,subagent?,owns?}]}]}
@@ -592,12 +607,17 @@ const server = http.createServer((req, res) => {
if (!s) return J({ ok: false, error: 'unknown suggestion' });
if (!['approve', 'remove', 'reset'].includes(action)) return J({ ok: false, error: 'bad action' });
const st = loadSugState(); st.decisions = st.decisions || {};
- let cab;
- if (action === 'approve') { st.decisions[key] = 'approved'; cab = applyToCabinet(s); }
- else if (action === 'remove') { st.decisions[key] = 'removed'; }
- else { delete st.decisions[key]; }
- saveSugState(st);
- return J({ ok: true, action, decisions: st.decisions, cabinet: cab });
+ if (action === 'remove') { st.decisions[key] = 'removed'; saveSugState(st); return J({ ok: true, action, decisions: st.decisions }); }
+ if (action === 'reset') { delete st.decisions[key]; saveSugState(st); return J({ ok: true, action, decisions: st.decisions }); }
+ // approve: record, write into cabinet.yaml, then auto-commit (only if newly added)
+ st.decisions[key] = 'approved'; saveSugState(st);
+ const cab = applyToCabinet(s);
+ if (cab && cab.added) {
+ gitCommitCabinet(s, (gerr, hash) => J({ ok: true, action, decisions: st.decisions, cabinet: cab, commit: gerr ? null : hash, gitError: gerr ? String(gerr) : undefined }));
+ } else {
+ J({ ok: true, action, decisions: st.decisions, cabinet: cab });
+ }
+ return;
}
if (req.url === '/cabinet.yaml') {
← d87e58a Pyramid: clickable suggestion lines — click a dotted arrow t
·
back to Agent Cabinet
·
Suggestion lines truly clickable: amber ◆ handle at each lin e46f975 →