@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 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.`);
@@ -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.4.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",