composto-ai 0.8.0 → 0.8.2
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/README.md +2 -0
- package/dist/index.js +30 -0
- package/dist/mcp/server.js +11 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**Token-efficient code context for AI agents. Your file's full structure in a fraction of the tokens, with its causal history baked in.**
|
|
4
4
|
|
|
5
|
+
> Send your agent the structure, not the noise.
|
|
6
|
+
|
|
5
7
|
Composto compresses any source file into a Health-Aware IR that keeps exactly what your agent needs — signatures, types, control flow, dependencies — at 60-95% fewer tokens than raw code. On top of that, it surfaces the file's causal history (what historically changed and broke alongside the code you're touching) as advisory context. Local-first, MIT. Works with Claude Code, Cursor, and Gemini CLI.
|
|
6
8
|
|
|
7
9
|
```
|
package/dist/index.js
CHANGED
|
@@ -1010,6 +1010,17 @@ function emitTier3(node) {
|
|
|
1010
1010
|
if (expr.type === "await_expression") {
|
|
1011
1011
|
return null;
|
|
1012
1012
|
}
|
|
1013
|
+
if (expr.type === "assignment_expression") {
|
|
1014
|
+
if (node.parent?.type === "statement_block") return null;
|
|
1015
|
+
const left = expr.childForFieldName("left");
|
|
1016
|
+
const right = expr.childForFieldName("right");
|
|
1017
|
+
if (left?.type === "member_expression" && right && (right.type === "function_expression" || right.type === "arrow_function")) {
|
|
1018
|
+
const asyncPrefix = isAsync(right) ? "ASYNC " : "";
|
|
1019
|
+
const params = right.childForFieldName("parameters")?.text ?? "()";
|
|
1020
|
+
return `${asyncPrefix}FN:${left.text}${collapseText(params, 60)}`;
|
|
1021
|
+
}
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1013
1024
|
if (expr.type === "call_expression") {
|
|
1014
1025
|
const callee = expr.child(0)?.text ?? "";
|
|
1015
1026
|
if (callee === "ObjectSetPrototypeOf" || callee === "Object.setPrototypeOf") {
|
|
@@ -2788,6 +2799,25 @@ async function runBenchmark(projectPath) {
|
|
|
2788
2799
|
console.log(` L1 (full IR): ${summary.totalRaw} \u2192 ${summary.totalIRL1} tokens (${summary.totalSavedPercent.toFixed(1)}% reduction)`);
|
|
2789
2800
|
console.log(` Files analyzed: ${summary.fileCount}`);
|
|
2790
2801
|
console.log(` Engine: ${summary.astCount} AST, ${summary.fpCount} FP`);
|
|
2802
|
+
printSavingsCard(summary);
|
|
2803
|
+
}
|
|
2804
|
+
function printSavingsCard(summary) {
|
|
2805
|
+
if (summary.totalRaw <= 0) return;
|
|
2806
|
+
const saved = summary.totalRaw - summary.totalIRL1;
|
|
2807
|
+
const pct2 = summary.totalSavedPercent.toFixed(1);
|
|
2808
|
+
const SONNET_PER_MTOK = 3;
|
|
2809
|
+
const LOADS_PER_DAY = 50;
|
|
2810
|
+
const DAYS = 30;
|
|
2811
|
+
const rawCost = summary.totalRaw / 1e6 * SONNET_PER_MTOK;
|
|
2812
|
+
const irCost = summary.totalIRL1 / 1e6 * SONNET_PER_MTOK;
|
|
2813
|
+
const monthly = (rawCost - irCost) * LOADS_PER_DAY * DAYS;
|
|
2814
|
+
console.log("\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2815
|
+
console.log(` \u{1F4B8} Every full-context load of this project: $${rawCost.toFixed(2)} raw \u2192 $${irCost.toFixed(2)} with Composto`);
|
|
2816
|
+
console.log(` (Claude Sonnet input, $3/Mtok). At ${LOADS_PER_DAY} loads/day that is ~$${monthly.toFixed(0)}/month saved.`);
|
|
2817
|
+
console.log("\n \u{1F4CB} Share your result:");
|
|
2818
|
+
console.log(` Composto compressed my ${summary.fileCount}-file project ${pct2}% (${summary.totalRaw.toLocaleString()} \u2192 ${summary.totalIRL1.toLocaleString()} tokens).`);
|
|
2819
|
+
console.log(" Try yours: npm i -g composto-ai && composto benchmark .");
|
|
2820
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2791
2821
|
}
|
|
2792
2822
|
async function runBenchmarkQuality(projectPath, filePath) {
|
|
2793
2823
|
const apiKey = process.env.ANTHROPIC_API_KEY;
|
package/dist/mcp/server.js
CHANGED
|
@@ -818,6 +818,17 @@ function emitTier3(node) {
|
|
|
818
818
|
if (expr.type === "await_expression") {
|
|
819
819
|
return null;
|
|
820
820
|
}
|
|
821
|
+
if (expr.type === "assignment_expression") {
|
|
822
|
+
if (node.parent?.type === "statement_block") return null;
|
|
823
|
+
const left = expr.childForFieldName("left");
|
|
824
|
+
const right = expr.childForFieldName("right");
|
|
825
|
+
if (left?.type === "member_expression" && right && (right.type === "function_expression" || right.type === "arrow_function")) {
|
|
826
|
+
const asyncPrefix = isAsync(right) ? "ASYNC " : "";
|
|
827
|
+
const params = right.childForFieldName("parameters")?.text ?? "()";
|
|
828
|
+
return `${asyncPrefix}FN:${left.text}${collapseText(params, 60)}`;
|
|
829
|
+
}
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
821
832
|
if (expr.type === "call_expression") {
|
|
822
833
|
const callee = expr.child(0)?.text ?? "";
|
|
823
834
|
if (callee === "ObjectSetPrototypeOf" || callee === "Object.setPrototypeOf") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "composto-ai",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Proactive AI team companion — less tokens, more insight",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsup",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
21
22
|
"test": "vitest run",
|
|
22
23
|
"test:watch": "vitest",
|
|
23
24
|
"dev": "tsx src/index.ts"
|