@mclawnet/agent 0.5.9 → 0.6.2
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.
- package/cli.js +168 -61
- package/dist/__tests__/cli.test.d.ts +2 -0
- package/dist/__tests__/cli.test.d.ts.map +1 -0
- package/dist/__tests__/service-config.test.d.ts +2 -0
- package/dist/__tests__/service-config.test.d.ts.map +1 -0
- package/dist/__tests__/service-linux.test.d.ts +2 -0
- package/dist/__tests__/service-linux.test.d.ts.map +1 -0
- package/dist/__tests__/service-macos.test.d.ts +2 -0
- package/dist/__tests__/service-macos.test.d.ts.map +1 -0
- package/dist/__tests__/service-windows.test.d.ts +2 -0
- package/dist/__tests__/service-windows.test.d.ts.map +1 -0
- package/dist/backend-adapter.d.ts +2 -0
- package/dist/backend-adapter.d.ts.map +1 -1
- package/dist/chunk-CBZIH6FY.js +93 -0
- package/dist/chunk-CBZIH6FY.js.map +1 -0
- package/dist/{chunk-KHPEQTWF.js → chunk-GLO5OZAY.js} +203 -213
- package/dist/chunk-GLO5OZAY.js.map +1 -0
- package/dist/chunk-RO47ET27.js +88 -0
- package/dist/chunk-RO47ET27.js.map +1 -0
- package/dist/hub-connection.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/linux-6AR7SXHW.js +176 -0
- package/dist/linux-6AR7SXHW.js.map +1 -0
- package/dist/macos-XVPWIH4C.js +174 -0
- package/dist/macos-XVPWIH4C.js.map +1 -0
- package/dist/service/config.d.ts +19 -0
- package/dist/service/config.d.ts.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +47 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/linux.d.ts +18 -0
- package/dist/service/linux.d.ts.map +1 -0
- package/dist/service/macos.d.ts +18 -0
- package/dist/service/macos.d.ts.map +1 -0
- package/dist/service/types.d.ts +19 -0
- package/dist/service/types.d.ts.map +1 -0
- package/dist/service/windows.d.ts +18 -0
- package/dist/service/windows.d.ts.map +1 -0
- package/dist/session-manager.d.ts +4 -7
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/skill-loader.d.ts +8 -0
- package/dist/skill-loader.d.ts.map +1 -0
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +2 -1
- package/dist/windows-NLONSCDA.js +165 -0
- package/dist/windows-NLONSCDA.js.map +1 -0
- package/package.json +7 -5
- package/skills/academic-search/SKILL.md +147 -0
- package/skills/architecture/SKILL.md +294 -0
- package/skills/changelog-generator/SKILL.md +112 -0
- package/skills/chart-visualization/SKILL.md +183 -0
- package/skills/code-review/SKILL.md +304 -0
- package/skills/codebase-health/SKILL.md +281 -0
- package/skills/consulting-analysis/SKILL.md +584 -0
- package/skills/content-research-writer/SKILL.md +546 -0
- package/skills/data-analysis/SKILL.md +194 -0
- package/skills/deep-research/SKILL.md +198 -0
- package/skills/docx/SKILL.md +211 -0
- package/skills/github-deep-research/SKILL.md +207 -0
- package/skills/image-generation/SKILL.md +209 -0
- package/skills/lead-research-assistant/SKILL.md +207 -0
- package/skills/mcp-builder/SKILL.md +304 -0
- package/skills/meeting-insights-analyzer/SKILL.md +335 -0
- package/skills/pair-programming/SKILL.md +196 -0
- package/skills/pdf/SKILL.md +309 -0
- package/skills/performance-analysis/SKILL.md +261 -0
- package/skills/podcast-generation/SKILL.md +224 -0
- package/skills/pptx/SKILL.md +497 -0
- package/skills/project-learnings/SKILL.md +280 -0
- package/skills/security-audit/SKILL.md +211 -0
- package/skills/skill-creator/SKILL.md +200 -0
- package/skills/technical-writing/SKILL.md +286 -0
- package/skills/testing/SKILL.md +363 -0
- package/skills/video-generation/SKILL.md +247 -0
- package/skills/web-design-guidelines/SKILL.md +203 -0
- package/skills/webapp-testing/SKILL.md +162 -0
- package/skills/workflow-automation/SKILL.md +299 -0
- package/skills/xlsx/SKILL.md +305 -0
- package/dist/chunk-KHPEQTWF.js.map +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pair-programming
|
|
3
|
+
description: Facilitate effective AI-assisted pair programming sessions with structured collaboration modes. Use when working through complex implementations, debugging sessions, refactoring tasks, or learning new codebases with an AI partner.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pair Programming
|
|
7
|
+
|
|
8
|
+
Structured AI-assisted pair programming for productive collaboration on implementation, debugging, refactoring, and learning tasks.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Pair programming with AI is most effective when roles are clear and the collaboration mode matches the task. This skill defines three modes — Driver, Navigator, and TDD — each with specific responsibilities, communication patterns, and quality checks. The goal is not to produce code faster, but to produce better code by combining human judgment with AI capabilities.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- Implementing complex features that benefit from real-time review
|
|
17
|
+
- Debugging problems that require systematic exploration
|
|
18
|
+
- Refactoring existing code while maintaining behavior
|
|
19
|
+
- Learning a new codebase, framework, or pattern
|
|
20
|
+
- Working through architectural decisions with concrete code
|
|
21
|
+
- Situations where you want continuous quality feedback as you code
|
|
22
|
+
|
|
23
|
+
## When NOT to Use
|
|
24
|
+
|
|
25
|
+
- **Quick one-line fixes** — just make the change
|
|
26
|
+
- **Code review of completed work** — use the `code-review` skill
|
|
27
|
+
- **Writing tests for existing code** — use the `testing` skill
|
|
28
|
+
- **Architecture planning without code** — use the `architecture` skill
|
|
29
|
+
|
|
30
|
+
## Collaboration Modes
|
|
31
|
+
|
|
32
|
+
### Driver Mode
|
|
33
|
+
|
|
34
|
+
**You write code. AI navigates.**
|
|
35
|
+
|
|
36
|
+
Best for: learning, implementing familiar features, hands-on debugging.
|
|
37
|
+
|
|
38
|
+
**Your role (Driver):**
|
|
39
|
+
- Write the actual code
|
|
40
|
+
- Make implementation decisions
|
|
41
|
+
- Control the pace
|
|
42
|
+
- Ask questions when stuck
|
|
43
|
+
|
|
44
|
+
**AI role (Navigator):**
|
|
45
|
+
- Review each change as it's made
|
|
46
|
+
- Spot potential bugs, edge cases, or security issues
|
|
47
|
+
- Suggest improvements and alternatives
|
|
48
|
+
- Keep the big picture in view — remind of requirements and constraints
|
|
49
|
+
- Flag when the approach is drifting from the goal
|
|
50
|
+
|
|
51
|
+
**Communication pattern:**
|
|
52
|
+
- After each meaningful change, pause for navigator feedback
|
|
53
|
+
- Navigator speaks up proactively when spotting issues
|
|
54
|
+
- Driver can request: "review this", "suggest a better approach", "what am I missing?"
|
|
55
|
+
|
|
56
|
+
### Navigator Mode
|
|
57
|
+
|
|
58
|
+
**AI writes code. You direct.**
|
|
59
|
+
|
|
60
|
+
Best for: rapid prototyping, boilerplate generation, exploring solutions.
|
|
61
|
+
|
|
62
|
+
**Your role (Navigator):**
|
|
63
|
+
- Define what to build and the acceptance criteria
|
|
64
|
+
- Review every piece of generated code before accepting
|
|
65
|
+
- Make architectural and design decisions
|
|
66
|
+
- Redirect when implementation drifts from requirements
|
|
67
|
+
- Approve or reject each change
|
|
68
|
+
|
|
69
|
+
**AI role (Driver):**
|
|
70
|
+
- Write implementation code as directed
|
|
71
|
+
- Explain decisions and trade-offs as it codes
|
|
72
|
+
- Present alternatives when there are multiple valid approaches
|
|
73
|
+
- Stop and ask when requirements are ambiguous
|
|
74
|
+
|
|
75
|
+
**Communication pattern:**
|
|
76
|
+
- AI explains what it's about to do before writing code
|
|
77
|
+
- You approve the approach, then AI implements
|
|
78
|
+
- You review the result before moving to the next piece
|
|
79
|
+
- You can say: "try a different approach", "simplify this", "add error handling"
|
|
80
|
+
|
|
81
|
+
### TDD Mode
|
|
82
|
+
|
|
83
|
+
**Alternate between writing tests and implementation.**
|
|
84
|
+
|
|
85
|
+
Best for: building features with high correctness requirements, learning TDD.
|
|
86
|
+
|
|
87
|
+
**Process:**
|
|
88
|
+
|
|
89
|
+
1. **Red**: Write one failing test that describes the next small behavior
|
|
90
|
+
2. **Verify**: Run the test and confirm it fails for the right reason
|
|
91
|
+
3. **Green**: Write the minimum code to make the test pass
|
|
92
|
+
4. **Verify**: Run all tests and confirm everything passes
|
|
93
|
+
5. **Refactor**: Improve code structure without changing behavior
|
|
94
|
+
6. **Verify**: Run all tests and confirm they still pass
|
|
95
|
+
7. **Commit**: Save progress
|
|
96
|
+
8. **Repeat**: Back to step 1 for the next behavior
|
|
97
|
+
|
|
98
|
+
**Role alternation:**
|
|
99
|
+
- Either person can write the test or the implementation
|
|
100
|
+
- A good pattern: you write the test (defining the spec), AI writes the implementation
|
|
101
|
+
- Or: AI writes the test, you verify it captures the right behavior, AI implements
|
|
102
|
+
|
|
103
|
+
## Session Flow
|
|
104
|
+
|
|
105
|
+
### Starting a Session
|
|
106
|
+
|
|
107
|
+
1. **State the goal**: What are we building/fixing/improving?
|
|
108
|
+
2. **Choose the mode**: Driver, Navigator, or TDD
|
|
109
|
+
3. **Set scope**: What files/modules are in scope? What's off-limits?
|
|
110
|
+
4. **Establish quality bar**: What does "done" look like?
|
|
111
|
+
|
|
112
|
+
### During the Session
|
|
113
|
+
|
|
114
|
+
**Every 15-20 minutes, check:**
|
|
115
|
+
- Are we still on track toward the goal?
|
|
116
|
+
- Has scope crept beyond what we started with?
|
|
117
|
+
- Are tests passing?
|
|
118
|
+
- Should we commit what we have?
|
|
119
|
+
|
|
120
|
+
**Switching modes is OK:**
|
|
121
|
+
- Start in Navigator mode for rapid scaffolding
|
|
122
|
+
- Switch to Driver mode when you want to understand the details
|
|
123
|
+
- Switch to TDD mode when correctness matters most
|
|
124
|
+
|
|
125
|
+
### Ending a Session
|
|
126
|
+
|
|
127
|
+
1. Run all tests
|
|
128
|
+
2. Review the diff of everything changed
|
|
129
|
+
3. Commit with a descriptive message
|
|
130
|
+
4. Note any follow-up items
|
|
131
|
+
|
|
132
|
+
## Quality Practices
|
|
133
|
+
|
|
134
|
+
### Continuous Review
|
|
135
|
+
|
|
136
|
+
Every change should be reviewed before moving on:
|
|
137
|
+
|
|
138
|
+
- **Correctness**: Does it do what it should? Edge cases handled?
|
|
139
|
+
- **Readability**: Will this make sense in a month?
|
|
140
|
+
- **Simplicity**: Is there a simpler way to achieve the same result?
|
|
141
|
+
- **Testability**: Can this be easily tested?
|
|
142
|
+
|
|
143
|
+
### Red Flags to Watch For
|
|
144
|
+
|
|
145
|
+
- **Growing complexity**: If the solution keeps getting more complicated, step back and reconsider the approach
|
|
146
|
+
- **Working around the framework**: If you're fighting the language/framework, you may be using it wrong
|
|
147
|
+
- **No tests**: If you've written more than 20 lines without a test, pause and add one
|
|
148
|
+
- **Copy-paste code**: If you're copying blocks, extract a function
|
|
149
|
+
- **Magic numbers/strings**: Name every constant
|
|
150
|
+
|
|
151
|
+
### Communication Signals
|
|
152
|
+
|
|
153
|
+
| Signal | Meaning |
|
|
154
|
+
|---|---|
|
|
155
|
+
| "I'm stuck" | Pause, explain the problem, brainstorm approaches |
|
|
156
|
+
| "This feels wrong" | Step back, review the approach, consider alternatives |
|
|
157
|
+
| "What if..." | Explore the idea before committing to code |
|
|
158
|
+
| "Let's commit" | We have a working increment, save it |
|
|
159
|
+
| "Let's refactor" | The code works but isn't clean, improve structure |
|
|
160
|
+
| "Let me drive" | Switch to Driver mode |
|
|
161
|
+
| "You drive" | Switch to Navigator mode |
|
|
162
|
+
|
|
163
|
+
## Debugging Sessions
|
|
164
|
+
|
|
165
|
+
When pair programming for debugging:
|
|
166
|
+
|
|
167
|
+
1. **Reproduce**: Get a reliable reproduction of the bug
|
|
168
|
+
2. **Hypothesize**: List 3 possible causes
|
|
169
|
+
3. **Test**: Check the most likely hypothesis first
|
|
170
|
+
4. **Narrow**: Binary search through the code to find the exact location
|
|
171
|
+
5. **Fix**: Write a test that fails because of the bug, then fix the code
|
|
172
|
+
6. **Verify**: Confirm the fix doesn't break anything else
|
|
173
|
+
|
|
174
|
+
**Navigator's job during debugging:**
|
|
175
|
+
- Track which hypotheses have been tested
|
|
176
|
+
- Suggest new hypotheses based on evidence
|
|
177
|
+
- Watch for confirmation bias (testing only what supports our theory)
|
|
178
|
+
- Remind to write a regression test
|
|
179
|
+
|
|
180
|
+
## Anti-Patterns
|
|
181
|
+
|
|
182
|
+
### Rubber Duck Syndrome
|
|
183
|
+
**Problem**: Using AI as a silent audience instead of an active partner.
|
|
184
|
+
**Fix**: Ask for explicit review, suggestions, and alternatives. Use the navigator role.
|
|
185
|
+
|
|
186
|
+
### Speed Over Quality
|
|
187
|
+
**Problem**: Rushing to produce code without review.
|
|
188
|
+
**Fix**: Review every function before moving to the next. Run tests frequently.
|
|
189
|
+
|
|
190
|
+
### Scope Creep
|
|
191
|
+
**Problem**: "While we're here, let's also fix X, Y, Z..."
|
|
192
|
+
**Fix**: Note follow-ups, stay focused on the original goal. One commit per concern.
|
|
193
|
+
|
|
194
|
+
### Not Committing
|
|
195
|
+
**Problem**: 200 lines of uncommitted changes.
|
|
196
|
+
**Fix**: Commit after each passing test or completed feature slice. Small, frequent commits.
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pdf
|
|
3
|
+
description: Process PDF documents including text extraction, table parsing, creation, merging, splitting, and form filling. Use when working with PDF files for reading, generating, manipulating, or analyzing PDF content at scale.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PDF Processing Guide
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see reference.md. If you need to fill out a PDF form, read forms.md and follow its instructions.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- Extracting text or tables from PDF files
|
|
15
|
+
- Creating new PDF documents programmatically
|
|
16
|
+
- Merging, splitting, or rotating PDF pages
|
|
17
|
+
- Filling out PDF forms
|
|
18
|
+
- Adding watermarks or password protection
|
|
19
|
+
- OCR on scanned PDF documents
|
|
20
|
+
|
|
21
|
+
## When NOT to Use
|
|
22
|
+
|
|
23
|
+
- **Word documents** — use the `docx` skill
|
|
24
|
+
- **Spreadsheets** — use the `xlsx` skill
|
|
25
|
+
- **Presentations** — use the `pptx` skill
|
|
26
|
+
- **Simple text extraction** — if the content is also available as .txt or .md, read directly
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from pypdf import PdfReader, PdfWriter
|
|
32
|
+
|
|
33
|
+
# Read a PDF
|
|
34
|
+
reader = PdfReader("document.pdf")
|
|
35
|
+
print(f"Pages: {len(reader.pages)}")
|
|
36
|
+
|
|
37
|
+
# Extract text
|
|
38
|
+
text = ""
|
|
39
|
+
for page in reader.pages:
|
|
40
|
+
text += page.extract_text()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Python Libraries
|
|
44
|
+
|
|
45
|
+
### pypdf - Basic Operations
|
|
46
|
+
|
|
47
|
+
#### Merge PDFs
|
|
48
|
+
```python
|
|
49
|
+
from pypdf import PdfWriter, PdfReader
|
|
50
|
+
|
|
51
|
+
writer = PdfWriter()
|
|
52
|
+
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
|
|
53
|
+
reader = PdfReader(pdf_file)
|
|
54
|
+
for page in reader.pages:
|
|
55
|
+
writer.add_page(page)
|
|
56
|
+
|
|
57
|
+
with open("merged.pdf", "wb") as output:
|
|
58
|
+
writer.write(output)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Split PDF
|
|
62
|
+
```python
|
|
63
|
+
reader = PdfReader("input.pdf")
|
|
64
|
+
for i, page in enumerate(reader.pages):
|
|
65
|
+
writer = PdfWriter()
|
|
66
|
+
writer.add_page(page)
|
|
67
|
+
with open(f"page_{i+1}.pdf", "wb") as output:
|
|
68
|
+
writer.write(output)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Extract Metadata
|
|
72
|
+
```python
|
|
73
|
+
reader = PdfReader("document.pdf")
|
|
74
|
+
meta = reader.metadata
|
|
75
|
+
print(f"Title: {meta.title}")
|
|
76
|
+
print(f"Author: {meta.author}")
|
|
77
|
+
print(f"Subject: {meta.subject}")
|
|
78
|
+
print(f"Creator: {meta.creator}")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Rotate Pages
|
|
82
|
+
```python
|
|
83
|
+
reader = PdfReader("input.pdf")
|
|
84
|
+
writer = PdfWriter()
|
|
85
|
+
|
|
86
|
+
page = reader.pages[0]
|
|
87
|
+
page.rotate(90) # Rotate 90 degrees clockwise
|
|
88
|
+
writer.add_page(page)
|
|
89
|
+
|
|
90
|
+
with open("rotated.pdf", "wb") as output:
|
|
91
|
+
writer.write(output)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### pdfplumber - Text and Table Extraction
|
|
95
|
+
|
|
96
|
+
#### Extract Text with Layout
|
|
97
|
+
```python
|
|
98
|
+
import pdfplumber
|
|
99
|
+
|
|
100
|
+
with pdfplumber.open("document.pdf") as pdf:
|
|
101
|
+
for page in pdf.pages:
|
|
102
|
+
text = page.extract_text()
|
|
103
|
+
print(text)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Extract Tables
|
|
107
|
+
```python
|
|
108
|
+
with pdfplumber.open("document.pdf") as pdf:
|
|
109
|
+
for i, page in enumerate(pdf.pages):
|
|
110
|
+
tables = page.extract_tables()
|
|
111
|
+
for j, table in enumerate(tables):
|
|
112
|
+
print(f"Table {j+1} on page {i+1}:")
|
|
113
|
+
for row in table:
|
|
114
|
+
print(row)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Advanced Table Extraction
|
|
118
|
+
```python
|
|
119
|
+
import pandas as pd
|
|
120
|
+
|
|
121
|
+
with pdfplumber.open("document.pdf") as pdf:
|
|
122
|
+
all_tables = []
|
|
123
|
+
for page in pdf.pages:
|
|
124
|
+
tables = page.extract_tables()
|
|
125
|
+
for table in tables:
|
|
126
|
+
if table: # Check if table is not empty
|
|
127
|
+
df = pd.DataFrame(table[1:], columns=table[0])
|
|
128
|
+
all_tables.append(df)
|
|
129
|
+
|
|
130
|
+
# Combine all tables
|
|
131
|
+
if all_tables:
|
|
132
|
+
combined_df = pd.concat(all_tables, ignore_index=True)
|
|
133
|
+
combined_df.to_excel("extracted_tables.xlsx", index=False)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### reportlab - Create PDFs
|
|
137
|
+
|
|
138
|
+
#### Basic PDF Creation
|
|
139
|
+
```python
|
|
140
|
+
from reportlab.lib.pagesizes import letter
|
|
141
|
+
from reportlab.pdfgen import canvas
|
|
142
|
+
|
|
143
|
+
c = canvas.Canvas("hello.pdf", pagesize=letter)
|
|
144
|
+
width, height = letter
|
|
145
|
+
|
|
146
|
+
# Add text
|
|
147
|
+
c.drawString(100, height - 100, "Hello World!")
|
|
148
|
+
c.drawString(100, height - 120, "This is a PDF created with reportlab")
|
|
149
|
+
|
|
150
|
+
# Add a line
|
|
151
|
+
c.line(100, height - 140, 400, height - 140)
|
|
152
|
+
|
|
153
|
+
# Save
|
|
154
|
+
c.save()
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Create PDF with Multiple Pages
|
|
158
|
+
```python
|
|
159
|
+
from reportlab.lib.pagesizes import letter
|
|
160
|
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
|
|
161
|
+
from reportlab.lib.styles import getSampleStyleSheet
|
|
162
|
+
|
|
163
|
+
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
|
|
164
|
+
styles = getSampleStyleSheet()
|
|
165
|
+
story = []
|
|
166
|
+
|
|
167
|
+
# Add content
|
|
168
|
+
title = Paragraph("Report Title", styles['Title'])
|
|
169
|
+
story.append(title)
|
|
170
|
+
story.append(Spacer(1, 12))
|
|
171
|
+
|
|
172
|
+
body = Paragraph("This is the body of the report. " * 20, styles['Normal'])
|
|
173
|
+
story.append(body)
|
|
174
|
+
story.append(PageBreak())
|
|
175
|
+
|
|
176
|
+
# Page 2
|
|
177
|
+
story.append(Paragraph("Page 2", styles['Heading1']))
|
|
178
|
+
story.append(Paragraph("Content for page 2", styles['Normal']))
|
|
179
|
+
|
|
180
|
+
# Build PDF
|
|
181
|
+
doc.build(story)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Command-Line Tools
|
|
185
|
+
|
|
186
|
+
### pdftotext (poppler-utils)
|
|
187
|
+
```bash
|
|
188
|
+
# Extract text
|
|
189
|
+
pdftotext input.pdf output.txt
|
|
190
|
+
|
|
191
|
+
# Extract text preserving layout
|
|
192
|
+
pdftotext -layout input.pdf output.txt
|
|
193
|
+
|
|
194
|
+
# Extract specific pages
|
|
195
|
+
pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### qpdf
|
|
199
|
+
```bash
|
|
200
|
+
# Merge PDFs
|
|
201
|
+
qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf
|
|
202
|
+
|
|
203
|
+
# Split pages
|
|
204
|
+
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
|
|
205
|
+
qpdf input.pdf --pages . 6-10 -- pages6-10.pdf
|
|
206
|
+
|
|
207
|
+
# Rotate pages
|
|
208
|
+
qpdf input.pdf output.pdf --rotate=+90:1 # Rotate page 1 by 90 degrees
|
|
209
|
+
|
|
210
|
+
# Remove password
|
|
211
|
+
qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### pdftk (if available)
|
|
215
|
+
```bash
|
|
216
|
+
# Merge
|
|
217
|
+
pdftk file1.pdf file2.pdf cat output merged.pdf
|
|
218
|
+
|
|
219
|
+
# Split
|
|
220
|
+
pdftk input.pdf burst
|
|
221
|
+
|
|
222
|
+
# Rotate
|
|
223
|
+
pdftk input.pdf rotate 1east output rotated.pdf
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Common Tasks
|
|
227
|
+
|
|
228
|
+
### Extract Text from Scanned PDFs
|
|
229
|
+
```python
|
|
230
|
+
# Requires: pip install pytesseract pdf2image
|
|
231
|
+
import pytesseract
|
|
232
|
+
from pdf2image import convert_from_path
|
|
233
|
+
|
|
234
|
+
# Convert PDF to images
|
|
235
|
+
images = convert_from_path('scanned.pdf')
|
|
236
|
+
|
|
237
|
+
# OCR each page
|
|
238
|
+
text = ""
|
|
239
|
+
for i, image in enumerate(images):
|
|
240
|
+
text += f"Page {i+1}:\n"
|
|
241
|
+
text += pytesseract.image_to_string(image)
|
|
242
|
+
text += "\n\n"
|
|
243
|
+
|
|
244
|
+
print(text)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Add Watermark
|
|
248
|
+
```python
|
|
249
|
+
from pypdf import PdfReader, PdfWriter
|
|
250
|
+
|
|
251
|
+
# Create watermark (or load existing)
|
|
252
|
+
watermark = PdfReader("watermark.pdf").pages[0]
|
|
253
|
+
|
|
254
|
+
# Apply to all pages
|
|
255
|
+
reader = PdfReader("document.pdf")
|
|
256
|
+
writer = PdfWriter()
|
|
257
|
+
|
|
258
|
+
for page in reader.pages:
|
|
259
|
+
page.merge_page(watermark)
|
|
260
|
+
writer.add_page(page)
|
|
261
|
+
|
|
262
|
+
with open("watermarked.pdf", "wb") as output:
|
|
263
|
+
writer.write(output)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Extract Images
|
|
267
|
+
```bash
|
|
268
|
+
# Using pdfimages (poppler-utils)
|
|
269
|
+
pdfimages -j input.pdf output_prefix
|
|
270
|
+
|
|
271
|
+
# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Password Protection
|
|
275
|
+
```python
|
|
276
|
+
from pypdf import PdfReader, PdfWriter
|
|
277
|
+
|
|
278
|
+
reader = PdfReader("input.pdf")
|
|
279
|
+
writer = PdfWriter()
|
|
280
|
+
|
|
281
|
+
for page in reader.pages:
|
|
282
|
+
writer.add_page(page)
|
|
283
|
+
|
|
284
|
+
# Add password
|
|
285
|
+
writer.encrypt("userpassword", "ownerpassword")
|
|
286
|
+
|
|
287
|
+
with open("encrypted.pdf", "wb") as output:
|
|
288
|
+
writer.write(output)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Quick Reference
|
|
292
|
+
|
|
293
|
+
| Task | Best Tool | Command/Code |
|
|
294
|
+
|------|-----------|--------------|
|
|
295
|
+
| Merge PDFs | pypdf | `writer.add_page(page)` |
|
|
296
|
+
| Split PDFs | pypdf | One page per file |
|
|
297
|
+
| Extract text | pdfplumber | `page.extract_text()` |
|
|
298
|
+
| Extract tables | pdfplumber | `page.extract_tables()` |
|
|
299
|
+
| Create PDFs | reportlab | Canvas or Platypus |
|
|
300
|
+
| Command line merge | qpdf | `qpdf --empty --pages ...` |
|
|
301
|
+
| OCR scanned PDFs | pytesseract | Convert to image first |
|
|
302
|
+
| Fill PDF forms | pdf-lib or pypdf (see forms.md) | See forms.md |
|
|
303
|
+
|
|
304
|
+
## Next Steps
|
|
305
|
+
|
|
306
|
+
- For advanced pypdfium2 usage, see reference.md
|
|
307
|
+
- For JavaScript libraries (pdf-lib), see reference.md
|
|
308
|
+
- If you need to fill out a PDF form, follow the instructions in forms.md
|
|
309
|
+
- For troubleshooting guides, see reference.md
|