quotacap 0.0.5 → 0.0.7
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/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +22 -3
- package/dist/src/mcp/server.d.ts +1 -0
- package/dist/src/mcp/server.js +22 -3
- package/dist/src/version.js +1 -1
- package/dist/tests/mcp/server.test.js +19 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/mcp/server.d.ts
CHANGED
|
@@ -37,5 +37,6 @@ export declare const tools: ({
|
|
|
37
37
|
required: string[];
|
|
38
38
|
};
|
|
39
39
|
})[];
|
|
40
|
+
export declare function recommendationTable(rec: any): string;
|
|
40
41
|
export declare function handleTool(name: string, args: any): Promise<any>;
|
|
41
42
|
export declare function runMcpServer(): Promise<void>;
|
package/dist/mcp/server.js
CHANGED
|
@@ -16,11 +16,30 @@ async function fetchJson(path) {
|
|
|
16
16
|
throw new Error(`daemon not running, run quotacap web — ${e?.message ?? String(e)}`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
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
|
+
return `| ${a.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${Math.round(a.wastePct)}% |`;
|
|
27
|
+
});
|
|
28
|
+
return [
|
|
29
|
+
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Waste if unused |",
|
|
30
|
+
"|---|---|---|---|---|---|---|",
|
|
31
|
+
...rows,
|
|
32
|
+
].join("\n");
|
|
33
|
+
}
|
|
19
34
|
export async function handleTool(name, args) {
|
|
20
35
|
if (name === "get_quotas")
|
|
21
36
|
return fetchJson("/api/quotas");
|
|
22
|
-
if (name === "get_recommendation")
|
|
23
|
-
|
|
37
|
+
if (name === "get_recommendation") {
|
|
38
|
+
const rec = await fetchJson(`/api/recommendation?task=${args?.task ?? "any"}`);
|
|
39
|
+
const table = recommendationTable(rec);
|
|
40
|
+
const json = JSON.stringify(rec, null, 2);
|
|
41
|
+
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
42
|
+
}
|
|
24
43
|
if (name === "forecast") {
|
|
25
44
|
if (!args?.provider)
|
|
26
45
|
throw new Error("provider required");
|
|
@@ -72,7 +91,7 @@ export async function runMcpServer() {
|
|
|
72
91
|
const toolArgs = params?.arguments ?? {};
|
|
73
92
|
try {
|
|
74
93
|
const result = await handleTool(toolName, toolArgs);
|
|
75
|
-
const content = [{ type: "text", text: JSON.stringify(result, null, 2) }];
|
|
94
|
+
const content = Array.isArray(result?.content) ? result.content : [{ type: "text", text: JSON.stringify(result, null, 2) }];
|
|
76
95
|
if (!isNotification)
|
|
77
96
|
respond(id, { content });
|
|
78
97
|
}
|
package/dist/src/mcp/server.d.ts
CHANGED
|
@@ -37,5 +37,6 @@ export declare const tools: ({
|
|
|
37
37
|
required: string[];
|
|
38
38
|
};
|
|
39
39
|
})[];
|
|
40
|
+
export declare function recommendationTable(rec: any): string;
|
|
40
41
|
export declare function handleTool(name: string, args: any): Promise<any>;
|
|
41
42
|
export declare function runMcpServer(): Promise<void>;
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -16,11 +16,30 @@ async function fetchJson(path) {
|
|
|
16
16
|
throw new Error(`daemon not running, run quotacap web — ${e?.message ?? String(e)}`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
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
|
+
return `| ${a.provider} | ${used}% | ${100 - used}% | ${resets} | ${daysLeft} | ${ideal} | ${Math.round(a.wastePct)}% |`;
|
|
27
|
+
});
|
|
28
|
+
return [
|
|
29
|
+
"| Provider | Used | Remaining | Resets | Days left | Ideal daily burn | Waste if unused |",
|
|
30
|
+
"|---|---|---|---|---|---|---|",
|
|
31
|
+
...rows,
|
|
32
|
+
].join("\n");
|
|
33
|
+
}
|
|
19
34
|
export async function handleTool(name, args) {
|
|
20
35
|
if (name === "get_quotas")
|
|
21
36
|
return fetchJson("/api/quotas");
|
|
22
|
-
if (name === "get_recommendation")
|
|
23
|
-
|
|
37
|
+
if (name === "get_recommendation") {
|
|
38
|
+
const rec = await fetchJson(`/api/recommendation?task=${args?.task ?? "any"}`);
|
|
39
|
+
const table = recommendationTable(rec);
|
|
40
|
+
const json = JSON.stringify(rec, null, 2);
|
|
41
|
+
return { content: [{ type: "text", text: table }, { type: "text", text: json }] };
|
|
42
|
+
}
|
|
24
43
|
if (name === "forecast") {
|
|
25
44
|
if (!args?.provider)
|
|
26
45
|
throw new Error("provider required");
|
|
@@ -72,7 +91,7 @@ export async function runMcpServer() {
|
|
|
72
91
|
const toolArgs = params?.arguments ?? {};
|
|
73
92
|
try {
|
|
74
93
|
const result = await handleTool(toolName, toolArgs);
|
|
75
|
-
const content = [{ type: "text", text: JSON.stringify(result, null, 2) }];
|
|
94
|
+
const content = Array.isArray(result?.content) ? result.content : [{ type: "text", text: JSON.stringify(result, null, 2) }];
|
|
76
95
|
if (!isNotification)
|
|
77
96
|
respond(id, { content });
|
|
78
97
|
}
|
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.7";
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { tools } from "../../src/mcp/server.js";
|
|
2
|
+
import { tools, recommendationTable } from "../../src/mcp/server.js";
|
|
3
3
|
describe("mcp", () => {
|
|
4
4
|
it("exposes three tools", () => {
|
|
5
5
|
expect(tools.map(t => t.name)).toEqual(expect.arrayContaining(["get_quotas", "get_recommendation", "forecast"]));
|
|
6
6
|
});
|
|
7
|
+
it("renders a markdown table with one row per provider", () => {
|
|
8
|
+
const rec = {
|
|
9
|
+
use: "kimi",
|
|
10
|
+
reason: "78% waste in 3.0d",
|
|
11
|
+
alternatives: [
|
|
12
|
+
{ provider: "kimi", usedPct: 16, resetsAt: "2026-09-01T09:02:00+10:00" },
|
|
13
|
+
{ provider: "claude", usedPct: 37, resetsAt: "2026-09-03T21:00:00+10:00" },
|
|
14
|
+
],
|
|
15
|
+
advisories: [
|
|
16
|
+
{ provider: "kimi", wastePct: 78.0, daysLeft: 3.0, idealRate: 28.0 },
|
|
17
|
+
{ provider: "claude", wastePct: 52.9, daysLeft: 5.5, idealRate: 11.6 },
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
const table = recommendationTable(rec);
|
|
21
|
+
expect(table).toMatch(/\| Provider \| Used \| Remaining \| Resets \| Days left \| Ideal daily burn \| Waste if unused \|/);
|
|
22
|
+
expect(table).toMatch(/\| kimi \| 16% \| 84% \|.*\| 3.0 \| 28%\/day \| 78% \|/);
|
|
23
|
+
expect(table).toMatch(/\| claude \| 37% \| 63% \|.*\| 5.5 \| 12%\/day \| 53% \|/);
|
|
24
|
+
});
|
|
7
25
|
});
|
package/dist/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.7";
|