@softspark/ai-toolkit 4.14.0 → 4.15.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 (48) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +11 -10
  3. package/app/.claude-plugin/plugin.json +1 -1
  4. package/app/CLAUDE.md.template +3 -0
  5. package/app/agents/fact-checker.md +1 -1
  6. package/app/hooks/_search-capability.sh +3 -2
  7. package/app/hooks/stop-search-check.sh +2 -1
  8. package/benchmarks/ecosystem-doctor-snapshot.json +73 -31
  9. package/kb/procedures/maintenance-sop.md +26 -13
  10. package/kb/procedures/release-verification-sop.md +41 -36
  11. package/kb/reference/architecture-overview.md +23 -7
  12. package/kb/reference/codex-cli-compatibility.md +96 -36
  13. package/kb/reference/extension-api.md +52 -9
  14. package/kb/reference/global-install-model.md +53 -21
  15. package/kb/reference/hooks-catalog.md +44 -8
  16. package/kb/reference/mcp-editor-compatibility.md +27 -6
  17. package/kb/reference/mcp-templates.md +12 -6
  18. package/kb/reference/opencode-compatibility.md +13 -7
  19. package/kb/reference/plugin-pack-conventions.md +7 -7
  20. package/kb/reference/skills-catalog.md +3 -3
  21. package/kb/reference/supported-tools-registry.md +19 -17
  22. package/kb/reference/windows-support.md +26 -3
  23. package/llms-full.txt +443 -180
  24. package/llms.txt +1 -1
  25. package/manifest.json +1 -1
  26. package/package.json +2 -2
  27. package/scripts/codex_skill_adapter.py +448 -198
  28. package/scripts/dir_rules_shared.py +2 -11
  29. package/scripts/ecosystem_tools.json +29 -8
  30. package/scripts/emission.py +5 -91
  31. package/scripts/generate_agents_md.py +4 -87
  32. package/scripts/generate_codex.py +5 -95
  33. package/scripts/generate_codex_agents.py +242 -0
  34. package/scripts/generate_codex_hooks.py +648 -55
  35. package/scripts/generate_codex_skills.py +15 -6
  36. package/scripts/generate_copilot.py +771 -74
  37. package/scripts/generate_copilot_hooks.py +606 -0
  38. package/scripts/generate_cursor_hooks.py +453 -121
  39. package/scripts/generate_opencode_commands.py +4 -6
  40. package/scripts/inject_hook_cli.py +770 -205
  41. package/scripts/injection.py +102 -23
  42. package/scripts/install_steps/ai_tools.py +123 -83
  43. package/scripts/instruction_core.py +95 -0
  44. package/scripts/mcp_editors.py +934 -80
  45. package/scripts/mcp_manager.py +46 -26
  46. package/scripts/plugin.py +291 -114
  47. package/scripts/secure_fs.py +538 -0
  48. package/scripts/uninstall.py +1279 -208
@@ -0,0 +1,538 @@
1
+ """Pinned-directory filesystem mutations for trusted configuration roots.
2
+
3
+ All mutating syscalls operate relative to directory descriptors opened with
4
+ ``O_NOFOLLOW``. Parent descriptors stay open for the whole transaction, so an
5
+ ancestor rename or symlink swap cannot redirect writes or rollback outside the
6
+ declared trust boundary.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import secrets
13
+ import stat
14
+ from collections import deque
15
+ from dataclasses import dataclass
16
+ from pathlib import Path
17
+ from typing import Callable, TypeVar
18
+
19
+
20
+ SECURE_DIR_FD = (
21
+ hasattr(os, "O_DIRECTORY")
22
+ and hasattr(os, "O_NOFOLLOW")
23
+ and all(
24
+ function in os.supports_dir_fd
25
+ for function in (
26
+ os.open,
27
+ os.unlink,
28
+ os.rmdir,
29
+ os.mkdir,
30
+ os.rename,
31
+ os.stat,
32
+ os.readlink,
33
+ os.symlink,
34
+ )
35
+ )
36
+ )
37
+
38
+ _DIRECTORY_FLAGS = (
39
+ os.O_RDONLY
40
+ | getattr(os, "O_CLOEXEC", 0)
41
+ | getattr(os, "O_DIRECTORY", 0)
42
+ | getattr(os, "O_NOFOLLOW", 0)
43
+ )
44
+ _READ_FLAGS = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
45
+ _WRITE_FLAGS = (
46
+ os.O_WRONLY
47
+ | os.O_CREAT
48
+ | os.O_EXCL
49
+ | getattr(os, "O_CLOEXEC", 0)
50
+ | getattr(os, "O_NOFOLLOW", 0)
51
+ )
52
+
53
+
54
+ @dataclass(frozen=True)
55
+ class SecureDestination:
56
+ path: Path
57
+ trusted_root: Path
58
+ label: str
59
+
60
+
61
+ @dataclass(frozen=True)
62
+ class _Snapshot:
63
+ existed: bool
64
+ content: bytes | None
65
+ mode: int
66
+ device: int | None
67
+ inode: int | None
68
+
69
+
70
+ @dataclass
71
+ class _PinnedDestination:
72
+ destination: SecureDestination
73
+ parent_fd: int
74
+ target_name: str
75
+ missing_parent_parts: tuple[str, ...]
76
+ snapshot: _Snapshot
77
+ materialized: bool
78
+
79
+
80
+ def lexical_absolute(path: str | os.PathLike[str]) -> Path:
81
+ """Return an absolute normalized path without resolving symlinks."""
82
+ return Path(os.path.abspath(os.path.expanduser(os.fspath(path))))
83
+
84
+
85
+ def nearest_existing_root(path: Path) -> Path:
86
+ """Return the closest existing real directory at or above ``path``."""
87
+ candidate = lexical_absolute(path)
88
+ while not candidate.exists() and not candidate.is_symlink():
89
+ parent = candidate.parent
90
+ if parent == candidate:
91
+ break
92
+ candidate = parent
93
+ if candidate.is_symlink():
94
+ raise RuntimeError(f"Refusing symlinked destination ancestor: {candidate}")
95
+ if not candidate.is_dir():
96
+ raise RuntimeError(f"Destination ancestor is not a directory: {candidate}")
97
+ return candidate
98
+
99
+
100
+ def _open_absolute_directory(path: Path) -> int:
101
+ """Resolve and open every absolute-path component from a stable root fd."""
102
+ absolute = lexical_absolute(path)
103
+ pending = deque(absolute.parts[1:])
104
+ descriptors = [os.open(os.sep, _DIRECTORY_FLAGS)]
105
+ symlink_expansions = 0
106
+ try:
107
+ while pending:
108
+ part = pending.popleft()
109
+ if part in ("", "."):
110
+ continue
111
+ if part == "..":
112
+ if len(descriptors) == 1:
113
+ raise RuntimeError(f"Trusted root escapes filesystem root: {path}")
114
+ os.close(descriptors.pop())
115
+ continue
116
+ try:
117
+ next_fd = os.open(part, _DIRECTORY_FLAGS, dir_fd=descriptors[-1])
118
+ except OSError as open_error:
119
+ if not pending:
120
+ raise open_error
121
+ try:
122
+ link_target = os.readlink(part, dir_fd=descriptors[-1])
123
+ except OSError:
124
+ raise open_error
125
+ symlink_expansions += 1
126
+ if symlink_expansions > 40:
127
+ raise RuntimeError(f"Too many symlinks in trusted root: {path}")
128
+ target_parts = list(Path(link_target).parts)
129
+ if os.path.isabs(link_target):
130
+ while len(descriptors) > 1:
131
+ os.close(descriptors.pop())
132
+ target_parts = target_parts[1:]
133
+ pending.extendleft(reversed(target_parts))
134
+ continue
135
+ descriptors.append(next_fd)
136
+ except BaseException:
137
+ for descriptor in reversed(descriptors):
138
+ try:
139
+ os.close(descriptor)
140
+ except OSError:
141
+ pass
142
+ raise
143
+ directory_fd = descriptors.pop()
144
+ for descriptor in reversed(descriptors):
145
+ try:
146
+ os.close(descriptor)
147
+ except OSError:
148
+ pass
149
+ return directory_fd
150
+
151
+
152
+ def _parts(destination: SecureDestination) -> tuple[Path, Path, tuple[str, ...]]:
153
+ path = lexical_absolute(destination.path)
154
+ root = lexical_absolute(destination.trusted_root)
155
+ try:
156
+ relative = path.relative_to(root)
157
+ except ValueError as error:
158
+ raise RuntimeError(
159
+ f"{destination.label} escapes trusted root {root}: {path}"
160
+ ) from error
161
+ if relative == Path(".") or not relative.parts or ".." in relative.parts:
162
+ raise RuntimeError(f"Refusing mutation of trusted root itself: {path}")
163
+ return path, root, relative.parts
164
+
165
+
166
+ def _read_regular_file(parent_fd: int, name: str, label: str) -> _Snapshot:
167
+ try:
168
+ metadata = os.stat(name, dir_fd=parent_fd, follow_symlinks=False)
169
+ except FileNotFoundError:
170
+ return _Snapshot(False, None, 0o600, None, None)
171
+ if not stat.S_ISREG(metadata.st_mode):
172
+ raise RuntimeError(f"Refusing non-regular {label} destination: {name}")
173
+
174
+ file_fd = os.open(name, _READ_FLAGS, dir_fd=parent_fd)
175
+ primary_error: BaseException | None = None
176
+ try:
177
+ opened = os.fstat(file_fd)
178
+ if not stat.S_ISREG(opened.st_mode):
179
+ raise RuntimeError(f"Refusing non-regular {label} destination: {name}")
180
+ with os.fdopen(file_fd, "rb") as handle:
181
+ file_fd = -1
182
+ content = handle.read()
183
+ except BaseException as error:
184
+ primary_error = error
185
+ raise
186
+ finally:
187
+ if file_fd >= 0:
188
+ try:
189
+ os.close(file_fd)
190
+ except OSError:
191
+ if primary_error is None:
192
+ raise
193
+ return _Snapshot(
194
+ True,
195
+ content,
196
+ stat.S_IMODE(opened.st_mode),
197
+ opened.st_dev,
198
+ opened.st_ino,
199
+ )
200
+
201
+
202
+ class SecureTransaction:
203
+ """Hold pinned parent descriptors for apply and byte-exact rollback."""
204
+
205
+ def __init__(self, destinations: list[SecureDestination]) -> None:
206
+ if not SECURE_DIR_FD:
207
+ raise RuntimeError("Secure mutations require POSIX dir_fd and O_NOFOLLOW")
208
+ self._pinned: dict[Path, _PinnedDestination] = {}
209
+ self._root_fds: dict[Path, int] = {}
210
+ self._created_directories: list[tuple[int, str]] = []
211
+ self._touched: set[Path] = set()
212
+ try:
213
+ for destination in destinations:
214
+ path = lexical_absolute(destination.path)
215
+ if path in self._pinned:
216
+ existing_root = self._pinned[path].destination.trusted_root
217
+ if lexical_absolute(destination.trusted_root) != existing_root:
218
+ raise RuntimeError(
219
+ f"Conflicting trusted roots for destination: {path}"
220
+ )
221
+ continue
222
+ self._pinned[path] = self._prepare(destination)
223
+ except BaseException:
224
+ self.close()
225
+ raise
226
+
227
+ def _prepare(self, destination: SecureDestination) -> _PinnedDestination:
228
+ path, root, parts = _parts(destination)
229
+ root_fd = self._root_fds.get(root)
230
+ if root_fd is None:
231
+ try:
232
+ root_fd = _open_absolute_directory(root)
233
+ except OSError as error:
234
+ raise RuntimeError(
235
+ f"Refusing unsafe trusted root for {destination.label}: "
236
+ f"{root}: {error}"
237
+ ) from error
238
+ self._root_fds[root] = root_fd
239
+ directory_fd = os.dup(root_fd)
240
+ missing: list[str] = []
241
+ try:
242
+ for part in parts[:-1]:
243
+ if missing:
244
+ missing.append(part)
245
+ continue
246
+ try:
247
+ next_fd = os.open(part, _DIRECTORY_FLAGS, dir_fd=directory_fd)
248
+ except FileNotFoundError:
249
+ missing.append(part)
250
+ continue
251
+ os.close(directory_fd)
252
+ directory_fd = next_fd
253
+ snapshot = (
254
+ _Snapshot(False, None, 0o600, None, None)
255
+ if missing
256
+ else _read_regular_file(directory_fd, parts[-1], destination.label)
257
+ )
258
+ except BaseException as error:
259
+ try:
260
+ os.close(directory_fd)
261
+ except OSError:
262
+ pass
263
+ if not isinstance(error, OSError):
264
+ raise
265
+ raise RuntimeError(
266
+ f"Refusing unsafe ancestor for {destination.label}: {path.parent}: {error}"
267
+ ) from error
268
+ return _PinnedDestination(
269
+ SecureDestination(path, root, destination.label),
270
+ directory_fd,
271
+ parts[-1],
272
+ tuple(missing),
273
+ snapshot,
274
+ not missing,
275
+ )
276
+
277
+ def materialize_parents(self) -> None:
278
+ """Create missing ancestors only after every destination is preflighted."""
279
+ for pinned in self._pinned.values():
280
+ if not pinned.missing_parent_parts:
281
+ continue
282
+ directory_fd = pinned.parent_fd
283
+ for part in pinned.missing_parent_parts:
284
+ created = False
285
+ try:
286
+ os.mkdir(part, mode=0o755, dir_fd=directory_fd)
287
+ created = True
288
+ except FileExistsError:
289
+ pass
290
+ if created:
291
+ self._created_directories.append((os.dup(directory_fd), part))
292
+ os.fsync(directory_fd)
293
+ try:
294
+ next_fd = os.open(part, _DIRECTORY_FLAGS, dir_fd=directory_fd)
295
+ except OSError as error:
296
+ raise RuntimeError(
297
+ f"Refusing unsafe created ancestor for "
298
+ f"{pinned.destination.label}: {error}"
299
+ ) from error
300
+ os.close(directory_fd)
301
+ directory_fd = next_fd
302
+ pinned.parent_fd = directory_fd
303
+ pinned.parent_fd = directory_fd
304
+ pinned.missing_parent_parts = ()
305
+ pinned.materialized = True
306
+ if self._exists(pinned):
307
+ raise RuntimeError(
308
+ f"{pinned.destination.label} appeared during secure preparation"
309
+ )
310
+
311
+ @staticmethod
312
+ def _exists(pinned: _PinnedDestination) -> bool:
313
+ try:
314
+ os.stat(
315
+ pinned.target_name,
316
+ dir_fd=pinned.parent_fd,
317
+ follow_symlinks=False,
318
+ )
319
+ return True
320
+ except FileNotFoundError:
321
+ return False
322
+
323
+ def _get(self, destination: SecureDestination) -> _PinnedDestination:
324
+ path = lexical_absolute(destination.path)
325
+ try:
326
+ return self._pinned[path]
327
+ except KeyError as error:
328
+ raise RuntimeError(f"Destination was not pinned: {path}") from error
329
+
330
+ def initial_content(self, destination: SecureDestination) -> bytes | None:
331
+ """Return the bytes captured through the pinned parent descriptor."""
332
+ return self._get(destination).snapshot.content
333
+
334
+ def atomic_write(
335
+ self,
336
+ destination: SecureDestination,
337
+ content: bytes,
338
+ mode: int | None = None,
339
+ ) -> None:
340
+ self._atomic_write(destination, content, mode, enforce_snapshot=True)
341
+
342
+ def _atomic_write(
343
+ self,
344
+ destination: SecureDestination,
345
+ content: bytes,
346
+ mode: int | None,
347
+ *,
348
+ enforce_snapshot: bool,
349
+ ) -> None:
350
+ pinned = self._get(destination)
351
+ if not pinned.materialized:
352
+ raise RuntimeError(
353
+ f"Destination parent was not materialized: {pinned.destination.path}"
354
+ )
355
+ if pinned.snapshot.existed:
356
+ file_mode = pinned.snapshot.mode
357
+ set_exact_mode = True
358
+ elif mode is None:
359
+ file_mode = 0o600
360
+ set_exact_mode = False
361
+ else:
362
+ file_mode = mode
363
+ set_exact_mode = True
364
+ temporary_name = f".{pinned.target_name}.{secrets.token_hex(8)}.tmp"
365
+ temporary_fd = -1
366
+ primary_error: BaseException | None = None
367
+ try:
368
+ temporary_fd = os.open(
369
+ temporary_name,
370
+ _WRITE_FLAGS,
371
+ file_mode,
372
+ dir_fd=pinned.parent_fd,
373
+ )
374
+ with os.fdopen(temporary_fd, "wb") as handle:
375
+ temporary_fd = -1
376
+ handle.write(content)
377
+ handle.flush()
378
+ if set_exact_mode:
379
+ os.fchmod(handle.fileno(), file_mode)
380
+ os.fsync(handle.fileno())
381
+ current = None
382
+ try:
383
+ current = os.stat(
384
+ pinned.target_name,
385
+ dir_fd=pinned.parent_fd,
386
+ follow_symlinks=False,
387
+ )
388
+ except FileNotFoundError:
389
+ pass
390
+ if current is not None and not stat.S_ISREG(current.st_mode):
391
+ raise RuntimeError(
392
+ f"Refusing replaced {pinned.destination.label} destination"
393
+ )
394
+ if enforce_snapshot:
395
+ if not pinned.snapshot.existed and current is not None:
396
+ raise RuntimeError(
397
+ f"Unexpected {pinned.destination.label} destination appeared"
398
+ )
399
+ if pinned.snapshot.existed and (
400
+ current is None
401
+ or current.st_dev != pinned.snapshot.device
402
+ or current.st_ino != pinned.snapshot.inode
403
+ ):
404
+ raise RuntimeError(
405
+ f"Refusing changed {pinned.destination.label} destination"
406
+ )
407
+ self._touched.add(pinned.destination.path)
408
+ os.replace(
409
+ temporary_name,
410
+ pinned.target_name,
411
+ src_dir_fd=pinned.parent_fd,
412
+ dst_dir_fd=pinned.parent_fd,
413
+ )
414
+ os.fsync(pinned.parent_fd)
415
+ except BaseException as error:
416
+ primary_error = error
417
+ raise
418
+ finally:
419
+ cleanup_error: OSError | None = None
420
+ if temporary_fd >= 0:
421
+ try:
422
+ os.close(temporary_fd)
423
+ except OSError as error:
424
+ cleanup_error = error
425
+ try:
426
+ os.unlink(temporary_name, dir_fd=pinned.parent_fd)
427
+ except FileNotFoundError:
428
+ pass
429
+ except OSError as error:
430
+ cleanup_error = cleanup_error or error
431
+ if primary_error is None and cleanup_error is not None:
432
+ raise cleanup_error
433
+
434
+ def unlink(self, destination: SecureDestination) -> None:
435
+ self._unlink(destination, enforce_snapshot=True)
436
+
437
+ def _unlink(
438
+ self,
439
+ destination: SecureDestination,
440
+ *,
441
+ enforce_snapshot: bool,
442
+ ) -> None:
443
+ pinned = self._get(destination)
444
+ try:
445
+ metadata = os.stat(
446
+ pinned.target_name,
447
+ dir_fd=pinned.parent_fd,
448
+ follow_symlinks=False,
449
+ )
450
+ except FileNotFoundError:
451
+ return
452
+ if not stat.S_ISREG(metadata.st_mode):
453
+ raise RuntimeError(
454
+ f"Refusing to unlink non-regular {pinned.destination.label}"
455
+ )
456
+ if enforce_snapshot and (
457
+ not pinned.snapshot.existed
458
+ or metadata.st_dev != pinned.snapshot.device
459
+ or metadata.st_ino != pinned.snapshot.inode
460
+ ):
461
+ raise RuntimeError(
462
+ f"Refusing changed {pinned.destination.label} destination"
463
+ )
464
+ self._touched.add(pinned.destination.path)
465
+ os.unlink(pinned.target_name, dir_fd=pinned.parent_fd)
466
+ os.fsync(pinned.parent_fd)
467
+
468
+ def rollback(self) -> None:
469
+ errors: list[Exception] = []
470
+ for pinned in reversed(list(self._pinned.values())):
471
+ if not pinned.materialized or pinned.destination.path not in self._touched:
472
+ continue
473
+ try:
474
+ if pinned.snapshot.existed:
475
+ assert pinned.snapshot.content is not None
476
+ self._atomic_write(
477
+ pinned.destination,
478
+ pinned.snapshot.content,
479
+ pinned.snapshot.mode,
480
+ enforce_snapshot=False,
481
+ )
482
+ else:
483
+ self._unlink(pinned.destination, enforce_snapshot=False)
484
+ except Exception as error: # pragma: no cover - catastrophic I/O
485
+ errors.append(error)
486
+ for parent_fd, name in reversed(self._created_directories):
487
+ try:
488
+ os.rmdir(name, dir_fd=parent_fd)
489
+ os.fsync(parent_fd)
490
+ except Exception as error: # pragma: no cover - catastrophic I/O
491
+ errors.append(error)
492
+ if errors:
493
+ raise RuntimeError(f"Secure rollback was incomplete: {errors}")
494
+
495
+ def close(self) -> None:
496
+ for pinned in self._pinned.values():
497
+ if pinned.parent_fd >= 0:
498
+ try:
499
+ os.close(pinned.parent_fd)
500
+ except OSError:
501
+ pass
502
+ pinned.parent_fd = -1
503
+ for root_fd in self._root_fds.values():
504
+ try:
505
+ os.close(root_fd)
506
+ except OSError:
507
+ pass
508
+ self._root_fds.clear()
509
+ for parent_fd, _ in self._created_directories:
510
+ try:
511
+ os.close(parent_fd)
512
+ except OSError:
513
+ pass
514
+ self._created_directories.clear()
515
+
516
+
517
+ T = TypeVar("T")
518
+
519
+
520
+ def run_secure_transaction(
521
+ destinations: list[SecureDestination],
522
+ mutation: Callable[[SecureTransaction], T],
523
+ ) -> T:
524
+ """Preflight all paths, apply via pinned fds, and rollback on failure."""
525
+ transaction = SecureTransaction(destinations)
526
+ try:
527
+ transaction.materialize_parents()
528
+ return mutation(transaction)
529
+ except BaseException as error:
530
+ try:
531
+ transaction.rollback()
532
+ except Exception as rollback_error:
533
+ raise RuntimeError(
534
+ f"Secure mutation failed and rollback was incomplete: {rollback_error}"
535
+ ) from error
536
+ raise
537
+ finally:
538
+ transaction.close()