quotacap 0.0.8 → 0.0.9
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/dist/cli/index.js +7 -3
- package/dist/format/table.d.ts +1 -0
- package/dist/format/table.js +21 -0
- package/dist/mcp/server.d.ts +12 -2
- package/dist/mcp/server.js +8 -20
- package/dist/src/cli/index.js +7 -3
- package/dist/src/format/table.d.ts +1 -0
- package/dist/src/format/table.js +21 -0
- package/dist/src/mcp/server.d.ts +12 -2
- package/dist/src/mcp/server.js +8 -20
- package/dist/src/version.js +1 -1
- package/dist/src/webAssets.js +1 -1
- package/dist/src/webHtml.js +1 -1
- package/dist/tests/cli/cli.test.js +16 -0
- package/dist/tests/format/table.test.d.ts +1 -0
- package/dist/tests/format/table.test.js +23 -0
- package/dist/tests/mcp/quotas.test.d.ts +1 -0
- package/dist/tests/mcp/quotas.test.js +24 -0
- package/dist/tests/mcp/server.test.js +1 -19
- package/dist/version.js +1 -1
- package/dist/web/src/App.js +2 -2
- package/dist/webAssets.js +1 -1
- package/dist/webHtml.js +1 -1
- package/package.json +1 -1
- package/web/dist/assets/{index-M-4j9c6v.js → index-C7g0JA14.js} +8 -8
- package/web/dist/index.html +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -17,12 +17,16 @@ program.command("status").option("--json", "json").action(async (opts) => {
|
|
|
17
17
|
ensureDbDir();
|
|
18
18
|
const db = openDb(getDbPath());
|
|
19
19
|
migrate(db);
|
|
20
|
-
const { getAllLatest } = await import("../store/quotas.js");
|
|
20
|
+
const { getAllLatest, getBurnRates } = await import("../store/quotas.js");
|
|
21
21
|
const quotas = getAllLatest(db);
|
|
22
22
|
if (opts.json)
|
|
23
23
|
console.log(JSON.stringify(quotas, null, 2));
|
|
24
|
-
else
|
|
25
|
-
|
|
24
|
+
else {
|
|
25
|
+
const { recommend } = await import("../advisory/engine.js");
|
|
26
|
+
const { renderQuotasTable } = await import("../format/table.js");
|
|
27
|
+
const rec = quotas.length ? recommend(quotas, "any", getBurnRates(db)) : null;
|
|
28
|
+
console.log(rec ? renderQuotasTable(quotas, rec.advisories) : "no quotas yet — run quotacap ingest or start the daemon");
|
|
29
|
+
}
|
|
26
30
|
});
|
|
27
31
|
program.command("advise").option("--json", "json").option("--task <t>", "task", "any").action(async (opts) => {
|
|
28
32
|
ensureDbDir();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderQuotasTable(quotas: any[], advisories?: any[]): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The one table every surface renders: MCP tools, CLI status, web dashboard.
|
|
2
|
+
// Quotas carry used/resets; advisories add days-left, burn and waste analysis.
|
|
3
|
+
// Without advisories the analysis columns render as placeholders.
|
|
4
|
+
export function renderQuotasTable(quotas, advisories = []) {
|
|
5
|
+
const rows = quotas.map((q) => {
|
|
6
|
+
const a = advisories.find((x) => x.provider === q.provider);
|
|
7
|
+
const used = Math.round(q.usedPct ?? 0);
|
|
8
|
+
const resets = q.resetsAt ? new Date(q.resetsAt).toLocaleString() : "—";
|
|
9
|
+
const daysLeft = a?.daysLeft != null ? a.daysLeft.toFixed(1) : "—";
|
|
10
|
+
const ideal = a?.idealRate != null ? `${Math.round(a.idealRate)}%/day` : "—";
|
|
11
|
+
const burn = a?.burnMeasured ? `${a.burnRate.toFixed(1)}%/day` : a != null ? "collecting…" : "—";
|
|
12
|
+
const icon = a?.status === "at risk" ? "⚠️" : a != null ? "✅" : "—";
|
|
13
|
+
const waste = a?.wastePct != null ? `${Math.round(a.wastePct)}%` : "—";
|
|
14
|
+
return `| ${q.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${burn} | ${icon} | ${waste} |`;
|
|
15
|
+
});
|
|
16
|
+
return [
|
|
17
|
+
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Burn rate | Status | Waste if unused |",
|
|
18
|
+
"|---|---|---|---|---|---|---|---|---|",
|
|
19
|
+
...rows,
|
|
20
|
+
].join("\n");
|
|
21
|
+
}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ export declare const tools: ({
|
|
|
37
37
|
required: string[];
|
|
38
38
|
};
|
|
39
39
|
})[];
|
|
40
|
-
export declare function
|
|
41
|
-
|
|
40
|
+
export declare function handleTool(name: string, args: any): Promise<{
|
|
41
|
+
content: {
|
|
42
|
+
type: string;
|
|
43
|
+
text: string;
|
|
44
|
+
}[];
|
|
45
|
+
quota?: undefined;
|
|
46
|
+
advisory?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
quota: any;
|
|
49
|
+
advisory: any;
|
|
50
|
+
content?: undefined;
|
|
51
|
+
}>;
|
|
42
52
|
export declare function runMcpServer(): Promise<void>;
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderQuotasTable } from "../format/table.js";
|
|
1
2
|
export const tools = [
|
|
2
3
|
{ name: "get_quotas", description: "All quotas with resets and health", inputSchema: { type: "object", properties: {}, required: [] } },
|
|
3
4
|
{ name: "get_recommendation", description: "Which provider to use next", inputSchema: { type: "object", properties: { task: { type: "string", enum: ["any", "heavy", "light"] } } } },
|
|
@@ -16,29 +17,16 @@ async function fetchJson(path) {
|
|
|
16
17
|
throw new Error(`daemon not running, run quotacap web — ${e?.message ?? String(e)}`);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
export function recommendationTable(rec) {
|
|
20
|
-
const rows = (rec.advisories ?? []).map((a) => {
|
|
21
|
-
const q = (rec.alternatives ?? []).find((x) => x.provider === a.provider);
|
|
22
|
-
const used = Math.round(q?.usedPct ?? 0);
|
|
23
|
-
const resets = q?.resetsAt ? new Date(q.resetsAt).toLocaleString() : "—";
|
|
24
|
-
const daysLeft = a.daysLeft != null ? a.daysLeft.toFixed(1) : "—";
|
|
25
|
-
const ideal = a.idealRate != null ? `${Math.round(a.idealRate)}%/day` : "—";
|
|
26
|
-
const burn = a.burnMeasured ? `${a.burnRate.toFixed(1)}%/day` : "collecting…";
|
|
27
|
-
const icon = a.status === "at risk" ? "⚠️" : "✅";
|
|
28
|
-
return `| ${a.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${burn} | ${icon} | ${Math.round(a.wastePct)}% |`;
|
|
29
|
-
});
|
|
30
|
-
return [
|
|
31
|
-
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Burn rate | Status | Waste if unused |",
|
|
32
|
-
"|---|---|---|---|---|---|---|---|---|",
|
|
33
|
-
...rows,
|
|
34
|
-
].join("\n");
|
|
35
|
-
}
|
|
36
20
|
export async function handleTool(name, args) {
|
|
37
|
-
if (name === "get_quotas")
|
|
38
|
-
|
|
21
|
+
if (name === "get_quotas") {
|
|
22
|
+
const [quotas, rec] = await Promise.all([fetchJson("/api/quotas"), fetchJson("/api/recommendation")]);
|
|
23
|
+
const table = renderQuotasTable(quotas, rec?.advisories ?? []);
|
|
24
|
+
const json = JSON.stringify(quotas, null, 2);
|
|
25
|
+
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
26
|
+
}
|
|
39
27
|
if (name === "get_recommendation") {
|
|
40
28
|
const rec = await fetchJson(`/api/recommendation?task=${args?.task ?? "any"}`);
|
|
41
|
-
const table =
|
|
29
|
+
const table = renderQuotasTable(rec.alternatives ?? [], rec.advisories ?? []);
|
|
42
30
|
const json = JSON.stringify(rec, null, 2);
|
|
43
31
|
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
44
32
|
}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -17,12 +17,16 @@ program.command("status").option("--json", "json").action(async (opts) => {
|
|
|
17
17
|
ensureDbDir();
|
|
18
18
|
const db = openDb(getDbPath());
|
|
19
19
|
migrate(db);
|
|
20
|
-
const { getAllLatest } = await import("../store/quotas.js");
|
|
20
|
+
const { getAllLatest, getBurnRates } = await import("../store/quotas.js");
|
|
21
21
|
const quotas = getAllLatest(db);
|
|
22
22
|
if (opts.json)
|
|
23
23
|
console.log(JSON.stringify(quotas, null, 2));
|
|
24
|
-
else
|
|
25
|
-
|
|
24
|
+
else {
|
|
25
|
+
const { recommend } = await import("../advisory/engine.js");
|
|
26
|
+
const { renderQuotasTable } = await import("../format/table.js");
|
|
27
|
+
const rec = quotas.length ? recommend(quotas, "any", getBurnRates(db)) : null;
|
|
28
|
+
console.log(rec ? renderQuotasTable(quotas, rec.advisories) : "no quotas yet — run quotacap ingest or start the daemon");
|
|
29
|
+
}
|
|
26
30
|
});
|
|
27
31
|
program.command("advise").option("--json", "json").option("--task <t>", "task", "any").action(async (opts) => {
|
|
28
32
|
ensureDbDir();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderQuotasTable(quotas: any[], advisories?: any[]): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The one table every surface renders: MCP tools, CLI status, web dashboard.
|
|
2
|
+
// Quotas carry used/resets; advisories add days-left, burn and waste analysis.
|
|
3
|
+
// Without advisories the analysis columns render as placeholders.
|
|
4
|
+
export function renderQuotasTable(quotas, advisories = []) {
|
|
5
|
+
const rows = quotas.map((q) => {
|
|
6
|
+
const a = advisories.find((x) => x.provider === q.provider);
|
|
7
|
+
const used = Math.round(q.usedPct ?? 0);
|
|
8
|
+
const resets = q.resetsAt ? new Date(q.resetsAt).toLocaleString() : "—";
|
|
9
|
+
const daysLeft = a?.daysLeft != null ? a.daysLeft.toFixed(1) : "—";
|
|
10
|
+
const ideal = a?.idealRate != null ? `${Math.round(a.idealRate)}%/day` : "—";
|
|
11
|
+
const burn = a?.burnMeasured ? `${a.burnRate.toFixed(1)}%/day` : a != null ? "collecting…" : "—";
|
|
12
|
+
const icon = a?.status === "at risk" ? "⚠️" : a != null ? "✅" : "—";
|
|
13
|
+
const waste = a?.wastePct != null ? `${Math.round(a.wastePct)}%` : "—";
|
|
14
|
+
return `| ${q.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${burn} | ${icon} | ${waste} |`;
|
|
15
|
+
});
|
|
16
|
+
return [
|
|
17
|
+
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Burn rate | Status | Waste if unused |",
|
|
18
|
+
"|---|---|---|---|---|---|---|---|---|",
|
|
19
|
+
...rows,
|
|
20
|
+
].join("\n");
|
|
21
|
+
}
|
package/dist/src/mcp/server.d.ts
CHANGED
|
@@ -37,6 +37,16 @@ export declare const tools: ({
|
|
|
37
37
|
required: string[];
|
|
38
38
|
};
|
|
39
39
|
})[];
|
|
40
|
-
export declare function
|
|
41
|
-
|
|
40
|
+
export declare function handleTool(name: string, args: any): Promise<{
|
|
41
|
+
content: {
|
|
42
|
+
type: string;
|
|
43
|
+
text: string;
|
|
44
|
+
}[];
|
|
45
|
+
quota?: undefined;
|
|
46
|
+
advisory?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
quota: any;
|
|
49
|
+
advisory: any;
|
|
50
|
+
content?: undefined;
|
|
51
|
+
}>;
|
|
42
52
|
export declare function runMcpServer(): Promise<void>;
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderQuotasTable } from "../format/table.js";
|
|
1
2
|
export const tools = [
|
|
2
3
|
{ name: "get_quotas", description: "All quotas with resets and health", inputSchema: { type: "object", properties: {}, required: [] } },
|
|
3
4
|
{ name: "get_recommendation", description: "Which provider to use next", inputSchema: { type: "object", properties: { task: { type: "string", enum: ["any", "heavy", "light"] } } } },
|
|
@@ -16,29 +17,16 @@ async function fetchJson(path) {
|
|
|
16
17
|
throw new Error(`daemon not running, run quotacap web — ${e?.message ?? String(e)}`);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
export function recommendationTable(rec) {
|
|
20
|
-
const rows = (rec.advisories ?? []).map((a) => {
|
|
21
|
-
const q = (rec.alternatives ?? []).find((x) => x.provider === a.provider);
|
|
22
|
-
const used = Math.round(q?.usedPct ?? 0);
|
|
23
|
-
const resets = q?.resetsAt ? new Date(q.resetsAt).toLocaleString() : "—";
|
|
24
|
-
const daysLeft = a.daysLeft != null ? a.daysLeft.toFixed(1) : "—";
|
|
25
|
-
const ideal = a.idealRate != null ? `${Math.round(a.idealRate)}%/day` : "—";
|
|
26
|
-
const burn = a.burnMeasured ? `${a.burnRate.toFixed(1)}%/day` : "collecting…";
|
|
27
|
-
const icon = a.status === "at risk" ? "⚠️" : "✅";
|
|
28
|
-
return `| ${a.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${burn} | ${icon} | ${Math.round(a.wastePct)}% |`;
|
|
29
|
-
});
|
|
30
|
-
return [
|
|
31
|
-
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Burn rate | Status | Waste if unused |",
|
|
32
|
-
"|---|---|---|---|---|---|---|---|---|",
|
|
33
|
-
...rows,
|
|
34
|
-
].join("\n");
|
|
35
|
-
}
|
|
36
20
|
export async function handleTool(name, args) {
|
|
37
|
-
if (name === "get_quotas")
|
|
38
|
-
|
|
21
|
+
if (name === "get_quotas") {
|
|
22
|
+
const [quotas, rec] = await Promise.all([fetchJson("/api/quotas"), fetchJson("/api/recommendation")]);
|
|
23
|
+
const table = renderQuotasTable(quotas, rec?.advisories ?? []);
|
|
24
|
+
const json = JSON.stringify(quotas, null, 2);
|
|
25
|
+
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
26
|
+
}
|
|
39
27
|
if (name === "get_recommendation") {
|
|
40
28
|
const rec = await fetchJson(`/api/recommendation?task=${args?.task ?? "any"}`);
|
|
41
|
-
const table =
|
|
29
|
+
const table = renderQuotasTable(rec.alternatives ?? [], rec.advisories ?? []);
|
|
42
30
|
const json = JSON.stringify(rec, null, 2);
|
|
43
31
|
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
44
32
|
}
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// generated by scripts/build-embed.mjs — do not edit
|
|
2
|
-
export const VERSION = "0.0.
|
|
2
|
+
export const VERSION = "0.0.9";
|