@dv.nghiem/flowdeck 0.1.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/LICENSE +21 -0
- package/README.md +136 -0
- package/bin/flowdeck.js +108 -0
- package/dist/agents/architect.d.ts +3 -0
- package/dist/agents/architect.d.ts.map +1 -0
- package/dist/agents/code-explorer.d.ts +3 -0
- package/dist/agents/code-explorer.d.ts.map +1 -0
- package/dist/agents/coder.d.ts +3 -0
- package/dist/agents/coder.d.ts.map +1 -0
- package/dist/agents/debug.d.ts +4 -0
- package/dist/agents/debug.d.ts.map +1 -0
- package/dist/agents/doc-updater.d.ts +3 -0
- package/dist/agents/doc-updater.d.ts.map +1 -0
- package/dist/agents/flowdeck.d.ts +5 -0
- package/dist/agents/flowdeck.d.ts.map +1 -0
- package/dist/agents/index.d.ts +38 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/mapper.d.ts +3 -0
- package/dist/agents/mapper.d.ts.map +1 -0
- package/dist/agents/orchestrator.d.ts +10 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/performance.d.ts +4 -0
- package/dist/agents/performance.d.ts.map +1 -0
- package/dist/agents/planner.d.ts +3 -0
- package/dist/agents/planner.d.ts.map +1 -0
- package/dist/agents/policy-enforcer.d.ts +3 -0
- package/dist/agents/policy-enforcer.d.ts.map +1 -0
- package/dist/agents/researcher.d.ts +3 -0
- package/dist/agents/researcher.d.ts.map +1 -0
- package/dist/agents/reviewer.d.ts +3 -0
- package/dist/agents/reviewer.d.ts.map +1 -0
- package/dist/agents/risk-analyst.d.ts +3 -0
- package/dist/agents/risk-analyst.d.ts.map +1 -0
- package/dist/agents/security-auditor.d.ts +3 -0
- package/dist/agents/security-auditor.d.ts.map +1 -0
- package/dist/agents/specialist.d.ts +5 -0
- package/dist/agents/specialist.d.ts.map +1 -0
- package/dist/agents/tester.d.ts +3 -0
- package/dist/agents/tester.d.ts.map +1 -0
- package/dist/agents/types.d.ts +20 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/writer.d.ts +3 -0
- package/dist/agents/writer.d.ts.map +1 -0
- package/dist/commands/analysis/analysis.test.d.ts +2 -0
- package/dist/commands/analysis/analysis.test.d.ts.map +1 -0
- package/dist/commands/analysis/analyze-change.d.ts +148 -0
- package/dist/commands/analysis/analyze-change.d.ts.map +1 -0
- package/dist/commands/analysis/evaluate-risk.d.ts +77 -0
- package/dist/commands/analysis/evaluate-risk.d.ts.map +1 -0
- package/dist/commands/analysis/guarded-edit.d.ts +72 -0
- package/dist/commands/analysis/guarded-edit.d.ts.map +1 -0
- package/dist/commands/execution/deploy-check.d.ts +91 -0
- package/dist/commands/execution/deploy-check.d.ts.map +1 -0
- package/dist/commands/execution/fix-bug.d.ts +187 -0
- package/dist/commands/execution/fix-bug.d.ts.map +1 -0
- package/dist/commands/execution/new-feature.d.ts +171 -0
- package/dist/commands/execution/new-feature.d.ts.map +1 -0
- package/dist/commands/execution/review-code.d.ts +130 -0
- package/dist/commands/execution/review-code.d.ts.map +1 -0
- package/dist/commands/execution/write-docs.d.ts +94 -0
- package/dist/commands/execution/write-docs.d.ts.map +1 -0
- package/dist/commands/governance/approve.d.ts +80 -0
- package/dist/commands/governance/approve.d.ts.map +1 -0
- package/dist/commands/intelligence/blast-radius.d.ts +67 -0
- package/dist/commands/intelligence/blast-radius.d.ts.map +1 -0
- package/dist/commands/intelligence/impact-radar.d.ts +71 -0
- package/dist/commands/intelligence/impact-radar.d.ts.map +1 -0
- package/dist/commands/intelligence/intelligence.test.d.ts +2 -0
- package/dist/commands/intelligence/intelligence.test.d.ts.map +1 -0
- package/dist/commands/intelligence/regression-predict.d.ts +75 -0
- package/dist/commands/intelligence/regression-predict.d.ts.map +1 -0
- package/dist/commands/intelligence/review-route.d.ts +65 -0
- package/dist/commands/intelligence/review-route.d.ts.map +1 -0
- package/dist/commands/intelligence/test-gap.d.ts +73 -0
- package/dist/commands/intelligence/test-gap.d.ts.map +1 -0
- package/dist/commands/intelligence/translate-intent.d.ts +87 -0
- package/dist/commands/intelligence/translate-intent.d.ts.map +1 -0
- package/dist/commands/intelligence/volatility-map-cmd.d.ts +68 -0
- package/dist/commands/intelligence/volatility-map-cmd.d.ts.map +1 -0
- package/dist/commands/planning/ask.d.ts +62 -0
- package/dist/commands/planning/ask.d.ts.map +1 -0
- package/dist/commands/planning/ask.test.d.ts +2 -0
- package/dist/commands/planning/ask.test.d.ts.map +1 -0
- package/dist/commands/planning/dashboard.d.ts +30 -0
- package/dist/commands/planning/dashboard.d.ts.map +1 -0
- package/dist/commands/planning/discuss.d.ts +39 -0
- package/dist/commands/planning/discuss.d.ts.map +1 -0
- package/dist/commands/planning/plan.d.ts +67 -0
- package/dist/commands/planning/plan.d.ts.map +1 -0
- package/dist/commands/planning/roadmap.d.ts +105 -0
- package/dist/commands/planning/roadmap.d.ts.map +1 -0
- package/dist/commands/setup/doctor.d.ts +10 -0
- package/dist/commands/setup/doctor.d.ts.map +1 -0
- package/dist/commands/setup/map-codebase.d.ts +62 -0
- package/dist/commands/setup/map-codebase.d.ts.map +1 -0
- package/dist/commands/setup/new-project.d.ts +19 -0
- package/dist/commands/setup/new-project.d.ts.map +1 -0
- package/dist/commands/setup/settings.d.ts +57 -0
- package/dist/commands/setup/settings.d.ts.map +1 -0
- package/dist/commands/state/checkpoint.d.ts +27 -0
- package/dist/commands/state/checkpoint.d.ts.map +1 -0
- package/dist/commands/state/multi-repo.d.ts +63 -0
- package/dist/commands/state/multi-repo.d.ts.map +1 -0
- package/dist/commands/state/progress.d.ts +57 -0
- package/dist/commands/state/progress.d.ts.map +1 -0
- package/dist/commands/state/resume.d.ts +11 -0
- package/dist/commands/state/resume.d.ts.map +1 -0
- package/dist/commands/state/workspace-commands.d.ts +207 -0
- package/dist/commands/state/workspace-commands.d.ts.map +1 -0
- package/dist/dashboard/lib/port-finder.d.ts +10 -0
- package/dist/dashboard/lib/port-finder.d.ts.map +1 -0
- package/dist/dashboard/lib/port-finder.test.d.ts +2 -0
- package/dist/dashboard/lib/port-finder.test.d.ts.map +1 -0
- package/dist/dashboard/lib/state-reader.d.ts +3 -0
- package/dist/dashboard/lib/state-reader.d.ts.map +1 -0
- package/dist/dashboard/server.d.ts +2 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.mjs +13649 -0
- package/dist/dashboard/types.d.ts +72 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/views/index.ejs +391 -0
- package/dist/dashboard/views/partials/blockers.ejs +10 -0
- package/dist/dashboard/views/partials/header.ejs +20 -0
- package/dist/dashboard/views/partials/phase-timeline.ejs +40 -0
- package/dist/dashboard/views/partials/progress.ejs +12 -0
- package/dist/hooks/approval-hook.d.ts +13 -0
- package/dist/hooks/approval-hook.d.ts.map +1 -0
- package/dist/hooks/compaction-hook.d.ts +23 -0
- package/dist/hooks/compaction-hook.d.ts.map +1 -0
- package/dist/hooks/context-window-monitor.d.ts +21 -0
- package/dist/hooks/context-window-monitor.d.ts.map +1 -0
- package/dist/hooks/decision-trace-hook.d.ts +13 -0
- package/dist/hooks/decision-trace-hook.d.ts.map +1 -0
- package/dist/hooks/file-tracker.d.ts +29 -0
- package/dist/hooks/file-tracker.d.ts.map +1 -0
- package/dist/hooks/guard-rails.d.ts +33 -0
- package/dist/hooks/guard-rails.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/notifications.d.ts +21 -0
- package/dist/hooks/notifications.d.ts.map +1 -0
- package/dist/hooks/patch-trust.d.ts +27 -0
- package/dist/hooks/patch-trust.d.ts.map +1 -0
- package/dist/hooks/patch-trust.test.d.ts +2 -0
- package/dist/hooks/patch-trust.test.d.ts.map +1 -0
- package/dist/hooks/session-events.d.ts +8 -0
- package/dist/hooks/session-events.d.ts.map +1 -0
- package/dist/hooks/session-idle-hook.d.ts +21 -0
- package/dist/hooks/session-idle-hook.d.ts.map +1 -0
- package/dist/hooks/session-start.d.ts +10 -0
- package/dist/hooks/session-start.d.ts.map +1 -0
- package/dist/hooks/shell-env-hook.d.ts +21 -0
- package/dist/hooks/shell-env-hook.d.ts.map +1 -0
- package/dist/hooks/telemetry-hook.d.ts +25 -0
- package/dist/hooks/telemetry-hook.d.ts.map +1 -0
- package/dist/hooks/todo-hook.d.ts +25 -0
- package/dist/hooks/todo-hook.d.ts.map +1 -0
- package/dist/hooks/tool-guard.d.ts +41 -0
- package/dist/hooks/tool-guard.d.ts.map +1 -0
- package/dist/hooks/tool-guard.test.d.ts +2 -0
- package/dist/hooks/tool-guard.test.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6639 -0
- package/dist/lib/confirmation.d.ts +20 -0
- package/dist/lib/confirmation.d.ts.map +1 -0
- package/dist/lib/impact-radar.d.ts +35 -0
- package/dist/lib/impact-radar.d.ts.map +1 -0
- package/dist/lib/signatures.d.ts +12 -0
- package/dist/lib/signatures.d.ts.map +1 -0
- package/dist/lib/timestamps.d.ts +23 -0
- package/dist/lib/timestamps.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +20 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/services/agent-performance.d.ts +29 -0
- package/dist/services/agent-performance.d.ts.map +1 -0
- package/dist/services/approval-manager.d.ts +30 -0
- package/dist/services/approval-manager.d.ts.map +1 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/model-router.d.ts +35 -0
- package/dist/services/model-router.d.ts.map +1 -0
- package/dist/services/policy-compiler.d.ts +27 -0
- package/dist/services/policy-compiler.d.ts.map +1 -0
- package/dist/services/run-trace.d.ts +34 -0
- package/dist/services/run-trace.d.ts.map +1 -0
- package/dist/services/services.test.d.ts +2 -0
- package/dist/services/services.test.d.ts.map +1 -0
- package/dist/services/telemetry.d.ts +34 -0
- package/dist/services/telemetry.d.ts.map +1 -0
- package/dist/tools/agent-dispatch.test.d.ts +2 -0
- package/dist/tools/agent-dispatch.test.d.ts.map +1 -0
- package/dist/tools/codebase-state.d.ts +4 -0
- package/dist/tools/codebase-state.d.ts.map +1 -0
- package/dist/tools/context-generator.d.ts +3 -0
- package/dist/tools/context-generator.d.ts.map +1 -0
- package/dist/tools/council.d.ts +4 -0
- package/dist/tools/council.d.ts.map +1 -0
- package/dist/tools/decision-trace.d.ts +16 -0
- package/dist/tools/decision-trace.d.ts.map +1 -0
- package/dist/tools/delegate.d.ts +4 -0
- package/dist/tools/delegate.d.ts.map +1 -0
- package/dist/tools/failure-replay.d.ts +19 -0
- package/dist/tools/failure-replay.d.ts.map +1 -0
- package/dist/tools/failure-replay.test.d.ts +2 -0
- package/dist/tools/failure-replay.test.d.ts.map +1 -0
- package/dist/tools/hash-edit.d.ts +3 -0
- package/dist/tools/hash-edit.d.ts.map +1 -0
- package/dist/tools/planning-state-lib.d.ts +65 -0
- package/dist/tools/planning-state-lib.d.ts.map +1 -0
- package/dist/tools/planning-state.d.ts +3 -0
- package/dist/tools/planning-state.d.ts.map +1 -0
- package/dist/tools/policy-engine.d.ts +19 -0
- package/dist/tools/policy-engine.d.ts.map +1 -0
- package/dist/tools/repo-memory.d.ts +20 -0
- package/dist/tools/repo-memory.d.ts.map +1 -0
- package/dist/tools/repo-memory.test.d.ts +2 -0
- package/dist/tools/repo-memory.test.d.ts.map +1 -0
- package/dist/tools/run-parallel.d.ts +4 -0
- package/dist/tools/run-parallel.d.ts.map +1 -0
- package/dist/tools/run-pipeline.d.ts +4 -0
- package/dist/tools/run-pipeline.d.ts.map +1 -0
- package/dist/tools/volatility-map.d.ts +18 -0
- package/dist/tools/volatility-map.d.ts.map +1 -0
- package/dist/tools/volatility-map.test.d.ts +2 -0
- package/dist/tools/volatility-map.test.d.ts.map +1 -0
- package/dist/tools/workspace-state.d.ts +3 -0
- package/dist/tools/workspace-state.d.ts.map +1 -0
- package/docs/USER_GUIDE.md +20 -0
- package/docs/agents.md +562 -0
- package/docs/best-practices.md +47 -0
- package/docs/command-migration.md +175 -0
- package/docs/commands/fd-analyze-change.md +107 -0
- package/docs/commands/fd-ask.md +51 -0
- package/docs/commands/fd-checkpoint.md +10 -0
- package/docs/commands/fd-dashboard.md +11 -0
- package/docs/commands/fd-deploy-check.md +11 -0
- package/docs/commands/fd-discuss.md +28 -0
- package/docs/commands/fd-evaluate-risk.md +134 -0
- package/docs/commands/fd-fix-bug.md +24 -0
- package/docs/commands/fd-guarded-edit.md +105 -0
- package/docs/commands/fd-map-codebase.md +27 -0
- package/docs/commands/fd-multi-repo.md +63 -0
- package/docs/commands/fd-new-feature.md +25 -0
- package/docs/commands/fd-new-project.md +24 -0
- package/docs/commands/fd-plan.md +33 -0
- package/docs/commands/fd-progress.md +11 -0
- package/docs/commands/fd-resume.md +10 -0
- package/docs/commands/fd-review-code.md +29 -0
- package/docs/commands/fd-roadmap.md +10 -0
- package/docs/commands/fd-settings.md +10 -0
- package/docs/commands/fd-write-docs.md +10 -0
- package/docs/commands.md +476 -0
- package/docs/configuration.md +211 -0
- package/docs/feature-integration-architecture.md +255 -0
- package/docs/index.md +75 -0
- package/docs/installation.md +134 -0
- package/docs/intelligence.md +294 -0
- package/docs/multi-repo.md +201 -0
- package/docs/notifications.md +170 -0
- package/docs/parallel-execution.md +227 -0
- package/docs/quick-start.md +174 -0
- package/docs/rules.md +459 -0
- package/docs/skills.md +408 -0
- package/docs/workflows.md +376 -0
- package/package.json +58 -0
- package/postinstall.mjs +102 -0
- package/src/rules/README.md +37 -0
- package/src/rules/common/agent-orchestration.md +86 -0
- package/src/rules/common/coding-style.md +120 -0
- package/src/rules/common/git-workflow.md +77 -0
- package/src/rules/common/security.md +94 -0
- package/src/rules/common/testing.md +105 -0
- package/src/rules/golang/patterns.md +187 -0
- package/src/rules/java/patterns.md +204 -0
- package/src/rules/python/patterns.md +141 -0
- package/src/rules/rust/patterns.md +210 -0
- package/src/rules/typescript/patterns.md +168 -0
- package/src/skills/api-design/SKILL.md +143 -0
- package/src/skills/arch-constraint-guard/SKILL.md +61 -0
- package/src/skills/blast-radius-preview/SKILL.md +65 -0
- package/src/skills/change-impact-radar/SKILL.md +63 -0
- package/src/skills/code-review/SKILL.md +108 -0
- package/src/skills/code-tour/SKILL.md +101 -0
- package/src/skills/codebase-mapping/SKILL.md +87 -0
- package/src/skills/codebase-onboarding/SKILL.md +133 -0
- package/src/skills/confidence-aware-planning/SKILL.md +67 -0
- package/src/skills/context-load/SKILL.md +63 -0
- package/src/skills/debug-flow/SKILL.md +75 -0
- package/src/skills/decision-trace/SKILL.md +72 -0
- package/src/skills/dependency-audit/SKILL.md +126 -0
- package/src/skills/deploy-check/SKILL.md +87 -0
- package/src/skills/documentation-writer/SKILL.md +154 -0
- package/src/skills/failure-replay-engine/SKILL.md +59 -0
- package/src/skills/git-release/SKILL.md +94 -0
- package/src/skills/git-workflow/SKILL.md +177 -0
- package/src/skills/golang-patterns/SKILL.md +511 -0
- package/src/skills/human-review-routing/SKILL.md +65 -0
- package/src/skills/intent-translator/SKILL.md +57 -0
- package/src/skills/java-patterns/SKILL.md +479 -0
- package/src/skills/multi-repo/SKILL.md +187 -0
- package/src/skills/parallel-execute/SKILL.md +92 -0
- package/src/skills/patch-trust-score/SKILL.md +44 -0
- package/src/skills/performance-profiling/SKILL.md +153 -0
- package/src/skills/plan-task/SKILL.md +101 -0
- package/src/skills/python-patterns/SKILL.md +529 -0
- package/src/skills/refactor-guide/SKILL.md +117 -0
- package/src/skills/regression-prediction/SKILL.md +57 -0
- package/src/skills/repo-memory-graph/SKILL.md +49 -0
- package/src/skills/rust-patterns/SKILL.md +492 -0
- package/src/skills/security-scan/SKILL.md +91 -0
- package/src/skills/self-healing-policies/SKILL.md +76 -0
- package/src/skills/tdd-workflow/SKILL.md +126 -0
- package/src/skills/test-coverage/SKILL.md +94 -0
- package/src/skills/test-gap-detector/SKILL.md +58 -0
- package/src/skills/volatility-map/SKILL.md +52 -0
- package/src/workflows/debug-flow.md +119 -0
- package/src/workflows/deploy-check-flow.md +98 -0
- package/src/workflows/discuss-flow.md +97 -0
- package/src/workflows/execute-flow.md +233 -0
- package/src/workflows/execute-phase.md +142 -0
- package/src/workflows/fix-bug-flow.md +210 -0
- package/src/workflows/map-codebase-flow.md +92 -0
- package/src/workflows/multi-repo-flow.md +226 -0
- package/src/workflows/parallel-execution-flow.md +236 -0
- package/src/workflows/plan-flow.md +126 -0
- package/src/workflows/plan-phase.md +101 -0
- package/src/workflows/refactor-flow.md +122 -0
- package/src/workflows/review-code-flow.md +105 -0
- package/src/workflows/spec-driven-flow.md +43 -0
- package/src/workflows/write-docs-flow.md +95 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: repo-memory-graph
|
|
3
|
+
description: Build and maintain a persistent graph of architecture, conventions, bug history, ownership patterns, and module relationships for this specific codebase.
|
|
4
|
+
origin: FlowDeck
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Repo Memory Graph
|
|
8
|
+
|
|
9
|
+
The Repo Memory Graph is FlowDeck's long-term knowledge store about this specific codebase. It persists in `.codebase/MEMORY.json` and grows over time.
|
|
10
|
+
|
|
11
|
+
## What Gets Stored
|
|
12
|
+
|
|
13
|
+
- **Modules**: files, their type (service/api/schema/config), owner, tags
|
|
14
|
+
- **Dependencies**: which modules import or call which others
|
|
15
|
+
- **Conventions**: patterns used in this repo (naming, error handling, auth flow)
|
|
16
|
+
- **Bug history**: which modules have had recurring issues
|
|
17
|
+
- **Ownership**: who owns what (from git blame, CODEOWNERS, or explicit annotation)
|
|
18
|
+
|
|
19
|
+
## When to Update
|
|
20
|
+
|
|
21
|
+
Update the graph:
|
|
22
|
+
- After running `/map-codebase`
|
|
23
|
+
- When onboarding a new module
|
|
24
|
+
- When a bug fix reveals a recurring pattern (add to `bug_history`)
|
|
25
|
+
- When a refactor changes module ownership
|
|
26
|
+
|
|
27
|
+
## Usage with `repo-memory` tool
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
// Write a node
|
|
31
|
+
{ "action": "write_node", "node_id": "auth-service", "node": {
|
|
32
|
+
"type": "service", "path": "src/services/auth.ts",
|
|
33
|
+
"owner": "security-team", "tags": ["auth", "jwt"],
|
|
34
|
+
"dependencies": ["user-model", "token-store"],
|
|
35
|
+
"dependents": ["api-gateway", "session-handler"],
|
|
36
|
+
"bug_history": ["jwt-expiry-bug-2024-03"],
|
|
37
|
+
"conventions": ["always validate token before processing"]
|
|
38
|
+
}}
|
|
39
|
+
|
|
40
|
+
// Query by owner
|
|
41
|
+
{ "action": "query", "query": { "owner": "security-team" } }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## How Agents Use This
|
|
45
|
+
|
|
46
|
+
- **Impact Radar**: walks the dependency graph to find affected modules
|
|
47
|
+
- **Blast Radius**: traverses dependents to map downstream risk
|
|
48
|
+
- **Regression Prediction**: uses bug_history to weight risk categories
|
|
49
|
+
- **Architectural Constraint Guard**: checks module boundaries before allowing edits
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-patterns
|
|
3
|
+
description: Rust patterns covering ownership, lifetimes, error handling, traits, async/await with Tokio, smart pointers, and common pitfalls. Activate when writing or reviewing Rust code.
|
|
4
|
+
origin: FlowDeck
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Rust Patterns Skill
|
|
8
|
+
|
|
9
|
+
Safe, idiomatic Rust for production systems. Covers the ownership model, trait system, and async patterns.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
Activate when:
|
|
14
|
+
- Writing new Rust crates or services
|
|
15
|
+
- Reviewing Rust code for safety and idiom
|
|
16
|
+
- Fighting the borrow checker and looking for solutions
|
|
17
|
+
- Designing async services with Tokio
|
|
18
|
+
- Choosing between smart pointer types
|
|
19
|
+
|
|
20
|
+
## Ownership and Borrowing — Mental Model
|
|
21
|
+
|
|
22
|
+
Every value has exactly one owner. When the owner goes out of scope, the value is dropped. References borrow a value without taking ownership.
|
|
23
|
+
|
|
24
|
+
### The Three Rules
|
|
25
|
+
|
|
26
|
+
1. Each value has exactly one owner.
|
|
27
|
+
2. There can be any number of shared (`&T`) references, OR exactly one exclusive (`&mut T`) reference — never both at the same time.
|
|
28
|
+
3. References must not outlive the value they point to.
|
|
29
|
+
|
|
30
|
+
```rust
|
|
31
|
+
fn main() {
|
|
32
|
+
let s1 = String::from("hello");
|
|
33
|
+
let s2 = s1; // ownership moved to s2
|
|
34
|
+
// println!("{s1}"); // compile error: s1 moved
|
|
35
|
+
|
|
36
|
+
let s3 = String::from("world");
|
|
37
|
+
let r1 = &s3; // shared borrow
|
|
38
|
+
let r2 = &s3; // another shared borrow — fine
|
|
39
|
+
println!("{r1} {r2}");
|
|
40
|
+
|
|
41
|
+
let mut s4 = String::from("mutable");
|
|
42
|
+
let r3 = &mut s4; // exclusive borrow
|
|
43
|
+
r3.push_str("!");
|
|
44
|
+
// let r4 = &s4; // compile error: s4 already mutably borrowed
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Clone When You Need a Copy
|
|
49
|
+
|
|
50
|
+
```rust
|
|
51
|
+
// clone() is explicit and potentially expensive — use it knowingly
|
|
52
|
+
let original = vec![1, 2, 3];
|
|
53
|
+
let copy = original.clone();
|
|
54
|
+
// both are usable
|
|
55
|
+
|
|
56
|
+
// For cheap copies, implement Copy (stack-allocated types)
|
|
57
|
+
#[derive(Clone, Copy)]
|
|
58
|
+
struct Point { x: f64, y: f64 }
|
|
59
|
+
|
|
60
|
+
let p1 = Point { x: 1.0, y: 2.0 };
|
|
61
|
+
let p2 = p1; // copied, not moved — p1 still valid
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Lifetime Annotations
|
|
65
|
+
|
|
66
|
+
The compiler infers lifetimes in most cases via elision rules. Annotate when the compiler cannot determine the relationship.
|
|
67
|
+
|
|
68
|
+
### When Annotations Are Required
|
|
69
|
+
|
|
70
|
+
```rust
|
|
71
|
+
// Return value borrows from one of the arguments — annotate the relationship
|
|
72
|
+
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
|
73
|
+
if x.len() > y.len() { x } else { y }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Struct holding a reference must declare its lifetime
|
|
77
|
+
struct Excerpt<'a> {
|
|
78
|
+
text: &'a str,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
impl<'a> Excerpt<'a> {
|
|
82
|
+
fn content(&self) -> &str {
|
|
83
|
+
self.text // lifetime elided — same as self's lifetime
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Elision Rules (No Annotation Needed)
|
|
89
|
+
|
|
90
|
+
```rust
|
|
91
|
+
// Rule 1: each input reference gets its own lifetime
|
|
92
|
+
fn first_word(s: &str) -> &str { ... }
|
|
93
|
+
// expanded: fn first_word<'a>(s: &'a str) -> &'a str
|
|
94
|
+
|
|
95
|
+
// Rule 2: if there's exactly one input lifetime, it applies to all outputs
|
|
96
|
+
fn trim(s: &str) -> &str { s.trim() }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 'static — Only When Truly Static
|
|
100
|
+
|
|
101
|
+
```rust
|
|
102
|
+
// String literals have 'static lifetime
|
|
103
|
+
let s: &'static str = "I live for the entire program";
|
|
104
|
+
|
|
105
|
+
// Avoid &'static in generic bounds unless you truly need it — it rules out
|
|
106
|
+
// borrowed data entirely and forces owned types or leaked memory
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Error Handling
|
|
110
|
+
|
|
111
|
+
### Result<T, E> and the ? Operator
|
|
112
|
+
|
|
113
|
+
```rust
|
|
114
|
+
use std::fs;
|
|
115
|
+
use std::io;
|
|
116
|
+
|
|
117
|
+
fn read_config(path: &str) -> Result<String, io::Error> {
|
|
118
|
+
let content = fs::read_to_string(path)?; // ? returns early on Err
|
|
119
|
+
Ok(content.trim().to_owned())
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Chaining with map_err to convert error types
|
|
123
|
+
fn parse_port(s: &str) -> Result<u16, String> {
|
|
124
|
+
s.parse::<u16>()
|
|
125
|
+
.map_err(|e| format!("invalid port {s:?}: {e}"))
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### thiserror — Library Error Types
|
|
130
|
+
|
|
131
|
+
```rust
|
|
132
|
+
use thiserror::Error;
|
|
133
|
+
|
|
134
|
+
#[derive(Debug, Error)]
|
|
135
|
+
pub enum StoreError {
|
|
136
|
+
#[error("record {id} not found")]
|
|
137
|
+
NotFound { id: u64 },
|
|
138
|
+
|
|
139
|
+
#[error("database error")]
|
|
140
|
+
Database(#[from] sqlx::Error),
|
|
141
|
+
|
|
142
|
+
#[error("serialization failed: {0}")]
|
|
143
|
+
Serialize(#[from] serde_json::Error),
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Callers can pattern-match on variants
|
|
147
|
+
match store.get(id).await {
|
|
148
|
+
Err(StoreError::NotFound { id }) => respond_404(id),
|
|
149
|
+
Err(e) => respond_500(e),
|
|
150
|
+
Ok(record) => respond_200(record),
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### anyhow — Application Error Handling
|
|
155
|
+
|
|
156
|
+
```rust
|
|
157
|
+
use anyhow::{Context, Result};
|
|
158
|
+
|
|
159
|
+
// anyhow::Result<T> = Result<T, anyhow::Error>
|
|
160
|
+
async fn run() -> Result<()> {
|
|
161
|
+
let config = load_config("app.toml")
|
|
162
|
+
.context("failed to load application config")?;
|
|
163
|
+
|
|
164
|
+
let db = connect(&config.database_url).await
|
|
165
|
+
.context("database connection failed")?;
|
|
166
|
+
|
|
167
|
+
serve(db, config.port).await
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// context() attaches a message; with_context() is lazy (use for expensive messages)
|
|
171
|
+
let data = fetch(url).await
|
|
172
|
+
.with_context(|| format!("fetch failed for url: {url}"))?;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Trait System
|
|
176
|
+
|
|
177
|
+
### impl Trait — Static Dispatch
|
|
178
|
+
|
|
179
|
+
```rust
|
|
180
|
+
// Return an opaque type — compiler monomorphises at call site
|
|
181
|
+
fn make_greeting(name: &str) -> impl Display {
|
|
182
|
+
format!("Hello, {name}!")
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Accept any type implementing a trait — zero-cost abstraction
|
|
186
|
+
fn print_all(items: &[impl Display]) {
|
|
187
|
+
for item in items {
|
|
188
|
+
println!("{item}");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### dyn Trait — Dynamic Dispatch
|
|
194
|
+
|
|
195
|
+
```rust
|
|
196
|
+
// Trait objects — runtime dispatch, heap-allocated
|
|
197
|
+
fn make_handler(kind: &str) -> Box<dyn Handler> {
|
|
198
|
+
match kind {
|
|
199
|
+
"log" => Box::new(LogHandler::new()),
|
|
200
|
+
"audit" => Box::new(AuditHandler::new()),
|
|
201
|
+
_ => Box::new(NoopHandler),
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Object safety rules: no generic methods, no Self return types
|
|
206
|
+
// Use dyn Trait only when you need heterogeneous collections or
|
|
207
|
+
// when the concrete type isn't known until runtime
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Where Clauses for Readability
|
|
211
|
+
|
|
212
|
+
```rust
|
|
213
|
+
// Inline bounds get crowded
|
|
214
|
+
fn process<T: Debug + Clone + Send + 'static>(item: T) { ... }
|
|
215
|
+
|
|
216
|
+
// Where clause is cleaner
|
|
217
|
+
fn process<T>(item: T)
|
|
218
|
+
where
|
|
219
|
+
T: Debug + Clone + Send + 'static,
|
|
220
|
+
{
|
|
221
|
+
...
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Blanket Implementations
|
|
226
|
+
|
|
227
|
+
```rust
|
|
228
|
+
// Implement a trait for all types that satisfy a constraint
|
|
229
|
+
impl<T: Display> MyPrint for T {
|
|
230
|
+
fn print(&self) { println!("{self}"); }
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Iterators
|
|
235
|
+
|
|
236
|
+
Iterators are lazy — no work until consumed. Chain adapters freely; the compiler fuses them.
|
|
237
|
+
|
|
238
|
+
```rust
|
|
239
|
+
let result: Vec<String> = (1..=10)
|
|
240
|
+
.filter(|n| n % 2 == 0)
|
|
241
|
+
.map(|n| n * n)
|
|
242
|
+
.take(3)
|
|
243
|
+
.map(|n| format!("n={n}"))
|
|
244
|
+
.collect();
|
|
245
|
+
// ["n=4", "n=16", "n=36"]
|
|
246
|
+
|
|
247
|
+
// fold — general reduction
|
|
248
|
+
let product: u64 = (1..=10).fold(1, |acc, n| acc * n);
|
|
249
|
+
|
|
250
|
+
// chain — concatenate iterators
|
|
251
|
+
let combined: Vec<i32> = vec![1, 2].into_iter()
|
|
252
|
+
.chain(vec![3, 4].into_iter())
|
|
253
|
+
.collect();
|
|
254
|
+
|
|
255
|
+
// Custom iterator
|
|
256
|
+
struct Counter { count: u32, max: u32 }
|
|
257
|
+
|
|
258
|
+
impl Iterator for Counter {
|
|
259
|
+
type Item = u32;
|
|
260
|
+
fn next(&mut self) -> Option<u32> {
|
|
261
|
+
if self.count < self.max {
|
|
262
|
+
self.count += 1;
|
|
263
|
+
Some(self.count)
|
|
264
|
+
} else {
|
|
265
|
+
None
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Async/Await with Tokio
|
|
272
|
+
|
|
273
|
+
### Spawning Tasks
|
|
274
|
+
|
|
275
|
+
```rust
|
|
276
|
+
use tokio::task;
|
|
277
|
+
|
|
278
|
+
#[tokio::main]
|
|
279
|
+
async fn main() {
|
|
280
|
+
let handle: task::JoinHandle<u64> = tokio::spawn(async {
|
|
281
|
+
compute_heavy_thing().await
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
let result = handle.await.expect("task panicked");
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### select! — Racing Futures
|
|
289
|
+
|
|
290
|
+
```rust
|
|
291
|
+
use tokio::select;
|
|
292
|
+
use tokio::time::{sleep, Duration};
|
|
293
|
+
|
|
294
|
+
async fn with_timeout<T>(fut: impl Future<Output = T>, ms: u64) -> Option<T> {
|
|
295
|
+
select! {
|
|
296
|
+
result = fut => Some(result),
|
|
297
|
+
_ = sleep(Duration::from_millis(ms)) => None,
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Channels
|
|
303
|
+
|
|
304
|
+
```rust
|
|
305
|
+
use tokio::sync::{mpsc, oneshot};
|
|
306
|
+
|
|
307
|
+
// mpsc — multiple producers, single consumer
|
|
308
|
+
let (tx, mut rx) = mpsc::channel::<String>(32); // bounded, backpressure
|
|
309
|
+
|
|
310
|
+
tokio::spawn(async move {
|
|
311
|
+
while let Some(msg) = rx.recv().await {
|
|
312
|
+
process(msg).await;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
tx.send("hello".to_owned()).await.unwrap();
|
|
317
|
+
|
|
318
|
+
// oneshot — single response (request/reply pattern)
|
|
319
|
+
let (resp_tx, resp_rx) = oneshot::channel::<Result<User, StoreError>>();
|
|
320
|
+
|
|
321
|
+
tokio::spawn(async move {
|
|
322
|
+
let user = db.find_user(id).await;
|
|
323
|
+
let _ = resp_tx.send(user);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
let user = resp_rx.await.expect("worker dropped");
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Smart Pointers
|
|
330
|
+
|
|
331
|
+
| Type | Ownership | Thread-safe | Interior mutability |
|
|
332
|
+
|------|-----------|-------------|---------------------|
|
|
333
|
+
| `Box<T>` | owned, heap | yes (if T: Send) | no |
|
|
334
|
+
| `Rc<T>` | shared, heap | ❌ no | no |
|
|
335
|
+
| `Arc<T>` | shared, heap | ✅ yes | no |
|
|
336
|
+
| `RefCell<T>` | owned | ❌ no | ✅ runtime borrow |
|
|
337
|
+
| `Mutex<T>` | owned | ✅ yes | ✅ locked |
|
|
338
|
+
| `RwLock<T>` | owned | ✅ yes | ✅ locked |
|
|
339
|
+
|
|
340
|
+
```rust
|
|
341
|
+
// Box — when you need heap allocation or unsized types
|
|
342
|
+
let large: Box<[u8; 1_000_000]> = Box::new([0; 1_000_000]);
|
|
343
|
+
|
|
344
|
+
// Arc — shared ownership across threads
|
|
345
|
+
let shared = Arc::new(Config::load());
|
|
346
|
+
let clone = Arc::clone(&shared);
|
|
347
|
+
tokio::spawn(async move { use_config(clone).await });
|
|
348
|
+
|
|
349
|
+
// Arc<Mutex<T>> — shared mutable state across threads
|
|
350
|
+
let counter = Arc::new(Mutex::new(0u64));
|
|
351
|
+
let c = Arc::clone(&counter);
|
|
352
|
+
tokio::spawn(async move {
|
|
353
|
+
*c.lock().await += 1;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// Rc<RefCell<T>> — shared mutable state in single-threaded contexts
|
|
357
|
+
let node = Rc::new(RefCell::new(Node::new()));
|
|
358
|
+
node.borrow_mut().value = 42;
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Enums and Pattern Matching
|
|
362
|
+
|
|
363
|
+
```rust
|
|
364
|
+
#[derive(Debug)]
|
|
365
|
+
enum Command {
|
|
366
|
+
Quit,
|
|
367
|
+
Move { x: i32, y: i32 },
|
|
368
|
+
Write(String),
|
|
369
|
+
ChangeColor(u8, u8, u8),
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
fn execute(cmd: Command) {
|
|
373
|
+
match cmd {
|
|
374
|
+
Command::Quit => println!("quit"),
|
|
375
|
+
Command::Move { x, y } => println!("move to ({x},{y})"),
|
|
376
|
+
Command::Write(msg) => println!("write: {msg}"),
|
|
377
|
+
Command::ChangeColor(r, g, b) => println!("color: #{r:02x}{g:02x}{b:02x}"),
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// if let — when only one variant matters
|
|
382
|
+
if let Some(value) = map.get("key") {
|
|
383
|
+
println!("found: {value}");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// while let — consume until variant changes
|
|
387
|
+
let mut stack = vec![1, 2, 3];
|
|
388
|
+
while let Some(top) = stack.pop() {
|
|
389
|
+
println!("{top}");
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Cargo Workspace and Features
|
|
394
|
+
|
|
395
|
+
### Workspace
|
|
396
|
+
|
|
397
|
+
```toml
|
|
398
|
+
# Cargo.toml at root
|
|
399
|
+
[workspace]
|
|
400
|
+
members = ["crates/core", "crates/api", "crates/cli"]
|
|
401
|
+
resolver = "2"
|
|
402
|
+
|
|
403
|
+
[workspace.dependencies]
|
|
404
|
+
tokio = { version = "1", features = ["full"] }
|
|
405
|
+
serde = { version = "1", features = ["derive"] }
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Conditional Compilation with Features
|
|
409
|
+
|
|
410
|
+
```toml
|
|
411
|
+
# crates/core/Cargo.toml
|
|
412
|
+
[features]
|
|
413
|
+
default = []
|
|
414
|
+
metrics = ["dep:prometheus"]
|
|
415
|
+
tracing = ["dep:tracing-subscriber"]
|
|
416
|
+
|
|
417
|
+
[dependencies]
|
|
418
|
+
prometheus = { version = "0.13", optional = true }
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
```rust
|
|
422
|
+
#[cfg(feature = "metrics")]
|
|
423
|
+
fn record_metric(name: &str, value: f64) {
|
|
424
|
+
prometheus::counter!(name).inc_by(value);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
#[cfg(not(feature = "metrics"))]
|
|
428
|
+
fn record_metric(_name: &str, _value: f64) {}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Common Pitfalls
|
|
432
|
+
|
|
433
|
+
### Fighting the Borrow Checker — Solutions
|
|
434
|
+
|
|
435
|
+
```rust
|
|
436
|
+
// Problem: returning a reference to something inside a match
|
|
437
|
+
// Solution: clone or restructure to return owned data
|
|
438
|
+
|
|
439
|
+
// Problem: two mutable references to different fields of a struct
|
|
440
|
+
struct Grid { rows: Vec<Vec<i32>>, count: usize }
|
|
441
|
+
impl Grid {
|
|
442
|
+
fn swap_and_count(&mut self, r1: usize, r2: usize) {
|
|
443
|
+
// borrow checker rejects: &mut self.rows and &mut self.count at once
|
|
444
|
+
// Solution: split borrows by borrowing fields directly
|
|
445
|
+
let (rows, count) = (&mut self.rows, &mut self.count);
|
|
446
|
+
rows.swap(r1, r2);
|
|
447
|
+
*count += 1;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Problem: value moved in loop
|
|
452
|
+
// Solution: borrow or clone before the loop, or use indices
|
|
453
|
+
for item in &items { // borrow — items still usable after loop
|
|
454
|
+
process(item);
|
|
455
|
+
}
|
|
456
|
+
for item in items.iter() { // same as above, explicit
|
|
457
|
+
process(item);
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### String vs &str vs &[u8]
|
|
462
|
+
|
|
463
|
+
```rust
|
|
464
|
+
// &str — borrowed string slice — use in function parameters when you don't need ownership
|
|
465
|
+
fn greet(name: &str) -> String { format!("Hello, {name}!") }
|
|
466
|
+
|
|
467
|
+
// String — owned, heap-allocated, growable — return types, struct fields
|
|
468
|
+
struct User { name: String }
|
|
469
|
+
|
|
470
|
+
// &[u8] — raw bytes — use for binary data or when encoding is uncertain
|
|
471
|
+
fn checksum(data: &[u8]) -> u32 { ... }
|
|
472
|
+
|
|
473
|
+
// Vec<u8> — owned bytes — when you need to mutate or own binary data
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Copy vs Clone
|
|
477
|
+
|
|
478
|
+
```rust
|
|
479
|
+
// Copy types are silently duplicated on assignment (all stack data: i32, bool, char, &T, arrays of Copy)
|
|
480
|
+
let x: i32 = 5;
|
|
481
|
+
let y = x; // x is still valid — i32 implements Copy
|
|
482
|
+
|
|
483
|
+
// Clone is explicit — use when the duplication is intentional and potentially expensive
|
|
484
|
+
#[derive(Clone)] // opt in
|
|
485
|
+
struct Config { /* ... */ }
|
|
486
|
+
|
|
487
|
+
let c1 = Config::load();
|
|
488
|
+
let c2 = c1.clone(); // explicit, reader knows a copy was made
|
|
489
|
+
|
|
490
|
+
// Do not implement Copy for types with heap data — it creates shallow copies
|
|
491
|
+
// that would double-free. The compiler prevents this for types with Drop.
|
|
492
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-scan
|
|
3
|
+
description: Pre-commit security scan covering secrets, injection, auth, CVE dependencies. Returns PASS/FAIL verdict with severity-ranked findings and specific remediations.
|
|
4
|
+
origin: FlowDeck
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Security Scan Skill
|
|
8
|
+
|
|
9
|
+
Catches security issues before they reach production. Returns a severity-ranked report with specific remediations.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
Activate:
|
|
14
|
+
- Before merging any PR that touches auth, data access, or API routes
|
|
15
|
+
- Before every production deployment
|
|
16
|
+
- When adding new dependencies
|
|
17
|
+
- When changing environment variable handling
|
|
18
|
+
|
|
19
|
+
## Core Principles
|
|
20
|
+
|
|
21
|
+
- Security takes priority over convenience
|
|
22
|
+
- Every finding includes a specific remediation
|
|
23
|
+
- CRITICAL or HIGH = must fix before merge
|
|
24
|
+
- No exceptions without documented risk acceptance
|
|
25
|
+
|
|
26
|
+
## Workflow
|
|
27
|
+
|
|
28
|
+
1. Check for hardcoded secrets (grep patterns)
|
|
29
|
+
2. Check for injection vulnerabilities (SQL, command, template)
|
|
30
|
+
3. Verify auth middleware on protected routes
|
|
31
|
+
4. Check input validation at API boundaries
|
|
32
|
+
5. Run `npm audit --audit-level=moderate`
|
|
33
|
+
6. Review sensitive data in logs
|
|
34
|
+
7. Produce verdict
|
|
35
|
+
|
|
36
|
+
## OWASP Top 10 Quick Reference
|
|
37
|
+
|
|
38
|
+
| ID | Name | Check For |
|
|
39
|
+
|----|------|-----------|
|
|
40
|
+
| A01 | Broken Access Control | Missing auth checks, IDOR, privilege escalation |
|
|
41
|
+
| A02 | Cryptographic Failures | HTTP for sensitive data, MD5/SHA1 for passwords |
|
|
42
|
+
| A03 | Injection | SQL/NoSQL/cmd/template injection via string concat |
|
|
43
|
+
| A04 | Insecure Design | Missing rate limiting, no lockout after failed logins |
|
|
44
|
+
| A05 | Security Misconfiguration | Debug mode in prod, default credentials, verbose errors |
|
|
45
|
+
| A06 | Vulnerable Components | CVEs in dependencies (run npm audit) |
|
|
46
|
+
| A07 | Auth Failures | Missing middleware, weak JWT, no session invalidation |
|
|
47
|
+
| A08 | Integrity Failures | Missing input validation, unsafe deserialization |
|
|
48
|
+
| A09 | Logging Failures | Passwords/tokens in logs, insufficient logging |
|
|
49
|
+
| A10 | SSRF | User-controlled URLs fetched by server without validation |
|
|
50
|
+
|
|
51
|
+
## Scan Commands
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Dependency vulnerabilities
|
|
55
|
+
npm audit --audit-level=moderate
|
|
56
|
+
|
|
57
|
+
# Hardcoded secrets (grep patterns)
|
|
58
|
+
grep -r "password\s*=\s*['\"]" src/ --include="*.ts"
|
|
59
|
+
grep -r "api_key\s*=\s*['\"]" src/ --include="*.ts"
|
|
60
|
+
grep -r "secret\s*=\s*['\"]" src/ --include="*.ts"
|
|
61
|
+
|
|
62
|
+
# SQL string concatenation
|
|
63
|
+
grep -r "query\`.*\${" src/ --include="*.ts"
|
|
64
|
+
grep -rn "query.*+.*req\." src/ --include="*.ts"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Output Format
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
## Security Scan Report
|
|
71
|
+
|
|
72
|
+
### 🔴 Critical
|
|
73
|
+
| # | File | Line | Issue | Remediation |
|
|
74
|
+
|---|------|------|-------|-------------|
|
|
75
|
+
|
|
76
|
+
### 🟠 High
|
|
77
|
+
| # | File | Line | Issue | Remediation |
|
|
78
|
+
|---|------|------|-------|-------------|
|
|
79
|
+
|
|
80
|
+
### 🟡 Medium
|
|
81
|
+
| # | File | Line | Issue | Remediation |
|
|
82
|
+
|---|------|------|-------|-------------|
|
|
83
|
+
|
|
84
|
+
### Dependencies
|
|
85
|
+
- npm audit: 0 critical, 0 high, 2 moderate (tracked)
|
|
86
|
+
|
|
87
|
+
### Verdict: PASS ✅ | FAIL ❌ | PASS_WITH_NOTES ⚠️
|
|
88
|
+
|
|
89
|
+
FAIL if any Critical or High findings.
|
|
90
|
+
PASS_WITH_NOTES if only Medium or Low findings.
|
|
91
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: self-healing-policies
|
|
3
|
+
description: Update internal editing rules automatically after repeated failures, making the plugin more reliable over time inside the same repo.
|
|
4
|
+
origin: FlowDeck
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Self-Healing Prompt Policies
|
|
8
|
+
|
|
9
|
+
FlowDeck can learn from its own mistakes. When the same type of failure recurs, a new policy is added to `.codebase/POLICIES.json` to prevent it from happening again.
|
|
10
|
+
|
|
11
|
+
## How Policies Work
|
|
12
|
+
|
|
13
|
+
A policy is a trigger → rule pair:
|
|
14
|
+
- **trigger**: the pattern that precedes the mistake (e.g., "editing auth middleware")
|
|
15
|
+
- **rule**: what the agent must do/avoid when the trigger matches (e.g., "always run auth integration tests before committing")
|
|
16
|
+
|
|
17
|
+
## Policy Lifecycle
|
|
18
|
+
|
|
19
|
+
1. **Detection**: A failure is recorded in FAILURES.json with recurrence_count ≥ 2
|
|
20
|
+
2. **Proposal**: The agent proposes a new policy to prevent the recurrence
|
|
21
|
+
3. **Review**: Human reviews and approves/rejects via `/policy-update`
|
|
22
|
+
4. **Active**: Policy is marked active=true and checked before relevant edits
|
|
23
|
+
5. **Violation tracking**: Every time a policy is nearly violated, record it
|
|
24
|
+
6. **Pruning**: Policies with 0 violations in 90 days are candidates for deactivation
|
|
25
|
+
|
|
26
|
+
## Policy Sources
|
|
27
|
+
|
|
28
|
+
| Source | Meaning |
|
|
29
|
+
|--------|---------|
|
|
30
|
+
| manual | Added by a human directly |
|
|
31
|
+
| learned | Proposed by the agent after failure pattern detected |
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
### Adding a Learned Policy
|
|
36
|
+
|
|
37
|
+
After recording a recurrent failure:
|
|
38
|
+
1. Check if recurrence_count ≥ 2 for any failure entry
|
|
39
|
+
2. If yes, propose a policy:
|
|
40
|
+
```json
|
|
41
|
+
{ "action": "add", "policy": {
|
|
42
|
+
"id": "no-auth-edit-without-tests",
|
|
43
|
+
"name": "Auth edits require test run",
|
|
44
|
+
"trigger": "editing files matching src/auth/ or src/middleware/",
|
|
45
|
+
"rule": "Always run auth test suite before committing. If no auth tests exist, create at least one regression test.",
|
|
46
|
+
"source": "learned",
|
|
47
|
+
"failure_count": 3
|
|
48
|
+
}}
|
|
49
|
+
```
|
|
50
|
+
3. Notify the human for approval
|
|
51
|
+
|
|
52
|
+
### Checking Policies Before Edit
|
|
53
|
+
|
|
54
|
+
Before editing a file:
|
|
55
|
+
1. Query active policies: `{ "action": "query", "query": { "active_only": true } }`
|
|
56
|
+
2. Check if any policy trigger matches the current file path or change type
|
|
57
|
+
3. If match: apply the rule before proceeding
|
|
58
|
+
|
|
59
|
+
### Updating Policies After New Failure
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{ "action": "record_violation", "policy_id": "no-auth-edit-without-tests" }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Manual Policy Management
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
/policy-update {"action": "add", "policy": {...}} — add new policy
|
|
69
|
+
/policy-update {"action": "toggle", "policy_id": "X", "active": false} — disable
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Guidance
|
|
73
|
+
|
|
74
|
+
- Policies should be specific ("when editing X, always Y") not vague ("be careful")
|
|
75
|
+
- Every learned policy must reference the failure ID that triggered it
|
|
76
|
+
- Review all policies quarterly — disable ones that have never fired
|