← back to Norma
chore: lint fixes (guard JSONL parses, __dirname paths, fix reshare href), v1.1.1 -> v1.1.2 (session close)
039ad5d3768d15d0bb62584ae0f078ab968fa4f6 · 2026-08-14 16:33:23 -0700 · Steve
Files touched
M agents/instagram-agent/comment-reply.jsM agents/instagram-agent/delete-originals.jsA agents/instagram-agent/gen-actions-viewer.jsM agents/instagram-agent/gen-delete-viewer.jsM agents/instagram-agent/package.json
Diff
commit 039ad5d3768d15d0bb62584ae0f078ab968fa4f6
Author: Steve <steve@designerwallcoverings.com>
Date: Fri Aug 14 16:33:23 2026 -0700
chore: lint fixes (guard JSONL parses, __dirname paths, fix reshare href), v1.1.1 -> v1.1.2 (session close)
---
agents/instagram-agent/comment-reply.js | 2 +-
agents/instagram-agent/delete-originals.js | 3 +-
agents/instagram-agent/gen-actions-viewer.js | 52 ++++++++++++++++++++++++++++
agents/instagram-agent/gen-delete-viewer.js | 8 +++--
agents/instagram-agent/package.json | 2 +-
5 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/agents/instagram-agent/comment-reply.js b/agents/instagram-agent/comment-reply.js
index 1cd962c..661f349 100644
--- a/agents/instagram-agent/comment-reply.js
+++ b/agents/instagram-agent/comment-reply.js
@@ -35,7 +35,7 @@ const g = async (url) => (await fetch(url)).json();
(async () => {
const LOG = path.join(__dirname, 'data', `comment-replies-${ACCOUNT}.jsonl`);
- const replied = new Set(fs.existsSync(LOG) ? fs.readFileSync(LOG, 'utf8').trim().split('\n').filter(Boolean).map((l) => { try { return JSON.parse(l).comment_id; } catch { return null; } }) : []);
+ const replied = new Set(fs.existsSync(LOG) ? fs.readFileSync(LOG, 'utf8').trim().split('\n').filter(Boolean).map((l) => { try { return JSON.parse(l).comment_id; } catch { return null; } }).filter(Boolean) : []);
const media2 = await g(`${H}/${V}/${ID}/media?fields=id,permalink,comments_count&limit=20&access_token=${encodeURIComponent(T)}`);
const withComments = (media2.data || []).filter((m) => (m.comments_count || 0) > 0);
diff --git a/agents/instagram-agent/delete-originals.js b/agents/instagram-agent/delete-originals.js
index 403daff..b4aa08f 100644
--- a/agents/instagram-agent/delete-originals.js
+++ b/agents/instagram-agent/delete-originals.js
@@ -43,7 +43,8 @@ if (!fs.existsSync(SRC)) {
process.exit(1);
}
const done = new Set(fs.existsSync(OUT)
- ? fs.readFileSync(OUT, 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l).old_permalink)
+ ? fs.readFileSync(OUT, 'utf8').trim().split('\n').filter(Boolean)
+ .map((l) => { try { return JSON.parse(l).old_permalink; } catch { return null; } }).filter(Boolean)
: []);
const rows = fs.readFileSync(SRC, 'utf8').trim().split('\n').filter(Boolean)
.map((l) => JSON.parse(l))
diff --git a/agents/instagram-agent/gen-actions-viewer.js b/agents/instagram-agent/gen-actions-viewer.js
new file mode 100644
index 0000000..bdc2105
--- /dev/null
+++ b/agents/instagram-agent/gen-actions-viewer.js
@@ -0,0 +1,52 @@
+const fs=require('fs');const path=require('path');
+const today=new Date().toISOString().slice(0,10);
+const rd=f=>{const P=path.join(__dirname,f);return fs.existsSync(P)?fs.readFileSync(P,'utf8').trim().split('\n').filter(Boolean).map(l=>{try{return JSON.parse(l)}catch{return null}}).filter(Boolean):[];};
+const ledger=rd('data/post-ledger.jsonl').filter(r=>(r.ts||'').slice(0,10)===today);
+const redo=rd('data/redo-results-20260814.jsonl');
+const redoSet=new Set(redo.map(r=>r.new_permalink));
+const reshares=rd('data/fabric-friday-reshares.jsonl').concat(...['designerwallcoverings','grassclothwallpaper','chinoiseriewallpaper','metallicwallpaper','suedewallpaper','fabric_fridays'].map(a=>rd(`data/reshares-${a}.jsonl`)));
+const replies=[].concat(...fs.readdirSync(path.join(__dirname,'data')).filter(f=>/^comment-replies-/.test(f)).map(f=>rd('data/'+f)));
+// classify each ledger post
+const posts=ledger.map(r=>({ts:r.ts,handle:r.handle,title:(r.product_title||'').split('|')[0].trim(),img:r.image_url,link:r.permalink,type:redoSet.has(r.permalink)?'repost (corrected)':'cadence post'}));
+const commits=fs.existsSync('/tmp/ig-commits.txt')?fs.readFileSync('/tmp/ig-commits.txt','utf8').trim().split('\n').filter(Boolean).map(l=>{const[h,ci,...m]=l.split('|');return{h,ci,msg:m.join('|')}}):[];
+const data={today,posts:posts.sort((a,b)=>b.ts.localeCompare(a.ts)),reshares,replies,commits,
+ stats:{posts:posts.length,reposts:posts.filter(p=>p.type.includes('repost')).length,reshares:reshares.length,replies:replies.length,commits:commits.length}};
+const D=JSON.stringify(data);
+const html=`<!doctype html><html><head><meta charset=utf8><meta name=viewport content="width=device-width,initial-scale=1"><title>IG Actions — ${today}</title><style>
+:root{--b:#0c0f1a;--s:#131829;--e:#1c2237;--t:#f0f0f5;--m:#a1a1b5;--p:#10b981;--a:#f59e0b;--bd:#2a3048}
+*{box-sizing:border-box}body{margin:0;background:var(--b);color:var(--t);font:14px/1.5 -apple-system,system-ui,sans-serif}
+header{padding:18px 20px;border-bottom:1px solid var(--bd);background:var(--s)}h1{margin:0 0 4px;font-size:18px}
+.sub{color:var(--m);font-size:13px}
+.stats{display:flex;gap:10px;flex-wrap:wrap;padding:14px 20px}
+.stat{background:var(--s);border:1px solid var(--bd);border-radius:10px;padding:10px 16px;min-width:90px}
+.stat b{font-size:24px;display:block;color:var(--p)}.stat span{font-size:12px;color:var(--m)}
+h2{margin:20px 20px 8px;font-size:15px;color:var(--a)}
+.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px;padding:0 20px}
+.card{background:var(--s);border:1px solid var(--bd);border-radius:10px;overflow:hidden;text-decoration:none;color:inherit;display:block}
+.thumb{width:100%;aspect-ratio:1;object-fit:cover;background:var(--e)}
+.meta{padding:8px}.h{font-size:12px;color:var(--p)}.ti{font-size:11px;color:var(--m);max-height:30px;overflow:hidden}
+.tag{display:inline-block;font-size:9px;padding:1px 5px;border-radius:4px;background:var(--e);color:var(--m);margin-top:4px}
+.tag.rp{background:#10b98122;color:var(--p)}.tag.rs{background:#f59e0b22;color:var(--a)}
+.list{padding:0 20px}.li{background:var(--s);border:1px solid var(--bd);border-radius:8px;padding:8px 12px;margin-bottom:6px;font-size:13px;display:flex;gap:10px}
+.li code{color:var(--a);font-family:ui-monospace,monospace}.t{color:var(--m);font-size:11px;white-space:nowrap}
+</style></head><body>
+<header><h1>📊 Instagram — Actions Today</h1><div class=sub id=sub></div></header>
+<div class=stats id=stats></div>
+<h2 id=postsH></h2><div class=grid id=posts></div>
+<h2 id=reshH></h2><div class=grid id=resh></div>
+<h2>🛠️ Build / config commits</h2><div class=list id=commits></div>
+<script>
+const D=${D};
+document.getElementById('sub').textContent=D.today+' · all live actions on the fleet';
+const S=D.stats;
+document.getElementById('stats').innerHTML=[['posts','posts to IG'],['reposts','corrected reposts'],['reshares','vendor reshares'],['replies','comment replies'],['commits','code commits']].map(([k,l])=>\`<div class=stat><b>\${S[k]||0}</b><span>\${l}</span></div>\`).join('');
+document.getElementById('postsH').textContent='📸 Posts to Instagram ('+D.posts.length+')';
+document.getElementById('posts').innerHTML=D.posts.map(p=>\`<a class=card href="\${p.link}" target=_blank rel=noopener><img class=thumb loading=lazy src="\${p.img||''}"><div class=meta><div class=h>@\${p.handle}</div><div class=ti>\${p.title||''}</div><span class="tag \${p.type.includes('repost')?'rp':''}">\${p.type}</span></div></a>\`).join('')||'<div class=sub style=padding:0-20px>none</div>';
+document.getElementById('reshH').textContent='🔁 Vendor reshares ('+D.reshares.length+')';
+document.getElementById('resh').innerHTML=D.reshares.map(r=>\`<a class=card href="\${r.permalink||'#'}" target=_blank rel=noopener><div class=meta><div class=h>reshared (source ↗)</div><div class=ti>\${r.permalink||r.our_media_id||''}</div><span class="tag rs">credited</span></div></a>\`).join('')||'<div class=sub style="padding:0 20px;color:#a1a1b5">none</div>';
+document.getElementById('commits').innerHTML=D.commits.map(c=>\`<div class=li><span class=t>\${(c.ci||'').slice(11,16)}</span><code>\${c.h}</code><span>\${c.msg}</span></div>\`).join('')||'<div class=sub>none</div>';
+</script></body></html>`;
+fs.mkdirSync(path.join(__dirname,'public'),{recursive:true});
+fs.writeFileSync(path.join(__dirname,'public','actions-today.html'),html);
+console.log('wrote public/actions-today.html');
+console.log('stats:',JSON.stringify(data.stats));
diff --git a/agents/instagram-agent/gen-delete-viewer.js b/agents/instagram-agent/gen-delete-viewer.js
index c386e7f..a60fb2e 100644
--- a/agents/instagram-agent/gen-delete-viewer.js
+++ b/agents/instagram-agent/gen-delete-viewer.js
@@ -1,6 +1,7 @@
const fs=require('fs');const path=require('path');
-const orig=fs.readFileSync('data/redo-originals-20260814.jsonl','utf8').trim().split('\n').map(l=>JSON.parse(l));
-const res=fs.existsSync('data/redo-results-20260814.jsonl')?fs.readFileSync('data/redo-results-20260814.jsonl','utf8').trim().split('\n').map(l=>JSON.parse(l)):[];
+const D=path.join(__dirname,'data');
+const orig=fs.readFileSync(path.join(D,'redo-originals-20260814.jsonl'),'utf8').trim().split('\n').map(l=>JSON.parse(l));
+const res=fs.existsSync(path.join(D,'redo-results-20260814.jsonl'))?fs.readFileSync(path.join(D,'redo-results-20260814.jsonl'),'utf8').trim().split('\n').map(l=>JSON.parse(l)):[];
const newBy={}; res.forEach(r=>{ if(r.old_permalink) newBy[r.old_permalink]=r.new_permalink; });
// each OLD post = a dupe to delete (skip nothing; include archived orphan too)
const posts=orig.map(o=>({handle:o.handle,title:(o.product_title||'').split('|')[0].trim(),img:o.image_url,old:o.permalink,neww:newBy[o.permalink]||null}));
@@ -63,5 +64,6 @@ function selAll(){POSTS.forEach((p,i)=>{if(!done[p.old])sel.add(i)});render()}
function selNone(){sel.clear();render()}
render();
</script></body></html>`;
-fs.writeFileSync('public/delete-viewer.html',html);
+fs.mkdirSync(path.join(__dirname,'public'),{recursive:true});
+fs.writeFileSync(path.join(__dirname,'public','delete-viewer.html'),html);
console.log('wrote public/delete-viewer.html ('+posts.length+' posts)');
diff --git a/agents/instagram-agent/package.json b/agents/instagram-agent/package.json
index e8a0ad0..b3d7dcb 100644
--- a/agents/instagram-agent/package.json
+++ b/agents/instagram-agent/package.json
@@ -1,6 +1,6 @@
{
"name": "norma-instagram-agent",
- "version": "1.1.1",
+ "version": "1.1.2",
"description": "Norma Instagram Agent — Posts, Reels, and Stories via Meta Graph API",
"main": "server.js",
"scripts": {
← aca7fab IG reshare: curate real populated community hashtags for all
·
back to Norma
·
auto-data-snapshot: 2026-08-14T17:28:57 (1 data files) — age 003881c →