@ngxtm/devkit 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -197
- package/cli/detect.js +292 -0
- package/cli/index.js +204 -92
- package/cli/init.js +245 -0
- package/cli/update.js +243 -0
- package/cli/utils.js +195 -0
- package/hooks/lib/__tests__/ck-config-utils.test.cjs +10 -0
- package/hooks/lib/__tests__/statusline-integration.test.cjs +46 -75
- package/hooks/scout-block/tests/test-monorepo-scenarios.cjs +2 -2
- package/hooks/tests/test-ckignore.cjs +7 -2
- package/package.json +16 -20
- package/rules-index.json +76 -0
- package/scripts/generate-index.js +223 -0
- package/scripts/merge-commands.js +290 -0
- package/scripts/organize-rules.js +226 -0
- package/templates/base/hooks/lib/ck-config-utils.cjs +769 -0
- package/templates/base/hooks/lib/ck-paths.cjs +110 -0
- package/templates/base/hooks/lib/colors.cjs +95 -0
- package/templates/base/hooks/lib/config-counter.cjs +103 -0
- package/templates/base/hooks/lib/context-builder.cjs +600 -0
- package/templates/base/hooks/lib/context-tracker.cjs +335 -0
- package/templates/base/hooks/lib/privacy-checker.cjs +297 -0
- package/templates/base/hooks/lib/project-detector.cjs +430 -0
- package/templates/base/hooks/lib/scout-checker.cjs +172 -0
- package/templates/base/hooks/lib/transcript-parser.cjs +164 -0
- package/templates/base/hooks/privacy-block.cjs +145 -0
- package/agents/backend-engineer.md +0 -154
- package/agents/brainstormer.md +0 -169
- package/agents/business-analyst.md +0 -166
- package/agents/database-architect.md +0 -159
- package/agents/debugger.md +0 -155
- package/agents/designer.md +0 -150
- package/agents/devops-engineer.md +0 -155
- package/agents/docs-manager.md +0 -171
- package/agents/frontend-engineer.md +0 -159
- package/agents/game-engineer.md +0 -148
- package/agents/mobile-engineer.md +0 -149
- package/agents/performance-engineer.md +0 -152
- package/agents/planner.md +0 -161
- package/agents/project-manager.md +0 -160
- package/agents/researcher.md +0 -146
- package/agents/reviewer.md +0 -155
- package/agents/scouter.md +0 -157
- package/agents/security-engineer.md +0 -154
- package/agents/tech-lead.md +0 -159
- package/agents/tester.md +0 -157
- package/agents-claudekit/brainstormer.md +0 -113
- package/agents-claudekit/code-reviewer.md +0 -157
- package/agents-claudekit/code-simplifier.md +0 -42
- package/agents-claudekit/copywriter.md +0 -110
- package/agents-claudekit/database-admin.md +0 -92
- package/agents-claudekit/debugger.md +0 -137
- package/agents-claudekit/docs-manager.md +0 -208
- package/agents-claudekit/fullstack-developer.md +0 -95
- package/agents-claudekit/git-manager.md +0 -394
- package/agents-claudekit/journal-writer.md +0 -113
- package/agents-claudekit/mcp-manager.md +0 -93
- package/agents-claudekit/planner.md +0 -108
- package/agents-claudekit/project-manager.md +0 -125
- package/agents-claudekit/researcher.md +0 -38
- package/agents-claudekit/scout-external.md +0 -141
- package/agents-claudekit/scout.md +0 -107
- package/agents-claudekit/tester.md +0 -105
- package/agents-claudekit/ui-ux-designer.md +0 -236
- package/commands/ask.md +0 -64
- package/commands/brainstorm.md +0 -64
- package/commands/code.md +0 -64
- package/commands/cook.md +0 -64
- package/commands/debug.md +0 -64
- package/commands/design/fast.md +0 -134
- package/commands/fix/fast.md +0 -84
- package/commands/fix/hard.md +0 -116
- package/commands/fix.md +0 -64
- package/commands/plan/fast.md +0 -78
- package/commands/plan/hard.md +0 -131
- package/commands/plan.md +0 -64
- package/commands/test.md +0 -64
- package/hooks/tests/test-modularization-hook.cjs +0 -126
- package/matrix-skills/_index.yaml +0 -275
- package/matrix-skills/ai-ml.yaml +0 -353
- package/matrix-skills/architecture.yaml +0 -93
- package/matrix-skills/backend.yaml +0 -280
- package/matrix-skills/cloud.yaml +0 -112
- package/matrix-skills/data.yaml +0 -74
- package/matrix-skills/design.yaml +0 -98
- package/matrix-skills/devops.yaml +0 -200
- package/matrix-skills/frontend.yaml +0 -200
- package/matrix-skills/gaming.yaml +0 -39
- package/matrix-skills/languages.yaml +0 -160
- package/matrix-skills/management.yaml +0 -50
- package/matrix-skills/mcp.yaml +0 -82
- package/matrix-skills/mobile.yaml +0 -85
- package/matrix-skills/performance.yaml +0 -23
- package/matrix-skills/planning.yaml +0 -117
- package/matrix-skills/quality.yaml +0 -195
- package/matrix-skills/research.yaml +0 -106
- package/matrix-skills/security.yaml +0 -293
- package/matrix-skills/tools.yaml +0 -352
- package/output-styles/coding-level-0-eli5.md +0 -103
- package/output-styles/coding-level-1-junior.md +0 -124
- package/output-styles/coding-level-2-mid.md +0 -146
- package/output-styles/coding-level-3-senior.md +0 -148
- package/output-styles/coding-level-4-lead.md +0 -159
- package/output-styles/coding-level-5-god.md +0 -91
- package/rules/README.md +0 -141
- package/rules/metadata.json +0 -54
- package/settings.json +0 -3
- package/statusline.cjs +0 -500
- package/statusline.ps1 +0 -307
- package/statusline.sh +0 -237
- package/workflows/development-rules.md +0 -42
- package/workflows/documentation-management.md +0 -121
- package/workflows/orchestration-protocol.md +0 -16
- package/workflows/primary-workflow.md +0 -45
- /package/{commands → merged-commands}/ask/fast.md +0 -0
- /package/{commands → merged-commands}/ask/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/ask.md +0 -0
- /package/{commands → merged-commands}/auto.md +0 -0
- /package/{commands-claudekit → merged-commands}/bootstrap/auto/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/bootstrap/auto/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/bootstrap/auto.md +0 -0
- /package/{commands-claudekit → merged-commands}/bootstrap.md +0 -0
- /package/{commands → merged-commands}/brainstorm/fast.md +0 -0
- /package/{commands → merged-commands}/brainstorm/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/brainstorm.md +0 -0
- /package/{commands-claudekit → merged-commands}/ck-help.md +0 -0
- /package/{commands-claudekit → merged-commands}/code/auto.md +0 -0
- /package/{commands → merged-commands}/code/fast.md +0 -0
- /package/{commands → merged-commands}/code/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/code/no-test.md +0 -0
- /package/{commands-claudekit → merged-commands}/code/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/code.md +0 -0
- /package/{commands-claudekit → merged-commands}/coding-level.md +0 -0
- /package/{commands-claudekit → merged-commands}/content/cro.md +0 -0
- /package/{commands-claudekit → merged-commands}/content/enhance.md +0 -0
- /package/{commands-claudekit → merged-commands}/content/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/content/good.md +0 -0
- /package/{commands-claudekit → merged-commands}/cook/auto/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/cook/auto/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/cook/auto.md +0 -0
- /package/{commands → merged-commands}/cook/fast.md +0 -0
- /package/{commands → merged-commands}/cook/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/cook.md +0 -0
- /package/{commands → merged-commands}/debug/fast.md +0 -0
- /package/{commands → merged-commands}/debug/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/debug.md +0 -0
- /package/{commands → merged-commands}/deploy/check.md +0 -0
- /package/{commands → merged-commands}/deploy/preview.md +0 -0
- /package/{commands → merged-commands}/deploy/production.md +0 -0
- /package/{commands → merged-commands}/deploy/rollback.md +0 -0
- /package/{commands → merged-commands}/deploy.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/3d.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/describe.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/good.md +0 -0
- /package/{commands → merged-commands}/design/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/screenshot.md +0 -0
- /package/{commands-claudekit → merged-commands}/design/video.md +0 -0
- /package/{commands → merged-commands}/design.md +0 -0
- /package/{commands → merged-commands}/docs/audit.md +0 -0
- /package/{commands → merged-commands}/docs/business.md +0 -0
- /package/{commands → merged-commands}/docs/core.md +0 -0
- /package/{commands-claudekit → merged-commands}/docs/init.md +0 -0
- /package/{commands-claudekit → merged-commands}/docs/summarize.md +0 -0
- /package/{commands-claudekit → merged-commands}/docs/update.md +0 -0
- /package/{commands → merged-commands}/docs.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/ci.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/logs.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/test.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/types.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix/ui.md +0 -0
- /package/{commands-claudekit → merged-commands}/fix.md +0 -0
- /package/{commands-claudekit → merged-commands}/git/cm.md +0 -0
- /package/{commands-claudekit → merged-commands}/git/cp.md +0 -0
- /package/{commands-claudekit → merged-commands}/git/merge.md +0 -0
- /package/{commands-claudekit → merged-commands}/git/pr.md +0 -0
- /package/{commands-claudekit → merged-commands}/integrate/polar.md +0 -0
- /package/{commands-claudekit → merged-commands}/integrate/sepay.md +0 -0
- /package/{commands-claudekit → merged-commands}/journal.md +0 -0
- /package/{commands-claudekit → merged-commands}/kanban.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/archive.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/ci.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/cro.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/fast.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/two.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan/validate.md +0 -0
- /package/{commands-claudekit → merged-commands}/plan.md +0 -0
- /package/{commands-claudekit → merged-commands}/preview.md +0 -0
- /package/{commands-claudekit → merged-commands}/review/codebase/parallel.md +0 -0
- /package/{commands-claudekit → merged-commands}/review/codebase.md +0 -0
- /package/{commands → merged-commands}/review/fast.md +0 -0
- /package/{commands → merged-commands}/review/hard.md +0 -0
- /package/{commands → merged-commands}/review.md +0 -0
- /package/{commands-claudekit → merged-commands}/scout/ext.md +0 -0
- /package/{commands-claudekit → merged-commands}/scout.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/add.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/create.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/fix-logs.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/optimize/auto.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/optimize.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/plan.md +0 -0
- /package/{commands-claudekit → merged-commands}/skill/update.md +0 -0
- /package/{commands → merged-commands}/test/fast.md +0 -0
- /package/{commands → merged-commands}/test/hard.md +0 -0
- /package/{commands-claudekit → merged-commands}/test/ui.md +0 -0
- /package/{commands-claudekit → merged-commands}/test.md +0 -0
- /package/{commands-claudekit → merged-commands}/use-mcp.md +0 -0
- /package/{commands-claudekit → merged-commands}/watzup.md +0 -0
- /package/{commands-claudekit → merged-commands}/worktree.md +0 -0
- /package/{rules → templates/dart/rules}/dart/best-practices/SKILL.md +0 -0
- /package/{rules → templates/dart/rules}/dart/language/SKILL.md +0 -0
- /package/{rules → templates/dart/rules}/dart/tooling/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/auto-route-navigation/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/auto-route-navigation/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/auto-route-navigation/references/router-config.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc-state-management/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc-state-management/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc-state-management/references/auth-bloc-example.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc-state-management/references/equatable-usage.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc-state-management/references/property-based-state.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/bloc.rule.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/cicd/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/cicd/references/advanced-workflow.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/cicd/references/fastlane.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/cicd/references/github-actions.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/dependency-injection/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/dependency-injection/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/dependency-injection/references/modules.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/error-handling/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/error-handling/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/error-handling/references/error-mapping.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/feature-based-clean-architecture/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/feature-based-clean-architecture/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/feature-based-clean-architecture/references/folder-structure.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-navigation/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-navigation/references/app-pages.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-navigation/references/middleware-example.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-state-management/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-state-management/references/binding-example.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/getx-state-management/references/reactive-vs-simple.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/go-router-navigation/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/idiomatic-flutter/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/layer-based-clean-architecture/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/layer-based-clean-architecture/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/layer-based-clean-architecture/references/repository-mapping.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/localization/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/localization/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/localization/references/sheet-loader.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/navigator-v1-navigation/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/navigator-v1-navigation/references/on-generate-route.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/performance/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/retrofit-networking/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/retrofit-networking/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/retrofit-networking/references/token-refresh.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/riverpod-state-management/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/riverpod-state-management/references/architecture.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/riverpod-state-management/references/best-practices.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/riverpod-state-management/references/testing.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/riverpod.rule.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/security/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/security/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/security/references/network-security.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/SKILL.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/REFERENCE.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/bloc-testing.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/integration-testing.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/robot-pattern.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/unit-testing.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/testing/references/widget-testing.md +0 -0
- /package/{rules → templates/flutter/rules}/flutter/widgets/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/chi-router/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/chi-router/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/chi-router/references/routing-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/cobra-cli/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/cobra-cli/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/cobra-cli/references/command-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/core/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/core/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/core/references/concurrency-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/core/references/error-handling.md +0 -0
- /package/{rules → templates/golang/rules}/golang/echo-framework/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/echo-framework/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/echo-framework/references/middleware-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/echo-framework/references/routing-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/ent-orm/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/ent-orm/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/ent-orm/references/schema-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/fiber-framework/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/fiber-framework/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/fiber-framework/references/routing-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gin-framework/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gin-framework/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gin-framework/references/middleware-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gorm-orm/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gorm-orm/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gorm-orm/references/model-definitions.md +0 -0
- /package/{rules → templates/golang/rules}/golang/gorm-orm/references/query-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/grpc/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/grpc/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/grpc/references/service-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/testify/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/testify/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/testify/references/assert-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/validator/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/validator/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/validator/references/validation-tags.md +0 -0
- /package/{rules → templates/golang/rules}/golang/viper-config/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/viper-config/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/viper-config/references/config-loading.md +0 -0
- /package/{rules → templates/golang/rules}/golang/wire-di/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/wire-di/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/wire-di/references/provider-patterns.md +0 -0
- /package/{rules → templates/golang/rules}/golang/zap-logging/SKILL.md +0 -0
- /package/{rules → templates/golang/rules}/golang/zap-logging/references/REFERENCE.md +0 -0
- /package/{rules → templates/golang/rules}/golang/zap-logging/references/logger-config.md +0 -0
- /package/{rules → templates/java/rules}/java/build-gradle/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/build-gradle/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/build-gradle/references/kotlin-dsl.md +0 -0
- /package/{rules → templates/java/rules}/java/build-gradle/references/task-configuration.md +0 -0
- /package/{rules → templates/java/rules}/java/build-maven/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/build-maven/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/build-maven/references/dependency-management.md +0 -0
- /package/{rules → templates/java/rules}/java/build-maven/references/lifecycle-phases.md +0 -0
- /package/{rules → templates/java/rules}/java/graalvm-native/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/graalvm-native/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/java-collections-streams/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/java-collections-streams/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/java-collections-streams/references/collectors-patterns.md +0 -0
- /package/{rules → templates/java/rules}/java/java-collections-streams/references/stream-pipelines.md +0 -0
- /package/{rules → templates/java/rules}/java/java-concurrency/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/java-concurrency/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/java-concurrency/references/completable-future.md +0 -0
- /package/{rules → templates/java/rules}/java/java-concurrency/references/executor-patterns.md +0 -0
- /package/{rules → templates/java/rules}/java/java-concurrency/references/virtual-threads.md +0 -0
- /package/{rules → templates/java/rules}/java/java-core-language/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/java-core-language/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/java-core-language/references/jvm-memory-model.md +0 -0
- /package/{rules → templates/java/rules}/java/java-core-language/references/modern-java-features.md +0 -0
- /package/{rules → templates/java/rules}/java/java-project-structure/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/java-project-structure/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/java-project-structure/references/maven-project-layout.md +0 -0
- /package/{rules → templates/java/rules}/java/java-project-structure/references/module-system.md +0 -0
- /package/{rules → templates/java/rules}/java/micronaut-core/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/micronaut-core/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/micronaut-reactive/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/micronaut-reactive/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/quarkus-core/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/quarkus-core/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/quarkus-reactive/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/quarkus-reactive/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-batch/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-batch/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-architecture/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-architecture/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-architecture/references/auto-configuration.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-architecture/references/configuration-properties.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-web/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-boot-web/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-cloud/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-cloud/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-data-jpa/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-data-jpa/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-security/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-security/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/spring-security/references/jwt-auth-flow.md +0 -0
- /package/{rules → templates/java/rules}/java/testing-junit-mockito/SKILL.md +0 -0
- /package/{rules → templates/java/rules}/java/testing-junit-mockito/references/REFERENCE.md +0 -0
- /package/{rules → templates/java/rules}/java/testing-junit-mockito/references/junit5-patterns.md +0 -0
- /package/{rules → templates/java/rules}/java/testing-junit-mockito/references/mockito-patterns.md +0 -0
- /package/{rules → templates/java/rules}/java/testing-junit-mockito/references/spring-boot-testing.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/best-practices/SKILL.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/best-practices/references/REFERENCE.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/language/SKILL.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/language/references/REFERENCE.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/tooling/SKILL.md +0 -0
- /package/{rules → templates/javascript/rules}/javascript/tooling/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/api-standards/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/api-standards/references/pagination-wrapper.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/architecture/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/architecture/references/dynamic-module.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/caching/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/caching/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/caching/references/cache-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/configuration/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/configuration/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/configuration/references/config-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/controllers-services/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/controllers-services/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/controllers-services/references/controller-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/controllers-services/references/service-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/database/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/database/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/database/references/typeorm-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/deployment/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/deployment/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/deployment/references/deployment-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/documentation/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/documentation/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/documentation/references/swagger-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/error-handling/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/error-handling/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/error-handling/references/exception-filters.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/file-uploads/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/file-uploads/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/file-uploads/references/upload-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/observability/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/observability/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/observability/references/logging-metrics.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/performance/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/performance/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/performance/references/performance-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/real-time/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/real-time/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/real-time/references/websocket-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/scheduling/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/scheduling/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/scheduling/references/scheduling-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/search/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/search/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/search/references/search-patterns.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/security/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/security/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/security/references/authentication.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/testing/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/testing/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/testing/references/unit-testing.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/transport/SKILL.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/transport/references/REFERENCE.md +0 -0
- /package/{rules → templates/nestjs/rules}/nestjs/transport/references/microservices-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/app-router/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/app-router/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/app-router/references/routing-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/architecture/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/architecture/references/fsd-structure.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/authentication/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/authentication/references/auth-implementation.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/caching/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/caching/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/caching/references/cache-strategies.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/data-access-layer/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/data-access-layer/references/patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/data-fetching/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/data-fetching/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/data-fetching/references/fetch-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/internationalization/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/internationalization/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/internationalization/references/i18n-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/optimization/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/optimization/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/optimization/references/optimization-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/rendering/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/rendering/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/rendering/references/rendering-modes.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-actions/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-actions/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-actions/references/action-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-components/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-components/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/server-components/references/component-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/state-management/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/state-management/references/REFERENCE.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/state-management/references/state-patterns.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/styling/SKILL.md +0 -0
- /package/{rules → templates/nextjs/rules}/nextjs/styling/references/implementation.md +0 -0
- /package/{rules → templates/react/rules}/react/component-patterns/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/component-patterns/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/hooks/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/hooks/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/hooks.rule.md +0 -0
- /package/{rules → templates/react/rules}/react/performance/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/performance/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/security/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/security/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/state-management/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/state-management/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/testing/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/testing/references/REFERENCE.md +0 -0
- /package/{rules → templates/react/rules}/react/tooling/SKILL.md +0 -0
- /package/{rules → templates/react/rules}/react/typescript/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/actix-web/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/actix-web/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/actix-web/references/handler-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/async-graphql/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/async-graphql/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/async-graphql/references/schema-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/axum/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/axum/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/axum/references/handler-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/bevy/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/bevy/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/bevy/references/ecs-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/clap/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/clap/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/clap/references/derive-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/core/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/core/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/core/references/error-handling.md +0 -0
- /package/{rules → templates/rust/rules}/rust/diesel-orm/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/diesel-orm/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/diesel-orm/references/schema-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/rocket/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/rocket/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/rocket/references/handler-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sea-orm/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sea-orm/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sea-orm/references/entity-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/serde-serialization/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/serde-serialization/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/serde-serialization/references/serialization-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sqlx-database/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sqlx-database/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/sqlx-database/references/query-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tauri/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tauri/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tauri/references/command-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tokio-runtime/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tokio-runtime/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tokio-runtime/references/async-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tokio-runtime/references/synchronization.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tonic/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tonic/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tonic/references/service-patterns.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tracing/SKILL.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tracing/references/REFERENCE.md +0 -0
- /package/{rules → templates/rust/rules}/rust/tracing/references/instrumentation.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/best-practices/SKILL.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/best-practices/references/REFERENCE.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/language/SKILL.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/language/references/REFERENCE.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/patterns.rule.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/security/SKILL.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/security/references/REFERENCE.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/tooling/SKILL.md +0 -0
- /package/{rules → templates/typescript/rules}/typescript/tooling/references/REFERENCE.md +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Context Window Tracker - Self-healing context reset detection
|
|
6
|
+
*
|
|
7
|
+
* Fixes #177: Race condition from shared global state file
|
|
8
|
+
* Fixes #178: Consolidates temp files to /tmp/ck/ namespace
|
|
9
|
+
*
|
|
10
|
+
* Architecture:
|
|
11
|
+
* - NO global state file (was causing race conditions in concurrent sessions)
|
|
12
|
+
* - All state embedded in session-specific marker files
|
|
13
|
+
* - Each session is completely isolated (no shared state)
|
|
14
|
+
*
|
|
15
|
+
* Detection layers:
|
|
16
|
+
* - Layer 1: Hook markers (explicit reset signal from PreCompact/SessionStart)
|
|
17
|
+
* - Layer 2: Token drop detection (50% threshold fallback for hook failures)
|
|
18
|
+
*
|
|
19
|
+
* Removed:
|
|
20
|
+
* - Old Layer 1 (session ID change detection) - was the BUG source
|
|
21
|
+
* - Global STATE_FILE - caused race conditions in concurrent sessions
|
|
22
|
+
*
|
|
23
|
+
* Marker schema:
|
|
24
|
+
* {
|
|
25
|
+
* sessionId: string,
|
|
26
|
+
* trigger: string, // 'session_start_clear', 'manual', 'auto', 'new_session', 'token_drop'
|
|
27
|
+
* baselineRecorded: boolean,
|
|
28
|
+
* baseline: number, // Token count at baseline
|
|
29
|
+
* lastTokenTotal: number, // For token drop detection (replaces global state)
|
|
30
|
+
* timestamp: number
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* @module context-tracker
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const fs = require('fs');
|
|
37
|
+
const {
|
|
38
|
+
MARKERS_DIR,
|
|
39
|
+
CALIBRATION_PATH,
|
|
40
|
+
ensureDir,
|
|
41
|
+
getMarkerPath
|
|
42
|
+
} = require('./ck-paths.cjs');
|
|
43
|
+
|
|
44
|
+
// Token drop threshold for Layer 2 detection (50%)
|
|
45
|
+
// Rationale: /compact typically reduces tokens by 60-80%, so 50% catches
|
|
46
|
+
// context resets while avoiding false positives from normal token accumulation.
|
|
47
|
+
// Exclusive: drops below (<) 50% trigger reset
|
|
48
|
+
const TOKEN_DROP_THRESHOLD = 0.5;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get smart default compact threshold based on context window size
|
|
52
|
+
* Research-based defaults:
|
|
53
|
+
* - 200k window: ~77.5% (155k) - confirmed from GitHub issues
|
|
54
|
+
* - 1M window: ~33% (330k) - derived from user observations
|
|
55
|
+
*
|
|
56
|
+
* @param {number} contextWindowSize - Model's context window size
|
|
57
|
+
* @returns {number} Estimated compact threshold in tokens
|
|
58
|
+
*/
|
|
59
|
+
function getDefaultCompactThreshold(contextWindowSize) {
|
|
60
|
+
const KNOWN_THRESHOLDS = {
|
|
61
|
+
200000: 155000, // 77.5% - confirmed via /context showing 45k buffer
|
|
62
|
+
1000000: 330000, // 33% - 1M beta window
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
if (KNOWN_THRESHOLDS[contextWindowSize]) {
|
|
66
|
+
return KNOWN_THRESHOLDS[contextWindowSize];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Tiered defaults based on window size
|
|
70
|
+
if (contextWindowSize >= 1000000) {
|
|
71
|
+
return Math.floor(contextWindowSize * 0.33);
|
|
72
|
+
}
|
|
73
|
+
return Math.floor(contextWindowSize * 0.775);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Read calibration data from file (recorded by PreCompact hook)
|
|
78
|
+
* @returns {Object} Calibration data keyed by context window size
|
|
79
|
+
*/
|
|
80
|
+
function readCalibration() {
|
|
81
|
+
try {
|
|
82
|
+
if (fs.existsSync(CALIBRATION_PATH)) {
|
|
83
|
+
return JSON.parse(fs.readFileSync(CALIBRATION_PATH, 'utf8'));
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// Silent fail - use defaults
|
|
87
|
+
}
|
|
88
|
+
return {};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get compact threshold, preferring calibrated value over default
|
|
93
|
+
* @param {number} contextWindowSize - Model's context window size
|
|
94
|
+
* @returns {number} Compact threshold in tokens
|
|
95
|
+
*/
|
|
96
|
+
function getCompactThreshold(contextWindowSize) {
|
|
97
|
+
const calibration = readCalibration();
|
|
98
|
+
const key = String(contextWindowSize);
|
|
99
|
+
|
|
100
|
+
if (calibration[key] && calibration[key].threshold > 0) {
|
|
101
|
+
return calibration[key].threshold;
|
|
102
|
+
}
|
|
103
|
+
return getDefaultCompactThreshold(contextWindowSize);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Read marker file for a session
|
|
108
|
+
* Defensive: handles missing/empty/corrupt files gracefully
|
|
109
|
+
* @param {string} sessionId - Session ID
|
|
110
|
+
* @returns {Object|null} Marker data or null
|
|
111
|
+
*/
|
|
112
|
+
function readMarker(sessionId) {
|
|
113
|
+
try {
|
|
114
|
+
const markerPath = getMarkerPath(sessionId);
|
|
115
|
+
if (!fs.existsSync(markerPath)) return null;
|
|
116
|
+
const data = fs.readFileSync(markerPath, 'utf8');
|
|
117
|
+
if (!data.trim()) return null; // Catch empty/corrupt files
|
|
118
|
+
const marker = JSON.parse(data);
|
|
119
|
+
// Basic schema validation
|
|
120
|
+
if (!marker || typeof marker.sessionId !== 'string') {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return marker;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
// Silent fail - corrupt JSON or read error
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Write marker file for a session
|
|
132
|
+
* @param {string} sessionId - Session ID
|
|
133
|
+
* @param {Object} marker - Marker data
|
|
134
|
+
*/
|
|
135
|
+
function writeMarker(sessionId, marker) {
|
|
136
|
+
try {
|
|
137
|
+
ensureDir(MARKERS_DIR);
|
|
138
|
+
const markerPath = getMarkerPath(sessionId);
|
|
139
|
+
fs.writeFileSync(markerPath, JSON.stringify(marker));
|
|
140
|
+
} catch (err) {
|
|
141
|
+
// Silent fail
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Delete marker file for a session
|
|
147
|
+
* @param {string} sessionId - Session ID
|
|
148
|
+
*/
|
|
149
|
+
function deleteMarker(sessionId) {
|
|
150
|
+
try {
|
|
151
|
+
const markerPath = getMarkerPath(sessionId);
|
|
152
|
+
if (fs.existsSync(markerPath)) {
|
|
153
|
+
fs.unlinkSync(markerPath);
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
// Silent fail
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Layer 2: Detect significant token drop (50%+ reduction)
|
|
162
|
+
* Uses session-specific lastTokenTotal from marker (no global state)
|
|
163
|
+
* @param {number} currentTotal - Current cumulative token total
|
|
164
|
+
* @param {Object|null} marker - Session marker with lastTokenTotal
|
|
165
|
+
* @returns {boolean} True if token drop detected
|
|
166
|
+
*/
|
|
167
|
+
function detectTokenDrop(currentTotal, marker) {
|
|
168
|
+
if (!marker || !marker.lastTokenTotal || marker.lastTokenTotal <= 0 || currentTotal <= 0) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Token total dropped by more than 50%
|
|
173
|
+
const dropRatio = currentTotal / marker.lastTokenTotal;
|
|
174
|
+
return dropRatio < TOKEN_DROP_THRESHOLD;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Layer 1: Check for explicit reset marker from hooks
|
|
179
|
+
* @param {Object|null} marker - Session marker
|
|
180
|
+
* @returns {{ shouldReset: boolean, trigger: string|null }}
|
|
181
|
+
*/
|
|
182
|
+
function checkResetMarker(marker) {
|
|
183
|
+
if (!marker) {
|
|
184
|
+
return { shouldReset: false, trigger: null };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check if marker indicates a reset (clear/compact)
|
|
188
|
+
const resetTriggers = ['clear', 'session_start_clear'];
|
|
189
|
+
if (resetTriggers.includes(marker.trigger)) {
|
|
190
|
+
return { shouldReset: true, trigger: marker.trigger };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return { shouldReset: false, trigger: marker.trigger };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Main context tracking function with 2-layer self-healing detection
|
|
198
|
+
*
|
|
199
|
+
* Layer 1: Hook markers (explicit reset from PreCompact/SessionStart)
|
|
200
|
+
* Layer 2: Token drop detection (50% threshold fallback)
|
|
201
|
+
*
|
|
202
|
+
* NO global state - all state is session-specific in marker files
|
|
203
|
+
*
|
|
204
|
+
* @param {Object} params - Tracking parameters
|
|
205
|
+
* @param {string} params.sessionId - Current session ID
|
|
206
|
+
* @param {number} params.contextInput - Input tokens
|
|
207
|
+
* @param {number} params.contextOutput - Output tokens
|
|
208
|
+
* @param {number} params.contextWindowSize - Model's context window size
|
|
209
|
+
* @returns {Object} { percentage, baseline, showCompactIndicator, resetLayer }
|
|
210
|
+
*/
|
|
211
|
+
function trackContext({ sessionId, contextInput, contextOutput, contextWindowSize }) {
|
|
212
|
+
const currentTotal = contextInput + contextOutput;
|
|
213
|
+
const compactThreshold = getCompactThreshold(contextWindowSize);
|
|
214
|
+
const effectiveSessionId = sessionId || 'default';
|
|
215
|
+
|
|
216
|
+
// Read session-specific marker (no global state!)
|
|
217
|
+
let marker = readMarker(effectiveSessionId);
|
|
218
|
+
|
|
219
|
+
// Track which layer triggered reset (for debugging)
|
|
220
|
+
let resetLayer = null;
|
|
221
|
+
let baseline = 0;
|
|
222
|
+
let showCompactIndicator = false;
|
|
223
|
+
|
|
224
|
+
// --- Layer 1: Hook marker system ---
|
|
225
|
+
// Markers from PreCompact/SessionStart hooks are explicit signals
|
|
226
|
+
const { shouldReset, trigger } = checkResetMarker(marker);
|
|
227
|
+
if (shouldReset) {
|
|
228
|
+
resetLayer = `marker_${trigger}`;
|
|
229
|
+
baseline = currentTotal;
|
|
230
|
+
// Clear the reset trigger after processing
|
|
231
|
+
marker = null; // Force fresh marker creation below
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// --- Layer 2: Token drop detection (fallback for hook failures) ---
|
|
235
|
+
if (!resetLayer && detectTokenDrop(currentTotal, marker)) {
|
|
236
|
+
resetLayer = 'token_drop';
|
|
237
|
+
baseline = currentTotal;
|
|
238
|
+
marker = null; // Force fresh marker creation below
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// --- No reset triggered - use existing marker/baseline ---
|
|
242
|
+
if (!resetLayer && marker) {
|
|
243
|
+
if (!marker.baselineRecorded) {
|
|
244
|
+
// Marker exists but baseline not recorded yet (from PreCompact)
|
|
245
|
+
marker.baselineRecorded = true;
|
|
246
|
+
marker.baseline = currentTotal;
|
|
247
|
+
marker.lastTokenTotal = currentTotal;
|
|
248
|
+
writeMarker(effectiveSessionId, marker);
|
|
249
|
+
baseline = currentTotal;
|
|
250
|
+
// PreCompact triggers: "manual" (from /compact) or "auto" (from auto-compact)
|
|
251
|
+
showCompactIndicator = ['compact', 'manual', 'auto'].includes(marker.trigger);
|
|
252
|
+
} else {
|
|
253
|
+
// Use stored baseline
|
|
254
|
+
baseline = marker.baseline || 0;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// --- Create fresh marker if needed ---
|
|
259
|
+
if (!marker || resetLayer) {
|
|
260
|
+
const newMarker = {
|
|
261
|
+
sessionId: effectiveSessionId,
|
|
262
|
+
trigger: resetLayer || 'new_session',
|
|
263
|
+
baselineRecorded: true,
|
|
264
|
+
baseline: currentTotal,
|
|
265
|
+
lastTokenTotal: currentTotal,
|
|
266
|
+
timestamp: Date.now()
|
|
267
|
+
};
|
|
268
|
+
writeMarker(effectiveSessionId, newMarker);
|
|
269
|
+
if (!resetLayer) {
|
|
270
|
+
baseline = currentTotal;
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
// Update lastTokenTotal for next token drop detection
|
|
274
|
+
marker.lastTokenTotal = currentTotal;
|
|
275
|
+
writeMarker(effectiveSessionId, marker);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Calculate effective tokens (since baseline)
|
|
279
|
+
let effectiveTotal = baseline > 0 ? currentTotal - baseline : currentTotal;
|
|
280
|
+
if (effectiveTotal < 0) effectiveTotal = 0;
|
|
281
|
+
|
|
282
|
+
// Calculate percentage against compact threshold (not model limit)
|
|
283
|
+
const percentage = Math.min(100, Math.floor(effectiveTotal * 100 / compactThreshold));
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
percentage,
|
|
287
|
+
baseline,
|
|
288
|
+
effectiveTotal,
|
|
289
|
+
compactThreshold,
|
|
290
|
+
showCompactIndicator,
|
|
291
|
+
resetLayer
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Write reset marker for session (called by SessionStart hook on /clear)
|
|
297
|
+
* @param {string} sessionId - Session ID
|
|
298
|
+
* @param {string} trigger - Reset trigger ('clear', 'compact', etc.)
|
|
299
|
+
*/
|
|
300
|
+
function writeResetMarker(sessionId, trigger = 'clear') {
|
|
301
|
+
const effectiveSessionId = sessionId || 'default';
|
|
302
|
+
ensureDir(MARKERS_DIR);
|
|
303
|
+
writeMarker(effectiveSessionId, {
|
|
304
|
+
sessionId: effectiveSessionId,
|
|
305
|
+
trigger: `session_start_${trigger}`,
|
|
306
|
+
baselineRecorded: false,
|
|
307
|
+
baseline: 0,
|
|
308
|
+
lastTokenTotal: 0,
|
|
309
|
+
timestamp: Date.now()
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Clear all markers (for testing/cleanup)
|
|
315
|
+
* Uses new /tmp/ck/ namespace
|
|
316
|
+
*/
|
|
317
|
+
function clearAllState() {
|
|
318
|
+
const { cleanAll } = require('./ck-paths.cjs');
|
|
319
|
+
cleanAll();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
module.exports = {
|
|
323
|
+
trackContext,
|
|
324
|
+
writeResetMarker,
|
|
325
|
+
clearAllState,
|
|
326
|
+
getCompactThreshold,
|
|
327
|
+
// Export for testing
|
|
328
|
+
detectTokenDrop,
|
|
329
|
+
checkResetMarker,
|
|
330
|
+
readMarker,
|
|
331
|
+
writeMarker,
|
|
332
|
+
deleteMarker,
|
|
333
|
+
TOKEN_DROP_THRESHOLD,
|
|
334
|
+
MARKERS_DIR
|
|
335
|
+
};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* privacy-checker.cjs - Privacy pattern matching logic for sensitive file detection
|
|
4
|
+
*
|
|
5
|
+
* Extracted from privacy-block.cjs for reuse in both Claude hooks and OpenCode plugins.
|
|
6
|
+
* Pure logic module - no stdin/stdout, no exit codes.
|
|
7
|
+
*
|
|
8
|
+
* @module privacy-checker
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
// CONSTANTS
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
const APPROVED_PREFIX = 'APPROVED:';
|
|
19
|
+
|
|
20
|
+
// Safe file patterns - exempt from privacy checks (documentation/template files)
|
|
21
|
+
const SAFE_PATTERNS = [
|
|
22
|
+
/\.example$/i, // .env.example, config.example
|
|
23
|
+
/\.sample$/i, // .env.sample
|
|
24
|
+
/\.template$/i, // .env.template
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Privacy-sensitive patterns
|
|
28
|
+
const PRIVACY_PATTERNS = [
|
|
29
|
+
/^\.env$/, // .env
|
|
30
|
+
/^\.env\./, // .env.local, .env.production, etc.
|
|
31
|
+
/\.env$/, // path/to/.env
|
|
32
|
+
/\/\.env\./, // path/to/.env.local
|
|
33
|
+
/credentials/i, // credentials.json, etc.
|
|
34
|
+
/secrets?\.ya?ml$/i, // secrets.yaml, secret.yml
|
|
35
|
+
/\.pem$/, // Private keys
|
|
36
|
+
/\.key$/, // Private keys
|
|
37
|
+
/id_rsa/, // SSH keys
|
|
38
|
+
/id_ed25519/, // SSH keys
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
// HELPER FUNCTIONS
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if path is a safe file (example/sample/template)
|
|
47
|
+
* @param {string} testPath - Path to check
|
|
48
|
+
* @returns {boolean} true if file matches safe patterns
|
|
49
|
+
*/
|
|
50
|
+
function isSafeFile(testPath) {
|
|
51
|
+
if (!testPath) return false;
|
|
52
|
+
const basename = path.basename(testPath);
|
|
53
|
+
return SAFE_PATTERNS.some(p => p.test(basename));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if path has APPROVED: prefix
|
|
58
|
+
* @param {string} testPath - Path to check
|
|
59
|
+
* @returns {boolean} true if path starts with APPROVED:
|
|
60
|
+
*/
|
|
61
|
+
function hasApprovalPrefix(testPath) {
|
|
62
|
+
return testPath && testPath.startsWith(APPROVED_PREFIX);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Strip APPROVED: prefix from path
|
|
67
|
+
* @param {string} testPath - Path to process
|
|
68
|
+
* @returns {string} Path without APPROVED: prefix
|
|
69
|
+
*/
|
|
70
|
+
function stripApprovalPrefix(testPath) {
|
|
71
|
+
if (hasApprovalPrefix(testPath)) {
|
|
72
|
+
return testPath.slice(APPROVED_PREFIX.length);
|
|
73
|
+
}
|
|
74
|
+
return testPath;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if stripped path is suspicious (path traversal or absolute)
|
|
79
|
+
* @param {string} strippedPath - Path after stripping APPROVED: prefix
|
|
80
|
+
* @returns {boolean} true if path looks suspicious
|
|
81
|
+
*/
|
|
82
|
+
function isSuspiciousPath(strippedPath) {
|
|
83
|
+
return strippedPath.includes('..') || path.isAbsolute(strippedPath);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if path matches privacy patterns
|
|
88
|
+
* @param {string} testPath - Path to check
|
|
89
|
+
* @returns {boolean} true if path matches privacy-sensitive patterns
|
|
90
|
+
*/
|
|
91
|
+
function isPrivacySensitive(testPath) {
|
|
92
|
+
if (!testPath) return false;
|
|
93
|
+
|
|
94
|
+
// Strip prefix for pattern matching
|
|
95
|
+
const cleanPath = stripApprovalPrefix(testPath);
|
|
96
|
+
let normalized = cleanPath.replace(/\\/g, '/');
|
|
97
|
+
|
|
98
|
+
// Decode URI components to catch obfuscated paths (%2e = '.')
|
|
99
|
+
try {
|
|
100
|
+
normalized = decodeURIComponent(normalized);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
// Invalid encoding, use as-is
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check safe patterns first - exempt example/sample/template files
|
|
106
|
+
if (isSafeFile(normalized)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const basename = path.basename(normalized);
|
|
111
|
+
|
|
112
|
+
for (const pattern of PRIVACY_PATTERNS) {
|
|
113
|
+
if (pattern.test(basename) || pattern.test(normalized)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract paths from tool input
|
|
122
|
+
* @param {Object} toolInput - Tool input object with file_path, path, pattern, or command
|
|
123
|
+
* @returns {Array<{value: string, field: string}>} Array of extracted paths with field names
|
|
124
|
+
*/
|
|
125
|
+
function extractPaths(toolInput) {
|
|
126
|
+
const paths = [];
|
|
127
|
+
if (!toolInput) return paths;
|
|
128
|
+
|
|
129
|
+
if (toolInput.file_path) paths.push({ value: toolInput.file_path, field: 'file_path' });
|
|
130
|
+
if (toolInput.path) paths.push({ value: toolInput.path, field: 'path' });
|
|
131
|
+
if (toolInput.pattern) paths.push({ value: toolInput.pattern, field: 'pattern' });
|
|
132
|
+
|
|
133
|
+
// Check bash commands for file paths
|
|
134
|
+
if (toolInput.command) {
|
|
135
|
+
// Look for APPROVED:.env or .env patterns
|
|
136
|
+
const approvedMatch = toolInput.command.match(/APPROVED:[^\s]+/g) || [];
|
|
137
|
+
approvedMatch.forEach(p => paths.push({ value: p, field: 'command' }));
|
|
138
|
+
|
|
139
|
+
// Only look for .env if no APPROVED: version found
|
|
140
|
+
if (approvedMatch.length === 0) {
|
|
141
|
+
const envMatch = toolInput.command.match(/\.env[^\s]*/g) || [];
|
|
142
|
+
envMatch.forEach(p => paths.push({ value: p, field: 'command' }));
|
|
143
|
+
|
|
144
|
+
// Also check bash variable assignments (FILE=.env, ENV_FILE=.env.local)
|
|
145
|
+
const varAssignments = toolInput.command.match(/\w+=[^\s]*\.env[^\s]*/g) || [];
|
|
146
|
+
varAssignments.forEach(a => {
|
|
147
|
+
const value = a.split('=')[1];
|
|
148
|
+
if (value) paths.push({ value, field: 'command' });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Check command substitution containing sensitive patterns - extract .env from inside
|
|
152
|
+
const cmdSubst = toolInput.command.match(/\$\([^)]*?(\.env[^\s)]*)[^)]*\)/g) || [];
|
|
153
|
+
for (const subst of cmdSubst) {
|
|
154
|
+
const inner = subst.match(/\.env[^\s)]*/);
|
|
155
|
+
if (inner) paths.push({ value: inner[0], field: 'command' });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return paths.filter(p => p.value);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Load .ck.json config to check if privacy block is disabled
|
|
165
|
+
* @param {string} [configDir] - Directory containing .ck.json (defaults to .claude in cwd)
|
|
166
|
+
* @returns {boolean} true if privacy block should be skipped
|
|
167
|
+
*/
|
|
168
|
+
function isPrivacyBlockDisabled(configDir) {
|
|
169
|
+
try {
|
|
170
|
+
const configPath = configDir
|
|
171
|
+
? path.join(configDir, '.ck.json')
|
|
172
|
+
: path.join(process.cwd(), '.claude', '.ck.json');
|
|
173
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
174
|
+
return config.privacyBlock === false;
|
|
175
|
+
} catch {
|
|
176
|
+
return false; // Default to enabled on error (file not found or invalid JSON)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build prompt data for AskUserQuestion tool
|
|
182
|
+
* @param {string} filePath - Blocked file path
|
|
183
|
+
* @returns {Object} Prompt data object
|
|
184
|
+
*/
|
|
185
|
+
function buildPromptData(filePath) {
|
|
186
|
+
const basename = path.basename(filePath);
|
|
187
|
+
return {
|
|
188
|
+
type: 'PRIVACY_PROMPT',
|
|
189
|
+
file: filePath,
|
|
190
|
+
basename: basename,
|
|
191
|
+
question: {
|
|
192
|
+
header: 'File Access',
|
|
193
|
+
text: `I need to read "${basename}" which may contain sensitive data (API keys, passwords, tokens). Do you approve?`,
|
|
194
|
+
options: [
|
|
195
|
+
{ label: 'Yes, approve access', description: `Allow reading ${basename} this time` },
|
|
196
|
+
{ label: 'No, skip this file', description: 'Continue without accessing this file' }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
203
|
+
// MAIN ENTRY POINT
|
|
204
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if a tool call accesses privacy-sensitive files
|
|
208
|
+
*
|
|
209
|
+
* @param {Object} params
|
|
210
|
+
* @param {string} params.toolName - Name of tool (Read, Write, Bash, etc.)
|
|
211
|
+
* @param {Object} params.toolInput - Tool input with file_path, path, command, etc.
|
|
212
|
+
* @param {Object} [params.options]
|
|
213
|
+
* @param {boolean} [params.options.disabled] - Skip checks if true
|
|
214
|
+
* @param {string} [params.options.configDir] - Directory for .ck.json config
|
|
215
|
+
* @param {boolean} [params.options.allowBash] - Allow Bash tool without blocking (default: true)
|
|
216
|
+
* @returns {{
|
|
217
|
+
* blocked: boolean,
|
|
218
|
+
* filePath?: string,
|
|
219
|
+
* reason?: string,
|
|
220
|
+
* approved?: boolean,
|
|
221
|
+
* isBash?: boolean,
|
|
222
|
+
* suspicious?: boolean,
|
|
223
|
+
* promptData?: Object
|
|
224
|
+
* }}
|
|
225
|
+
*/
|
|
226
|
+
function checkPrivacy({ toolName, toolInput, options = {} }) {
|
|
227
|
+
const { disabled, configDir, allowBash = true } = options;
|
|
228
|
+
|
|
229
|
+
// Check if disabled via options or config
|
|
230
|
+
if (disabled || isPrivacyBlockDisabled(configDir)) {
|
|
231
|
+
return { blocked: false };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const isBashTool = toolName === 'Bash';
|
|
235
|
+
const paths = extractPaths(toolInput);
|
|
236
|
+
|
|
237
|
+
// Check each path
|
|
238
|
+
for (const { value: testPath } of paths) {
|
|
239
|
+
if (!isPrivacySensitive(testPath)) continue;
|
|
240
|
+
|
|
241
|
+
// Check for approval prefix
|
|
242
|
+
if (hasApprovalPrefix(testPath)) {
|
|
243
|
+
const strippedPath = stripApprovalPrefix(testPath);
|
|
244
|
+
return {
|
|
245
|
+
blocked: false,
|
|
246
|
+
approved: true,
|
|
247
|
+
filePath: strippedPath,
|
|
248
|
+
suspicious: isSuspiciousPath(strippedPath)
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// For Bash: warn but don't block (allows "Yes → bash cat" flow)
|
|
253
|
+
if (isBashTool && allowBash) {
|
|
254
|
+
return {
|
|
255
|
+
blocked: false,
|
|
256
|
+
isBash: true,
|
|
257
|
+
filePath: testPath,
|
|
258
|
+
reason: `Bash command accesses sensitive file: ${testPath}`
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Block - sensitive file without approval
|
|
263
|
+
return {
|
|
264
|
+
blocked: true,
|
|
265
|
+
filePath: testPath,
|
|
266
|
+
reason: `Sensitive file access requires user approval`,
|
|
267
|
+
promptData: buildPromptData(testPath)
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// No sensitive paths found
|
|
272
|
+
return { blocked: false };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
276
|
+
// EXPORTS
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
// Main entry point
|
|
281
|
+
checkPrivacy,
|
|
282
|
+
|
|
283
|
+
// Helper functions (for testing and direct use)
|
|
284
|
+
isSafeFile,
|
|
285
|
+
isPrivacySensitive,
|
|
286
|
+
hasApprovalPrefix,
|
|
287
|
+
stripApprovalPrefix,
|
|
288
|
+
isSuspiciousPath,
|
|
289
|
+
extractPaths,
|
|
290
|
+
isPrivacyBlockDisabled,
|
|
291
|
+
buildPromptData,
|
|
292
|
+
|
|
293
|
+
// Constants
|
|
294
|
+
APPROVED_PREFIX,
|
|
295
|
+
SAFE_PATTERNS,
|
|
296
|
+
PRIVACY_PATTERNS
|
|
297
|
+
};
|