pragma-so 0.1.3 → 0.1.5
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/dist/cli/index.js +0 -0
- package/dist/server/bundledSkills.js +535 -0
- package/dist/server/conversation/gitWorkflow.js +39 -27
- package/dist/server/conversation/prompts.js +2 -2
- package/dist/server/db.js +34 -6
- package/dist/server/http/schemas.js +49 -2
- package/dist/server/index.js +482 -151
- package/package.json +1 -1
- package/ui/dist/assets/index-Cg6eTG3d.css +1 -0
- package/ui/dist/assets/{index-Dr1FqdaF.js → index-b98Exg-i.js} +117 -112
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-DEkzJ5rp.css +0 -1
package/dist/cli/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bundled skill definitions that ship with every new workspace database.
|
|
4
|
+
* Sourced from https://github.com/anthropics/skills
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.BUNDLED_SKILLS = void 0;
|
|
8
|
+
// Helper constants for embedding backticks inside template literals
|
|
9
|
+
const BT = "`";
|
|
10
|
+
const BT3 = "```";
|
|
11
|
+
exports.BUNDLED_SKILLS = [
|
|
12
|
+
{
|
|
13
|
+
id: "skill_bundled_docx",
|
|
14
|
+
name: "docx",
|
|
15
|
+
description: "Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads.",
|
|
16
|
+
content: `---
|
|
17
|
+
name: docx
|
|
18
|
+
description: "Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation."
|
|
19
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# DOCX creation, editing, and analysis
|
|
23
|
+
|
|
24
|
+
## Overview
|
|
25
|
+
|
|
26
|
+
A .docx file is a ZIP archive containing XML files.
|
|
27
|
+
|
|
28
|
+
## Quick Reference
|
|
29
|
+
|
|
30
|
+
| Task | Approach |
|
|
31
|
+
|------|----------|
|
|
32
|
+
| Read/analyze content | ${BT}pandoc${BT} or unpack for raw XML |
|
|
33
|
+
| Create new document | Use ${BT}docx-js${BT} - see Creating New Documents below |
|
|
34
|
+
| Edit existing document | Unpack → edit XML → repack - see Editing Existing Documents below |
|
|
35
|
+
|
|
36
|
+
### Converting .doc to .docx
|
|
37
|
+
|
|
38
|
+
Legacy ${BT}.doc${BT} files must be converted before editing:
|
|
39
|
+
|
|
40
|
+
${BT3}bash
|
|
41
|
+
python scripts/office/soffice.py --headless --convert-to docx document.doc
|
|
42
|
+
${BT3}
|
|
43
|
+
|
|
44
|
+
### Reading Content
|
|
45
|
+
|
|
46
|
+
${BT3}bash
|
|
47
|
+
# Text extraction with tracked changes
|
|
48
|
+
pandoc --track-changes=all document.docx -o output.md
|
|
49
|
+
|
|
50
|
+
# Raw XML access
|
|
51
|
+
python scripts/office/unpack.py document.docx unpacked/
|
|
52
|
+
${BT3}
|
|
53
|
+
|
|
54
|
+
### Converting to Images
|
|
55
|
+
|
|
56
|
+
${BT3}bash
|
|
57
|
+
python scripts/office/soffice.py --headless --convert-to pdf document.docx
|
|
58
|
+
pdftoppm -jpeg -r 150 document.pdf page
|
|
59
|
+
${BT3}
|
|
60
|
+
|
|
61
|
+
## Creating New Documents
|
|
62
|
+
|
|
63
|
+
Generate .docx files with JavaScript, then validate. Install: ${BT}npm install -g docx${BT}
|
|
64
|
+
|
|
65
|
+
### Setup
|
|
66
|
+
${BT3}javascript
|
|
67
|
+
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,
|
|
68
|
+
Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,
|
|
69
|
+
InternalHyperlink, Bookmark, FootnoteReferenceRun, PositionalTab,
|
|
70
|
+
PositionalTabAlignment, PositionalTabRelativeTo, PositionalTabLeader,
|
|
71
|
+
TabStopType, TabStopPosition, Column, SectionType,
|
|
72
|
+
TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,
|
|
73
|
+
VerticalAlign, PageNumber, PageBreak } = require('docx');
|
|
74
|
+
|
|
75
|
+
const doc = new Document({ sections: [{ children: [/* content */] }] });
|
|
76
|
+
Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer));
|
|
77
|
+
${BT3}
|
|
78
|
+
|
|
79
|
+
### Validation
|
|
80
|
+
After creating the file, validate it. If validation fails, unpack, fix the XML, and repack.
|
|
81
|
+
${BT3}bash
|
|
82
|
+
python scripts/office/validate.py doc.docx
|
|
83
|
+
${BT3}
|
|
84
|
+
|
|
85
|
+
## Dependencies
|
|
86
|
+
|
|
87
|
+
- **pandoc**: Text extraction
|
|
88
|
+
- **docx**: ${BT}npm install -g docx${BT} (new documents)
|
|
89
|
+
- **LibreOffice**: PDF conversion
|
|
90
|
+
- **Poppler**: ${BT}pdftoppm${BT} for images`,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "skill_bundled_fdes",
|
|
94
|
+
name: "frontend-design",
|
|
95
|
+
description: "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications. Generates creative, polished code and UI design that avoids generic AI aesthetics.",
|
|
96
|
+
content: `---
|
|
97
|
+
name: frontend-design
|
|
98
|
+
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
|
|
99
|
+
license: Complete terms in LICENSE.txt
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
|
|
103
|
+
|
|
104
|
+
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
|
|
105
|
+
|
|
106
|
+
## Design Thinking
|
|
107
|
+
|
|
108
|
+
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
|
109
|
+
- **Purpose**: What problem does this interface solve? Who uses it?
|
|
110
|
+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc.
|
|
111
|
+
- **Constraints**: Technical requirements (framework, performance, accessibility).
|
|
112
|
+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
|
113
|
+
|
|
114
|
+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
|
|
115
|
+
|
|
116
|
+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
|
|
117
|
+
- Production-grade and functional
|
|
118
|
+
- Visually striking and memorable
|
|
119
|
+
- Cohesive with a clear aesthetic point-of-view
|
|
120
|
+
- Meticulously refined in every detail
|
|
121
|
+
|
|
122
|
+
## Frontend Aesthetics Guidelines
|
|
123
|
+
|
|
124
|
+
Focus on:
|
|
125
|
+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics.
|
|
126
|
+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
|
|
127
|
+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Focus on high-impact moments: one well-orchestrated page load with staggered reveals creates more delight than scattered micro-interactions.
|
|
128
|
+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
|
|
129
|
+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors.
|
|
130
|
+
|
|
131
|
+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes, predictable layouts, and cookie-cutter design that lacks context-specific character.
|
|
132
|
+
|
|
133
|
+
Remember: Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.`,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "skill_bundled_pdf0",
|
|
137
|
+
name: "pdf",
|
|
138
|
+
description: "Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs.",
|
|
139
|
+
content: `---
|
|
140
|
+
name: pdf
|
|
141
|
+
description: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.
|
|
142
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
# PDF Processing Guide
|
|
146
|
+
|
|
147
|
+
## Overview
|
|
148
|
+
|
|
149
|
+
This guide covers essential PDF processing operations using Python libraries and command-line tools.
|
|
150
|
+
|
|
151
|
+
## Quick Start
|
|
152
|
+
|
|
153
|
+
${BT3}python
|
|
154
|
+
from pypdf import PdfReader, PdfWriter
|
|
155
|
+
|
|
156
|
+
# Read a PDF
|
|
157
|
+
reader = PdfReader("document.pdf")
|
|
158
|
+
print(f"Pages: {len(reader.pages)}")
|
|
159
|
+
|
|
160
|
+
# Extract text
|
|
161
|
+
text = ""
|
|
162
|
+
for page in reader.pages:
|
|
163
|
+
text += page.extract_text()
|
|
164
|
+
${BT3}
|
|
165
|
+
|
|
166
|
+
## Python Libraries
|
|
167
|
+
|
|
168
|
+
### pypdf - Basic Operations
|
|
169
|
+
|
|
170
|
+
#### Merge PDFs
|
|
171
|
+
${BT3}python
|
|
172
|
+
from pypdf import PdfWriter, PdfReader
|
|
173
|
+
|
|
174
|
+
writer = PdfWriter()
|
|
175
|
+
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
|
|
176
|
+
reader = PdfReader(pdf_file)
|
|
177
|
+
for page in reader.pages:
|
|
178
|
+
writer.add_page(page)
|
|
179
|
+
|
|
180
|
+
with open("merged.pdf", "wb") as output:
|
|
181
|
+
writer.write(output)
|
|
182
|
+
${BT3}
|
|
183
|
+
|
|
184
|
+
### pdfplumber - Text and Table Extraction
|
|
185
|
+
|
|
186
|
+
${BT3}python
|
|
187
|
+
import pdfplumber
|
|
188
|
+
|
|
189
|
+
with pdfplumber.open("document.pdf") as pdf:
|
|
190
|
+
for page in pdf.pages:
|
|
191
|
+
text = page.extract_text()
|
|
192
|
+
print(text)
|
|
193
|
+
${BT3}
|
|
194
|
+
|
|
195
|
+
### reportlab - Create PDFs
|
|
196
|
+
|
|
197
|
+
${BT3}python
|
|
198
|
+
from reportlab.lib.pagesizes import letter
|
|
199
|
+
from reportlab.pdfgen import canvas
|
|
200
|
+
|
|
201
|
+
c = canvas.Canvas("hello.pdf", pagesize=letter)
|
|
202
|
+
width, height = letter
|
|
203
|
+
c.drawString(100, height - 100, "Hello World!")
|
|
204
|
+
c.save()
|
|
205
|
+
${BT3}
|
|
206
|
+
|
|
207
|
+
## Command-Line Tools
|
|
208
|
+
|
|
209
|
+
### pdftotext (poppler-utils)
|
|
210
|
+
${BT3}bash
|
|
211
|
+
pdftotext input.pdf output.txt
|
|
212
|
+
pdftotext -layout input.pdf output.txt
|
|
213
|
+
${BT3}
|
|
214
|
+
|
|
215
|
+
### qpdf
|
|
216
|
+
${BT3}bash
|
|
217
|
+
qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf
|
|
218
|
+
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
|
|
219
|
+
${BT3}
|
|
220
|
+
|
|
221
|
+
## Quick Reference
|
|
222
|
+
|
|
223
|
+
| Task | Best Tool | Command/Code |
|
|
224
|
+
|------|-----------|--------------|
|
|
225
|
+
| Merge PDFs | pypdf | ${BT}writer.add_page(page)${BT} |
|
|
226
|
+
| Split PDFs | pypdf | One page per file |
|
|
227
|
+
| Extract text | pdfplumber | ${BT}page.extract_text()${BT} |
|
|
228
|
+
| Extract tables | pdfplumber | ${BT}page.extract_tables()${BT} |
|
|
229
|
+
| Create PDFs | reportlab | Canvas or Platypus |
|
|
230
|
+
| Command line merge | qpdf | ${BT}qpdf --empty --pages ...${BT} |
|
|
231
|
+
| OCR scanned PDFs | pytesseract | Convert to image first |
|
|
232
|
+
| Fill PDF forms | pdf-lib or pypdf | See FORMS.md |`,
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
id: "skill_bundled_pptx",
|
|
236
|
+
name: "pptx",
|
|
237
|
+
description: 'Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file; editing, modifying, or updating existing presentations.',
|
|
238
|
+
content: `---
|
|
239
|
+
name: pptx
|
|
240
|
+
description: "Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \\"deck,\\" \\"slides,\\" \\"presentation,\\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill."
|
|
241
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
# PPTX Skill
|
|
245
|
+
|
|
246
|
+
## Quick Reference
|
|
247
|
+
|
|
248
|
+
| Task | Guide |
|
|
249
|
+
|------|-------|
|
|
250
|
+
| Read/analyze content | ${BT}python -m markitdown presentation.pptx${BT} |
|
|
251
|
+
| Edit or create from template | Read editing.md |
|
|
252
|
+
| Create from scratch | Read pptxgenjs.md |
|
|
253
|
+
|
|
254
|
+
## Reading Content
|
|
255
|
+
|
|
256
|
+
${BT3}bash
|
|
257
|
+
# Text extraction
|
|
258
|
+
python -m markitdown presentation.pptx
|
|
259
|
+
|
|
260
|
+
# Visual overview
|
|
261
|
+
python scripts/thumbnail.py presentation.pptx
|
|
262
|
+
|
|
263
|
+
# Raw XML
|
|
264
|
+
python scripts/office/unpack.py presentation.pptx unpacked/
|
|
265
|
+
${BT3}
|
|
266
|
+
|
|
267
|
+
## Design Ideas
|
|
268
|
+
|
|
269
|
+
**Don't create boring slides.** Plain bullets on a white background won't impress anyone.
|
|
270
|
+
|
|
271
|
+
### Before Starting
|
|
272
|
+
|
|
273
|
+
- **Pick a bold, content-informed color palette**
|
|
274
|
+
- **Dominance over equality**: One color should dominate (60-70% visual weight)
|
|
275
|
+
- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content
|
|
276
|
+
- **Commit to a visual motif**: Pick ONE distinctive element and repeat it
|
|
277
|
+
|
|
278
|
+
### Typography
|
|
279
|
+
|
|
280
|
+
| Element | Size |
|
|
281
|
+
|---------|------|
|
|
282
|
+
| Slide title | 36-44pt bold |
|
|
283
|
+
| Section header | 20-24pt bold |
|
|
284
|
+
| Body text | 14-16pt |
|
|
285
|
+
| Captions | 10-12pt muted |
|
|
286
|
+
|
|
287
|
+
## Dependencies
|
|
288
|
+
|
|
289
|
+
- ${BT}pip install "markitdown[pptx]"${BT} - text extraction
|
|
290
|
+
- ${BT}pip install Pillow${BT} - thumbnail grids
|
|
291
|
+
- ${BT}npm install -g pptxgenjs${BT} - creating from scratch
|
|
292
|
+
- LibreOffice (${BT}soffice${BT}) - PDF conversion
|
|
293
|
+
- Poppler (${BT}pdftoppm${BT}) - PDF to images`,
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
id: "skill_bundled_xlsx",
|
|
297
|
+
name: "xlsx",
|
|
298
|
+
description: 'Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file; create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats.',
|
|
299
|
+
content: `---
|
|
300
|
+
name: xlsx
|
|
301
|
+
description: "Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved."
|
|
302
|
+
license: Proprietary. LICENSE.txt has complete terms
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
# XLSX creation, editing, and analysis
|
|
306
|
+
|
|
307
|
+
## Overview
|
|
308
|
+
|
|
309
|
+
A user may ask you to create, edit, or analyze the contents of an .xlsx file.
|
|
310
|
+
|
|
311
|
+
## CRITICAL: Use Formulas, Not Hardcoded Values
|
|
312
|
+
|
|
313
|
+
**Always use Excel formulas instead of calculating values in Python and hardcoding them.**
|
|
314
|
+
|
|
315
|
+
### Reading and analyzing data
|
|
316
|
+
|
|
317
|
+
${BT3}python
|
|
318
|
+
import pandas as pd
|
|
319
|
+
|
|
320
|
+
df = pd.read_excel('file.xlsx')
|
|
321
|
+
all_sheets = pd.read_excel('file.xlsx', sheet_name=None)
|
|
322
|
+
${BT3}
|
|
323
|
+
|
|
324
|
+
### Creating new Excel files
|
|
325
|
+
|
|
326
|
+
${BT3}python
|
|
327
|
+
from openpyxl import Workbook
|
|
328
|
+
from openpyxl.styles import Font, PatternFill, Alignment
|
|
329
|
+
|
|
330
|
+
wb = Workbook()
|
|
331
|
+
sheet = wb.active
|
|
332
|
+
sheet['A1'] = 'Hello'
|
|
333
|
+
sheet['B2'] = '=SUM(A1:A10)'
|
|
334
|
+
sheet['A1'].font = Font(bold=True, color='FF0000')
|
|
335
|
+
wb.save('output.xlsx')
|
|
336
|
+
${BT3}
|
|
337
|
+
|
|
338
|
+
### Editing existing Excel files
|
|
339
|
+
|
|
340
|
+
${BT3}python
|
|
341
|
+
from openpyxl import load_workbook
|
|
342
|
+
|
|
343
|
+
wb = load_workbook('existing.xlsx')
|
|
344
|
+
sheet = wb.active
|
|
345
|
+
sheet['A1'] = 'New Value'
|
|
346
|
+
wb.save('modified.xlsx')
|
|
347
|
+
${BT3}
|
|
348
|
+
|
|
349
|
+
## Recalculating formulas
|
|
350
|
+
|
|
351
|
+
${BT3}bash
|
|
352
|
+
python scripts/recalc.py <excel_file> [timeout_seconds]
|
|
353
|
+
${BT3}
|
|
354
|
+
|
|
355
|
+
## Best Practices
|
|
356
|
+
|
|
357
|
+
- **pandas**: Best for data analysis, bulk operations, and simple data export
|
|
358
|
+
- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features
|
|
359
|
+
- Cell indices are 1-based
|
|
360
|
+
- Use ${BT}data_only=True${BT} to read calculated values
|
|
361
|
+
- Formulas are preserved but not evaluated - use scripts/recalc.py to update values`,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: "skill_bundled_dcoa",
|
|
365
|
+
name: "doc-coauthoring",
|
|
366
|
+
description: "Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content.",
|
|
367
|
+
content: `---
|
|
368
|
+
name: doc-coauthoring
|
|
369
|
+
description: Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers.
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
# Doc Co-Authoring Workflow
|
|
373
|
+
|
|
374
|
+
This skill provides a structured workflow for guiding users through collaborative document creation. Act as an active guide, walking users through three stages: Context Gathering, Refinement & Structure, and Reader Testing.
|
|
375
|
+
|
|
376
|
+
## Stage 1: Context Gathering
|
|
377
|
+
|
|
378
|
+
**Goal:** Close the gap between what the user knows and what Claude knows.
|
|
379
|
+
|
|
380
|
+
### Initial Questions
|
|
381
|
+
1. What type of document is this?
|
|
382
|
+
2. Who's the primary audience?
|
|
383
|
+
3. What's the desired impact when someone reads this?
|
|
384
|
+
4. Is there a template or specific format to follow?
|
|
385
|
+
5. Any other constraints or context to know?
|
|
386
|
+
|
|
387
|
+
Then encourage the user to dump all relevant context.
|
|
388
|
+
|
|
389
|
+
## Stage 2: Refinement & Structure
|
|
390
|
+
|
|
391
|
+
**Goal:** Build the document section by section through brainstorming, curation, and iterative refinement.
|
|
392
|
+
|
|
393
|
+
For each section:
|
|
394
|
+
1. Ask clarifying questions about what to include
|
|
395
|
+
2. Brainstorm 5-20 options
|
|
396
|
+
3. User indicates what to keep/remove/combine
|
|
397
|
+
4. Draft the section
|
|
398
|
+
5. Refine through surgical edits
|
|
399
|
+
|
|
400
|
+
## Stage 3: Reader Testing
|
|
401
|
+
|
|
402
|
+
**Goal:** Test the document with a fresh Claude (no context) to verify it works for readers.
|
|
403
|
+
|
|
404
|
+
1. Predict reader questions
|
|
405
|
+
2. Test with sub-agent or fresh conversation
|
|
406
|
+
3. Run additional checks for ambiguity and contradictions
|
|
407
|
+
4. Fix any gaps found`,
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
id: "skill_bundled_jnb0",
|
|
411
|
+
name: "jupyter-notebook",
|
|
412
|
+
description: "Use this skill when the user wants to create, edit, read, or work with Jupyter notebooks (.ipynb files). Covers creating notebooks with code cells, markdown cells, and outputs, as well as running and managing notebook workflows.",
|
|
413
|
+
content: `---
|
|
414
|
+
name: jupyter-notebook
|
|
415
|
+
description: Use this skill when the user wants to create, edit, read, or work with Jupyter notebooks (.ipynb files). Covers creating notebooks with code cells, markdown cells, and outputs, as well as running and managing notebook workflows.
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
# Jupyter Notebook Skill
|
|
419
|
+
|
|
420
|
+
## Overview
|
|
421
|
+
|
|
422
|
+
Jupyter notebooks (.ipynb) are JSON documents containing an ordered list of cells (code, markdown, or raw) with optional outputs. They are widely used for data analysis, machine learning, scientific computing, and documentation.
|
|
423
|
+
|
|
424
|
+
## Reading Notebooks
|
|
425
|
+
|
|
426
|
+
${BT3}python
|
|
427
|
+
import json
|
|
428
|
+
|
|
429
|
+
with open("notebook.ipynb", "r") as f:
|
|
430
|
+
nb = json.load(f)
|
|
431
|
+
|
|
432
|
+
for cell in nb["cells"]:
|
|
433
|
+
print(f"Type: {cell['cell_type']}")
|
|
434
|
+
print("".join(cell["source"]))
|
|
435
|
+
print("---")
|
|
436
|
+
${BT3}
|
|
437
|
+
|
|
438
|
+
Or use nbformat:
|
|
439
|
+
|
|
440
|
+
${BT3}python
|
|
441
|
+
import nbformat
|
|
442
|
+
|
|
443
|
+
nb = nbformat.read("notebook.ipynb", as_version=4)
|
|
444
|
+
for cell in nb.cells:
|
|
445
|
+
print(cell.cell_type, ":", "".join(cell.source)[:80])
|
|
446
|
+
${BT3}
|
|
447
|
+
|
|
448
|
+
## Creating Notebooks
|
|
449
|
+
|
|
450
|
+
${BT3}python
|
|
451
|
+
import nbformat
|
|
452
|
+
|
|
453
|
+
nb = nbformat.v4.new_notebook()
|
|
454
|
+
nb.cells = [
|
|
455
|
+
nbformat.v4.new_markdown_cell("# My Notebook\\n\\nThis is an example."),
|
|
456
|
+
nbformat.v4.new_code_cell("import pandas as pd\\nprint('Hello')"),
|
|
457
|
+
nbformat.v4.new_markdown_cell("## Results\\n\\nAnalysis below."),
|
|
458
|
+
nbformat.v4.new_code_cell("df = pd.DataFrame({'x': [1,2,3]})\\ndf"),
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
with open("output.ipynb", "w") as f:
|
|
462
|
+
nbformat.write(nb, f)
|
|
463
|
+
${BT3}
|
|
464
|
+
|
|
465
|
+
## Running Notebooks
|
|
466
|
+
|
|
467
|
+
${BT3}bash
|
|
468
|
+
# Execute notebook and save output in place
|
|
469
|
+
jupyter nbconvert --to notebook --execute notebook.ipynb --output notebook.ipynb
|
|
470
|
+
|
|
471
|
+
# Execute and convert to HTML
|
|
472
|
+
jupyter nbconvert --to html --execute notebook.ipynb
|
|
473
|
+
|
|
474
|
+
# Execute and convert to PDF
|
|
475
|
+
jupyter nbconvert --to pdf --execute notebook.ipynb
|
|
476
|
+
|
|
477
|
+
# Run with papermill (parameterized execution)
|
|
478
|
+
papermill input.ipynb output.ipynb -p param_name value
|
|
479
|
+
${BT3}
|
|
480
|
+
|
|
481
|
+
## Editing Notebooks
|
|
482
|
+
|
|
483
|
+
${BT3}python
|
|
484
|
+
import nbformat
|
|
485
|
+
|
|
486
|
+
nb = nbformat.read("notebook.ipynb", as_version=4)
|
|
487
|
+
|
|
488
|
+
# Add a cell
|
|
489
|
+
nb.cells.append(nbformat.v4.new_code_cell("print('new cell')"))
|
|
490
|
+
|
|
491
|
+
# Modify a cell
|
|
492
|
+
nb.cells[0].source = "# Updated Title"
|
|
493
|
+
|
|
494
|
+
# Delete a cell
|
|
495
|
+
del nb.cells[2]
|
|
496
|
+
|
|
497
|
+
# Insert at position
|
|
498
|
+
nb.cells.insert(1, nbformat.v4.new_markdown_cell("## Inserted Section"))
|
|
499
|
+
|
|
500
|
+
nbformat.write(nb, open("notebook.ipynb", "w"))
|
|
501
|
+
${BT3}
|
|
502
|
+
|
|
503
|
+
## Converting Formats
|
|
504
|
+
|
|
505
|
+
${BT3}bash
|
|
506
|
+
# To Python script
|
|
507
|
+
jupyter nbconvert --to script notebook.ipynb
|
|
508
|
+
|
|
509
|
+
# To Markdown
|
|
510
|
+
jupyter nbconvert --to markdown notebook.ipynb
|
|
511
|
+
|
|
512
|
+
# To HTML (no execution)
|
|
513
|
+
jupyter nbconvert --to html notebook.ipynb
|
|
514
|
+
|
|
515
|
+
# From Python script to notebook
|
|
516
|
+
jupytext --to notebook script.py
|
|
517
|
+
${BT3}
|
|
518
|
+
|
|
519
|
+
## Best Practices
|
|
520
|
+
|
|
521
|
+
- Use markdown cells to document your analysis flow
|
|
522
|
+
- Keep code cells focused on one logical step
|
|
523
|
+
- Clear outputs before committing to version control
|
|
524
|
+
- Use requirements.txt or environment.yml for dependencies
|
|
525
|
+
- Consider using jupytext for version-control-friendly notebook formats
|
|
526
|
+
|
|
527
|
+
## Dependencies
|
|
528
|
+
|
|
529
|
+
- **nbformat**: Reading/writing notebooks programmatically
|
|
530
|
+
- **jupyter**: Core notebook infrastructure
|
|
531
|
+
- **nbconvert**: Converting between formats
|
|
532
|
+
- **papermill**: Parameterized notebook execution
|
|
533
|
+
- **jupytext**: Notebook/script synchronization`,
|
|
534
|
+
},
|
|
535
|
+
];
|
|
@@ -296,7 +296,7 @@ async function createFreshTaskWorktrees(input) {
|
|
|
296
296
|
branchName,
|
|
297
297
|
startPoint: baseCommit,
|
|
298
298
|
});
|
|
299
|
-
await
|
|
299
|
+
await copyGitignoredEntriesToWorktree({
|
|
300
300
|
sourceRepoPath,
|
|
301
301
|
worktreePath: taskRepoPath,
|
|
302
302
|
excludedEntries: getManagedIgnoredEntryExcludes(relativePath),
|
|
@@ -328,7 +328,7 @@ async function createFollowupTaskWorktrees(input) {
|
|
|
328
328
|
branchName,
|
|
329
329
|
startPoint: predecessorHead,
|
|
330
330
|
});
|
|
331
|
-
await
|
|
331
|
+
await copyGitignoredEntriesToWorktree({
|
|
332
332
|
sourceRepoPath,
|
|
333
333
|
worktreePath: taskRepoPath,
|
|
334
334
|
excludedEntries: getManagedIgnoredEntryExcludes(relativePath),
|
|
@@ -359,7 +359,7 @@ async function ensureExistingTaskWorktrees(input) {
|
|
|
359
359
|
branchName: input.gitState.branch_name,
|
|
360
360
|
startPoint: repo.base_commit,
|
|
361
361
|
});
|
|
362
|
-
await
|
|
362
|
+
await copyGitignoredEntriesToWorktree({
|
|
363
363
|
sourceRepoPath,
|
|
364
364
|
worktreePath: taskRepoPath,
|
|
365
365
|
excludedEntries: getManagedIgnoredEntryExcludes(relativePath),
|
|
@@ -419,11 +419,16 @@ async function getTopLevelGitignoredEntries(repoPath, excludedEntries = new Set(
|
|
|
419
419
|
}
|
|
420
420
|
return entries;
|
|
421
421
|
}
|
|
422
|
-
async function
|
|
422
|
+
async function copyGitignoredEntriesToWorktree(input) {
|
|
423
|
+
const sourceRepoPath = (0, node_path_1.resolve)(input.sourceRepoPath);
|
|
424
|
+
const worktreePath = (0, node_path_1.resolve)(input.worktreePath);
|
|
425
|
+
if (sourceRepoPath === worktreePath) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
423
428
|
const entries = await getTopLevelGitignoredEntries(input.sourceRepoPath, input.excludedEntries);
|
|
424
429
|
for (const entry of entries) {
|
|
425
|
-
const sourcePath = (0, node_path_1.
|
|
426
|
-
const targetPath = (0, node_path_1.
|
|
430
|
+
const sourcePath = (0, node_path_1.resolve)(sourceRepoPath, entry);
|
|
431
|
+
const targetPath = (0, node_path_1.resolve)(worktreePath, entry);
|
|
427
432
|
try {
|
|
428
433
|
if (sourcePath === targetPath)
|
|
429
434
|
continue;
|
|
@@ -434,14 +439,7 @@ async function symlinkOrCopyGitignoredFiles(input) {
|
|
|
434
439
|
const sourceStat = await (0, promises_1.lstat)(sourcePath).catch(() => null);
|
|
435
440
|
if (!sourceStat)
|
|
436
441
|
continue;
|
|
437
|
-
|
|
438
|
-
// Large directories → symlink
|
|
439
|
-
await (0, promises_1.symlink)(sourcePath, targetPath);
|
|
440
|
-
}
|
|
441
|
-
else if (sourceStat.isFile()) {
|
|
442
|
-
// Small files → copy (avoids shared-mutation for .env etc.)
|
|
443
|
-
await (0, promises_1.copyFile)(sourcePath, targetPath);
|
|
444
|
-
}
|
|
442
|
+
await copyIgnoredEntry(sourcePath, targetPath);
|
|
445
443
|
}
|
|
446
444
|
catch {
|
|
447
445
|
// Silently continue on individual failures (race conditions, permissions, etc.)
|
|
@@ -449,27 +447,33 @@ async function symlinkOrCopyGitignoredFiles(input) {
|
|
|
449
447
|
}
|
|
450
448
|
}
|
|
451
449
|
async function syncGitignoredFilesBackToSource(input) {
|
|
452
|
-
const
|
|
450
|
+
const sourceRepoPath = (0, node_path_1.resolve)(input.sourceRepoPath);
|
|
451
|
+
const worktreePath = (0, node_path_1.resolve)(input.worktreePath);
|
|
452
|
+
if (sourceRepoPath === worktreePath) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const [sourceEntries, worktreeEntries] = await Promise.all([
|
|
456
|
+
getTopLevelGitignoredEntries(input.sourceRepoPath, input.excludedEntries),
|
|
457
|
+
getTopLevelGitignoredEntries(input.worktreePath, input.excludedEntries),
|
|
458
|
+
]);
|
|
459
|
+
const entries = [...new Set([...sourceEntries, ...worktreeEntries])];
|
|
453
460
|
for (const entry of entries) {
|
|
454
|
-
const worktreeEntryPath = (0, node_path_1.
|
|
455
|
-
const sourceEntryPath = (0, node_path_1.
|
|
461
|
+
const worktreeEntryPath = (0, node_path_1.resolve)(worktreePath, entry);
|
|
462
|
+
const sourceEntryPath = (0, node_path_1.resolve)(sourceRepoPath, entry);
|
|
456
463
|
try {
|
|
457
464
|
if (worktreeEntryPath === sourceEntryPath)
|
|
458
465
|
continue;
|
|
459
466
|
const worktreeStat = await (0, promises_1.lstat)(worktreeEntryPath).catch(() => null);
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
467
|
+
const sourceStat = await (0, promises_1.lstat)(sourceEntryPath).catch(() => null);
|
|
468
|
+
if (!worktreeStat) {
|
|
469
|
+
if (sourceStat) {
|
|
470
|
+
await (0, promises_1.rm)(sourceEntryPath, { recursive: true, force: true });
|
|
471
|
+
}
|
|
464
472
|
continue;
|
|
465
|
-
if (worktreeStat.isFile()) {
|
|
466
|
-
// Agent replaced copied file — copy it back to source
|
|
467
|
-
await (0, promises_1.copyFile)(worktreeEntryPath, sourceEntryPath);
|
|
468
473
|
}
|
|
469
|
-
|
|
470
|
-
// Agent replaced symlink with real directory — copy back to source
|
|
474
|
+
if (worktreeStat.isFile() || worktreeStat.isDirectory() || worktreeStat.isSymbolicLink()) {
|
|
471
475
|
await (0, promises_1.rm)(sourceEntryPath, { recursive: true, force: true });
|
|
472
|
-
await (
|
|
476
|
+
await copyIgnoredEntry(worktreeEntryPath, sourceEntryPath);
|
|
473
477
|
}
|
|
474
478
|
}
|
|
475
479
|
catch {
|
|
@@ -477,6 +481,14 @@ async function syncGitignoredFilesBackToSource(input) {
|
|
|
477
481
|
}
|
|
478
482
|
}
|
|
479
483
|
}
|
|
484
|
+
async function copyIgnoredEntry(sourcePath, targetPath) {
|
|
485
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(targetPath), { recursive: true });
|
|
486
|
+
await (0, promises_1.cp)(sourcePath, targetPath, {
|
|
487
|
+
recursive: true,
|
|
488
|
+
force: true,
|
|
489
|
+
dereference: false,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
480
492
|
async function discoverFlatRepoPaths(paths) {
|
|
481
493
|
const rootRepo = await isGitRepo(paths.workspaceDir);
|
|
482
494
|
if (!rootRepo) {
|
|
@@ -184,8 +184,8 @@ function buildWorkerPrompt(input) {
|
|
|
184
184
|
"If you changed code, submit at least one runnable validation command for the task window.",
|
|
185
185
|
`For richer testing UIs with multiple processes and panels, use \`submit-testing-config\`:`,
|
|
186
186
|
submitTestingConfigCommand,
|
|
187
|
-
`The config JSON has: \`processes\` (array of {name, command, cwd?,
|
|
188
|
-
`Example: \`--config '{"processes":[{"name":"server","command":"npm run dev","cwd":"code/my-app","
|
|
187
|
+
`The config JSON has: \`processes\` (array of {name, command, cwd?, ready_pattern?}) and \`panels\` (array of panel objects). Panel types: \`web-preview\` ({type, title, process, path?, devices?}), \`api-tester\` ({type, title, process, endpoints: [{method, path, description?, body?, headers?}]}), \`terminal\` ({type, title, command, cwd?}), \`log-viewer\` ({type, title, process}). Optional: \`setup\` (array of setup commands), \`layout\` ("tabs"|"grid").`,
|
|
188
|
+
`Example: \`--config '{"processes":[{"name":"server","command":"npm run dev","cwd":"code/my-app","ready_pattern":"ready on"}],"panels":[{"type":"web-preview","title":"App","process":"server"}]}'\``,
|
|
189
189
|
`Fallback: for simple single-command cases, use:`,
|
|
190
190
|
"Include the exact run directory for each command (for example: `--cwd \"code/default/my-app\"`):",
|
|
191
191
|
submitTestsCommand,
|