composto-ai 0.2.0 → 0.2.1

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.
@@ -499,36 +499,89 @@ function detectLanguage(filePath) {
499
499
 
500
500
  // src/ir/ast-walker.ts
501
501
  var TIER_MAP = {
502
- // Tier 1 — structural declarations
502
+ // Tier 1 — structural declarations (JS/TS)
503
503
  import_statement: "T1_KEEP",
504
504
  function_declaration: "T1_KEEP",
505
505
  class_declaration: "T1_KEEP",
506
506
  interface_declaration: "T1_KEEP",
507
507
  type_alias_declaration: "T1_KEEP",
508
508
  enum_declaration: "T1_KEEP",
509
- // Tier 2control flow
509
+ // Tier 1Python
510
+ function_definition: "T1_KEEP",
511
+ class_definition: "T1_KEEP",
512
+ import_from_statement: "T1_KEEP",
513
+ decorated_definition: "T1_KEEP",
514
+ // Tier 1 — Go
515
+ function_item: "T1_KEEP",
516
+ // Rust
517
+ method_declaration: "T1_KEEP",
518
+ // Go
519
+ type_declaration: "T1_KEEP",
520
+ // Go
521
+ import_declaration: "T1_KEEP",
522
+ // Go
523
+ use_declaration: "T1_KEEP",
524
+ // Rust
525
+ struct_item: "T1_KEEP",
526
+ // Rust
527
+ enum_item: "T1_KEEP",
528
+ // Rust
529
+ trait_item: "T1_KEEP",
530
+ // Rust
531
+ impl_item: "T1_KEEP",
532
+ // Rust
533
+ // Tier 2 — control flow (universal)
510
534
  if_statement: "T2_CONTROL",
535
+ if_expression: "T2_CONTROL",
536
+ // Rust
511
537
  else_clause: "WALK_ONLY",
538
+ elif_clause: "T2_CONTROL",
539
+ // Python
512
540
  for_statement: "T2_CONTROL",
513
541
  for_in_statement: "T2_CONTROL",
542
+ for_expression: "T2_CONTROL",
543
+ // Rust
514
544
  while_statement: "T2_CONTROL",
515
545
  do_statement: "T2_CONTROL",
516
546
  switch_statement: "T2_CONTROL",
517
547
  switch_case: "T2_CONTROL",
518
548
  switch_default: "T2_CONTROL",
549
+ match_expression: "T2_CONTROL",
550
+ // Rust
519
551
  return_statement: "T2_CONTROL",
552
+ return_expression: "T2_CONTROL",
553
+ // Rust
520
554
  throw_statement: "T2_CONTROL",
555
+ raise_statement: "T2_CONTROL",
556
+ // Python
521
557
  try_statement: "T2_CONTROL",
522
558
  catch_clause: "T2_CONTROL",
559
+ except_clause: "T2_CONTROL",
560
+ // Python
561
+ with_statement: "T2_CONTROL",
562
+ // Python
563
+ defer_statement: "T2_CONTROL",
564
+ // Go
523
565
  // Tier 3 — compressible expressions
524
566
  lexical_declaration: "T3_COMPRESS",
525
567
  expression_statement: "T3_COMPRESS",
526
- // Walk-only — containers that need traversal but no emission
568
+ assignment: "T3_COMPRESS",
569
+ // Python
570
+ short_var_declaration: "T3_COMPRESS",
571
+ // Go
572
+ // Walk-only — containers
527
573
  program: "WALK_ONLY",
574
+ module: "WALK_ONLY",
575
+ // Python
528
576
  statement_block: "WALK_ONLY",
577
+ block: "WALK_ONLY",
578
+ // Python/Go/Rust
529
579
  class_body: "WALK_ONLY",
580
+ // JS/TS
530
581
  switch_body: "WALK_ONLY",
531
- export_statement: "WALK_ONLY"
582
+ export_statement: "WALK_ONLY",
583
+ source_file: "WALK_ONLY"
584
+ // Go/Rust
532
585
  };
533
586
  function tierOf(nodeType) {
534
587
  return TIER_MAP[nodeType] ?? "T4_DROP";
@@ -644,6 +697,35 @@ function emitTier2(node) {
644
697
  const paramText = param ? param.text : "...";
645
698
  return `CATCH:${paramText}`;
646
699
  }
700
+ // Python
701
+ case "raise_statement": {
702
+ const val = node.childCount > 1 ? node.child(1)?.text ?? "" : "";
703
+ return `RAISE:${val.length > 50 ? val.slice(0, 47) + "..." : val}`;
704
+ }
705
+ case "except_clause":
706
+ return "EXCEPT";
707
+ case "elif_clause": {
708
+ const cond = extractCondition(node);
709
+ return `ELIF:${cond}`;
710
+ }
711
+ case "with_statement":
712
+ return "WITH";
713
+ // Rust
714
+ case "if_expression": {
715
+ const cond = extractCondition(node);
716
+ return `IF:${cond}`;
717
+ }
718
+ case "for_expression":
719
+ return "LOOP";
720
+ case "match_expression":
721
+ return "MATCH";
722
+ case "return_expression": {
723
+ const val = node.childCount > 1 ? node.child(1)?.text ?? "" : "";
724
+ return `RET ${val.length > 60 ? val.slice(0, 57) + "..." : val}`.trimEnd();
725
+ }
726
+ // Go
727
+ case "defer_statement":
728
+ return "DEFER";
647
729
  default:
648
730
  return null;
649
731
  }
@@ -681,6 +763,46 @@ function emitTier1(node) {
681
763
  const name = node.childForFieldName("name")?.text ?? "Anonymous";
682
764
  return `${outPrefix}ENUM:${name}`;
683
765
  }
766
+ // Python
767
+ case "function_definition": {
768
+ const name = node.childForFieldName("name")?.text ?? "anonymous";
769
+ const params = node.childForFieldName("parameters")?.text ?? "()";
770
+ const returnType = node.childForFieldName("return_type")?.text ?? "";
771
+ const rt = returnType ? ` -> ${returnType}` : "";
772
+ return `FN:${name}${collapseText(params, 60)}${rt}`;
773
+ }
774
+ case "class_definition": {
775
+ const name = node.childForFieldName("name")?.text ?? "Anonymous";
776
+ const superclass = node.childForFieldName("superclasses")?.text ?? "";
777
+ const sc = superclass ? `(${collapseText(superclass, 40)})` : "";
778
+ return `CLASS:${name}${sc}`;
779
+ }
780
+ case "import_from_statement": {
781
+ return `USE:${collapseText(node.text, 80)}`;
782
+ }
783
+ case "decorated_definition": {
784
+ return null;
785
+ }
786
+ // Go
787
+ case "method_declaration":
788
+ case "type_declaration":
789
+ case "import_declaration": {
790
+ return `${collapseText(node.text, 80)}`;
791
+ }
792
+ // Rust
793
+ case "function_item": {
794
+ const name = node.childForFieldName("name")?.text ?? "anonymous";
795
+ const params = node.childForFieldName("parameters")?.text ?? "()";
796
+ return `FN:${name}${collapseText(params, 60)}`;
797
+ }
798
+ case "struct_item":
799
+ case "enum_item":
800
+ case "trait_item":
801
+ case "impl_item":
802
+ case "use_declaration": {
803
+ const firstLine = node.text.split("\n")[0];
804
+ return collapseText(firstLine, 80);
805
+ }
684
806
  default:
685
807
  return null;
686
808
  }
@@ -726,6 +848,17 @@ function emitTier3(node) {
726
848
  return null;
727
849
  }
728
850
  if (expr.type === "call_expression") {
851
+ const callee = expr.child(0)?.text ?? "";
852
+ if (callee === "ObjectSetPrototypeOf" || callee === "Object.setPrototypeOf") {
853
+ const args = expr.child(1);
854
+ if (args && args.childCount >= 4) {
855
+ const child = args.child(1)?.text ?? "?";
856
+ const parent = args.child(3)?.text ?? "?";
857
+ const shortChild = child.length > 30 ? child.slice(0, 27) + "..." : child;
858
+ const shortParent = parent.length > 30 ? parent.slice(0, 27) + "..." : parent;
859
+ return `EXTENDS:${shortChild} < ${shortParent}`;
860
+ }
861
+ }
729
862
  return null;
730
863
  }
731
864
  return null;
@@ -743,7 +876,9 @@ function walkNode(node, depth, lines) {
743
876
  for (let i = 0; i < node.childCount; i++) {
744
877
  const child = node.child(i);
745
878
  const childType = child.type;
746
- if (childType === "statement_block" || childType === "class_body") {
879
+ if (childType === "statement_block" || childType === "class_body" || childType === "block" || // Python/Go/Rust
880
+ childType === "body" || // Python class/function body
881
+ childType === "declaration_list") {
747
882
  walkNode(child, depth + 1, lines);
748
883
  }
749
884
  }
@@ -834,7 +969,7 @@ async function astWalkIR(code, filePath) {
834
969
  const lines = [];
835
970
  walkNode(root, 0, lines);
836
971
  if (lines.length === 0) return null;
837
- const merged = [];
972
+ const pass1 = [];
838
973
  let useBlock = [];
839
974
  for (const line of lines) {
840
975
  if (line.startsWith("USE:")) {
@@ -843,20 +978,45 @@ async function astWalkIR(code, filePath) {
843
978
  } else {
844
979
  if (useBlock.length > 0) {
845
980
  if (useBlock.length <= 3) {
846
- for (const mod of useBlock) merged.push(`USE:${mod}`);
981
+ for (const mod of useBlock) pass1.push(`USE:${mod}`);
847
982
  } else {
848
- merged.push(`USE:[${useBlock.join(", ")}]`);
983
+ pass1.push(`USE:[${useBlock.join(", ")}]`);
849
984
  }
850
985
  useBlock = [];
851
986
  }
852
- merged.push(line);
987
+ pass1.push(line);
853
988
  }
854
989
  }
855
990
  if (useBlock.length > 0) {
856
991
  if (useBlock.length <= 3) {
857
- for (const mod of useBlock) merged.push(`USE:${mod}`);
992
+ for (const mod of useBlock) pass1.push(`USE:${mod}`);
858
993
  } else {
859
- merged.push(`USE:[${useBlock.join(", ")}]`);
994
+ pass1.push(`USE:[${useBlock.join(", ")}]`);
995
+ }
996
+ }
997
+ const merged = [];
998
+ let guardBlock = [];
999
+ for (const line of pass1) {
1000
+ const guardMatch = line.match(/^(\s*)IF:(.+?) \u2192 RET/);
1001
+ if (guardMatch) {
1002
+ guardBlock.push(guardMatch[2].trim());
1003
+ continue;
1004
+ }
1005
+ if (guardBlock.length > 0) {
1006
+ if (guardBlock.length < 3) {
1007
+ for (const g of guardBlock) merged.push(` IF:${g} \u2192 RET`);
1008
+ } else {
1009
+ merged.push(` GUARD:[${guardBlock.join(", ")}]`);
1010
+ }
1011
+ guardBlock = [];
1012
+ }
1013
+ merged.push(line);
1014
+ }
1015
+ if (guardBlock.length > 0) {
1016
+ if (guardBlock.length < 3) {
1017
+ for (const g of guardBlock) merged.push(` IF:${g} \u2192 RET`);
1018
+ } else {
1019
+ merged.push(` GUARD:[${guardBlock.join(", ")}]`);
860
1020
  }
861
1021
  }
862
1022
  return merged.join("\n");
@@ -879,10 +1039,11 @@ ${declarations.join("\n")}`;
879
1039
  }
880
1040
  async function generateL1(code, filePath, health) {
881
1041
  const ir = await astWalkIR(code, filePath) ?? fingerprintFile(code, 0.75);
1042
+ const result = ir.length < code.length ? ir : code;
882
1043
  if (health) {
883
- return annotateIR(ir, health);
1044
+ return annotateIR(result, health);
884
1045
  }
885
- return ir;
1046
+ return result;
886
1047
  }
887
1048
  function generateL2(delta, health) {
888
1049
  const parts = [`FILE: ${delta.file}`];
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  packContext,
13
13
  runDetector,
14
14
  summarize
15
- } from "./chunk-MFNGSHTZ.js";
15
+ } from "./chunk-T2SFR7QS.js";
16
16
 
17
17
  // src/cli/commands.ts
18
18
  import { readFileSync, readdirSync } from "fs";
@@ -12,7 +12,7 @@ import {
12
12
  packContext,
13
13
  runDetector,
14
14
  summarize
15
- } from "../chunk-MFNGSHTZ.js";
15
+ } from "../chunk-T2SFR7QS.js";
16
16
 
17
17
  // src/mcp/server.ts
18
18
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "composto-ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Proactive AI team companion — less tokens, more insight",
5
5
  "type": "module",
6
6
  "bin": {