@fonderie/cli 0.4.0 → 0.6.0
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.
- package/bin/fonderie.mjs +31 -0
- package/bin/fonderie.test.mjs +18 -0
- package/package.json +1 -1
package/bin/fonderie.mjs
CHANGED
|
@@ -328,6 +328,9 @@ const ADMIN_PAGES = {
|
|
|
328
328
|
routes: { path: '/routes', about: 'every exposed route with its guard' },
|
|
329
329
|
tokens: { path: '/access/tokens', about: 'the admin token verdict + legacy per-brick tokens' },
|
|
330
330
|
log: { path: '/activity/admin-log', about: 'who did what through the surface (--limit, --before)' },
|
|
331
|
+
user: { path: '/users', about: 'look up a user: admin user <email|id> [sessions|history|revoke-sessions|suspend|unsuspend]' },
|
|
332
|
+
catalog: { path: '/catalog', about: 'plans as configured and as stored' },
|
|
333
|
+
subscriber:{ path: '/subscriptions', about: 'admin subscriber <user|workspace> <id> [subscription|wallet|ledger]' },
|
|
331
334
|
};
|
|
332
335
|
async function adminCmd() {
|
|
333
336
|
const pageName = argv[1];
|
|
@@ -338,6 +341,32 @@ async function adminCmd() {
|
|
|
338
341
|
process.exit(2);
|
|
339
342
|
}
|
|
340
343
|
const prefix = (process.env.FONDERIE_ADMIN_PREFIX || '/_admin').replace(/\/$/, '');
|
|
344
|
+
if (pageName === 'user') {
|
|
345
|
+
// fonderie admin user <email|id> [sessions|history|revoke-sessions|suspend|unsuspend]
|
|
346
|
+
const who = argv[2]; const verb = argv[3] ?? 'show';
|
|
347
|
+
if (!who) { console.error('fonderie admin user <email|id> [sessions|history|revoke-sessions|suspend|unsuspend]'); process.exit(2); }
|
|
348
|
+
const byEmail = who.includes('@');
|
|
349
|
+
const base = byEmail ? `${prefix}/users?email=${encodeURIComponent(who)}` : `${prefix}/users/${encodeURIComponent(who)}`;
|
|
350
|
+
if (verb === 'show') return adminFetch('GET', base);
|
|
351
|
+
if (byEmail) { console.error('sessions/history/revoke-sessions/suspend/unsuspend need the user id (run `admin user <email>` first).'); process.exit(2); }
|
|
352
|
+
const sub = { sessions: ['GET', '/sessions'], history: ['GET', '/login-history'], 'revoke-sessions': ['DELETE', '/sessions'], suspend: ['POST', '/suspend'], unsuspend: ['POST', '/unsuspend'] }[verb];
|
|
353
|
+
if (!sub) { console.error(`unknown verb "${verb}"`); process.exit(2); }
|
|
354
|
+
const q = new URLSearchParams(); const limit = arg('--limit', undefined); if (limit && verb === 'history') q.set('limit', limit);
|
|
355
|
+
const qs = q.toString();
|
|
356
|
+
return adminFetch(sub[0], base + sub[1] + (qs ? `?${qs}` : ''));
|
|
357
|
+
}
|
|
358
|
+
if (pageName === 'subscriber') {
|
|
359
|
+
const type = argv[2]; const id = argv[3]; const verb = argv[4] ?? 'subscription';
|
|
360
|
+
if ((type !== 'user' && type !== 'workspace') || !id) { console.error('fonderie admin subscriber <user|workspace> <id> [subscription|wallet|ledger] [--currency <c>] [--limit <n>]'); process.exit(2); }
|
|
361
|
+
const sub = `/${type}/${encodeURIComponent(id)}`;
|
|
362
|
+
const q = new URLSearchParams(); const cur = arg('--currency', undefined); const lim = arg('--limit', undefined);
|
|
363
|
+
if (cur) q.set('currency', cur); if (lim && verb === 'ledger') q.set('limit', lim);
|
|
364
|
+
const qs = q.toString(); const tail = qs ? `?${qs}` : '';
|
|
365
|
+
if (verb === 'subscription') return adminFetch('GET', `${prefix}/subscriptions${sub}`);
|
|
366
|
+
if (verb === 'wallet') return adminFetch('GET', `${prefix}/wallet${sub}${tail}`);
|
|
367
|
+
if (verb === 'ledger') return adminFetch('GET', `${prefix}/wallet${sub}/ledger${tail}`);
|
|
368
|
+
console.error(`unknown verb "${verb}"`); process.exit(2);
|
|
369
|
+
}
|
|
341
370
|
const q = new URLSearchParams();
|
|
342
371
|
const limit = arg('--limit', undefined);
|
|
343
372
|
const before = arg('--before', undefined);
|
|
@@ -443,6 +472,8 @@ else {
|
|
|
443
472
|
fonderie template <get|set|delete|history|rollback> [type] [text] [--locale <l>] [--subject <s>] [--html <h>] ...
|
|
444
473
|
manage a live deployment over its admin API — set FONDERIE_ADMIN_URL + FONDERIE_ADMIN_TOKEN
|
|
445
474
|
fonderie admin <attention|manifest|doctor|config|routes|tokens|log> [--limit <n>] [--before <cursor>]
|
|
475
|
+
fonderie admin user <email|id> [sessions|history|revoke-sessions|suspend|unsuspend]
|
|
476
|
+
fonderie admin catalog · admin subscriber <user|workspace> <id> [subscription|wallet|ledger] [--currency <c>]
|
|
446
477
|
read a deployment's operator surface (@fonderie/admin) — same env; FONDERIE_ADMIN_PREFIX if moved
|
|
447
478
|
|
|
448
479
|
Zero deps. No MCP server. A binary + markdown that runs in any agent harness.`);
|
package/bin/fonderie.test.mjs
CHANGED
|
@@ -141,6 +141,24 @@ await (async () => {
|
|
|
141
141
|
if (!find('GET', '/_admin')) fail('admin attention: should hit the prefix root');
|
|
142
142
|
if (!find('GET', '/_admin/activity/admin-log?limit=5&before=abc')) fail('admin log: flags not forwarded');
|
|
143
143
|
if (!find('GET', '/ops/doctor')) fail('admin doctor: FONDERIE_ADMIN_PREFIX not honoured');
|
|
144
|
+
await cli(['admin', 'user', 'ada@example.com']);
|
|
145
|
+
await cli(['admin', 'user', 'u1', 'history', '--limit', '3']);
|
|
146
|
+
await cli(['admin', 'user', 'u1', 'suspend']);
|
|
147
|
+
if (!find('GET', '/_admin/users?email=ada%40example.com')) fail('admin user <email>: wrong lookup path');
|
|
148
|
+
if (!find('GET', '/_admin/users/u1/login-history?limit=3')) fail('admin user history: flags not forwarded');
|
|
149
|
+
if (!find('POST', '/_admin/users/u1/suspend')) fail('admin user suspend: wrong request');
|
|
150
|
+
await cli(['admin', 'catalog']);
|
|
151
|
+
await cli(['admin', 'subscriber', 'workspace', 'w1']);
|
|
152
|
+
await cli(['admin', 'subscriber', 'user', 'u1', 'ledger', '--currency', 'eur', '--limit', '7']);
|
|
153
|
+
if (!find('GET', '/_admin/catalog')) fail('admin catalog: wrong path');
|
|
154
|
+
if (!find('GET', '/_admin/subscriptions/workspace/w1')) fail('admin subscriber: wrong path');
|
|
155
|
+
if (!find('GET', '/_admin/wallet/user/u1/ledger?currency=eur&limit=7')) fail('admin subscriber ledger: flags not forwarded');
|
|
156
|
+
let badType = 0;
|
|
157
|
+
try { await cli(['admin', 'subscriber', 'team', 'x']); } catch (e) { badType = e.code; }
|
|
158
|
+
if (badType !== 2) fail(`admin subscriber <bad type> should exit 2, got ${badType}`);
|
|
159
|
+
let needsId = 0;
|
|
160
|
+
try { await cli(['admin', 'user', 'ada@example.com', 'suspend']); } catch (e) { needsId = e.code; }
|
|
161
|
+
if (needsId !== 2) fail(`admin user <email> suspend should exit 2, got ${needsId}`);
|
|
144
162
|
let unknown = 0;
|
|
145
163
|
try { await cli(['admin', 'nope']); } catch (e) { unknown = e.code; }
|
|
146
164
|
if (unknown !== 2) fail(`admin <unknown page> should exit 2, got ${unknown}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonderie/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The Fonderie CLI — teaches any coding agent the SDK without loading it eagerly. `fonderie skill` writes a lazy skill (a small router + per-package bodies read on demand); `fonderie query` answers what to install for a capability. Zero deps, runs anywhere.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fonderiejs",
|