doclogs-cli 0.1.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.
- doclogs_cli-0.1.0/LICENSE +21 -0
- doclogs_cli-0.1.0/PKG-INFO +141 -0
- doclogs_cli-0.1.0/README.md +115 -0
- doclogs_cli-0.1.0/commands/__init__.py +0 -0
- doclogs_cli-0.1.0/commands/capture.py +51 -0
- doclogs_cli-0.1.0/commands/config.py +28 -0
- doclogs_cli-0.1.0/commands/generate.py +49 -0
- doclogs_cli-0.1.0/commands/sanitize.py +33 -0
- doclogs_cli-0.1.0/commands/weekly.py +27 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/PKG-INFO +141 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/SOURCES.txt +34 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/dependency_links.txt +1 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/entry_points.txt +2 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/requires.txt +2 -0
- doclogs_cli-0.1.0/doclogs_cli.egg-info/top_level.txt +3 -0
- doclogs_cli-0.1.0/helper/__init__.py +0 -0
- doclogs_cli-0.1.0/helper/capture.py +44 -0
- doclogs_cli-0.1.0/helper/capture_prompts.py +95 -0
- doclogs_cli-0.1.0/helper/entry.py +107 -0
- doclogs_cli-0.1.0/helper/generate.py +17 -0
- doclogs_cli-0.1.0/helper/git_collector.py +72 -0
- doclogs_cli-0.1.0/helper/paths.py +57 -0
- doclogs_cli-0.1.0/helper/prompts.py +17 -0
- doclogs_cli-0.1.0/helper/sanitize.py +81 -0
- doclogs_cli-0.1.0/helper/story.py +31 -0
- doclogs_cli-0.1.0/helper/task_notes.py +65 -0
- doclogs_cli-0.1.0/helper/templates/blog.md +9 -0
- doclogs_cli-0.1.0/helper/templates/changelog.md +7 -0
- doclogs_cli-0.1.0/helper/templates/config.yaml +20 -0
- doclogs_cli-0.1.0/helper/templates/interview.md +8 -0
- doclogs_cli-0.1.0/helper/templates/linkedin.md +8 -0
- doclogs_cli-0.1.0/helper/templates/resume.md +8 -0
- doclogs_cli-0.1.0/helper/weekly.py +64 -0
- doclogs_cli-0.1.0/main.py +22 -0
- doclogs_cli-0.1.0/pyproject.toml +47 -0
- doclogs_cli-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mridul Tiwari
|
|
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,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: doclogs-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI for capturing engineering work and turning it into career artifacts.
|
|
5
|
+
Author: Mridul Tiwari
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MridulTi/DocLogs
|
|
8
|
+
Project-URL: Repository, https://github.com/MridulTi/DocLogs
|
|
9
|
+
Project-URL: Issues, https://github.com/MridulTi/DocLogs/issues
|
|
10
|
+
Keywords: cli,engineering,career,devlog,documentation,resume
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: typer>=0.10.0
|
|
24
|
+
Requires-Dist: PyYAML>=6.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# DocLogs
|
|
28
|
+
|
|
29
|
+
DocLogs is an engineer career operating system for capturing and reusing technical work.
|
|
30
|
+
|
|
31
|
+
## What it solves
|
|
32
|
+
|
|
33
|
+
Engineers do valuable work every day: incident response, CI/CD and platform debugging, automation, infrastructure changes, PR reviews, and migrations. Most of that work is forgotten when it matters most: performance reviews, promotion packets, interviews, and professional storytelling.
|
|
34
|
+
|
|
35
|
+
DocLogs helps you turn day-to-day engineering activity into durable artifacts by:
|
|
36
|
+
|
|
37
|
+
- capturing evidence automatically from git, branches, PRs, and optional histories
|
|
38
|
+
- summarizing weekly progress and surfacing strong stories
|
|
39
|
+
- generating markdown artifacts for blog posts, LinkedIn, resumes, and interview prep
|
|
40
|
+
- keeping model usage provider-agnostic and safe with sanitization
|
|
41
|
+
|
|
42
|
+
## Core commands
|
|
43
|
+
|
|
44
|
+
- `doclog capture`
|
|
45
|
+
- collect commits, repository activity, PR titles, tickets, and optional notes
|
|
46
|
+
- store structured daily entries in local storage
|
|
47
|
+
- `doclog weekly`
|
|
48
|
+
- review weekly work
|
|
49
|
+
- surface candidate stories worth expanding
|
|
50
|
+
- `doclog generate <type>`
|
|
51
|
+
- create reusable artifacts such as `blog`, `linkedin`, `resume`, `interview`, or `changelog`
|
|
52
|
+
- `doclog sanitize`
|
|
53
|
+
- sanitize captured content before any LLM request
|
|
54
|
+
- redact internal URLs, tokens, IP addresses, and other sensitive details
|
|
55
|
+
|
|
56
|
+
## Recommended repository structure
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
./
|
|
60
|
+
├── README.md
|
|
61
|
+
├── config.yaml
|
|
62
|
+
├── commands/
|
|
63
|
+
│ ├── capture.py
|
|
64
|
+
│ └── config.py
|
|
65
|
+
├── docs/
|
|
66
|
+
│ ├── vision.md
|
|
67
|
+
│ └── architecture.md
|
|
68
|
+
├── doclog/
|
|
69
|
+
│ ├── entries/
|
|
70
|
+
│ ├── posts/
|
|
71
|
+
│ └── cache/
|
|
72
|
+
├── prompts/
|
|
73
|
+
│ ├── blog.md
|
|
74
|
+
│ ├── linkedin.md
|
|
75
|
+
│ └── resume.md
|
|
76
|
+
└── .copilot
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Architecture overview
|
|
80
|
+
|
|
81
|
+
DocLogs keeps the capture layer local and the generation layer model-agnostic. It is intentionally not a scheduler; use OS-level schedulers like `cron`, `systemd --user`, `launchd`, or Task Scheduler to invoke `doclog capture` at reminder times.
|
|
82
|
+
|
|
83
|
+
For implementation, start by focusing on:
|
|
84
|
+
|
|
85
|
+
1. evidence collection and local storage
|
|
86
|
+
2. weekly summaries and story selection
|
|
87
|
+
3. safe prompt generation
|
|
88
|
+
4. provider adapters for OpenAI, Ollama, Anthropic, Gemini, or other APIs
|
|
89
|
+
|
|
90
|
+
## Getting started
|
|
91
|
+
|
|
92
|
+
### Install from PyPI
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install doclogs-cli
|
|
96
|
+
doclog --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Install from source (development)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/MridulTi/DocLogs.git
|
|
103
|
+
cd DocLogs
|
|
104
|
+
python -m venv .venv
|
|
105
|
+
source .venv/bin/activate
|
|
106
|
+
pip install -e .
|
|
107
|
+
doclog --help
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### First run
|
|
111
|
+
|
|
112
|
+
Data is stored under `~/.doclog/` (entries, posts, config). On first use, a default `config.yaml` is created there.
|
|
113
|
+
|
|
114
|
+
To keep using a project-local folder instead:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export DOCLOG_HOME="$PWD/doclog"
|
|
118
|
+
doclog capture
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Daily use
|
|
122
|
+
|
|
123
|
+
1. Configure `~/.doclog/config.yaml` with your preferred LLM provider (created automatically on first run).
|
|
124
|
+
2. Add a scheduler entry outside the CLI to invoke `doclog capture` at your preferred check-in time.
|
|
125
|
+
3. Capture daily progress and generate reusable career artifacts from the same captured story.
|
|
126
|
+
|
|
127
|
+
## Publish to PyPI (GitHub Actions)
|
|
128
|
+
|
|
129
|
+
Publishing runs via GitHub Actions — no local `twine upload` needed.
|
|
130
|
+
|
|
131
|
+
1. Configure [trusted publishing](docs/publishing.md) on PyPI (leave Environment blank)
|
|
132
|
+
2. Push a version tag:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git tag v0.1.0
|
|
136
|
+
git push origin v0.1.0
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The workflow uploads to PyPI automatically.
|
|
140
|
+
|
|
141
|
+
See [docs/publishing.md](docs/publishing.md) for full setup.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# DocLogs
|
|
2
|
+
|
|
3
|
+
DocLogs is an engineer career operating system for capturing and reusing technical work.
|
|
4
|
+
|
|
5
|
+
## What it solves
|
|
6
|
+
|
|
7
|
+
Engineers do valuable work every day: incident response, CI/CD and platform debugging, automation, infrastructure changes, PR reviews, and migrations. Most of that work is forgotten when it matters most: performance reviews, promotion packets, interviews, and professional storytelling.
|
|
8
|
+
|
|
9
|
+
DocLogs helps you turn day-to-day engineering activity into durable artifacts by:
|
|
10
|
+
|
|
11
|
+
- capturing evidence automatically from git, branches, PRs, and optional histories
|
|
12
|
+
- summarizing weekly progress and surfacing strong stories
|
|
13
|
+
- generating markdown artifacts for blog posts, LinkedIn, resumes, and interview prep
|
|
14
|
+
- keeping model usage provider-agnostic and safe with sanitization
|
|
15
|
+
|
|
16
|
+
## Core commands
|
|
17
|
+
|
|
18
|
+
- `doclog capture`
|
|
19
|
+
- collect commits, repository activity, PR titles, tickets, and optional notes
|
|
20
|
+
- store structured daily entries in local storage
|
|
21
|
+
- `doclog weekly`
|
|
22
|
+
- review weekly work
|
|
23
|
+
- surface candidate stories worth expanding
|
|
24
|
+
- `doclog generate <type>`
|
|
25
|
+
- create reusable artifacts such as `blog`, `linkedin`, `resume`, `interview`, or `changelog`
|
|
26
|
+
- `doclog sanitize`
|
|
27
|
+
- sanitize captured content before any LLM request
|
|
28
|
+
- redact internal URLs, tokens, IP addresses, and other sensitive details
|
|
29
|
+
|
|
30
|
+
## Recommended repository structure
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
./
|
|
34
|
+
├── README.md
|
|
35
|
+
├── config.yaml
|
|
36
|
+
├── commands/
|
|
37
|
+
│ ├── capture.py
|
|
38
|
+
│ └── config.py
|
|
39
|
+
├── docs/
|
|
40
|
+
│ ├── vision.md
|
|
41
|
+
│ └── architecture.md
|
|
42
|
+
├── doclog/
|
|
43
|
+
│ ├── entries/
|
|
44
|
+
│ ├── posts/
|
|
45
|
+
│ └── cache/
|
|
46
|
+
├── prompts/
|
|
47
|
+
│ ├── blog.md
|
|
48
|
+
│ ├── linkedin.md
|
|
49
|
+
│ └── resume.md
|
|
50
|
+
└── .copilot
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Architecture overview
|
|
54
|
+
|
|
55
|
+
DocLogs keeps the capture layer local and the generation layer model-agnostic. It is intentionally not a scheduler; use OS-level schedulers like `cron`, `systemd --user`, `launchd`, or Task Scheduler to invoke `doclog capture` at reminder times.
|
|
56
|
+
|
|
57
|
+
For implementation, start by focusing on:
|
|
58
|
+
|
|
59
|
+
1. evidence collection and local storage
|
|
60
|
+
2. weekly summaries and story selection
|
|
61
|
+
3. safe prompt generation
|
|
62
|
+
4. provider adapters for OpenAI, Ollama, Anthropic, Gemini, or other APIs
|
|
63
|
+
|
|
64
|
+
## Getting started
|
|
65
|
+
|
|
66
|
+
### Install from PyPI
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install doclogs-cli
|
|
70
|
+
doclog --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Install from source (development)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/MridulTi/DocLogs.git
|
|
77
|
+
cd DocLogs
|
|
78
|
+
python -m venv .venv
|
|
79
|
+
source .venv/bin/activate
|
|
80
|
+
pip install -e .
|
|
81
|
+
doclog --help
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### First run
|
|
85
|
+
|
|
86
|
+
Data is stored under `~/.doclog/` (entries, posts, config). On first use, a default `config.yaml` is created there.
|
|
87
|
+
|
|
88
|
+
To keep using a project-local folder instead:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
export DOCLOG_HOME="$PWD/doclog"
|
|
92
|
+
doclog capture
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Daily use
|
|
96
|
+
|
|
97
|
+
1. Configure `~/.doclog/config.yaml` with your preferred LLM provider (created automatically on first run).
|
|
98
|
+
2. Add a scheduler entry outside the CLI to invoke `doclog capture` at your preferred check-in time.
|
|
99
|
+
3. Capture daily progress and generate reusable career artifacts from the same captured story.
|
|
100
|
+
|
|
101
|
+
## Publish to PyPI (GitHub Actions)
|
|
102
|
+
|
|
103
|
+
Publishing runs via GitHub Actions — no local `twine upload` needed.
|
|
104
|
+
|
|
105
|
+
1. Configure [trusted publishing](docs/publishing.md) on PyPI (leave Environment blank)
|
|
106
|
+
2. Push a version tag:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git tag v0.1.0
|
|
110
|
+
git push origin v0.1.0
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The workflow uploads to PyPI automatically.
|
|
114
|
+
|
|
115
|
+
See [docs/publishing.md](docs/publishing.md) for full setup.
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from helper.capture import build_capture_entry, merge_notes
|
|
5
|
+
from helper.capture_prompts import iter_interactive_tasks
|
|
6
|
+
from helper.entry import save_entry
|
|
7
|
+
from helper.git_collector import find_git_root
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _print_summary(entry, path) -> None:
|
|
11
|
+
typer.echo(f"\n📥 Captured to {path}")
|
|
12
|
+
typer.echo(f" branch: {entry.branch or 'n/a'}")
|
|
13
|
+
typer.echo(f" commits today: {len(entry.commits)}")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register(app: typer.Typer):
|
|
17
|
+
|
|
18
|
+
@app.command("capture", help="Capture today's engineering work into local storage.")
|
|
19
|
+
def capture(
|
|
20
|
+
notes: Optional[str] = typer.Option(None, "-n", "--notes", help="Optional notes (skips interactive prompts)."),
|
|
21
|
+
no_interactive: bool = typer.Option(False, "--no-interactive", help="Skip questions; git-only capture."),
|
|
22
|
+
include_terminal: bool = typer.Option(False, help="Include optional terminal history evidence."),
|
|
23
|
+
include_tickets: bool = typer.Option(False, help="Include optional ticket IDs or issue references."),
|
|
24
|
+
) -> None:
|
|
25
|
+
if find_git_root() is None:
|
|
26
|
+
typer.echo("⚠️ Not inside a git repo — git evidence will be empty.")
|
|
27
|
+
|
|
28
|
+
# Interactive: multiple tasks in one session
|
|
29
|
+
if not no_interactive and notes is None:
|
|
30
|
+
path = None
|
|
31
|
+
entry = None
|
|
32
|
+
saved_any = False
|
|
33
|
+
|
|
34
|
+
for batch, replace in iter_interactive_tasks():
|
|
35
|
+
entry = build_capture_entry(notes=batch, replace_notes=replace)
|
|
36
|
+
path = save_entry(entry)
|
|
37
|
+
saved_any = True
|
|
38
|
+
typer.echo(" ✓ Task saved" if not replace else " ✓ Task updated")
|
|
39
|
+
|
|
40
|
+
if not saved_any:
|
|
41
|
+
entry = build_capture_entry(notes=None)
|
|
42
|
+
path = save_entry(entry)
|
|
43
|
+
|
|
44
|
+
_print_summary(entry, path)
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
# Non-interactive: git only or single --notes
|
|
48
|
+
final_notes = merge_notes(notes)
|
|
49
|
+
entry = build_capture_entry(notes=final_notes)
|
|
50
|
+
path = save_entry(entry)
|
|
51
|
+
_print_summary(entry, path)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
|
|
7
|
+
from helper.paths import config_path, ensure_config
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_config(path: Path | None = None) -> dict[str, object]:
|
|
11
|
+
config_file = path or ensure_config()
|
|
12
|
+
if not config_file.exists():
|
|
13
|
+
raise typer.Exit(code=1, message=f"Config file not found: {config_file}")
|
|
14
|
+
with config_file.open("r", encoding="utf-8") as stream:
|
|
15
|
+
return yaml.safe_load(stream) or {}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register(app: typer.Typer):
|
|
19
|
+
|
|
20
|
+
@app.command("config", help="Show the active DocLogs configuration.")
|
|
21
|
+
def config(
|
|
22
|
+
path: Optional[Path] = typer.Option(None, "-c", "--config", help="Path to the config file."),
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Print the active DocLogs configuration."""
|
|
25
|
+
active = path or ensure_config()
|
|
26
|
+
settings = load_config(active)
|
|
27
|
+
typer.echo(f"Active DocLogs configuration ({active}):")
|
|
28
|
+
typer.echo(settings)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from helper.generate import build_prompt
|
|
7
|
+
from helper.paths import posts_dir
|
|
8
|
+
from helper.story import find_story_text
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def slugify(text: str) -> str:
|
|
12
|
+
text = text.strip().lower()
|
|
13
|
+
text = re.sub(r"[^\w\s-]", "", text)
|
|
14
|
+
return re.sub(r"[-\s]+", "-", text).strip("-")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def register(app: typer.Typer):
|
|
18
|
+
|
|
19
|
+
@app.command("generate", help="Generate a reusable artifact from a captured story.")
|
|
20
|
+
def generate(
|
|
21
|
+
artifact_type: str = typer.Argument(..., help="blog, linkedin, resume, interview, changelog"),
|
|
22
|
+
title: Optional[str] = typer.Option(None, "-t", "--title", help="Story title from doclog weekly."),
|
|
23
|
+
days: int = typer.Option(7, help="Days back to search for the story."),
|
|
24
|
+
) -> None:
|
|
25
|
+
if not title:
|
|
26
|
+
typer.echo("Pass a story title: doclog generate blog -t \"Phase 0 completed\"")
|
|
27
|
+
raise typer.Exit(code=1)
|
|
28
|
+
|
|
29
|
+
story = find_story_text(title, days=days)
|
|
30
|
+
if not story:
|
|
31
|
+
typer.echo(f"Story not found: {title!r}")
|
|
32
|
+
typer.echo("Run doclog weekly to see available titles.")
|
|
33
|
+
raise typer.Exit(code=1)
|
|
34
|
+
|
|
35
|
+
prompt, findings, flags = build_prompt(artifact_type, story)
|
|
36
|
+
|
|
37
|
+
if flags:
|
|
38
|
+
typer.echo("⚠️ Sensitive patterns flagged — review before sending to an LLM:")
|
|
39
|
+
for flag in flags:
|
|
40
|
+
typer.echo(f" - [{flag.kind}] {flag.matched[:60]}")
|
|
41
|
+
|
|
42
|
+
output_dir = posts_dir()
|
|
43
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
out = output_dir / f"{slugify(title)}-{artifact_type}.md"
|
|
45
|
+
out.write_text(prompt, encoding="utf-8")
|
|
46
|
+
|
|
47
|
+
typer.echo(f"✨ Prompt saved to {out}")
|
|
48
|
+
if findings:
|
|
49
|
+
typer.echo(f" ({len(findings)} item(s) redacted in evidence)")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from typing import *
|
|
3
|
+
|
|
4
|
+
from helper.entry import entry_path_for, load_entry
|
|
5
|
+
from helper.sanitize import redact, sanitize_with_review, text_from_entry
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register(app: typer.Typer):
|
|
9
|
+
|
|
10
|
+
@app.command("sanitize", help="Sanitize content before sending to an LLM.")
|
|
11
|
+
def sanitize(
|
|
12
|
+
source: Optional[str] = typer.Argument(None, help="Text to sanitize. If omitted, uses today's capture."),
|
|
13
|
+
) -> None:
|
|
14
|
+
if source:
|
|
15
|
+
text = source
|
|
16
|
+
else:
|
|
17
|
+
entry = load_entry(entry_path_for())
|
|
18
|
+
if not entry:
|
|
19
|
+
typer.echo("No capture for today. Run: doclog capture")
|
|
20
|
+
raise typer.Exit(code=1)
|
|
21
|
+
text = text_from_entry(entry)
|
|
22
|
+
sanitized, findings, flags = sanitize_with_review(text)
|
|
23
|
+
typer.echo("🔒 Sanitized output:\n")
|
|
24
|
+
typer.echo(sanitized)
|
|
25
|
+
if findings:
|
|
26
|
+
typer.echo(f"\n({len(findings)} item(s) redacted)")
|
|
27
|
+
else:
|
|
28
|
+
typer.echo("\n(no sensitive patterns detected)")
|
|
29
|
+
if flags:
|
|
30
|
+
typer.echo("\n⚠️ Review before sending to LLM:")
|
|
31
|
+
for flag in flags:
|
|
32
|
+
snippet = flag.matched[:60] + ("..." if len(flag.matched) > 60 else "")
|
|
33
|
+
typer.echo(f" - [{flag.kind}] {snippet}")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from ast import Return
|
|
2
|
+
import typer
|
|
3
|
+
from typing import *
|
|
4
|
+
from helper.weekly import build_story_candidates, load_entries_for_days
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def register(app: typer.Typer):
|
|
8
|
+
|
|
9
|
+
@app.command("weekly", help="run workflows")
|
|
10
|
+
def weekly(
|
|
11
|
+
limit: int = typer.Option(5, help="Maximum number of story candidates to display."),
|
|
12
|
+
days: int = typer.Option(7, help="How many days back to review.")
|
|
13
|
+
) -> None:
|
|
14
|
+
"""Summarize the week and surface candidate stories for expansion."""
|
|
15
|
+
entries = load_entries_for_days(days)
|
|
16
|
+
if not entries:
|
|
17
|
+
typer.echo(f"📅 No captures found in the last {days} days.")
|
|
18
|
+
typer.echo('Run: doclog capture --notes "what you worked on today"')
|
|
19
|
+
return
|
|
20
|
+
typer.echo(f"📅 Weekly summary ({len(entries)} day(s) captured)")
|
|
21
|
+
candidates = build_story_candidates(entries, limit=limit)
|
|
22
|
+
|
|
23
|
+
if not candidates:
|
|
24
|
+
typer.echo("No story candidates yet.")
|
|
25
|
+
return
|
|
26
|
+
for i, story in enumerate(candidates, start=1):
|
|
27
|
+
typer.echo(f"{i}. [{story.source}] {story.title} ({story.date})")
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: doclogs-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI for capturing engineering work and turning it into career artifacts.
|
|
5
|
+
Author: Mridul Tiwari
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/MridulTi/DocLogs
|
|
8
|
+
Project-URL: Repository, https://github.com/MridulTi/DocLogs
|
|
9
|
+
Project-URL: Issues, https://github.com/MridulTi/DocLogs/issues
|
|
10
|
+
Keywords: cli,engineering,career,devlog,documentation,resume
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: typer>=0.10.0
|
|
24
|
+
Requires-Dist: PyYAML>=6.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# DocLogs
|
|
28
|
+
|
|
29
|
+
DocLogs is an engineer career operating system for capturing and reusing technical work.
|
|
30
|
+
|
|
31
|
+
## What it solves
|
|
32
|
+
|
|
33
|
+
Engineers do valuable work every day: incident response, CI/CD and platform debugging, automation, infrastructure changes, PR reviews, and migrations. Most of that work is forgotten when it matters most: performance reviews, promotion packets, interviews, and professional storytelling.
|
|
34
|
+
|
|
35
|
+
DocLogs helps you turn day-to-day engineering activity into durable artifacts by:
|
|
36
|
+
|
|
37
|
+
- capturing evidence automatically from git, branches, PRs, and optional histories
|
|
38
|
+
- summarizing weekly progress and surfacing strong stories
|
|
39
|
+
- generating markdown artifacts for blog posts, LinkedIn, resumes, and interview prep
|
|
40
|
+
- keeping model usage provider-agnostic and safe with sanitization
|
|
41
|
+
|
|
42
|
+
## Core commands
|
|
43
|
+
|
|
44
|
+
- `doclog capture`
|
|
45
|
+
- collect commits, repository activity, PR titles, tickets, and optional notes
|
|
46
|
+
- store structured daily entries in local storage
|
|
47
|
+
- `doclog weekly`
|
|
48
|
+
- review weekly work
|
|
49
|
+
- surface candidate stories worth expanding
|
|
50
|
+
- `doclog generate <type>`
|
|
51
|
+
- create reusable artifacts such as `blog`, `linkedin`, `resume`, `interview`, or `changelog`
|
|
52
|
+
- `doclog sanitize`
|
|
53
|
+
- sanitize captured content before any LLM request
|
|
54
|
+
- redact internal URLs, tokens, IP addresses, and other sensitive details
|
|
55
|
+
|
|
56
|
+
## Recommended repository structure
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
./
|
|
60
|
+
├── README.md
|
|
61
|
+
├── config.yaml
|
|
62
|
+
├── commands/
|
|
63
|
+
│ ├── capture.py
|
|
64
|
+
│ └── config.py
|
|
65
|
+
├── docs/
|
|
66
|
+
│ ├── vision.md
|
|
67
|
+
│ └── architecture.md
|
|
68
|
+
├── doclog/
|
|
69
|
+
│ ├── entries/
|
|
70
|
+
│ ├── posts/
|
|
71
|
+
│ └── cache/
|
|
72
|
+
├── prompts/
|
|
73
|
+
│ ├── blog.md
|
|
74
|
+
│ ├── linkedin.md
|
|
75
|
+
│ └── resume.md
|
|
76
|
+
└── .copilot
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Architecture overview
|
|
80
|
+
|
|
81
|
+
DocLogs keeps the capture layer local and the generation layer model-agnostic. It is intentionally not a scheduler; use OS-level schedulers like `cron`, `systemd --user`, `launchd`, or Task Scheduler to invoke `doclog capture` at reminder times.
|
|
82
|
+
|
|
83
|
+
For implementation, start by focusing on:
|
|
84
|
+
|
|
85
|
+
1. evidence collection and local storage
|
|
86
|
+
2. weekly summaries and story selection
|
|
87
|
+
3. safe prompt generation
|
|
88
|
+
4. provider adapters for OpenAI, Ollama, Anthropic, Gemini, or other APIs
|
|
89
|
+
|
|
90
|
+
## Getting started
|
|
91
|
+
|
|
92
|
+
### Install from PyPI
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install doclogs-cli
|
|
96
|
+
doclog --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Install from source (development)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/MridulTi/DocLogs.git
|
|
103
|
+
cd DocLogs
|
|
104
|
+
python -m venv .venv
|
|
105
|
+
source .venv/bin/activate
|
|
106
|
+
pip install -e .
|
|
107
|
+
doclog --help
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### First run
|
|
111
|
+
|
|
112
|
+
Data is stored under `~/.doclog/` (entries, posts, config). On first use, a default `config.yaml` is created there.
|
|
113
|
+
|
|
114
|
+
To keep using a project-local folder instead:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export DOCLOG_HOME="$PWD/doclog"
|
|
118
|
+
doclog capture
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Daily use
|
|
122
|
+
|
|
123
|
+
1. Configure `~/.doclog/config.yaml` with your preferred LLM provider (created automatically on first run).
|
|
124
|
+
2. Add a scheduler entry outside the CLI to invoke `doclog capture` at your preferred check-in time.
|
|
125
|
+
3. Capture daily progress and generate reusable career artifacts from the same captured story.
|
|
126
|
+
|
|
127
|
+
## Publish to PyPI (GitHub Actions)
|
|
128
|
+
|
|
129
|
+
Publishing runs via GitHub Actions — no local `twine upload` needed.
|
|
130
|
+
|
|
131
|
+
1. Configure [trusted publishing](docs/publishing.md) on PyPI (leave Environment blank)
|
|
132
|
+
2. Push a version tag:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git tag v0.1.0
|
|
136
|
+
git push origin v0.1.0
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The workflow uploads to PyPI automatically.
|
|
140
|
+
|
|
141
|
+
See [docs/publishing.md](docs/publishing.md) for full setup.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
main.py
|
|
4
|
+
pyproject.toml
|
|
5
|
+
commands/__init__.py
|
|
6
|
+
commands/capture.py
|
|
7
|
+
commands/config.py
|
|
8
|
+
commands/generate.py
|
|
9
|
+
commands/sanitize.py
|
|
10
|
+
commands/weekly.py
|
|
11
|
+
doclogs_cli.egg-info/PKG-INFO
|
|
12
|
+
doclogs_cli.egg-info/SOURCES.txt
|
|
13
|
+
doclogs_cli.egg-info/dependency_links.txt
|
|
14
|
+
doclogs_cli.egg-info/entry_points.txt
|
|
15
|
+
doclogs_cli.egg-info/requires.txt
|
|
16
|
+
doclogs_cli.egg-info/top_level.txt
|
|
17
|
+
helper/__init__.py
|
|
18
|
+
helper/capture.py
|
|
19
|
+
helper/capture_prompts.py
|
|
20
|
+
helper/entry.py
|
|
21
|
+
helper/generate.py
|
|
22
|
+
helper/git_collector.py
|
|
23
|
+
helper/paths.py
|
|
24
|
+
helper/prompts.py
|
|
25
|
+
helper/sanitize.py
|
|
26
|
+
helper/story.py
|
|
27
|
+
helper/task_notes.py
|
|
28
|
+
helper/weekly.py
|
|
29
|
+
helper/templates/blog.md
|
|
30
|
+
helper/templates/changelog.md
|
|
31
|
+
helper/templates/config.yaml
|
|
32
|
+
helper/templates/interview.md
|
|
33
|
+
helper/templates/linkedin.md
|
|
34
|
+
helper/templates/resume.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
File without changes
|