Download github_read_inference_v235.py from kamiloki/Swyrlz: direct link, hf CLI and curl.
- Browser
- Download file 15.5 kB
-
https://huggingface.co/spaces/kamiloki/Swyrlz/resolve/main/github_read_inference_v235.py
- Command line
-
hf download hf://spaces/kamiloki/Swyrlz/github_read_inference_v235.py
-
curl -L -o github_read_inference_v235.py https://huggingface.co/spaces/kamiloki/Swyrlz/resolve/main/github_read_inference_v235.py
15.5 kB
| """Read-only user question -> existing evidence command, never tool authority. | |
| Scope comes from explicit GitHub wording or a previously verified same-thread | |
| repository context. This classifier selects an allowed read, not the answer: | |
| GitHub results, pinned revisions and inspection limits still own the facts. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| _MUTATION = re.compile( | |
| r"\b(?:add|build|create|delete|deploy|dispatch|edit|fix|" | |
| r"implement|install|merge|modify|patch|push|refactor|remove|rename|" | |
| r"rerun|retry|rewrite|run|trigger|update|upload|write)\b", re.I) | |
| _REPO = re.compile(r"\b(?:github|repo|repository)\b", re.I) | |
| _READ = re.compile( | |
| r"\b(?:analy[sz]e|architecture|compare|count|describe|directory|" | |
| r"directories|display|browse|view|explain|explore|file|files|folder|folders|history|inspect|" | |
| r"how|largest|list|locate|modified|overview|read|relate|related|relationship|report|" | |
| r"search|see|show|size|source|structure|summari[sz]e|tree|what|" | |
| r"where|which|how many|when)\b", re.I) | |
| _PATH = re.compile( | |
| r"(?<![\w./])(?:[A-Za-z0-9_§.+-]+/){1,6}[A-Za-z0-9_§.+-]+" | |
| r"|(?<![\w./])[A-Za-z0-9_§.+-]+\.(?:py|js|mjs|ts|tsx|jsx|" | |
| r"html|css|json|md|txt|yaml|yml|toml|kt|java|go|rs|sh|xml|sql)", | |
| re.I) | |
| _BARE = re.compile(r"\b(?:folder|directory|under|inside|within|in)\s+" | |
| r"(?:the\s+)?(?:folder\s+|directory\s+)?" | |
| r"([A-Za-z0-9_§.-]{2,80})(?=\s|$)", re.I) | |
| _BAD_PATH = re.compile(r"[\\\x00-\x1f?#%*{}\[\]<>|]") | |
| _COMMAND = re.compile(r"^@github\s+", re.I) | |
| _PREFIX = re.compile(r"^@github\s+(?:ask\s+)?", re.I) | |
| _EXPLICIT_COMMAND = re.compile( | |
| r"^(?:@github\s+)(?:files|stats|largest|report|read|open|view|" | |
| r"history|search|compare|project status|chat status|permissions|" | |
| r"capabilities|help)(?:\s|$)", re.I) | |
| _DIRECT_PATH_READ = re.compile( | |
| # Exact, explicit, multi-component file reads can use the signed-in | |
| # account's selected repo even in a new thread. The authorized GitHub | |
| # command handler re-verifies access and the path before returning data. | |
| r"^(?:please\s+)?(?:read|open|view)\s+(?:the\s+)?(?:file\s+)?" | |
| r"((?:[A-Za-z0-9_§.+-]+/){1,6}[A-Za-z0-9_§.+-]+\." | |
| r"(?:py|js|mjs|ts|tsx|jsx|html|css|json|md|txt|yaml|yml|toml|" | |
| r"kt|java|go|rs|sh|xml|sql))[?.!\s]*$", re.I) | |
| def _safe(path): | |
| path = str(path or "").strip().strip("`\"'").rstrip(".,!?").strip("/") | |
| if (not path or len(path) > 160 or _BAD_PATH.search(path) | |
| or any(p in ("", ".", "..") for p in path.split("/"))): | |
| return "" | |
| return path | |
| def _scope_context(context): | |
| if not isinstance(context, dict): | |
| return "", "" | |
| # The account/tool layer separately re-verifies repository access. These | |
| # hints are never trusted as GitHub authorization or as source evidence. | |
| directory = _safe(context.get("directory")) | |
| file_path = _safe(context.get("lastFile")) | |
| return directory, file_path | |
| def _paths(question): | |
| found = [] | |
| for m in _PATH.finditer(question): | |
| item = _safe(m.group(0)) | |
| if item and item.casefold() not in [x.casefold() for x in found]: | |
| found.append(item) | |
| if len(found) == 8: | |
| break | |
| return found | |
| _CONVERSATIONAL_REFLECTION = re.compile( | |
| r"\b(?:what do you think|what(?:'s| is) your (?:opinion|take)|" | |
| r"(?:do|did) you (?:like|notice)|what (?:would|do) you say|" | |
| r"what you would say|from your perspective|" | |
| r"just wanted to (?:see|hear|know)|wanted to see what)\b", re.I) | |
| _EXPLICIT_READ_REQUEST = re.compile( | |
| r"^(?:(?:please\s+)|(?:(?:can|could|would)\s+you\s+(?:please\s+)?))?" | |
| r"(?:read|open|view|show|list|inspect|review|analy[sz]e|search|find)\b", re.I) | |
| _TECHNICAL_REVIEW = re.compile( | |
| r"\b(?:source|code|function|module|architecture|implementation|" | |
| r"logic|security|test coverage|structure|design|bugs?|" | |
| r"performance|technical|§tart|github|repo|repository|" | |
| r"analy[sz]e|review|debug|audit|" | |
| r"inspect|explain)\b", re.I) | |
| def is_conversational_reflection(prompt): | |
| """An opinion or social follow-up, not an implicit GitHub read/review. | |
| Intent is evaluated independently of existing verified repository scope: | |
| a file mention is context, not a request to fetch that file again. | |
| Explicit read/analysis actions and technical questions remain tool-eligible. | |
| """ | |
| raw = str(prompt or "").strip() | |
| return bool( | |
| raw and _CONVERSATIONAL_REFLECTION.search(raw) | |
| and not _COMMAND.match(raw) | |
| and not _EXPLICIT_READ_REQUEST.match(raw) | |
| and not _TECHNICAL_REVIEW.search(raw) | |
| ) | |
| def classify_read(prompt, context=None): | |
| """Return one *existing* Stage-1 @GitHub read command, or None. | |
| A natural-language question is not a source of new GitHub capabilities. | |
| Do not route writes, freeform dialogue, private-history recall, or ambiguous | |
| pronouns with no verified thread context into a repo operation. | |
| """ | |
| raw = str(prompt or "").strip() | |
| if not raw or len(raw) > 600 or "\n" in raw or "\r" in raw: | |
| return None | |
| if re.fullmatch( | |
| r"(?i)(?:what (?:is|are)|how does) (?:github|(?:a|the) (?:git )?repo(?:sitory)?)" | |
| r"(?: work)?[?.!]*", raw): | |
| return None # General GitHub education is not a connected-repository read. | |
| if _EXPLICIT_COMMAND.match(raw): | |
| return None # existing command owners handle their own parameters | |
| # v289: explicit repo-maturity questions select a pinned read-only | |
| # classification, never a guessed implementation or write capability. | |
| if re.fullmatch( | |
| r"(?i)(?:(?:is|was)\s+(?:our|my|the)\s+(?:github\s+)?(?:repo|repository)\s+" | |
| r"(?:empty|populated|ready\s+for\s+testing)|" | |
| r"how\s+ready\s+is\s+(?:our|my|the)\s+(?:github\s+)?(?:repo|repository))" | |
| r"[?.!]*", raw): | |
| return "@GitHub readiness" | |
| if is_conversational_reflection(raw): | |
| return None # social response owns this turn; retained GitHub scope is data | |
| # Match the entire read-only command BEFORE verb scans. Folder segments | |
| # such as "write-action-tests" are path data, not instructions to write. | |
| # No thread context is synthesized: the connected account's repository | |
| # and current Git revision are resolved inside the existing Stage-1 gate. | |
| direct = _DIRECT_PATH_READ.fullmatch(raw) | |
| if direct: | |
| path = _safe(direct[1]) | |
| if path: | |
| return "@GitHub read file " + path | |
| if _MUTATION.search(raw) or re.search(r"\bcommit\s+(?:my\s+|the\s+|these\s+)?(?:changes?|code|files?)\b", raw, re.I): | |
| return None | |
| if re.search(r"\b(?:remember|recall|previous chat|chat history|" | |
| r"imported conversations?|chatgpt archive)\b", raw, re.I): | |
| return None | |
| directory, last_file = _scope_context(context) | |
| # A verified root is still a repository scope, even with directory="". | |
| verified_root = bool(isinstance(context, dict) | |
| and re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", str(context.get("repo") or "")) | |
| and re.fullmatch(r"[a-f0-9]{40}", str(context.get("sourceSha") or "")) | |
| and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._/-]{0,100}", str(context.get("branch") or "")) | |
| and context.get("kind") in ("directory", "file")) | |
| explicit = bool(_COMMAND.match(raw) or _REPO.search(raw)) | |
| # A short answer to a verified directory/file-list turn can identify a | |
| # filename already shown in the repository. Discursive openers ("ok so") | |
| # do not change the operation: the EXISTING authenticated GitHub resolver | |
| # must prove a unique name/stem match. Never trust or invent a model path. | |
| selection = None | |
| if verified_root and context.get("kind") == "directory": | |
| selection_prompt = re.sub( | |
| r"(?i)^(?:(?:ok(?:ay)?|alright)[,!\s]+)?(?:so[,!\s]+)?", | |
| "", raw).strip() | |
| candidate = re.fullmatch( | |
| r"(?:the|that|this)\s+([A-Za-z0-9_§.+-]{2,100})" | |
| r"(?:\s+(?:one|file))?[?.!\s]*", | |
| selection_prompt, re.I) | |
| if candidate: | |
| name = candidate[1] | |
| if (("." in name or re.search(r"\b(?:one|file)\b", selection_prompt, re.I)) | |
| and name.casefold() not in ( | |
| "first", "second", "third", "last", "next", | |
| "other", "same", "right", "left", "good", "bad", | |
| "nice", "new", "old", "correct", "file")): | |
| selection = _safe(name) | |
| if not explicit and not (directory or last_file or verified_root): | |
| return None | |
| # GitHub provenance narrows a real source operation; it does not turn | |
| # generic demonstratives ("it", "that") or a bare "what" into one. | |
| # Literal paths / singular source nouns are strong enough. Generic | |
| # plural requests ("show the files", "how many files") continue through | |
| # the existing directory-scoped followup resolver. Keep the verified | |
| # single-file "explain how it works" continuation. | |
| if (not explicit and not selection | |
| and not re.search( | |
| r"\b(?:file|folder|directory|repo|repository|source|code|" | |
| r"module|function|path|project)\b", raw, re.I) | |
| and not _paths(raw) | |
| and not (last_file and re.fullmatch( | |
| r"(?i)explain how it works[?.!]*", raw))): | |
| return None | |
| q = _PREFIX.sub("", raw) if _COMMAND.match(raw) else raw | |
| if not _READ.search(q) and not selection: | |
| return None | |
| lower = q.casefold() | |
| paths = _paths(q) | |
| branch_match = re.search(r"\b(?:on|from)\s+branch\s+([A-Za-z0-9][A-Za-z0-9._/-]{0,100})\b", q, re.I) | |
| named_branch = branch_match[1] if branch_match else "" | |
| if not named_branch and isinstance(context, dict): | |
| candidate = str(context.get("branch") or "") | |
| rev = str(context.get("sourceSha") or "") | |
| if (candidate not in ("", "main", "master") | |
| and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._/-]{0,100}", candidate) | |
| and re.fullmatch(r"[a-f0-9]{40}", rev)): | |
| named_branch = candidate | |
| if branch_match: | |
| paths = [p for p in paths if p != branch_match[1]] | |
| suffix = (" on branch " + named_branch) if named_branch else "" | |
| if selection: | |
| return "@GitHub read file " + selection + suffix | |
| # Simple file-list questions need an inventory, not a source-analysis report. | |
| # Recursive listing includes files below the root, not just top-level items. | |
| if re.fullmatch(r"(?:what(?: are)?|which)(?: the)? files(?: are)? (?:in|of) (?:my|our|the) (?:github )?(?:repo|repository)[?.!\s]*", lower): | |
| return "@GitHub files" + suffix # Reuse v223 interactive directory explorer. | |
| # Bare filename answers to a previous file-location exchange are read-only | |
| # source requests, not instructions to generate a new program. | |
| nominal = re.fullmatch( | |
| r"(?:the|this|that)\s+([A-Za-z0-9_§.+/-]+\.(?:py|js|mjs|ts|tsx|jsx|html|css|json|md|txt|yaml|yml|kt|java|go|rs|sh|xml|sql))\s+file[?.!\s]*", | |
| q, re.I) | |
| if nominal and verified_root: | |
| named = _safe(nominal[1]) | |
| if named: | |
| return "@GitHub read file " + named + suffix | |
| # Locate a descriptive test file by matching the *repository path*, not | |
| # by inventing a file or replaying the previous whole-source report. | |
| if re.fullmatch( | |
| r"(?:can|could|would) you (?:please )?locate (?:the|a) test file (?:in|from) (?:the|my|our) (?:github )?(?:repo|repository)[?.!\s]*", | |
| lower): | |
| return "@GitHub search test" + suffix | |
| # A directory named in a question is a literal scope, never a guessed | |
| # implementation owner. Do not pick random matching files by meaning. | |
| if not paths: | |
| end_scope = re.search( | |
| r"\b([A-Za-z0-9_§.-]{2,80})\s+(?:folder|directory)\b", q, re.I) | |
| if end_scope: | |
| candidate = _safe(end_scope[1]) | |
| if candidate not in ("the", "this", "that", "current", "our", "my"): | |
| paths = [candidate] | |
| if not paths: | |
| m = _BARE.search(q) | |
| if m and m[1].lower() not in ( | |
| "repo", "repository", "github", "project", "source", "code", | |
| "file", "files", "folder", "directory", "this", "that", "our", | |
| "my", "the", "here", "which", "what", "how", "git", "history"): | |
| if re.search(r"\b(?:folder|directory|under|inside|within|files?\s+in|directories\s+in)\b", q, re.I): | |
| paths = [_safe(m[1])] | |
| scoped = paths[:] | |
| if last_file and paths and re.search(r"\b(?:that|this|the|original)\s+(?:original\s+)?file\b", lower): | |
| scoped = [last_file] + [p for p in paths if p != last_file] | |
| if not scoped and re.search(r"\b(?:this|that|those|same|last|previous|original|first)\s+" | |
| r"(?:(?:original|first|previous|source|earlier)\s+)*files?\b|\b(?:it|that file)\b",lower): | |
| if last_file: | |
| scoped = [last_file] | |
| elif not explicit: | |
| return None | |
| if not scoped and re.search(r"\b(?:this|that|current|same)\s+" | |
| r"(?:folder|directory)\b|\bhere\b", lower): | |
| if directory: | |
| scoped = [directory] | |
| elif not explicit: | |
| return None | |
| if re.search(r"\b(?:how many|count|number of|total|size of)\b", lower) and re.search( | |
| r"\b(?:files?|folders?|directories|directory|bytes|size)\b", lower): | |
| return "@GitHub stats" + (" " + scoped[0] if scoped else "") + suffix | |
| if re.search(r"\b(?:largest|biggest)\b", lower) and re.search(r"\bfiles?\b", lower): | |
| return "@GitHub largest 15" + (" " + scoped[0] if scoped else "") + suffix | |
| if re.search(r"\b(?:history|when|last modified|last changed|" | |
| r"first added|changed|modified|changes? (?:to|in))\b",lower): | |
| if scoped: | |
| return "@GitHub history " + scoped[0] + suffix | |
| return "@GitHub report structure /" + suffix | |
| # A named singular file is a deterministic repository read, including | |
| # conversational "can you see <name> file" phrasing. Do not send it | |
| # through the generic GitHub command parser or programming inference. | |
| if scoped and re.search(r"\b(?:see|find|show|read|open|view)\b", lower) and re.search(r"\bfile\b", lower): | |
| return "@GitHub read file " + scoped[0] + suffix | |
| if re.search(r"\b(?:list|show|see|browse|open|display|view)\b", lower) and re.search( | |
| r"\b(?:files?|folders?|directories|contents|tree)\b", lower): | |
| if re.search(r"\b(?:all|every|entire|complete|recursive|again)\b", lower) and re.search( | |
| r"\b(?:files?|tree)\b", lower): | |
| return "@GitHub files recursive" + (" " + scoped[0] if scoped else "") + suffix | |
| return "@GitHub files" + (" " + scoped[0] if scoped else "") + suffix | |
| if re.search(r"\b(?:read|open|show)\b", lower) and re.search(r"\bfile\b", lower): | |
| if scoped: | |
| return "@GitHub read file " + scoped[0] + suffix | |
| return None # explicit target required for a source-file read | |
| if re.search(r"\b(?:explain|explore|describe|summari[sz]e|analy[sz]e|" | |
| r"inspect|how|what|which|where|architecture|" | |
| r"dependencies|related|relationship|work|purpose|overview)\b", lower): | |
| if scoped: | |
| cmd = "@GitHub report deep " + " | ".join(scoped) | |
| return cmd + (" on branch " + named_branch if named_branch else "") | |
| return "@GitHub report structure /" + (" on branch " + named_branch if named_branch else "") | |
| return None | |