branch: externals/ellama
commit aff8c73aaf94d3a25a271ce453bbf57b096c9fbd
Author: Sergey Kostyaev <[email protected]>
Commit: Sergey Kostyaev <[email protected]>

    Check README command coverage
    
    Add a check-commands target to compare public Ellama commands with the 
README Commands section and include it in check-readme so documentation hooks 
catch missing or stale command entries. Use a static Elisp source parser to 
avoid load-time false negatives, document the DLP commands it reports, and 
refresh the generated Info manual.
---
 Makefile                    |   7 ++-
 README.org                  |   5 ++
 ellama.info                 |  88 +++++++++++++++--------------
 scripts/check-commands.sh   | 125 +++++++++++++++++++++++++++++++++++++++++
 scripts/extract-commands.el | 133 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 315 insertions(+), 43 deletions(-)

diff --git a/Makefile b/Makefile
index 232c72d485..ac3bea29a9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 # Makefile for ellama project
 
-.PHONY: build test test-detailed test-integration test-srt-integration 
docker-build-srt-parity test-srt-integration-linux check-compile-warnings 
checkdocs manual format-elisp install-git-hooks refill-news refill-readme 
check-elisp check-readme check-news check-custom-variables
+.PHONY: build test test-detailed test-integration test-srt-integration 
docker-build-srt-parity test-srt-integration-linux check-compile-warnings 
checkdocs manual format-elisp install-git-hooks refill-news refill-readme 
check-elisp check-readme check-news check-custom-variables check-commands
 
 SRT_PARITY_DOCKER_IMAGE ?= ellama-srt-parity:latest
 SRT_PARITY_DOCKERFILE ?= docker/srt-parity-linux.Dockerfile
@@ -114,9 +114,12 @@ refill-readme:
 
 check-elisp: format-elisp build test check-compile-warnings checkdocs
 
-check-readme: refill-readme manual check-custom-variables
+check-readme: refill-readme manual check-custom-variables check-commands
 
 check-news: refill-news
 
 check-custom-variables:
        ./scripts/check-custom-variables.sh
+
+check-commands:
+       ./scripts/check-commands.sh
diff --git a/README.org b/README.org
index 2bafa00c19..ed0d1501e8 100644
--- a/README.org
+++ b/README.org
@@ -253,6 +253,11 @@ More sophisticated configuration example:
   needed.
 - ~ellama-tools-disable-all~: Disable all enabled tools simultaneously. Use 
this
   command to reset the system to a minimal state, ensuring no tools are active.
+- ~ellama-tools-dlp-show-incident-stats~: Show a summary buffer with recent DLP
+  incident statistics.
+- ~ellama-tools-dlp-clear-session-bypasses~: Clear session-scoped DLP bypasses.
+- ~ellama-tools-dlp-reset-runtime-state~: Reset in-memory DLP runtime state,
+  including incident logs and detector caches.
 
 * Keymap
 
diff --git a/ellama.info b/ellama.info
index 37c78db3c7..f364a9248f 100644
--- a/ellama.info
+++ b/ellama.info
@@ -382,6 +382,12 @@ File: ellama.info,  Node: Commands,  Next: Keymap,  Prev: 
Installation,  Up: Top
    • ‘ellama-tools-disable-all’: Disable all enabled tools
      simultaneously.  Use this command to reset the system to a minimal
      state, ensuring no tools are active.
+   • ‘ellama-tools-dlp-show-incident-stats’: Show a summary buffer with
+     recent DLP incident statistics.
+   • ‘ellama-tools-dlp-clear-session-bypasses’: Clear session-scoped DLP
+     bypasses.
+   • ‘ellama-tools-dlp-reset-runtime-state’: Reset in-memory DLP runtime
+     state, including incident logs and detector caches.
 
 
 File: ellama.info,  Node: Keymap,  Next: Configuration,  Prev: Commands,  Up: 
Top
@@ -2646,47 +2652,47 @@ Tag Table:
 Node: Top1379
 Node: Installation3973
 Node: Commands8987
-Node: Keymap17925
-Node: Configuration20812
-Node: Session Provider Keys37385
-Node: Session Compaction39246
-Node: Image Input41540
-Node: Task Tool Subagents43685
-Node: Plan-and-Act Agent Loop46859
-Node: Edit Tool Shell Hooks49440
-Node: DLP for Tool Input/Output51733
-Node: SRT Filesystem Policy for Tools67732
-Node: Context Management73401
-Node: Transient Menus for Context Management74469
-Node: Managing the Context76148
-Node: Considerations76923
-Node: Minor modes77516
-Node: ellama-context-header-line-mode79504
-Node: ellama-context-header-line-global-mode80329
-Node: ellama-context-mode-line-mode81049
-Node: ellama-context-mode-line-global-mode81897
-Node: Ellama Session Header Line Mode82601
-Node: Enabling and Disabling83170
-Node: Customization83617
-Node: Ellama Session Mode Line Mode83905
-Node: Enabling and Disabling (1)84490
-Node: Customization (1)84937
-Node: Using Blueprints85231
-Node: Key Components of Ellama Blueprints85871
-Node: Creating and Managing Blueprints86478
-Node: Blueprints files87456
-Node: Variable Management87877
-Node: Keymap and Mode88330
-Node: Transient Menus89266
-Node: Running Blueprints programmatically89812
-Node: MCP Integration90399
-Node: Agent Skills91634
-Node: Directory Structure91997
-Node: Creating a Skill93024
-Node: How it works93399
-Node: Acknowledgments93790
-Node: Contributions94501
-Node: GNU Free Documentation License95175
+Node: Keymap18270
+Node: Configuration21157
+Node: Session Provider Keys37730
+Node: Session Compaction39591
+Node: Image Input41885
+Node: Task Tool Subagents44030
+Node: Plan-and-Act Agent Loop47204
+Node: Edit Tool Shell Hooks49785
+Node: DLP for Tool Input/Output52078
+Node: SRT Filesystem Policy for Tools68077
+Node: Context Management73746
+Node: Transient Menus for Context Management74814
+Node: Managing the Context76493
+Node: Considerations77268
+Node: Minor modes77861
+Node: ellama-context-header-line-mode79849
+Node: ellama-context-header-line-global-mode80674
+Node: ellama-context-mode-line-mode81394
+Node: ellama-context-mode-line-global-mode82242
+Node: Ellama Session Header Line Mode82946
+Node: Enabling and Disabling83515
+Node: Customization83962
+Node: Ellama Session Mode Line Mode84250
+Node: Enabling and Disabling (1)84835
+Node: Customization (1)85282
+Node: Using Blueprints85576
+Node: Key Components of Ellama Blueprints86216
+Node: Creating and Managing Blueprints86823
+Node: Blueprints files87801
+Node: Variable Management88222
+Node: Keymap and Mode88675
+Node: Transient Menus89611
+Node: Running Blueprints programmatically90157
+Node: MCP Integration90744
+Node: Agent Skills91979
+Node: Directory Structure92342
+Node: Creating a Skill93369
+Node: How it works93744
+Node: Acknowledgments94135
+Node: Contributions94846
+Node: GNU Free Documentation License95520
 
 End Tag Table
 
diff --git a/scripts/check-commands.sh b/scripts/check-commands.sh
new file mode 100755
index 0000000000..45ad008f9f
--- /dev/null
+++ b/scripts/check-commands.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+# check-commands.sh - Verify interactive command documentation coverage
+#
+# Usage: ./scripts/check-commands.sh [project-dir]
+# If project-dir is omitted, uses the current directory.
+#
+# Performs two checks:
+#   1. Verify all public commands are documented in README.org
+#   2. Verify all documented commands in README.org correspond to real commands
+#
+# Exit code 0 = all checks pass, 1 = discrepancies found
+
+set -euo pipefail
+
+# Determine project root (resolve to absolute path)
+PROJECT_DIR="${1:-$(pwd)}"
+PROJECT_DIR="$(cd "$PROJECT_DIR" && pwd)"
+README_FILE="$PROJECT_DIR/README.org"
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+echo "=== Ellama Interactive Command Documentation Checker ==="
+echo "Project directory: $PROJECT_DIR"
+echo "README file: $README_FILE"
+echo ""
+
+# Validate README.org exists
+if [ ! -f "$README_FILE" ]; then
+    echo "ERROR: README.org not found at $README_FILE"
+    exit 1
+fi
+
+# Validate Elisp extraction script exists
+if [ ! -f "$SCRIPT_DIR/extract-commands.el" ]; then
+    echo "ERROR: Elisp extraction script not found at 
$SCRIPT_DIR/extract-commands.el"
+    exit 1
+fi
+
+# Create temp files
+CMD_FILE=$(mktemp)
+DOCUMENTED_FILE=$(mktemp)
+TMP_RAW_DOCS=$(mktemp)
+
+trap "rm -f '$CMD_FILE' '$DOCUMENTED_FILE' '$TMP_RAW_DOCS'" EXIT
+
+# --- Step 1: Extract public commands using Emacs batch mode ---
+echo "--- Extracting public commands from .el files ---"
+
+# Use safe Emacs-based extraction to avoid false positives from regex.
+# Pass directory via environment variable to avoid command-line processing 
issues
+if ELLAMA_DIR="$PROJECT_DIR" emacs -Q -batch -l 
"$SCRIPT_DIR/extract-commands.el" 2>/dev/null > "$CMD_FILE"; then
+    CMD_COUNT=$(wc -l < "$CMD_FILE")
+    echo "Found $CMD_COUNT public commands in .el files."
+else
+    echo "ERROR: Failed to extract public commands."
+    exit 1
+fi
+echo ""
+
+# --- Step 2: Extract documented commands from README.org Commands section ---
+echo "--- Extracting documented commands from README.org Commands section ---"
+
+# Use oq to get Commands section range
+COMMANDS_SECTION_RANGE=$(oq "$README_FILE" ".section('Commands')" 2>&1 | head 
-1 || true)
+
+# Extract lines from Commands section
+if [ -n "$COMMANDS_SECTION_RANGE" ]; then
+    # Parse line range
+    START_LINE=$(echo "$COMMANDS_SECTION_RANGE" | sed -n 's/.*lines 
\([0-9]*\):.*/\1/p')
+    END_LINE=$(echo "$COMMANDS_SECTION_RANGE" | sed -n 's/.*lines 
[0-9]*:\([0-9]*\)).*/\1/p')
+
+    # Extract documented commands
+    sed -n "${START_LINE},${END_LINE}p" "$README_FILE" \
+        | grep -oE '~ellama-[a-zA-Z0-9_-]+~' \
+        | sed 's/~//g' \
+        | sort -u > "$TMP_RAW_DOCS" || true
+else
+    echo "WARNING: Could not locate Commands section with oq, using fallback."
+    sed -n '/^\* Commands$/,/^\* /p' "$README_FILE" \
+        | grep -oE '~ellama-[a-zA-Z0-9_-]*~' \
+        | sed 's/~//g' \
+        | sort -u > "$TMP_RAW_DOCS" || true
+fi
+
+sort -u "$TMP_RAW_DOCS" > "$DOCUMENTED_FILE"
+
+DOCUMENTED_COUNT=$(wc -l < "$DOCUMENTED_FILE")
+echo "Found $DOCUMENTED_COUNT documented commands in README.org."
+echo ""
+
+# --- Step 3: Compare and report ---
+echo "--- Checking coverage ---"
+echo ""
+
+# Check 1: Public commands not documented
+UNDOCUMENTED=$(comm -23 "$CMD_FILE" "$DOCUMENTED_FILE")
+if [ -n "$UNDOCUMENTED" ]; then
+    echo "ERROR: Public commands NOT documented in README.org:"
+    echo "$UNDOCUMENTED"
+    UNDOCUMENTED_FLAG=1
+else
+    echo "OK: All public commands are documented."
+    UNDOCUMENTED_FLAG=0
+fi
+echo ""
+
+# Check 2: Documented commands that don't exist
+EXTRA=$(comm -13 "$CMD_FILE" "$DOCUMENTED_FILE")
+if [ -n "$EXTRA" ]; then
+    echo "ERROR: Commands documented in README.org that do not exist:"
+    echo "$EXTRA"
+    EXTRA_FLAG=1
+else
+    echo "OK: All documented commands correspond to real functions."
+    EXTRA_FLAG=0
+fi
+echo ""
+
+# Exit with error if discrepancies
+if [ "$UNDOCUMENTED_FLAG" -eq 1 ] || [ "$EXTRA_FLAG" -eq 1 ]; then
+    echo "FAIL: Documentation coverage issues detected."
+    exit 1
+fi
+
+echo "PASS: All public commands are properly documented."
+exit 0
diff --git a/scripts/extract-commands.el b/scripts/extract-commands.el
new file mode 100644
index 0000000000..7ec746fa51
--- /dev/null
+++ b/scripts/extract-commands.el
@@ -0,0 +1,133 @@
+;;; extract-commands.el --- Extract documented public commands -*- 
lexical-binding: t -*-
+
+;; This script reads Ellama source files as forms.  It intentionally does not
+;; load the project, because loading depends on user packages and local runtime
+;; state and can silently miss commands in batch checks.
+
+(require 'cl-lib)
+
+(defconst check-commands--extra-public-commands
+  '(ellama-summarize-webpage
+    ellama-tools-dlp-clear-session-bypasses
+    ellama-tools-dlp-reset-runtime-state
+    ellama-tools-dlp-show-incident-stats)
+  "Interactive public commands without autoload cookies.")
+
+(defconst check-commands--ignored-commands
+  '(ellama-blueprint-chat-with-system-kill-buffer
+    ellama-blueprint-create
+    ellama-blueprint-edit-system-message
+    ellama-blueprint-new
+    ellama-blueprint-remove
+    ellama-blueprint-select
+    ellama-blueprint-select-user-defined-blueprint
+    ellama-blueprint-set-system-kill-buffer
+    ellama-chat-with-system-from-buffer
+    ellama-context-add-file-quote
+    ellama-context-add-info-node-quote
+    ellama-context-add-webpage-quote-eww
+    ellama-context-element-remove-by-name
+    ellama-eval-run-hypothesis-suite-interactive
+    ellama-kill-current-buffer
+    ellama-manual-export
+    ellama-send-buffer-to-new-chat
+    ellama-send-buffer-to-new-chat-then-kill
+    ellama-transient-ask-menu
+    ellama-transient-blueprint-menu
+    ellama-transient-blueprint-mode-menu
+    ellama-transient-code-menu
+    ellama-transient-context-menu
+    ellama-transient-improve-menu
+    ellama-transient-main-menu
+    ellama-transient-make-menu
+    ellama-transient-session-menu
+    ellama-transient-summarize-menu
+    ellama-transient-tools-menu
+    ellama-transient-translate-menu)
+  "Interactive commands intentionally excluded from README Commands coverage.")
+
+(defun check-commands--source-files (dir)
+  "Return Ellama source .el files in DIR."
+  (sort
+   (directory-files dir t "\\`ellama.*\\.el\\'")
+   #'string<))
+
+(defun check-commands--public-command-name-p (name)
+  "Return non-nil when NAME is an Ellama command name worth documenting."
+  (and (symbolp name)
+       (string-prefix-p "ellama-" (symbol-name name))
+       (not (string-prefix-p "ellama--" (symbol-name name)))
+       (not (memq name check-commands--ignored-commands))))
+
+(defun check-commands--interactive-body-p (body)
+  "Return non-nil when BODY starts with an `interactive' form."
+  (when (stringp (car body))
+    (setq body (cdr body)))
+  (while (and (consp (car body))
+              (eq (caar body) 'declare))
+    (setq body (cdr body)))
+  (and (consp (car body))
+       (eq (caar body) 'interactive)))
+
+(defun check-commands--command-form-name (form autoloadp)
+  "Return public command name from FORM when AUTOLOADP marks it as public."
+  (when (consp form)
+    (let ((head (car form))
+          (name (cadr form)))
+      (cond
+       ((memq head '(defun cl-defun))
+        (let ((body (cdddr form)))
+          (when (and autoloadp
+                     (check-commands--public-command-name-p name)
+                     (check-commands--interactive-body-p body))
+            name)))
+       ((eq head 'transient-define-prefix)
+        (when (and autoloadp
+                   (check-commands--public-command-name-p name))
+          name))))))
+
+(defun check-commands--extract-file (file)
+  "Return public command symbols found in FILE."
+  (let (commands)
+    (with-temp-buffer
+      (insert-file-contents file)
+      (emacs-lisp-mode)
+      (goto-char (point-min))
+      (while (not (eobp))
+        (condition-case nil
+            (let* ((comment-start (point))
+                   (_ (forward-comment (point-max)))
+                   (autoloadp
+                    (string-match-p
+                     ";;;###autoload"
+                     (buffer-substring-no-properties
+                      comment-start (point))))
+                   (form (unless (eobp)
+                           (read (current-buffer))))
+                   (name (check-commands--command-form-name form autoloadp)))
+              (when name
+                (push name commands)))
+          (end-of-file
+           (goto-char (point-max)))
+          (invalid-read-syntax
+           (forward-char 1))
+          (error
+           (forward-char 1)))))
+    commands))
+
+(defun check-commands--extract-public (dir)
+  "Extract public command names from Ellama sources in DIR."
+  (let ((commands (copy-sequence check-commands--extra-public-commands)))
+    (dolist (file (check-commands--source-files dir))
+      (setq commands (append (check-commands--extract-file file) commands)))
+    (dolist (command (sort (delete-dups commands)
+                           (lambda (left right)
+                             (string< (symbol-name left)
+                                      (symbol-name right)))))
+      (princ (format "%s\n" command)))))
+
+(when (and noninteractive (getenv "ELLAMA_DIR"))
+  (check-commands--extract-public (getenv "ELLAMA_DIR")))
+
+(provide 'extract-commands)
+;;; extract-commands.el ends here

Reply via email to