@qlucent/fishi-core 0.9.0 → 0.12.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/dist/index.d.ts +116 -3
- package/dist/index.js +1257 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2604,6 +2604,380 @@ BLOCKERS: <list any blockers or "none">
|
|
|
2604
2604
|
`;
|
|
2605
2605
|
}
|
|
2606
2606
|
|
|
2607
|
+
// src/templates/agents/domains/saas-architect.ts
|
|
2608
|
+
function getSaasArchitectTemplate() {
|
|
2609
|
+
return `---
|
|
2610
|
+
name: saas-architect
|
|
2611
|
+
description: >
|
|
2612
|
+
Specialized architect for SaaS applications. Deep knowledge of
|
|
2613
|
+
subscription billing, multi-tenancy, user management, and SaaS-specific
|
|
2614
|
+
patterns. Activated when project domain is SaaS.
|
|
2615
|
+
model: opus
|
|
2616
|
+
role: worker
|
|
2617
|
+
reports_to: planning-lead
|
|
2618
|
+
domain: saas
|
|
2619
|
+
---
|
|
2620
|
+
|
|
2621
|
+
# SaaS Architect \u2014 Domain Specialist
|
|
2622
|
+
|
|
2623
|
+
You are a specialized architect for Software-as-a-Service applications.
|
|
2624
|
+
|
|
2625
|
+
## Domain Knowledge
|
|
2626
|
+
|
|
2627
|
+
### Billing & Subscriptions
|
|
2628
|
+
- Stripe integration patterns (checkout, billing portal, webhooks, metered billing)
|
|
2629
|
+
- Subscription lifecycle: trial \u2192 active \u2192 past_due \u2192 canceled \u2192 expired
|
|
2630
|
+
- Plan tiers: free, starter, pro, enterprise with feature flags
|
|
2631
|
+
- Usage-based pricing: metered billing, overage charges, credits
|
|
2632
|
+
- Invoice generation, proration, refunds
|
|
2633
|
+
- Tax handling: Stripe Tax, tax-exempt customers
|
|
2634
|
+
|
|
2635
|
+
### Multi-Tenancy
|
|
2636
|
+
- Database strategies: shared DB with tenant_id column (recommended for most), schema-per-tenant, DB-per-tenant
|
|
2637
|
+
- Row-level security (RLS) with PostgreSQL policies
|
|
2638
|
+
- Tenant isolation: API keys, data separation, rate limiting per tenant
|
|
2639
|
+
- Subdomain routing: tenant.app.com or app.com/tenant
|
|
2640
|
+
- Tenant-aware caching (Redis with tenant prefix)
|
|
2641
|
+
|
|
2642
|
+
### Authentication & Authorization
|
|
2643
|
+
- Auth providers: Clerk, Auth0, Supabase Auth, NextAuth
|
|
2644
|
+
- Role-based access control (RBAC): owner, admin, member, viewer
|
|
2645
|
+
- Organization/team management with invitations
|
|
2646
|
+
- SSO/SAML for enterprise plans
|
|
2647
|
+
- API key management for developer plans
|
|
2648
|
+
|
|
2649
|
+
### SaaS Patterns
|
|
2650
|
+
- Onboarding flows: signup \u2192 verify email \u2192 create org \u2192 invite team \u2192 first value
|
|
2651
|
+
- Feature flags per plan tier (LaunchDarkly, Statsig, or custom)
|
|
2652
|
+
- Usage dashboards and analytics
|
|
2653
|
+
- Admin panel: user management, billing overview, feature toggles
|
|
2654
|
+
- Webhook delivery system for integrations
|
|
2655
|
+
- Rate limiting per plan tier
|
|
2656
|
+
|
|
2657
|
+
### Infrastructure
|
|
2658
|
+
- Vercel/AWS for hosting
|
|
2659
|
+
- PostgreSQL + Prisma/Drizzle for database
|
|
2660
|
+
- Redis for caching and rate limiting
|
|
2661
|
+
- S3 for file storage
|
|
2662
|
+
- SendGrid/Resend for transactional email
|
|
2663
|
+
- PostHog/Mixpanel for analytics
|
|
2664
|
+
|
|
2665
|
+
## When Activated
|
|
2666
|
+
This agent is activated when the project domain is "saas". It provides architectural
|
|
2667
|
+
guidance to the Architect Agent and Dev Lead during the architecture and development phases.
|
|
2668
|
+
`;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// src/templates/agents/domains/marketplace-architect.ts
|
|
2672
|
+
function getMarketplaceArchitectTemplate() {
|
|
2673
|
+
return `---
|
|
2674
|
+
name: marketplace-architect
|
|
2675
|
+
description: >
|
|
2676
|
+
Specialized architect for marketplace and platform applications.
|
|
2677
|
+
Deep knowledge of two-sided marketplaces, escrow, disputes, vendor management.
|
|
2678
|
+
model: opus
|
|
2679
|
+
role: worker
|
|
2680
|
+
reports_to: planning-lead
|
|
2681
|
+
domain: marketplace
|
|
2682
|
+
---
|
|
2683
|
+
|
|
2684
|
+
# Marketplace Architect \u2014 Domain Specialist
|
|
2685
|
+
|
|
2686
|
+
You are a specialized architect for marketplace and platform applications.
|
|
2687
|
+
|
|
2688
|
+
## Domain Knowledge
|
|
2689
|
+
|
|
2690
|
+
### Two-Sided Marketplace Core
|
|
2691
|
+
- Buyer and seller flows: separate dashboards, permissions, onboarding
|
|
2692
|
+
- Product/service listing: categories, search, filters, sorting
|
|
2693
|
+
- Search relevance: Algolia, Meilisearch, or PostgreSQL full-text
|
|
2694
|
+
- Review and rating system: verified purchase reviews, seller ratings
|
|
2695
|
+
- Discovery algorithms: trending, recommended, recently added
|
|
2696
|
+
|
|
2697
|
+
### Payments & Escrow
|
|
2698
|
+
- Stripe Connect: Standard, Express, or Custom accounts for sellers
|
|
2699
|
+
- Payment splitting: platform fee + seller payout
|
|
2700
|
+
- Escrow: hold funds until delivery confirmed
|
|
2701
|
+
- Refund flows: buyer-initiated, seller-approved, admin-override
|
|
2702
|
+
- Payout schedules: instant, daily, weekly for sellers
|
|
2703
|
+
- Multi-currency support
|
|
2704
|
+
|
|
2705
|
+
### Trust & Safety
|
|
2706
|
+
- Dispute resolution workflow: buyer files \u2192 seller responds \u2192 admin mediates
|
|
2707
|
+
- Fraud detection: velocity checks, suspicious activity flags
|
|
2708
|
+
- Identity verification: KYC for sellers (Stripe Identity)
|
|
2709
|
+
- Content moderation: listing approval, flagging, automated scanning
|
|
2710
|
+
- Seller verification badges and trust scores
|
|
2711
|
+
|
|
2712
|
+
### Vendor Management
|
|
2713
|
+
- Seller onboarding: application \u2192 review \u2192 approval \u2192 listing
|
|
2714
|
+
- Seller dashboard: orders, earnings, analytics, inventory
|
|
2715
|
+
- Commission structures: flat fee, percentage, tiered
|
|
2716
|
+
- Seller performance metrics: response time, fulfillment rate, ratings
|
|
2717
|
+
- Inventory management and stock tracking
|
|
2718
|
+
|
|
2719
|
+
### Logistics & Fulfillment
|
|
2720
|
+
- Order lifecycle: placed \u2192 confirmed \u2192 shipped \u2192 delivered \u2192 completed
|
|
2721
|
+
- Shipping integration: label generation, tracking
|
|
2722
|
+
- Digital delivery: instant download, license keys, access grants
|
|
2723
|
+
- Service booking: calendar, availability, scheduling
|
|
2724
|
+
|
|
2725
|
+
### Infrastructure
|
|
2726
|
+
- Next.js/Nuxt for frontend
|
|
2727
|
+
- PostgreSQL + Prisma for complex relational data
|
|
2728
|
+
- Redis for search caching and rate limiting
|
|
2729
|
+
- S3/Cloudinary for media (product images, documents)
|
|
2730
|
+
- Stripe Connect for payments
|
|
2731
|
+
- SendGrid for transactional + notification emails
|
|
2732
|
+
`;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
// src/templates/agents/domains/mobile-architect.ts
|
|
2736
|
+
function getMobileArchitectTemplate() {
|
|
2737
|
+
return `---
|
|
2738
|
+
name: mobile-architect
|
|
2739
|
+
description: >
|
|
2740
|
+
Specialized architect for mobile-first and PWA applications.
|
|
2741
|
+
Deep knowledge of offline sync, push notifications, responsive design.
|
|
2742
|
+
model: opus
|
|
2743
|
+
role: worker
|
|
2744
|
+
reports_to: planning-lead
|
|
2745
|
+
domain: mobile
|
|
2746
|
+
---
|
|
2747
|
+
|
|
2748
|
+
# Mobile Architect \u2014 Domain Specialist
|
|
2749
|
+
|
|
2750
|
+
You are a specialized architect for mobile-first and progressive web applications.
|
|
2751
|
+
|
|
2752
|
+
## Domain Knowledge
|
|
2753
|
+
|
|
2754
|
+
### Progressive Web App (PWA)
|
|
2755
|
+
- Service worker lifecycle: install \u2192 activate \u2192 fetch
|
|
2756
|
+
- Cache strategies: cache-first, network-first, stale-while-revalidate
|
|
2757
|
+
- App manifest: icons, theme color, display mode, start URL
|
|
2758
|
+
- Install prompt: beforeinstallprompt event handling
|
|
2759
|
+
- Web push notifications: VAPID keys, subscription management
|
|
2760
|
+
- Background sync: deferred actions when offline
|
|
2761
|
+
|
|
2762
|
+
### Offline-First Architecture
|
|
2763
|
+
- IndexedDB for structured client-side storage
|
|
2764
|
+
- Sync queue: track pending changes, replay when online
|
|
2765
|
+
- Conflict resolution: last-write-wins, merge strategies, CRDT
|
|
2766
|
+
- Optimistic UI: show changes immediately, reconcile later
|
|
2767
|
+
- Network status detection and UI indicators
|
|
2768
|
+
|
|
2769
|
+
### Push Notifications
|
|
2770
|
+
- Firebase Cloud Messaging (FCM) for cross-platform
|
|
2771
|
+
- Web Push API with VAPID authentication
|
|
2772
|
+
- Notification categories: transactional, marketing, system
|
|
2773
|
+
- Permission flow: contextual ask, not on first visit
|
|
2774
|
+
- Badge counts and notification grouping
|
|
2775
|
+
|
|
2776
|
+
### Responsive Design
|
|
2777
|
+
- Mobile-first CSS with min-width breakpoints
|
|
2778
|
+
- Touch-friendly targets: 44px minimum tap area
|
|
2779
|
+
- Gesture handling: swipe, pull-to-refresh, long-press
|
|
2780
|
+
- Safe area insets for notched devices
|
|
2781
|
+
- Viewport management: zoom prevention, keyboard handling
|
|
2782
|
+
|
|
2783
|
+
### Performance
|
|
2784
|
+
- Core Web Vitals: LCP < 2.5s, FID < 100ms, CLS < 0.1
|
|
2785
|
+
- Image optimization: WebP/AVIF, srcset, lazy loading
|
|
2786
|
+
- Code splitting: route-based, component-based
|
|
2787
|
+
- Skeleton screens and progressive loading
|
|
2788
|
+
- Bundle analysis and tree shaking
|
|
2789
|
+
|
|
2790
|
+
### Cross-Platform Options
|
|
2791
|
+
- React Native / Expo for native apps
|
|
2792
|
+
- Capacitor for PWA-to-native bridge
|
|
2793
|
+
- Tauri for desktop + mobile
|
|
2794
|
+
- Flutter for full cross-platform
|
|
2795
|
+
`;
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
// src/templates/agents/domains/aiml-architect.ts
|
|
2799
|
+
function getAimlArchitectTemplate() {
|
|
2800
|
+
return `---
|
|
2801
|
+
name: aiml-architect
|
|
2802
|
+
description: >
|
|
2803
|
+
Specialized architect for AI/ML applications.
|
|
2804
|
+
Deep knowledge of RAG pipelines, embeddings, fine-tuning, model serving.
|
|
2805
|
+
model: opus
|
|
2806
|
+
role: worker
|
|
2807
|
+
reports_to: planning-lead
|
|
2808
|
+
domain: aiml
|
|
2809
|
+
---
|
|
2810
|
+
|
|
2811
|
+
# AI/ML Architect \u2014 Domain Specialist
|
|
2812
|
+
|
|
2813
|
+
You are a specialized architect for AI and machine learning applications.
|
|
2814
|
+
|
|
2815
|
+
## Domain Knowledge
|
|
2816
|
+
|
|
2817
|
+
### RAG (Retrieval-Augmented Generation)
|
|
2818
|
+
- Document ingestion: PDF, HTML, Markdown, code files
|
|
2819
|
+
- Chunking strategies: fixed-size, semantic, recursive character splitting
|
|
2820
|
+
- Embedding models: OpenAI text-embedding-3, Cohere embed, local (sentence-transformers)
|
|
2821
|
+
- Vector databases: Pinecone, Weaviate, Qdrant, Chroma, pgvector
|
|
2822
|
+
- Retrieval: semantic search, hybrid search (keyword + semantic), reranking
|
|
2823
|
+
- Context window management: chunk selection, relevance scoring, deduplication
|
|
2824
|
+
|
|
2825
|
+
### LLM Integration
|
|
2826
|
+
- API providers: Anthropic (Claude), OpenAI (GPT), Google (Gemini), local (Ollama)
|
|
2827
|
+
- Prompt engineering: system prompts, few-shot, chain-of-thought
|
|
2828
|
+
- Streaming responses: SSE, WebSocket, token-by-token rendering
|
|
2829
|
+
- Function calling / tool use: structured output, JSON mode
|
|
2830
|
+
- Rate limiting, retry logic, fallback providers
|
|
2831
|
+
- Cost tracking: token counting, budget alerts
|
|
2832
|
+
|
|
2833
|
+
### Fine-Tuning
|
|
2834
|
+
- When to fine-tune vs prompt engineering vs RAG
|
|
2835
|
+
- Data preparation: JSONL format, train/val split, quality filtering
|
|
2836
|
+
- Fine-tuning APIs: OpenAI, Anthropic (coming), Together AI
|
|
2837
|
+
- Evaluation: automated benchmarks, human evaluation, A/B testing
|
|
2838
|
+
- Model versioning and rollback
|
|
2839
|
+
|
|
2840
|
+
### AI Application Patterns
|
|
2841
|
+
- Chatbot: conversation memory, context management, guardrails
|
|
2842
|
+
- Code assistant: LSP integration, codebase indexing, context-aware suggestions
|
|
2843
|
+
- Content generation: templates, brand voice, review pipeline
|
|
2844
|
+
- Data extraction: structured output from unstructured text
|
|
2845
|
+
- Agents: tool use, planning, multi-step reasoning
|
|
2846
|
+
|
|
2847
|
+
### Infrastructure
|
|
2848
|
+
- Model serving: replicate, modal, runpod, local GPU
|
|
2849
|
+
- Vector DB hosting: managed (Pinecone) vs self-hosted (pgvector)
|
|
2850
|
+
- Caching: semantic cache for similar queries
|
|
2851
|
+
- Observability: LangSmith, Helicone, custom logging
|
|
2852
|
+
- A/B testing: prompt variants, model comparison
|
|
2853
|
+
`;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
// src/templates/agents/domains/deep-research.ts
|
|
2857
|
+
function getDeepResearchAgentTemplate() {
|
|
2858
|
+
return `---
|
|
2859
|
+
name: deep-research-agent
|
|
2860
|
+
description: >
|
|
2861
|
+
Autonomous research agent that gathers domain intelligence, competitive analysis,
|
|
2862
|
+
tech stack evaluation, and best practices. Produces structured research reports
|
|
2863
|
+
for other agents to use as context. Uses web search, documentation crawling,
|
|
2864
|
+
and synthesis to build comprehensive knowledge.
|
|
2865
|
+
model: opus
|
|
2866
|
+
role: worker
|
|
2867
|
+
reports_to: planning-lead
|
|
2868
|
+
---
|
|
2869
|
+
|
|
2870
|
+
# Deep Research Agent
|
|
2871
|
+
|
|
2872
|
+
You are FISHI's autonomous research agent. Your role is to gather, synthesize, and
|
|
2873
|
+
report information that other agents need to make informed decisions.
|
|
2874
|
+
|
|
2875
|
+
## Research Types
|
|
2876
|
+
|
|
2877
|
+
### 1. Domain Research
|
|
2878
|
+
**When:** Discovery phase
|
|
2879
|
+
**Goal:** Understand the target domain deeply
|
|
2880
|
+
**Process:**
|
|
2881
|
+
1. Search for industry overview, market size, key players
|
|
2882
|
+
2. Identify regulatory requirements and compliance needs
|
|
2883
|
+
3. Find common user expectations and pain points
|
|
2884
|
+
4. Map the competitive landscape
|
|
2885
|
+
5. Identify domain-specific terminology
|
|
2886
|
+
|
|
2887
|
+
**Output:** \`.fishi/research/domain-analysis.md\`
|
|
2888
|
+
|
|
2889
|
+
### 2. Competitive Analysis
|
|
2890
|
+
**When:** PRD phase
|
|
2891
|
+
**Goal:** Analyze competitor products
|
|
2892
|
+
**Process:**
|
|
2893
|
+
1. Identify top 5-10 competitors in the space
|
|
2894
|
+
2. Analyze their feature sets, pricing, UX patterns
|
|
2895
|
+
3. Find their strengths and weaknesses
|
|
2896
|
+
4. Identify market gaps and opportunities
|
|
2897
|
+
5. Extract UX patterns worth adopting
|
|
2898
|
+
|
|
2899
|
+
**Output:** \`.fishi/research/competitive-analysis.md\`
|
|
2900
|
+
|
|
2901
|
+
### 3. Tech Stack Research
|
|
2902
|
+
**When:** Architecture phase
|
|
2903
|
+
**Goal:** Evaluate technology options
|
|
2904
|
+
**Process:**
|
|
2905
|
+
1. Research current best practices for the chosen stack
|
|
2906
|
+
2. Compare framework options (performance, ecosystem, community)
|
|
2907
|
+
3. Evaluate hosting/deployment options and costs
|
|
2908
|
+
4. Research database options for the data model
|
|
2909
|
+
5. Find proven integration patterns
|
|
2910
|
+
|
|
2911
|
+
**Output:** \`.fishi/research/tech-stack-evaluation.md\`
|
|
2912
|
+
|
|
2913
|
+
### 4. Best Practices Research
|
|
2914
|
+
**When:** Before Development
|
|
2915
|
+
**Goal:** Gather current patterns and anti-patterns
|
|
2916
|
+
**Process:**
|
|
2917
|
+
1. Search for latest framework documentation and guides
|
|
2918
|
+
2. Find community-recommended patterns for the stack
|
|
2919
|
+
3. Identify common pitfalls and anti-patterns
|
|
2920
|
+
4. Research testing strategies for the chosen tools
|
|
2921
|
+
5. Find performance optimization techniques
|
|
2922
|
+
|
|
2923
|
+
**Output:** \`.fishi/research/best-practices.md\`
|
|
2924
|
+
|
|
2925
|
+
### 5. Security Research
|
|
2926
|
+
**When:** Before Deployment
|
|
2927
|
+
**Goal:** Identify security considerations
|
|
2928
|
+
**Process:**
|
|
2929
|
+
1. Research known vulnerabilities for chosen dependencies
|
|
2930
|
+
2. Find OWASP guidelines relevant to the project type
|
|
2931
|
+
3. Identify authentication/authorization best practices
|
|
2932
|
+
4. Research data protection requirements (GDPR, CCPA)
|
|
2933
|
+
5. Find security testing approaches
|
|
2934
|
+
|
|
2935
|
+
**Output:** \`.fishi/research/security-assessment.md\`
|
|
2936
|
+
|
|
2937
|
+
## Report Format
|
|
2938
|
+
|
|
2939
|
+
Every research report follows this structure:
|
|
2940
|
+
|
|
2941
|
+
\`\`\`markdown
|
|
2942
|
+
# [Research Type] \u2014 [Project Name]
|
|
2943
|
+
**Date:** [timestamp]
|
|
2944
|
+
**Researcher:** deep-research-agent
|
|
2945
|
+
**Confidence:** high|medium|low
|
|
2946
|
+
|
|
2947
|
+
## Executive Summary
|
|
2948
|
+
[2-3 sentence overview of findings]
|
|
2949
|
+
|
|
2950
|
+
## Key Findings
|
|
2951
|
+
1. [Finding with supporting evidence]
|
|
2952
|
+
2. [Finding with supporting evidence]
|
|
2953
|
+
...
|
|
2954
|
+
|
|
2955
|
+
## Recommendations
|
|
2956
|
+
- [Actionable recommendation for other agents]
|
|
2957
|
+
- [Actionable recommendation for other agents]
|
|
2958
|
+
|
|
2959
|
+
## Sources
|
|
2960
|
+
- [Source 1 with URL]
|
|
2961
|
+
- [Source 2 with URL]
|
|
2962
|
+
|
|
2963
|
+
## Raw Data
|
|
2964
|
+
[Detailed notes and excerpts organized by topic]
|
|
2965
|
+
\`\`\`
|
|
2966
|
+
|
|
2967
|
+
## Tools Available
|
|
2968
|
+
- Web search via MCP (perplexity, context7)
|
|
2969
|
+
- Documentation fetching via WebFetch
|
|
2970
|
+
- GitHub repository analysis via MCP (github)
|
|
2971
|
+
- Package registry search (npm, PyPI)
|
|
2972
|
+
|
|
2973
|
+
## Integration
|
|
2974
|
+
- Reports saved to \`.fishi/research/\` directory
|
|
2975
|
+
- Other agents reference reports via memory system
|
|
2976
|
+
- Research findings feed into PRD and architecture decisions
|
|
2977
|
+
- Updated research can trigger architecture revisions
|
|
2978
|
+
`;
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2607
2981
|
// src/templates/skills/brainstorming.ts
|
|
2608
2982
|
function getBrainstormingSkill() {
|
|
2609
2983
|
return `# Brainstorming & Design Refinement Skill
|
|
@@ -3940,6 +4314,64 @@ documentation as a first-class deliverable, not an afterthought.
|
|
|
3940
4314
|
`;
|
|
3941
4315
|
}
|
|
3942
4316
|
|
|
4317
|
+
// src/templates/skills/deep-research.ts
|
|
4318
|
+
function getDeepResearchSkill() {
|
|
4319
|
+
return `---
|
|
4320
|
+
name: deep-research
|
|
4321
|
+
description: Autonomous research workflow \u2014 domain analysis, competitive intel, tech stack evaluation, best practices gathering
|
|
4322
|
+
---
|
|
4323
|
+
|
|
4324
|
+
# Deep Research Skill
|
|
4325
|
+
|
|
4326
|
+
## Purpose
|
|
4327
|
+
Conduct structured autonomous research to inform project decisions.
|
|
4328
|
+
Used by the Deep Research Agent during Discovery, PRD, and Architecture phases.
|
|
4329
|
+
|
|
4330
|
+
## Workflow
|
|
4331
|
+
|
|
4332
|
+
### Step 1: Define Research Scope
|
|
4333
|
+
- What domain/topic needs research?
|
|
4334
|
+
- What specific questions need answers?
|
|
4335
|
+
- What decisions will this research inform?
|
|
4336
|
+
|
|
4337
|
+
### Step 2: Gather Information
|
|
4338
|
+
- Search web for current information (use MCP tools)
|
|
4339
|
+
- Read relevant documentation and guides
|
|
4340
|
+
- Analyze competitor products and patterns
|
|
4341
|
+
- Check package registries for library options
|
|
4342
|
+
|
|
4343
|
+
### Step 3: Synthesize Findings
|
|
4344
|
+
- Organize by topic with evidence
|
|
4345
|
+
- Rate confidence: high (multiple sources agree), medium (some evidence), low (limited data)
|
|
4346
|
+
- Identify gaps where more research is needed
|
|
4347
|
+
|
|
4348
|
+
### Step 4: Produce Report
|
|
4349
|
+
Save to \`.fishi/research/{topic}.md\` with standard format:
|
|
4350
|
+
- Executive Summary
|
|
4351
|
+
- Key Findings (numbered, with evidence)
|
|
4352
|
+
- Recommendations (actionable)
|
|
4353
|
+
- Sources (with URLs)
|
|
4354
|
+
|
|
4355
|
+
### Step 5: Feed to Agents
|
|
4356
|
+
- Notify planning-lead of completed research
|
|
4357
|
+
- Update agent memory with key findings
|
|
4358
|
+
- Reference in PRD and architecture documents
|
|
4359
|
+
|
|
4360
|
+
## Research Commands
|
|
4361
|
+
\`\`\`bash
|
|
4362
|
+
node .fishi/scripts/phase-runner.mjs current # Check current phase
|
|
4363
|
+
node .fishi/scripts/memory-manager.mjs write --agent deep-research-agent --key domain-research --value "findings..."
|
|
4364
|
+
\`\`\`
|
|
4365
|
+
|
|
4366
|
+
## Quality Checklist
|
|
4367
|
+
- [ ] Multiple sources consulted (not just one)
|
|
4368
|
+
- [ ] Findings are current (within last 12 months)
|
|
4369
|
+
- [ ] Recommendations are specific and actionable
|
|
4370
|
+
- [ ] Confidence levels assigned to each finding
|
|
4371
|
+
- [ ] Sources are cited with URLs
|
|
4372
|
+
`;
|
|
4373
|
+
}
|
|
4374
|
+
|
|
3943
4375
|
// src/templates/hooks/session-start.ts
|
|
3944
4376
|
function getSessionStartHook() {
|
|
3945
4377
|
return `#!/usr/bin/env node
|
|
@@ -10308,6 +10740,160 @@ tasks where speed matters more than nuance.
|
|
|
10308
10740
|
`;
|
|
10309
10741
|
}
|
|
10310
10742
|
|
|
10743
|
+
// src/templates/configs/soul-md.ts
|
|
10744
|
+
function getSoulMdTemplate() {
|
|
10745
|
+
return `# SOUL.md \u2014 FISHI Agent Boundaries
|
|
10746
|
+
|
|
10747
|
+
> This file defines absolute boundaries that NO agent may cross autonomously.
|
|
10748
|
+
> These rules override all other instructions, skills, and commands.
|
|
10749
|
+
|
|
10750
|
+
## Core Principles
|
|
10751
|
+
|
|
10752
|
+
1. **Human authority is final.** Agents assist; humans decide.
|
|
10753
|
+
2. **Reversibility first.** Prefer reversible actions. Irreversible actions require human confirmation.
|
|
10754
|
+
3. **Least privilege.** Agents operate with minimum necessary access.
|
|
10755
|
+
4. **Transparency.** All agent actions are logged and observable.
|
|
10756
|
+
|
|
10757
|
+
## Absolute Boundaries
|
|
10758
|
+
|
|
10759
|
+
### Never Do Autonomously
|
|
10760
|
+
- Delete files, directories, or data without explicit human approval
|
|
10761
|
+
- Push code to production branches (main, master, production) without gate approval
|
|
10762
|
+
- Modify environment variables, secrets, or credentials
|
|
10763
|
+
- Make external API calls to services not in the sandbox allowlist
|
|
10764
|
+
- Install global packages or modify system configuration
|
|
10765
|
+
- Access files outside the assigned worktree (workers)
|
|
10766
|
+
- Execute shell commands that affect other users or processes
|
|
10767
|
+
- Disable safety hooks, permission rules, or gate requirements
|
|
10768
|
+
- Bypass the phase pipeline or skip mandatory gates
|
|
10769
|
+
- Send emails, messages, or notifications to external services
|
|
10770
|
+
- Access or transmit user personal data
|
|
10771
|
+
- Modify CI/CD pipelines without human review
|
|
10772
|
+
|
|
10773
|
+
### Always Require Human Confirmation
|
|
10774
|
+
- Merging branches into main/dev
|
|
10775
|
+
- Deploying to any environment (staging, production)
|
|
10776
|
+
- Adding new external dependencies
|
|
10777
|
+
- Changing database schemas
|
|
10778
|
+
- Modifying authentication/authorization logic
|
|
10779
|
+
- Creating or modifying API endpoints that handle user data
|
|
10780
|
+
- Any action flagged by the security agent
|
|
10781
|
+
|
|
10782
|
+
### Always Do
|
|
10783
|
+
- Log all significant actions to .fishi/logs/
|
|
10784
|
+
- Emit monitoring events via monitor-emitter
|
|
10785
|
+
- Work within assigned worktree boundaries
|
|
10786
|
+
- Follow the phase pipeline sequence
|
|
10787
|
+
- Submit work as PRs for review
|
|
10788
|
+
- Run tests before submitting work
|
|
10789
|
+
- Check sandbox policy before external access
|
|
10790
|
+
|
|
10791
|
+
## Enforcement
|
|
10792
|
+
|
|
10793
|
+
These boundaries are enforced at three levels:
|
|
10794
|
+
1. **SOUL.md** (this file) \u2014 read by all agents at session start
|
|
10795
|
+
2. **AGENTS.md** \u2014 per-role action gates
|
|
10796
|
+
3. **Tool permissions** \u2014 per-agent allow/deny lists in settings.json
|
|
10797
|
+
|
|
10798
|
+
Violation of these boundaries should be reported to the master-orchestrator
|
|
10799
|
+
and logged as a critical learnings entry.
|
|
10800
|
+
`;
|
|
10801
|
+
}
|
|
10802
|
+
|
|
10803
|
+
// src/templates/configs/agents-md.ts
|
|
10804
|
+
function getAgentsMdTemplate() {
|
|
10805
|
+
return `# AGENTS.md \u2014 FISHI Role-Based Action Gates
|
|
10806
|
+
|
|
10807
|
+
> Maps which actions require approval per agent role.
|
|
10808
|
+
> Read alongside SOUL.md for complete safety configuration.
|
|
10809
|
+
|
|
10810
|
+
## Role Hierarchy
|
|
10811
|
+
|
|
10812
|
+
\`\`\`
|
|
10813
|
+
Level 0: Master Orchestrator \u2014 strategy only, no code, no file writes
|
|
10814
|
+
Level 1: Coordinators \u2014 task assignment, code review, limited writes
|
|
10815
|
+
Level 2: Workers \u2014 full dev within worktree, no merge, no deploy
|
|
10816
|
+
\`\`\`
|
|
10817
|
+
|
|
10818
|
+
## Action Permissions by Role
|
|
10819
|
+
|
|
10820
|
+
### Master Orchestrator (L0)
|
|
10821
|
+
| Action | Permission |
|
|
10822
|
+
|--------|-----------|
|
|
10823
|
+
| Read files | Allowed |
|
|
10824
|
+
| Write/Edit files | **DENIED** \u2014 delegates to coordinators |
|
|
10825
|
+
| Run shell commands | **DENIED** \u2014 delegates to workers |
|
|
10826
|
+
| Approve gates | Allowed (with human confirmation) |
|
|
10827
|
+
| Assign tasks | Allowed |
|
|
10828
|
+
| Create agents | Allowed (dynamic agent factory) |
|
|
10829
|
+
| Merge branches | **DENIED** \u2014 requires human gate approval |
|
|
10830
|
+
| Deploy | **DENIED** \u2014 requires deployment gate |
|
|
10831
|
+
| Delete files | **DENIED** |
|
|
10832
|
+
|
|
10833
|
+
### Coordinators (L1)
|
|
10834
|
+
| Action | Permission |
|
|
10835
|
+
|--------|-----------|
|
|
10836
|
+
| Read files | Allowed |
|
|
10837
|
+
| Write/Edit files | Allowed (planning docs, task assignments) |
|
|
10838
|
+
| Run shell commands | Allowed (git status, test runs, non-destructive) |
|
|
10839
|
+
| Approve worker PRs | Allowed (code review) |
|
|
10840
|
+
| Create worktrees | Allowed |
|
|
10841
|
+
| Merge to dev branch | Allowed (after review) |
|
|
10842
|
+
| Merge to main/production | **DENIED** \u2014 requires gate |
|
|
10843
|
+
| Delete files | **DENIED** \u2014 archive instead |
|
|
10844
|
+
| Install dependencies | Allowed (within sandbox) |
|
|
10845
|
+
| Modify configs | **REQUIRES CONFIRMATION** |
|
|
10846
|
+
|
|
10847
|
+
### Workers (L2)
|
|
10848
|
+
| Action | Permission |
|
|
10849
|
+
|--------|-----------|
|
|
10850
|
+
| Read files | Allowed (within worktree + shared) |
|
|
10851
|
+
| Write/Edit files | Allowed (within worktree only) |
|
|
10852
|
+
| Run shell commands | Allowed (within worktree sandbox) |
|
|
10853
|
+
| Run tests | Allowed |
|
|
10854
|
+
| Install dev dependencies | Allowed (within sandbox) |
|
|
10855
|
+
| Commit to worktree branch | Allowed |
|
|
10856
|
+
| Push to worktree branch | Allowed |
|
|
10857
|
+
| Merge branches | **DENIED** \u2014 submit PR to coordinator |
|
|
10858
|
+
| Delete files | **DENIED** \u2014 request via coordinator |
|
|
10859
|
+
| Access main branch | **READ ONLY** |
|
|
10860
|
+
| External API calls | **DENIED** \u2014 unless in sandbox allowlist |
|
|
10861
|
+
|
|
10862
|
+
## Destructive Action Protocol
|
|
10863
|
+
|
|
10864
|
+
### Delete Operations
|
|
10865
|
+
1. **Files:** Never delete. Move to \`.fishi/archive/\` with timestamp.
|
|
10866
|
+
2. **Branches:** Only after merge confirmed + worktree cleaned.
|
|
10867
|
+
3. **Database records:** Never in production. Soft-delete only.
|
|
10868
|
+
4. **Dependencies:** Remove only via coordinator approval.
|
|
10869
|
+
|
|
10870
|
+
### Archive Instead of Delete
|
|
10871
|
+
\`\`\`
|
|
10872
|
+
Instead of: rm -rf old-feature/
|
|
10873
|
+
Do: mv old-feature/ .fishi/archive/old-feature-{timestamp}/
|
|
10874
|
+
\`\`\`
|
|
10875
|
+
|
|
10876
|
+
### Escalation Path
|
|
10877
|
+
\`\`\`
|
|
10878
|
+
Worker encounters destructive need
|
|
10879
|
+
\u2192 Reports to Coordinator
|
|
10880
|
+
\u2192 Coordinator evaluates risk
|
|
10881
|
+
\u2192 If safe: Coordinator executes with logging
|
|
10882
|
+
\u2192 If risky: Escalate to Master
|
|
10883
|
+
\u2192 Master requests human confirmation via gate
|
|
10884
|
+
\`\`\`
|
|
10885
|
+
|
|
10886
|
+
## Emergency Stop
|
|
10887
|
+
|
|
10888
|
+
If any agent detects behavior outside these boundaries:
|
|
10889
|
+
1. Log the incident to \`.fishi/logs/safety-incidents.log\`
|
|
10890
|
+
2. Emit \`safety.violation\` event to monitor
|
|
10891
|
+
3. Notify master-orchestrator
|
|
10892
|
+
4. Halt the violating agent's current task
|
|
10893
|
+
5. Wait for human review before resuming
|
|
10894
|
+
`;
|
|
10895
|
+
}
|
|
10896
|
+
|
|
10311
10897
|
// src/templates/factories/agent-template.ts
|
|
10312
10898
|
function getAgentFactoryTemplate() {
|
|
10313
10899
|
return `---
|
|
@@ -10691,6 +11277,7 @@ async function generateScaffold(targetDir, options) {
|
|
|
10691
11277
|
".claude/skills/brownfield-discovery",
|
|
10692
11278
|
".claude/skills/adaptive-taskgraph",
|
|
10693
11279
|
".claude/skills/documentation",
|
|
11280
|
+
".claude/skills/deep-research",
|
|
10694
11281
|
".claude/commands",
|
|
10695
11282
|
"docs",
|
|
10696
11283
|
".fishi/plans/prd",
|
|
@@ -10708,6 +11295,8 @@ async function generateScaffold(targetDir, options) {
|
|
|
10708
11295
|
".fishi/todos/agents",
|
|
10709
11296
|
".fishi/learnings/by-domain",
|
|
10710
11297
|
".fishi/learnings/by-agent",
|
|
11298
|
+
".fishi/archive",
|
|
11299
|
+
".fishi/research",
|
|
10711
11300
|
".trees"
|
|
10712
11301
|
];
|
|
10713
11302
|
for (const dir of dirs) {
|
|
@@ -10731,7 +11320,22 @@ async function generateScaffold(targetDir, options) {
|
|
|
10731
11320
|
await write(".claude/agents/docs-agent.md", docsAgentTemplate(ctx), "agents");
|
|
10732
11321
|
await write(".claude/agents/writing-agent.md", writingAgentTemplate(ctx), "agents");
|
|
10733
11322
|
await write(".claude/agents/marketing-agent.md", marketingAgentTemplate(ctx), "agents");
|
|
10734
|
-
|
|
11323
|
+
let agentCount = 18;
|
|
11324
|
+
await write(".claude/agents/deep-research-agent.md", getDeepResearchAgentTemplate(), "agents");
|
|
11325
|
+
agentCount++;
|
|
11326
|
+
if (options.domain && options.domain !== "general") {
|
|
11327
|
+
const domainTemplates = {
|
|
11328
|
+
saas: getSaasArchitectTemplate,
|
|
11329
|
+
marketplace: getMarketplaceArchitectTemplate,
|
|
11330
|
+
mobile: getMobileArchitectTemplate,
|
|
11331
|
+
aiml: getAimlArchitectTemplate
|
|
11332
|
+
};
|
|
11333
|
+
const template = domainTemplates[options.domain];
|
|
11334
|
+
if (template) {
|
|
11335
|
+
await write(`.claude/agents/${options.domain}-architect.md`, template(), "agents");
|
|
11336
|
+
agentCount++;
|
|
11337
|
+
}
|
|
11338
|
+
}
|
|
10735
11339
|
await write(".fishi/agent-factory/agent-template.md", getAgentFactoryTemplate());
|
|
10736
11340
|
await write(".fishi/agent-factory/coordinator-template.md", getCoordinatorFactoryTemplate());
|
|
10737
11341
|
await write(".claude/skills/brainstorming/SKILL.md", getBrainstormingSkill(), "skills");
|
|
@@ -10746,7 +11350,8 @@ async function generateScaffold(targetDir, options) {
|
|
|
10746
11350
|
await write(".claude/skills/brownfield-discovery/SKILL.md", getBrownfieldDiscoverySkill(), "skills");
|
|
10747
11351
|
await write(".claude/skills/adaptive-taskgraph/SKILL.md", getAdaptiveTaskGraphSkill(), "skills");
|
|
10748
11352
|
await write(".claude/skills/documentation/SKILL.md", getDocumentationSkill(), "skills");
|
|
10749
|
-
|
|
11353
|
+
await write(".claude/skills/deep-research/SKILL.md", getDeepResearchSkill(), "skills");
|
|
11354
|
+
const skillCount = 13;
|
|
10750
11355
|
await write(".fishi/scripts/session-start.mjs", getSessionStartHook());
|
|
10751
11356
|
await write(".fishi/scripts/auto-checkpoint.mjs", getAutoCheckpointHook());
|
|
10752
11357
|
await write(".fishi/scripts/agent-complete.mjs", getAgentCompleteHook());
|
|
@@ -10788,6 +11393,8 @@ async function generateScaffold(targetDir, options) {
|
|
|
10788
11393
|
await write(".claude/commands/fishi-reset.md", getResetCommand(), "commands");
|
|
10789
11394
|
await write(".claude/commands/fishi-prd.md", getPrdCommand(), "commands");
|
|
10790
11395
|
const commandCount = 8;
|
|
11396
|
+
await write("SOUL.md", getSoulMdTemplate());
|
|
11397
|
+
await write("AGENTS.md", getAgentsMdTemplate());
|
|
10791
11398
|
await write(".fishi/fishi.yaml", getFishiYamlTemplate({
|
|
10792
11399
|
projectName: options.projectName,
|
|
10793
11400
|
projectDescription: ctx.projectDescription,
|
|
@@ -11111,7 +11718,7 @@ async function createBackup(targetDir, conflictingFiles) {
|
|
|
11111
11718
|
manifestFiles.push({ path: relPath, size: stat.size });
|
|
11112
11719
|
}
|
|
11113
11720
|
}
|
|
11114
|
-
const fishiVersion = "0.
|
|
11721
|
+
const fishiVersion = "0.12.0";
|
|
11115
11722
|
const manifest = {
|
|
11116
11723
|
timestamp: now.toISOString(),
|
|
11117
11724
|
fishi_version: fishiVersion,
|
|
@@ -11780,6 +12387,635 @@ function walkDir(dir, extensions, result) {
|
|
|
11780
12387
|
}
|
|
11781
12388
|
}
|
|
11782
12389
|
|
|
12390
|
+
// src/generators/domain-manager.ts
|
|
12391
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
12392
|
+
import { join as join8 } from "path";
|
|
12393
|
+
var DOMAIN_INFO = {
|
|
12394
|
+
saas: {
|
|
12395
|
+
label: "SaaS",
|
|
12396
|
+
description: "Subscription billing, multi-tenancy, user management (Stripe, Auth0)",
|
|
12397
|
+
agent: "saas-architect"
|
|
12398
|
+
},
|
|
12399
|
+
marketplace: {
|
|
12400
|
+
label: "Marketplace",
|
|
12401
|
+
description: "Two-sided platform, escrow, disputes, vendor management (Stripe Connect)",
|
|
12402
|
+
agent: "marketplace-architect"
|
|
12403
|
+
},
|
|
12404
|
+
mobile: {
|
|
12405
|
+
label: "Mobile / PWA",
|
|
12406
|
+
description: "Progressive web app, offline sync, push notifications, responsive design",
|
|
12407
|
+
agent: "mobile-architect"
|
|
12408
|
+
},
|
|
12409
|
+
aiml: {
|
|
12410
|
+
label: "AI / ML",
|
|
12411
|
+
description: "RAG pipelines, embeddings, fine-tuning, model serving, LLM integration",
|
|
12412
|
+
agent: "aiml-architect"
|
|
12413
|
+
},
|
|
12414
|
+
general: {
|
|
12415
|
+
label: "General",
|
|
12416
|
+
description: "No domain specialization \u2014 use base agents only",
|
|
12417
|
+
agent: null
|
|
12418
|
+
}
|
|
12419
|
+
};
|
|
12420
|
+
function getAvailableDomains() {
|
|
12421
|
+
return Object.entries(DOMAIN_INFO).map(([key, info]) => ({
|
|
12422
|
+
value: key,
|
|
12423
|
+
name: `${info.label} \u2014 ${info.description}`
|
|
12424
|
+
}));
|
|
12425
|
+
}
|
|
12426
|
+
function readDomainConfig(projectDir) {
|
|
12427
|
+
const yamlPath = join8(projectDir, ".fishi", "fishi.yaml");
|
|
12428
|
+
if (!existsSync8(yamlPath)) {
|
|
12429
|
+
return { domain: "general", domainAgent: null, researchEnabled: false };
|
|
12430
|
+
}
|
|
12431
|
+
const content = readFileSync5(yamlPath, "utf-8");
|
|
12432
|
+
const domainMatch = content.match(/^\s*type:\s*(\w+)/m);
|
|
12433
|
+
const researchMatch = content.match(/^\s*research_enabled:\s*(true|false)/m);
|
|
12434
|
+
const domain = domainMatch?.[1] || "general";
|
|
12435
|
+
return {
|
|
12436
|
+
domain,
|
|
12437
|
+
domainAgent: DOMAIN_INFO[domain]?.agent || null,
|
|
12438
|
+
researchEnabled: researchMatch?.[1] === "true"
|
|
12439
|
+
};
|
|
12440
|
+
}
|
|
12441
|
+
function getDomainConfigYaml(domain) {
|
|
12442
|
+
const info = DOMAIN_INFO[domain];
|
|
12443
|
+
return `
|
|
12444
|
+
domain:
|
|
12445
|
+
type: ${domain}
|
|
12446
|
+
label: "${info.label}"
|
|
12447
|
+
specialist_agent: ${info.agent || "none"}
|
|
12448
|
+
research_enabled: true
|
|
12449
|
+
`;
|
|
12450
|
+
}
|
|
12451
|
+
|
|
12452
|
+
// src/generators/agent-permissions.ts
|
|
12453
|
+
function getPermissionsForRole(role) {
|
|
12454
|
+
switch (role) {
|
|
12455
|
+
case "master":
|
|
12456
|
+
return {
|
|
12457
|
+
role: "master",
|
|
12458
|
+
allow: [
|
|
12459
|
+
"Read",
|
|
12460
|
+
"Glob",
|
|
12461
|
+
"Grep",
|
|
12462
|
+
"Agent",
|
|
12463
|
+
"TodoRead",
|
|
12464
|
+
"TodoWrite",
|
|
12465
|
+
"WebFetch",
|
|
12466
|
+
"WebSearch"
|
|
12467
|
+
],
|
|
12468
|
+
deny: [
|
|
12469
|
+
"Write",
|
|
12470
|
+
"Edit",
|
|
12471
|
+
"Bash(*)",
|
|
12472
|
+
"NotebookEdit",
|
|
12473
|
+
"Bash(rm *)",
|
|
12474
|
+
"Bash(git push *)",
|
|
12475
|
+
"Bash(git merge *)",
|
|
12476
|
+
"Bash(npm *)",
|
|
12477
|
+
"Bash(pnpm *)"
|
|
12478
|
+
]
|
|
12479
|
+
};
|
|
12480
|
+
case "coordinator":
|
|
12481
|
+
return {
|
|
12482
|
+
role: "coordinator",
|
|
12483
|
+
allow: [
|
|
12484
|
+
"Read",
|
|
12485
|
+
"Write",
|
|
12486
|
+
"Edit",
|
|
12487
|
+
"Glob",
|
|
12488
|
+
"Grep",
|
|
12489
|
+
"Agent",
|
|
12490
|
+
"TodoRead",
|
|
12491
|
+
"TodoWrite",
|
|
12492
|
+
"WebFetch",
|
|
12493
|
+
"WebSearch",
|
|
12494
|
+
"Bash(git status *)",
|
|
12495
|
+
"Bash(git log *)",
|
|
12496
|
+
"Bash(git diff *)",
|
|
12497
|
+
"Bash(git branch *)",
|
|
12498
|
+
"Bash(git checkout *)",
|
|
12499
|
+
"Bash(git worktree *)",
|
|
12500
|
+
"Bash(node *)",
|
|
12501
|
+
"Bash(npx vitest *)",
|
|
12502
|
+
"Bash(npx tsc *)",
|
|
12503
|
+
"Bash(pnpm install *)",
|
|
12504
|
+
"Bash(pnpm add *)",
|
|
12505
|
+
"Bash(cat *)",
|
|
12506
|
+
"Bash(ls *)",
|
|
12507
|
+
"Bash(find *)"
|
|
12508
|
+
],
|
|
12509
|
+
deny: [
|
|
12510
|
+
"Bash(rm -rf *)",
|
|
12511
|
+
"Bash(git push --force *)",
|
|
12512
|
+
"Bash(git push * main)",
|
|
12513
|
+
"Bash(git push * master)",
|
|
12514
|
+
"Bash(git push * production)",
|
|
12515
|
+
"Bash(git merge * main)",
|
|
12516
|
+
"Bash(git merge * master)",
|
|
12517
|
+
"Bash(sudo *)",
|
|
12518
|
+
"Bash(chmod *)",
|
|
12519
|
+
"Bash(shutdown *)",
|
|
12520
|
+
"Bash(mkfs *)",
|
|
12521
|
+
"Bash(dd *)",
|
|
12522
|
+
"Bash(npm *)"
|
|
12523
|
+
]
|
|
12524
|
+
};
|
|
12525
|
+
case "worker":
|
|
12526
|
+
return {
|
|
12527
|
+
role: "worker",
|
|
12528
|
+
allow: [
|
|
12529
|
+
"Read",
|
|
12530
|
+
"Write",
|
|
12531
|
+
"Edit",
|
|
12532
|
+
"Glob",
|
|
12533
|
+
"Grep",
|
|
12534
|
+
"Agent",
|
|
12535
|
+
"TodoRead",
|
|
12536
|
+
"TodoWrite",
|
|
12537
|
+
"WebFetch",
|
|
12538
|
+
"WebSearch",
|
|
12539
|
+
"Bash(node *)",
|
|
12540
|
+
"Bash(npx *)",
|
|
12541
|
+
"Bash(pnpm *)",
|
|
12542
|
+
"Bash(git add *)",
|
|
12543
|
+
"Bash(git commit *)",
|
|
12544
|
+
"Bash(git status *)",
|
|
12545
|
+
"Bash(git log *)",
|
|
12546
|
+
"Bash(git diff *)",
|
|
12547
|
+
"Bash(tsc *)",
|
|
12548
|
+
"Bash(eslint *)",
|
|
12549
|
+
"Bash(prettier *)",
|
|
12550
|
+
"Bash(cat *)",
|
|
12551
|
+
"Bash(ls *)",
|
|
12552
|
+
"Bash(find *)",
|
|
12553
|
+
"Bash(grep *)",
|
|
12554
|
+
"Bash(wc *)",
|
|
12555
|
+
"Bash(head *)",
|
|
12556
|
+
"Bash(tail *)",
|
|
12557
|
+
"Bash(sort *)",
|
|
12558
|
+
"Bash(mkdir *)",
|
|
12559
|
+
"Bash(cp *)",
|
|
12560
|
+
"Bash(mv *)"
|
|
12561
|
+
],
|
|
12562
|
+
deny: [
|
|
12563
|
+
"Bash(rm -rf *)",
|
|
12564
|
+
"Bash(rm -r /)",
|
|
12565
|
+
"Bash(git push --force *)",
|
|
12566
|
+
"Bash(git push * main)",
|
|
12567
|
+
"Bash(git push * master)",
|
|
12568
|
+
"Bash(git push * production)",
|
|
12569
|
+
"Bash(git merge *)",
|
|
12570
|
+
"Bash(git branch -D *)",
|
|
12571
|
+
"Bash(sudo *)",
|
|
12572
|
+
"Bash(chmod 777 *)",
|
|
12573
|
+
"Bash(shutdown *)",
|
|
12574
|
+
"Bash(reboot *)",
|
|
12575
|
+
"Bash(mkfs *)",
|
|
12576
|
+
"Bash(dd *)",
|
|
12577
|
+
"Bash(kill -9 *)",
|
|
12578
|
+
"Bash(pkill *)",
|
|
12579
|
+
"Bash(npm *)",
|
|
12580
|
+
"Bash(curl * | sh)",
|
|
12581
|
+
"Bash(wget * | sh)"
|
|
12582
|
+
]
|
|
12583
|
+
};
|
|
12584
|
+
}
|
|
12585
|
+
}
|
|
12586
|
+
function getAllPermissionSummary() {
|
|
12587
|
+
const roles = ["master", "coordinator", "worker"];
|
|
12588
|
+
const result = {};
|
|
12589
|
+
for (const role of roles) {
|
|
12590
|
+
const perms = getPermissionsForRole(role);
|
|
12591
|
+
result[role] = { allowCount: perms.allow.length, denyCount: perms.deny.length };
|
|
12592
|
+
}
|
|
12593
|
+
return result;
|
|
12594
|
+
}
|
|
12595
|
+
function generatePermissionBlock(role) {
|
|
12596
|
+
const perms = getPermissionsForRole(role);
|
|
12597
|
+
const allowLines = perms.allow.map((r) => ` - "${r}"`).join("\n");
|
|
12598
|
+
const denyLines = perms.deny.map((r) => ` - "${r}"`).join("\n");
|
|
12599
|
+
return `permissions:
|
|
12600
|
+
role: ${role}
|
|
12601
|
+
allow:
|
|
12602
|
+
${allowLines}
|
|
12603
|
+
deny:
|
|
12604
|
+
${denyLines}`;
|
|
12605
|
+
}
|
|
12606
|
+
|
|
12607
|
+
// src/generators/security-scanner.ts
|
|
12608
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
|
|
12609
|
+
import { join as join9, extname } from "path";
|
|
12610
|
+
var SCAN_RULES = [
|
|
12611
|
+
// -- OWASP A01: Broken Access Control --
|
|
12612
|
+
{
|
|
12613
|
+
id: "no-cors-wildcard",
|
|
12614
|
+
category: "OWASP-A01: Broken Access Control",
|
|
12615
|
+
severity: "high",
|
|
12616
|
+
pattern: /['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/,
|
|
12617
|
+
message: "CORS wildcard (*) allows any origin \u2014 restrict to specific domains",
|
|
12618
|
+
fix: "Set Access-Control-Allow-Origin to specific trusted domains",
|
|
12619
|
+
cwe: "CWE-942",
|
|
12620
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12621
|
+
},
|
|
12622
|
+
{
|
|
12623
|
+
id: "no-open-redirect",
|
|
12624
|
+
category: "OWASP-A01: Broken Access Control",
|
|
12625
|
+
severity: "medium",
|
|
12626
|
+
pattern: /redirect\s*\(\s*req\.(query|params|body)\./,
|
|
12627
|
+
message: "Open redirect \u2014 user-controlled redirect target",
|
|
12628
|
+
fix: "Validate redirect URLs against an allowlist of trusted domains",
|
|
12629
|
+
cwe: "CWE-601",
|
|
12630
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12631
|
+
},
|
|
12632
|
+
// -- OWASP A02: Cryptographic Failures --
|
|
12633
|
+
{
|
|
12634
|
+
id: "no-hardcoded-secret",
|
|
12635
|
+
category: "OWASP-A02: Cryptographic Failures",
|
|
12636
|
+
severity: "critical",
|
|
12637
|
+
pattern: /(?:password|secret|api_?key|token|auth|private_?key)\s*[:=]\s*['"][^'"]{8,}['"]/i,
|
|
12638
|
+
message: "Possible hardcoded secret or credential",
|
|
12639
|
+
fix: "Move secrets to environment variables (.env) and never commit them",
|
|
12640
|
+
cwe: "CWE-798",
|
|
12641
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx", ".py", ".java", ".go", ".rb"],
|
|
12642
|
+
exclude: /example|placeholder|test|mock|fake|dummy|sample|TODO|FIXME|xxx|your[_-]?/i
|
|
12643
|
+
},
|
|
12644
|
+
{
|
|
12645
|
+
id: "no-md5",
|
|
12646
|
+
category: "OWASP-A02: Cryptographic Failures",
|
|
12647
|
+
severity: "high",
|
|
12648
|
+
pattern: /(?:createHash|hashlib\.md5|MD5|md5)\s*\(\s*['"]?md5['"]?\s*\)/,
|
|
12649
|
+
message: "MD5 is cryptographically broken \u2014 use SHA-256 or bcrypt",
|
|
12650
|
+
fix: "Replace MD5 with SHA-256 for hashing or bcrypt/argon2 for passwords",
|
|
12651
|
+
cwe: "CWE-328"
|
|
12652
|
+
},
|
|
12653
|
+
{
|
|
12654
|
+
id: "no-weak-crypto",
|
|
12655
|
+
category: "OWASP-A02: Cryptographic Failures",
|
|
12656
|
+
severity: "medium",
|
|
12657
|
+
pattern: /createHash\s*\(\s*['"]sha1['"]\s*\)/,
|
|
12658
|
+
message: "SHA-1 is deprecated \u2014 use SHA-256 or stronger",
|
|
12659
|
+
fix: 'Replace SHA-1 with SHA-256: createHash("sha256")',
|
|
12660
|
+
cwe: "CWE-328",
|
|
12661
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12662
|
+
},
|
|
12663
|
+
// -- OWASP A03: Injection --
|
|
12664
|
+
{
|
|
12665
|
+
id: "no-sql-injection",
|
|
12666
|
+
category: "OWASP-A03: Injection",
|
|
12667
|
+
severity: "critical",
|
|
12668
|
+
pattern: /(?:query|execute|raw)\s*\(\s*[`'"].*\$\{.*\}.*[`'"]/,
|
|
12669
|
+
message: "Possible SQL injection \u2014 string interpolation in query",
|
|
12670
|
+
fix: 'Use parameterized queries: db.query("SELECT * FROM users WHERE id = $1", [userId])',
|
|
12671
|
+
cwe: "CWE-89",
|
|
12672
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12673
|
+
},
|
|
12674
|
+
{
|
|
12675
|
+
id: "no-command-injection",
|
|
12676
|
+
category: "OWASP-A03: Injection",
|
|
12677
|
+
severity: "critical",
|
|
12678
|
+
pattern: /(?:exec|execSync|spawn|spawnSync)\s*\(\s*[`'"].*\$\{.*\}.*[`'"]/,
|
|
12679
|
+
message: "Possible command injection \u2014 user input in shell command",
|
|
12680
|
+
fix: "Use execFile() with argument array instead of string interpolation in exec()",
|
|
12681
|
+
cwe: "CWE-78",
|
|
12682
|
+
fileTypes: [".ts", ".js", ".mjs"],
|
|
12683
|
+
exclude: /fishi|scripts|hooks/i
|
|
12684
|
+
},
|
|
12685
|
+
{
|
|
12686
|
+
id: "no-eval",
|
|
12687
|
+
category: "OWASP-A03: Injection",
|
|
12688
|
+
severity: "high",
|
|
12689
|
+
pattern: /\beval\s*\(/,
|
|
12690
|
+
message: "eval() executes arbitrary code \u2014 never use with user input",
|
|
12691
|
+
fix: "Replace eval() with JSON.parse() for data or a safe parser for expressions",
|
|
12692
|
+
cwe: "CWE-95",
|
|
12693
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"],
|
|
12694
|
+
exclude: /['"]use strict['"]/
|
|
12695
|
+
},
|
|
12696
|
+
{
|
|
12697
|
+
id: "no-dangerouslySetInnerHTML",
|
|
12698
|
+
category: "OWASP-A03: Injection",
|
|
12699
|
+
severity: "high",
|
|
12700
|
+
pattern: /dangerouslySetInnerHTML/,
|
|
12701
|
+
message: "dangerouslySetInnerHTML can lead to XSS if content is not sanitized",
|
|
12702
|
+
fix: "Sanitize HTML with DOMPurify before using dangerouslySetInnerHTML, or use React components instead",
|
|
12703
|
+
cwe: "CWE-79",
|
|
12704
|
+
fileTypes: [".tsx", ".jsx"]
|
|
12705
|
+
},
|
|
12706
|
+
// -- OWASP A04: Insecure Design --
|
|
12707
|
+
{
|
|
12708
|
+
id: "no-console-log-sensitive",
|
|
12709
|
+
category: "OWASP-A04: Insecure Design",
|
|
12710
|
+
severity: "medium",
|
|
12711
|
+
pattern: /console\.(log|info|debug)\s*\(.*(?:password|secret|token|key|credential|auth)/i,
|
|
12712
|
+
message: "Logging sensitive data (password, secret, token)",
|
|
12713
|
+
fix: "Remove sensitive data from log statements or use structured logging with redaction",
|
|
12714
|
+
cwe: "CWE-532",
|
|
12715
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"],
|
|
12716
|
+
exclude: /\/\/|test|spec|mock/i
|
|
12717
|
+
},
|
|
12718
|
+
// -- OWASP A05: Security Misconfiguration --
|
|
12719
|
+
{
|
|
12720
|
+
id: "no-debug-mode",
|
|
12721
|
+
category: "OWASP-A05: Security Misconfiguration",
|
|
12722
|
+
severity: "medium",
|
|
12723
|
+
pattern: /(?:DEBUG|debug)\s*[:=]\s*(?:true|1|['"]true['"])/,
|
|
12724
|
+
message: "Debug mode enabled \u2014 disable in production",
|
|
12725
|
+
fix: 'Use environment-based config: DEBUG = process.env.NODE_ENV !== "production"',
|
|
12726
|
+
cwe: "CWE-489",
|
|
12727
|
+
exclude: /test|spec|\.env\.example|\.env\.local/i
|
|
12728
|
+
},
|
|
12729
|
+
{
|
|
12730
|
+
id: "no-http-only-false",
|
|
12731
|
+
category: "OWASP-A05: Security Misconfiguration",
|
|
12732
|
+
severity: "high",
|
|
12733
|
+
pattern: /httpOnly\s*:\s*false/,
|
|
12734
|
+
message: "Cookie httpOnly set to false \u2014 vulnerable to XSS cookie theft",
|
|
12735
|
+
fix: "Set httpOnly: true for authentication cookies",
|
|
12736
|
+
cwe: "CWE-1004",
|
|
12737
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12738
|
+
},
|
|
12739
|
+
{
|
|
12740
|
+
id: "no-secure-false",
|
|
12741
|
+
category: "OWASP-A05: Security Misconfiguration",
|
|
12742
|
+
severity: "medium",
|
|
12743
|
+
pattern: /secure\s*:\s*false/,
|
|
12744
|
+
message: "Cookie secure flag set to false \u2014 cookie sent over HTTP",
|
|
12745
|
+
fix: "Set secure: true for cookies in production (HTTPS only)",
|
|
12746
|
+
cwe: "CWE-614",
|
|
12747
|
+
fileTypes: [".ts", ".js", ".mjs"],
|
|
12748
|
+
exclude: /development|localhost|test/i
|
|
12749
|
+
},
|
|
12750
|
+
// -- OWASP A07: Identification and Authentication Failures --
|
|
12751
|
+
{
|
|
12752
|
+
id: "no-jwt-none-alg",
|
|
12753
|
+
category: "OWASP-A07: Auth Failures",
|
|
12754
|
+
severity: "critical",
|
|
12755
|
+
pattern: /algorithm\s*[:=]\s*['"]none['"]/i,
|
|
12756
|
+
message: 'JWT "none" algorithm \u2014 allows token forgery',
|
|
12757
|
+
fix: 'Always specify a strong algorithm: { algorithm: "HS256" } or RS256',
|
|
12758
|
+
cwe: "CWE-327",
|
|
12759
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12760
|
+
},
|
|
12761
|
+
{
|
|
12762
|
+
id: "no-weak-password-regex",
|
|
12763
|
+
category: "OWASP-A07: Auth Failures",
|
|
12764
|
+
severity: "low",
|
|
12765
|
+
pattern: /password.*\.length\s*[<>=]+\s*[1-5]\b/,
|
|
12766
|
+
message: "Weak password policy \u2014 minimum length too short",
|
|
12767
|
+
fix: "Require minimum 8 characters with complexity requirements",
|
|
12768
|
+
cwe: "CWE-521",
|
|
12769
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12770
|
+
},
|
|
12771
|
+
// -- OWASP A08: Software and Data Integrity --
|
|
12772
|
+
{
|
|
12773
|
+
id: "no-unsafe-deserialization",
|
|
12774
|
+
category: "OWASP-A08: Data Integrity",
|
|
12775
|
+
severity: "high",
|
|
12776
|
+
pattern: /JSON\.parse\s*\(\s*req\.(body|query|params)/,
|
|
12777
|
+
message: "Parsing untrusted input without validation",
|
|
12778
|
+
fix: "Validate and sanitize input with zod, joi, or yup before parsing",
|
|
12779
|
+
cwe: "CWE-502",
|
|
12780
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12781
|
+
},
|
|
12782
|
+
// -- OWASP A09: Security Logging and Monitoring Failures --
|
|
12783
|
+
{
|
|
12784
|
+
id: "no-empty-catch",
|
|
12785
|
+
category: "OWASP-A09: Logging Failures",
|
|
12786
|
+
severity: "low",
|
|
12787
|
+
pattern: /catch\s*\([^)]*\)\s*\{\s*\}/,
|
|
12788
|
+
message: "Empty catch block \u2014 errors silently swallowed",
|
|
12789
|
+
fix: 'Log the error: catch(e) { console.error("Context:", e); }',
|
|
12790
|
+
cwe: "CWE-390",
|
|
12791
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12792
|
+
},
|
|
12793
|
+
// -- OWASP A10: Server-Side Request Forgery (SSRF) --
|
|
12794
|
+
{
|
|
12795
|
+
id: "no-ssrf",
|
|
12796
|
+
category: "OWASP-A10: SSRF",
|
|
12797
|
+
severity: "high",
|
|
12798
|
+
pattern: /(?:fetch|axios|got|request|http\.get)\s*\(\s*(?:req\.|params\.|query\.|body\.)/,
|
|
12799
|
+
message: "Possible SSRF \u2014 user-controlled URL in server-side request",
|
|
12800
|
+
fix: "Validate URLs against an allowlist; block internal IPs (127.0.0.1, 10.x, 192.168.x)",
|
|
12801
|
+
cwe: "CWE-918",
|
|
12802
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12803
|
+
},
|
|
12804
|
+
// -- Additional SAST Rules --
|
|
12805
|
+
{
|
|
12806
|
+
id: "no-innerhtml",
|
|
12807
|
+
category: "SAST: XSS",
|
|
12808
|
+
severity: "high",
|
|
12809
|
+
pattern: /\.innerHTML\s*=/,
|
|
12810
|
+
message: "Direct innerHTML assignment \u2014 XSS vulnerability",
|
|
12811
|
+
fix: "Use textContent for text, or sanitize with DOMPurify before innerHTML",
|
|
12812
|
+
cwe: "CWE-79",
|
|
12813
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12814
|
+
},
|
|
12815
|
+
{
|
|
12816
|
+
id: "no-document-write",
|
|
12817
|
+
category: "SAST: XSS",
|
|
12818
|
+
severity: "high",
|
|
12819
|
+
pattern: /document\.write\s*\(/,
|
|
12820
|
+
message: "document.write() can inject malicious content",
|
|
12821
|
+
fix: "Use DOM manipulation methods (createElement, appendChild) instead",
|
|
12822
|
+
cwe: "CWE-79",
|
|
12823
|
+
fileTypes: [".ts", ".js", ".mjs", ".tsx", ".jsx"]
|
|
12824
|
+
},
|
|
12825
|
+
{
|
|
12826
|
+
id: "no-prototype-pollution",
|
|
12827
|
+
category: "SAST: Prototype Pollution",
|
|
12828
|
+
severity: "medium",
|
|
12829
|
+
pattern: /\[['"]__proto__['"]\]|\[['"]constructor['"]\]\s*\[['"]prototype['"]\]/,
|
|
12830
|
+
message: "Potential prototype pollution via __proto__ or constructor.prototype",
|
|
12831
|
+
fix: "Use Object.create(null) for dictionaries, validate keys against blocklist",
|
|
12832
|
+
cwe: "CWE-1321",
|
|
12833
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12834
|
+
},
|
|
12835
|
+
{
|
|
12836
|
+
id: "no-unvalidated-file-path",
|
|
12837
|
+
category: "SAST: Path Traversal",
|
|
12838
|
+
severity: "high",
|
|
12839
|
+
pattern: /(?:readFile|writeFile|readFileSync|writeFileSync|createReadStream)\s*\(\s*(?:req\.|params\.|query\.|body\.|`.*\$\{)/,
|
|
12840
|
+
message: "User input in file path \u2014 possible path traversal (../../etc/passwd)",
|
|
12841
|
+
fix: "Sanitize paths: use path.resolve() + verify within allowed directory",
|
|
12842
|
+
cwe: "CWE-22",
|
|
12843
|
+
fileTypes: [".ts", ".js", ".mjs"]
|
|
12844
|
+
},
|
|
12845
|
+
{
|
|
12846
|
+
id: "no-env-in-client",
|
|
12847
|
+
category: "SAST: Secret Exposure",
|
|
12848
|
+
severity: "high",
|
|
12849
|
+
pattern: /process\.env\.(?!NEXT_PUBLIC_|VITE_|NUXT_PUBLIC_)[\w]+/,
|
|
12850
|
+
message: "Server-side env var accessed \u2014 ensure this is not in client-side code",
|
|
12851
|
+
fix: "Use framework-specific public prefixes (NEXT_PUBLIC_, VITE_) for client-side env vars",
|
|
12852
|
+
cwe: "CWE-200",
|
|
12853
|
+
fileTypes: [".tsx", ".jsx"],
|
|
12854
|
+
exclude: /server|api|middleware|getServerSideProps|getStaticProps|loader|action/i
|
|
12855
|
+
},
|
|
12856
|
+
{
|
|
12857
|
+
id: "no-crypto-random",
|
|
12858
|
+
category: "SAST: Weak Randomness",
|
|
12859
|
+
severity: "medium",
|
|
12860
|
+
pattern: /Math\.random\s*\(\)/,
|
|
12861
|
+
message: "Math.random() is not cryptographically secure",
|
|
12862
|
+
fix: "Use crypto.randomUUID() or crypto.getRandomValues() for security-sensitive operations",
|
|
12863
|
+
cwe: "CWE-330",
|
|
12864
|
+
fileTypes: [".ts", ".js", ".mjs"],
|
|
12865
|
+
exclude: /test|spec|mock|animation|color|delay|jitter/i
|
|
12866
|
+
}
|
|
12867
|
+
];
|
|
12868
|
+
function runSecurityScan(projectDir) {
|
|
12869
|
+
const findings = [];
|
|
12870
|
+
let filesScanned = 0;
|
|
12871
|
+
const files = findScanFiles(projectDir);
|
|
12872
|
+
for (const file of files) {
|
|
12873
|
+
try {
|
|
12874
|
+
const content = readFileSync6(file, "utf-8");
|
|
12875
|
+
const lines = content.split("\n");
|
|
12876
|
+
const relPath = file.replace(projectDir, "").replace(/\\/g, "/").replace(/^\//, "");
|
|
12877
|
+
const ext = extname(file);
|
|
12878
|
+
filesScanned++;
|
|
12879
|
+
for (const rule of SCAN_RULES) {
|
|
12880
|
+
if (rule.fileTypes && rule.fileTypes.length > 0 && !rule.fileTypes.includes(ext)) continue;
|
|
12881
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12882
|
+
const line = lines[i];
|
|
12883
|
+
if (line.trimStart().startsWith("//") || line.trimStart().startsWith("*") || line.trimStart().startsWith("#")) continue;
|
|
12884
|
+
if (rule.exclude && rule.exclude.test(line)) continue;
|
|
12885
|
+
if (rule.pattern.test(line)) {
|
|
12886
|
+
findings.push({
|
|
12887
|
+
rule: rule.id,
|
|
12888
|
+
category: rule.category,
|
|
12889
|
+
severity: rule.severity,
|
|
12890
|
+
file: relPath,
|
|
12891
|
+
line: i + 1,
|
|
12892
|
+
code: line.trim().slice(0, 120),
|
|
12893
|
+
message: rule.message,
|
|
12894
|
+
fix: rule.fix,
|
|
12895
|
+
cwe: rule.cwe
|
|
12896
|
+
});
|
|
12897
|
+
}
|
|
12898
|
+
}
|
|
12899
|
+
}
|
|
12900
|
+
} catch {
|
|
12901
|
+
}
|
|
12902
|
+
}
|
|
12903
|
+
const critical = findings.filter((f) => f.severity === "critical").length;
|
|
12904
|
+
const high = findings.filter((f) => f.severity === "high").length;
|
|
12905
|
+
const medium = findings.filter((f) => f.severity === "medium").length;
|
|
12906
|
+
const low = findings.filter((f) => f.severity === "low").length;
|
|
12907
|
+
const info = findings.filter((f) => f.severity === "info").length;
|
|
12908
|
+
return {
|
|
12909
|
+
findings,
|
|
12910
|
+
summary: {
|
|
12911
|
+
critical,
|
|
12912
|
+
high,
|
|
12913
|
+
medium,
|
|
12914
|
+
low,
|
|
12915
|
+
info,
|
|
12916
|
+
total: findings.length,
|
|
12917
|
+
filesScanned,
|
|
12918
|
+
passed: critical === 0 && high === 0
|
|
12919
|
+
},
|
|
12920
|
+
scanDate: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12921
|
+
projectDir
|
|
12922
|
+
};
|
|
12923
|
+
}
|
|
12924
|
+
function generateSecurityReport(report) {
|
|
12925
|
+
const { findings, summary } = report;
|
|
12926
|
+
let md = `# Security Scan Report
|
|
12927
|
+
|
|
12928
|
+
`;
|
|
12929
|
+
md += `**Date:** ${report.scanDate}
|
|
12930
|
+
`;
|
|
12931
|
+
md += `**Files Scanned:** ${summary.filesScanned}
|
|
12932
|
+
`;
|
|
12933
|
+
md += `**Status:** ${summary.passed ? "PASSED" : "FAILED"}
|
|
12934
|
+
|
|
12935
|
+
`;
|
|
12936
|
+
md += `## Summary
|
|
12937
|
+
|
|
12938
|
+
`;
|
|
12939
|
+
md += `| Severity | Count |
|
|
12940
|
+
|----------|-------|
|
|
12941
|
+
`;
|
|
12942
|
+
md += `| Critical | ${summary.critical} |
|
|
12943
|
+
`;
|
|
12944
|
+
md += `| High | ${summary.high} |
|
|
12945
|
+
`;
|
|
12946
|
+
md += `| Medium | ${summary.medium} |
|
|
12947
|
+
`;
|
|
12948
|
+
md += `| Low | ${summary.low} |
|
|
12949
|
+
`;
|
|
12950
|
+
md += `| Info | ${summary.info} |
|
|
12951
|
+
`;
|
|
12952
|
+
md += `| **Total** | **${summary.total}** |
|
|
12953
|
+
|
|
12954
|
+
`;
|
|
12955
|
+
if (findings.length === 0) {
|
|
12956
|
+
md += `No security issues found.
|
|
12957
|
+
`;
|
|
12958
|
+
return md;
|
|
12959
|
+
}
|
|
12960
|
+
const byCategory = {};
|
|
12961
|
+
for (const f of findings) {
|
|
12962
|
+
if (!byCategory[f.category]) byCategory[f.category] = [];
|
|
12963
|
+
byCategory[f.category].push(f);
|
|
12964
|
+
}
|
|
12965
|
+
for (const [category, catFindings] of Object.entries(byCategory)) {
|
|
12966
|
+
md += `## ${category}
|
|
12967
|
+
|
|
12968
|
+
`;
|
|
12969
|
+
for (const f of catFindings) {
|
|
12970
|
+
const icon = f.severity === "critical" ? "\u{1F534}" : f.severity === "high" ? "\u{1F7E0}" : f.severity === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
12971
|
+
md += `### ${icon} ${f.rule} (${f.severity.toUpperCase()})
|
|
12972
|
+
`;
|
|
12973
|
+
md += `**File:** \`${f.file}:${f.line}\`
|
|
12974
|
+
`;
|
|
12975
|
+
if (f.cwe) md += `**CWE:** ${f.cwe}
|
|
12976
|
+
`;
|
|
12977
|
+
md += `**Issue:** ${f.message}
|
|
12978
|
+
`;
|
|
12979
|
+
md += `**Code:** \`${f.code}\`
|
|
12980
|
+
`;
|
|
12981
|
+
md += `**Fix:** ${f.fix}
|
|
12982
|
+
|
|
12983
|
+
`;
|
|
12984
|
+
}
|
|
12985
|
+
}
|
|
12986
|
+
return md;
|
|
12987
|
+
}
|
|
12988
|
+
function getScanRules() {
|
|
12989
|
+
return SCAN_RULES.map((r) => ({
|
|
12990
|
+
id: r.id,
|
|
12991
|
+
category: r.category,
|
|
12992
|
+
severity: r.severity,
|
|
12993
|
+
message: r.message,
|
|
12994
|
+
cwe: r.cwe
|
|
12995
|
+
}));
|
|
12996
|
+
}
|
|
12997
|
+
function findScanFiles(projectDir) {
|
|
12998
|
+
const scanExts = [".ts", ".js", ".mjs", ".tsx", ".jsx", ".py", ".java", ".go", ".rb"];
|
|
12999
|
+
const skipDirs = ["node_modules", ".next", "dist", ".git", ".fishi", ".trees", "coverage", "__pycache__", ".venv"];
|
|
13000
|
+
const files = [];
|
|
13001
|
+
function walk(dir) {
|
|
13002
|
+
try {
|
|
13003
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
13004
|
+
for (const entry of entries) {
|
|
13005
|
+
if (entry.isDirectory()) {
|
|
13006
|
+
if (skipDirs.includes(entry.name)) continue;
|
|
13007
|
+
walk(join9(dir, entry.name));
|
|
13008
|
+
} else if (scanExts.some((ext) => entry.name.endsWith(ext))) {
|
|
13009
|
+
files.push(join9(dir, entry.name));
|
|
13010
|
+
}
|
|
13011
|
+
}
|
|
13012
|
+
} catch {
|
|
13013
|
+
}
|
|
13014
|
+
}
|
|
13015
|
+
walk(projectDir);
|
|
13016
|
+
return files.slice(0, 500);
|
|
13017
|
+
}
|
|
13018
|
+
|
|
11783
13019
|
// src/templates/configs/sandbox-policy.ts
|
|
11784
13020
|
function getSandboxPolicyTemplate() {
|
|
11785
13021
|
return `# FISHI Sandbox Policy
|
|
@@ -12172,6 +13408,7 @@ function getDashboardHtml() {
|
|
|
12172
13408
|
</html>`;
|
|
12173
13409
|
}
|
|
12174
13410
|
export {
|
|
13411
|
+
DOMAIN_INFO,
|
|
12175
13412
|
architectAgentTemplate,
|
|
12176
13413
|
backendAgentTemplate,
|
|
12177
13414
|
buildSandboxEnv,
|
|
@@ -12189,14 +13426,20 @@ export {
|
|
|
12189
13426
|
fullstackAgentTemplate,
|
|
12190
13427
|
generateDefaultTokens,
|
|
12191
13428
|
generateDesignSystemConfig,
|
|
13429
|
+
generatePermissionBlock,
|
|
12192
13430
|
generateScaffold,
|
|
13431
|
+
generateSecurityReport,
|
|
12193
13432
|
getAdaptiveTaskGraphSkill,
|
|
12194
13433
|
getAgentCompleteHook,
|
|
12195
13434
|
getAgentFactoryTemplate,
|
|
12196
13435
|
getAgentRegistryTemplate,
|
|
12197
13436
|
getAgentSummary,
|
|
13437
|
+
getAgentsMdTemplate,
|
|
13438
|
+
getAimlArchitectTemplate,
|
|
13439
|
+
getAllPermissionSummary,
|
|
12198
13440
|
getApiDesignSkill,
|
|
12199
13441
|
getAutoCheckpointHook,
|
|
13442
|
+
getAvailableDomains,
|
|
12200
13443
|
getBoardCommand,
|
|
12201
13444
|
getBrainstormingSkill,
|
|
12202
13445
|
getBrownfieldAnalysisSkill,
|
|
@@ -12206,21 +13449,27 @@ export {
|
|
|
12206
13449
|
getCoordinatorFactoryTemplate,
|
|
12207
13450
|
getDashboardHtml,
|
|
12208
13451
|
getDebuggingSkill,
|
|
13452
|
+
getDeepResearchAgentTemplate,
|
|
13453
|
+
getDeepResearchSkill,
|
|
12209
13454
|
getDeploymentSkill,
|
|
12210
13455
|
getDocCheckerScript,
|
|
12211
13456
|
getDockerfileTemplate,
|
|
12212
13457
|
getDocumentationSkill,
|
|
13458
|
+
getDomainConfigYaml,
|
|
12213
13459
|
getFishiYamlTemplate,
|
|
12214
13460
|
getGateCommand,
|
|
12215
13461
|
getGateManagerScript,
|
|
12216
13462
|
getGitignoreAdditions,
|
|
12217
13463
|
getInitCommand,
|
|
12218
13464
|
getLearningsManagerScript,
|
|
13465
|
+
getMarketplaceArchitectTemplate,
|
|
12219
13466
|
getMasterOrchestratorTemplate,
|
|
12220
13467
|
getMcpJsonTemplate,
|
|
12221
13468
|
getMemoryManagerScript,
|
|
13469
|
+
getMobileArchitectTemplate,
|
|
12222
13470
|
getModelRoutingReference,
|
|
12223
13471
|
getMonitorEmitterScript,
|
|
13472
|
+
getPermissionsForRole,
|
|
12224
13473
|
getPhaseRunnerScript,
|
|
12225
13474
|
getPostEditHook,
|
|
12226
13475
|
getPrdCommand,
|
|
@@ -12228,10 +13477,13 @@ export {
|
|
|
12228
13477
|
getProjectYamlTemplate,
|
|
12229
13478
|
getResetCommand,
|
|
12230
13479
|
getResumeCommand,
|
|
13480
|
+
getSaasArchitectTemplate,
|
|
12231
13481
|
getSafetyCheckHook,
|
|
12232
13482
|
getSandboxPolicyTemplate,
|
|
13483
|
+
getScanRules,
|
|
12233
13484
|
getSessionStartHook,
|
|
12234
13485
|
getSettingsJsonTemplate,
|
|
13486
|
+
getSoulMdTemplate,
|
|
12235
13487
|
getSprintCommand,
|
|
12236
13488
|
getStatusCommand,
|
|
12237
13489
|
getTaskboardOpsSkill,
|
|
@@ -12252,6 +13504,7 @@ export {
|
|
|
12252
13504
|
planningAgentTemplate,
|
|
12253
13505
|
planningLeadTemplate,
|
|
12254
13506
|
qualityLeadTemplate,
|
|
13507
|
+
readDomainConfig,
|
|
12255
13508
|
readMonitorState,
|
|
12256
13509
|
readSandboxConfig,
|
|
12257
13510
|
readSandboxPolicy,
|
|
@@ -12260,6 +13513,7 @@ export {
|
|
|
12260
13513
|
runInDockerSandbox,
|
|
12261
13514
|
runInProcessSandbox,
|
|
12262
13515
|
runInSandbox,
|
|
13516
|
+
runSecurityScan,
|
|
12263
13517
|
securityAgentTemplate,
|
|
12264
13518
|
startDevServer,
|
|
12265
13519
|
testingAgentTemplate,
|