@modelstatus/cli 0.1.88 → 0.1.89
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/package.json +3 -2
- package/src/fix-prompt.js +22 -7
- package/src/index.js +5 -5
- package/src/tui/views/inventory.js +4 -4
- package/src/tui/views/local.js +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modelstatus/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.89",
|
|
4
4
|
"description": "Track which AI models you use, where, and never get surprised by a retirement. Free offline model-health for any repo (mm status), browser sign-in for cloud inventory + alerts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"llm",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"LICENSE"
|
|
39
39
|
],
|
|
40
40
|
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
41
|
+
"access": "public",
|
|
42
|
+
"provenance": false
|
|
42
43
|
},
|
|
43
44
|
"engines": {
|
|
44
45
|
"node": ">=18"
|
package/src/fix-prompt.js
CHANGED
|
@@ -50,6 +50,24 @@ function healthPhrase(f) {
|
|
|
50
50
|
return `${f.health}${f.retires_date ? `, retires ${f.retires_date}` : ""}`;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Dedupe + drop empty findings + sort — the rows the prompt actually renders. */
|
|
54
|
+
function buildRows(findings) {
|
|
55
|
+
return (findings || [])
|
|
56
|
+
.map((f) => ({ ...f, refs: dedupeRefs(f.refs) }))
|
|
57
|
+
.filter((f) => f.refs.length)
|
|
58
|
+
.sort((a, b) => (TIER[a.health] ?? 3) - (TIER[b.health] ?? 3)
|
|
59
|
+
|| String(a.retires_date || "9999").localeCompare(String(b.retires_date || "9999"))
|
|
60
|
+
|| String(a.slug || a.display).localeCompare(String(b.slug || b.display)));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The model/reference counts the rendered prompt will actually contain (after
|
|
64
|
+
* dedupe and empty-finding drops) — use these for any summary line or toast so
|
|
65
|
+
* it never disagrees with the prompt body. */
|
|
66
|
+
export function promptCounts(findings) {
|
|
67
|
+
const rows = buildRows(findings);
|
|
68
|
+
return { models: rows.length, refs: rows.reduce((n, f) => n + f.refs.length, 0) };
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
/**
|
|
54
72
|
* Render the prompt. `findings` = [{ slug, display, health, retires_date,
|
|
55
73
|
* replacement, refs: [{ file, line, matched, repo? }] }] where `replacement`
|
|
@@ -58,15 +76,12 @@ function healthPhrase(f) {
|
|
|
58
76
|
* usable refs are dropped; returns null when nothing remains.
|
|
59
77
|
*/
|
|
60
78
|
export function buildFixPrompt(findings, { date = new Date() } = {}) {
|
|
61
|
-
const rows = (findings
|
|
62
|
-
.map((f) => ({ ...f, refs: dedupeRefs(f.refs) }))
|
|
63
|
-
.filter((f) => f.refs.length)
|
|
64
|
-
.sort((a, b) => (TIER[a.health] ?? 3) - (TIER[b.health] ?? 3)
|
|
65
|
-
|| String(a.retires_date || "9999").localeCompare(String(b.retires_date || "9999"))
|
|
66
|
-
|| String(a.slug || a.display).localeCompare(String(b.slug || b.display)));
|
|
79
|
+
const rows = buildRows(findings);
|
|
67
80
|
if (!rows.length) return null;
|
|
68
81
|
|
|
69
|
-
|
|
82
|
+
// Local calendar date — toISOString() is UTC and stamps "tomorrow" for
|
|
83
|
+
// anyone west of Greenwich in the evening.
|
|
84
|
+
const day = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
70
85
|
const nRefs = rows.reduce((n, f) => n + f.refs.length, 0);
|
|
71
86
|
const out = [];
|
|
72
87
|
out.push("# Task: update retired / retiring AI model references");
|
package/src/index.js
CHANGED
|
@@ -792,7 +792,7 @@ async function cmdPrompt(positional, flags) {
|
|
|
792
792
|
const { getRegistry } = await import("./registry/fetch.js");
|
|
793
793
|
const { resolveLocal, computeHealth, dropResolvedFragments } = await import("./registry/local.js");
|
|
794
794
|
const { terminalReplacement } = await import("./fix.js");
|
|
795
|
-
const { buildFixPrompt } = await import("./fix-prompt.js");
|
|
795
|
+
const { buildFixPrompt, promptCounts } = await import("./fix-prompt.js");
|
|
796
796
|
const prog = startProgress(true, "fetching the model registry…");
|
|
797
797
|
const snapshot = await getRegistry({
|
|
798
798
|
offline: !!flags.offline || process.env.LLMSTATUS_REGISTRY_OFFLINE === "1",
|
|
@@ -842,9 +842,9 @@ async function cmdPrompt(positional, flags) {
|
|
|
842
842
|
return;
|
|
843
843
|
}
|
|
844
844
|
console.log(text);
|
|
845
|
-
const
|
|
845
|
+
const counts = promptCounts(findings);
|
|
846
846
|
const copyTool = process.platform === "darwin" ? "pbcopy" : process.platform === "win32" ? "clip" : "xclip -selection clipboard";
|
|
847
|
-
process.stderr.write(`\n(${
|
|
847
|
+
process.stderr.write(`\n(${counts.models} model(s), ${counts.refs} reference(s). Copy it straight to your clipboard: mm prompt | ${copyTool})\n`);
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
/** List detection sources and whether each can run right now. Live integrations
|
|
@@ -861,7 +861,7 @@ async function cmdSources(_positional, flags) {
|
|
|
861
861
|
}
|
|
862
862
|
console.log("\nScan with: mm scan --sources env,aws-secrets,k8s,helm,sql (or --sources all)");
|
|
863
863
|
console.log("Integrations (toggle with `mm integrations enable <id>`): " + INTEGRATION_IDS.join(", "));
|
|
864
|
-
console.log("Options: --region <r> · --namespace <ns> · --kube-context <c> · --db <pg-dsn> --sql-table <t>");
|
|
864
|
+
console.log("Options: --region <r> · --namespace <ns> · --kube-context <c> · --db <pg-dsn> · --sql-table <t>");
|
|
865
865
|
console.log(" --vercel-project <p> · --vercel-team <t> · --gh-repo <owner/name> · --supabase-ref <ref>");
|
|
866
866
|
console.log("Safety: secret VALUES never leave your machine — only model ids upload. Use --dry-run to preview.");
|
|
867
867
|
}
|
|
@@ -1083,7 +1083,7 @@ Scan sources (--sources; default = filesystem + enabled integrations; "all" for
|
|
|
1083
1083
|
and only ever upload model ids — secret VALUES never leave your machine.
|
|
1084
1084
|
|
|
1085
1085
|
Flags: --update · --api <url> · --key <key> · --project <id|name> · --dir <path> · --yes · --json · --ci · --dry-run
|
|
1086
|
-
--offline (use the cached registry) · --model <slug> (fix) · --fail-on <t> · --json-out <file> (ci) · --all · --force (clear)
|
|
1086
|
+
--offline (use the cached registry) · --model <slug> (fix, prompt) · --fail-on <t> · --json-out <file> (ci) · --all · --force (clear)
|
|
1087
1087
|
--sources <list> · --region <r> · --namespace <ns> · --kube-context <c> · --db <dsn> · --sql-table <t>
|
|
1088
1088
|
--vercel-project <p> · --vercel-team <t> · --gh-repo <owner/name> · --supabase-ref <ref>
|
|
1089
1089
|
|
|
@@ -112,7 +112,7 @@ export function InventoryView({ client, ui, dir = ".", active, width = 78, heigh
|
|
|
112
112
|
const dying = filtered.filter((u) => u.health && u.health !== "ok" && u.health !== "custom");
|
|
113
113
|
if (!dying.length) return ui.showToast(query ? "no matching usages need fixing" : "all current — nothing to fix", "#16a34a");
|
|
114
114
|
try {
|
|
115
|
-
const [{ terminalReplacement }, { buildFixPrompt }, { deliverText }, { computeHealth }] = await Promise.all([
|
|
115
|
+
const [{ terminalReplacement }, { buildFixPrompt, promptCounts }, { deliverText }, { computeHealth }] = await Promise.all([
|
|
116
116
|
import("../../fix.js"), import("../../fix-prompt.js"), import("../../clipboard.js"), import("../../registry/local.js"),
|
|
117
117
|
]);
|
|
118
118
|
const today = new Date();
|
|
@@ -146,10 +146,10 @@ export function InventoryView({ client, ui, dir = ".", active, width = 78, heigh
|
|
|
146
146
|
}
|
|
147
147
|
const text = buildFixPrompt([...byModel.values()], { date: today });
|
|
148
148
|
if (!text) return ui.showToast("no locatable references to hand off", "#d97706");
|
|
149
|
-
const
|
|
149
|
+
const counts = promptCounts([...byModel.values()]);
|
|
150
150
|
const res = deliverText(text);
|
|
151
|
-
if (res.method === "clipboard") ui.showToast(`${GLYPH.check} LLM fix prompt copied (${
|
|
152
|
-
else if (res.method === "file") ui.showToast(`${GLYPH.check}
|
|
151
|
+
if (res.method === "clipboard") ui.showToast(`${GLYPH.check} LLM fix prompt copied (${counts.models} model${counts.models === 1 ? "" : "s"} · ${counts.refs} refs) — paste into your AI agent`);
|
|
152
|
+
else if (res.method === "file") ui.showToast(`${GLYPH.check} couldn't copy — prompt saved to ${res.path}`);
|
|
153
153
|
else ui.showToast("couldn't copy or save the prompt", "#dc2626");
|
|
154
154
|
} catch (e) {
|
|
155
155
|
ui.showToast(e.message, "red");
|
package/src/tui/views/local.js
CHANGED
|
@@ -143,7 +143,7 @@ export function LocalView({ client, me, dir, ui, width = 78, height = 14, active
|
|
|
143
143
|
const dying = items.filter((it) => it.model && it.health !== "ok" && it.health !== "custom");
|
|
144
144
|
if (!dying.length) return ui?.showToast?.("all current — nothing to fix", "#16a34a");
|
|
145
145
|
Promise.all([import("../../fix.js"), import("../../fix-prompt.js"), import("../../clipboard.js")]).then(
|
|
146
|
-
([{ terminalReplacement }, { buildFixPrompt }, { deliverText }]) => {
|
|
146
|
+
([{ terminalReplacement }, { buildFixPrompt, promptCounts }, { deliverText }]) => {
|
|
147
147
|
const bySlug = new Map((scan.snapshot?.models || []).map((m) => [m.slug, m]));
|
|
148
148
|
const today = new Date();
|
|
149
149
|
const isCurrent = (m) => computeHealth(m, 90, today) === "ok";
|
|
@@ -159,10 +159,10 @@ export function LocalView({ client, me, dir, ui, width = 78, height = 14, active
|
|
|
159
159
|
}));
|
|
160
160
|
const text = buildFixPrompt(findings, { date: today });
|
|
161
161
|
if (!text) return ui?.showToast?.("no file references to hand off", "#d97706");
|
|
162
|
-
const
|
|
162
|
+
const counts = promptCounts(findings);
|
|
163
163
|
const res = deliverText(text);
|
|
164
|
-
if (res.method === "clipboard") ui?.showToast?.(`${GLYPH.check} LLM fix prompt copied (${
|
|
165
|
-
else if (res.method === "file") ui?.showToast?.(`${GLYPH.check}
|
|
164
|
+
if (res.method === "clipboard") ui?.showToast?.(`${GLYPH.check} LLM fix prompt copied (${counts.models} model${counts.models === 1 ? "" : "s"} · ${counts.refs} refs) — paste into your AI agent`);
|
|
165
|
+
else if (res.method === "file") ui?.showToast?.(`${GLYPH.check} couldn't copy — prompt saved to ${res.path}`);
|
|
166
166
|
else ui?.showToast?.("couldn't copy or save the prompt", "#dc2626");
|
|
167
167
|
},
|
|
168
168
|
);
|