exim-hub-registry 1.0.1 → 1.0.2

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 (3) hide show
  1. package/README.md +10 -5
  2. package/package.json +1 -1
  3. package/registry.js +147 -2
package/README.md CHANGED
@@ -8,14 +8,19 @@ https://cdn.jsdelivr.net/npm/exim-hub-registry@1/registry.js
8
8
 
9
9
  ## Add or change a tool
10
10
 
11
- 1. Open `registry.js` on GitHub → pencil icon → add one line before `/*EXIM_REG_END*/` using the next free `n`.
11
+ 1. Open `registry.js` on GitHub → pencil icon → add one line before `/*EXIM_REG_END*/` using the next free `n` (never reuse a number).
12
12
  2. Commit to `main`.
13
- 3. The "Publish registry to npm" Action runs (about 1 minute). Check the **Actions** tab for a green tick.
13
+ 3. The "Publish registry to npm" Action runs (about 30 seconds). Check the **Actions** tab for a green tick.
14
14
  4. Reload any tool page: the new entry appears. (jsDelivr's cache is purged by the Action; worst case a few minutes.)
15
15
 
16
- Never reuse a slot number. Every page also carries an inline copy of the registry as a fallback, so if the CDN is unreachable the hub still works with the last patched list.
16
+ Every page also carries an inline copy of the registry as a fallback, so if the CDN is unreachable the hub still works with the last patched list.
17
17
 
18
- ## One-time setup (already done if the Action is green)
18
+ ## How publishing works (no tokens, nothing to renew)
19
+
20
+ The Action publishes to npm with **Trusted Publishing**: npm trusts this repository's `publish.yml` workflow directly (configured on npmjs.com → package `exim-hub-registry` → Settings → Trusted Publisher). There is no npm token and no GitHub secret to keep alive.
19
21
 
20
- - npm account (free) at npmjs.com, with a Granular Access Token (Packages: Read and write) saved in this repo as the secret `NPM_TOKEN`.
21
22
  - Package name `exim-hub-registry` (change it in `package.json` **and** in the URL inside the tool pages if you ever rename it).
23
+ - Version 1.0.0 was published once by hand (`npm login` + `npm publish` on 16 Sep 2026); every later version is published by the Action, which bumps the patch number automatically.
24
+ - If the Action ever goes red on "Publish", check that the Trusted Publisher entry on npmjs.com still says user `CaptRavinder`, repository `exim`, workflow `publish.yml`, with "Allow npm publish" ticked.
25
+
26
+ Check page (loads the registry from the CDN with no fallback): https://claude.ai/artifact/3e1eudbVw7oeF8UMghQyey
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exim-hub-registry",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Tool registry for Ravinder Kumar's EXIM Command Center and Hub Navigator. Served to the tool pages via jsDelivr.",
5
5
  "main": "registry.js",
6
6
  "files": [
package/registry.js CHANGED
@@ -3,8 +3,9 @@
3
3
  HOW TO ADD A TOOL: add one line before EXIM_REG_END with the next free n (never reuse a number),
4
4
  commit on GitHub → the Action publishes to npm → jsDelivr serves it → every page updates on next load.
5
5
  Keys: n = slot · l = label · e = emoji · u = URL · c = Core | Operations | Intelligence | Finance | Knowledge | Advanced | Agents
6
- Slots: 1–34 tools · 35–50 agents A-01…A-16 · 51–57 reserved A-17…A-23 · 58 Launch Checklist · 59 Finance Finder · 60–64 A-24…A-28 · 65 Cumin UK Brief · next 66 */
7
- window.EXIM_REGISTRY_VERSION = "2026-09-16.2";
6
+ Slots: 1–34 tools · 35–50 agents A-01…A-16 · 51–57 reserved A-17…A-23 · 58 Launch Checklist · 59 Finance Finder · 60–64 A-24…A-28 · 65 Cumin UK Brief · next 66
7
+ Below the list: the EXIM Nav Strip (Home · prev/next · Tools · Alt+T) that every page gets from this file — edit with care, test with `node -e` as the Action does. */
8
+ window.EXIM_REGISTRY_VERSION = "2026-09-16.3";
8
9
  window.EXIM_REGISTRY = [
9
10
  /*EXIM_REG_START*/
10
11
  {n:1,l:'HS Code & Tariff',e:'🔍',u:'https://claude.ai/code/artifact/7226049f-4253-41e7-9767-c7b1533959cc',c:'Core'},
@@ -67,3 +68,147 @@ window.EXIM_REGISTRY = [
67
68
  {n:65,l:'Cumin UK Brief',e:'🌿',u:'https://claude.ai/artifact/Utxy5aX7XJrgWKUifquUtS',c:'Intelligence'},
68
69
  /*EXIM_REG_END*/
69
70
  ];
71
+
72
+ /* ══════════════════════════════════════════════════════════════════════════════════════
73
+ EXIM NAV STRIP — shipped inside registry.js so all pages get it from one commit (added 16 Sep 2026).
74
+ What it does on a tool page: 🏠 Home · ◁ prev · [current tool ▾ list] · next ▷ · collapse.
75
+ How navigation works inside claude.ai: a page cannot change its own tab (sandboxed frame), so tools open
76
+ in ONE shared tab named "exim-tool"; whoever opened that tab (the Command Center, or the previous tool)
77
+ receives a postMessage {exim:'nav',url} and re-points the tab. Home = close this tab (returns to the opener)
78
+ or open the Command Center. Keyboard: Alt+T list · Alt+Home home · Alt+[ / Alt+] prev/next.
79
+ Skips the Command Center (n:30), which has its own navigation. Does nothing outside a browser.
80
+ ══════════════════════════════════════════════════════════════════════════════════════ */
81
+ (function(){
82
+ if (typeof document === 'undefined' || typeof location === 'undefined') return;
83
+ var R = window.EXIM_REGISTRY; if (!R || R.length < 50) return;
84
+ var HOME = 'https://claude.ai/code/artifact/70732c91-84d9-4dd7-8827-462d7d53633d';
85
+ var TAB = 'exim-tool';
86
+ function idOf(u){ var m = /artifact\/([A-Za-z0-9-]+)/.exec(u || ''); return m ? m[1].toLowerCase() : ''; }
87
+ var known = {}; for (var k = 0; k < R.length; k++) known[R[k].u] = R[k];
88
+ known[HOME] = {l:'Command Center', u:HOME, n:30};
89
+
90
+ /* shared listener: re-point the tool tab we opened (installed on every page, once) */
91
+ if (!window.__EXIM_NAV_LISTENER__) {
92
+ window.__EXIM_NAV_LISTENER__ = 1;
93
+ window.addEventListener('message', function(e){
94
+ var d = e.data; if (!d || d.exim !== 'nav' || typeof d.url !== 'string' || !known[d.url]) return;
95
+ var w = null; try { w = window.open(d.url, TAB); } catch (err) {}
96
+ if (w) { try { w.focus(); } catch (err) {} try { e.source.postMessage({exim:'ack', url:d.url}, '*'); } catch (err) {} }
97
+ });
98
+ }
99
+
100
+ /* which tool is this page? (the frame host starts with the artifact id) */
101
+ var host = (location.hostname || '').toLowerCase(), href = (location.href || '').toLowerCase(), cur = null;
102
+ for (var i = 0; i < R.length; i++) { var id = idOf(R[i].u); if (id && (host.indexOf(id) === 0 || href.indexOf('/' + id) >= 0)) { cur = R[i]; break; } }
103
+ if (cur && cur.n === 30) return; /* Command Center: no strip */
104
+ if (window.__EXIM_NAV__) return; window.__EXIM_NAV__ = 1;
105
+ if (typeof window.EXIM_NAV_OFF !== 'undefined') return; /* a page can opt out */
106
+
107
+ var list = R.filter(function(t){ return t.n !== 30; }).sort(function(a,b){ return a.n - b.n; });
108
+ var pos = -1; for (var j = 0; j < list.length; j++) if (cur && list[j].n === cur.n) pos = j;
109
+ var openerWin = null; try { openerWin = window.top.opener; } catch (e) {}
110
+ function openerAlive(){ try { return !!(openerWin && !openerWin.closed); } catch (e) { return false; } }
111
+
112
+ var pendingAck = null;
113
+ window.addEventListener('message', function(e){ var d = e.data; if (d && d.exim === 'ack' && pendingAck && d.url === pendingAck.url) { clearTimeout(pendingAck.t); pendingAck = null; } });
114
+ function fallbackOpen(u){
115
+ var w = null; try { w = window.open(u, TAB); } catch (e) {}
116
+ if (!w) { try { w = window.open(u, '_blank'); } catch (e) {} }
117
+ if (w) { try { w.focus(); } catch (e) {} } else toast('Pop-up blocked — allow pop-ups for claude.ai to move between tools');
118
+ }
119
+ function go(u){
120
+ if (!u) return;
121
+ if (openerAlive()) {
122
+ try {
123
+ openerWin.postMessage({exim:'nav', url:u}, '*');
124
+ pendingAck = {url:u, t:setTimeout(function(){ pendingAck = null; fallbackOpen(u); }, 400)};
125
+ return;
126
+ } catch (e) {}
127
+ }
128
+ fallbackOpen(u);
129
+ }
130
+ function goHome(){
131
+ // Home = bring the shared tab to the Command Center. If this tab was opened by the
132
+ // Command Center, closing it lands the user back on it; otherwise re-point to HOME.
133
+ if (openerAlive()) {
134
+ try { window.top.close(); } catch (e) {}
135
+ setTimeout(function(){ go(HOME); }, 350); // if close was ignored, navigate instead
136
+ return;
137
+ }
138
+ go(HOME);
139
+ }
140
+
141
+ /* any link on the page that points at a registry tool goes through the shared tab too */
142
+ document.addEventListener('click', function(e){
143
+ if (e.defaultPrevented || e.button !== 0 || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
144
+ var a = e.target && e.target.closest ? e.target.closest('a[href]') : null; if (!a) return;
145
+ var u = a.href; if (!known[u] || a.closest('#exim-nav')) return;
146
+ e.preventDefault(); e.stopPropagation();
147
+ if (known[u].n === 30) goHome(); else go(u);
148
+ }, true);
149
+
150
+ /* ── UI ── */
151
+ var css = '#exim-nav{position:fixed;left:50%;bottom:10px;transform:translateX(-50%);z-index:2147483000;display:flex;align-items:center;gap:2px;padding:4px;border-radius:999px;background:rgba(255,255,255,.92);color:#1B222B;border:1px solid rgba(0,0,0,.12);box-shadow:0 6px 24px rgba(0,0,0,.18);font:13px/1 system-ui,-apple-system,"Segoe UI",sans-serif;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);max-width:calc(100vw - 16px)}'
152
+ + '#exim-nav button{appearance:none;border:0;background:transparent;color:inherit;font:inherit;padding:7px 10px;border-radius:999px;cursor:pointer;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;line-height:1}'
153
+ + '#exim-nav button:hover{background:rgba(0,0,0,.07)}#exim-nav button:disabled{opacity:.35;cursor:default}#exim-nav button:disabled:hover{background:transparent}'
154
+ + '#exim-nav .cur{font-weight:600;max-width:46vw;overflow:hidden;text-overflow:ellipsis}#exim-nav .cur small{font-weight:500;opacity:.6}'
155
+ + '#exim-nav .sep{width:1px;height:18px;background:rgba(0,0,0,.12);margin:0 2px}'
156
+ + '#exim-nav.min{padding:3px}#exim-nav.min > *:not(.expand){display:none}#exim-nav .expand{display:none}#exim-nav.min .expand{display:inline-flex}'
157
+ + '#exim-nav-list{position:fixed;left:50%;bottom:58px;transform:translateX(-50%);z-index:2147483000;width:min(560px,calc(100vw - 16px));max-height:min(70vh,560px);display:none;flex-direction:column;background:#fff;color:#1B222B;border:1px solid rgba(0,0,0,.12);border-radius:14px;box-shadow:0 12px 40px rgba(0,0,0,.25);font:13px/1.35 system-ui,-apple-system,"Segoe UI",sans-serif;overflow:hidden}'
158
+ + '#exim-nav-list.open{display:flex}#exim-nav-list input{margin:10px 10px 6px;padding:8px 10px;border:1px solid rgba(0,0,0,.15);border-radius:8px;font:inherit;background:transparent;color:inherit;outline:none}#exim-nav-list input:focus{border-color:#D97706}'
159
+ + '#exim-nav-list .grid{overflow:auto;padding:0 6px 8px;display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:2px}'
160
+ + '#exim-nav-list .cat{grid-column:1/-1;font-size:10px;letter-spacing:.08em;text-transform:uppercase;opacity:.55;padding:10px 6px 2px}'
161
+ + '#exim-nav-list a{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:8px;color:inherit;text-decoration:none;cursor:pointer}#exim-nav-list a:hover{background:rgba(0,0,0,.06)}#exim-nav-list a.here{background:rgba(217,119,6,.12)}'
162
+ + '#exim-nav-list a .n{font:11px ui-monospace,Menlo,Consolas,monospace;opacity:.5;min-width:20px}#exim-nav-list a.hide{display:none}#exim-nav-list .foot{padding:6px 12px 10px;font-size:11px;opacity:.55;border-top:1px solid rgba(0,0,0,.08)}'
163
+ + '#exim-nav-toast{position:fixed;left:50%;bottom:64px;transform:translateX(-50%);z-index:2147483001;background:#1B222B;color:#fff;padding:8px 14px;border-radius:8px;font:13px system-ui,sans-serif;box-shadow:0 6px 20px rgba(0,0,0,.3)}'
164
+ + '@media (prefers-color-scheme:dark){#exim-nav{background:rgba(24,29,36,.94);color:#E5E9EE;border-color:rgba(255,255,255,.14)}#exim-nav button:hover{background:rgba(255,255,255,.1)}#exim-nav .sep{background:rgba(255,255,255,.16)}#exim-nav-list{background:#181D24;color:#E5E9EE;border-color:rgba(255,255,255,.14)}#exim-nav-list input{border-color:rgba(255,255,255,.2)}#exim-nav-list a:hover{background:rgba(255,255,255,.08)}#exim-nav-list a.here{background:rgba(245,158,11,.2)}#exim-nav-list .foot{border-color:rgba(255,255,255,.1)}}'
165
+ + '@media print{#exim-nav,#exim-nav-list{display:none!important}}';
166
+ var CATS = ['Core','Operations','Intelligence','Finance','Knowledge','Advanced','Agents'];
167
+ function esc(s){ return String(s).replace(/[&<>"]/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
168
+ function toast(msg){ var t = document.getElementById('exim-nav-toast'); if (!t) { t = document.createElement('div'); t.id = 'exim-nav-toast'; document.body.appendChild(t); } t.textContent = msg; clearTimeout(t._t); t._t = setTimeout(function(){ t.remove(); }, 3500); }
169
+ var minKey = 'exim_nav_min';
170
+ function mount(){
171
+ if (document.getElementById('exim-nav')) return;
172
+ var st = document.createElement('style'); st.textContent = css; document.head.appendChild(st);
173
+ var nav = document.createElement('nav'); nav.id = 'exim-nav'; nav.setAttribute('aria-label', 'EXIM tools navigation');
174
+ var prev = pos > 0 ? list[pos - 1] : null, next = (pos >= 0 && pos < list.length - 1) ? list[pos + 1] : null;
175
+ nav.innerHTML =
176
+ '<button class="expand" title="Show EXIM navigation" aria-label="Show EXIM navigation">⚡</button>'
177
+ + '<button data-act="home" title="Command Center (Alt+Home)">🏠<span>Home</span></button><span class="sep"></span>'
178
+ + '<button data-act="prev" title="' + (prev ? esc('Previous: #' + prev.n + ' ' + prev.l) : 'Previous tool') + ' (Alt+[)"' + (prev ? '' : ' disabled') + '>◁</button>'
179
+ + '<button data-act="list" class="cur" title="All tools (Alt+T)" aria-haspopup="true" aria-expanded="false">' + (cur ? esc(cur.e + ' ' + cur.l) + ' <small>#' + cur.n + '</small>' : '⚡ EXIM tools') + ' ▾</button>'
180
+ + '<button data-act="next" title="' + (next ? esc('Next: #' + next.n + ' ' + next.l) : 'Next tool') + ' (Alt+])"' + (next ? '' : ' disabled') + '>▷</button><span class="sep"></span>'
181
+ + '<button data-act="min" title="Collapse" aria-label="Collapse navigation">–</button>';
182
+ document.body.appendChild(nav);
183
+ var panel = document.createElement('div'); panel.id = 'exim-nav-list'; panel.setAttribute('role', 'dialog'); panel.setAttribute('aria-label', 'All EXIM tools');
184
+ var html = '<input type="search" placeholder="Search ' + list.length + ' tools… (type, then Enter opens the first match)" aria-label="Search tools"><div class="grid">';
185
+ for (var c = 0; c < CATS.length; c++) {
186
+ var items = list.filter(function(t){ return t.c === CATS[c]; }); if (!items.length) continue;
187
+ html += '<div class="cat" data-cat="' + CATS[c] + '">' + CATS[c] + ' · ' + items.length + '</div>';
188
+ for (var q = 0; q < items.length; q++) { var t = items[q]; html += '<a href="' + esc(t.u) + '" data-n="' + t.n + '"' + (cur && t.n === cur.n ? ' class="here"' : '') + '><span class="n">' + String(t.n).padStart(2, '0') + '</span><span>' + esc(t.e) + '</span><span>' + esc(t.l) + '</span></a>'; }
189
+ }
190
+ html += '</div><div class="foot">Registry v' + esc(window.EXIM_REGISTRY_VERSION || '') + ' · tools open in one shared tab · 🏠 returns to the Command Center · Alt+T list · Alt+[ ] prev/next</div>';
191
+ panel.innerHTML = html; document.body.appendChild(panel);
192
+ var search = panel.querySelector('input');
193
+ function filter(){ var qv = search.value.trim().toLowerCase(); var rows = panel.querySelectorAll('a'); var vis = {};
194
+ for (var r = 0; r < rows.length; r++) { var a = rows[r]; var hit = !qv || a.textContent.toLowerCase().indexOf(qv) >= 0; a.classList.toggle('hide', !hit); if (hit) vis[known[a.href] ? known[a.href].c : ''] = 1; }
195
+ var cats = panel.querySelectorAll('.cat'); for (var s = 0; s < cats.length; s++) cats[s].style.display = vis[cats[s].getAttribute('data-cat')] ? '' : 'none'; }
196
+ search.addEventListener('input', filter);
197
+ search.addEventListener('keydown', function(e){ if (e.key === 'Enter') { var first = panel.querySelector('a:not(.hide)'); if (first) { e.preventDefault(); toggle(false); go(first.href); } } if (e.key === 'Escape') toggle(false); });
198
+ panel.addEventListener('click', function(e){ var a = e.target.closest('a[href]'); if (!a) return; e.preventDefault(); toggle(false); go(a.href); });
199
+ function toggle(force){ var open = typeof force === 'boolean' ? force : !panel.classList.contains('open'); panel.classList.toggle('open', open); nav.querySelector('[data-act=list]').setAttribute('aria-expanded', open ? 'true' : 'false'); if (open) { search.value = ''; filter(); setTimeout(function(){ search.focus(); }, 30); } }
200
+ nav.addEventListener('click', function(e){ var b = e.target.closest('button'); if (!b) return;
201
+ if (b.classList.contains('expand')) { nav.classList.remove('min'); try { localStorage.removeItem(minKey); } catch (err) {} return; }
202
+ var act = b.getAttribute('data-act');
203
+ if (act === 'home') goHome(); else if (act === 'prev' && prev) go(prev.u); else if (act === 'next' && next) go(next.u);
204
+ else if (act === 'list') toggle(); else if (act === 'min') { toggle(false); nav.classList.add('min'); try { localStorage.setItem(minKey, '1'); } catch (err) {} } });
205
+ document.addEventListener('keydown', function(e){ if (!e.altKey || e.ctrlKey || e.metaKey) return; var k = e.key;
206
+ if (k === 't' || k === 'T') { e.preventDefault(); nav.classList.remove('min'); toggle(); }
207
+ else if (k === 'Home') { e.preventDefault(); goHome(); }
208
+ else if (k === '[' && prev) { e.preventDefault(); go(prev.u); }
209
+ else if (k === ']' && next) { e.preventDefault(); go(next.u); } });
210
+ document.addEventListener('click', function(e){ if (panel.classList.contains('open') && !panel.contains(e.target) && !nav.contains(e.target)) toggle(false); });
211
+ try { if (localStorage.getItem(minKey) === '1') nav.classList.add('min'); } catch (e) {}
212
+ }
213
+ if (document.body) mount(); else document.addEventListener('DOMContentLoaded', mount);
214
+ })();