@asm-agent/coding-agent 0.8.5 → 0.8.6

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/bundle/{anthropic-BS3XM5BT.js → anthropic-CILMWJ23.js} +1 -1
  3. package/dist/bundle/{azure-openai-responses-IENK6KME.js → azure-openai-responses-TPNZ54LG.js} +2 -2
  4. package/dist/bundle/{bundled-modules-VBE3REQM.js → bundled-modules-SKYRKITN.js} +3 -3
  5. package/dist/bundle/{chunk-KC3DQ3DI.js → chunk-7QIBGY2R.js} +64 -64
  6. package/dist/bundle/{chunk-D55J7N6R.js → chunk-EFDSSG52.js} +69 -18
  7. package/dist/bundle/{chunk-G73LOLKD.js → chunk-IYXHHLR6.js} +1 -1
  8. package/dist/bundle/{chunk-D5ZUG2IX.js → chunk-YYVQTKC6.js} +2 -2
  9. package/dist/bundle/{cli-main-JCK7QTSE.js → cli-main-O3HK7MNQ.js} +3 -3
  10. package/dist/bundle/cli.js +1 -1
  11. package/dist/bundle/{google-L6GUE5MM.js → google-3TL5FKLN.js} +1 -1
  12. package/dist/bundle/{google-vertex-ALYRXEBH.js → google-vertex-WVFMK6QO.js} +1 -1
  13. package/dist/bundle/{main-OA5G7OQN.js → main-4QYKME2K.js} +3 -3
  14. package/dist/bundle/{mistral-NTC6RHCF.js → mistral-QV2OSBWW.js} +1 -1
  15. package/dist/bundle/{openai-codex-responses-FKZNCKA3.js → openai-codex-responses-J2GJ2FAO.js} +2 -2
  16. package/dist/bundle/{openai-completions-LQJM5PDC.js → openai-completions-W622H2EL.js} +1 -1
  17. package/dist/bundle/{openai-responses-AHIOFAPZ.js → openai-responses-V75QG5T7.js} +2 -2
  18. package/dist/core/always-applied-skills.d.ts +3 -0
  19. package/dist/core/always-applied-skills.d.ts.map +1 -0
  20. package/dist/core/always-applied-skills.js +47 -0
  21. package/dist/core/always-applied-skills.js.map +1 -0
  22. package/dist/core/system-prompt.d.ts.map +1 -1
  23. package/dist/core/system-prompt.js +9 -0
  24. package/dist/core/system-prompt.js.map +1 -1
  25. package/dist/skills/final-response-summary/SKILL.md +39 -0
  26. package/dist/skills/request-report/SKILL.md +46 -0
  27. package/dist/skills/request-report/pyproject.toml +16 -0
  28. package/dist/skills/request-report/src/request_report/__init__.py +160 -0
  29. package/dist/skills/skill-creator/SKILL.md +2 -1
  30. package/dist/skills/solid-source-modularity/SKILL.md +48 -0
  31. package/dist/skills/solid-source-modularity/pyproject.toml +16 -0
  32. package/dist/skills/solid-source-modularity/src/solid_source_modularity/__init__.py +154 -0
  33. package/docs/skills.md +8 -3
  34. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  35. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  36. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  37. package/examples/extensions/sandbox/package-lock.json +2 -2
  38. package/examples/extensions/sandbox/package.json +1 -1
  39. package/examples/extensions/with-deps/package-lock.json +2 -2
  40. package/examples/extensions/with-deps/package.json +1 -1
  41. package/package.json +5 -5
  42. package/skills/final-response-summary/SKILL.md +39 -0
  43. package/skills/request-report/SKILL.md +46 -0
  44. package/skills/request-report/pyproject.toml +16 -0
  45. package/skills/request-report/src/request_report/__init__.py +160 -0
  46. package/skills/skill-creator/SKILL.md +2 -1
  47. package/skills/solid-source-modularity/SKILL.md +48 -0
  48. package/skills/solid-source-modularity/pyproject.toml +16 -0
  49. package/skills/solid-source-modularity/src/solid_source_modularity/__init__.py +154 -0
@@ -0,0 +1,16 @@
1
+ [project]
2
+ name = "solid-source-modularity"
3
+ version = "0.1.0"
4
+ description = "Audit authored source files against ASM Agent modularity limits."
5
+ requires-python = ">=3.10"
6
+ dependencies = []
7
+
8
+ [project.scripts]
9
+ solid_source_modularity = "rlm.skill:cli"
10
+
11
+ [build-system]
12
+ requires = ["hatchling"]
13
+ build-backend = "hatchling.build"
14
+
15
+ [tool.hatch.build.targets.wheel]
16
+ packages = ["src/solid_source_modularity"]
@@ -0,0 +1,154 @@
1
+ """Audit authored source files against ASM Agent modularity limits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Iterable
8
+
9
+ _DEFAULT_EXTENSIONS = (
10
+ ".c",
11
+ ".cpp",
12
+ ".cs",
13
+ ".go",
14
+ ".h",
15
+ ".hpp",
16
+ ".java",
17
+ ".js",
18
+ ".jsx",
19
+ ".py",
20
+ ".rs",
21
+ ".ts",
22
+ ".tsx",
23
+ )
24
+ _DEFAULT_EXCLUDED_NAMES = (
25
+ "Cargo.lock",
26
+ "package-lock.json",
27
+ "pnpm-lock.yaml",
28
+ "yarn.lock",
29
+ )
30
+ _EXCLUDED_DIRECTORIES = frozenset(
31
+ {
32
+ ".git",
33
+ ".mypy_cache",
34
+ ".next",
35
+ ".pytest_cache",
36
+ ".tox",
37
+ ".venv",
38
+ "build",
39
+ "coverage",
40
+ "dist",
41
+ "node_modules",
42
+ "target",
43
+ "vendor",
44
+ }
45
+ )
46
+ _GENERATED_NAME_MARKERS = (".generated.", ".gen.")
47
+
48
+
49
+ def _normalize_extensions(extensions: Iterable[str]) -> frozenset[str]:
50
+ normalized = set()
51
+ for extension in extensions:
52
+ if not isinstance(extension, str) or not extension.strip():
53
+ raise TypeError("extensions must contain non-empty strings")
54
+ value = extension.strip().lower()
55
+ normalized.add(value if value.startswith(".") else f".{value}")
56
+ if not normalized:
57
+ raise ValueError("extensions must not be empty")
58
+ return frozenset(normalized)
59
+
60
+
61
+ def _validate_limits(target_lines: int, hard_limit: int) -> None:
62
+ if not isinstance(target_lines, int) or isinstance(target_lines, bool):
63
+ raise TypeError("target_lines must be an integer")
64
+ if not isinstance(hard_limit, int) or isinstance(hard_limit, bool):
65
+ raise TypeError("hard_limit must be an integer")
66
+ if target_lines <= 0 or target_lines > 300:
67
+ raise ValueError("target_lines must be between 1 and 300")
68
+ if hard_limit <= target_lines or hard_limit > 500:
69
+ raise ValueError("hard_limit must be greater than target_lines and at most 500")
70
+
71
+
72
+ def _is_generated_name(name: str) -> bool:
73
+ lowered = name.lower()
74
+ return any(marker in lowered for marker in _GENERATED_NAME_MARKERS)
75
+
76
+
77
+ def _entry(path: Path, root: Path, lines: int) -> dict[str, object]:
78
+ return {"path": path.relative_to(root).as_posix(), "lines": lines}
79
+
80
+
81
+ async def audit_source_files(
82
+ root: str,
83
+ extensions: list[str] | None = None,
84
+ target_lines: int = 300,
85
+ hard_limit: int = 500,
86
+ excluded_names: list[str] | None = None,
87
+ ) -> dict[str, object]:
88
+ """Audit authored source files and classify their physical line counts."""
89
+ _validate_limits(target_lines, hard_limit)
90
+ root_path = Path(root).expanduser().resolve()
91
+ if not root_path.is_dir():
92
+ raise NotADirectoryError(f"{root} is not an existing directory")
93
+
94
+ included_extensions = _normalize_extensions(extensions or list(_DEFAULT_EXTENSIONS))
95
+ excluded = set(excluded_names or list(_DEFAULT_EXCLUDED_NAMES))
96
+ compliant: list[dict[str, object]] = []
97
+ exceptions: list[dict[str, object]] = []
98
+ violations: list[dict[str, object]] = []
99
+ skipped: list[dict[str, str]] = []
100
+
101
+ for current_root, directories, filenames in os.walk(root_path):
102
+ directories[:] = sorted(name for name in directories if name not in _EXCLUDED_DIRECTORIES)
103
+ current_path = Path(current_root)
104
+ for filename in sorted(filenames):
105
+ path = current_path / filename
106
+ if path.suffix.lower() not in included_extensions:
107
+ continue
108
+ relative = path.relative_to(root_path).as_posix()
109
+ if filename in excluded or _is_generated_name(filename):
110
+ skipped.append({"path": relative, "reason": "excluded or generated"})
111
+ continue
112
+ try:
113
+ line_count = len(path.read_text(encoding="utf-8").splitlines())
114
+ except (OSError, UnicodeError) as error:
115
+ skipped.append({"path": relative, "reason": str(error)})
116
+ continue
117
+ entry = _entry(path, root_path, line_count)
118
+ if line_count <= target_lines:
119
+ compliant.append(entry)
120
+ elif line_count <= hard_limit:
121
+ exceptions.append(entry)
122
+ else:
123
+ violations.append(entry)
124
+
125
+ return {
126
+ "root": str(root_path),
127
+ "target_lines": target_lines,
128
+ "hard_limit": hard_limit,
129
+ "scanned_files": len(compliant) + len(exceptions) + len(violations),
130
+ "compliant": compliant,
131
+ "exceptions": exceptions,
132
+ "violations": violations,
133
+ "skipped": skipped,
134
+ }
135
+
136
+
137
+ async def run(
138
+ root: str,
139
+ extensions: list[str] | None = None,
140
+ target_lines: int = 300,
141
+ hard_limit: int = 500,
142
+ excluded_names: list[str] | None = None,
143
+ ) -> dict[str, object]:
144
+ """Audit source files under ``root`` against the 300/500-line policy."""
145
+ return await audit_source_files(
146
+ root,
147
+ extensions=extensions,
148
+ target_lines=target_lines,
149
+ hard_limit=hard_limit,
150
+ excluded_names=excluded_names,
151
+ )
152
+
153
+
154
+ __all__ = ["audit_source_files", "run"]