cli-wikia 0.10.0__tar.gz

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 (127) hide show
  1. cli_wikia-0.10.0/.gitignore +7 -0
  2. cli_wikia-0.10.0/LICENSE +21 -0
  3. cli_wikia-0.10.0/PKG-INFO +90 -0
  4. cli_wikia-0.10.0/README.md +53 -0
  5. cli_wikia-0.10.0/pyproject.toml +31 -0
  6. cli_wikia-0.10.0/src/cli_wikia/__init__.py +5 -0
  7. cli_wikia-0.10.0/src/cli_wikia/cli.py +456 -0
  8. cli_wikia-0.10.0/src/cli_wikia/hooks.py +310 -0
  9. cli_wikia-0.10.0/src/cli_wikia/schedule.py +206 -0
  10. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/README.md +142 -0
  11. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/agentic-model.md +130 -0
  12. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/cli-reference.md +184 -0
  13. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/cli-vs-api.md +33 -0
  14. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/configuration.md +124 -0
  15. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/customization.md +119 -0
  16. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/hooks.md +64 -0
  17. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/ide-and-app.md +110 -0
  18. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/mcp.md +98 -0
  19. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/models.md +92 -0
  20. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/overview.md +80 -0
  21. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/permissions.md +134 -0
  22. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/plugins.md +115 -0
  23. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/projects-sessions-conversations.md +111 -0
  24. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/sandbox.md +90 -0
  25. cli_wikia-0.10.0/src/cli_wikia/wikis/antigravity/sdk.md +120 -0
  26. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/README.md +80 -0
  27. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/cli-reference.md +90 -0
  28. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/cli-vs-api.md +34 -0
  29. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-agents-md.md +90 -0
  30. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-approvals-sandbox.md +136 -0
  31. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-auth.md +111 -0
  32. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-cli-reference.md +136 -0
  33. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-config.md +276 -0
  34. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-exec.md +104 -0
  35. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-mcp.md +114 -0
  36. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-models.md +82 -0
  37. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-overview.md +136 -0
  38. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/codex-slash-commands.md +97 -0
  39. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/configuration.md +55 -0
  40. cli_wikia-0.10.0/src/cli_wikia/wikis/chatgpt/models.md +43 -0
  41. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/README.md +163 -0
  42. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/advisor.md +127 -0
  43. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/agent-teams.md +310 -0
  44. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/agents.md +329 -0
  45. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/channels.md +193 -0
  46. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/claude-code-web.md +317 -0
  47. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/cli-reference.md +240 -0
  48. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/cli-vs-api.md +27 -0
  49. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/environment-variables.md +176 -0
  50. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/headless-sdk.md +206 -0
  51. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/hooks.md +380 -0
  52. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/ide-integrations.md +117 -0
  53. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/marketplaces.md +133 -0
  54. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/mcp.md +369 -0
  55. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/memory.md +193 -0
  56. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/models.md +179 -0
  57. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/monitors.md +121 -0
  58. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/output-styles.md +110 -0
  59. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/permission-modes.md +219 -0
  60. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/permissions.md +249 -0
  61. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/plugins.md +335 -0
  62. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/remote-control.md +169 -0
  63. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/sandboxing.md +259 -0
  64. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/settings.md +342 -0
  65. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/skills.md +338 -0
  66. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/slash-commands.md +150 -0
  67. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/stacking.md +301 -0
  68. cli_wikia-0.10.0/src/cli_wikia/wikis/claude/statusline.md +109 -0
  69. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/README.md +109 -0
  70. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/billing.md +48 -0
  71. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/cli-reference.md +193 -0
  72. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/cli-vs-api.md +32 -0
  73. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/configuration.md +140 -0
  74. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/custom-agents.md +95 -0
  75. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/custom-instructions.md +96 -0
  76. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/environment-variables.md +100 -0
  77. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/getting-started.md +117 -0
  78. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/hooks.md +50 -0
  79. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/logging.md +56 -0
  80. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/mcp.md +127 -0
  81. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/models.md +77 -0
  82. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/modes.md +80 -0
  83. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/monitoring.md +94 -0
  84. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/permissions.md +112 -0
  85. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/plugins.md +83 -0
  86. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/providers-byok.md +89 -0
  87. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/sessions.md +93 -0
  88. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/skills.md +59 -0
  89. cli_wikia-0.10.0/src/cli_wikia/wikis/copilot/slash-commands.md +112 -0
  90. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/README.md +137 -0
  91. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/agents.md +203 -0
  92. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/architecture.md +205 -0
  93. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/cli-reference.md +182 -0
  94. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/cli-vs-api.md +28 -0
  95. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/configuration.md +175 -0
  96. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/hooks.md +232 -0
  97. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/models.md +136 -0
  98. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/permissions.md +160 -0
  99. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/plugins.md +107 -0
  100. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/sessions.md +128 -0
  101. cli_wikia-0.10.0/src/cli_wikia/wikis/deepseek/skills.md +184 -0
  102. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/README.md +161 -0
  103. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/checkpointing.md +104 -0
  104. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/cli-reference.md +201 -0
  105. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/cli-vs-api.md +27 -0
  106. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/commands.md +150 -0
  107. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/configuration.md +129 -0
  108. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/context-files.md +191 -0
  109. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/custom-commands.md +169 -0
  110. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/enterprise.md +395 -0
  111. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/environment-variables.md +142 -0
  112. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/extensions.md +305 -0
  113. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/getting-started.md +145 -0
  114. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/git-worktrees.md +74 -0
  115. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/headless.md +208 -0
  116. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/hooks.md +448 -0
  117. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/ide-integration.md +129 -0
  118. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/mcp.md +484 -0
  119. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/models.md +267 -0
  120. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/permissions.md +252 -0
  121. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/sandboxing.md +275 -0
  122. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/sessions.md +161 -0
  123. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/settings.md +238 -0
  124. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/skills.md +228 -0
  125. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/subagents.md +424 -0
  126. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/themes.md +204 -0
  127. cli_wikia-0.10.0/src/cli_wikia/wikis/gemini/tools.md +468 -0
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander Sorrell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,90 @@
1
+ Metadata-Version: 2.4
2
+ Name: cli-wikia
3
+ Version: 0.10.0
4
+ Summary: Offline, pip-installable reference wiki for AI coding CLIs (Claude, DeepSeek, Copilot, ChatGPT, Gemini) with a search/read command.
5
+ Project-URL: Homepage, https://github.com/Alexander-Sorrell-IT/CLI-Wikia
6
+ Project-URL: Repository, https://github.com/Alexander-Sorrell-IT/CLI-Wikia
7
+ Author-email: Alexander Sorrell <codehunterextreme@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 Alexander Sorrell
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: ai,chatgpt,claude,cli,copilot,deepseek,gemini,reference,wiki
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Operating System :: OS Independent
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Topic :: Documentation
35
+ Requires-Python: >=3.8
36
+ Description-Content-Type: text/markdown
37
+
38
+ # CLI Wikia
39
+
40
+ An **offline, pip-installable reference wiki** for AI coding CLIs —
41
+ Claude Code, DeepSeek, GitHub Copilot, ChatGPT/OpenAI, and Gemini —
42
+ with a single command to browse, search, read and edit the docs.
43
+
44
+ It's more than a wiki: the bundled docs can also be used as **grounding
45
+ context for a local model** (`wikia ask`), so the same content works as a
46
+ reference *and* as a knowledge base you fully control and can edit.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install cli-wikia
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ```bash
57
+ wikia models # list models + topic counts
58
+ wikia list claude # list Claude topics
59
+ wikia read claude hooks # print a topic
60
+ wikia search "permission" # search across all models
61
+ wikia search "mcp" --model claude # search one model
62
+ wikia path claude # show where the files live (to edit them)
63
+ wikia ask claude "how do hooks work?" # answer from the docs via a local model
64
+ ```
65
+
66
+ ## How it's organized
67
+
68
+ ```
69
+ src/cli_wikia/wikis/
70
+ ├── claude/ # populated (Claude Code docs)
71
+ ├── deepseek/ # skeleton
72
+ ├── copilot/ # skeleton
73
+ ├── chatgpt/ # skeleton
74
+ └── gemini/ # skeleton
75
+ ```
76
+
77
+ Each topic is a plain Markdown file. Add or edit files in a model's folder
78
+ and reinstall (`pip install -e .`) to update your local copy. Because the
79
+ repo is git-backed, **every revision of every doc is kept** in history.
80
+
81
+ ## Status
82
+
83
+ - **Claude** wiki is fully populated.
84
+ - DeepSeek / Copilot / ChatGPT / Gemini are skeletons to be filled from each
85
+ tool's CLI (you have `deepseek-code`, `copilot`, `gemini`, `ollama`
86
+ installed) or official documentation.
87
+
88
+ ## License
89
+
90
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,53 @@
1
+ # CLI Wikia
2
+
3
+ An **offline, pip-installable reference wiki** for AI coding CLIs —
4
+ Claude Code, DeepSeek, GitHub Copilot, ChatGPT/OpenAI, and Gemini —
5
+ with a single command to browse, search, read and edit the docs.
6
+
7
+ It's more than a wiki: the bundled docs can also be used as **grounding
8
+ context for a local model** (`wikia ask`), so the same content works as a
9
+ reference *and* as a knowledge base you fully control and can edit.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install cli-wikia
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ wikia models # list models + topic counts
21
+ wikia list claude # list Claude topics
22
+ wikia read claude hooks # print a topic
23
+ wikia search "permission" # search across all models
24
+ wikia search "mcp" --model claude # search one model
25
+ wikia path claude # show where the files live (to edit them)
26
+ wikia ask claude "how do hooks work?" # answer from the docs via a local model
27
+ ```
28
+
29
+ ## How it's organized
30
+
31
+ ```
32
+ src/cli_wikia/wikis/
33
+ ├── claude/ # populated (Claude Code docs)
34
+ ├── deepseek/ # skeleton
35
+ ├── copilot/ # skeleton
36
+ ├── chatgpt/ # skeleton
37
+ └── gemini/ # skeleton
38
+ ```
39
+
40
+ Each topic is a plain Markdown file. Add or edit files in a model's folder
41
+ and reinstall (`pip install -e .`) to update your local copy. Because the
42
+ repo is git-backed, **every revision of every doc is kept** in history.
43
+
44
+ ## Status
45
+
46
+ - **Claude** wiki is fully populated.
47
+ - DeepSeek / Copilot / ChatGPT / Gemini are skeletons to be filled from each
48
+ tool's CLI (you have `deepseek-code`, `copilot`, `gemini`, `ollama`
49
+ installed) or official documentation.
50
+
51
+ ## License
52
+
53
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "cli-wikia"
7
+ version = "0.10.0"
8
+ description = "Offline, pip-installable reference wiki for AI coding CLIs (Claude, DeepSeek, Copilot, ChatGPT, Gemini) with a search/read command."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Alexander Sorrell", email = "codehunterextreme@gmail.com" }]
13
+ keywords = ["ai", "cli", "wiki", "claude", "deepseek", "copilot", "chatgpt", "gemini", "reference"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Documentation",
19
+ ]
20
+ dependencies = []
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/Alexander-Sorrell-IT/CLI-Wikia"
24
+ Repository = "https://github.com/Alexander-Sorrell-IT/CLI-Wikia"
25
+
26
+ [project.scripts]
27
+ wikia = "cli_wikia.cli:main"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/cli_wikia"]
31
+ artifacts = ["src/cli_wikia/wikis/**/*.md"]
@@ -0,0 +1,5 @@
1
+ """cli-wikia: offline reference wiki for AI coding CLIs."""
2
+
3
+ __version__ = "0.10.0"
4
+
5
+ MODELS = ["claude", "deepseek", "copilot", "chatgpt", "gemini", "antigravity"]
@@ -0,0 +1,456 @@
1
+ """Command-line interface for cli-wikia.
2
+
3
+ A small, dependency-free CLI to browse, search, read and edit an offline
4
+ reference wiki for AI coding CLIs. Run `wikia --help` for usage.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import argparse
9
+ import difflib
10
+ import os
11
+ import re
12
+ import shutil
13
+ import subprocess
14
+ import sys
15
+ import urllib.request
16
+ from importlib import resources
17
+
18
+ from . import MODELS, __version__
19
+
20
+ # Which installed CLI can answer questions / provide updates for each model.
21
+ MODEL_CLIS = {
22
+ "claude": "claude",
23
+ "deepseek": "deepseek-code",
24
+ "copilot": "copilot",
25
+ "chatgpt": "codex", # OpenAI Codex CLI (may not be installed yet)
26
+ "gemini": "gemini",
27
+ "antigravity": "agy", # Google Antigravity CLI
28
+ }
29
+
30
+ # Sources the `update` command checks for changes, per model. The real signal
31
+ # comes from (1) the official docs and (2) asking the model itself — NOT a
32
+ # `--help` dump. `version` is just a cheap authoritative version string.
33
+ # - version: read-only version probe (no side effects).
34
+ # - docs: official documentation URL (best-effort; edit if a tool moves its docs).
35
+ # - ask: argv template to query the model in one-shot mode; "{q}" = the question.
36
+ # None means the model can't be queried that way (e.g. tool not installed).
37
+ MODEL_SOURCES = {
38
+ "claude": {
39
+ "version": ["--version"],
40
+ "docs": "https://docs.claude.com/en/docs/claude-code/overview",
41
+ "ask": ["-p", "{q}"],
42
+ },
43
+ "deepseek": {
44
+ "version": ["--version"],
45
+ "docs": "https://api-docs.deepseek.com/",
46
+ "ask": ["-p", "{q}"],
47
+ },
48
+ "copilot": {
49
+ "version": ["--version"],
50
+ "docs": "https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli",
51
+ "ask": ["-p", "{q}", "--allow-all-tools"],
52
+ },
53
+ "chatgpt": {
54
+ "version": ["--version"],
55
+ "docs": "https://developers.openai.com/codex/cli/",
56
+ "ask": None, # codex isn't installed; openai CLI isn't a one-shot agent
57
+ },
58
+ "gemini": {
59
+ "version": ["--version"],
60
+ "docs": "https://google-gemini.github.io/gemini-cli/",
61
+ "ask": ["-p", "{q}"],
62
+ },
63
+ "antigravity": {
64
+ "version": ["--version"],
65
+ "docs": "https://antigravity.google/docs",
66
+ "ask": ["-p", "{q}"],
67
+ },
68
+ }
69
+
70
+ # What `update` asks each model about itself.
71
+ WHATS_NEW_Q = (
72
+ "What is your exact version, and what are your most recent features, "
73
+ "commands, or changes? Be specific and concise."
74
+ )
75
+
76
+
77
+ def wikis_root():
78
+ """Filesystem path to the bundled wikis/ directory."""
79
+ return resources.files("cli_wikia") / "wikis"
80
+
81
+
82
+ def model_dir(model):
83
+ return wikis_root() / model
84
+
85
+
86
+ def topics(model):
87
+ """Sorted list of topic names (filenames without .md) for a model."""
88
+ d = model_dir(model)
89
+ if not d.is_dir():
90
+ return []
91
+ return sorted(p.name[:-3] for p in d.iterdir() if p.name.endswith(".md"))
92
+
93
+
94
+ def resolve_model(model):
95
+ if model not in MODELS:
96
+ sys.exit(f"unknown model '{model}'. choose from: {', '.join(MODELS)}")
97
+ return model
98
+
99
+
100
+ # --------------------------------------------------------------------------- #
101
+ # commands
102
+ # --------------------------------------------------------------------------- #
103
+ def cmd_models(args):
104
+ for m in MODELS:
105
+ n = len(topics(m))
106
+ cli = MODEL_CLIS.get(m)
107
+ cli_state = f"cli: {cli}" if cli and shutil.which(cli) else "cli: not installed"
108
+ print(f"{m:12} {n:3} topics ({cli_state})")
109
+
110
+
111
+ def cmd_list(args):
112
+ models = [resolve_model(args.model)] if args.model else MODELS
113
+ for m in models:
114
+ ts = topics(m)
115
+ print(f"\n# {m} ({len(ts)} topics)")
116
+ for t in ts:
117
+ print(f" {t}")
118
+
119
+
120
+ def cmd_read(args):
121
+ m = resolve_model(args.model)
122
+ f = model_dir(m) / f"{args.topic}.md"
123
+ if not f.is_file():
124
+ avail = ", ".join(topics(m)) or "(none yet)"
125
+ sys.exit(f"no topic '{args.topic}' in {m}.\navailable: {avail}")
126
+ sys.stdout.write(f.read_text(encoding="utf-8"))
127
+
128
+
129
+ def cmd_search(args):
130
+ needle = args.query.lower()
131
+ models = [resolve_model(args.model)] if args.model else MODELS
132
+ hits = 0
133
+ for m in models:
134
+ d = model_dir(m)
135
+ if not d.is_dir():
136
+ continue
137
+ for p in sorted(d.iterdir(), key=lambda x: x.name):
138
+ if not p.name.endswith(".md"):
139
+ continue
140
+ for i, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1):
141
+ if needle in line.lower():
142
+ hits += 1
143
+ print(f"{m}/{p.name[:-3]}:{i}: {line.strip()}")
144
+ if not hits:
145
+ print(f"no matches for '{args.query}'")
146
+
147
+
148
+ def cmd_path(args):
149
+ if args.model:
150
+ print(model_dir(resolve_model(args.model)))
151
+ else:
152
+ print(wikis_root())
153
+
154
+
155
+ def cmd_ask(args):
156
+ """Use a local model CLI to answer a question grounded in the wiki docs."""
157
+ m = resolve_model(args.model)
158
+ cli = MODEL_CLIS.get(m)
159
+ runner = cli if (cli and shutil.which(cli)) else ("ollama" if shutil.which("ollama") else None)
160
+ if not runner:
161
+ sys.exit(
162
+ "no local model CLI available to answer. install one of: "
163
+ f"{cli or 'ollama'}, or read the docs with `wikia read {m} <topic>`."
164
+ )
165
+ # Build context from the model's docs (capped to keep the prompt sane).
166
+ context = ""
167
+ for t in topics(m):
168
+ context += f"\n\n## {t}\n" + (model_dir(m) / f"{t}.md").read_text(encoding="utf-8")
169
+ context = context[: args.max_context]
170
+ prompt = (
171
+ "Answer the question using ONLY the reference docs below. "
172
+ "If the answer is not in them, say so.\n"
173
+ f"=== REFERENCE DOCS ({m}) ===\n{context}\n=== QUESTION ===\n{args.question}\n"
174
+ )
175
+ print(f"(asking via: {runner})\n", file=sys.stderr)
176
+ try:
177
+ if runner == "ollama":
178
+ subprocess.run(["ollama", "run", args.ollama_model, prompt], check=False)
179
+ else:
180
+ subprocess.run([runner, prompt], check=False)
181
+ except FileNotFoundError:
182
+ sys.exit(f"could not run '{runner}'.")
183
+
184
+
185
+ def snapshot_dir():
186
+ """Writable per-user dir where CLI ground-truth snapshots are stored."""
187
+ base = os.environ.get("XDG_STATE_HOME") or os.path.join(
188
+ os.path.expanduser("~"), ".local", "state"
189
+ )
190
+ return os.path.join(base, "cli-wikia", "snapshots")
191
+
192
+
193
+ def _run_cli(cli, probe, timeout=30):
194
+ """Run one read-only CLI probe and return its labelled output."""
195
+ try:
196
+ r = subprocess.run(
197
+ [cli, *probe],
198
+ capture_output=True,
199
+ text=True,
200
+ timeout=timeout,
201
+ stdin=subprocess.DEVNULL,
202
+ )
203
+ return f"$ {cli} {' '.join(probe)}\n{r.stdout}{r.stderr}".strip()
204
+ except (subprocess.TimeoutExpired, OSError) as e:
205
+ return f"$ {cli} {' '.join(probe)}\n<error: {e}>"
206
+
207
+
208
+ def fetch_docs(url):
209
+ """Fetch an official docs page and reduce it to text for change detection.
210
+
211
+ Uses only the standard library. Returns a text block, or an error note if
212
+ offline / the page is unreachable (so update still works offline).
213
+ """
214
+ try:
215
+ req = urllib.request.Request(url, headers={"User-Agent": "cli-wikia/update"})
216
+ with urllib.request.urlopen(req, timeout=20) as resp:
217
+ html = resp.read(500_000).decode("utf-8", "replace")
218
+ except Exception as e: # noqa: BLE001 - network can fail many ways; degrade gracefully
219
+ return f"# docs: {url}\n<unreachable: {e}>"
220
+ text = re.sub(r"(?is)<(script|style).*?</\1>", " ", html)
221
+ text = re.sub(r"(?s)<[^>]+>", " ", text)
222
+ text = re.sub(r"\s+", " ", text).strip()
223
+ return f"# docs: {url}\n{text[:30000]}"
224
+
225
+
226
+ def wiki_doc_urls(model, limit=2):
227
+ """Official doc URLs for a model, discovered FROM its own wiki pages
228
+ (dynamic — not a hardcoded list). Prefers documentation-looking links."""
229
+ d = model_dir(model)
230
+ if not d.is_dir():
231
+ return []
232
+ text = "".join(
233
+ p.read_text(encoding="utf-8") for p in sorted(d.iterdir()) if p.name.endswith(".md")
234
+ )
235
+ urls = [u.rstrip(".,);]`") for u in re.findall(r"https?://[^\s)\]\"'>`]+", text)]
236
+ bad = ("example.com", "example.org", "localhost", "127.0.0.1", "your-", "git-scm.com")
237
+ urls = [u for u in urls if not any(b in u for b in bad)]
238
+ docish = [u for u in urls if re.search(r"docs?[./]|/docs|developers?\.|\.github\.io|/guide", u)]
239
+ out = []
240
+ for u in (docish or urls):
241
+ if u not in out:
242
+ out.append(u)
243
+ if len(out) >= limit:
244
+ break
245
+ return out
246
+
247
+
248
+ def query_model(cli, ask_template, question):
249
+ """Ask the model itself, in one-shot mode, via its per-model invocation."""
250
+ if not ask_template:
251
+ return None
252
+ argv = [question if tok == "{q}" else tok for tok in ask_template]
253
+ out = _run_cli(cli, argv, timeout=180) # models take a while
254
+ return "# model self-report (the model's own answer about itself):\n" + out
255
+
256
+
257
+ def capture_sources(m, cli, use_docs, use_model):
258
+ """Gather sources for a model into one snapshot blob, leaning on the docs.
259
+ Order = priority: (1) OFFICIAL DOCUMENTATION first (URLs discovered from the
260
+ model's own wiki, plus a seed), (2) the CLI's own facts (version + help),
261
+ (3) the model's self-report (secondary — models are unreliable about
262
+ themselves). Use --no-docs / --no-model to drop a source."""
263
+ src = MODEL_SOURCES.get(m, {})
264
+ parts = []
265
+ if use_docs:
266
+ urls = wiki_doc_urls(m)
267
+ seed = src.get("docs")
268
+ if seed and seed not in urls:
269
+ urls.append(seed)
270
+ for url in urls[:2]:
271
+ parts.append(fetch_docs(url))
272
+ parts.append(_run_cli(cli, src.get("version", ["--version"])))
273
+ parts.append(_run_cli(cli, ["--help"]))
274
+ if use_model and src.get("ask"):
275
+ mq = query_model(cli, src["ask"], WHATS_NEW_Q)
276
+ if mq:
277
+ parts.append(mq)
278
+ return "\n\n".join(p for p in parts if p) + "\n"
279
+
280
+
281
+ def cmd_update(args):
282
+ """Check each model's sources (CLI --help/--version, official docs, and
283
+ optionally the model itself) for changes vs the last saved snapshot.
284
+
285
+ Reports what changed so curated docs can be refreshed. No API keys. Never
286
+ overwrites the curated .md files; snapshots live in the user state dir.
287
+ """
288
+ if not args.all and not args.model:
289
+ sys.exit("specify a model (e.g. `wikia update gemini`) or use `--all`.")
290
+ models = MODELS if args.all else [resolve_model(args.model)]
291
+ use_docs = not args.no_docs
292
+ use_model = not args.no_model
293
+ sdir = snapshot_dir()
294
+ os.makedirs(sdir, exist_ok=True)
295
+ changed_any = False
296
+ for m in models:
297
+ cli = MODEL_CLIS.get(m)
298
+ if not cli:
299
+ print(f"{m:12} no associated CLI — skip")
300
+ continue
301
+ if not shutil.which(cli):
302
+ print(f"{m:12} '{cli}' not installed — can't check for updates")
303
+ continue
304
+ sources = "help/version" + (" + docs" if use_docs else "") + (" + model" if use_model else "")
305
+ current = capture_sources(m, cli, use_docs, use_model)
306
+ snap = os.path.join(sdir, f"{m}.txt")
307
+ if not os.path.exists(snap):
308
+ with open(snap, "w", encoding="utf-8") as f:
309
+ f.write(current)
310
+ print(f"{m:12} baseline snapshot saved ({sources}). Run again later to detect changes.")
311
+ continue
312
+ with open(snap, encoding="utf-8") as f:
313
+ prev = f.read()
314
+ if prev == current:
315
+ print(f"{m:12} up to date ({sources}, no change)")
316
+ continue
317
+ changed_any = True
318
+ diff = [
319
+ ln
320
+ for ln in difflib.unified_diff(
321
+ prev.splitlines(), current.splitlines(), lineterm="", n=0
322
+ )
323
+ if ln and ln[0] in "+-" and not ln.startswith(("+++", "---"))
324
+ ]
325
+ print(f"{m:12} CHANGED ({sources}) — {len(diff)} differing lines:")
326
+ for ln in diff[:30]:
327
+ print(f" {ln}")
328
+ if len(diff) > 30:
329
+ print(f" … (+{len(diff) - 30} more)")
330
+ print(f" review/update curated docs in: {model_dir(m)}")
331
+ if args.write:
332
+ with open(snap, "w", encoding="utf-8") as f:
333
+ f.write(current)
334
+ print(f" snapshot updated (acknowledged).")
335
+ else:
336
+ print(f" re-run with --write to accept this as the new baseline.")
337
+ if changed_any and not args.write:
338
+ print("\nTip: `wikia update --all --write` after you've refreshed the docs.")
339
+
340
+
341
+ def build_parser():
342
+ p = argparse.ArgumentParser(
343
+ prog="wikia",
344
+ description="Offline reference wiki for AI coding CLIs "
345
+ "(claude, deepseek, copilot, chatgpt, gemini).",
346
+ )
347
+ p.add_argument("--version", action="version", version=f"cli-wikia {__version__}")
348
+ sub = p.add_subparsers(dest="cmd", required=True)
349
+
350
+ sub.add_parser("models", help="list models and how many topics each has").set_defaults(func=cmd_models)
351
+
352
+ sp = sub.add_parser("list", help="list topics (optionally for one model)")
353
+ sp.add_argument("model", nargs="?", help="model name (default: all)")
354
+ sp.set_defaults(func=cmd_list)
355
+
356
+ sp = sub.add_parser("read", help="print a topic")
357
+ sp.add_argument("model")
358
+ sp.add_argument("topic")
359
+ sp.set_defaults(func=cmd_read)
360
+
361
+ sp = sub.add_parser("search", help="search text across topics")
362
+ sp.add_argument("query")
363
+ sp.add_argument("--model", help="limit to one model")
364
+ sp.set_defaults(func=cmd_search)
365
+
366
+ sp = sub.add_parser("path", help="print the on-disk path (for editing files)")
367
+ sp.add_argument("model", nargs="?")
368
+ sp.set_defaults(func=cmd_path)
369
+
370
+ sp = sub.add_parser("ask", help="ask a question answered from the docs via a local model")
371
+ sp.add_argument("model")
372
+ sp.add_argument("question")
373
+ sp.add_argument("--ollama-model", default="llama3", help="ollama model to use as fallback")
374
+ sp.add_argument("--max-context", type=int, default=24000, help="max chars of docs to feed")
375
+ sp.set_defaults(func=cmd_ask)
376
+
377
+ sp = sub.add_parser("update", help="check a model's sources (help, docs, model) for changes")
378
+ sp.add_argument("model", nargs="?", help="model name (omit and use --all for every model)")
379
+ sp.add_argument("--all", action="store_true", help="check every model")
380
+ sp.add_argument("--write", action="store_true", help="accept current state as the new baseline")
381
+ sp.add_argument("--no-docs", action="store_true", help="skip fetching official docs (offline / faster)")
382
+ sp.add_argument("--no-model", action="store_true", help="skip asking the model itself (faster)")
383
+ sp.set_defaults(func=cmd_update)
384
+
385
+ # hooks (Level 1 awareness + Level 2 tailored hooks) — see hooks.py
386
+ from . import hooks as H
387
+
388
+ hp = sub.add_parser("hooks", help="integrate the wiki into a model (awareness + real hooks)")
389
+ hsub = hp.add_subparsers(dest="hooks_cmd", required=True)
390
+
391
+ s = hsub.add_parser("status", help="show integration status per model")
392
+ s.add_argument("model", nargs="?")
393
+ s.add_argument("--all", action="store_true")
394
+ s.set_defaults(func=H.cmd_status)
395
+
396
+ s = hsub.add_parser("enable", help="Level 1: tell a model the wiki exists (dry-run unless --write)")
397
+ s.add_argument("model")
398
+ s.add_argument("--file", help="instructions file to write (default: per-model convention)")
399
+ s.add_argument("--write", action="store_true", help="actually write the change")
400
+ s.set_defaults(func=H.cmd_enable)
401
+
402
+ s = hsub.add_parser("disable", help="Level 1: remove the wiki awareness block")
403
+ s.add_argument("model")
404
+ s.add_argument("--file")
405
+ s.add_argument("--write", action="store_true")
406
+ s.set_defaults(func=H.cmd_disable)
407
+
408
+ s = hsub.add_parser("manifest", help="Level 2: generate the hook-positions doc from the wiki")
409
+ s.add_argument("model")
410
+ s.set_defaults(func=H.cmd_manifest)
411
+
412
+ s = hsub.add_parser("apply", help="Level 2: install the edited hooks (dry-run unless --write)")
413
+ s.add_argument("model")
414
+ s.add_argument("--file", help="target settings file (default: per-model)")
415
+ s.add_argument("--write", action="store_true", help="actually install the hooks")
416
+ s.set_defaults(func=H.cmd_apply)
417
+
418
+ # schedule — config-driven auto-update timer (see schedule.py)
419
+ from . import schedule as S
420
+
421
+ sc = sub.add_parser("schedule", help="auto-update on a timer, configured via a file")
422
+ scsub = sc.add_subparsers(dest="schedule_cmd", required=True)
423
+
424
+ c = scsub.add_parser("config", help="create/show the schedule config file (pick interval here)")
425
+ c.add_argument("--write", action="store_true", help="create the config file")
426
+ c.set_defaults(func=S.cmd_config)
427
+
428
+ c = scsub.add_parser("apply", help="make the timer match the config (dry-run unless --write)")
429
+ c.add_argument("--write", action="store_true", help="actually install/remove the timer")
430
+ c.set_defaults(func=S.cmd_apply)
431
+
432
+ c = scsub.add_parser("status", help="show config + installed timer")
433
+ c.set_defaults(func=S.cmd_status)
434
+
435
+ c = scsub.add_parser("remove", help="remove the scheduled timer (dry-run unless --write)")
436
+ c.add_argument("--write", action="store_true", help="actually remove")
437
+ c.set_defaults(func=S.cmd_remove)
438
+
439
+ return p
440
+
441
+
442
+ def main(argv=None):
443
+ # Behave like a normal Unix tool when output is piped into `head`/`less`
444
+ # and the reader closes early: die quietly instead of dumping a traceback.
445
+ try:
446
+ import signal
447
+
448
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
449
+ except (ImportError, AttributeError):
450
+ pass # SIGPIPE not available (e.g. Windows)
451
+ args = build_parser().parse_args(argv)
452
+ args.func(args)
453
+
454
+
455
+ if __name__ == "__main__":
456
+ main()