scriptonia 0.6.0 → 0.7.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/scriptonia.mjs +76 -5
- package/package.json +1 -1
package/bin/scriptonia.mjs
CHANGED
|
@@ -32,7 +32,7 @@ const commands = {
|
|
|
32
32
|
add, ingest: add, push: add,
|
|
33
33
|
plan, plans, comment,
|
|
34
34
|
query, contexts, link,
|
|
35
|
-
status, logout, skill: reinstallSkill, mcp,
|
|
35
|
+
status, credits, logout, skill: reinstallSkill, mcp,
|
|
36
36
|
flow, guide: flow,
|
|
37
37
|
help: async () => usage(),
|
|
38
38
|
};
|
|
@@ -132,13 +132,19 @@ async function flow() {
|
|
|
132
132
|
const row = (n, name, desc, cmd) =>
|
|
133
133
|
console.log(` ${C.v}${n}${C.r} ${C.b}${name.padEnd(7)}${C.r} ${C.dim}${desc.padEnd(34)}${C.r} ${cmd ? C.g + cmd + C.r : ""}`);
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
const cr = o?.credits;
|
|
136
|
+
const creditStr = cr && cr.metered !== false ? ` · ${cr.plan} ${cr.used}/${cr.cap} credits` : "";
|
|
137
|
+
console.log(` ${C.dim}THE LOOP${C.r} ${C.dim}${s.total} signals · ${plansN} plans${creditStr}${C.r}`);
|
|
136
138
|
row("1", "SIGNAL", "feed customer reality (text·md·vtt)", `scriptonia add <files>`);
|
|
137
139
|
row("2", "PLAN", "issue → PLAN.md, sourced & checked", `scriptonia plan "<issue>"`);
|
|
138
140
|
row("3", "BUILD", "your agent executes PLAN.md → PR", `claude "execute PLAN.md"`);
|
|
139
141
|
row("4", "REFINE", "a note regenerates the plan", `scriptonia comment plan/<slug> "…"`);
|
|
140
142
|
|
|
141
|
-
console.log(`\n ${C.b}NEXT${C.r} ${nextStep(s, plansN, recentPlan, repo, C)}
|
|
143
|
+
console.log(`\n ${C.b}NEXT${C.r} ${nextStep(s, plansN, recentPlan, repo, C)}`);
|
|
144
|
+
if (cr && cr.metered !== false && cr.available <= 0) {
|
|
145
|
+
console.log(` ${C.w}Out of credits${C.r} ${C.dim}— ${cr.topup}${C.r}`);
|
|
146
|
+
}
|
|
147
|
+
console.log("");
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
function nextStep(s, plansN, recentPlan, repo, C) {
|
|
@@ -339,6 +345,7 @@ async function comment(args) {
|
|
|
339
345
|
body: JSON.stringify({ slug, body: text, author: flags.as ?? cfg.email }),
|
|
340
346
|
});
|
|
341
347
|
const data = await res.json().catch(() => ({}));
|
|
348
|
+
if (res.status === 402) failCredits(data);
|
|
342
349
|
if (res.status === 404) fail(`no plan "${slug}" — generate one first: scriptonia plan "<issue>"`);
|
|
343
350
|
if (!res.ok) fail(`comment failed (${res.status}): ${JSON.stringify(data).slice(0, 200)}`);
|
|
344
351
|
// Approval-chain receipt: which human note produced which plan version.
|
|
@@ -362,6 +369,7 @@ async function comment(args) {
|
|
|
362
369
|
body: JSON.stringify({ slug: target, body: text, author: flags.as ?? cfg.email }),
|
|
363
370
|
});
|
|
364
371
|
const data = await res.json().catch(() => ({}));
|
|
372
|
+
if (res.status === 402) failCredits(data);
|
|
365
373
|
if (res.status === 404) fail(`no context "${target}" — see \`scriptonia contexts\``);
|
|
366
374
|
if (!res.ok) fail(`comment failed (${res.status}): ${JSON.stringify(data)}`);
|
|
367
375
|
|
|
@@ -384,6 +392,7 @@ async function query(args) {
|
|
|
384
392
|
body: JSON.stringify({ query: q, window: flags.window, segment: flags.segment }),
|
|
385
393
|
});
|
|
386
394
|
const data = await res.json();
|
|
395
|
+
if (res.status === 402) failCredits(data);
|
|
387
396
|
if (!res.ok) fail(`query failed (${res.status}): ${JSON.stringify(data)}`);
|
|
388
397
|
|
|
389
398
|
const wantJson = flags.json !== undefined || !process.stdout.isTTY;
|
|
@@ -412,12 +421,65 @@ async function link(args) {
|
|
|
412
421
|
async function status() {
|
|
413
422
|
const cfg = loadConfig();
|
|
414
423
|
if (!cfg) { console.log("not logged in — run `scriptonia login`"); return; }
|
|
424
|
+
const active = activeCreds();
|
|
425
|
+
const C = colors();
|
|
415
426
|
console.log(`signed in as ${cfg.email}`);
|
|
416
|
-
console.log(`project ${
|
|
427
|
+
console.log(`project ${active.project}`);
|
|
428
|
+
const c = await fetchCredits(active);
|
|
429
|
+
if (c && c.metered !== false) {
|
|
430
|
+
const bar = creditBar(c.used, c.cap, C);
|
|
431
|
+
console.log(`plan ${C.b}${c.plan}${C.r}`);
|
|
432
|
+
console.log(`credits ${bar} ${c.used}/${c.cap} used · resets ${c.resets_at}`);
|
|
433
|
+
if (c.available <= 0) console.log(` ${C.w}out of credits${C.r} — ${c.topup}`);
|
|
434
|
+
else if (c.available <= Math.max(2, Math.round(c.cap * 0.2))) console.log(` ${C.dim}running low — ${c.topup}${C.r}`);
|
|
435
|
+
}
|
|
417
436
|
console.log(`endpoint ${cfg.url}`);
|
|
418
437
|
console.log(`config ${CONFIG_PATH}`);
|
|
419
438
|
}
|
|
420
439
|
|
|
440
|
+
// ── credits ───────────────────────────────────────────────────
|
|
441
|
+
async function credits() {
|
|
442
|
+
const cfg = activeCreds();
|
|
443
|
+
const C = colors();
|
|
444
|
+
const c = await fetchCredits(cfg);
|
|
445
|
+
if (!c) fail("could not load credits");
|
|
446
|
+
if (c.metered === false) { console.log(`\n ${C.dim}This project isn't metered.${C.r}\n`); return; }
|
|
447
|
+
console.log(`\n ${C.b}${c.plan.toUpperCase()}${C.r} · ${cfg.project}`);
|
|
448
|
+
console.log(` ${creditBar(c.used, c.cap, C)} ${C.b}${c.available}${C.r} of ${c.cap} credits left ${C.dim}(resets ${c.resets_at})${C.r}`);
|
|
449
|
+
console.log(`\n ${C.dim}Plans & comments cost 5 · queries 1 · adding signal is free.${C.r}`);
|
|
450
|
+
if (c.available <= 0) console.log(` ${C.w}Out of credits.${C.r} ${c.topup}`);
|
|
451
|
+
else console.log(` ${C.dim}Need more? ${c.topup}${C.r}`);
|
|
452
|
+
console.log("");
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
async function fetchCredits(cfg) {
|
|
456
|
+
try {
|
|
457
|
+
const res = await fetch(`${cfg.url}/api/credits`, { headers: { authorization: `Bearer ${cfg.token}` } });
|
|
458
|
+
if (!res.ok) return null;
|
|
459
|
+
return await res.json();
|
|
460
|
+
} catch { return null; }
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function creditBar(used, cap, C) {
|
|
464
|
+
const width = 16;
|
|
465
|
+
const frac = cap > 0 ? Math.min(1, used / cap) : 0;
|
|
466
|
+
const filled = Math.round(frac * width);
|
|
467
|
+
const color = frac >= 1 ? C.w : frac >= 0.8 ? C.w : C.g;
|
|
468
|
+
return `${color}${"█".repeat(filled)}${C.dim}${"░".repeat(width - filled)}${C.r}`;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** Render an HTTP 402 credits_exhausted body and exit. Shared by plan/query/comment. */
|
|
472
|
+
function failCredits(data) {
|
|
473
|
+
const C = colors();
|
|
474
|
+
const resets = data.resets_at ? ` (resets ${data.resets_at})` : "";
|
|
475
|
+
console.error(`\n ${C.w}✕ Out of credits${C.r} — ${data.plan}: ${data.used}/${data.cap} used this month${resets}.\n`);
|
|
476
|
+
console.error(` Your signal is safe and still being collected. Plans & queries resume`);
|
|
477
|
+
console.error(` when credits do.\n`);
|
|
478
|
+
console.error(` ${C.b}Top up:${C.r} ${data.topup}`);
|
|
479
|
+
console.error(` ${C.dim}(adding signal, sync, contexts, plans list — all still free)${C.r}\n`);
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
|
|
421
483
|
async function logout() {
|
|
422
484
|
if (fs.existsSync(CONFIG_PATH)) fs.rmSync(CONFIG_PATH);
|
|
423
485
|
console.log("logged out.");
|
|
@@ -621,8 +683,10 @@ function usage() {
|
|
|
621
683
|
scriptonia query "<topic>" quick lookup, no full plan (--json)
|
|
622
684
|
scriptonia link "<id>" a signal's full text
|
|
623
685
|
scriptonia sync write the brain to local files
|
|
686
|
+
scriptonia credits plan, balance, reset date
|
|
624
687
|
|
|
625
688
|
ACCOUNT scriptonia status | logout | skill | mcp
|
|
689
|
+
Plans & comments cost 5 credits · queries 1 · adding signal is free.
|
|
626
690
|
`);
|
|
627
691
|
}
|
|
628
692
|
|
|
@@ -798,6 +862,7 @@ async function plan(args) {
|
|
|
798
862
|
body: JSON.stringify({ issue, repo_summary: repoSummary }),
|
|
799
863
|
});
|
|
800
864
|
const data = await res.json();
|
|
865
|
+
if (res.status === 402) failCredits(data);
|
|
801
866
|
if (!res.ok) fail(`plan failed (${res.status}): ${JSON.stringify(data).slice(0, 200)}`);
|
|
802
867
|
writePlan(cfg, data, flags);
|
|
803
868
|
}
|
|
@@ -817,7 +882,13 @@ function writePlan(cfg, data, flags) {
|
|
|
817
882
|
console.log(`\n ${C.g}✓${C.r} Plan ${C.b}${data.slug}${C.r} ${C.dim}v${data.version}${C.r} → ${C.v}${out}${C.r}`);
|
|
818
883
|
console.log(` ${C.dim}${(data.sources ?? []).length} cited signal(s)${data.contradictions ? `, ${data.contradictions} unresolved contradiction(s)` : ""}${C.r}`);
|
|
819
884
|
console.log(`\n ${C.b}Hand it to your agent:${C.r} ${C.g}claude "execute PLAN.md"${C.r} ${C.dim}(or codex · opencode · hermes)${C.r}`);
|
|
820
|
-
console.log(` ${C.dim}refine:${C.r} ${C.g}scriptonia comment plan/${data.slug} "…"${C.r} ${C.dim}(rewrites PLAN.md)${C.r}
|
|
885
|
+
console.log(` ${C.dim}refine:${C.r} ${C.g}scriptonia comment plan/${data.slug} "…"${C.r} ${C.dim}(rewrites PLAN.md)${C.r}`);
|
|
886
|
+
if (data.credits) {
|
|
887
|
+
const cr = data.credits;
|
|
888
|
+
const low = cr.cap > 0 && cr.cap - cr.used <= Math.max(2, Math.round(cr.cap * 0.2));
|
|
889
|
+
console.log(` ${low ? C.w : C.dim}${cr.used}/${cr.cap} credits used this month${low ? " — top up: sathwik07@scriptonia.dev" : ""}${C.r}`);
|
|
890
|
+
}
|
|
891
|
+
console.log("");
|
|
821
892
|
}
|
|
822
893
|
|
|
823
894
|
// ── repo scan ─────────────────────────────────────────────────
|