@heytherevibin/skillforge 0.2.1
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 +16 -0
- package/CODE_OF_CONDUCT.md +34 -0
- package/CONTRIBUTING.md +38 -0
- package/LICENSE +21 -0
- package/README.md +337 -0
- package/RELEASING.md +93 -0
- package/SECURITY.md +31 -0
- package/STRATEGY.md +26 -0
- package/bin/cli.js +547 -0
- package/lib/packs.js +184 -0
- package/package.json +38 -0
- package/python/app/__init__.py +0 -0
- package/python/app/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/app/__pycache__/auth.cpython-312.pyc +0 -0
- package/python/app/__pycache__/main.cpython-312.pyc +0 -0
- package/python/app/auth.py +63 -0
- package/python/app/cli.py +78 -0
- package/python/app/db_paths.py +26 -0
- package/python/app/events_cli.py +175 -0
- package/python/app/main.py +647 -0
- package/python/app/materialize.py +138 -0
- package/python/app/mcp_server.py +610 -0
- package/python/app/route_cli.py +117 -0
- package/python/requirements-dev.txt +1 -0
- package/python/requirements.txt +7 -0
- package/python/tests/test_db_paths.py +41 -0
- package/skills/accessibility/SKILL.md +145 -0
- package/skills/agent-architecture-audit/SKILL.md +256 -0
- package/skills/agent-eval/SKILL.md +144 -0
- package/skills/agent-harness-construction/SKILL.md +72 -0
- package/skills/agent-introspection-debugging/SKILL.md +152 -0
- package/skills/agent-payment-x402/SKILL.md +224 -0
- package/skills/agent-sort/SKILL.md +214 -0
- package/skills/agentic-engineering/SKILL.md +62 -0
- package/skills/agentic-os/SKILL.md +386 -0
- package/skills/ai-first-engineering/SKILL.md +50 -0
- package/skills/ai-regression-testing/SKILL.md +384 -0
- package/skills/android-clean-architecture/SKILL.md +338 -0
- package/skills/angular-developer/SKILL.md +153 -0
- package/skills/angular-developer/references/angular-animations.md +160 -0
- package/skills/angular-developer/references/angular-aria.md +410 -0
- package/skills/angular-developer/references/cli.md +86 -0
- package/skills/angular-developer/references/component-harnesses.md +59 -0
- package/skills/angular-developer/references/component-styling.md +91 -0
- package/skills/angular-developer/references/components.md +117 -0
- package/skills/angular-developer/references/creating-services.md +97 -0
- package/skills/angular-developer/references/data-resolvers.md +69 -0
- package/skills/angular-developer/references/define-routes.md +67 -0
- package/skills/angular-developer/references/defining-providers.md +72 -0
- package/skills/angular-developer/references/di-fundamentals.md +120 -0
- package/skills/angular-developer/references/e2e-testing.md +56 -0
- package/skills/angular-developer/references/effects.md +83 -0
- package/skills/angular-developer/references/hierarchical-injectors.md +43 -0
- package/skills/angular-developer/references/host-elements.md +80 -0
- package/skills/angular-developer/references/injection-context.md +63 -0
- package/skills/angular-developer/references/inputs.md +101 -0
- package/skills/angular-developer/references/linked-signal.md +59 -0
- package/skills/angular-developer/references/loading-strategies.md +61 -0
- package/skills/angular-developer/references/mcp.md +108 -0
- package/skills/angular-developer/references/navigate-to-routes.md +69 -0
- package/skills/angular-developer/references/outputs.md +86 -0
- package/skills/angular-developer/references/reactive-forms.md +122 -0
- package/skills/angular-developer/references/rendering-strategies.md +44 -0
- package/skills/angular-developer/references/resource.md +77 -0
- package/skills/angular-developer/references/route-animations.md +56 -0
- package/skills/angular-developer/references/route-guards.md +52 -0
- package/skills/angular-developer/references/router-lifecycle.md +45 -0
- package/skills/angular-developer/references/router-testing.md +87 -0
- package/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
- package/skills/angular-developer/references/signal-forms.md +795 -0
- package/skills/angular-developer/references/signals-overview.md +94 -0
- package/skills/angular-developer/references/tailwind-css.md +69 -0
- package/skills/angular-developer/references/template-driven-forms.md +114 -0
- package/skills/angular-developer/references/testing-fundamentals.md +65 -0
- package/skills/api-connector-builder/SKILL.md +120 -0
- package/skills/api-design/SKILL.md +522 -0
- package/skills/architecture-decision-records/SKILL.md +178 -0
- package/skills/article-writing/SKILL.md +78 -0
- package/skills/automation-audit-ops/SKILL.md +141 -0
- package/skills/autonomous-agent-harness/SKILL.md +272 -0
- package/skills/autonomous-loops/SKILL.md +609 -0
- package/skills/backend-patterns/SKILL.md +560 -0
- package/skills/benchmark/SKILL.md +92 -0
- package/skills/blueprint/SKILL.md +104 -0
- package/skills/browser-qa/SKILL.md +86 -0
- package/skills/bun-runtime/SKILL.md +83 -0
- package/skills/canary-watch/SKILL.md +98 -0
- package/skills/carrier-relationship-management/SKILL.md +211 -0
- package/skills/cisco-ios-patterns/SKILL.md +163 -0
- package/skills/ck/SKILL.md +147 -0
- package/skills/ck/commands/forget.mjs +44 -0
- package/skills/ck/commands/info.mjs +24 -0
- package/skills/ck/commands/init.mjs +143 -0
- package/skills/ck/commands/list.mjs +40 -0
- package/skills/ck/commands/migrate.mjs +202 -0
- package/skills/ck/commands/resume.mjs +36 -0
- package/skills/ck/commands/save.mjs +210 -0
- package/skills/ck/commands/shared.mjs +387 -0
- package/skills/ck/hooks/session-start.mjs +224 -0
- package/skills/claude-devfleet/SKILL.md +103 -0
- package/skills/click-path-audit/SKILL.md +244 -0
- package/skills/clickhouse-io/SKILL.md +438 -0
- package/skills/code-tour/SKILL.md +235 -0
- package/skills/codebase-onboarding/SKILL.md +232 -0
- package/skills/coding-standards/SKILL.md +548 -0
- package/skills/compose-multiplatform-patterns/SKILL.md +298 -0
- package/skills/connections-optimizer/SKILL.md +188 -0
- package/skills/content-engine/SKILL.md +126 -0
- package/skills/content-hash-cache-pattern/SKILL.md +160 -0
- package/skills/context-budget/SKILL.md +134 -0
- package/skills/continuous-agent-loop/SKILL.md +44 -0
- package/skills/continuous-learning/SKILL.md +129 -0
- package/skills/continuous-learning/config.json +18 -0
- package/skills/continuous-learning/evaluate-session.sh +69 -0
- package/skills/continuous-learning-v2/SKILL.md +358 -0
- package/skills/continuous-learning-v2/agents/observer-loop.sh +322 -0
- package/skills/continuous-learning-v2/agents/observer.md +198 -0
- package/skills/continuous-learning-v2/agents/session-guardian.sh +150 -0
- package/skills/continuous-learning-v2/agents/start-observer.sh +248 -0
- package/skills/continuous-learning-v2/config.json +8 -0
- package/skills/continuous-learning-v2/hooks/observe.sh +476 -0
- package/skills/continuous-learning-v2/scripts/detect-project.sh +288 -0
- package/skills/continuous-learning-v2/scripts/instinct-cli.py +1519 -0
- package/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh +31 -0
- package/skills/continuous-learning-v2/scripts/migrate-homunculus.sh +62 -0
- package/skills/continuous-learning-v2/scripts/test_parse_instinct.py +1018 -0
- package/skills/cost-aware-llm-pipeline/SKILL.md +182 -0
- package/skills/cost-tracking/SKILL.md +147 -0
- package/skills/council/SKILL.md +202 -0
- package/skills/cpp-coding-standards/SKILL.md +722 -0
- package/skills/cpp-testing/SKILL.md +323 -0
- package/skills/crosspost/SKILL.md +110 -0
- package/skills/csharp-testing/SKILL.md +320 -0
- package/skills/customer-billing-ops/SKILL.md +139 -0
- package/skills/customs-trade-compliance/SKILL.md +262 -0
- package/skills/dart-flutter-patterns/SKILL.md +562 -0
- package/skills/dashboard-builder/SKILL.md +108 -0
- package/skills/data-scraper-agent/SKILL.md +764 -0
- package/skills/database-migrations/SKILL.md +428 -0
- package/skills/deep-research/SKILL.md +158 -0
- package/skills/defi-amm-security/SKILL.md +166 -0
- package/skills/deployment-patterns/SKILL.md +426 -0
- package/skills/design-system/SKILL.md +81 -0
- package/skills/django-celery/SKILL.md +456 -0
- package/skills/django-patterns/SKILL.md +733 -0
- package/skills/django-security/SKILL.md +592 -0
- package/skills/django-tdd/SKILL.md +728 -0
- package/skills/django-verification/SKILL.md +468 -0
- package/skills/dmux-workflows/SKILL.md +190 -0
- package/skills/docker-patterns/SKILL.md +363 -0
- package/skills/documentation-lookup/SKILL.md +89 -0
- package/skills/dotnet-patterns/SKILL.md +320 -0
- package/skills/e2e-testing/SKILL.md +325 -0
- package/skills/email-ops/SKILL.md +120 -0
- package/skills/energy-procurement/SKILL.md +227 -0
- package/skills/enterprise-agent-ops/SKILL.md +49 -0
- package/skills/error-handling/SKILL.md +375 -0
- package/skills/eval-harness/SKILL.md +269 -0
- package/skills/evm-token-decimals/SKILL.md +130 -0
- package/skills/exa-search/SKILL.md +106 -0
- package/skills/fal-ai-media/SKILL.md +287 -0
- package/skills/fastapi-patterns/SKILL.md +327 -0
- package/skills/finance-billing-ops/SKILL.md +126 -0
- package/skills/flox-environments/SKILL.md +496 -0
- package/skills/flutter-dart-code-review/SKILL.md +434 -0
- package/skills/foundation-models-on-device/SKILL.md +243 -0
- package/skills/frontend-design-direction/SKILL.md +92 -0
- package/skills/frontend-patterns/SKILL.md +641 -0
- package/skills/frontend-slides/SKILL.md +183 -0
- package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
- package/skills/frontend-slides/animation-patterns.md +122 -0
- package/skills/frontend-slides/html-template.md +419 -0
- package/skills/frontend-slides/scripts/export-pdf.sh +418 -0
- package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
- package/skills/frontend-slides/viewport-base.css +153 -0
- package/skills/fsharp-testing/SKILL.md +279 -0
- package/skills/gan-style-harness/SKILL.md +278 -0
- package/skills/gateguard/SKILL.md +125 -0
- package/skills/git-workflow/SKILL.md +714 -0
- package/skills/github-ops/SKILL.md +143 -0
- package/skills/golang-patterns/SKILL.md +673 -0
- package/skills/golang-testing/SKILL.md +719 -0
- package/skills/google-workspace-ops/SKILL.md +94 -0
- package/skills/healthcare-cdss-patterns/SKILL.md +245 -0
- package/skills/healthcare-emr-patterns/SKILL.md +159 -0
- package/skills/healthcare-eval-harness/SKILL.md +207 -0
- package/skills/healthcare-phi-compliance/SKILL.md +145 -0
- package/skills/hermes-imports/SKILL.md +87 -0
- package/skills/hexagonal-architecture/SKILL.md +275 -0
- package/skills/hipaa-compliance/SKILL.md +78 -0
- package/skills/homelab-network-readiness/SKILL.md +169 -0
- package/skills/homelab-network-setup/SKILL.md +129 -0
- package/skills/homelab-pihole-dns/SKILL.md +274 -0
- package/skills/homelab-vlan-segmentation/SKILL.md +311 -0
- package/skills/homelab-wireguard-vpn/SKILL.md +305 -0
- package/skills/hookify-rules/SKILL.md +128 -0
- package/skills/inventory-demand-planning/SKILL.md +246 -0
- package/skills/investor-materials/SKILL.md +95 -0
- package/skills/investor-outreach/SKILL.md +90 -0
- package/skills/ios-icon-gen/SKILL.md +157 -0
- package/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
- package/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
- package/skills/iterative-retrieval/SKILL.md +209 -0
- package/skills/java-coding-standards/SKILL.md +382 -0
- package/skills/jira-integration/SKILL.md +292 -0
- package/skills/jpa-patterns/SKILL.md +150 -0
- package/skills/knowledge-ops/SKILL.md +153 -0
- package/skills/kotlin-coroutines-flows/SKILL.md +283 -0
- package/skills/kotlin-exposed-patterns/SKILL.md +718 -0
- package/skills/kotlin-ktor-patterns/SKILL.md +688 -0
- package/skills/kotlin-patterns/SKILL.md +710 -0
- package/skills/kotlin-testing/SKILL.md +823 -0
- package/skills/laravel-patterns/SKILL.md +414 -0
- package/skills/laravel-plugin-discovery/SKILL.md +228 -0
- package/skills/laravel-security/SKILL.md +284 -0
- package/skills/laravel-tdd/SKILL.md +282 -0
- package/skills/laravel-verification/SKILL.md +178 -0
- package/skills/lead-intelligence/SKILL.md +320 -0
- package/skills/lead-intelligence/agents/enrichment-agent.md +85 -0
- package/skills/lead-intelligence/agents/mutual-mapper.md +75 -0
- package/skills/lead-intelligence/agents/outreach-drafter.md +98 -0
- package/skills/lead-intelligence/agents/signal-scorer.md +60 -0
- package/skills/liquid-glass-design/SKILL.md +279 -0
- package/skills/llm-trading-agent-security/SKILL.md +146 -0
- package/skills/logistics-exception-management/SKILL.md +221 -0
- package/skills/make-interfaces-feel-better/SKILL.md +151 -0
- package/skills/manim-video/SKILL.md +88 -0
- package/skills/manim-video/assets/network_graph_scene.py +52 -0
- package/skills/market-research/SKILL.md +74 -0
- package/skills/mcp-server-patterns/SKILL.md +68 -0
- package/skills/messages-ops/SKILL.md +103 -0
- package/skills/mle-workflow/SKILL.md +345 -0
- package/skills/motion-advanced/SKILL.md +596 -0
- package/skills/motion-foundations/SKILL.md +299 -0
- package/skills/motion-patterns/SKILL.md +435 -0
- package/skills/motion-ui/SKILL.md +574 -0
- package/skills/mysql-patterns/SKILL.md +411 -0
- package/skills/nanoclaw-repl/SKILL.md +32 -0
- package/skills/nestjs-patterns/SKILL.md +229 -0
- package/skills/netmiko-ssh-automation/SKILL.md +173 -0
- package/skills/network-bgp-diagnostics/SKILL.md +167 -0
- package/skills/network-config-validation/SKILL.md +210 -0
- package/skills/network-interface-health/SKILL.md +152 -0
- package/skills/nextjs-turbopack/SKILL.md +43 -0
- package/skills/nodejs-keccak256/SKILL.md +102 -0
- package/skills/nutrient-document-processing/SKILL.md +166 -0
- package/skills/nuxt4-patterns/SKILL.md +99 -0
- package/skills/openclaw-persona-forge/SKILL.md +288 -0
- package/skills/openclaw-persona-forge/gacha.py +224 -0
- package/skills/openclaw-persona-forge/gacha.sh +5 -0
- package/skills/openclaw-persona-forge/references/avatar-style.md +124 -0
- package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -0
- package/skills/openclaw-persona-forge/references/error-handling.md +53 -0
- package/skills/openclaw-persona-forge/references/identity-tension.md +48 -0
- package/skills/openclaw-persona-forge/references/naming-system.md +39 -0
- package/skills/openclaw-persona-forge/references/output-template.md +166 -0
- package/skills/opensource-pipeline/SKILL.md +254 -0
- package/skills/perl-patterns/SKILL.md +503 -0
- package/skills/perl-security/SKILL.md +502 -0
- package/skills/perl-testing/SKILL.md +474 -0
- package/skills/plan-orchestrate/SKILL.md +253 -0
- package/skills/plankton-code-quality/SKILL.md +236 -0
- package/skills/postgres-patterns/SKILL.md +146 -0
- package/skills/product-capability/SKILL.md +140 -0
- package/skills/product-lens/SKILL.md +91 -0
- package/skills/production-audit/SKILL.md +206 -0
- package/skills/production-scheduling/SKILL.md +237 -0
- package/skills/project-flow-ops/SKILL.md +110 -0
- package/skills/prompt-optimizer/SKILL.md +398 -0
- package/skills/python-patterns/SKILL.md +749 -0
- package/skills/python-testing/SKILL.md +815 -0
- package/skills/pytorch-patterns/SKILL.md +395 -0
- package/skills/quality-nonconformance/SKILL.md +259 -0
- package/skills/quarkus-patterns/SKILL.md +721 -0
- package/skills/quarkus-security/SKILL.md +466 -0
- package/skills/quarkus-tdd/SKILL.md +810 -0
- package/skills/quarkus-verification/SKILL.md +478 -0
- package/skills/ralphinho-rfc-pipeline/SKILL.md +66 -0
- package/skills/redis-patterns/SKILL.md +402 -0
- package/skills/regex-vs-llm-structured-text/SKILL.md +219 -0
- package/skills/remotion-video-creation/SKILL.md +43 -0
- package/skills/remotion-video-creation/rules/3d.md +86 -0
- package/skills/remotion-video-creation/rules/animations.md +29 -0
- package/skills/remotion-video-creation/rules/assets/charts-bar-chart.tsx +173 -0
- package/skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx +100 -0
- package/skills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/skills/remotion-video-creation/rules/assets.md +78 -0
- package/skills/remotion-video-creation/rules/audio.md +172 -0
- package/skills/remotion-video-creation/rules/calculate-metadata.md +104 -0
- package/skills/remotion-video-creation/rules/can-decode.md +75 -0
- package/skills/remotion-video-creation/rules/charts.md +58 -0
- package/skills/remotion-video-creation/rules/compositions.md +146 -0
- package/skills/remotion-video-creation/rules/display-captions.md +126 -0
- package/skills/remotion-video-creation/rules/extract-frames.md +229 -0
- package/skills/remotion-video-creation/rules/fonts.md +152 -0
- package/skills/remotion-video-creation/rules/get-audio-duration.md +58 -0
- package/skills/remotion-video-creation/rules/get-video-dimensions.md +68 -0
- package/skills/remotion-video-creation/rules/get-video-duration.md +58 -0
- package/skills/remotion-video-creation/rules/gifs.md +138 -0
- package/skills/remotion-video-creation/rules/images.md +130 -0
- package/skills/remotion-video-creation/rules/import-srt-captions.md +67 -0
- package/skills/remotion-video-creation/rules/lottie.md +67 -0
- package/skills/remotion-video-creation/rules/measuring-dom-nodes.md +34 -0
- package/skills/remotion-video-creation/rules/measuring-text.md +143 -0
- package/skills/remotion-video-creation/rules/sequencing.md +106 -0
- package/skills/remotion-video-creation/rules/tailwind.md +11 -0
- package/skills/remotion-video-creation/rules/text-animations.md +20 -0
- package/skills/remotion-video-creation/rules/timing.md +179 -0
- package/skills/remotion-video-creation/rules/transcribe-captions.md +19 -0
- package/skills/remotion-video-creation/rules/transitions.md +122 -0
- package/skills/remotion-video-creation/rules/trimming.md +52 -0
- package/skills/remotion-video-creation/rules/videos.md +171 -0
- package/skills/repo-scan/SKILL.md +78 -0
- package/skills/research-ops/SKILL.md +111 -0
- package/skills/returns-reverse-logistics/SKILL.md +239 -0
- package/skills/rules-distill/SKILL.md +263 -0
- package/skills/rules-distill/scripts/scan-rules.sh +58 -0
- package/skills/rules-distill/scripts/scan-skills.sh +129 -0
- package/skills/rust-patterns/SKILL.md +498 -0
- package/skills/rust-testing/SKILL.md +499 -0
- package/skills/safety-guard/SKILL.md +74 -0
- package/skills/santa-method/SKILL.md +306 -0
- package/skills/scientific-db-pubmed-database/SKILL.md +175 -0
- package/skills/scientific-db-uspto-database/SKILL.md +177 -0
- package/skills/scientific-pkg-gget/SKILL.md +166 -0
- package/skills/scientific-thinking-literature-review/SKILL.md +192 -0
- package/skills/scientific-thinking-scholar-evaluation/SKILL.md +160 -0
- package/skills/search-first/SKILL.md +181 -0
- package/skills/security-bounty-hunter/SKILL.md +99 -0
- package/skills/security-review/SKILL.md +502 -0
- package/skills/security-review/cloud-infrastructure-security.md +361 -0
- package/skills/seo/SKILL.md +153 -0
- package/skills/skill-comply/SKILL.md +57 -0
- package/skills/skill-comply/fixtures/compliant_trace.jsonl +5 -0
- package/skills/skill-comply/fixtures/noncompliant_trace.jsonl +3 -0
- package/skills/skill-comply/fixtures/tdd_spec.yaml +44 -0
- package/skills/skill-comply/prompts/classifier.md +24 -0
- package/skills/skill-comply/prompts/scenario_generator.md +62 -0
- package/skills/skill-comply/prompts/spec_generator.md +42 -0
- package/skills/skill-comply/pyproject.toml +15 -0
- package/skills/skill-comply/scripts/__init__.py +0 -0
- package/skills/skill-comply/scripts/classifier.py +85 -0
- package/skills/skill-comply/scripts/grader.py +124 -0
- package/skills/skill-comply/scripts/parser.py +107 -0
- package/skills/skill-comply/scripts/report.py +170 -0
- package/skills/skill-comply/scripts/run.py +127 -0
- package/skills/skill-comply/scripts/runner.py +186 -0
- package/skills/skill-comply/scripts/scenario_generator.py +70 -0
- package/skills/skill-comply/scripts/spec_generator.py +72 -0
- package/skills/skill-comply/scripts/utils.py +13 -0
- package/skills/skill-comply/tests/test_grader.py +197 -0
- package/skills/skill-comply/tests/test_parser.py +90 -0
- package/skills/skill-comply/tests/test_runner.py +172 -0
- package/skills/skill-scout/SKILL.md +139 -0
- package/skills/skill-stocktake/SKILL.md +193 -0
- package/skills/skill-stocktake/scripts/quick-diff.sh +87 -0
- package/skills/skill-stocktake/scripts/save-results.sh +56 -0
- package/skills/skill-stocktake/scripts/scan.sh +170 -0
- package/skills/social-graph-ranker/SKILL.md +153 -0
- package/skills/springboot-patterns/SKILL.md +313 -0
- package/skills/springboot-security/SKILL.md +271 -0
- package/skills/springboot-tdd/SKILL.md +157 -0
- package/skills/springboot-verification/SKILL.md +230 -0
- package/skills/strategic-compact/SKILL.md +129 -0
- package/skills/strategic-compact/suggest-compact.sh +54 -0
- package/skills/swift-actor-persistence/SKILL.md +142 -0
- package/skills/swift-concurrency-6-2/SKILL.md +216 -0
- package/skills/swift-protocol-di-testing/SKILL.md +189 -0
- package/skills/swiftui-patterns/SKILL.md +259 -0
- package/skills/tdd-workflow/SKILL.md +462 -0
- package/skills/team-builder/SKILL.md +166 -0
- package/skills/terminal-ops/SKILL.md +108 -0
- package/skills/tinystruct-patterns/SKILL.md +130 -0
- package/skills/tinystruct-patterns/references/architecture.md +77 -0
- package/skills/tinystruct-patterns/references/data-handling.md +35 -0
- package/skills/tinystruct-patterns/references/routing.md +57 -0
- package/skills/tinystruct-patterns/references/system-usage.md +74 -0
- package/skills/tinystruct-patterns/references/testing.md +59 -0
- package/skills/token-budget-advisor/SKILL.md +133 -0
- package/skills/ui-demo/SKILL.md +464 -0
- package/skills/ui-to-vue/SKILL.md +134 -0
- package/skills/unified-notifications-ops/SKILL.md +186 -0
- package/skills/verification-loop/SKILL.md +125 -0
- package/skills/video-editing/SKILL.md +309 -0
- package/skills/videodb/SKILL.md +373 -0
- package/skills/videodb/reference/api-reference.md +550 -0
- package/skills/videodb/reference/capture-reference.md +407 -0
- package/skills/videodb/reference/capture.md +101 -0
- package/skills/videodb/reference/editor.md +443 -0
- package/skills/videodb/reference/generative.md +331 -0
- package/skills/videodb/reference/rtstream-reference.md +564 -0
- package/skills/videodb/reference/rtstream.md +65 -0
- package/skills/videodb/reference/search.md +230 -0
- package/skills/videodb/reference/streaming.md +406 -0
- package/skills/videodb/reference/use-cases.md +118 -0
- package/skills/videodb/scripts/ws_listener.py +282 -0
- package/skills/visa-doc-translate/README.md +86 -0
- package/skills/visa-doc-translate/SKILL.md +117 -0
- package/skills/vite-patterns/SKILL.md +448 -0
- package/skills/windows-desktop-e2e/SKILL.md +787 -0
- package/skills/workspace-surface-audit/SKILL.md +124 -0
- package/skills/x-api/SKILL.md +233 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Continuous Learning v2 - Observation Hook
|
|
3
|
+
#
|
|
4
|
+
# Captures tool use events for pattern analysis.
|
|
5
|
+
# Claude Code passes hook data via stdin as JSON.
|
|
6
|
+
#
|
|
7
|
+
# v2.1: Project-scoped observations — detects current project context
|
|
8
|
+
# and writes observations to project-specific directory.
|
|
9
|
+
#
|
|
10
|
+
# Registered via plugin hooks/hooks.json (auto-loaded when plugin is enabled).
|
|
11
|
+
# Can also be registered manually in ~/.claude/settings.json.
|
|
12
|
+
|
|
13
|
+
set -e
|
|
14
|
+
|
|
15
|
+
# Hook phase from CLI argument: "pre" (PreToolUse) or "post" (PostToolUse).
|
|
16
|
+
# Manual settings.json installs can call this script without the plugin
|
|
17
|
+
# wrapper's positional phase argument, but Claude Code still exposes the hook
|
|
18
|
+
# event name in CLAUDE_HOOK_EVENT_NAME. Fall back to that env var before
|
|
19
|
+
# defaulting to post so manually registered PreToolUse hooks are recorded as
|
|
20
|
+
# tool_start instead of being silently misclassified as tool_complete.
|
|
21
|
+
HOOK_PHASE="${1:-}"
|
|
22
|
+
if [ -z "$HOOK_PHASE" ]; then
|
|
23
|
+
case "${CLAUDE_HOOK_EVENT_NAME:-}" in
|
|
24
|
+
PreToolUse|pretooluse|pre_tool_use|pre) HOOK_PHASE="pre" ;;
|
|
25
|
+
PostToolUse|posttooluse|post_tool_use|post) HOOK_PHASE="post" ;;
|
|
26
|
+
*) HOOK_PHASE="post" ;;
|
|
27
|
+
esac
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# ─────────────────────────────────────────────
|
|
31
|
+
# Read stdin first (before project detection)
|
|
32
|
+
# ─────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
# Read JSON from stdin (Claude Code hook format)
|
|
35
|
+
INPUT_JSON=$(cat)
|
|
36
|
+
|
|
37
|
+
# Exit if no input
|
|
38
|
+
if [ -z "$INPUT_JSON" ]; then
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
_is_windows_app_installer_stub() {
|
|
43
|
+
# Windows 10/11 ships an "App Execution Alias" stub at
|
|
44
|
+
# %LOCALAPPDATA%\Microsoft\WindowsApps\python.exe
|
|
45
|
+
# %LOCALAPPDATA%\Microsoft\WindowsApps\python3.exe
|
|
46
|
+
# Both are symlinks to AppInstallerPythonRedirector.exe which, when Python
|
|
47
|
+
# is not installed from the Store, neither launches Python nor honors "-c".
|
|
48
|
+
# Calls to it hang or print a bare "Python " line, silently breaking every
|
|
49
|
+
# JSON-parsing step in this hook. Detect and skip such stubs here.
|
|
50
|
+
local _candidate="$1"
|
|
51
|
+
[ -z "$_candidate" ] && return 1
|
|
52
|
+
local _resolved
|
|
53
|
+
_resolved="$(command -v "$_candidate" 2>/dev/null || true)"
|
|
54
|
+
[ -z "$_resolved" ] && return 1
|
|
55
|
+
case "$_resolved" in
|
|
56
|
+
*AppInstallerPythonRedirector.exe|*AppInstallerPythonRedirector.EXE) return 0 ;;
|
|
57
|
+
esac
|
|
58
|
+
# Also resolve one level of symlink on POSIX-like shells (Git Bash, WSL).
|
|
59
|
+
if command -v readlink >/dev/null 2>&1; then
|
|
60
|
+
local _target
|
|
61
|
+
_target="$(readlink -f "$_resolved" 2>/dev/null || readlink "$_resolved" 2>/dev/null || true)"
|
|
62
|
+
case "$_target" in
|
|
63
|
+
*AppInstallerPythonRedirector.exe|*AppInstallerPythonRedirector.EXE) return 0 ;;
|
|
64
|
+
esac
|
|
65
|
+
fi
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
resolve_python_cmd() {
|
|
70
|
+
if [ -n "${CLV2_PYTHON_CMD:-}" ] && command -v "$CLV2_PYTHON_CMD" >/dev/null 2>&1; then
|
|
71
|
+
printf '%s\n' "$CLV2_PYTHON_CMD"
|
|
72
|
+
return 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if command -v python3 >/dev/null 2>&1 && ! _is_windows_app_installer_stub python3; then
|
|
76
|
+
printf '%s\n' python3
|
|
77
|
+
return 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
if command -v python >/dev/null 2>&1 && ! _is_windows_app_installer_stub python; then
|
|
81
|
+
printf '%s\n' python
|
|
82
|
+
return 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
return 1
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
PYTHON_CMD="$(resolve_python_cmd 2>/dev/null || true)"
|
|
89
|
+
if [ -z "$PYTHON_CMD" ]; then
|
|
90
|
+
echo "[observe] No python interpreter found, skipping observation" >&2
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Propagate our stub-aware selection so detect-project.sh (which is sourced
|
|
95
|
+
# below) does not re-resolve and silently fall back to the App Installer stub.
|
|
96
|
+
# detect-project.sh honors an already-set CLV2_PYTHON_CMD.
|
|
97
|
+
export CLV2_PYTHON_CMD="${CLV2_PYTHON_CMD:-$PYTHON_CMD}"
|
|
98
|
+
|
|
99
|
+
# ─────────────────────────────────────────────
|
|
100
|
+
# Extract cwd from stdin for project detection
|
|
101
|
+
# ─────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
# Extract cwd from the hook JSON to use for project detection.
|
|
104
|
+
# If cwd is a subdirectory inside a git repo, resolve it to the repo root so
|
|
105
|
+
# observations attach to the project instead of a nested path.
|
|
106
|
+
STDIN_CWD=$(echo "$INPUT_JSON" | "$PYTHON_CMD" -c '
|
|
107
|
+
import json, sys
|
|
108
|
+
try:
|
|
109
|
+
data = json.load(sys.stdin)
|
|
110
|
+
cwd = data.get("cwd", "")
|
|
111
|
+
print(cwd)
|
|
112
|
+
except(KeyError, TypeError, ValueError):
|
|
113
|
+
print("")
|
|
114
|
+
' 2>/dev/null || echo "")
|
|
115
|
+
|
|
116
|
+
# If cwd was provided in stdin, use it for project detection
|
|
117
|
+
if [ -n "$STDIN_CWD" ] && [ -d "$STDIN_CWD" ]; then
|
|
118
|
+
_GIT_ROOT=$(git -C "$STDIN_CWD" rev-parse --show-toplevel 2>/dev/null || true)
|
|
119
|
+
export CLAUDE_PROJECT_DIR="${_GIT_ROOT:-$STDIN_CWD}"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# ─────────────────────────────────────────────
|
|
123
|
+
# Lightweight config and automated session guards
|
|
124
|
+
# ─────────────────────────────────────────────
|
|
125
|
+
#
|
|
126
|
+
# IMPORTANT: keep these guards above detect-project.sh.
|
|
127
|
+
# Sourcing detect-project.sh creates project-scoped directories and updates
|
|
128
|
+
# projects.json, so automated sessions must return before that point.
|
|
129
|
+
|
|
130
|
+
# shellcheck disable=SC1091
|
|
131
|
+
. "$(dirname "$0")/../scripts/lib/homunculus-dir.sh"
|
|
132
|
+
CONFIG_DIR="$(_sf_resolve_homunculus_dir)"
|
|
133
|
+
|
|
134
|
+
# Skip if disabled (check both default and CLV2_CONFIG-derived locations)
|
|
135
|
+
if [ -f "$CONFIG_DIR/disabled" ]; then
|
|
136
|
+
exit 0
|
|
137
|
+
fi
|
|
138
|
+
if [ -n "${CLV2_CONFIG:-}" ] && [ -f "$(dirname "$CLV2_CONFIG")/disabled" ]; then
|
|
139
|
+
exit 0
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# Prevent observe.sh from firing on non-human sessions to avoid:
|
|
143
|
+
# - the toolset observing its own Haiku observer sessions (self-loop)
|
|
144
|
+
# - the toolset observing other tools' automated sessions
|
|
145
|
+
# - automated sessions creating project-scoped homunculus metadata
|
|
146
|
+
|
|
147
|
+
# Layer 1: entrypoint. Only interactive terminal sessions should continue.
|
|
148
|
+
# sdk-ts: Agent SDK sessions can be human-interactive (e.g. via Happy).
|
|
149
|
+
# Non-interactive SDK automation is still filtered by Layers 2-5 below
|
|
150
|
+
# (SKILLFORGE_HOOK_PROFILE=minimal, SKILLFORGE_SKIP_OBSERVE=1, agent_id, path exclusions).
|
|
151
|
+
case "${CLAUDE_CODE_ENTRYPOINT:-cli}" in
|
|
152
|
+
cli|sdk-ts|claude-desktop) ;;
|
|
153
|
+
*) exit 0 ;;
|
|
154
|
+
esac
|
|
155
|
+
|
|
156
|
+
# Layer 2: minimal hook profile suppresses non-essential hooks.
|
|
157
|
+
[ "${SKILLFORGE_HOOK_PROFILE:-standard}" = "minimal" ] && exit 0
|
|
158
|
+
|
|
159
|
+
# Layer 3: cooperative skip env var for automated sessions.
|
|
160
|
+
[ "${SKILLFORGE_SKIP_OBSERVE:-0}" = "1" ] && exit 0
|
|
161
|
+
|
|
162
|
+
# Layer 4: subagent sessions are automated by definition.
|
|
163
|
+
_SKILLFORGE_AGENT_ID=$(echo "$INPUT_JSON" | "$PYTHON_CMD" -c "import json,sys; print(json.load(sys.stdin).get('agent_id',''))" 2>/dev/null || true)
|
|
164
|
+
[ -n "$_SKILLFORGE_AGENT_ID" ] && exit 0
|
|
165
|
+
|
|
166
|
+
# Layer 5: known observer-session path exclusions.
|
|
167
|
+
_SKILLFORGE_SKIP_PATHS="${SKILLFORGE_OBSERVE_SKIP_PATHS:-observer-sessions,.claude-mem}"
|
|
168
|
+
if [ -n "$STDIN_CWD" ]; then
|
|
169
|
+
IFS=',' read -ra _SKILLFORGE_SKIP_ARRAY <<< "$_SKILLFORGE_SKIP_PATHS"
|
|
170
|
+
for _pattern in "${_SKILLFORGE_SKIP_ARRAY[@]}"; do
|
|
171
|
+
_pattern="${_pattern#"${_pattern%%[![:space:]]*}"}"
|
|
172
|
+
_pattern="${_pattern%"${_pattern##*[![:space:]]}"}"
|
|
173
|
+
[ -z "$_pattern" ] && continue
|
|
174
|
+
case "$STDIN_CWD" in *"$_pattern"*) exit 0 ;; esac
|
|
175
|
+
done
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# ─────────────────────────────────────────────
|
|
179
|
+
# Project detection
|
|
180
|
+
# ─────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
183
|
+
SKILL_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
184
|
+
|
|
185
|
+
# Source shared project detection helper
|
|
186
|
+
# This sets: PROJECT_ID, PROJECT_NAME, PROJECT_ROOT, PROJECT_DIR
|
|
187
|
+
source "${SKILL_ROOT}/scripts/detect-project.sh"
|
|
188
|
+
PYTHON_CMD="${CLV2_PYTHON_CMD:-$PYTHON_CMD}"
|
|
189
|
+
|
|
190
|
+
# ─────────────────────────────────────────────
|
|
191
|
+
# Configuration
|
|
192
|
+
# ─────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
OBSERVATIONS_FILE="${PROJECT_DIR}/observations.jsonl"
|
|
195
|
+
MAX_FILE_SIZE_MB=10
|
|
196
|
+
|
|
197
|
+
# Auto-purge observation files older than 30 days (runs once per session)
|
|
198
|
+
PURGE_MARKER="${PROJECT_DIR}/.last-purge"
|
|
199
|
+
if [ ! -f "$PURGE_MARKER" ] || [ "$(find "$PURGE_MARKER" -mtime +1 2>/dev/null)" ]; then
|
|
200
|
+
find "${PROJECT_DIR}" -name "observations-*.jsonl" -mtime +30 -delete 2>/dev/null || true
|
|
201
|
+
touch "$PURGE_MARKER" 2>/dev/null || true
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
# Parse using Python via stdin pipe (safe for all JSON payloads)
|
|
205
|
+
# Pass HOOK_PHASE via env var since Claude Code does not include hook type in stdin JSON
|
|
206
|
+
PARSED=$(echo "$INPUT_JSON" | HOOK_PHASE="$HOOK_PHASE" "$PYTHON_CMD" -c '
|
|
207
|
+
import json
|
|
208
|
+
import sys
|
|
209
|
+
import os
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
data = json.load(sys.stdin)
|
|
213
|
+
|
|
214
|
+
# Determine event type from CLI argument passed via env var.
|
|
215
|
+
# Claude Code does NOT include a "hook_type" field in the stdin JSON,
|
|
216
|
+
# so we rely on the shell argument ("pre" or "post") instead.
|
|
217
|
+
hook_phase = os.environ.get("HOOK_PHASE", "post")
|
|
218
|
+
event = "tool_start" if hook_phase == "pre" else "tool_complete"
|
|
219
|
+
|
|
220
|
+
# Extract fields - Claude Code hook format
|
|
221
|
+
tool_name = data.get("tool_name", data.get("tool", "unknown"))
|
|
222
|
+
tool_input = data.get("tool_input", data.get("input", {}))
|
|
223
|
+
tool_output = data.get("tool_response")
|
|
224
|
+
if tool_output is None:
|
|
225
|
+
tool_output = data.get("tool_output", data.get("output", ""))
|
|
226
|
+
session_id = data.get("session_id", "unknown")
|
|
227
|
+
tool_use_id = data.get("tool_use_id", "")
|
|
228
|
+
cwd = data.get("cwd", "")
|
|
229
|
+
|
|
230
|
+
# Truncate large inputs/outputs
|
|
231
|
+
if isinstance(tool_input, dict):
|
|
232
|
+
tool_input_str = json.dumps(tool_input)[:5000]
|
|
233
|
+
else:
|
|
234
|
+
tool_input_str = str(tool_input)[:5000]
|
|
235
|
+
|
|
236
|
+
if isinstance(tool_output, dict):
|
|
237
|
+
tool_response_str = json.dumps(tool_output)[:5000]
|
|
238
|
+
else:
|
|
239
|
+
tool_response_str = str(tool_output)[:5000]
|
|
240
|
+
|
|
241
|
+
print(json.dumps({
|
|
242
|
+
"parsed": True,
|
|
243
|
+
"event": event,
|
|
244
|
+
"tool": tool_name,
|
|
245
|
+
"input": tool_input_str if event == "tool_start" else None,
|
|
246
|
+
"output": tool_response_str if event == "tool_complete" else None,
|
|
247
|
+
"session": session_id,
|
|
248
|
+
"tool_use_id": tool_use_id,
|
|
249
|
+
"cwd": cwd
|
|
250
|
+
}))
|
|
251
|
+
except Exception as e:
|
|
252
|
+
print(json.dumps({"parsed": False, "error": str(e)}))
|
|
253
|
+
')
|
|
254
|
+
|
|
255
|
+
# Check if parsing succeeded
|
|
256
|
+
PARSED_OK=$(echo "$PARSED" | "$PYTHON_CMD" -c "import json,sys; print(json.load(sys.stdin).get('parsed', False))" 2>/dev/null || echo "False")
|
|
257
|
+
|
|
258
|
+
if [ "$PARSED_OK" != "True" ]; then
|
|
259
|
+
# Fallback: log raw input for debugging (scrub secrets before persisting)
|
|
260
|
+
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
261
|
+
export TIMESTAMP="$timestamp"
|
|
262
|
+
echo "$INPUT_JSON" | "$PYTHON_CMD" -c '
|
|
263
|
+
import json, sys, os, re
|
|
264
|
+
|
|
265
|
+
_SECRET_RE = re.compile(
|
|
266
|
+
r"(?i)(api[_-]?key|token|secret|password|authorization|credentials?|auth)"
|
|
267
|
+
r"""(["'"'"'\s:=]+)"""
|
|
268
|
+
r"([A-Za-z]+\s+)?"
|
|
269
|
+
r"([A-Za-z0-9_\-/.+=]{8,})"
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
raw = sys.stdin.read()[:2000]
|
|
273
|
+
raw = _SECRET_RE.sub(lambda m: m.group(1) + m.group(2) + (m.group(3) or "") + "[REDACTED]", raw)
|
|
274
|
+
print(json.dumps({"timestamp": os.environ["TIMESTAMP"], "event": "parse_error", "raw": raw}))
|
|
275
|
+
' >> "$OBSERVATIONS_FILE"
|
|
276
|
+
exit 0
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# Archive if file too large (atomic: rename with unique suffix to avoid race)
|
|
280
|
+
if [ -f "$OBSERVATIONS_FILE" ]; then
|
|
281
|
+
file_size_mb=$(du -m "$OBSERVATIONS_FILE" 2>/dev/null | cut -f1)
|
|
282
|
+
if [ "${file_size_mb:-0}" -ge "$MAX_FILE_SIZE_MB" ]; then
|
|
283
|
+
archive_dir="${PROJECT_DIR}/observations.archive"
|
|
284
|
+
mkdir -p "$archive_dir"
|
|
285
|
+
mv "$OBSERVATIONS_FILE" "$archive_dir/observations-$(date +%Y%m%d-%H%M%S)-$$.jsonl" 2>/dev/null || true
|
|
286
|
+
fi
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
# Build and write observation (now includes project context)
|
|
290
|
+
# Scrub common secret patterns from tool I/O before persisting
|
|
291
|
+
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
292
|
+
|
|
293
|
+
export PROJECT_ID_ENV="$PROJECT_ID"
|
|
294
|
+
export PROJECT_NAME_ENV="$PROJECT_NAME"
|
|
295
|
+
export TIMESTAMP="$timestamp"
|
|
296
|
+
|
|
297
|
+
echo "$PARSED" | "$PYTHON_CMD" -c '
|
|
298
|
+
import json, sys, os, re
|
|
299
|
+
|
|
300
|
+
parsed = json.load(sys.stdin)
|
|
301
|
+
observation = {
|
|
302
|
+
"timestamp": os.environ["TIMESTAMP"],
|
|
303
|
+
"event": parsed["event"],
|
|
304
|
+
"tool": parsed["tool"],
|
|
305
|
+
"session": parsed["session"],
|
|
306
|
+
"project_id": os.environ.get("PROJECT_ID_ENV", "global"),
|
|
307
|
+
"project_name": os.environ.get("PROJECT_NAME_ENV", "global")
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Scrub secrets: match common key=value, key: value, and key"value patterns
|
|
311
|
+
# Includes optional auth scheme (e.g., "Bearer", "Basic") before token
|
|
312
|
+
_SECRET_RE = re.compile(
|
|
313
|
+
r"(?i)(api[_-]?key|token|secret|password|authorization|credentials?|auth)"
|
|
314
|
+
r"""(["'"'"'\s:=]+)"""
|
|
315
|
+
r"([A-Za-z]+\s+)?"
|
|
316
|
+
r"([A-Za-z0-9_\-/.+=]{8,})"
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
def scrub(val):
|
|
320
|
+
if val is None:
|
|
321
|
+
return None
|
|
322
|
+
return _SECRET_RE.sub(lambda m: m.group(1) + m.group(2) + (m.group(3) or "") + "[REDACTED]", str(val))
|
|
323
|
+
|
|
324
|
+
if parsed["input"]:
|
|
325
|
+
observation["input"] = scrub(parsed["input"])
|
|
326
|
+
if parsed["output"] is not None:
|
|
327
|
+
observation["output"] = scrub(parsed["output"])
|
|
328
|
+
|
|
329
|
+
print(json.dumps(observation))
|
|
330
|
+
' >> "$OBSERVATIONS_FILE"
|
|
331
|
+
|
|
332
|
+
# Lazy-start observer if enabled but not running (first-time setup)
|
|
333
|
+
# Use flock for atomic check-then-act to prevent race conditions
|
|
334
|
+
# Fallback for macOS (no flock): use lockfile or skip
|
|
335
|
+
LAZY_START_LOCK="${PROJECT_DIR}/.observer-start.lock"
|
|
336
|
+
_CHECK_OBSERVER_RUNNING() {
|
|
337
|
+
local pid_file="$1"
|
|
338
|
+
if [ -f "$pid_file" ]; then
|
|
339
|
+
local pid
|
|
340
|
+
pid=$(cat "$pid_file" 2>/dev/null)
|
|
341
|
+
# Validate PID is a positive integer (>1) to prevent signaling invalid targets
|
|
342
|
+
case "$pid" in
|
|
343
|
+
''|*[!0-9]*|0|1)
|
|
344
|
+
rm -f "$pid_file" 2>/dev/null || true
|
|
345
|
+
return 1
|
|
346
|
+
;;
|
|
347
|
+
esac
|
|
348
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
349
|
+
return 0 # Process is alive
|
|
350
|
+
fi
|
|
351
|
+
# Stale PID file - remove it
|
|
352
|
+
rm -f "$pid_file" 2>/dev/null || true
|
|
353
|
+
fi
|
|
354
|
+
return 1 # No PID file or process dead
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if [ -f "${CONFIG_DIR}/disabled" ]; then
|
|
358
|
+
OBSERVER_ENABLED=false
|
|
359
|
+
else
|
|
360
|
+
OBSERVER_ENABLED=false
|
|
361
|
+
if [ -n "${CLV2_CONFIG:-}" ]; then
|
|
362
|
+
CONFIG_FILE="$CLV2_CONFIG"
|
|
363
|
+
elif [ -f "${CONFIG_DIR}/config.json" ]; then
|
|
364
|
+
CONFIG_FILE="${CONFIG_DIR}/config.json"
|
|
365
|
+
else
|
|
366
|
+
CONFIG_FILE="${SKILL_ROOT}/config.json"
|
|
367
|
+
fi
|
|
368
|
+
# Use effective config path for both existence check and reading
|
|
369
|
+
EFFECTIVE_CONFIG="$CONFIG_FILE"
|
|
370
|
+
if [ -f "$EFFECTIVE_CONFIG" ] && [ -n "$PYTHON_CMD" ]; then
|
|
371
|
+
_enabled=$(CLV2_CONFIG_PATH="$EFFECTIVE_CONFIG" "$PYTHON_CMD" -c "
|
|
372
|
+
import json, os
|
|
373
|
+
with open(os.environ['CLV2_CONFIG_PATH']) as f:
|
|
374
|
+
cfg = json.load(f)
|
|
375
|
+
print(str(cfg.get('observer', {}).get('enabled', False)).lower())
|
|
376
|
+
" 2>/dev/null || echo "false")
|
|
377
|
+
if [ "$_enabled" = "true" ]; then
|
|
378
|
+
OBSERVER_ENABLED=true
|
|
379
|
+
fi
|
|
380
|
+
fi
|
|
381
|
+
fi
|
|
382
|
+
|
|
383
|
+
# Check both project-scoped AND global PID files (with stale PID recovery)
|
|
384
|
+
if [ "$OBSERVER_ENABLED" = "true" ]; then
|
|
385
|
+
# Clean up stale PID files first
|
|
386
|
+
_CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
|
|
387
|
+
_CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
|
|
388
|
+
|
|
389
|
+
# Check if observer is now running after cleanup
|
|
390
|
+
if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
|
|
391
|
+
# Use flock if available (Linux), fallback for macOS
|
|
392
|
+
if command -v flock >/dev/null 2>&1; then
|
|
393
|
+
(
|
|
394
|
+
flock -n 9 || exit 0
|
|
395
|
+
# Double-check PID files after acquiring lock
|
|
396
|
+
_CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
|
|
397
|
+
_CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
|
|
398
|
+
if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
|
|
399
|
+
nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
|
|
400
|
+
fi
|
|
401
|
+
) 9>"$LAZY_START_LOCK"
|
|
402
|
+
else
|
|
403
|
+
# macOS fallback: use lockfile if available, otherwise mkdir-based lock
|
|
404
|
+
if command -v lockfile >/dev/null 2>&1; then
|
|
405
|
+
# Use subshell to isolate exit and add trap for cleanup
|
|
406
|
+
(
|
|
407
|
+
trap 'rm -f "$LAZY_START_LOCK" 2>/dev/null || true' EXIT
|
|
408
|
+
lockfile -r 1 -l 30 "$LAZY_START_LOCK" 2>/dev/null || exit 0
|
|
409
|
+
_CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
|
|
410
|
+
_CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
|
|
411
|
+
if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
|
|
412
|
+
nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
|
|
413
|
+
fi
|
|
414
|
+
rm -f "$LAZY_START_LOCK" 2>/dev/null || true
|
|
415
|
+
)
|
|
416
|
+
else
|
|
417
|
+
# POSIX fallback: mkdir is atomic -- fails if dir already exists
|
|
418
|
+
(
|
|
419
|
+
trap 'rmdir "${LAZY_START_LOCK}.d" 2>/dev/null || true' EXIT
|
|
420
|
+
mkdir "${LAZY_START_LOCK}.d" 2>/dev/null || exit 0
|
|
421
|
+
_CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
|
|
422
|
+
_CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
|
|
423
|
+
if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
|
|
424
|
+
nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
|
|
425
|
+
fi
|
|
426
|
+
)
|
|
427
|
+
fi
|
|
428
|
+
fi
|
|
429
|
+
fi
|
|
430
|
+
fi
|
|
431
|
+
|
|
432
|
+
# Throttle SIGUSR1: only signal observer every N observations (#521)
|
|
433
|
+
# This prevents rapid signaling when tool calls fire every second,
|
|
434
|
+
# which caused runaway parallel Claude analysis processes.
|
|
435
|
+
SIGNAL_EVERY_N="${SKILLFORGE_OBSERVER_SIGNAL_EVERY_N:-20}"
|
|
436
|
+
SIGNAL_COUNTER_FILE="${PROJECT_DIR}/.observer-signal-counter"
|
|
437
|
+
ACTIVITY_FILE="${PROJECT_DIR}/.observer-last-activity"
|
|
438
|
+
|
|
439
|
+
touch "$ACTIVITY_FILE" 2>/dev/null || true
|
|
440
|
+
|
|
441
|
+
should_signal=0
|
|
442
|
+
if [ -f "$SIGNAL_COUNTER_FILE" ]; then
|
|
443
|
+
counter=$(cat "$SIGNAL_COUNTER_FILE" 2>/dev/null || echo 0)
|
|
444
|
+
counter=$((counter + 1))
|
|
445
|
+
if [ "$counter" -ge "$SIGNAL_EVERY_N" ]; then
|
|
446
|
+
should_signal=1
|
|
447
|
+
counter=0
|
|
448
|
+
fi
|
|
449
|
+
echo "$counter" > "$SIGNAL_COUNTER_FILE"
|
|
450
|
+
else
|
|
451
|
+
echo "1" > "$SIGNAL_COUNTER_FILE"
|
|
452
|
+
fi
|
|
453
|
+
|
|
454
|
+
# Signal observer if running and throttle allows (check both project-scoped and global observer, deduplicate)
|
|
455
|
+
if [ "$should_signal" -eq 1 ]; then
|
|
456
|
+
signaled_pids=" "
|
|
457
|
+
for pid_file in "${PROJECT_DIR}/.observer.pid" "${CONFIG_DIR}/.observer.pid"; do
|
|
458
|
+
if [ -f "$pid_file" ]; then
|
|
459
|
+
observer_pid=$(cat "$pid_file" 2>/dev/null || true)
|
|
460
|
+
# Validate PID is a positive integer (>1)
|
|
461
|
+
case "$observer_pid" in
|
|
462
|
+
''|*[!0-9]*|0|1) rm -f "$pid_file" 2>/dev/null || true; continue ;;
|
|
463
|
+
esac
|
|
464
|
+
# Deduplicate: skip if already signaled this pass
|
|
465
|
+
case "$signaled_pids" in
|
|
466
|
+
*" $observer_pid "*) continue ;;
|
|
467
|
+
esac
|
|
468
|
+
if kill -0 "$observer_pid" 2>/dev/null; then
|
|
469
|
+
kill -USR1 "$observer_pid" 2>/dev/null || true
|
|
470
|
+
signaled_pids="${signaled_pids}${observer_pid} "
|
|
471
|
+
fi
|
|
472
|
+
fi
|
|
473
|
+
done
|
|
474
|
+
fi
|
|
475
|
+
|
|
476
|
+
exit 0
|