@prismer/runtime 2.0.8 → 2.2.63
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/CHANGELOG.md +4004 -0
- package/README.md +34 -12
- package/apc/skills/FIELD-DICTIONARY.md +111 -0
- package/apc/skills/bug-reproduce/SKILL.md +150 -0
- package/apc/skills/bug-reproduce/skill.json +96 -0
- package/apc/skills/code-review/SKILL.md +198 -0
- package/apc/skills/code-review/skill.json +124 -0
- package/apc/skills/design-review/SKILL.md +122 -0
- package/apc/skills/design-review/skill.json +88 -0
- package/apc/skills/doc-sync/SKILL.md +168 -0
- package/apc/skills/doc-sync/skill.json +81 -0
- package/apc/skills/env-doctor/SKILL.md +194 -0
- package/apc/skills/env-doctor/skill.json +209 -0
- package/apc/skills/git-ops/SKILL.md +189 -0
- package/apc/skills/git-ops/skill.json +94 -0
- package/apc/skills/impact-trace/SKILL.md +168 -0
- package/apc/skills/impact-trace/skill.json +104 -0
- package/apc/skills/observability/SKILL.md +195 -0
- package/apc/skills/observability/skill.json +116 -0
- package/apc/skills/release-db-config-sync/SKILL.md +186 -0
- package/apc/skills/release-db-config-sync/skill.json +109 -0
- package/apc/skills/release-ota-promote/SKILL.md +195 -0
- package/apc/skills/release-ota-promote/skill.json +176 -0
- package/apc/skills/release-preflight/SKILL.md +174 -0
- package/apc/skills/release-preflight/skill.json +175 -0
- package/apc/skills/release-rollback/SKILL.md +214 -0
- package/apc/skills/release-rollback/skill.json +230 -0
- package/apc/skills/release-tag/SKILL.md +194 -0
- package/apc/skills/release-tag/skill.json +94 -0
- package/apc/skills/releasing-prod/SKILL.md +49 -0
- package/apc/skills/releasing-test/SKILL.md +144 -0
- package/apc/skills/sdk-release/SKILL.md +200 -0
- package/apc/skills/spec-intake/SKILL.md +169 -0
- package/apc/skills/spec-intake/skill.json +93 -0
- package/apc/skills/test-result-feedback/SKILL.md +239 -0
- package/apc/skills/test-result-feedback/skill.json +193 -0
- package/apc/skills/test-runner/SKILL.md +169 -0
- package/apc/skills/test-runner/skill.json +103 -0
- package/apc/skills/ui-align/SKILL.md +209 -0
- package/apc/skills/ui-align/skill.json +114 -0
- package/apc/skills/ui-canvas/SKILL.md +148 -0
- package/apc/skills/ui-canvas/skill.json +127 -0
- package/built-in-skills/agent-coordination/SKILL.md +77 -38
- package/built-in-skills/agent-meta/SKILL.md +12 -0
- package/built-in-skills/assets/SKILL.md +9 -7
- package/built-in-skills/browser-use/SKILL.md +93 -0
- package/built-in-skills/canvas-design/SKILL.md +4 -3
- package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-OFL.txt +93 -0
- package/built-in-skills/canvas-design/canvas-fonts/InstrumentSerif-OFL.txt +93 -0
- package/built-in-skills/canvas-design/canvas-fonts/LICENSE-SOURCES.md +16 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +10 -5
- package/built-in-skills/claude-api/SKILL.md +2 -1
- package/built-in-skills/claude-api/python/claude-api/README.md +2 -2
- package/built-in-skills/claude-api/python/claude-api/tool-use.md +9 -5
- package/built-in-skills/claude-api/python/managed-agents/README.md +11 -1
- package/built-in-skills/claude-api/shared/error-codes.md +4 -4
- package/built-in-skills/claude-api/shared/managed-agents-client-patterns.md +4 -2
- package/built-in-skills/claude-api/shared/managed-agents-core.md +1 -2
- package/built-in-skills/claude-api/shared/managed-agents-events.md +41 -22
- package/built-in-skills/claude-api/shared/managed-agents-multiagent.md +5 -3
- package/built-in-skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +1 -1
- package/built-in-skills/claude-api/shared/managed-agents-tools.md +2 -3
- package/built-in-skills/claude-api/shared/model-migration.md +3 -3
- package/built-in-skills/claude-api/shared/models.md +1 -1
- package/built-in-skills/claude-api/typescript/claude-api/batches.md +1 -1
- package/built-in-skills/claude-api/typescript/claude-api/files-api.md +3 -1
- package/built-in-skills/claude-api/typescript/claude-api/tool-use.md +8 -2
- package/built-in-skills/claude-api/typescript/managed-agents/README.md +8 -2
- package/built-in-skills/codebase-design/DEEPENING.md +37 -0
- package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/built-in-skills/codebase-design/LICENSE +21 -0
- package/built-in-skills/codebase-design/SKILL.md +130 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/GUIDE.md +291 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE.superpowers +21 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/NOTICE.md +37 -0
- package/built-in-skills/codebase-design/references/sdlc-review/GUIDE.md +130 -0
- package/built-in-skills/codebase-design/references/sdlc-review/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/sdlc-review/NOTICE.md +17 -0
- package/built-in-skills/codebase-design/references/simplify-code/GUIDE.md +269 -0
- package/built-in-skills/codebase-design/references/simplify-code/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/simplify-code/NOTICE.md +37 -0
- package/built-in-skills/competitor-intelligence/LICENSE +21 -0
- package/built-in-skills/competitor-intelligence/NOTICE.md +6 -0
- package/built-in-skills/competitor-intelligence/SKILL.md +125 -0
- package/built-in-skills/competitor-intelligence/scripts/watch_state.py +160 -0
- package/built-in-skills/conversation-compaction/SKILL.md +117 -0
- package/built-in-skills/council-creator/SKILL.md +427 -0
- package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/SKILL.md +148 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/GUIDE.md +64 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/NOTICE.md +17 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/GUIDE.md +410 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE.superpowers +21 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/NOTICE.md +37 -0
- package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +7 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/GUIDE.md +647 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE +21 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE.hermes +21 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/PROVENANCE.md +7 -0
- package/built-in-skills/document-actions/LICENSE +21 -0
- package/built-in-skills/document-actions/NOTICE.md +21 -0
- package/built-in-skills/document-actions/SKILL.md +46 -0
- package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/built-in-skills/domain-modeling/LICENSE +21 -0
- package/built-in-skills/domain-modeling/SKILL.md +76 -0
- package/built-in-skills/evidence-citations/LICENSE +21 -0
- package/built-in-skills/evidence-citations/NOTICE.md +21 -0
- package/built-in-skills/evidence-citations/SKILL.md +46 -0
- package/built-in-skills/evidence-citations/references/citation-formats.md +68 -0
- package/built-in-skills/evidence-citations/references/grounding-rationale.md +64 -0
- package/built-in-skills/evidence-citations/scripts/sources.py +720 -0
- package/built-in-skills/frontend-design/SKILL.md +7 -0
- package/built-in-skills/frontend-design/references/claude-design/GUIDE.md +650 -0
- package/built-in-skills/frontend-design/references/claude-design/LICENSE +21 -0
- package/built-in-skills/frontend-design/references/claude-design/LICENSE.hermes +21 -0
- package/built-in-skills/frontend-design/references/claude-design/PROVENANCE.md +7 -0
- package/built-in-skills/human-approval/SKILL.md +17 -2
- package/built-in-skills/image-generate/SKILL.md +107 -301
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +310 -0
- package/built-in-skills/ingest/SKILL.md +13 -45
- package/built-in-skills/internal-comms/SKILL.md +1 -0
- package/built-in-skills/liteparse/SKILL.md +130 -110
- package/built-in-skills/mcp-builder/SKILL.md +1 -0
- package/built-in-skills/mcp-builder/reference/evaluation.md +11 -2
- package/built-in-skills/mcp-builder/reference/node_mcp_server.md +34 -5
- package/built-in-skills/mcp-builder/reference/python_mcp_server.md +6 -2
- package/built-in-skills/mcp-builder/scripts/connections.py +1 -1
- package/built-in-skills/mcp-builder/scripts/evaluation.py +52 -34
- package/built-in-skills/mcp-builder/scripts/requirements.txt +2 -2
- package/built-in-skills/meeting-actions/LICENSE +21 -0
- package/built-in-skills/meeting-actions/NOTICE.md +21 -0
- package/built-in-skills/meeting-actions/SKILL.md +48 -0
- package/built-in-skills/memory/SKILL.md +444 -55
- package/built-in-skills/memory/references/llm-wiki/GUIDE.md +468 -0
- package/built-in-skills/memory/references/llm-wiki/LICENSE +21 -0
- package/built-in-skills/memory/references/llm-wiki/NOTICE.md +4 -0
- package/built-in-skills/memory/references/llm-wiki/scripts/lint_wiki.py +84 -0
- package/built-in-skills/memory/references/llm-wiki/scripts/requirements.txt +1 -0
- package/built-in-skills/memory/references/llm-wiki/templates/SCHEMA.md +19 -0
- package/built-in-skills/memory/references/llm-wiki/templates/index.md +9 -0
- package/built-in-skills/memory/references/llm-wiki/templates/log.md +4 -0
- package/built-in-skills/memory-dream/SKILL.md +332 -0
- package/built-in-skills/memory-import/SKILL.md +51 -0
- package/built-in-skills/office-artifacts/NOTICE.md +15 -0
- package/built-in-skills/office-artifacts/SKILL.md +37 -4
- package/built-in-skills/office-artifacts/references/RESOURCE-LIMITS.md +44 -0
- package/built-in-skills/office-artifacts/references/document-generation/GUIDE.md +105 -0
- package/built-in-skills/office-artifacts/references/docx/GUIDE.md +196 -0
- package/built-in-skills/office-artifacts/references/docx/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/docx/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/docx/references/revisions-and-comments.md +88 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_comments.py +292 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_common.py +93 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_create.py +177 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_edit.py +250 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_read.py +169 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_revisions.py +149 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_template.py +70 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_validate.py +155 -0
- package/built-in-skills/office-artifacts/references/docx/tests/test_docx_skill.py +525 -0
- package/built-in-skills/office-artifacts/references/pdf/GUIDE.md +125 -0
- package/built-in-skills/office-artifacts/references/pdf/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/pdf/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/pdf/references/forms.md +99 -0
- package/built-in-skills/office-artifacts/references/pdf/references/nano-pdf-editing.md +40 -0
- package/built-in-skills/office-artifacts/references/pdf/references/ocr-extraction.md +165 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/_raster.py +87 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/extract_marker.py +95 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/extract_pymupdf.py +107 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_create.py +153 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_fill_form.py +97 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_form_layout.py +168 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_make_form.py +145 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_merge.py +50 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_meta.py +123 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_page_image.py +101 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_read.py +153 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_secure.py +71 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_split.py +86 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_stamp.py +145 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_watermark.py +51 -0
- package/built-in-skills/office-artifacts/references/pdf/tests/test_pdf_skill.py +414 -0
- package/built-in-skills/office-artifacts/references/powerpoint/GUIDE.md +220 -0
- package/built-in-skills/office-artifacts/references/powerpoint/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/powerpoint/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_create.py +214 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_edit.py +442 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_from_template.py +88 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_read.py +131 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_render.py +104 -0
- package/built-in-skills/office-artifacts/references/powerpoint/tests/test_powerpoint_skill.py +478 -0
- package/built-in-skills/office-artifacts/references/xlsx/GUIDE.md +196 -0
- package/built-in-skills/office-artifacts/references/xlsx/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/xlsx/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/xlsx/references/restructuring.md +74 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/csv_to_xlsx.py +108 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_create.py +259 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_edit.py +269 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_read.py +160 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_recalc.py +111 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_restructure.py +418 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/built-in-skills/office-artifacts/references/xlsx/tests/test_xlsx_skill.py +542 -0
- package/built-in-skills/office-artifacts/tests/test_resource_regressions.py +272 -0
- package/built-in-skills/okr/SKILL.md +154 -0
- package/built-in-skills/persona/SKILL.md +81 -0
- package/built-in-skills/persona-generator/SKILL.md +296 -0
- package/built-in-skills/pkf-svg/SKILL.md +258 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/GUIDE.md +148 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE +21 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE.hermes +21 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/PROVENANCE.md +7 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/templates/template.html +345 -0
- package/built-in-skills/pkf-writing/SKILL.md +258 -0
- package/built-in-skills/prismer-airtable/LICENSE +21 -0
- package/built-in-skills/prismer-airtable/NOTICE.md +11 -0
- package/built-in-skills/prismer-airtable/SKILL.md +248 -0
- package/built-in-skills/prismer-airtable/scripts/airtable_client.py +76 -0
- package/built-in-skills/prismer-apple-notes/LICENSE +21 -0
- package/built-in-skills/prismer-apple-notes/NOTICE.md +17 -0
- package/built-in-skills/prismer-apple-notes/SKILL.md +118 -0
- package/built-in-skills/prismer-apple-notes/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-apple-reminders/LICENSE +21 -0
- package/built-in-skills/prismer-apple-reminders/NOTICE.md +17 -0
- package/built-in-skills/prismer-apple-reminders/SKILL.md +155 -0
- package/built-in-skills/prismer-apple-reminders/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-ascii-video/LICENSE +21 -0
- package/built-in-skills/prismer-ascii-video/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-ascii-video/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-ascii-video/README.md +290 -0
- package/built-in-skills/prismer-ascii-video/SKILL.md +252 -0
- package/built-in-skills/prismer-ascii-video/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-ascii-video/references/architecture.md +807 -0
- package/built-in-skills/prismer-ascii-video/references/composition.md +900 -0
- package/built-in-skills/prismer-ascii-video/references/effects.md +1877 -0
- package/built-in-skills/prismer-ascii-video/references/inputs.md +693 -0
- package/built-in-skills/prismer-ascii-video/references/optimization.md +688 -0
- package/built-in-skills/prismer-ascii-video/references/scenes.md +1018 -0
- package/built-in-skills/prismer-ascii-video/references/shaders.md +1408 -0
- package/built-in-skills/prismer-ascii-video/references/troubleshooting.md +360 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE +21 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE.origin +21 -0
- package/built-in-skills/prismer-baoyu-infographic/PORT_NOTES.md +37 -0
- package/built-in-skills/prismer-baoyu-infographic/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-baoyu-infographic/SKILL.md +240 -0
- package/built-in-skills/prismer-baoyu-infographic/references/analysis-framework.md +182 -0
- package/built-in-skills/prismer-baoyu-infographic/references/base-prompt.md +43 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/bento-grid.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/binary-comparison.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/bridge.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/circular-flow.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/comic-strip.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/dashboard.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/dense-modules.md +72 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/funnel.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/hub-spoke.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/iceberg.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/isometric-map.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/jigsaw.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/linear-progression.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/periodic-table.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/story-mountain.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/tree-branching.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/venn-diagram.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/structured-content-template.md +244 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/aged-academia.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/bold-graphic.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/chalkboard.md +61 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/claymation.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/corporate-memphis.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/craft-handmade.md +44 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/ikea-manual.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/kawaii.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/knolling.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/lego-brick.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/morandi-journal.md +60 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/origami.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/pixel-art.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/pop-laboratory.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/subway-map.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/technical-schematic.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/ui-wireframe.md +29 -0
- package/built-in-skills/prismer-blocked-page-recovery/LICENSE +21 -0
- package/built-in-skills/prismer-blocked-page-recovery/NOTICE.md +17 -0
- package/built-in-skills/prismer-blocked-page-recovery/SKILL.md +158 -0
- package/built-in-skills/prismer-blocked-page-recovery/scripts/recover_page.py +311 -0
- package/built-in-skills/prismer-box/LICENSE +21 -0
- package/built-in-skills/prismer-box/NOTICE.md +11 -0
- package/built-in-skills/prismer-box/SKILL.md +147 -0
- package/built-in-skills/prismer-box/references/bulk-operations.md +43 -0
- package/built-in-skills/prismer-box/references/cli-guide.md +133 -0
- package/built-in-skills/prismer-box/references/content-workflows.md +86 -0
- package/built-in-skills/prismer-box/references/hubs.md +77 -0
- package/built-in-skills/prismer-box/references/oauth-setup.md +92 -0
- package/built-in-skills/prismer-box/references/rest-api.md +37 -0
- package/built-in-skills/prismer-box/references/sdk-development.md +85 -0
- package/built-in-skills/prismer-box/references/search-and-ai.md +147 -0
- package/built-in-skills/prismer-box/references/troubleshooting.md +33 -0
- package/built-in-skills/prismer-box/references/webhooks-and-events.md +43 -0
- package/built-in-skills/prismer-codebase-inspection/LICENSE +21 -0
- package/built-in-skills/prismer-codebase-inspection/NOTICE.md +17 -0
- package/built-in-skills/prismer-codebase-inspection/SKILL.md +141 -0
- package/built-in-skills/prismer-computer-use/LICENSE +21 -0
- package/built-in-skills/prismer-computer-use/NOTICE.md +17 -0
- package/built-in-skills/prismer-computer-use/SKILL.md +372 -0
- package/built-in-skills/prismer-design-md/LICENSE +21 -0
- package/built-in-skills/prismer-design-md/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-design-md/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-design-md/SKILL.md +227 -0
- package/built-in-skills/prismer-design-md/templates/starter.md +99 -0
- package/built-in-skills/prismer-email-inbox-triage/LICENSE +21 -0
- package/built-in-skills/prismer-email-inbox-triage/NOTICE.md +11 -0
- package/built-in-skills/prismer-email-inbox-triage/SKILL.md +116 -0
- package/built-in-skills/prismer-findmy/LICENSE +21 -0
- package/built-in-skills/prismer-findmy/NOTICE.md +17 -0
- package/built-in-skills/prismer-findmy/SKILL.md +150 -0
- package/built-in-skills/prismer-findmy/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-gif-search/LICENSE +21 -0
- package/built-in-skills/prismer-gif-search/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-gif-search/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-gif-search/SKILL.md +97 -0
- package/built-in-skills/prismer-gif-search/scripts/tenor.py +81 -0
- package/built-in-skills/prismer-github/LICENSE +21 -0
- package/built-in-skills/prismer-github/NOTICE.md +17 -0
- package/built-in-skills/prismer-github/SKILL.md +74 -0
- package/built-in-skills/prismer-github/references/auth.md +91 -0
- package/built-in-skills/prismer-github/references/ci-troubleshooting.md +193 -0
- package/built-in-skills/prismer-github/references/code-review.md +465 -0
- package/built-in-skills/prismer-github/references/conventional-commits.md +81 -0
- package/built-in-skills/prismer-github/references/github-api-cheatsheet.md +177 -0
- package/built-in-skills/prismer-github/references/issue-to-pr.md +74 -0
- package/built-in-skills/prismer-github/references/issues.md +336 -0
- package/built-in-skills/prismer-github/references/pr-workflow.md +346 -0
- package/built-in-skills/prismer-github/references/repo-management.md +484 -0
- package/built-in-skills/prismer-github/references/review-output-template.md +84 -0
- package/built-in-skills/prismer-github/scripts/ensure-gh.py +132 -0
- package/built-in-skills/prismer-github/scripts/gh-env.sh +25 -0
- package/built-in-skills/prismer-github/scripts/git-credential-token.py +68 -0
- package/built-in-skills/prismer-github/scripts/github-api.py +71 -0
- package/built-in-skills/prismer-github/scripts/github-context.py +28 -0
- package/built-in-skills/prismer-github/templates/bug-report.md +35 -0
- package/built-in-skills/prismer-github/templates/feature-request.md +31 -0
- package/built-in-skills/prismer-github/templates/pr-body-bugfix.md +35 -0
- package/built-in-skills/prismer-github/templates/pr-body-feature.md +33 -0
- package/built-in-skills/prismer-google-workspace/LICENSE +21 -0
- package/built-in-skills/prismer-google-workspace/NOTICE.md +11 -0
- package/built-in-skills/prismer-google-workspace/SKILL.md +369 -0
- package/built-in-skills/prismer-google-workspace/references/daily-brief.md +65 -0
- package/built-in-skills/prismer-google-workspace/references/gmail-search-syntax.md +63 -0
- package/built-in-skills/prismer-google-workspace/scripts/_hermes_home.py +17 -0
- package/built-in-skills/prismer-google-workspace/scripts/_private_state.py +39 -0
- package/built-in-skills/prismer-google-workspace/scripts/google_api.py +1339 -0
- package/built-in-skills/prismer-google-workspace/scripts/gws_bridge.py +121 -0
- package/built-in-skills/prismer-google-workspace/scripts/setup.py +563 -0
- package/built-in-skills/prismer-google-workspace/tests/test_productivity_regressions.py +214 -0
- package/built-in-skills/prismer-hermes-agent/LICENSE +21 -0
- package/built-in-skills/prismer-hermes-agent/NOTICE.md +17 -0
- package/built-in-skills/prismer-hermes-agent/SKILL.md +247 -0
- package/built-in-skills/prismer-hermes-agent/references/background-systems.md +108 -0
- package/built-in-skills/prismer-hermes-agent/references/cli-reference.md +158 -0
- package/built-in-skills/prismer-hermes-agent/references/configuration.md +96 -0
- package/built-in-skills/prismer-hermes-agent/references/contributor-guide.md +151 -0
- package/built-in-skills/prismer-hermes-agent/references/delegate-task-concurrency-diagnosis.md +47 -0
- package/built-in-skills/prismer-hermes-agent/references/desktop-plugins.md +215 -0
- package/built-in-skills/prismer-hermes-agent/references/native-mcp.md +351 -0
- package/built-in-skills/prismer-hermes-agent/references/petdex.md +82 -0
- package/built-in-skills/prismer-hermes-agent/references/portal-auth-for-third-party-apps.md +135 -0
- package/built-in-skills/prismer-hermes-agent/references/project-context-files.md +55 -0
- package/built-in-skills/prismer-hermes-agent/references/providers-and-models.md +81 -0
- package/built-in-skills/prismer-hermes-agent/references/security-privacy.md +73 -0
- package/built-in-skills/prismer-hermes-agent/references/slash-commands.md +119 -0
- package/built-in-skills/prismer-hermes-agent/references/themes.md +134 -0
- package/built-in-skills/prismer-hermes-agent/references/troubleshooting.md +87 -0
- package/built-in-skills/prismer-hermes-agent/references/tui-widgets.md +144 -0
- package/built-in-skills/prismer-hermes-agent/references/webhooks.md +219 -0
- package/built-in-skills/prismer-hermes-agent/references/windows-quirks.md +64 -0
- package/built-in-skills/prismer-hermes-agent/templates/clock.mjs +51 -0
- package/built-in-skills/prismer-hermes-agent/templates/plugin.js +97 -0
- package/built-in-skills/prismer-hermes-agent/templates/skin.yaml +49 -0
- package/built-in-skills/prismer-himalaya/LICENSE +21 -0
- package/built-in-skills/prismer-himalaya/NOTICE.md +11 -0
- package/built-in-skills/prismer-himalaya/SKILL.md +340 -0
- package/built-in-skills/prismer-himalaya/references/configuration.md +227 -0
- package/built-in-skills/prismer-himalaya/references/message-composition.md +206 -0
- package/built-in-skills/prismer-himalaya/scripts/compose_draft.py +48 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +27 -7
- package/built-in-skills/prismer-imessage/LICENSE +21 -0
- package/built-in-skills/prismer-imessage/NOTICE.md +17 -0
- package/built-in-skills/prismer-imessage/SKILL.md +128 -0
- package/built-in-skills/prismer-imessage/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-manim-video/LICENSE +21 -0
- package/built-in-skills/prismer-manim-video/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-manim-video/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-manim-video/README.md +23 -0
- package/built-in-skills/prismer-manim-video/SKILL.md +279 -0
- package/built-in-skills/prismer-manim-video/references/animation-design-thinking.md +161 -0
- package/built-in-skills/prismer-manim-video/references/animations.md +282 -0
- package/built-in-skills/prismer-manim-video/references/camera-and-3d.md +135 -0
- package/built-in-skills/prismer-manim-video/references/decorations.md +202 -0
- package/built-in-skills/prismer-manim-video/references/equations.md +216 -0
- package/built-in-skills/prismer-manim-video/references/graphs-and-data.md +163 -0
- package/built-in-skills/prismer-manim-video/references/mobjects.md +333 -0
- package/built-in-skills/prismer-manim-video/references/paper-explainer.md +255 -0
- package/built-in-skills/prismer-manim-video/references/production-quality.md +190 -0
- package/built-in-skills/prismer-manim-video/references/rendering.md +187 -0
- package/built-in-skills/prismer-manim-video/references/scene-planning.md +118 -0
- package/built-in-skills/prismer-manim-video/references/troubleshooting.md +135 -0
- package/built-in-skills/prismer-manim-video/references/updaters-and-trackers.md +260 -0
- package/built-in-skills/prismer-manim-video/references/visual-design.md +124 -0
- package/built-in-skills/prismer-manim-video/scripts/setup.sh +15 -0
- package/built-in-skills/prismer-maps/LICENSE +21 -0
- package/built-in-skills/prismer-maps/NOTICE.md +11 -0
- package/built-in-skills/prismer-maps/SKILL.md +240 -0
- package/built-in-skills/prismer-maps/scripts/maps_client.py +1324 -0
- package/built-in-skills/prismer-node-inspect-debugger/LICENSE +21 -0
- package/built-in-skills/prismer-node-inspect-debugger/NOTICE.md +17 -0
- package/built-in-skills/prismer-node-inspect-debugger/SKILL.md +347 -0
- package/built-in-skills/prismer-notion/LICENSE +21 -0
- package/built-in-skills/prismer-notion/NOTICE.md +11 -0
- package/built-in-skills/prismer-notion/SKILL.md +495 -0
- package/built-in-skills/prismer-notion/references/block-types.md +112 -0
- package/built-in-skills/prismer-obsidian/LICENSE +21 -0
- package/built-in-skills/prismer-obsidian/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-obsidian/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-obsidian/SKILL.md +80 -0
- package/built-in-skills/prismer-obsidian/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-obsidian/scripts/write_note.py +84 -0
- package/built-in-skills/prismer-p5js/LICENSE +21 -0
- package/built-in-skills/prismer-p5js/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-p5js/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-p5js/README.md +64 -0
- package/built-in-skills/prismer-p5js/SKILL.md +574 -0
- package/built-in-skills/prismer-p5js/references/animation.md +439 -0
- package/built-in-skills/prismer-p5js/references/color-systems.md +355 -0
- package/built-in-skills/prismer-p5js/references/core-api.md +410 -0
- package/built-in-skills/prismer-p5js/references/export-pipeline.md +534 -0
- package/built-in-skills/prismer-p5js/references/interaction.md +398 -0
- package/built-in-skills/prismer-p5js/references/shapes-and-geometry.md +300 -0
- package/built-in-skills/prismer-p5js/references/troubleshooting.md +532 -0
- package/built-in-skills/prismer-p5js/references/typography.md +302 -0
- package/built-in-skills/prismer-p5js/references/visual-effects.md +905 -0
- package/built-in-skills/prismer-p5js/references/webgl-and-3d.md +423 -0
- package/built-in-skills/prismer-p5js/scripts/export-frames.js +91 -0
- package/built-in-skills/prismer-p5js/scripts/render.sh +113 -0
- package/built-in-skills/prismer-p5js/scripts/serve.sh +25 -0
- package/built-in-skills/prismer-p5js/scripts/setup.sh +87 -0
- package/built-in-skills/prismer-p5js/templates/viewer.html +401 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE +21 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE.origin +21 -0
- package/built-in-skills/prismer-popular-web-designs/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-popular-web-designs/SKILL.md +218 -0
- package/built-in-skills/prismer-popular-web-designs/templates/airbnb.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/airtable.md +102 -0
- package/built-in-skills/prismer-popular-web-designs/templates/apple.md +326 -0
- package/built-in-skills/prismer-popular-web-designs/templates/bmw.md +193 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cal.md +272 -0
- package/built-in-skills/prismer-popular-web-designs/templates/claude.md +325 -0
- package/built-in-skills/prismer-popular-web-designs/templates/clay.md +317 -0
- package/built-in-skills/prismer-popular-web-designs/templates/clickhouse.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cohere.md +279 -0
- package/built-in-skills/prismer-popular-web-designs/templates/coinbase.md +142 -0
- package/built-in-skills/prismer-popular-web-designs/templates/composio.md +320 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cursor.md +322 -0
- package/built-in-skills/prismer-popular-web-designs/templates/elevenlabs.md +278 -0
- package/built-in-skills/prismer-popular-web-designs/templates/expo.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/figma.md +233 -0
- package/built-in-skills/prismer-popular-web-designs/templates/framer.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/hashicorp.md +291 -0
- package/built-in-skills/prismer-popular-web-designs/templates/ibm.md +345 -0
- package/built-in-skills/prismer-popular-web-designs/templates/intercom.md +159 -0
- package/built-in-skills/prismer-popular-web-designs/templates/kraken.md +138 -0
- package/built-in-skills/prismer-popular-web-designs/templates/linear.app.md +380 -0
- package/built-in-skills/prismer-popular-web-designs/templates/lovable.md +311 -0
- package/built-in-skills/prismer-popular-web-designs/templates/minimax.md +270 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mintlify.md +339 -0
- package/built-in-skills/prismer-popular-web-designs/templates/miro.md +121 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mistral.ai.md +274 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mongodb.md +279 -0
- package/built-in-skills/prismer-popular-web-designs/templates/notion.md +322 -0
- package/built-in-skills/prismer-popular-web-designs/templates/nvidia.md +306 -0
- package/built-in-skills/prismer-popular-web-designs/templates/ollama.md +280 -0
- package/built-in-skills/prismer-popular-web-designs/templates/opencode.ai.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/pinterest.md +243 -0
- package/built-in-skills/prismer-popular-web-designs/templates/posthog.md +269 -0
- package/built-in-skills/prismer-popular-web-designs/templates/raycast.md +281 -0
- package/built-in-skills/prismer-popular-web-designs/templates/replicate.md +274 -0
- package/built-in-skills/prismer-popular-web-designs/templates/resend.md +316 -0
- package/built-in-skills/prismer-popular-web-designs/templates/revolut.md +198 -0
- package/built-in-skills/prismer-popular-web-designs/templates/runwayml.md +257 -0
- package/built-in-skills/prismer-popular-web-designs/templates/sanity.md +370 -0
- package/built-in-skills/prismer-popular-web-designs/templates/sentry.md +275 -0
- package/built-in-skills/prismer-popular-web-designs/templates/spacex.md +207 -0
- package/built-in-skills/prismer-popular-web-designs/templates/spotify.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/stripe.md +335 -0
- package/built-in-skills/prismer-popular-web-designs/templates/supabase.md +268 -0
- package/built-in-skills/prismer-popular-web-designs/templates/superhuman.md +265 -0
- package/built-in-skills/prismer-popular-web-designs/templates/together.ai.md +276 -0
- package/built-in-skills/prismer-popular-web-designs/templates/uber.md +308 -0
- package/built-in-skills/prismer-popular-web-designs/templates/vercel.md +323 -0
- package/built-in-skills/prismer-popular-web-designs/templates/voltagent.md +336 -0
- package/built-in-skills/prismer-popular-web-designs/templates/warp.md +266 -0
- package/built-in-skills/prismer-popular-web-designs/templates/webflow.md +105 -0
- package/built-in-skills/prismer-popular-web-designs/templates/wise.md +186 -0
- package/built-in-skills/prismer-popular-web-designs/templates/x.ai.md +270 -0
- package/built-in-skills/prismer-popular-web-designs/templates/zapier.md +341 -0
- package/built-in-skills/prismer-product-price-monitor/LICENSE +21 -0
- package/built-in-skills/prismer-product-price-monitor/NOTICE.md +11 -0
- package/built-in-skills/prismer-product-price-monitor/SKILL.md +97 -0
- package/built-in-skills/prismer-product-price-monitor/scripts/watch_state.py +116 -0
- package/built-in-skills/prismer-python-debugpy/LICENSE +21 -0
- package/built-in-skills/prismer-python-debugpy/NOTICE.md +17 -0
- package/built-in-skills/prismer-python-debugpy/SKILL.md +377 -0
- package/built-in-skills/prismer-python-debugpy/scripts/dap_client.py +68 -0
- package/built-in-skills/prismer-songsee/LICENSE +21 -0
- package/built-in-skills/prismer-songsee/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-songsee/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-songsee/SKILL.md +91 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE +21 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/SKILL.md +317 -0
- package/built-in-skills/prismer-spike/LICENSE +21 -0
- package/built-in-skills/prismer-spike/LICENSE.gsd +21 -0
- package/built-in-skills/prismer-spike/NOTICE.md +17 -0
- package/built-in-skills/prismer-spike/SKILL.md +212 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/LICENSE +21 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/NOTICE.md +11 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/SKILL.md +156 -0
- package/built-in-skills/prismer-xurl/LICENSE +21 -0
- package/built-in-skills/prismer-xurl/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-xurl/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-xurl/SKILL.md +444 -0
- package/built-in-skills/prismer-xurl/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-youtube-content/LICENSE +21 -0
- package/built-in-skills/prismer-youtube-content/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-youtube-content/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-youtube-content/SKILL.md +86 -0
- package/built-in-skills/prismer-youtube-content/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-youtube-content/references/output-formats.md +56 -0
- package/built-in-skills/prismer-youtube-content/scripts/fetch_transcript.py +146 -0
- package/built-in-skills/proactivity/SKILL.md +84 -0
- package/built-in-skills/remotion/SKILL.md +431 -0
- package/built-in-skills/research-arxiv/LICENSE +21 -0
- package/built-in-skills/research-arxiv/NOTICE.md +4 -0
- package/built-in-skills/research-arxiv/SKILL.md +263 -0
- package/built-in-skills/research-arxiv/scripts/search_arxiv.py +111 -0
- package/built-in-skills/role-builder/SKILL.md +209 -0
- package/built-in-skills/role-builder/scripts/author-role.mjs +350 -0
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +121 -0
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +304 -0
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +269 -0
- package/built-in-skills/skill-creator/LICENSE.prismer +21 -0
- package/built-in-skills/skill-creator/NOTICE.md +18 -0
- package/built-in-skills/skill-creator/SKILL.md +182 -421
- package/built-in-skills/skill-creator/eval-viewer/generate_review.py +20 -31
- package/built-in-skills/skill-creator/eval-viewer/viewer.html +35 -23
- package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
- package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/GUIDE.md +220 -0
- package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/LICENSE +21 -0
- package/built-in-skills/skill-creator/references/skill-authoring/GUIDE.md +134 -0
- package/built-in-skills/{skill-authoring/skill.json → skill-creator/references/skill-authoring/draft-contract.json} +3 -3
- package/built-in-skills/skill-creator/references/skill-builder/GUIDE.md +167 -0
- package/built-in-skills/skill-creator/references/skill-builder/scripts/ingest.mjs +93 -0
- package/built-in-skills/skill-creator/scripts/aggregate_benchmark.py +3 -2
- package/built-in-skills/skill-creator/scripts/import-library.mjs +498 -0
- package/built-in-skills/skill-creator/scripts/improve_description.py +14 -16
- package/built-in-skills/skill-creator/scripts/package_skill.py +16 -9
- package/built-in-skills/skill-creator/scripts/quick_validate.py +22 -5
- package/built-in-skills/skill-creator/scripts/run_eval.py +63 -144
- package/built-in-skills/skill-creator/scripts/run_loop.py +24 -16
- package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
- package/built-in-skills/slack-gif-creator/core/gif_builder.py +13 -2
- package/built-in-skills/slack-gif-creator/core/validators.py +17 -7
- package/built-in-skills/tasks/SKILL.md +39 -24
- package/built-in-skills/tdd/LICENSE +21 -0
- package/built-in-skills/tdd/SKILL.md +117 -0
- package/built-in-skills/tdd/mocking.md +59 -0
- package/built-in-skills/tdd/refactoring.md +10 -0
- package/built-in-skills/tdd/references/test-driven-development/GUIDE.md +356 -0
- package/built-in-skills/tdd/references/test-driven-development/LICENSE +21 -0
- package/built-in-skills/tdd/references/test-driven-development/LICENSE.superpowers +21 -0
- package/built-in-skills/tdd/references/test-driven-development/NOTICE.md +37 -0
- package/built-in-skills/tdd/tests.md +61 -0
- package/built-in-skills/team/SKILL.md +3 -2
- package/built-in-skills/web-artifacts-builder/SKILL.md +4 -3
- package/built-in-skills/web-artifacts-builder/scripts/bundle-artifact.sh +9 -7
- package/built-in-skills/web-artifacts-builder/scripts/init-artifact.sh +28 -55
- package/built-in-skills/webapp-qa/LICENSE +21 -0
- package/built-in-skills/webapp-qa/NOTICE.md +37 -0
- package/built-in-skills/webapp-qa/SKILL.md +41 -0
- package/built-in-skills/webapp-qa/references/dogfood/GUIDE.md +161 -0
- package/built-in-skills/webapp-qa/references/issue-taxonomy.md +109 -0
- package/built-in-skills/webapp-qa/templates/dogfood-report-template.md +86 -0
- package/built-in-skills/webapp-testing/SKILL.md +10 -2
- package/built-in-skills/webapp-testing/examples/console_logging.py +10 -4
- package/built-in-skills/webapp-testing/examples/element_discovery.py +11 -4
- package/built-in-skills/webapp-testing/examples/static_html_automation.py +14 -9
- package/built-in-skills/webapp-testing/scripts/with_server.py +34 -10
- package/built-in-skills/wechat-pay/SKILL.md +59 -0
- package/built-in-skills/weekly-review/LICENSE +21 -0
- package/built-in-skills/weekly-review/NOTICE.md +21 -0
- package/built-in-skills/weekly-review/SKILL.md +49 -0
- package/components/eaas-pi-components.manifest.json +37 -0
- package/dist/cli.cjs +75799 -20210
- package/dist/cli.js +75900 -20248
- package/dist/index.cjs +76159 -20082
- package/dist/index.d.cts +4766 -766
- package/dist/index.d.ts +4766 -766
- package/dist/index.js +76040 -19960
- package/package.json +42 -6
- package/plugins/memory/prismer/__init__.py +1215 -0
- package/plugins/memory/prismer/plugin.yaml +8 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +257 -0
- package/plugins/tools/prismer-recall/__init__.py +282 -0
- package/plugins/tools/prismer-recall/plugin.yaml +15 -0
- package/built-in-skills/memory-curation/SKILL.md +0 -135
- package/built-in-skills/skill-authoring/SKILL.md +0 -124
- package/built-in-skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
|
@@ -0,0 +1,720 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Citation ledger for grounded answers and documents.
|
|
3
|
+
|
|
4
|
+
Owns the ``url -> [n]`` mapping used by the ``grounded-citations`` skill.
|
|
5
|
+
Ids are assigned at retrieval time and never change, so a draft's ``[3]``
|
|
6
|
+
always resolves to the same page. The model only ever emits integers the
|
|
7
|
+
ledger handed it, which is what makes the citations verifiable.
|
|
8
|
+
|
|
9
|
+
Subcommands
|
|
10
|
+
-----------
|
|
11
|
+
reset start a clean ledger
|
|
12
|
+
add URL [URL ...] register source(s), print their ids
|
|
13
|
+
ingest FILE|- register every url found in JSON tool output
|
|
14
|
+
quote ID --text T --from FILE|- attach verbatim supporting evidence to a source
|
|
15
|
+
list show the ledger
|
|
16
|
+
render render a Sources block
|
|
17
|
+
verify DRAFT check a draft's citations against the ledger
|
|
18
|
+
|
|
19
|
+
Fact-checking is evidence-backed citation: ``quote`` only accepts text that
|
|
20
|
+
literally appears in the fetched page text you point it at, ``verify
|
|
21
|
+
--evidence`` requires every cited source to carry at least one such quote, and
|
|
22
|
+
``render --style evidence`` prints the quotes under each source so the reader
|
|
23
|
+
can check the chain themselves. Claims from model knowledge are declared with
|
|
24
|
+
an ``[unverified]`` marker rather than silently blended in.
|
|
25
|
+
|
|
26
|
+
Ledger path resolution (first wins):
|
|
27
|
+
--ledger PATH
|
|
28
|
+
$PRISMER_SCRATCH_DIR/citations.json (dispatch-isolated scratch only)
|
|
29
|
+
Otherwise fail rather than share a profile-global mutable ledger.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import argparse
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import sys
|
|
39
|
+
import tempfile
|
|
40
|
+
import time
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
from typing import Any, Iterable
|
|
43
|
+
|
|
44
|
+
SCHEMA_VERSION = 1
|
|
45
|
+
|
|
46
|
+
# A citation marker in prose: [12]. Markdown links ([text](url)) and
|
|
47
|
+
# reference-style labels are excluded by requiring digits only and no
|
|
48
|
+
# following "(" or ":".
|
|
49
|
+
_CITE_RE = re.compile(r"\[(\d{1,4})\](?![(:])")
|
|
50
|
+
_SOURCES_HEADER_RE = re.compile(r"^\s*(?:#{1,6}\s*)?(?:\*\*)?sources:?(?:\*\*)?\s*$", re.IGNORECASE)
|
|
51
|
+
_SOURCE_LINE_RE = re.compile(r"^ {0,3}\[(\d{1,4})\][ \t]+(https?://[^\s\"'<>)\]}]+)(?:[ \t]+.*)?$")
|
|
52
|
+
_URL_IN_TEXT_RE = re.compile(r"https?://[^\s\"'<>)\]}]+")
|
|
53
|
+
_FENCE_RE = re.compile(r"^ {0,3}(`{3,}|~{3,})(.*)$")
|
|
54
|
+
_CJK_RE = re.compile(r"[\u3400-\u9fff\u3040-\u30ff\uac00-\ud7af]")
|
|
55
|
+
# Explicit declaration that a claim comes from model knowledge, not a source.
|
|
56
|
+
_UNVERIFIED_RE = re.compile(r"\[unverified\]", re.IGNORECASE)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# Ledger I/O
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def resolve_ledger_path(explicit: str | None = None) -> Path:
|
|
65
|
+
if explicit:
|
|
66
|
+
return Path(explicit).expanduser()
|
|
67
|
+
scratch = os.environ.get("PRISMER_SCRATCH_DIR", "").strip()
|
|
68
|
+
if scratch and Path(scratch).is_absolute():
|
|
69
|
+
return Path(scratch) / "citations.json"
|
|
70
|
+
raise SystemExit("Pass --ledger with a task-specific path; no shared ledger default is allowed")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def normalize_url(url: str) -> str:
|
|
74
|
+
"""Canonicalize a URL for ledger identity.
|
|
75
|
+
|
|
76
|
+
Strips the fragment and a trailing slash so ``/page``, ``/page/`` and
|
|
77
|
+
``/page#section`` are one source. Query strings are significant and are
|
|
78
|
+
kept — they usually select different content.
|
|
79
|
+
"""
|
|
80
|
+
u = (url or "").strip()
|
|
81
|
+
if "#" in u:
|
|
82
|
+
u = u.split("#", 1)[0]
|
|
83
|
+
stripped = u.rstrip("/")
|
|
84
|
+
return stripped or u
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def load_ledger(path: Path) -> dict[str, Any]:
|
|
88
|
+
if not path.exists():
|
|
89
|
+
return {"version": SCHEMA_VERSION, "sources": []}
|
|
90
|
+
try:
|
|
91
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
92
|
+
except (json.JSONDecodeError, OSError) as exc:
|
|
93
|
+
raise SystemExit(f"error: ledger at {path} is unreadable ({exc}); run `reset` to start over")
|
|
94
|
+
if not isinstance(data, dict) or not isinstance(data.get("sources"), list):
|
|
95
|
+
raise SystemExit(f"error: ledger at {path} has an unexpected shape; run `reset`")
|
|
96
|
+
return data
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def save_ledger(path: Path, data: dict[str, Any]) -> None:
|
|
100
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
tmp = path.with_suffix(path.suffix + f".tmp{os.getpid()}")
|
|
102
|
+
tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
|
103
|
+
os.replace(tmp, path)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class _LedgerLock:
|
|
107
|
+
"""Exclusive writer lock; contention times out without stealing ownership.
|
|
108
|
+
|
|
109
|
+
Parallel subagents can share one ledger via --ledger; without a lock two
|
|
110
|
+
concurrent ``add`` calls can assign the same id. A stale lock requires
|
|
111
|
+
explicit recovery after confirming no writer owns it.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, path: Path, timeout: float = 5.0) -> None:
|
|
115
|
+
self.lock_path = path.with_suffix(path.suffix + ".lock")
|
|
116
|
+
self.timeout = timeout
|
|
117
|
+
self.fd: int | None = None
|
|
118
|
+
|
|
119
|
+
def __enter__(self) -> "_LedgerLock":
|
|
120
|
+
self.lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
121
|
+
deadline = time.monotonic() + self.timeout
|
|
122
|
+
while True:
|
|
123
|
+
try:
|
|
124
|
+
self.fd = os.open(str(self.lock_path), os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
|
|
125
|
+
return self
|
|
126
|
+
except FileExistsError:
|
|
127
|
+
if time.monotonic() >= deadline:
|
|
128
|
+
raise TimeoutError(f"ledger is locked: {self.lock_path}")
|
|
129
|
+
time.sleep(0.05)
|
|
130
|
+
|
|
131
|
+
def __exit__(self, *_exc: object) -> None:
|
|
132
|
+
if self.fd is not None:
|
|
133
|
+
try:
|
|
134
|
+
owned = os.fstat(self.fd)
|
|
135
|
+
current = self.lock_path.stat(follow_symlinks=False)
|
|
136
|
+
if (owned.st_dev, owned.st_ino) == (current.st_dev, current.st_ino):
|
|
137
|
+
self.lock_path.unlink()
|
|
138
|
+
except FileNotFoundError:
|
|
139
|
+
pass
|
|
140
|
+
finally:
|
|
141
|
+
os.close(self.fd)
|
|
142
|
+
self.fd = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# Core operations
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _by_url(sources: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
|
151
|
+
return {s["url"]: s for s in sources}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def add_sources(
|
|
155
|
+
path: Path,
|
|
156
|
+
urls: Iterable[str],
|
|
157
|
+
title: str | None = None,
|
|
158
|
+
accessed: str | None = None,
|
|
159
|
+
) -> list[dict[str, Any]]:
|
|
160
|
+
"""Register urls, returning their ledger entries (existing or new)."""
|
|
161
|
+
urls = [u for u in (str(u).strip() for u in urls) if u]
|
|
162
|
+
if not urls:
|
|
163
|
+
return []
|
|
164
|
+
with _LedgerLock(path):
|
|
165
|
+
data = load_ledger(path)
|
|
166
|
+
sources = data["sources"]
|
|
167
|
+
index = _by_url(sources)
|
|
168
|
+
out: list[dict[str, Any]] = []
|
|
169
|
+
changed = False
|
|
170
|
+
for raw in urls:
|
|
171
|
+
key = normalize_url(raw)
|
|
172
|
+
existing = index.get(key)
|
|
173
|
+
if existing is not None:
|
|
174
|
+
if title and not existing.get("title"):
|
|
175
|
+
existing["title"] = title
|
|
176
|
+
changed = True
|
|
177
|
+
out.append(existing)
|
|
178
|
+
continue
|
|
179
|
+
entry = {
|
|
180
|
+
"id": len(sources) + 1,
|
|
181
|
+
"url": key,
|
|
182
|
+
"title": (title or "").strip(),
|
|
183
|
+
"accessed": accessed or time.strftime("%Y-%m-%d"),
|
|
184
|
+
}
|
|
185
|
+
sources.append(entry)
|
|
186
|
+
index[key] = entry
|
|
187
|
+
out.append(entry)
|
|
188
|
+
changed = True
|
|
189
|
+
if changed:
|
|
190
|
+
save_ledger(path, data)
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def urls_from_json(payload: Any) -> list[tuple[str, str]]:
|
|
195
|
+
"""Walk arbitrary JSON tool output collecting (url, title) pairs.
|
|
196
|
+
|
|
197
|
+
Handles web_search (``data.web[]``), web_extract (``results[]``) and any
|
|
198
|
+
other nesting, in document order, deduped.
|
|
199
|
+
"""
|
|
200
|
+
found: list[tuple[str, str]] = []
|
|
201
|
+
seen: set[str] = set()
|
|
202
|
+
|
|
203
|
+
def walk(node: Any) -> None:
|
|
204
|
+
if isinstance(node, dict):
|
|
205
|
+
url = node.get("url") or node.get("link") or node.get("source_url")
|
|
206
|
+
if isinstance(url, str) and url.startswith(("http://", "https://")):
|
|
207
|
+
key = normalize_url(url)
|
|
208
|
+
if key not in seen:
|
|
209
|
+
seen.add(key)
|
|
210
|
+
raw_title = node.get("title") or node.get("name") or ""
|
|
211
|
+
found.append((url, raw_title if isinstance(raw_title, str) else ""))
|
|
212
|
+
for value in node.values():
|
|
213
|
+
walk(value)
|
|
214
|
+
elif isinstance(node, list):
|
|
215
|
+
for item in node:
|
|
216
|
+
walk(item)
|
|
217
|
+
|
|
218
|
+
walk(payload)
|
|
219
|
+
return found
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# ---------------------------------------------------------------------------
|
|
223
|
+
# Evidence quotes (fact-checking)
|
|
224
|
+
# ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _normalize_ws(text: str) -> str:
|
|
228
|
+
"""Collapse all whitespace runs to single spaces for verbatim matching."""
|
|
229
|
+
return " ".join((text or "").split())
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# Markdown artifacts that retrieval tools inject into otherwise-identical prose.
|
|
233
|
+
# ``web_extract`` returns markdown, so the most citation-worthy sentences are
|
|
234
|
+
# exactly the ones carrying inline links and emphasis around terms:
|
|
235
|
+
# "including _[ERAP1](https://…/erap1/)_, _[IL1A](…)_, have also been…"
|
|
236
|
+
# reads identically to the page a human sees. Matching has to see through that
|
|
237
|
+
# markup, or the skill pushes the agent toward weaker evidence fragments.
|
|
238
|
+
_MD_LINK_RE = re.compile(r"\[([^\]]*)\]\((?:[^()\s]|\([^()]*\))*\)")
|
|
239
|
+
_MD_NOISE_RE = re.compile(r"[*_`~]|\\(?=[^\w\s])")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _match_key(text: str) -> str:
|
|
243
|
+
"""Canonicalize text for verbatim comparison.
|
|
244
|
+
|
|
245
|
+
Whitespace-, case-, and markdown-insensitive: inline links collapse to
|
|
246
|
+
their label, emphasis/code markers and backslash escapes are dropped. The
|
|
247
|
+
stored quote keeps whatever the caller passed, so the rendered evidence
|
|
248
|
+
block shows clean prose rather than extractor artifacts.
|
|
249
|
+
"""
|
|
250
|
+
collapsed = _MD_LINK_RE.sub(r"\1", text or "")
|
|
251
|
+
return _normalize_ws(_MD_NOISE_RE.sub("", collapsed)).casefold()
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def quote_in_evidence(quote: str, evidence: str) -> bool:
|
|
255
|
+
"""True when ``quote`` appears verbatim in the fetched ``evidence`` text,
|
|
256
|
+
ignoring whitespace, case, and markdown markup on either side."""
|
|
257
|
+
q = _match_key(quote)
|
|
258
|
+
return bool(q) and q in _match_key(evidence)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def attach_quote(path: Path, source_id: int, quote: str, evidence: str) -> dict[str, Any]:
|
|
262
|
+
"""Attach a verbatim quote to a ledger entry after checking it against
|
|
263
|
+
the evidence text. Raises SystemExit on unknown id or non-verbatim text —
|
|
264
|
+
a quote the page does not contain is exactly the fabrication this guards
|
|
265
|
+
against."""
|
|
266
|
+
quote = (quote or "").strip()
|
|
267
|
+
if len(_normalize_ws(quote).split()) < 3 and len(_CJK_RE.findall(quote)) < 6:
|
|
268
|
+
raise SystemExit("error: quote too short — use at least 3 words or 6 CJK characters")
|
|
269
|
+
if not quote_in_evidence(quote, evidence):
|
|
270
|
+
raise SystemExit(
|
|
271
|
+
"error: quote not found verbatim in the evidence text — "
|
|
272
|
+
"copy the exact wording from the fetched page, do not paraphrase"
|
|
273
|
+
)
|
|
274
|
+
with _LedgerLock(path):
|
|
275
|
+
data = load_ledger(path)
|
|
276
|
+
entry = next((s for s in data["sources"] if s["id"] == source_id), None)
|
|
277
|
+
if entry is None:
|
|
278
|
+
raise SystemExit(f"error: no source [{source_id}] in the ledger")
|
|
279
|
+
quotes = entry.setdefault("quotes", [])
|
|
280
|
+
norm = _match_key(quote)
|
|
281
|
+
if not any(_match_key(q.get("text", "")) == norm for q in quotes):
|
|
282
|
+
quotes.append({"text": quote, "added": time.strftime("%Y-%m-%d")})
|
|
283
|
+
save_ledger(path, data)
|
|
284
|
+
return entry
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def render_sources(
|
|
288
|
+
sources: list[dict[str, Any]],
|
|
289
|
+
style: str = "markdown",
|
|
290
|
+
only: set[int] | None = None,
|
|
291
|
+
) -> str:
|
|
292
|
+
picked = [s for s in sources if only is None or s["id"] in only]
|
|
293
|
+
picked.sort(key=lambda s: s["id"])
|
|
294
|
+
if not picked:
|
|
295
|
+
return ""
|
|
296
|
+
lines: list[str] = []
|
|
297
|
+
if style == "bibtex":
|
|
298
|
+
for s in picked:
|
|
299
|
+
key = f"source{s['id']}"
|
|
300
|
+
title = s.get("title") or s["url"]
|
|
301
|
+
lines.append(
|
|
302
|
+
"@misc{%s,\n title = {%s},\n howpublished = {\\url{%s}},\n note = {Accessed %s}\n}"
|
|
303
|
+
% (key, _bibtex_escape(title), _bibtex_escape(s["url"]), _bibtex_escape(s.get("accessed", "")))
|
|
304
|
+
)
|
|
305
|
+
return "\n".join(lines)
|
|
306
|
+
if style == "footnotes":
|
|
307
|
+
for s in picked:
|
|
308
|
+
title = s.get("title")
|
|
309
|
+
suffix = f" — {title}" if title else ""
|
|
310
|
+
lines.append(f"[^{s['id']}]: {s['url']}{suffix}")
|
|
311
|
+
return "\n".join(lines)
|
|
312
|
+
header = "Sources:" if style == "plain" else "## Sources"
|
|
313
|
+
lines.append(header)
|
|
314
|
+
if style != "plain":
|
|
315
|
+
lines.append("")
|
|
316
|
+
for s in picked:
|
|
317
|
+
title = s.get("title")
|
|
318
|
+
suffix = f" — {title}" if title else ""
|
|
319
|
+
lines.append(f"[{s['id']}] {s['url']}{suffix}")
|
|
320
|
+
if style == "evidence":
|
|
321
|
+
for q in s.get("quotes", []):
|
|
322
|
+
lines.append(f' > "{q.get("text", "")}"')
|
|
323
|
+
return "\n".join(lines)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# ---------------------------------------------------------------------------
|
|
327
|
+
# Verification
|
|
328
|
+
# ---------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _bibtex_escape(value: str) -> str:
|
|
332
|
+
escapes = {"\\": r"\textbackslash{}", "{": r"\{", "}": r"\}",
|
|
333
|
+
"%": r"\%", "&": r"\&", "#": r"\#", "_": r"\_",
|
|
334
|
+
"$": r"\$", "~": r"\textasciitilde{}", "^": r"\textasciicircum{}"}
|
|
335
|
+
return "".join(escapes.get(char, char) for char in str(value).replace("\n", " "))
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def _prose_lines(lines: list[str], include_indented: bool = False) -> list[tuple[int, str]]:
|
|
339
|
+
result = []
|
|
340
|
+
fence = ""
|
|
341
|
+
for index, line in enumerate(lines):
|
|
342
|
+
match = _FENCE_RE.match(line)
|
|
343
|
+
if fence:
|
|
344
|
+
if match and match[1][0] == fence[0] and len(match[1]) >= len(fence) and not match[2].strip():
|
|
345
|
+
fence = ""
|
|
346
|
+
continue
|
|
347
|
+
if match:
|
|
348
|
+
fence = match[1]
|
|
349
|
+
elif include_indented or not line.startswith((" ", "\t")):
|
|
350
|
+
result.append((index, line))
|
|
351
|
+
return result
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _sources_tail(text: str) -> tuple[int | None, dict[int, str]]:
|
|
355
|
+
"""Only an unambiguous terminal bibliography may be replaced."""
|
|
356
|
+
lines = text.splitlines()
|
|
357
|
+
headers = [i for i, line in _prose_lines(lines) if _SOURCES_HEADER_RE.match(line)]
|
|
358
|
+
if len(headers) != 1:
|
|
359
|
+
return None, {}
|
|
360
|
+
index = headers[0]
|
|
361
|
+
listed = {}
|
|
362
|
+
for line in lines[index + 1:]:
|
|
363
|
+
if not line.strip():
|
|
364
|
+
continue
|
|
365
|
+
match = _SOURCE_LINE_RE.match(line)
|
|
366
|
+
if match:
|
|
367
|
+
sid = int(match[1])
|
|
368
|
+
if sid in listed:
|
|
369
|
+
return None, {}
|
|
370
|
+
listed[sid] = match[2]
|
|
371
|
+
elif listed and line.startswith(" > "):
|
|
372
|
+
continue
|
|
373
|
+
else:
|
|
374
|
+
return None, {}
|
|
375
|
+
return (index, listed) if listed else (None, {})
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _split_draft(text: str) -> tuple[str, dict[int, str]]:
|
|
379
|
+
index, listed = _sources_tail(text)
|
|
380
|
+
lines = text.splitlines()
|
|
381
|
+
return "\n".join(line for _, line in _prose_lines(lines[:index])), listed
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _strip_sources_block(text: str) -> str:
|
|
385
|
+
"""Return the draft with its trailing Sources block removed.
|
|
386
|
+
|
|
387
|
+
Ambiguous, non-terminal and fenced headers are preserved verbatim.
|
|
388
|
+
"""
|
|
389
|
+
header_idx, _ = _sources_tail(text)
|
|
390
|
+
if header_idx is None:
|
|
391
|
+
return text
|
|
392
|
+
return "\n".join(text.splitlines()[:header_idx])
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _sentences(prose: str) -> list[str]:
|
|
396
|
+
"""Rough sentence split over prose lines, skipping headings and tables."""
|
|
397
|
+
out: list[str] = []
|
|
398
|
+
for line in prose.splitlines():
|
|
399
|
+
stripped = line.strip()
|
|
400
|
+
if not stripped or stripped.startswith("#") or stripped.startswith("|"):
|
|
401
|
+
continue
|
|
402
|
+
if stripped.startswith(">"):
|
|
403
|
+
stripped = stripped.lstrip("> ").strip()
|
|
404
|
+
for part in re.findall(r".+?(?:[.!?。!?](?:\[\d{1,4}\]|\[unverified\])*|$)", stripped):
|
|
405
|
+
part = part.strip()
|
|
406
|
+
if len(part.split()) >= 4 or len(_CJK_RE.findall(part)) >= 4:
|
|
407
|
+
out.append(part)
|
|
408
|
+
return out
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def verify_draft(
|
|
412
|
+
draft_path: Path,
|
|
413
|
+
sources: list[dict[str, Any]],
|
|
414
|
+
strict: bool = False,
|
|
415
|
+
min_coverage: float | None = None,
|
|
416
|
+
require_evidence: bool = False,
|
|
417
|
+
) -> tuple[int, list[str], list[str]]:
|
|
418
|
+
"""Return (exit_code, errors, warnings)."""
|
|
419
|
+
text = draft_path.read_text(encoding="utf-8")
|
|
420
|
+
prose, listed = _split_draft(text)
|
|
421
|
+
by_id = {s["id"]: s for s in sources}
|
|
422
|
+
|
|
423
|
+
errors: list[str] = []
|
|
424
|
+
warnings: list[str] = []
|
|
425
|
+
# Containers (quotes/lists) can define document-wide Markdown references.
|
|
426
|
+
# Reject numeric definitions conservatively, while ignoring fenced examples.
|
|
427
|
+
definitions = "\n".join(line for _, line in _prose_lines(text.splitlines(), include_indented=True))
|
|
428
|
+
if re.search(r"\[\s*\d{1,4}\s*\]\s*:", definitions):
|
|
429
|
+
errors.append("numeric reference definition can redirect a citation; use plain [n] citations and Sources entries")
|
|
430
|
+
if re.search(r"\[\^\w+\]|\\cite\w*\{", prose):
|
|
431
|
+
errors.append("unsupported citation format: verify a numeric [n] Markdown draft before export")
|
|
432
|
+
if min_coverage is not None and not 0 <= min_coverage <= 1:
|
|
433
|
+
errors.append("min-coverage must be between 0 and 1")
|
|
434
|
+
|
|
435
|
+
cited = [int(m) for m in _CITE_RE.findall(prose)]
|
|
436
|
+
cited_set = set(cited)
|
|
437
|
+
|
|
438
|
+
unknown = sorted(i for i in cited_set if i not in by_id)
|
|
439
|
+
if unknown:
|
|
440
|
+
errors.append(
|
|
441
|
+
"citations not in the ledger (hallucinated or renumbered): "
|
|
442
|
+
+ ", ".join(f"[{i}]" for i in unknown)
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
if cited_set and not listed:
|
|
446
|
+
errors.append("draft cites sources but has no `Sources:` block — run `render --cited-in`")
|
|
447
|
+
|
|
448
|
+
missing_from_block = sorted(cited_set - set(listed)) if listed else []
|
|
449
|
+
if missing_from_block:
|
|
450
|
+
errors.append(
|
|
451
|
+
"cited but absent from the Sources block: "
|
|
452
|
+
+ ", ".join(f"[{i}]" for i in missing_from_block)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
for sid, url in sorted(listed.items()):
|
|
456
|
+
entry = by_id.get(sid)
|
|
457
|
+
if entry is None:
|
|
458
|
+
errors.append(f"Sources block lists [{sid}], which is not in the ledger")
|
|
459
|
+
continue
|
|
460
|
+
if normalize_url(url) != entry["url"]:
|
|
461
|
+
errors.append(
|
|
462
|
+
f"Sources block URL for [{sid}] does not match the ledger "
|
|
463
|
+
f"(block: {url} / ledger: {entry['url']}) — re-run `render`"
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
extra_in_block = sorted(set(listed) - cited_set)
|
|
467
|
+
if extra_in_block:
|
|
468
|
+
warnings.append(
|
|
469
|
+
"listed in Sources but never cited inline: "
|
|
470
|
+
+ ", ".join(f"[{i}]" for i in extra_in_block)
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
registered_uncited = sorted(set(by_id) - cited_set)
|
|
474
|
+
if registered_uncited:
|
|
475
|
+
warnings.append(
|
|
476
|
+
"registered in the ledger but not cited in this draft: "
|
|
477
|
+
+ ", ".join(f"[{i}]" for i in registered_uncited)
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
sentences = _sentences(prose)
|
|
481
|
+
cited_sentences = [s for s in sentences if _CITE_RE.search(s)]
|
|
482
|
+
unverified_sentences = [s for s in sentences if _UNVERIFIED_RE.search(s)]
|
|
483
|
+
covered = [s for s in sentences if _CITE_RE.search(s) or _UNVERIFIED_RE.search(s)]
|
|
484
|
+
coverage = (len(covered) / len(sentences)) if sentences else 0.0
|
|
485
|
+
if min_coverage is not None and not sentences:
|
|
486
|
+
errors.append("citation coverage cannot be measured: no prose sentences")
|
|
487
|
+
if min_coverage is not None and sentences and coverage < min_coverage:
|
|
488
|
+
errors.append(
|
|
489
|
+
f"citation coverage {coverage:.0%} is below the required {min_coverage:.0%} "
|
|
490
|
+
f"({len(covered)}/{len(sentences)} sentences cited or marked [unverified])"
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
if require_evidence:
|
|
494
|
+
unevidenced = sorted(
|
|
495
|
+
i for i in cited_set if i in by_id and not by_id[i].get("quotes")
|
|
496
|
+
)
|
|
497
|
+
if unevidenced:
|
|
498
|
+
errors.append(
|
|
499
|
+
"cited sources carry no verbatim evidence quote (run `quote` with the "
|
|
500
|
+
"fetched page text): " + ", ".join(f"[{i}]" for i in unevidenced)
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
over_cited = [s for s in sentences if len(_CITE_RE.findall(s)) > 3]
|
|
504
|
+
if over_cited:
|
|
505
|
+
warnings.append(f"{len(over_cited)} sentence(s) carry more than 3 citations")
|
|
506
|
+
|
|
507
|
+
code = 1 if errors else (1 if (strict and warnings) else 0)
|
|
508
|
+
quoted = sum(1 for s in sources if s.get("quotes"))
|
|
509
|
+
stats = (
|
|
510
|
+
f"{len(sentences)} prose sentence(s), {len(covered)} with declared provenance "
|
|
511
|
+
f"({coverage:.0%}) — {len(cited_sentences)} cited, "
|
|
512
|
+
f"{len(unverified_sentences)} marked [unverified] (a sentence may be both); "
|
|
513
|
+
f"{len(cited_set)} distinct source(s) cited, "
|
|
514
|
+
f"{len(by_id)} in ledger ({quoted} with evidence quotes)"
|
|
515
|
+
)
|
|
516
|
+
warnings.insert(0, f"stats: {stats}")
|
|
517
|
+
return code, errors, warnings
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
# ---------------------------------------------------------------------------
|
|
521
|
+
# CLI
|
|
522
|
+
# ---------------------------------------------------------------------------
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def _parse_only(spec: str | None) -> set[int] | None:
|
|
526
|
+
if not spec:
|
|
527
|
+
return None
|
|
528
|
+
out: set[int] = set()
|
|
529
|
+
for chunk in spec.replace(" ", "").split(","):
|
|
530
|
+
if not chunk:
|
|
531
|
+
continue
|
|
532
|
+
if "-" in chunk:
|
|
533
|
+
lo, _, hi = chunk.partition("-")
|
|
534
|
+
out.update(range(int(lo), int(hi) + 1))
|
|
535
|
+
else:
|
|
536
|
+
out.add(int(chunk))
|
|
537
|
+
return out
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def main(argv: list[str] | None = None) -> int:
|
|
541
|
+
parser = argparse.ArgumentParser(
|
|
542
|
+
prog="sources.py", description="Citation ledger for grounded answers and documents."
|
|
543
|
+
)
|
|
544
|
+
parser.add_argument("--ledger", help="ledger file path (overrides env / default)")
|
|
545
|
+
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
546
|
+
|
|
547
|
+
sub.add_parser("reset", help="start a clean ledger")
|
|
548
|
+
|
|
549
|
+
p_add = sub.add_parser("add", help="register source url(s), print their ids")
|
|
550
|
+
p_add.add_argument("urls", nargs="+")
|
|
551
|
+
p_add.add_argument("--title", help="title for the source (single-url calls)")
|
|
552
|
+
p_add.add_argument("--accessed", help="access date (default: today)")
|
|
553
|
+
p_add.add_argument("--json", action="store_true", help="emit JSON instead of ids")
|
|
554
|
+
|
|
555
|
+
p_ing = sub.add_parser("ingest", help="register every url in JSON tool output")
|
|
556
|
+
p_ing.add_argument("file", help="JSON file, or - for stdin")
|
|
557
|
+
|
|
558
|
+
p_q = sub.add_parser("quote", help="attach verbatim supporting evidence to a source")
|
|
559
|
+
p_q.add_argument("id", type=int, help="ledger id of the source the quote supports")
|
|
560
|
+
p_q.add_argument("--text", required=True, help="the exact quote, copied from the page")
|
|
561
|
+
p_q.add_argument(
|
|
562
|
+
"--from",
|
|
563
|
+
dest="evidence",
|
|
564
|
+
required=True,
|
|
565
|
+
help="file with the fetched page text (or - for stdin) the quote must appear in",
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
p_list = sub.add_parser("list", help="show the ledger")
|
|
569
|
+
p_list.add_argument("--json", action="store_true")
|
|
570
|
+
|
|
571
|
+
p_render = sub.add_parser("render", help="render a Sources block")
|
|
572
|
+
p_render.add_argument(
|
|
573
|
+
"--style", default="markdown", choices=["markdown", "plain", "footnotes", "bibtex", "evidence"]
|
|
574
|
+
)
|
|
575
|
+
p_render.add_argument("--only", help="ids to include, e.g. 1,3,5-7")
|
|
576
|
+
p_render.add_argument("--cited-in", help="include only ids cited in this draft file")
|
|
577
|
+
p_render.add_argument(
|
|
578
|
+
"--replace-in",
|
|
579
|
+
help="rewrite this draft's Sources block in place (implies --cited-in on it)",
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
p_ver = sub.add_parser("verify", help="check a draft's citations against the ledger")
|
|
583
|
+
p_ver.add_argument("draft")
|
|
584
|
+
p_ver.add_argument("--strict", action="store_true", help="treat warnings as failures")
|
|
585
|
+
p_ver.add_argument("--min-coverage", type=float, help="required cited-sentence share, e.g. 0.5")
|
|
586
|
+
p_ver.add_argument(
|
|
587
|
+
"--evidence",
|
|
588
|
+
action="store_true",
|
|
589
|
+
help="require every cited source to carry at least one verbatim quote",
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
args = parser.parse_args(argv)
|
|
593
|
+
path = resolve_ledger_path(args.ledger)
|
|
594
|
+
|
|
595
|
+
if args.cmd == "reset":
|
|
596
|
+
with _LedgerLock(path):
|
|
597
|
+
save_ledger(path, {"version": SCHEMA_VERSION, "sources": []})
|
|
598
|
+
print(f"ledger reset: {path}")
|
|
599
|
+
return 0
|
|
600
|
+
|
|
601
|
+
if args.cmd == "add":
|
|
602
|
+
title = args.title if len(args.urls) == 1 else None
|
|
603
|
+
entries = add_sources(path, args.urls, title=title, accessed=args.accessed)
|
|
604
|
+
if args.json:
|
|
605
|
+
print(json.dumps(entries, indent=2, ensure_ascii=False))
|
|
606
|
+
else:
|
|
607
|
+
for e in entries:
|
|
608
|
+
print(f"[{e['id']}] {e['url']}")
|
|
609
|
+
return 0
|
|
610
|
+
|
|
611
|
+
if args.cmd == "ingest":
|
|
612
|
+
raw = sys.stdin.read() if args.file == "-" else Path(args.file).read_text(encoding="utf-8")
|
|
613
|
+
try:
|
|
614
|
+
payload = json.loads(raw)
|
|
615
|
+
except json.JSONDecodeError as exc:
|
|
616
|
+
print(f"error: input is not valid JSON ({exc})", file=sys.stderr)
|
|
617
|
+
return 2
|
|
618
|
+
pairs = urls_from_json(payload)
|
|
619
|
+
if not pairs:
|
|
620
|
+
print("no urls found in input", file=sys.stderr)
|
|
621
|
+
return 1
|
|
622
|
+
for url, title in pairs:
|
|
623
|
+
entry = add_sources(path, [url], title=title or None)[0]
|
|
624
|
+
print(f"[{entry['id']}] {entry['url']}")
|
|
625
|
+
return 0
|
|
626
|
+
|
|
627
|
+
if args.cmd == "quote":
|
|
628
|
+
raw = (
|
|
629
|
+
sys.stdin.read()
|
|
630
|
+
if args.evidence == "-"
|
|
631
|
+
else Path(args.evidence).read_text(encoding="utf-8")
|
|
632
|
+
)
|
|
633
|
+
entry = attach_quote(path, args.id, args.text, raw)
|
|
634
|
+
print(f"[{entry['id']}] evidence attached ({len(entry.get('quotes', []))} quote(s))")
|
|
635
|
+
return 0
|
|
636
|
+
|
|
637
|
+
data = load_ledger(path)
|
|
638
|
+
sources = sorted(data["sources"], key=lambda s: s["id"])
|
|
639
|
+
|
|
640
|
+
if args.cmd == "list":
|
|
641
|
+
if args.json:
|
|
642
|
+
print(json.dumps(sources, indent=2, ensure_ascii=False))
|
|
643
|
+
elif not sources:
|
|
644
|
+
print(f"ledger is empty: {path}")
|
|
645
|
+
else:
|
|
646
|
+
for s in sources:
|
|
647
|
+
title = f" {s['title']}" if s.get("title") else ""
|
|
648
|
+
nq = len(s.get("quotes", []))
|
|
649
|
+
mark = f" ({nq} quote{'s' if nq != 1 else ''})" if nq else ""
|
|
650
|
+
print(f"[{s['id']}] {s['url']}{title}{mark}")
|
|
651
|
+
return 0
|
|
652
|
+
|
|
653
|
+
if args.cmd == "render":
|
|
654
|
+
only = _parse_only(args.only)
|
|
655
|
+
if args.replace_in:
|
|
656
|
+
target = Path(args.replace_in)
|
|
657
|
+
if args.style not in {"markdown", "plain", "evidence"}:
|
|
658
|
+
parser.error("--replace-in requires a numeric Markdown Sources style; export other formats separately")
|
|
659
|
+
with _LedgerLock(target):
|
|
660
|
+
original = target.read_text(encoding="utf-8")
|
|
661
|
+
prose, _ = _split_draft(original)
|
|
662
|
+
cited = {int(m) for m in _CITE_RE.findall(prose)}
|
|
663
|
+
selected = cited if only is None else (only & cited)
|
|
664
|
+
current_sources = sorted(load_ledger(path)["sources"], key=lambda s: s["id"])
|
|
665
|
+
block = render_sources(current_sources, style=args.style, only=selected)
|
|
666
|
+
if not block:
|
|
667
|
+
print("no sources to render", file=sys.stderr)
|
|
668
|
+
return 1
|
|
669
|
+
body = _strip_sources_block(original)
|
|
670
|
+
if any(_SOURCES_HEADER_RE.match(line) for _, line in _prose_lines(body.splitlines())):
|
|
671
|
+
parser.error("ambiguous or non-terminal Sources section; draft left unchanged")
|
|
672
|
+
temporary = None
|
|
673
|
+
try:
|
|
674
|
+
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", dir=target.parent, delete=False) as handle:
|
|
675
|
+
temporary = Path(handle.name)
|
|
676
|
+
handle.write(body.rstrip("\n") + "\n\n" + block + "\n")
|
|
677
|
+
temporary.chmod(target.stat().st_mode & 0o777)
|
|
678
|
+
os.replace(temporary, target)
|
|
679
|
+
finally:
|
|
680
|
+
if temporary is not None:
|
|
681
|
+
temporary.unlink(missing_ok=True)
|
|
682
|
+
print(f"Sources block rewritten in {target}")
|
|
683
|
+
return 0
|
|
684
|
+
if args.cited_in:
|
|
685
|
+
draft = Path(args.cited_in).read_text(encoding="utf-8")
|
|
686
|
+
prose, _ = _split_draft(draft)
|
|
687
|
+
cited = {int(m) for m in _CITE_RE.findall(prose)}
|
|
688
|
+
only = cited if only is None else (only & cited)
|
|
689
|
+
block = render_sources(sources, style=args.style, only=only)
|
|
690
|
+
if not block:
|
|
691
|
+
print("no sources to render", file=sys.stderr)
|
|
692
|
+
return 1
|
|
693
|
+
print(block)
|
|
694
|
+
return 0
|
|
695
|
+
|
|
696
|
+
if args.cmd == "verify":
|
|
697
|
+
draft_path = Path(args.draft)
|
|
698
|
+
if not draft_path.is_file():
|
|
699
|
+
print(f"error: no such draft: {draft_path}", file=sys.stderr)
|
|
700
|
+
return 2
|
|
701
|
+
code, errors, warnings = verify_draft(
|
|
702
|
+
draft_path,
|
|
703
|
+
sources,
|
|
704
|
+
strict=args.strict,
|
|
705
|
+
min_coverage=args.min_coverage,
|
|
706
|
+
require_evidence=args.evidence,
|
|
707
|
+
)
|
|
708
|
+
for w in warnings:
|
|
709
|
+
prefix = "info" if w.startswith("stats: ") else "warn"
|
|
710
|
+
print(f"{prefix}: {w}")
|
|
711
|
+
for e in errors:
|
|
712
|
+
print(f"FAIL: {e}", file=sys.stderr)
|
|
713
|
+
print("citations OK" if code == 0 else "verification failed")
|
|
714
|
+
return code
|
|
715
|
+
|
|
716
|
+
return 2
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
if __name__ == "__main__":
|
|
720
|
+
sys.exit(main())
|