@softspark/ai-toolkit 4.6.0 → 4.7.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.
- package/CHANGELOG.md +18 -0
- package/README.md +11 -11
- package/app/.claude-plugin/plugin.json +1 -1
- package/benchmarks/ecosystem-doctor-snapshot.json +21 -12
- package/kb/procedures/maintenance-sop.md +9 -8
- package/kb/procedures/release-verification-sop.md +1 -1
- package/kb/reference/architecture-overview.md +4 -4
- package/kb/reference/supported-tools-registry.md +29 -24
- package/llms-full.txt +43 -37
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/ecosystem_tools.json +60 -9
- package/scripts/generate_antigravity.py +22 -15
- package/scripts/generate_cursor_mdc.py +4 -3
- package/scripts/generate_windsurf_hooks.py +6 -0
- package/scripts/generate_windsurf_rules.py +39 -24
- package/scripts/generate_windsurf_skills.py +14 -4
- package/scripts/install_steps/ai_tools.py +21 -4
- package/scripts/validate.py +1 -0
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Generate ``.windsurf/rules/*.md`` (and workflows)
|
|
2
|
+
"""Generate ``.devin/rules/*.md`` and ``.windsurf/rules/*.md`` (and workflows)
|
|
3
|
+
for Devin Desktop (formerly Windsurf).
|
|
3
4
|
|
|
4
|
-
Windsurf
|
|
5
|
-
|
|
6
|
-
(
|
|
5
|
+
Windsurf rebranded to Devin Desktop on 2026-06-02. ``.devin/`` is now the
|
|
6
|
+
primary read+write workspace tree; ``.windsurf/`` is a legacy read-only
|
|
7
|
+
fallback that current builds still honor (docs.devin.ai/desktop/devin-desktop-faq:
|
|
8
|
+
"The application already supports .devin/ as the primary workspace directory
|
|
9
|
+
and falls back to .windsurf/ for backward compatibility"). We dual-emit the
|
|
10
|
+
same content to both trees so old Windsurf builds keep working during the
|
|
11
|
+
transition.
|
|
12
|
+
|
|
13
|
+
Each rule file supports YAML frontmatter with these fields
|
|
14
|
+
(from docs.devin.ai/desktop — memories docs):
|
|
7
15
|
|
|
8
16
|
* ``trigger`` — activation mode: ``always_on`` | ``glob`` | ``model_decision``
|
|
9
|
-
| ``manual``. When omitted,
|
|
17
|
+
| ``manual``. When omitted, the IDE defaults to manual-only.
|
|
10
18
|
* ``globs`` — comma-separated glob patterns (only when ``trigger: glob``).
|
|
11
19
|
* ``description`` — shown to the model when ``trigger: model_decision``.
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
Workflow markdown files (invoked via ``/<name>`` slash commands) are emitted
|
|
22
|
+
to ``.devin/workflows/*.md`` and ``.windsurf/workflows/*.md``. This generator
|
|
15
23
|
emits the same workflow catalogue used by Antigravity and Cline.
|
|
16
24
|
|
|
17
25
|
The legacy ``.windsurfrules`` single-file format is still produced by
|
|
@@ -142,20 +150,26 @@ def _build_rules(language_modules: list[str] | None,
|
|
|
142
150
|
|
|
143
151
|
|
|
144
152
|
# ---------------------------------------------------------------------------
|
|
145
|
-
# Workflows —
|
|
153
|
+
# Workflows — <tree>/workflows/<name>.md invocable via /<name>
|
|
146
154
|
# ---------------------------------------------------------------------------
|
|
147
155
|
|
|
156
|
+
# .devin/ is primary since the 2026-06-02 Devin Desktop rebrand; .windsurf/
|
|
157
|
+
# is the legacy fallback still read by pre-rebrand builds.
|
|
158
|
+
CONFIG_TREES: tuple[str, ...] = (".devin", ".windsurf")
|
|
159
|
+
|
|
160
|
+
|
|
148
161
|
def _write_workflows(target_dir: Path, *, cleanup: bool = True) -> None:
|
|
149
|
-
"""Write
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
"""Write ``workflows/*.md`` slash-command files to both config trees."""
|
|
163
|
+
for tree in CONFIG_TREES:
|
|
164
|
+
workflows_dir = target_dir / tree / "workflows"
|
|
165
|
+
workflows_dir.mkdir(parents=True, exist_ok=True)
|
|
152
166
|
|
|
153
|
-
|
|
154
|
-
|
|
167
|
+
if cleanup:
|
|
168
|
+
cleanup_stale(workflows_dir, set(STANDARD_WORKFLOWS.keys()))
|
|
155
169
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
170
|
+
for filename, content_fn in STANDARD_WORKFLOWS.items():
|
|
171
|
+
(workflows_dir / filename).write_text(content_fn(), encoding="utf-8")
|
|
172
|
+
print(f" Generated: {tree}/workflows/{filename}")
|
|
159
173
|
|
|
160
174
|
|
|
161
175
|
# ---------------------------------------------------------------------------
|
|
@@ -170,15 +184,16 @@ def generate(target_dir: Path, *,
|
|
|
170
184
|
managed_scopes: tuple[str, ...] = (
|
|
171
185
|
STANDARD_SCOPE, LANG_SCOPE, CUSTOM_SCOPE,
|
|
172
186
|
)) -> None:
|
|
173
|
-
"""Write
|
|
187
|
+
"""Write ``rules/*.md`` and ``workflows/*.md`` to both config trees."""
|
|
174
188
|
rules = _build_rules(language_modules, rules_dir)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
for tree in CONFIG_TREES:
|
|
190
|
+
write_rules(
|
|
191
|
+
target_dir,
|
|
192
|
+
rules,
|
|
193
|
+
f"{tree}/rules",
|
|
194
|
+
cleanup=cleanup,
|
|
195
|
+
managed_scopes=managed_scopes,
|
|
196
|
+
)
|
|
182
197
|
|
|
183
198
|
if emit_workflows:
|
|
184
199
|
_write_workflows(target_dir, cleanup=cleanup)
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Generate a Windsurf skill pointer
|
|
2
|
+
"""Generate a Devin Desktop (formerly Windsurf) skill pointer.
|
|
3
|
+
|
|
4
|
+
Dual-emits under ``.devin/skills/`` (primary since the 2026-06-02 rebrand)
|
|
5
|
+
and ``.windsurf/skills/`` (legacy fallback). Pass an explicit ``skill_root``
|
|
6
|
+
to emit a single location instead (used for the ``~/.codeium/windsurf/``
|
|
7
|
+
global install path).
|
|
8
|
+
"""
|
|
3
9
|
from __future__ import annotations
|
|
4
10
|
|
|
5
11
|
import sys
|
|
@@ -8,13 +14,17 @@ from pathlib import Path
|
|
|
8
14
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
9
15
|
from skill_pointer import POINTER_SKILL_NAME, write_pointer_skill
|
|
10
16
|
|
|
17
|
+
DEFAULT_SKILL_ROOTS: tuple[str, ...] = (".devin/skills", ".windsurf/skills")
|
|
18
|
+
|
|
11
19
|
|
|
12
20
|
def generate(target_dir: Path, *, emit_skill_pointer: bool = True,
|
|
13
|
-
skill_root: str =
|
|
21
|
+
skill_root: str | None = None) -> None:
|
|
14
22
|
if not emit_skill_pointer:
|
|
15
23
|
return
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
roots = (skill_root,) if skill_root else DEFAULT_SKILL_ROOTS
|
|
25
|
+
for root in roots:
|
|
26
|
+
write_pointer_skill(target_dir, root, "Windsurf")
|
|
27
|
+
print(f" Generated: {root}/{POINTER_SKILL_NAME}/SKILL.md")
|
|
18
28
|
|
|
19
29
|
|
|
20
30
|
def main() -> None:
|
|
@@ -381,6 +381,9 @@ _EDITOR_MARKERS: dict[str, str] = {
|
|
|
381
381
|
".cursor/rules": "cursor",
|
|
382
382
|
".windsurfrules": "windsurf",
|
|
383
383
|
".windsurf/rules": "windsurf",
|
|
384
|
+
# .devin/ is the primary Devin Desktop tree since the 2026-06-02 rebrand;
|
|
385
|
+
# .windsurf/ markers stay to detect legacy installs.
|
|
386
|
+
".devin/rules": "windsurf",
|
|
384
387
|
".clinerules": "cline",
|
|
385
388
|
".roomodes": "roo",
|
|
386
389
|
".roo/rules": "roo",
|
|
@@ -411,11 +414,25 @@ def _detect_editors(cwd: Path) -> list[str]:
|
|
|
411
414
|
found: set[str] = set()
|
|
412
415
|
for marker, editor in _EDITOR_MARKERS.items():
|
|
413
416
|
p = cwd / marker
|
|
414
|
-
if p.exists():
|
|
415
|
-
|
|
417
|
+
if not p.exists():
|
|
418
|
+
continue
|
|
419
|
+
if marker == ".agents/skills" and _is_pointer_only_skills_dir(p):
|
|
420
|
+
# The Antigravity CLI pointer skill also lives in .agents/skills/;
|
|
421
|
+
# only real (materialized) skills indicate a Codex install.
|
|
422
|
+
continue
|
|
423
|
+
found.add(editor)
|
|
416
424
|
return sorted(found)
|
|
417
425
|
|
|
418
426
|
|
|
427
|
+
def _is_pointer_only_skills_dir(skills_dir: Path) -> bool:
|
|
428
|
+
"""True when a skills dir holds only the ai-toolkit pointer skill."""
|
|
429
|
+
try:
|
|
430
|
+
entries = [e.name for e in skills_dir.iterdir() if not e.name.startswith(".")]
|
|
431
|
+
except OSError:
|
|
432
|
+
return False
|
|
433
|
+
return entries == ["ai-toolkit-skill-catalogue"]
|
|
434
|
+
|
|
435
|
+
|
|
419
436
|
def _resolve_editors(editors_arg: str, cwd: Path) -> list[str]:
|
|
420
437
|
"""Resolve --editors argument to a list of editor names.
|
|
421
438
|
|
|
@@ -709,7 +726,7 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
|
|
|
709
726
|
_EDITOR_DRY_RUN = {
|
|
710
727
|
"copilot": " Would inject: .github/copilot-instructions.md",
|
|
711
728
|
"cursor": " Would generate: .cursorrules + .cursor/rules/*.mdc",
|
|
712
|
-
"windsurf": " Would generate: .windsurfrules + .windsurf/rules/*.md",
|
|
729
|
+
"windsurf": " Would generate: .windsurfrules + .devin/rules/*.md + .windsurf/rules/*.md",
|
|
713
730
|
"cline": " Would generate: .clinerules/*.md",
|
|
714
731
|
"roo": " Would generate: .roomodes + .roo/rules/*.md",
|
|
715
732
|
"aider": " Would generate: .aider.conf.yml + CONVENTIONS.md",
|
|
@@ -731,7 +748,7 @@ def _install_local_dry_run(reset: bool, editors: list[str] | None = None,
|
|
|
731
748
|
if "cursor" in eds:
|
|
732
749
|
print(" Would generate: .cursor/hooks.json + .cursor/agents/ + .cursor/skills/ (profile=full)")
|
|
733
750
|
if "windsurf" in eds:
|
|
734
|
-
print(" Would generate: .windsurf/hooks.json + .windsurf/skills/ (profile=full)")
|
|
751
|
+
print(" Would generate: .windsurf/hooks.json + .devin/skills/ + .windsurf/skills/ (profile=full)")
|
|
735
752
|
if "cline" in eds:
|
|
736
753
|
print(" Would generate: .cline/skills/ (profile=full)")
|
|
737
754
|
if "augment" in eds:
|
package/scripts/validate.py
CHANGED