@softspark/ai-toolkit 2.11.0 → 3.0.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.
Files changed (108) hide show
  1. package/AGENTS.md +21 -21
  2. package/CHANGELOG.md +62 -0
  3. package/README.md +16 -9
  4. package/app/.claude-plugin/plugin.json +1 -1
  5. package/app/agents/meta-architect.md +44 -0
  6. package/app/skills/agent-creator/SKILL.md +22 -6
  7. package/app/skills/analyze/SKILL.md +21 -1
  8. package/app/skills/api-patterns/SKILL.md +27 -0
  9. package/app/skills/app-builder/SKILL.md +24 -0
  10. package/app/skills/architecture-audit/SKILL.md +24 -0
  11. package/app/skills/architecture-decision/SKILL.md +24 -0
  12. package/app/skills/biz-scan/SKILL.md +24 -0
  13. package/app/skills/brand-voice/SKILL.md +36 -0
  14. package/app/skills/briefing/SKILL.md +41 -1
  15. package/app/skills/build/SKILL.md +24 -1
  16. package/app/skills/chaos/SKILL.md +22 -1
  17. package/app/skills/ci/SKILL.md +22 -1
  18. package/app/skills/ci-cd-patterns/SKILL.md +25 -0
  19. package/app/skills/command-creator/SKILL.md +31 -2
  20. package/app/skills/content-moderation-patterns/SKILL.md +25 -0
  21. package/app/skills/database-patterns/SKILL.md +25 -0
  22. package/app/skills/debug/SKILL.md +23 -1
  23. package/app/skills/design-engineering/SKILL.md +25 -0
  24. package/app/skills/docker-devops/SKILL.md +26 -0
  25. package/app/skills/ecommerce-patterns/SKILL.md +26 -0
  26. package/app/skills/evaluate/SKILL.md +22 -1
  27. package/app/skills/evolve/SKILL.md +25 -0
  28. package/app/skills/explain/SKILL.md +26 -1
  29. package/app/skills/explore/SKILL.md +25 -0
  30. package/app/skills/fix/SKILL.md +26 -1
  31. package/app/skills/git-mastery/SKILL.md +26 -0
  32. package/app/skills/grill-me/SKILL.md +22 -7
  33. package/app/skills/health/SKILL.md +22 -1
  34. package/app/skills/hipaa-validate/SKILL.md +25 -8
  35. package/app/skills/hook-creator/SKILL.md +107 -14
  36. package/app/skills/index/SKILL.md +22 -1
  37. package/app/skills/instinct-review/SKILL.md +25 -1
  38. package/app/skills/introspect/SKILL.md +26 -1
  39. package/app/skills/lint/SKILL.md +27 -1
  40. package/app/skills/mcp-builder/SKILL.md +27 -0
  41. package/app/skills/mem-search/SKILL.md +40 -0
  42. package/app/skills/migrate/SKILL.md +27 -1
  43. package/app/skills/migration-patterns/SKILL.md +26 -0
  44. package/app/skills/night-watch/SKILL.md +22 -1
  45. package/app/skills/observability-patterns/SKILL.md +26 -0
  46. package/app/skills/onboard/SKILL.md +22 -1
  47. package/app/skills/panic/SKILL.md +21 -1
  48. package/app/skills/performance-profiling/SKILL.md +34 -0
  49. package/app/skills/persona/SKILL.md +21 -4
  50. package/app/skills/plan/SKILL.md +26 -0
  51. package/app/skills/plan-writing/SKILL.md +26 -0
  52. package/app/skills/plugin-creator/SKILL.md +23 -6
  53. package/app/skills/pr/SKILL.md +24 -1
  54. package/app/skills/prd-to-issues/SKILL.md +22 -6
  55. package/app/skills/prd-to-plan/SKILL.md +22 -4
  56. package/app/skills/predict/SKILL.md +25 -0
  57. package/app/skills/qa-session/SKILL.md +23 -7
  58. package/app/skills/rag-patterns/SKILL.md +26 -0
  59. package/app/skills/refactor/SKILL.md +26 -0
  60. package/app/skills/refactor-plan/SKILL.md +23 -6
  61. package/app/skills/rollback/SKILL.md +27 -1
  62. package/app/skills/security-patterns/SKILL.md +27 -0
  63. package/app/skills/skill-audit/SKILL.md +22 -5
  64. package/app/skills/skill-creator/SKILL.md +58 -13
  65. package/app/skills/swift-patterns/SKILL.md +27 -107
  66. package/app/skills/swift-patterns/reference/frameworks.md +111 -0
  67. package/app/skills/test/SKILL.md +23 -1
  68. package/app/skills/testing-patterns/SKILL.md +26 -0
  69. package/app/skills/triage-issue/SKILL.md +22 -4
  70. package/app/skills/ubiquitous-language/SKILL.md +23 -8
  71. package/benchmarks/ecosystem-doctor-snapshot.json +395 -0
  72. package/kb/history/completed/deep-coverage-v3-20260423.md +160 -0
  73. package/kb/history/completed/ecosystem-deep-sweep-20260423.md +273 -0
  74. package/kb/procedures/ecosystem-sync-sop.md +255 -0
  75. package/kb/procedures/maintenance-sop.md +13 -2
  76. package/kb/procedures/release-preparation-sop.md +91 -12
  77. package/kb/procedures/release-verification-sop.md +24 -6
  78. package/kb/reference/global-install-model.md +15 -2
  79. package/kb/reference/supported-tools-registry.md +229 -0
  80. package/llms-full.txt +1105 -43
  81. package/llms.txt +4 -0
  82. package/manifest.json +1 -1
  83. package/package.json +4 -1
  84. package/scripts/ecosystem_doctor.py +348 -0
  85. package/scripts/ecosystem_tools.json +500 -0
  86. package/scripts/evaluate_skills.py +84 -0
  87. package/scripts/generate_aider_conf.py +26 -1
  88. package/scripts/generate_antigravity.py +77 -8
  89. package/scripts/generate_augment_agents.py +161 -0
  90. package/scripts/generate_augment_commands.py +160 -0
  91. package/scripts/generate_augment_hooks.py +162 -0
  92. package/scripts/generate_augment_skills.py +98 -0
  93. package/scripts/generate_cline_rules.py +96 -9
  94. package/scripts/generate_codex_hooks.py +13 -2
  95. package/scripts/generate_codex_skills.py +195 -0
  96. package/scripts/generate_copilot.py +296 -18
  97. package/scripts/generate_cursor_agents.py +144 -0
  98. package/scripts/generate_cursor_hooks.py +155 -0
  99. package/scripts/generate_cursor_mdc.py +20 -8
  100. package/scripts/generate_gemini_commands.py +158 -0
  101. package/scripts/generate_gemini_hooks.py +159 -0
  102. package/scripts/generate_gemini_skills.py +98 -0
  103. package/scripts/generate_roo_modes.py +42 -1
  104. package/scripts/generate_windsurf_hooks.py +143 -0
  105. package/scripts/generate_windsurf_rules.py +162 -10
  106. package/scripts/install.py +11 -2
  107. package/scripts/install_steps/ai_tools.py +120 -5
  108. package/scripts/validate.py +20 -3
@@ -1,9 +1,21 @@
1
1
  #!/usr/bin/env python3
2
- """Generate .windsurf/rules/*.md files for Windsurf IDE.
2
+ """Generate ``.windsurf/rules/*.md`` (and workflows) for Windsurf IDE.
3
3
 
4
- Windsurf reads directory-based rules from .windsurf/rules/*.md (since mid-2025).
5
- The legacy .windsurfrules single-file format is still generated separately
6
- by generate_windsurf.py for backwards compatibility.
4
+ Windsurf reads directory-based rules from ``.windsurf/rules/*.md`` (since
5
+ mid-2025). Each rule file supports YAML frontmatter with these fields
6
+ (from docs.windsurf.com/windsurf/cascade/memories):
7
+
8
+ * ``trigger`` — activation mode: ``always_on`` | ``glob`` | ``model_decision``
9
+ | ``manual``. When omitted, Windsurf defaults to manual-only.
10
+ * ``globs`` — comma-separated glob patterns (only when ``trigger: glob``).
11
+ * ``description`` — shown to the model when ``trigger: model_decision``.
12
+
13
+ Windsurf also reads workflow markdown files from ``.windsurf/workflows/*.md``
14
+ which users invoke via ``/<name>`` slash commands (Cascade). This generator
15
+ emits the same workflow catalogue used by Antigravity and Cline.
16
+
17
+ The legacy ``.windsurfrules`` single-file format is still produced by
18
+ ``generate_windsurf.py`` for backwards compatibility.
7
19
 
8
20
  Usage:
9
21
  python3 scripts/generate_windsurf_rules.py [target-dir]
@@ -15,21 +27,161 @@ from pathlib import Path
15
27
 
16
28
  sys.path.insert(0, str(Path(__file__).resolve().parent))
17
29
  from dir_rules_shared import (
30
+ CUSTOM_SCOPE,
31
+ LANG_GLOBS,
32
+ LANG_PREFIX,
33
+ LANG_SCOPE,
34
+ PREFIX,
18
35
  STANDARD_RULES,
36
+ STANDARD_SCOPE,
37
+ STANDARD_WORKFLOWS,
19
38
  build_language_rules,
20
39
  build_registered_rules,
40
+ cleanup_stale,
41
+ rule_testing,
21
42
  write_rules,
22
43
  )
23
44
 
24
45
 
46
+ # ---------------------------------------------------------------------------
47
+ # Frontmatter helpers — Windsurf rule activation modes
48
+ # ---------------------------------------------------------------------------
49
+
50
+ def _frontmatter(content: str, *,
51
+ trigger: str,
52
+ description: str = "",
53
+ globs: list[str] | None = None) -> str:
54
+ """Prepend a Windsurf YAML frontmatter block to rule content.
55
+
56
+ ``trigger`` must be one of: ``always_on``, ``glob``, ``model_decision``,
57
+ ``manual``. ``description`` is shown to the model for ``model_decision``
58
+ mode; ignored otherwise. ``globs`` is only meaningful for ``glob`` mode.
59
+ """
60
+ lines = ["---", f"trigger: {trigger}"]
61
+ if description:
62
+ lines.append(f"description: {description}")
63
+ if trigger == "glob" and globs:
64
+ lines.append("globs: " + ",".join(globs))
65
+ lines.append("---")
66
+ lines.append("")
67
+ lines.append(content.rstrip("\n"))
68
+ lines.append("")
69
+ return "\n".join(lines)
70
+
71
+
72
+ def _always_on(content_fn):
73
+ """Wrap a content callable so Windsurf treats it as always-on."""
74
+ return lambda: _frontmatter(content_fn(), trigger="always_on")
75
+
76
+
77
+ def _glob_rule(content_fn, globs: list[str]):
78
+ """Wrap a content callable for Windsurf's glob activation mode."""
79
+ return lambda: _frontmatter(content_fn(), trigger="glob", globs=globs)
80
+
81
+
82
+ def _model_decision(content_fn, description: str):
83
+ """Wrap a content callable for Windsurf's model-decision activation."""
84
+ return lambda: _frontmatter(
85
+ content_fn(), trigger="model_decision", description=description,
86
+ )
87
+
88
+
89
+ def _build_rules(language_modules: list[str] | None,
90
+ rules_dir: Path | None) -> dict[str, callable]:
91
+ """Build the full rule registry with per-rule activation frontmatter."""
92
+ rules: dict[str, callable] = {}
93
+
94
+ # Standard rules: agents/skills index + quality/security are always-on.
95
+ # Code style + testing + workflow are model-decision so Cascade only
96
+ # expands them when relevant.
97
+ always_on_names = {
98
+ f"{PREFIX}agents-and-skills.md",
99
+ f"{PREFIX}security.md",
100
+ f"{PREFIX}quality-standards.md",
101
+ }
102
+ model_decision_descs = {
103
+ f"{PREFIX}code-style.md":
104
+ "Code style conventions for all languages",
105
+ f"{PREFIX}workflow.md":
106
+ "Development workflow, commits, and quality gates",
107
+ }
108
+ testing_globs = ["**/*.test.*", "**/*.spec.*", "**/test_*", "**/tests/**"]
109
+
110
+ for filename, content_fn in STANDARD_RULES.items():
111
+ if filename in always_on_names:
112
+ rules[filename] = _always_on(content_fn)
113
+ elif filename == f"{PREFIX}testing.md":
114
+ rules[filename] = _glob_rule(content_fn, testing_globs)
115
+ elif filename in model_decision_descs:
116
+ rules[filename] = _model_decision(
117
+ content_fn, model_decision_descs[filename],
118
+ )
119
+ else:
120
+ rules[filename] = _always_on(content_fn)
121
+
122
+ # Language rules: scope to their own file globs so they activate only
123
+ # when touching matching files.
124
+ for filename, content_fn in build_language_rules(language_modules).items():
125
+ lang = filename.removeprefix(LANG_PREFIX).removesuffix(".md")
126
+ if lang == "common":
127
+ rules[filename] = _always_on(content_fn)
128
+ continue
129
+ globs = LANG_GLOBS.get(lang)
130
+ if globs:
131
+ rules[filename] = _glob_rule(content_fn, globs)
132
+ else:
133
+ rules[filename] = _always_on(content_fn)
134
+
135
+ # Custom user-registered rules — always-on by default (user intent).
136
+ rules.update({
137
+ name: _always_on(fn)
138
+ for name, fn in build_registered_rules(rules_dir).items()
139
+ })
140
+
141
+ return rules
142
+
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # Workflows — .windsurf/workflows/<name>.md invocable via /<name>
146
+ # ---------------------------------------------------------------------------
147
+
148
+ def _write_workflows(target_dir: Path, *, cleanup: bool = True) -> None:
149
+ """Write ``.windsurf/workflows/*.md`` files for Cascade slash commands."""
150
+ workflows_dir = target_dir / ".windsurf" / "workflows"
151
+ workflows_dir.mkdir(parents=True, exist_ok=True)
152
+
153
+ if cleanup:
154
+ cleanup_stale(workflows_dir, set(STANDARD_WORKFLOWS.keys()))
155
+
156
+ for filename, content_fn in STANDARD_WORKFLOWS.items():
157
+ (workflows_dir / filename).write_text(content_fn(), encoding="utf-8")
158
+ print(f" Generated: .windsurf/workflows/{filename}")
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Main
163
+ # ---------------------------------------------------------------------------
164
+
25
165
  def generate(target_dir: Path, *,
26
166
  language_modules: list[str] | None = None,
27
- rules_dir: Path | None = None) -> None:
28
- """Write .windsurf/rules/*.md files to target_dir."""
29
- rules = dict(STANDARD_RULES)
30
- rules.update(build_language_rules(language_modules))
31
- rules.update(build_registered_rules(rules_dir))
32
- write_rules(target_dir, rules, ".windsurf/rules")
167
+ rules_dir: Path | None = None,
168
+ cleanup: bool = True,
169
+ emit_workflows: bool = True,
170
+ managed_scopes: tuple[str, ...] = (
171
+ STANDARD_SCOPE, LANG_SCOPE, CUSTOM_SCOPE,
172
+ )) -> None:
173
+ """Write ``.windsurf/rules/*.md`` and ``.windsurf/workflows/*.md``."""
174
+ rules = _build_rules(language_modules, rules_dir)
175
+ write_rules(
176
+ target_dir,
177
+ rules,
178
+ ".windsurf/rules",
179
+ cleanup=cleanup,
180
+ managed_scopes=managed_scopes,
181
+ )
182
+
183
+ if emit_workflows:
184
+ _write_workflows(target_dir, cleanup=cleanup)
33
185
 
34
186
 
35
187
  def main() -> None:
@@ -216,6 +216,7 @@ def parse_args(argv: list[str]) -> dict:
216
216
  "config": "",
217
217
  "refresh_base": False,
218
218
  "skip_register": False,
219
+ "codex_skills": False,
219
220
  }
220
221
  i = 0
221
222
  while i < len(argv):
@@ -274,6 +275,8 @@ def parse_args(argv: list[str]) -> dict:
274
275
  cfg["refresh_base"] = True
275
276
  elif arg == "--skip-register":
276
277
  cfg["skip_register"] = True
278
+ elif arg == "--codex-skills":
279
+ cfg["codex_skills"] = True
277
280
  elif arg.startswith("-"):
278
281
  print(f"Unknown option: {arg}")
279
282
  sys.exit(1)
@@ -361,8 +364,12 @@ def resolve_profile(profile: str, only: str) -> str:
361
364
  pass
362
365
  elif profile == "strict":
363
366
  pass
367
+ elif profile == "full":
368
+ # `full` is a `standard`-shaped install for Claude Code components;
369
+ # the extra native surfaces are wired into editor-local generators.
370
+ pass
364
371
  else:
365
- print(f"Unknown profile: {profile} (valid: minimal, standard, strict)")
372
+ print(f"Unknown profile: {profile} (valid: minimal, standard, strict, full)")
366
373
  sys.exit(1)
367
374
  return only
368
375
 
@@ -714,7 +721,9 @@ def main() -> None:
714
721
  local_editors_arg: str = cfg["editors"]
715
722
  install_local_project(rules_dir, dry_run, reset, lang_modules or None,
716
723
  editors=local_editors_arg,
717
- merged_config=merged_config)
724
+ merged_config=merged_config,
725
+ profile=profile or "standard",
726
+ codex_skills=cfg.get("codex_skills", False))
718
727
  installed_eds: list[str] = [] # local install doesn't track global editors
719
728
  install_strict_git_hooks(profile, local, dry_run)
720
729
  else:
@@ -314,7 +314,9 @@ def _resolve_editors(editors_arg: str, cwd: Path) -> list[str]:
314
314
  def install_local_project(rules_dir: Path, dry_run: bool, reset: bool,
315
315
  language_modules: list[str] | None = None,
316
316
  editors: str = "",
317
- merged_config: dict | None = None) -> None:
317
+ merged_config: dict | None = None,
318
+ profile: str = "standard",
319
+ codex_skills: bool = False) -> None:
318
320
  """Install project-local configs.
319
321
 
320
322
  Claude Code configs (CLAUDE.md, settings, constitution) are always installed.
@@ -323,6 +325,17 @@ def install_local_project(rules_dir: Path, dry_run: bool, reset: bool,
323
325
  - ``--editors cursor,aider``: install only these
324
326
  - (empty): auto-detect from existing project files, install only those
325
327
 
328
+ ``profile`` controls which native surfaces are emitted for each editor:
329
+ - ``minimal`` / ``standard`` / ``strict``: rules (+ Copilot directory mode
330
+ and Gemini hooks from ``standard`` onwards — both non-breaking).
331
+ - ``full``: adds every native surface an editor can host (subagents,
332
+ custom commands, hooks, skill-catalogue pointers).
333
+
334
+ ``codex_skills`` (opt-in, off by default) additionally writes a full skill
335
+ mirror under ``.codex/skills/``. Required even for ``--profile full`` —
336
+ the mirror is intentionally gated behind an extra flag to keep the default
337
+ footprint small.
338
+
326
339
  If ``merged_config`` is provided (from .softspark-toolkit.json extends resolution),
327
340
  additional rules and constitution amendments from the base config are injected.
328
341
  """
@@ -340,10 +353,13 @@ def install_local_project(rules_dir: Path, dry_run: bool, reset: bool,
340
353
  print(f" Editors: {', '.join(resolved_editors)}")
341
354
  else:
342
355
  print(" Editors: none (use --editors <list> or --editors all to enable)")
356
+ if profile:
357
+ print(f" Profile: {profile}")
343
358
  print()
344
359
 
345
360
  if dry_run:
346
- _install_local_dry_run(reset, resolved_editors)
361
+ _install_local_dry_run(reset, resolved_editors, profile=profile,
362
+ codex_skills=codex_skills)
347
363
  if language_modules:
348
364
  print(f" Would inject language rules: {', '.join(language_modules)}")
349
365
  if merged_config:
@@ -382,7 +398,9 @@ def install_local_project(rules_dir: Path, dry_run: bool, reset: bool,
382
398
 
383
399
  # Install editor configs only for resolved editors
384
400
  _create_local_ai_tool_configs(cwd, rules_dir, resolved_editors,
385
- language_modules=language_modules)
401
+ language_modules=language_modules,
402
+ profile=profile,
403
+ codex_skills=codex_skills)
386
404
 
387
405
 
388
406
  def _apply_extends_config(cwd: Path, merged: dict) -> None:
@@ -533,7 +551,9 @@ def _inject_language_rules(cwd: Path, language_modules: list[str] | None) -> Non
533
551
  tmp_path.unlink(missing_ok=True)
534
552
 
535
553
 
536
- def _install_local_dry_run(reset: bool, editors: list[str] | None = None) -> None:
554
+ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
555
+ profile: str = "standard",
556
+ codex_skills: bool = False) -> None:
537
557
  eds = set(editors or [])
538
558
  if reset:
539
559
  print(" Would remove: CLAUDE.md, .claude/settings.local.json")
@@ -544,6 +564,10 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None) -> Non
544
564
  print(" Would create: .claude/settings.local.json (if missing)")
545
565
  print(" Would inject: .claude/constitution.md")
546
566
 
567
+ add_copilot_dir = profile in {"standard", "strict", "full"}
568
+ add_gemini_hooks = profile in {"standard", "strict", "full"}
569
+ add_native_surfaces = profile == "full"
570
+
547
571
  # Editor-specific dry-run messages
548
572
  _EDITOR_DRY_RUN = {
549
573
  "copilot": " Would inject: .github/copilot-instructions.md",
@@ -554,12 +578,31 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None) -> Non
554
578
  "aider": " Would generate: .aider.conf.yml + CONVENTIONS.md",
555
579
  "augment": " Would generate: .augment/rules/ai-toolkit-*.md",
556
580
  "antigravity": " Would generate: .agent/rules/ + .agent/workflows/",
581
+ "gemini": " Would generate: GEMINI.md",
557
582
  "opencode": " Would generate: AGENTS.md + .opencode/{agents,commands,plugins}/ + opencode.json",
558
583
  }
559
584
  for ed, msg in _EDITOR_DRY_RUN.items():
560
585
  if ed in eds:
561
586
  print(msg)
562
587
 
588
+ # Profile-driven extras (matrix in kb/reference/global-install-model.md)
589
+ if "copilot" in eds and add_copilot_dir:
590
+ print(" Would generate: .github/instructions/ + .github/prompts/ (profile >= standard)")
591
+ if "gemini" in eds and add_gemini_hooks:
592
+ print(" Would generate: .gemini/settings.json hooks (profile >= standard)")
593
+ if add_native_surfaces:
594
+ if "cursor" in eds:
595
+ print(" Would generate: .cursor/hooks.json + .cursor/agents/ (profile=full)")
596
+ if "windsurf" in eds:
597
+ print(" Would generate: .windsurf/hooks.json (profile=full)")
598
+ if "augment" in eds:
599
+ print(" Would generate: .augment/agents/ + .augment/commands/ + "
600
+ "$HOME/.augment/settings.json + .augment/skills/ (profile=full)")
601
+ if "gemini" in eds:
602
+ print(" Would generate: .gemini/commands/ + .gemini/skills/ (profile=full)")
603
+ if "codex" in eds and codex_skills:
604
+ print(" Would generate: .codex/skills/ full mirror (--codex-skills)")
605
+
563
606
  if not eds:
564
607
  print(" No editors selected (use --editors <list> or --editors all)")
565
608
 
@@ -695,10 +738,46 @@ def _install_codex_skills(cwd: Path) -> None:
695
738
  )
696
739
 
697
740
 
741
+ def _try_generator(module_name: str, *args, **kwargs) -> bool:
742
+ """Import and invoke ``<module>.generate(...)``.
743
+
744
+ Post v3.0.0 all referenced generators ship with the toolkit. An ImportError
745
+ here therefore indicates a real packaging bug, not a roll-out gap. We print
746
+ a loud error and re-raise so CI and interactive installs fail fast instead
747
+ of silently skipping a native surface.
748
+ """
749
+ try:
750
+ module = __import__(module_name)
751
+ except ImportError as exc:
752
+ print(f" INTERNAL ERROR: shipped generator '{module_name}' failed to "
753
+ f"import ({exc.msg}). Please file a bug at "
754
+ f"https://github.com/softspark/ai-toolkit/issues")
755
+ raise
756
+
757
+ gen = getattr(module, "generate", None)
758
+ if gen is None:
759
+ raise RuntimeError(
760
+ f"INTERNAL ERROR: shipped generator '{module_name}' has no "
761
+ f"generate() function. This is a packaging bug."
762
+ )
763
+
764
+ gen(*args, **kwargs)
765
+ return True
766
+
767
+
698
768
  def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
699
769
  editors: list[str],
700
- language_modules: list[str] | None = None) -> None:
770
+ language_modules: list[str] | None = None,
771
+ profile: str = "standard",
772
+ codex_skills: bool = False) -> None:
701
773
  eds = set(editors)
774
+ # `full` implies the `standard` additions (Copilot dir + Gemini hooks)
775
+ # plus every native-surface generator we ship. Normalize unknown
776
+ # profiles to `standard` so callers never produce a silent no-op.
777
+ _profile = profile if profile in {"minimal", "standard", "strict", "full"} else "standard"
778
+ add_copilot_dir = _profile in {"standard", "strict", "full"}
779
+ add_gemini_hooks = _profile in {"standard", "strict", "full"}
780
+ add_native_surfaces = _profile == "full"
702
781
 
703
782
  if "copilot" in eds:
704
783
  inject_with_rules(
@@ -706,6 +785,12 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
706
785
  cwd / ".github" / "copilot-instructions.md",
707
786
  rules_dir,
708
787
  )
788
+ # `standard` and above: emit path-specific instructions + prompt files
789
+ # (directory mode). `minimal` stays backwards-compatible with v2.
790
+ if add_copilot_dir:
791
+ from generate_copilot import generate as gen_copilot_dir
792
+ gen_copilot_dir(cwd, language_modules=language_modules,
793
+ rules_dir=rules_dir)
709
794
 
710
795
  if "cursor" in eds:
711
796
  inject_with_rules(
@@ -716,6 +801,9 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
716
801
  from generate_cursor_mdc import generate as gen_cursor_mdc
717
802
  gen_cursor_mdc(cwd, language_modules=language_modules,
718
803
  rules_dir=rules_dir)
804
+ if add_native_surfaces:
805
+ _try_generator("generate_cursor_hooks", cwd)
806
+ _try_generator("generate_cursor_agents", cwd)
719
807
 
720
808
  if "windsurf" in eds:
721
809
  inject_with_rules(
@@ -726,6 +814,8 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
726
814
  from generate_windsurf_rules import generate as gen_windsurf_rules
727
815
  gen_windsurf_rules(cwd, language_modules=language_modules,
728
816
  rules_dir=rules_dir)
817
+ if add_native_surfaces:
818
+ _try_generator("generate_windsurf_hooks", cwd)
729
819
 
730
820
  if "cline" in eds:
731
821
  # Migrate: remove legacy .clinerules single file (replaced by directory)
@@ -759,6 +849,13 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
759
849
  from generate_augment_rules import generate as gen_augment_rules
760
850
  gen_augment_rules(cwd, language_modules=language_modules,
761
851
  rules_dir=rules_dir)
852
+ if add_native_surfaces:
853
+ _try_generator("generate_augment_agents", cwd)
854
+ _try_generator("generate_augment_commands", cwd)
855
+ # Augment hooks live under $HOME/.augment/settings.json. The
856
+ # generator takes HOME (not cwd) per bucket-1 contract.
857
+ _try_generator("generate_augment_hooks", Path.home())
858
+ _try_generator("generate_augment_skills", cwd)
762
859
 
763
860
  if "antigravity" in eds:
764
861
  from generate_antigravity import generate as gen_antigravity
@@ -786,6 +883,24 @@ def _create_local_ai_tool_configs(cwd: Path, rules_dir: Path,
786
883
  print(" Created: .codex/hooks.json")
787
884
  # .agents/skills/ — filtered symlinks (Codex-compatible skills only)
788
885
  _install_codex_skills(cwd)
886
+ # .codex/skills/ — full mirror, gated behind explicit --codex-skills flag
887
+ # (does NOT activate automatically on --profile full — must opt in).
888
+ if codex_skills:
889
+ _try_generator("generate_codex_skills", cwd,
890
+ enable_codex_skills=True)
891
+
892
+ if "gemini" in eds:
893
+ # GEMINI.md — marker injection from the shared generator output
894
+ inject_with_rules(
895
+ "generate-gemini.sh",
896
+ cwd / "GEMINI.md",
897
+ rules_dir,
898
+ )
899
+ if add_gemini_hooks:
900
+ _try_generator("generate_gemini_hooks", cwd)
901
+ if add_native_surfaces:
902
+ _try_generator("generate_gemini_commands", cwd)
903
+ _try_generator("generate_gemini_skills", cwd)
789
904
 
790
905
  if "opencode" in eds:
791
906
  # AGENTS.md — shared with Codex via marker injection (opencode reads same file)
@@ -39,9 +39,26 @@ VALID_TOOLS = frozenset({
39
39
  })
40
40
 
41
41
  VALID_HOOK_EVENTS = frozenset({
42
- "SessionStart", "Notification", "PreToolUse", "PostToolUse", "Stop",
43
- "PreCompact", "SubagentStop", "UserPromptSubmit", "TaskCompleted",
44
- "TeammateIdle", "SubagentStart", "SessionEnd", "PermissionRequest", "Setup",
42
+ # Core lifecycle
43
+ "SessionStart", "SessionEnd", "UserPromptSubmit", "Notification",
44
+ # Tool lifecycle
45
+ "PreToolUse", "PostToolUse",
46
+ # Turn lifecycle
47
+ "Stop", "StopFailure",
48
+ # Subagent lifecycle
49
+ "SubagentStart", "SubagentStop",
50
+ # Compaction
51
+ "PreCompact", "PostCompact",
52
+ # Permissions & elicitation
53
+ "PermissionRequest", "PermissionDenied",
54
+ "Elicitation", "ElicitationResult",
55
+ # Agent Teams
56
+ "TaskCreated", "TaskCompleted", "TeammateIdle",
57
+ # Worktrees & environment
58
+ "WorktreeCreate", "WorktreeRemove",
59
+ "CwdChanged", "FileChanged", "ConfigChange",
60
+ # Setup / bootstrap
61
+ "Setup", "InstructionsLoaded",
45
62
  })
46
63
 
47
64
  VALID_KB_CATEGORIES = frozenset({