@rfxlamia/skillkit 1.0.0 → 1.2.0
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/agents/agents/creative-copywriter.md +212 -0
- package/agents/agents/dario-amodei.md +135 -0
- package/agents/agents/doc-simplifier.md +63 -0
- package/agents/agents/kotlin-pro.md +433 -0
- package/agents/agents/red-team.md +136 -0
- package/agents/agents/sam-altman.md +121 -0
- package/agents/agents/seo-manager.md +184 -0
- package/package.json +7 -2
- package/skills/quick-spec/tests/__pycache__/test_skill.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skillkit/.claude/settings.local.json +7 -0
- package/skills/skillkit/scripts/__pycache__/decision_helper.cpython-314.pyc +0 -0
- package/skills/skillkit/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/skills/skillkit/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
- package/skills/skillkit/scripts/__pycache__/test_generator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-312.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-314.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-312.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-314.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-312.pyc +0 -0
- package/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-314.pyc +0 -0
- package/skills/skillkit-help/SKILL.md +81 -0
- package/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
- package/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skillkit-help/template/SKILL.md +52 -0
- package/skills/skills/adversarial-review/SKILL.md +219 -0
- package/skills/skills/baby-education/SKILL.md +260 -0
- package/skills/skills/baby-education/references/advanced-techniques.md +323 -0
- package/skills/skills/baby-education/references/transformations.md +345 -0
- package/skills/skills/been-there-done-that/SKILL.md +455 -0
- package/skills/skills/been-there-done-that/references/analysis-patterns.md +162 -0
- package/skills/skills/been-there-done-that/references/git-commands.md +132 -0
- package/skills/skills/been-there-done-that/references/tree-insertion-logic.md +145 -0
- package/skills/skills/coolhunter/SKILL.md +270 -0
- package/skills/skills/coolhunter/assets/elicitation-methods.csv +51 -0
- package/skills/skills/coolhunter/knowledge/elicitation-methods.md +312 -0
- package/skills/skills/coolhunter/references/workflow-execution.md +238 -0
- package/skills/skills/coolhunter/workflow-plan-coolhunter.md +232 -0
- package/skills/skills/creative-copywriting/SKILL.md +324 -0
- package/skills/skills/creative-copywriting/databases/README.md +60 -0
- package/skills/skills/creative-copywriting/databases/carousel-structures.csv +16 -0
- package/skills/skills/creative-copywriting/databases/emotional-arcs.csv +11 -0
- package/skills/skills/creative-copywriting/databases/hook-formulas.csv +51 -0
- package/skills/skills/creative-copywriting/databases/power-words.csv +201 -0
- package/skills/skills/creative-copywriting/databases/psychological-triggers.csv +21 -0
- package/skills/skills/creative-copywriting/databases/read-more-patterns.csv +26 -0
- package/skills/skills/creative-copywriting/databases/swipe-triggers.csv +31 -0
- package/skills/skills/creative-copywriting/references/carousel-psychology.md +223 -0
- package/skills/skills/creative-copywriting/references/hook-anatomy.md +169 -0
- package/skills/skills/creative-copywriting/references/power-word-science.md +134 -0
- package/skills/skills/creative-copywriting/references/storytelling-frameworks.md +157 -0
- package/skills/skills/diverse-content-gen/SKILL.md +201 -0
- package/skills/skills/diverse-content-gen/references/advanced-techniques.md +320 -0
- package/skills/skills/diverse-content-gen/references/research-findings.md +379 -0
- package/skills/skills/diverse-content-gen/references/task-workflows.md +241 -0
- package/skills/skills/diverse-content-gen/references/tool-integration.md +419 -0
- package/skills/skills/diverse-content-gen/references/troubleshooting.md +426 -0
- package/skills/skills/diverse-content-gen/references/vs-core-technique.md +240 -0
- package/skills/skills/framework-critical-thinking/SKILL.md +220 -0
- package/skills/skills/framework-critical-thinking/references/bias_detector.md +375 -0
- package/skills/skills/framework-critical-thinking/references/fallback_handler.md +239 -0
- package/skills/skills/framework-critical-thinking/references/memory_curator.md +161 -0
- package/skills/skills/framework-critical-thinking/references/metacognitive_monitor.md +297 -0
- package/skills/skills/framework-critical-thinking/references/producer_critic_orchestrator.md +333 -0
- package/skills/skills/framework-critical-thinking/references/reasoning_router.md +235 -0
- package/skills/skills/framework-critical-thinking/references/reasoning_validator.md +97 -0
- package/skills/skills/framework-critical-thinking/references/reflection_trigger.md +78 -0
- package/skills/skills/framework-critical-thinking/references/self_verification.md +388 -0
- package/skills/skills/framework-critical-thinking/references/uncertainty_quantifier.md +207 -0
- package/skills/skills/framework-initiative/SKILL.md +231 -0
- package/skills/skills/framework-initiative/references/examples.md +150 -0
- package/skills/skills/framework-initiative/references/impact-analysis.md +157 -0
- package/skills/skills/framework-initiative/references/intent-patterns.md +145 -0
- package/skills/skills/framework-initiative/references/star-framework.md +165 -0
- package/skills/skills/humanize-docs/SKILL.md +203 -0
- package/skills/skills/humanize-docs/references/advanced-techniques.md +13 -0
- package/skills/skills/humanize-docs/references/core-transformations.md +368 -0
- package/skills/skills/humanize-docs/references/detection-patterns.md +400 -0
- package/skills/skills/humanize-docs/references/examples-gallery.md +374 -0
- package/skills/skills/imagine/SKILL.md +190 -0
- package/skills/skills/imagine/references/artstyle-corporate-memphis.md +625 -0
- package/skills/skills/imagine/references/artstyle-crewdson-hyperrealism.md +295 -0
- package/skills/skills/imagine/references/artstyle-iphone-social-media.md +426 -0
- package/skills/skills/imagine/references/artstyle-sciencesaru.md +276 -0
- package/skills/skills/pre-deploy-checklist/README.md +26 -0
- package/skills/skills/pre-deploy-checklist/SKILL.md +153 -0
- package/skills/skills/pre-deploy-checklist/references/checklist-categories.md +174 -0
- package/skills/skills/pre-deploy-checklist/references/domain-prompts.md +216 -0
- package/skills/skills/prompt-engineering/SKILL.md +209 -0
- package/skills/skills/prompt-engineering/references/advanced-combinations.md +444 -0
- package/skills/skills/prompt-engineering/references/chain-of-thought.md +140 -0
- package/skills/skills/prompt-engineering/references/decision_matrix.md +220 -0
- package/skills/skills/prompt-engineering/references/few-shot.md +346 -0
- package/skills/skills/prompt-engineering/references/json-format.md +270 -0
- package/skills/skills/prompt-engineering/references/natural-language.md +420 -0
- package/skills/skills/prompt-engineering/references/pitfalls.md +365 -0
- package/skills/skills/prompt-engineering/references/prompt-chaining.md +498 -0
- package/skills/skills/prompt-engineering/references/react.md +108 -0
- package/skills/skills/prompt-engineering/references/self-consistency.md +322 -0
- package/skills/skills/prompt-engineering/references/tree-of-thoughts.md +386 -0
- package/skills/skills/prompt-engineering/references/xml-format.md +220 -0
- package/skills/skills/prompt-engineering/references/yaml-format.md +488 -0
- package/skills/skills/prompt-engineering/references/zero-shot.md +74 -0
- package/skills/skills/quick-spec/SKILL.md +280 -0
- package/skills/skills/quick-spec/assets/tech-spec-template.md +74 -0
- package/skills/skills/quick-spec/references/step-01-understand.md +189 -0
- package/skills/skills/quick-spec/references/step-02-investigate.md +144 -0
- package/skills/skills/quick-spec/references/step-03-generate.md +128 -0
- package/skills/skills/quick-spec/references/step-04-review.md +173 -0
- package/skills/skills/quick-spec/tests/__pycache__/test_skill.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skills/quick-spec/tests/test_scenarios.md +83 -0
- package/skills/skills/quick-spec/tests/test_skill.py +136 -0
- package/skills/skills/readme-expert/SKILL.md +538 -0
- package/skills/skills/readme-expert/knowledge/INDEX.md +192 -0
- package/skills/skills/readme-expert/knowledge/application/quality-standards.md +470 -0
- package/skills/skills/readme-expert/knowledge/application/script-executor.md +604 -0
- package/skills/skills/readme-expert/knowledge/application/template-library.md +822 -0
- package/skills/skills/readme-expert/knowledge/foundation/codebase-scanner.md +361 -0
- package/skills/skills/readme-expert/knowledge/foundation/validation-checklist.md +481 -0
- package/skills/skills/red-teaming/SKILL.md +321 -0
- package/skills/skills/red-teaming/references/ai-llm-redteam.md +517 -0
- package/skills/skills/red-teaming/references/attack-techniques.md +410 -0
- package/skills/skills/red-teaming/references/cybersecurity-redteam.md +383 -0
- package/skills/skills/red-teaming/references/tools-frameworks.md +446 -0
- package/skills/skills/releasing/.skillkit-mode +1 -0
- package/skills/skills/releasing/SKILL.md +225 -0
- package/skills/skills/releasing/references/version-detection.md +108 -0
- package/skills/skills/screenwriter/SKILL.md +273 -0
- package/skills/skills/screenwriter/references/advanced-techniques.md +216 -0
- package/skills/skills/screenwriter/references/pipeline-integration.md +266 -0
- package/skills/skills/skillkit/.claude/settings.local.json +7 -0
- package/skills/skills/skillkit/.claude-plugin/plugin.json +27 -0
- package/skills/skills/skillkit/CHANGELOG.md +484 -0
- package/skills/skills/skillkit/SKILL.md +511 -0
- package/skills/skills/skillkit/commands/skillkit.md +6 -0
- package/skills/skills/skillkit/commands/validate-plan.md +6 -0
- package/skills/skills/skillkit/commands/verify.md +6 -0
- package/skills/skills/skillkit/knowledge/INDEX.md +352 -0
- package/skills/skills/skillkit/knowledge/application/09-case-studies.md +257 -0
- package/skills/skills/skillkit/knowledge/application/10-technical-architecture.md +324 -0
- package/skills/skills/skillkit/knowledge/application/11-adoption-strategy.md +267 -0
- package/skills/skills/skillkit/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skills/skillkit/knowledge/application/13-competitive-landscape.md +198 -0
- package/skills/skills/skillkit/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skills/skillkit/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skills/skillkit/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skills/skillkit/knowledge/foundation/04-hybrid-patterns.md +308 -0
- package/skills/skills/skillkit/knowledge/foundation/05-token-economics.md +275 -0
- package/skills/skills/skillkit/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skills/skillkit/knowledge/foundation/07-security-concerns.md +322 -0
- package/skills/skills/skillkit/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skills/skillkit/knowledge/plugin-guide.md +614 -0
- package/skills/skills/skillkit/knowledge/tools/14-validation-tools-guide.md +150 -0
- package/skills/skills/skillkit/knowledge/tools/15-cost-tools-guide.md +157 -0
- package/skills/skills/skillkit/knowledge/tools/16-security-tools-guide.md +122 -0
- package/skills/skills/skillkit/knowledge/tools/17-pattern-tools-guide.md +161 -0
- package/skills/skills/skillkit/knowledge/tools/18-decision-helper-guide.md +243 -0
- package/skills/skills/skillkit/knowledge/tools/19-test-generator-guide.md +275 -0
- package/skills/skills/skillkit/knowledge/tools/20-split-skill-guide.md +149 -0
- package/skills/skills/skillkit/knowledge/tools/21-quality-scorer-guide.md +226 -0
- package/skills/skills/skillkit/knowledge/tools/22-migration-helper-guide.md +356 -0
- package/skills/skills/skillkit/knowledge/tools/23-subagent-creation-guide.md +448 -0
- package/skills/skills/skillkit/knowledge/tools/24-behavioral-testing-guide.md +122 -0
- package/skills/skills/skillkit/references/proposal-generation.md +982 -0
- package/skills/skills/skillkit/references/rationalization-catalog.md +75 -0
- package/skills/skills/skillkit/references/research-methodology.md +661 -0
- package/skills/skills/skillkit/references/section-2-full-creation-workflow.md +452 -0
- package/skills/skills/skillkit/references/section-3-validation-workflow-existing-skill.md +63 -0
- package/skills/skills/skillkit/references/section-4-decision-workflow-skills-vs-subagents.md +64 -0
- package/skills/skills/skillkit/references/section-5-migration-workflow-doc-to-skill.md +58 -0
- package/skills/skills/skillkit/references/section-6-subagent-creation-workflow.md +499 -0
- package/skills/skills/skillkit/references/section-7-knowledge-reference-map.md +72 -0
- package/skills/skills/skillkit/scripts/__pycache__/decision_helper.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/__pycache__/test_generator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/skills/skills/skillkit/scripts/decision_helper.py +799 -0
- package/skills/skills/skillkit/scripts/init_skill.py +400 -0
- package/skills/skills/skillkit/scripts/init_subagent.py +231 -0
- package/skills/skills/skillkit/scripts/migration_helper.py +669 -0
- package/skills/skills/skillkit/scripts/package_skill.py +211 -0
- package/skills/skills/skillkit/scripts/pattern_detector.py +381 -0
- package/skills/skills/skillkit/scripts/pattern_detector_new.py +382 -0
- package/skills/skills/skillkit/scripts/pressure_tester.py +157 -0
- package/skills/skills/skillkit/scripts/quality_scorer.py +999 -0
- package/skills/skills/skillkit/scripts/quick_validate.py +100 -0
- package/skills/skills/skillkit/scripts/security_scanner.py +474 -0
- package/skills/skills/skillkit/scripts/split_skill.py +540 -0
- package/skills/skills/skillkit/scripts/test_generator.py +695 -0
- package/skills/skills/skillkit/scripts/token_estimator.py +493 -0
- package/skills/skills/skillkit/scripts/utils/__init__.py +49 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/budget_tracker.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/output_formatter.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-312.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/__pycache__/reference_validator.cpython-314.pyc +0 -0
- package/skills/skills/skillkit/scripts/utils/budget_tracker.py +388 -0
- package/skills/skills/skillkit/scripts/utils/output_formatter.py +263 -0
- package/skills/skills/skillkit/scripts/utils/reference_validator.py +401 -0
- package/skills/skills/skillkit/scripts/validate_skill.py +594 -0
- package/skills/skills/skillkit/tests/test_behavioral.py +39 -0
- package/skills/skills/skillkit/tests/test_scenarios.md +83 -0
- package/skills/skills/skillkit/tests/test_skill.py +136 -0
- package/skills/skills/skillkit-help/SKILL.md +81 -0
- package/skills/skills/skillkit-help/knowledge/application/09-case-studies.md +257 -0
- package/skills/skills/skillkit-help/knowledge/application/12-testing-and-validation.md +276 -0
- package/skills/skills/skillkit-help/knowledge/foundation/01-why-skills-exist.md +246 -0
- package/skills/skills/skillkit-help/knowledge/foundation/02-skills-vs-subagents-comparison.md +312 -0
- package/skills/skills/skillkit-help/knowledge/foundation/03-skills-vs-subagents-decision-tree.md +346 -0
- package/skills/skills/skillkit-help/knowledge/foundation/06-platform-constraints.md +237 -0
- package/skills/skills/skillkit-help/knowledge/foundation/08-when-not-to-use-skills.md +270 -0
- package/skills/skills/skillkit-help/template/SKILL.md +52 -0
- package/skills/skills/social-media-seo/SKILL.md +278 -0
- package/skills/skills/social-media-seo/databases/caption-styles.csv +31 -0
- package/skills/skills/social-media-seo/databases/engagement-tactics.csv +16 -0
- package/skills/skills/social-media-seo/databases/hashtag-strategies.csv +21 -0
- package/skills/skills/social-media-seo/databases/hook-formulas.csv +26 -0
- package/skills/skills/social-media-seo/databases/keyword-clusters.csv +11 -0
- package/skills/skills/social-media-seo/databases/thread-structures.csv +26 -0
- package/skills/skills/social-media-seo/databases/viral-patterns.csv +21 -0
- package/skills/skills/social-media-seo/references/analytics-guide.md +321 -0
- package/skills/skills/social-media-seo/references/instagram-seo.md +235 -0
- package/skills/skills/social-media-seo/references/threads-seo.md +305 -0
- package/skills/skills/social-media-seo/references/x-twitter-seo.md +337 -0
- package/skills/skills/social-media-seo/scripts/query_database.py +191 -0
- package/skills/skills/storyteller/SKILL.md +241 -0
- package/skills/skills/storyteller/references/transformation-methodology.md +293 -0
- package/skills/skills/storyteller/references/visual-vocabulary.md +177 -0
- package/skills/skills/thread-pro/SKILL.md +162 -0
- package/skills/skills/thread-pro/anti-ai-patterns.md +120 -0
- package/skills/skills/thread-pro/hook-formulas.md +138 -0
- package/skills/skills/thread-pro/references/anti-ai-patterns.md +120 -0
- package/skills/skills/thread-pro/references/hook-formulas.md +138 -0
- package/skills/skills/thread-pro/references/thread-structures.md +240 -0
- package/skills/skills/thread-pro/references/voice-injection.md +130 -0
- package/skills/skills/thread-pro/thread-structures.md +240 -0
- package/skills/skills/thread-pro/voice-injection.md +130 -0
- package/skills/skills/tinkering/SKILL.md +251 -0
- package/skills/skills/tinkering/references/graduation-checklist.md +100 -0
- package/skills/skills/validate-plan/.skillkit-mode +1 -0
- package/skills/skills/validate-plan/SKILL.md +406 -0
- package/skills/skills/validate-plan/references/dry-principles.md +251 -0
- package/skills/skills/validate-plan/references/gap-analysis-guide.md +320 -0
- package/skills/skills/validate-plan/references/tdd-patterns.md +413 -0
- package/skills/skills/validate-plan/references/yagni-checklist.md +330 -0
- package/skills/skills/verify-before-ship/.skillkit-mode +1 -0
- package/skills/skills/verify-before-ship/SKILL.md +116 -0
- package/skills/skills/verify-before-ship/references/anti-rationalization.md +212 -0
- package/skills/skills/verify-before-ship/references/verification-gates.md +305 -0
- package/skills-manifest.json +8 -2
- package/src/banner.js +1 -1
- package/src/cli.js +15 -4
- package/src/install.js +45 -29
- package/src/install.test.js +75 -7
- package/src/picker.js +15 -4
- package/src/picker.test.js +36 -1
- package/src/scope.js +8 -39
- package/src/scope.test.js +9 -13
- package/src/tools.js +76 -0
- package/src/tools.test.js +80 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Content Budget Tracking - Hard Limits Enforcement
|
|
4
|
+
|
|
5
|
+
Prevents file bloat by enforcing hard line/token limits during content generation.
|
|
6
|
+
Provides real-time progress tracking and prevents exceeding budgets.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from utils.budget_tracker import FileContentBudget, BudgetExceeded
|
|
10
|
+
|
|
11
|
+
budget = FileContentBudget(max_lines=150, max_tokens=200)
|
|
12
|
+
|
|
13
|
+
for chunk in generate_content():
|
|
14
|
+
if not budget.can_add(chunk):
|
|
15
|
+
raise BudgetExceeded(budget.status_message())
|
|
16
|
+
budget.add_content(chunk)
|
|
17
|
+
print(budget.progress_indicator())
|
|
18
|
+
|
|
19
|
+
budget.finalize() # Validate final state
|
|
20
|
+
|
|
21
|
+
Version: 1.0
|
|
22
|
+
Part of: Advanced Skill Creator v1.2 - Issue #2 fix (File Size Bloat)
|
|
23
|
+
Reference: TEST-REPORT.md Issue #2 - File Size Bloat (4-9x target)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from typing import Dict, Optional, List
|
|
27
|
+
from dataclasses import dataclass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BudgetExceeded(Exception):
|
|
31
|
+
"""Raised when content exceeds hard limits."""
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BudgetWarning(UserWarning):
|
|
36
|
+
"""Warning when approaching budget threshold (80%)."""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class BudgetConfig:
|
|
42
|
+
"""Budget constraints for content generation."""
|
|
43
|
+
max_lines: int
|
|
44
|
+
max_tokens: int
|
|
45
|
+
warning_threshold: float = 0.80 # Warn at 80%
|
|
46
|
+
|
|
47
|
+
def __post_init__(self):
|
|
48
|
+
if self.max_lines <= 0 or self.max_tokens <= 0:
|
|
49
|
+
raise ValueError("Limits must be positive integers")
|
|
50
|
+
if not (0 < self.warning_threshold < 1):
|
|
51
|
+
raise ValueError("Warning threshold must be between 0 and 1")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TokenCounter:
|
|
55
|
+
"""
|
|
56
|
+
Estimate tokens using simple algorithm.
|
|
57
|
+
|
|
58
|
+
No external dependencies (works in Claude.ai and local environments).
|
|
59
|
+
|
|
60
|
+
Algorithm: Combined word-based and character-based estimation
|
|
61
|
+
- Words: ~1.3 tokens per word (verified against GPT tokenization patterns)
|
|
62
|
+
- Characters: ~0.25 tokens per character average
|
|
63
|
+
- Result: Use maximum of both methods for conservative estimate
|
|
64
|
+
|
|
65
|
+
Accuracy: Within ~10% of actual Claude Sonnet tokenization
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def estimate(content: str) -> int:
|
|
70
|
+
"""
|
|
71
|
+
Estimate token count for content.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
content: Text to count tokens for
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Estimated token count (conservative, tends to overestimate)
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
>>> TokenCounter.estimate("Hello world")
|
|
81
|
+
3
|
|
82
|
+
>>> TokenCounter.estimate("# Heading\n\nParagraph with content.\n")
|
|
83
|
+
12
|
|
84
|
+
"""
|
|
85
|
+
if not content:
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
# Count words (rough approximation: ~1.3 tokens/word)
|
|
89
|
+
words = len(content.split())
|
|
90
|
+
word_tokens = max(1, int(words * 1.3))
|
|
91
|
+
|
|
92
|
+
# Count characters (rough approximation: ~0.25 tokens/char)
|
|
93
|
+
# This accounts for average character-to-token ratio
|
|
94
|
+
chars = len(content)
|
|
95
|
+
char_tokens = max(1, int(chars * 0.25))
|
|
96
|
+
|
|
97
|
+
# Use maximum of both methods (conservative estimate)
|
|
98
|
+
# This prevents underestimating complex content
|
|
99
|
+
estimated = max(word_tokens, char_tokens)
|
|
100
|
+
return estimated
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class FileContentBudget:
|
|
104
|
+
"""
|
|
105
|
+
Enforce hard limits on file content during generation.
|
|
106
|
+
|
|
107
|
+
Prevents file bloat (Issue #2: File Size Bloat 4-9x target) by:
|
|
108
|
+
1. Tracking current lines/tokens in real-time
|
|
109
|
+
2. Preventing additions that would exceed limits
|
|
110
|
+
3. Providing progress indicators
|
|
111
|
+
4. Warning at 80% threshold before hard failure at 100%
|
|
112
|
+
|
|
113
|
+
Attributes:
|
|
114
|
+
config: BudgetConfig with max_lines and max_tokens
|
|
115
|
+
current_lines: Current line count
|
|
116
|
+
current_tokens: Current token count
|
|
117
|
+
additions: List of additions (for debugging/audit)
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(self, max_lines: int = 150, max_tokens: int = 200):
|
|
121
|
+
"""
|
|
122
|
+
Initialize budget tracker.
|
|
123
|
+
|
|
124
|
+
Typical P0 constraints (addressing Issue #2):
|
|
125
|
+
- max_lines: 150 (target: 100-150 lines, prevents 5.5x bloat)
|
|
126
|
+
- max_tokens: 200 (ensures ~20k tokens for 100 P0 files vs 80k actual)
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
max_lines: Maximum allowed lines in file
|
|
130
|
+
max_tokens: Maximum allowed tokens in file
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If limits are not positive
|
|
134
|
+
"""
|
|
135
|
+
self.config = BudgetConfig(max_lines=max_lines, max_tokens=max_tokens)
|
|
136
|
+
self.current_lines = 0
|
|
137
|
+
self.current_tokens = 0
|
|
138
|
+
self.additions: List[Dict] = [] # Track all additions for debugging
|
|
139
|
+
self._warned = False # Track if 80% warning already issued
|
|
140
|
+
|
|
141
|
+
def can_add(self, content: str) -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Check if content can be added without exceeding limits.
|
|
144
|
+
|
|
145
|
+
Performs non-destructive check - does not modify state.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
content: Content to potentially add
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
True if content fits within remaining budget, False otherwise
|
|
152
|
+
"""
|
|
153
|
+
if not content:
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
lines = content.count('\n')
|
|
157
|
+
tokens = TokenCounter.estimate(content)
|
|
158
|
+
|
|
159
|
+
return (self.current_lines + lines <= self.config.max_lines and
|
|
160
|
+
self.current_tokens + tokens <= self.config.max_tokens)
|
|
161
|
+
|
|
162
|
+
def add_content(self, content: str) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Add content to budget if within limits.
|
|
165
|
+
|
|
166
|
+
Raises BudgetExceeded with clear message showing current state
|
|
167
|
+
and what would cause the failure.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
content: Content to add
|
|
171
|
+
|
|
172
|
+
Raises:
|
|
173
|
+
BudgetExceeded: If adding content would exceed limits
|
|
174
|
+
"""
|
|
175
|
+
if not content:
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
lines = content.count('\n')
|
|
179
|
+
tokens = TokenCounter.estimate(content)
|
|
180
|
+
|
|
181
|
+
# Check line limit (hard stop)
|
|
182
|
+
if self.current_lines + lines > self.config.max_lines:
|
|
183
|
+
raise BudgetExceeded(
|
|
184
|
+
f"Line limit exceeded: Adding {lines} lines would exceed {self.config.max_lines} line limit. "
|
|
185
|
+
f"Current: {self.current_lines}/{self.config.max_lines} lines. "
|
|
186
|
+
f"Consider: compress content, split into multiple files, or increase budget."
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Check token limit (hard stop)
|
|
190
|
+
if self.current_tokens + tokens > self.config.max_tokens:
|
|
191
|
+
raise BudgetExceeded(
|
|
192
|
+
f"Token limit exceeded: Adding {tokens} tokens would exceed {self.config.max_tokens} token limit. "
|
|
193
|
+
f"Current: {self.current_tokens}/{self.config.max_tokens} tokens. "
|
|
194
|
+
f"Consider: reduce verbosity or split content."
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# Add content (both checks passed)
|
|
198
|
+
self.current_lines += lines
|
|
199
|
+
self.current_tokens += tokens
|
|
200
|
+
self.additions.append({
|
|
201
|
+
'lines': lines,
|
|
202
|
+
'tokens': tokens,
|
|
203
|
+
'content_preview': content[:50] + '...' if len(content) > 50 else content
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
def progress_percentage(self) -> float:
|
|
207
|
+
"""
|
|
208
|
+
Get progress as percentage of line limit.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Percentage (0-100+, can exceed 100 if manually set)
|
|
212
|
+
"""
|
|
213
|
+
if self.config.max_lines == 0:
|
|
214
|
+
return 0.0
|
|
215
|
+
return min(100.0, (self.current_lines / self.config.max_lines) * 100)
|
|
216
|
+
|
|
217
|
+
def progress_indicator(self) -> str:
|
|
218
|
+
"""
|
|
219
|
+
Get human-readable progress indicator.
|
|
220
|
+
|
|
221
|
+
Format: "File at 120/150 lines (80%) | 195/200 tokens (97%) | ⚠️ WARNING (80%+)"
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Progress string suitable for logging/display
|
|
225
|
+
"""
|
|
226
|
+
percentage = self.progress_percentage()
|
|
227
|
+
tokens_pct = (self.current_tokens / self.config.max_tokens * 100) if self.config.max_tokens > 0 else 0
|
|
228
|
+
|
|
229
|
+
# Determine status icon and message
|
|
230
|
+
if percentage >= 100:
|
|
231
|
+
status = "❌ LIMIT EXCEEDED"
|
|
232
|
+
elif percentage >= 90:
|
|
233
|
+
status = "🔴 CRITICAL (90%+)"
|
|
234
|
+
elif percentage >= 80:
|
|
235
|
+
status = "🟠 WARNING (80%+)"
|
|
236
|
+
elif percentage >= 50:
|
|
237
|
+
status = "🟡 HALFWAY"
|
|
238
|
+
else:
|
|
239
|
+
status = "🟢 OK"
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
f"File at {self.current_lines}/{self.config.max_lines} lines ({percentage:.0f}%) "
|
|
243
|
+
f"| {self.current_tokens}/{self.config.max_tokens} tokens ({tokens_pct:.0f}%) "
|
|
244
|
+
f"| {status}"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def status_message(self) -> str:
|
|
248
|
+
"""
|
|
249
|
+
Get detailed status message for logging.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
Multi-line status summary
|
|
253
|
+
"""
|
|
254
|
+
return (
|
|
255
|
+
f"Budget Status:\n"
|
|
256
|
+
f" Lines: {self.current_lines}/{self.config.max_lines} ({self.progress_percentage():.0f}%)\n"
|
|
257
|
+
f" Tokens: {self.current_tokens}/{self.config.max_tokens}\n"
|
|
258
|
+
f" Chunks added: {len(self.additions)}"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
def check_threshold_warning(self) -> Optional[str]:
|
|
262
|
+
"""
|
|
263
|
+
Check if threshold warning should be issued (80%).
|
|
264
|
+
|
|
265
|
+
Returns warning once at 80% threshold, subsequent calls return None.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Warning message if at threshold and not previously warned, None otherwise
|
|
269
|
+
"""
|
|
270
|
+
threshold = self.config.max_lines * self.config.warning_threshold
|
|
271
|
+
|
|
272
|
+
if self.current_lines >= threshold and not self._warned:
|
|
273
|
+
self._warned = True
|
|
274
|
+
return (
|
|
275
|
+
f"⚠️ WARNING: Approaching line limit! "
|
|
276
|
+
f"{self.current_lines}/{self.config.max_lines} lines ({self.progress_percentage():.0f}%). "
|
|
277
|
+
f"Compress content or split file to stay within budget."
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
def finalize(self) -> Dict:
|
|
283
|
+
"""
|
|
284
|
+
Finalize budget and return summary.
|
|
285
|
+
|
|
286
|
+
Call after all content generation complete to get final stats.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Summary dict with final statistics and status
|
|
290
|
+
"""
|
|
291
|
+
return {
|
|
292
|
+
'final_lines': self.current_lines,
|
|
293
|
+
'final_tokens': self.current_tokens,
|
|
294
|
+
'max_lines': self.config.max_lines,
|
|
295
|
+
'max_tokens': self.config.max_tokens,
|
|
296
|
+
'line_percentage': self.progress_percentage(),
|
|
297
|
+
'additions_count': len(self.additions),
|
|
298
|
+
'status': 'success' if self.current_lines <= self.config.max_lines else 'exceeded',
|
|
299
|
+
'within_budget': self.current_lines <= self.config.max_lines
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
def reset(self) -> None:
|
|
303
|
+
"""Reset budget tracker for reuse (e.g., next file)."""
|
|
304
|
+
self.current_lines = 0
|
|
305
|
+
self.current_tokens = 0
|
|
306
|
+
self.additions = []
|
|
307
|
+
self._warned = False
|
|
308
|
+
|
|
309
|
+
def get_remaining_budget(self) -> Dict[str, int]:
|
|
310
|
+
"""
|
|
311
|
+
Get remaining budget capacity.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Dict with remaining_lines and remaining_tokens
|
|
315
|
+
"""
|
|
316
|
+
return {
|
|
317
|
+
'remaining_lines': max(0, self.config.max_lines - self.current_lines),
|
|
318
|
+
'remaining_tokens': max(0, self.config.max_tokens - self.current_tokens)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# Constants for standard P0/P1/P2 budgets
|
|
323
|
+
# Based on Issue #2 analysis: Prevent 5.5x bloat
|
|
324
|
+
STANDARD_BUDGETS = {
|
|
325
|
+
'P0': {'max_lines': 150, 'max_tokens': 200}, # Core skill files (was 500+ lines, bloat 5.5x)
|
|
326
|
+
'P1': {'max_lines': 100, 'max_tokens': 150}, # Important supporting files
|
|
327
|
+
'P2': {'max_lines': 60, 'max_tokens': 100}, # Optional files
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def create_budget(priority: str) -> FileContentBudget:
|
|
332
|
+
"""
|
|
333
|
+
Create budget tracker for specific priority level.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
priority: 'P0', 'P1', or 'P2'
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
FileContentBudget configured for priority level
|
|
340
|
+
|
|
341
|
+
Raises:
|
|
342
|
+
ValueError: If priority not in STANDARD_BUDGETS
|
|
343
|
+
|
|
344
|
+
Examples:
|
|
345
|
+
>>> budget = create_budget('P0')
|
|
346
|
+
>>> budget.config.max_lines
|
|
347
|
+
150
|
|
348
|
+
"""
|
|
349
|
+
if priority not in STANDARD_BUDGETS:
|
|
350
|
+
raise ValueError(f"Unknown priority: {priority}. Must be P0, P1, or P2")
|
|
351
|
+
|
|
352
|
+
config = STANDARD_BUDGETS[priority]
|
|
353
|
+
return FileContentBudget(**config)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
if __name__ == '__main__':
|
|
357
|
+
# Example usage and testing
|
|
358
|
+
print("Testing FileContentBudget...")
|
|
359
|
+
print()
|
|
360
|
+
|
|
361
|
+
budget = FileContentBudget(max_lines=150, max_tokens=200)
|
|
362
|
+
|
|
363
|
+
# Simulate content additions
|
|
364
|
+
test_content = [
|
|
365
|
+
"# Section 1\nThis is the first section.\n",
|
|
366
|
+
"## Subsection 1.1\nMore content here with details.\n",
|
|
367
|
+
"## Subsection 1.2\nEven more content with examples.\n",
|
|
368
|
+
]
|
|
369
|
+
|
|
370
|
+
for i, content in enumerate(test_content, 1):
|
|
371
|
+
if budget.can_add(content):
|
|
372
|
+
budget.add_content(content)
|
|
373
|
+
print(f"✅ Added chunk {i}")
|
|
374
|
+
print(f" {budget.progress_indicator()}")
|
|
375
|
+
|
|
376
|
+
warning = budget.check_threshold_warning()
|
|
377
|
+
if warning:
|
|
378
|
+
print(f" {warning}")
|
|
379
|
+
else:
|
|
380
|
+
print(f"❌ Cannot add chunk {i} - would exceed budget")
|
|
381
|
+
break
|
|
382
|
+
|
|
383
|
+
print()
|
|
384
|
+
print("Final Summary:")
|
|
385
|
+
print(budget.status_message())
|
|
386
|
+
print()
|
|
387
|
+
print(f"Final Stats: {budget.finalize()}")
|
|
388
|
+
print(f"Remaining: {budget.get_remaining_budget()}")
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Standardized output formatting utilities for automation scripts.
|
|
4
|
+
|
|
5
|
+
Provides consistent JSON/text output patterns across all tools based on
|
|
6
|
+
proven patterns from validate_skill.py and quality_scorer.py.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from utils import add_format_argument, output_json, output_error
|
|
10
|
+
|
|
11
|
+
parser = argparse.ArgumentParser(...)
|
|
12
|
+
add_format_argument(parser)
|
|
13
|
+
|
|
14
|
+
if args.format == 'json':
|
|
15
|
+
output_json(data, tool_name="my_tool")
|
|
16
|
+
else:
|
|
17
|
+
print(human_readable_output)
|
|
18
|
+
|
|
19
|
+
Version: 1.0
|
|
20
|
+
Author: Advanced Skill Creator Project
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
from typing import Dict, Any, Optional
|
|
26
|
+
from datetime import datetime
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def add_format_argument(parser, default='text'):
|
|
30
|
+
"""
|
|
31
|
+
Add standardized --format argument to argparse parser.
|
|
32
|
+
|
|
33
|
+
Based on proven pattern from validate_skill.py (line 516) and
|
|
34
|
+
quality_scorer.py.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
parser: argparse.ArgumentParser instance
|
|
38
|
+
default: Default format ('text' or 'json')
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
>>> parser = argparse.ArgumentParser(description='My tool')
|
|
42
|
+
>>> add_format_argument(parser)
|
|
43
|
+
>>> args = parser.parse_args()
|
|
44
|
+
>>> print(args.format) # 'text' or 'json'
|
|
45
|
+
"""
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
'--format',
|
|
48
|
+
choices=['text', 'json'],
|
|
49
|
+
default=default,
|
|
50
|
+
help='Output format: text (human-readable) or json (machine-readable)'
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_success_response(
|
|
55
|
+
data: Dict[str, Any],
|
|
56
|
+
tool_name: str,
|
|
57
|
+
skill_name: Optional[str] = None,
|
|
58
|
+
skill_path: Optional[str] = None,
|
|
59
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
60
|
+
) -> Dict[str, Any]:
|
|
61
|
+
"""
|
|
62
|
+
Create standardized success response structure.
|
|
63
|
+
|
|
64
|
+
Based on quality_scorer.py pattern (lines 817-838).
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
data: Tool-specific result data
|
|
68
|
+
tool_name: Name of the tool (e.g., 'token_estimator', 'validator')
|
|
69
|
+
skill_name: Optional skill name
|
|
70
|
+
skill_path: Optional skill path
|
|
71
|
+
metadata: Optional additional metadata
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Standardized dictionary ready for JSON serialization
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
>>> response = format_success_response(
|
|
78
|
+
... data={'tokens': 500, 'cost': 0.02},
|
|
79
|
+
... tool_name='token_estimator',
|
|
80
|
+
... skill_name='my-skill'
|
|
81
|
+
... )
|
|
82
|
+
>>> print(response['status'])
|
|
83
|
+
'success'
|
|
84
|
+
"""
|
|
85
|
+
response = {
|
|
86
|
+
'status': 'success',
|
|
87
|
+
'tool': tool_name,
|
|
88
|
+
'timestamp': datetime.now().isoformat(),
|
|
89
|
+
'data': data
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Add optional fields if provided
|
|
93
|
+
if skill_name:
|
|
94
|
+
response['skill_name'] = skill_name
|
|
95
|
+
|
|
96
|
+
if skill_path:
|
|
97
|
+
response['skill_path'] = skill_path
|
|
98
|
+
|
|
99
|
+
if metadata:
|
|
100
|
+
response['metadata'] = metadata
|
|
101
|
+
|
|
102
|
+
return response
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def format_error_response(
|
|
106
|
+
error_type: str,
|
|
107
|
+
message: str,
|
|
108
|
+
tool_name: str,
|
|
109
|
+
help_text: Optional[str] = None,
|
|
110
|
+
details: Optional[Dict[str, Any]] = None
|
|
111
|
+
) -> Dict[str, Any]:
|
|
112
|
+
"""
|
|
113
|
+
Create standardized error response structure.
|
|
114
|
+
|
|
115
|
+
Based on quality_scorer.py pattern (lines 864-874, 876-886).
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
error_type: Error category (e.g., 'FileNotFound', 'ValidationError')
|
|
119
|
+
message: Error message
|
|
120
|
+
tool_name: Name of the tool
|
|
121
|
+
help_text: Optional helpful guidance for user
|
|
122
|
+
details: Optional additional error details
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Standardized error dictionary ready for JSON serialization
|
|
126
|
+
|
|
127
|
+
Example:
|
|
128
|
+
>>> response = format_error_response(
|
|
129
|
+
... error_type='FileNotFoundError',
|
|
130
|
+
... message='SKILL.md not found',
|
|
131
|
+
... tool_name='validator',
|
|
132
|
+
... help_text='Ensure skill directory contains SKILL.md'
|
|
133
|
+
... )
|
|
134
|
+
>>> print(response['status'])
|
|
135
|
+
'error'
|
|
136
|
+
"""
|
|
137
|
+
response = {
|
|
138
|
+
'status': 'error',
|
|
139
|
+
'tool': tool_name,
|
|
140
|
+
'timestamp': datetime.now().isoformat(),
|
|
141
|
+
'error_type': error_type,
|
|
142
|
+
'message': message
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if help_text:
|
|
146
|
+
response['help'] = help_text
|
|
147
|
+
|
|
148
|
+
if details:
|
|
149
|
+
response['details'] = details
|
|
150
|
+
|
|
151
|
+
return response
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def output_json(
|
|
155
|
+
response: Dict[str, Any],
|
|
156
|
+
file=None
|
|
157
|
+
) -> None:
|
|
158
|
+
"""
|
|
159
|
+
Output JSON response to stdout or file.
|
|
160
|
+
|
|
161
|
+
Based on quality_scorer.py pattern (line 838).
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
response: Response dictionary (from format_success_response or format_error_response)
|
|
165
|
+
file: Optional file object (default: sys.stdout)
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
>>> response = format_success_response(data={'result': 'ok'}, tool_name='my_tool')
|
|
169
|
+
>>> output_json(response)
|
|
170
|
+
{
|
|
171
|
+
"status": "success",
|
|
172
|
+
"tool": "my_tool",
|
|
173
|
+
...
|
|
174
|
+
}
|
|
175
|
+
"""
|
|
176
|
+
if file is None:
|
|
177
|
+
file = sys.stdout
|
|
178
|
+
|
|
179
|
+
print(json.dumps(response, indent=2), file=file)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def output_error(
|
|
183
|
+
error_type: str,
|
|
184
|
+
message: str,
|
|
185
|
+
tool_name: str,
|
|
186
|
+
help_text: Optional[str] = None,
|
|
187
|
+
details: Optional[Dict[str, Any]] = None,
|
|
188
|
+
file=None
|
|
189
|
+
) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Convenience function to format and output error in one call.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
error_type: Error category
|
|
195
|
+
message: Error message
|
|
196
|
+
tool_name: Name of the tool
|
|
197
|
+
help_text: Optional helpful guidance
|
|
198
|
+
details: Optional additional details
|
|
199
|
+
file: Optional file object (default: sys.stdout)
|
|
200
|
+
|
|
201
|
+
Example:
|
|
202
|
+
>>> output_error(
|
|
203
|
+
... error_type='FileNotFoundError',
|
|
204
|
+
... message='File not found: skill.md',
|
|
205
|
+
... tool_name='validator',
|
|
206
|
+
... help_text='Check file path'
|
|
207
|
+
... )
|
|
208
|
+
"""
|
|
209
|
+
response = format_error_response(
|
|
210
|
+
error_type=error_type,
|
|
211
|
+
message=message,
|
|
212
|
+
tool_name=tool_name,
|
|
213
|
+
help_text=help_text,
|
|
214
|
+
details=details
|
|
215
|
+
)
|
|
216
|
+
output_json(response, file=file)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# Convenience function for backward compatibility
|
|
220
|
+
def output_success(
|
|
221
|
+
data: Dict[str, Any],
|
|
222
|
+
tool_name: str,
|
|
223
|
+
skill_name: Optional[str] = None,
|
|
224
|
+
skill_path: Optional[str] = None,
|
|
225
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
226
|
+
file=None
|
|
227
|
+
) -> None:
|
|
228
|
+
"""
|
|
229
|
+
Convenience function to format and output success response in one call.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
data: Tool-specific result data
|
|
233
|
+
tool_name: Name of the tool
|
|
234
|
+
skill_name: Optional skill name
|
|
235
|
+
skill_path: Optional skill path
|
|
236
|
+
metadata: Optional additional metadata
|
|
237
|
+
file: Optional file object (default: sys.stdout)
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
>>> output_success(
|
|
241
|
+
... data={'score': 85, 'grade': 'B'},
|
|
242
|
+
... tool_name='quality_scorer',
|
|
243
|
+
... skill_name='my-skill'
|
|
244
|
+
... )
|
|
245
|
+
"""
|
|
246
|
+
response = format_success_response(
|
|
247
|
+
data=data,
|
|
248
|
+
tool_name=tool_name,
|
|
249
|
+
skill_name=skill_name,
|
|
250
|
+
skill_path=skill_path,
|
|
251
|
+
metadata=metadata
|
|
252
|
+
)
|
|
253
|
+
output_json(response, file=file)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# Exit code constants for consistency
|
|
257
|
+
class ExitCode:
|
|
258
|
+
"""Standardized exit codes across all tools."""
|
|
259
|
+
SUCCESS = 0
|
|
260
|
+
ERROR = 1
|
|
261
|
+
VALIDATION_ERROR = 1
|
|
262
|
+
FILE_NOT_FOUND = 1
|
|
263
|
+
UNEXPECTED_ERROR = 2
|