@softspark/ai-toolkit 4.5.0 → 4.6.0

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.
@@ -79,7 +79,7 @@ def install_ai_tools(target_dir: Path, rules_dir: Path,
79
79
 
80
80
  if "cline" in eds:
81
81
  if dry_run:
82
- print(" Would generate: ~/.cline/rules/ai-toolkit-*.md")
82
+ print(" Would generate: ~/Documents/Cline/Rules/ai-toolkit-*.md")
83
83
  print(" Would generate: ~/.cline/skills/ai-toolkit-skill-catalogue/SKILL.md")
84
84
  else:
85
85
  _install_cline_global(target_dir, rules_dir)
@@ -125,8 +125,8 @@ def _install_codex_global(target_dir: Path, rules_dir: Path) -> None:
125
125
  """Install Codex at the global level (~/ layer).
126
126
 
127
127
  Creates:
128
- - ~/AGENTS.md (marker injection with rules)
129
- - ~/.agents/rules/*.md (directory-based rules)
128
+ - ~/AGENTS.md (marker injection; universal coding rules inlined here —
129
+ Codex reads instructions only from AGENTS.md, not .agents/rules/)
130
130
  - ~/.agents/skills/* (skill symlinks)
131
131
  - ~/.codex/hooks.json (lifecycle hooks)
132
132
  """
@@ -136,13 +136,6 @@ def _install_codex_global(target_dir: Path, rules_dir: Path) -> None:
136
136
  rules_dir,
137
137
  )
138
138
 
139
- from generate_codex_rules import generate as gen_codex_rules
140
- gen_codex_rules(
141
- target_dir,
142
- rules_dir=rules_dir,
143
- managed_scopes=("standard", "custom"),
144
- )
145
-
146
139
  from generate_codex_hooks import generate as gen_codex_hooks
147
140
  gen_codex_hooks(target_dir)
148
141
  print(" Created: ~/.codex/hooks.json")
@@ -150,12 +143,33 @@ def _install_codex_global(target_dir: Path, rules_dir: Path) -> None:
150
143
  _install_codex_skills(target_dir)
151
144
 
152
145
 
146
+ def _claude_skills_discoverable(project_dir: Path | None = None) -> bool:
147
+ """True when real ai-toolkit skills already exist at a ``.claude/skills``
148
+ directory the editor scans natively (project-local or global
149
+ ``~/.claude/skills``), making an editor skill-catalogue pointer redundant.
150
+
151
+ Cursor, Cline and Augment discover ``SKILL.md`` from ``.claude/skills`` and
152
+ ``~/.claude/skills`` by default, so when those are populated the pointer adds
153
+ nothing. (Windsurf/Devin gates that scan behind a setting and is excluded
154
+ from the conditional by its callers.) Returns ``False`` for editor-only
155
+ installs (no Claude skills present), where the pointer is the only
156
+ skill-discovery surface.
157
+ """
158
+ candidates = [Path.home() / ".claude" / "skills"]
159
+ if project_dir is not None:
160
+ candidates.insert(0, project_dir / ".claude" / "skills")
161
+ return any(d.is_dir() and any(d.glob("*/SKILL.md")) for d in candidates)
162
+
163
+
153
164
  def _install_windsurf_global(target_dir: Path, rules_dir: Path) -> None:
154
165
  """Install Windsurf global rules plus an Agent Skills catalogue pointer."""
155
166
  windsurf_file = target_dir / ".codeium" / "windsurf" / "memories" / "global_rules.md"
156
167
  inject_with_rules("generate-windsurf.sh", windsurf_file, rules_dir)
157
168
 
158
169
  from generate_windsurf_skills import generate as gen_windsurf_skills
170
+ # Windsurf is excluded from the .claude/skills conditional: its native scan
171
+ # of .claude/skills is gated behind a Devin "Claude Code config reading"
172
+ # setting, so we always emit the pointer as a reliable fallback.
159
173
  gen_windsurf_skills(
160
174
  target_dir,
161
175
  skill_root=".codeium/windsurf/skills",
@@ -166,7 +180,9 @@ def _install_cline_global(target_dir: Path, rules_dir: Path) -> None:
166
180
  """Install Cline global rules in the documented ~/.cline directory."""
167
181
  from generate_cline_rules import generate as gen_cline_rules
168
182
 
169
- rules_root = target_dir / ".cline" / "rules"
183
+ # Cline reads GLOBAL rules from ~/Documents/Cline/Rules/ (docs.cline.bot);
184
+ # ~/.cline/rules/ is not a Cline-read path.
185
+ rules_root = target_dir / "Documents" / "Cline" / "Rules"
170
186
  gen_cline_rules(
171
187
  target_dir,
172
188
  rules_dir=rules_dir,
@@ -174,10 +190,10 @@ def _install_cline_global(target_dir: Path, rules_dir: Path) -> None:
174
190
  emit_workflows=False,
175
191
  managed_scopes=("standard", "custom"),
176
192
  )
177
- print(" Created: ~/.cline/rules/ai-toolkit-*.md")
193
+ print(" Created: ~/Documents/Cline/Rules/ai-toolkit-*.md")
178
194
 
179
195
  from generate_cline_skills import generate as gen_cline_skills
180
- gen_cline_skills(target_dir)
196
+ gen_cline_skills(target_dir, emit_skill_pointer=not _claude_skills_discoverable(target_dir))
181
197
 
182
198
 
183
199
  def _install_roo_global(target_dir: Path, rules_dir: Path) -> None:
@@ -371,6 +387,10 @@ _EDITOR_MARKERS: dict[str, str] = {
371
387
  ".aider.conf.yml": "aider",
372
388
  "CONVENTIONS.md": "aider",
373
389
  ".augment/rules": "augment",
390
+ # Antigravity 2.0 default is plural .agents/; .agents/workflows is the
391
+ # unambiguous marker (Codex also writes .agents/rules but no workflows).
392
+ # Singular .agent/rules is kept to detect legacy installs.
393
+ ".agents/workflows": "antigravity",
374
394
  ".agent/rules": "antigravity",
375
395
  ".agents/skills": "codex",
376
396
  ".codex": "codex",
@@ -694,7 +714,7 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
694
714
  "roo": " Would generate: .roomodes + .roo/rules/*.md",
695
715
  "aider": " Would generate: .aider.conf.yml + CONVENTIONS.md",
696
716
  "augment": " Would generate: .augment/rules/ai-toolkit-*.md",
697
- "antigravity": " Would generate: .agent/rules/ + .agent/workflows/",
717
+ "antigravity": " Would generate: .agents/rules/ + .agents/workflows/",
698
718
  "gemini": " Would generate: GEMINI.md",
699
719
  "opencode": " Would generate: AGENTS.md + .opencode/{agents,commands,plugins}/ + opencode.json",
700
720
  }
@@ -899,6 +919,12 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
899
919
  add_copilot_dir = _profile in {"standard", "strict", "full"}
900
920
  add_gemini_hooks = _profile in {"standard", "strict", "full"}
901
921
  add_native_surfaces = _profile == "full"
922
+ # Skip the editor skill-catalogue pointer when real skills are already
923
+ # discoverable at .claude/skills (project or ~/.claude/skills global):
924
+ # Cursor/Cline/Augment read those natively and by default. Emit it only as
925
+ # the editor-only fallback when no Claude skills are present. Windsurf is
926
+ # excluded (its .claude scan is gated) and keeps its pointer unconditionally.
927
+ emit_pointer = not _claude_skills_discoverable(cwd)
902
928
 
903
929
  if "copilot" in eds:
904
930
  inject_with_rules(
@@ -925,7 +951,7 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
925
951
  if add_native_surfaces:
926
952
  _try_generator("generate_cursor_hooks", cwd)
927
953
  _try_generator("generate_cursor_agents", cwd)
928
- _try_generator("generate_cursor_skills", cwd)
954
+ _try_generator("generate_cursor_skills", cwd, emit_skill_pointer=emit_pointer)
929
955
 
930
956
  if "windsurf" in eds:
931
957
  inject_with_rules(
@@ -938,6 +964,7 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
938
964
  rules_dir=rules_dir)
939
965
  if add_native_surfaces:
940
966
  _try_generator("generate_windsurf_hooks", cwd)
967
+ # Windsurf pointer stays unconditional (its .claude scan is gated).
941
968
  _try_generator("generate_windsurf_skills", cwd)
942
969
 
943
970
  if "cline" in eds:
@@ -954,7 +981,7 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
954
981
  managed_scopes=("standard", "lang", "custom"),
955
982
  )
956
983
  if add_native_surfaces:
957
- _try_generator("generate_cline_skills", cwd)
984
+ _try_generator("generate_cline_skills", cwd, emit_skill_pointer=emit_pointer)
958
985
 
959
986
  if "roo" in eds:
960
987
  roo_output = run_script("generate-roo-modes.sh", capture=True)
@@ -980,7 +1007,7 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
980
1007
  # Augment hooks live under $HOME/.augment/settings.json. The
981
1008
  # generator takes HOME (not cwd) per bucket-1 contract.
982
1009
  _try_generator("generate_augment_hooks", Path.home())
983
- _try_generator("generate_augment_skills", cwd)
1010
+ _try_generator("generate_augment_skills", cwd, emit_skill_pointer=emit_pointer)
984
1011
 
985
1012
  if "antigravity" in eds:
986
1013
  from generate_antigravity import generate as gen_antigravity
@@ -988,20 +1015,14 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
988
1015
  rules_dir=rules_dir)
989
1016
 
990
1017
  if "codex" in eds:
991
- # AGENTS.md — marker injection (like CLAUDE.md)
1018
+ # AGENTS.md — marker injection; universal coding rules are inlined into
1019
+ # AGENTS.md (Codex reads instructions only from AGENTS.md, not a
1020
+ # .agents/rules/ directory). Language rules reach Codex via .agents/skills/.
992
1021
  inject_with_rules(
993
1022
  "generate_codex.py",
994
1023
  cwd / "AGENTS.md",
995
1024
  rules_dir,
996
1025
  )
997
- # .agents/rules/ — directory-based rules
998
- from generate_codex_rules import generate as gen_codex_rules
999
- gen_codex_rules(
1000
- cwd,
1001
- language_modules=language_modules,
1002
- rules_dir=rules_dir,
1003
- managed_scopes=("standard", "lang", "custom"),
1004
- )
1005
1026
  # .codex/hooks.json — Codex lifecycle hooks
1006
1027
  from generate_codex_hooks import generate as gen_codex_hooks
1007
1028
  gen_codex_hooks(cwd)
package/scripts/plugin.py CHANGED
@@ -33,7 +33,6 @@ sys.path.insert(0, str(Path(__file__).resolve().parent))
33
33
  from _common import app_dir, inject_section, inject_rule, remove_rule_section
34
34
  from codex_skill_adapter import cleanup_codex_skills, sync_codex_skill
35
35
  from generate_codex_hooks import generate as generate_codex_hooks
36
- from generate_codex_rules import generate as generate_codex_rules
37
36
  from install_steps.ai_tools import inject_with_rules
38
37
  from paths import HOOKS_DIR as _HOOKS_DIR
39
38
  from paths import RULES_DIR, TOOLKIT_DATA_DIR
@@ -536,8 +535,9 @@ def _install_codex_extra_skills(pack: dict, pack_dir: Path) -> None:
536
535
 
537
536
  def _install_codex_base() -> None:
538
537
  _ensure_core_hook_scripts()
538
+ # Universal coding rules are inlined into AGENTS.md by generate_codex.py;
539
+ # Codex does not read a .agents/rules/ directory.
539
540
  inject_with_rules("generate_codex.py", CODEX_ROOT / "AGENTS.md", RULES_DIR)
540
- generate_codex_rules(CODEX_ROOT, rules_dir=RULES_DIR)
541
541
  hooks_path = CODEX_ROOT / ".codex" / "hooks.json"
542
542
  existing = _load_json(hooks_path, {"hooks": {}})
543
543
  plugin_entries: dict[str, list[dict]] = {}
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Generate Codex CLI .agents/rules/ files.
3
-
4
- Codex discovers rules in .agents/rules/ at the project root.
5
- This generator follows the same pattern as generate_antigravity.py.
6
-
7
- Usage:
8
- python3 scripts/generate_codex_rules.py [target-dir]
9
-
10
- Writes files directly to target-dir/.agents/rules/.
11
- """
12
- from __future__ import annotations
13
-
14
- import sys
15
- from pathlib import Path
16
-
17
- sys.path.insert(0, str(Path(__file__).resolve().parent))
18
- from dir_rules_shared import (
19
- STANDARD_RULES,
20
- STANDARD_SCOPE,
21
- build_language_rules,
22
- build_registered_rules,
23
- write_rules,
24
- )
25
-
26
-
27
- def generate(target_dir: Path, *,
28
- language_modules: list[str] | None = None,
29
- rules_dir: Path | None = None,
30
- cleanup: bool = True,
31
- managed_scopes: tuple[str, ...] = (STANDARD_SCOPE,)) -> None:
32
- """Write .agents/rules/ files to target_dir."""
33
- rules = dict(STANDARD_RULES)
34
- rules.update(build_language_rules(language_modules))
35
- rules.update(build_registered_rules(rules_dir))
36
- write_rules(
37
- target_dir,
38
- rules,
39
- ".agents/rules",
40
- cleanup=cleanup,
41
- managed_scopes=managed_scopes,
42
- )
43
-
44
-
45
- def main() -> None:
46
- target = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()
47
- from paths import RULES_DIR
48
- generate(target, rules_dir=RULES_DIR)
49
-
50
-
51
- if __name__ == "__main__":
52
- main()