@winspan/claude-forge 0.1.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/LICENSE +21 -0
- package/README.md +505 -0
- package/dist/autopilot/index.d.ts +4 -0
- package/dist/autopilot/index.d.ts.map +1 -0
- package/dist/autopilot/index.js +4 -0
- package/dist/autopilot/index.js.map +1 -0
- package/dist/autopilot/intent-engine.d.ts +60 -0
- package/dist/autopilot/intent-engine.d.ts.map +1 -0
- package/dist/autopilot/intent-engine.js +308 -0
- package/dist/autopilot/intent-engine.js.map +1 -0
- package/dist/autopilot/knowledge-engine.d.ts +67 -0
- package/dist/autopilot/knowledge-engine.d.ts.map +1 -0
- package/dist/autopilot/knowledge-engine.js +262 -0
- package/dist/autopilot/knowledge-engine.js.map +1 -0
- package/dist/autopilot/quality-gate.d.ts +69 -0
- package/dist/autopilot/quality-gate.d.ts.map +1 -0
- package/dist/autopilot/quality-gate.js +244 -0
- package/dist/autopilot/quality-gate.js.map +1 -0
- package/dist/autopilot/team-orchestrator.d.ts +16 -0
- package/dist/autopilot/team-orchestrator.d.ts.map +1 -0
- package/dist/autopilot/team-orchestrator.js +56 -0
- package/dist/autopilot/team-orchestrator.js.map +1 -0
- package/dist/backup/index.d.ts +16 -0
- package/dist/backup/index.d.ts.map +1 -0
- package/dist/backup/index.js +169 -0
- package/dist/backup/index.js.map +1 -0
- package/dist/claudemd/detector.d.ts +54 -0
- package/dist/claudemd/detector.d.ts.map +1 -0
- package/dist/claudemd/detector.js +510 -0
- package/dist/claudemd/detector.js.map +1 -0
- package/dist/claudemd/index.d.ts +44 -0
- package/dist/claudemd/index.d.ts.map +1 -0
- package/dist/claudemd/index.js +193 -0
- package/dist/claudemd/index.js.map +1 -0
- package/dist/claudemd/modules-config.d.ts +37 -0
- package/dist/claudemd/modules-config.d.ts.map +1 -0
- package/dist/claudemd/modules-config.js +80 -0
- package/dist/claudemd/modules-config.js.map +1 -0
- package/dist/claudemd/prompt-injector.d.ts +29 -0
- package/dist/claudemd/prompt-injector.d.ts.map +1 -0
- package/dist/claudemd/prompt-injector.js +144 -0
- package/dist/claudemd/prompt-injector.js.map +1 -0
- package/dist/claudemd/prompts.d.ts +16 -0
- package/dist/claudemd/prompts.d.ts.map +1 -0
- package/dist/claudemd/prompts.js +439 -0
- package/dist/claudemd/prompts.js.map +1 -0
- package/dist/claudemd/writer.d.ts +27 -0
- package/dist/claudemd/writer.d.ts.map +1 -0
- package/dist/claudemd/writer.js +91 -0
- package/dist/claudemd/writer.js.map +1 -0
- package/dist/cli/commands/backup.d.ts +3 -0
- package/dist/cli/commands/backup.d.ts.map +1 -0
- package/dist/cli/commands/backup.js +63 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/claudemd.d.ts +3 -0
- package/dist/cli/commands/claudemd.d.ts.map +1 -0
- package/dist/cli/commands/claudemd.js +322 -0
- package/dist/cli/commands/claudemd.js.map +1 -0
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +67 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/console.d.ts +3 -0
- package/dist/cli/commands/console.d.ts.map +1 -0
- package/dist/cli/commands/console.js +11 -0
- package/dist/cli/commands/console.js.map +1 -0
- package/dist/cli/commands/convention.d.ts +3 -0
- package/dist/cli/commands/convention.d.ts.map +1 -0
- package/dist/cli/commands/convention.js +269 -0
- package/dist/cli/commands/convention.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +3 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +191 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/distill.d.ts +3 -0
- package/dist/cli/commands/distill.d.ts.map +1 -0
- package/dist/cli/commands/distill.js +61 -0
- package/dist/cli/commands/distill.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +306 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +3 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +311 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/pattern.d.ts +3 -0
- package/dist/cli/commands/pattern.d.ts.map +1 -0
- package/dist/cli/commands/pattern.js +118 -0
- package/dist/cli/commands/pattern.js.map +1 -0
- package/dist/cli/commands/pipeline.d.ts +3 -0
- package/dist/cli/commands/pipeline.d.ts.map +1 -0
- package/dist/cli/commands/pipeline.js +75 -0
- package/dist/cli/commands/pipeline.js.map +1 -0
- package/dist/cli/commands/profile.d.ts +3 -0
- package/dist/cli/commands/profile.d.ts.map +1 -0
- package/dist/cli/commands/profile.js +213 -0
- package/dist/cli/commands/profile.js.map +1 -0
- package/dist/cli/commands/query.d.ts +3 -0
- package/dist/cli/commands/query.d.ts.map +1 -0
- package/dist/cli/commands/query.js +115 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/skill.d.ts +3 -0
- package/dist/cli/commands/skill.d.ts.map +1 -0
- package/dist/cli/commands/skill.js +466 -0
- package/dist/cli/commands/skill.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +49 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/interceptor.d.ts +5 -0
- package/dist/cli/interceptor.d.ts.map +1 -0
- package/dist/cli/interceptor.js +55 -0
- package/dist/cli/interceptor.js.map +1 -0
- package/dist/cli/tui.d.ts +2 -0
- package/dist/cli/tui.d.ts.map +1 -0
- package/dist/cli/tui.js +360 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/utils/errors.d.ts +17 -0
- package/dist/cli/utils/errors.d.ts.map +1 -0
- package/dist/cli/utils/errors.js +42 -0
- package/dist/cli/utils/errors.js.map +1 -0
- package/dist/cli/utils/output.d.ts +23 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +69 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/config/defaults.d.ts +3 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +50 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +26 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +161 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +59 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +86 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/convention/convention-distiller.d.ts +28 -0
- package/dist/convention/convention-distiller.d.ts.map +1 -0
- package/dist/convention/convention-distiller.js +172 -0
- package/dist/convention/convention-distiller.js.map +1 -0
- package/dist/convention/convention-evolver.d.ts +31 -0
- package/dist/convention/convention-evolver.d.ts.map +1 -0
- package/dist/convention/convention-evolver.js +175 -0
- package/dist/convention/convention-evolver.js.map +1 -0
- package/dist/convention/convention-loader.d.ts +22 -0
- package/dist/convention/convention-loader.d.ts.map +1 -0
- package/dist/convention/convention-loader.js +139 -0
- package/dist/convention/convention-loader.js.map +1 -0
- package/dist/convention/convention-manager.d.ts +46 -0
- package/dist/convention/convention-manager.d.ts.map +1 -0
- package/dist/convention/convention-manager.js +193 -0
- package/dist/convention/convention-manager.js.map +1 -0
- package/dist/convention/index.d.ts +6 -0
- package/dist/convention/index.d.ts.map +1 -0
- package/dist/convention/index.js +5 -0
- package/dist/convention/index.js.map +1 -0
- package/dist/convention/types.d.ts +90 -0
- package/dist/convention/types.d.ts.map +1 -0
- package/dist/convention/types.js +13 -0
- package/dist/convention/types.js.map +1 -0
- package/dist/daemon/engine-registry/init-autopilot.d.ts +12 -0
- package/dist/daemon/engine-registry/init-autopilot.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-autopilot.js +20 -0
- package/dist/daemon/engine-registry/init-autopilot.js.map +1 -0
- package/dist/daemon/engine-registry/init-distill.d.ts +6 -0
- package/dist/daemon/engine-registry/init-distill.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-distill.js +25 -0
- package/dist/daemon/engine-registry/init-distill.js.map +1 -0
- package/dist/daemon/engine-registry/init-orchestration.d.ts +5 -0
- package/dist/daemon/engine-registry/init-orchestration.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-orchestration.js +11 -0
- package/dist/daemon/engine-registry/init-orchestration.js.map +1 -0
- package/dist/daemon/engine-registry/init-pattern-engine.d.ts +9 -0
- package/dist/daemon/engine-registry/init-pattern-engine.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-pattern-engine.js +22 -0
- package/dist/daemon/engine-registry/init-pattern-engine.js.map +1 -0
- package/dist/daemon/engine-registry/init-pipeline.d.ts +5 -0
- package/dist/daemon/engine-registry/init-pipeline.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-pipeline.js +12 -0
- package/dist/daemon/engine-registry/init-pipeline.js.map +1 -0
- package/dist/daemon/engine-registry/init-profile.d.ts +3 -0
- package/dist/daemon/engine-registry/init-profile.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-profile.js +28 -0
- package/dist/daemon/engine-registry/init-profile.js.map +1 -0
- package/dist/daemon/engine-registry/init-resume.d.ts +6 -0
- package/dist/daemon/engine-registry/init-resume.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-resume.js +16 -0
- package/dist/daemon/engine-registry/init-resume.js.map +1 -0
- package/dist/daemon/engine-registry/init-skill-registry.d.ts +10 -0
- package/dist/daemon/engine-registry/init-skill-registry.d.ts.map +1 -0
- package/dist/daemon/engine-registry/init-skill-registry.js +46 -0
- package/dist/daemon/engine-registry/init-skill-registry.js.map +1 -0
- package/dist/daemon/engine-registry.d.ts +13 -0
- package/dist/daemon/engine-registry.d.ts.map +1 -0
- package/dist/daemon/engine-registry.js +45 -0
- package/dist/daemon/engine-registry.js.map +1 -0
- package/dist/daemon/event-parser.d.ts +5 -0
- package/dist/daemon/event-parser.d.ts.map +1 -0
- package/dist/daemon/event-parser.js +29 -0
- package/dist/daemon/event-parser.js.map +1 -0
- package/dist/daemon/handler-context.d.ts +37 -0
- package/dist/daemon/handler-context.d.ts.map +1 -0
- package/dist/daemon/handler-context.js +2 -0
- package/dist/daemon/handler-context.js.map +1 -0
- package/dist/daemon/handlers/base-handler.d.ts +14 -0
- package/dist/daemon/handlers/base-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/base-handler.js +18 -0
- package/dist/daemon/handlers/base-handler.js.map +1 -0
- package/dist/daemon/handlers/conversational-config-handler.d.ts +24 -0
- package/dist/daemon/handlers/conversational-config-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/conversational-config-handler.js +175 -0
- package/dist/daemon/handlers/conversational-config-handler.js.map +1 -0
- package/dist/daemon/handlers/post-tool-use-handler.d.ts +9 -0
- package/dist/daemon/handlers/post-tool-use-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/post-tool-use-handler.js +82 -0
- package/dist/daemon/handlers/post-tool-use-handler.js.map +1 -0
- package/dist/daemon/handlers/pre-tool-use-handler.d.ts +11 -0
- package/dist/daemon/handlers/pre-tool-use-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/pre-tool-use-handler.js +58 -0
- package/dist/daemon/handlers/pre-tool-use-handler.js.map +1 -0
- package/dist/daemon/handlers/stop-handler.d.ts +11 -0
- package/dist/daemon/handlers/stop-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/stop-handler.js +112 -0
- package/dist/daemon/handlers/stop-handler.js.map +1 -0
- package/dist/daemon/handlers/user-prompt-handler.d.ts +72 -0
- package/dist/daemon/handlers/user-prompt-handler.d.ts.map +1 -0
- package/dist/daemon/handlers/user-prompt-handler.js +374 -0
- package/dist/daemon/handlers/user-prompt-handler.js.map +1 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +284 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +9 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +56 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/server.d.ts +22 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +139 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/distill/index.d.ts +16 -0
- package/dist/distill/index.d.ts.map +1 -0
- package/dist/distill/index.js +104 -0
- package/dist/distill/index.js.map +1 -0
- package/dist/distill/prompts.d.ts +6 -0
- package/dist/distill/prompts.d.ts.map +1 -0
- package/dist/distill/prompts.js +77 -0
- package/dist/distill/prompts.js.map +1 -0
- package/dist/distill/trigger.d.ts +40 -0
- package/dist/distill/trigger.d.ts.map +1 -0
- package/dist/distill/trigger.js +127 -0
- package/dist/distill/trigger.js.map +1 -0
- package/dist/distill/writer.d.ts +15 -0
- package/dist/distill/writer.d.ts.map +1 -0
- package/dist/distill/writer.js +73 -0
- package/dist/distill/writer.js.map +1 -0
- package/dist/doc-sync/index.d.ts +21 -0
- package/dist/doc-sync/index.d.ts.map +1 -0
- package/dist/doc-sync/index.js +190 -0
- package/dist/doc-sync/index.js.map +1 -0
- package/dist/hooks/check-context-limit.sh +97 -0
- package/dist/hooks/hooks/check-context-limit.sh +97 -0
- package/dist/hooks/hooks/notification.sh +33 -0
- package/dist/hooks/hooks/post-tool-use.sh +49 -0
- package/dist/hooks/hooks/pre-tool-use.sh +55 -0
- package/dist/hooks/hooks/stop.sh +29 -0
- package/dist/hooks/hooks/user-prompt-submit.sh +72 -0
- package/dist/hooks/notification.sh +33 -0
- package/dist/hooks/post-tool-use.sh +49 -0
- package/dist/hooks/pre-tool-use.sh +55 -0
- package/dist/hooks/stop.sh +29 -0
- package/dist/hooks/user-prompt-submit.sh +72 -0
- package/dist/orchestration/index.d.ts +32 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +72 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/notifier.d.ts +11 -0
- package/dist/orchestration/notifier.d.ts.map +1 -0
- package/dist/orchestration/notifier.js +22 -0
- package/dist/orchestration/notifier.js.map +1 -0
- package/dist/orchestration/policy-engine.d.ts +21 -0
- package/dist/orchestration/policy-engine.d.ts.map +1 -0
- package/dist/orchestration/policy-engine.js +77 -0
- package/dist/orchestration/policy-engine.js.map +1 -0
- package/dist/orchestration/tracker.d.ts +45 -0
- package/dist/orchestration/tracker.d.ts.map +1 -0
- package/dist/orchestration/tracker.js +95 -0
- package/dist/orchestration/tracker.js.map +1 -0
- package/dist/pattern-engine/execution-tracker.d.ts +45 -0
- package/dist/pattern-engine/execution-tracker.d.ts.map +1 -0
- package/dist/pattern-engine/execution-tracker.js +132 -0
- package/dist/pattern-engine/execution-tracker.js.map +1 -0
- package/dist/pattern-engine/index.d.ts +52 -0
- package/dist/pattern-engine/index.d.ts.map +1 -0
- package/dist/pattern-engine/index.js +104 -0
- package/dist/pattern-engine/index.js.map +1 -0
- package/dist/pattern-engine/pattern-evolver.d.ts +39 -0
- package/dist/pattern-engine/pattern-evolver.d.ts.map +1 -0
- package/dist/pattern-engine/pattern-evolver.js +170 -0
- package/dist/pattern-engine/pattern-evolver.js.map +1 -0
- package/dist/pattern-engine/pattern-executor.d.ts +43 -0
- package/dist/pattern-engine/pattern-executor.d.ts.map +1 -0
- package/dist/pattern-engine/pattern-executor.js +185 -0
- package/dist/pattern-engine/pattern-executor.js.map +1 -0
- package/dist/pattern-engine/pattern-loader.d.ts +14 -0
- package/dist/pattern-engine/pattern-loader.d.ts.map +1 -0
- package/dist/pattern-engine/pattern-loader.js +111 -0
- package/dist/pattern-engine/pattern-loader.js.map +1 -0
- package/dist/pattern-engine/pattern-router.d.ts +24 -0
- package/dist/pattern-engine/pattern-router.d.ts.map +1 -0
- package/dist/pattern-engine/pattern-router.js +124 -0
- package/dist/pattern-engine/pattern-router.js.map +1 -0
- package/dist/pattern-engine/types.d.ts +144 -0
- package/dist/pattern-engine/types.d.ts.map +1 -0
- package/dist/pattern-engine/types.js +8 -0
- package/dist/pattern-engine/types.js.map +1 -0
- package/dist/pipeline/analyzer.d.ts +17 -0
- package/dist/pipeline/analyzer.d.ts.map +1 -0
- package/dist/pipeline/analyzer.js +103 -0
- package/dist/pipeline/analyzer.js.map +1 -0
- package/dist/pipeline/index.d.ts +68 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +183 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/phase-manager.d.ts +32 -0
- package/dist/pipeline/phase-manager.d.ts.map +1 -0
- package/dist/pipeline/phase-manager.js +188 -0
- package/dist/pipeline/phase-manager.js.map +1 -0
- package/dist/pipeline/pipeline-options.d.ts +19 -0
- package/dist/pipeline/pipeline-options.d.ts.map +1 -0
- package/dist/pipeline/pipeline-options.js +136 -0
- package/dist/pipeline/pipeline-options.js.map +1 -0
- package/dist/pipeline/store.d.ts +32 -0
- package/dist/pipeline/store.d.ts.map +1 -0
- package/dist/pipeline/store.js +113 -0
- package/dist/pipeline/store.js.map +1 -0
- package/dist/pipeline/types.d.ts +25 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +16 -0
- package/dist/pipeline/types.js.map +1 -0
- package/dist/profile/index.d.ts +77 -0
- package/dist/profile/index.d.ts.map +1 -0
- package/dist/profile/index.js +407 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/resume/context-gen.d.ts +20 -0
- package/dist/resume/context-gen.d.ts.map +1 -0
- package/dist/resume/context-gen.js +130 -0
- package/dist/resume/context-gen.js.map +1 -0
- package/dist/resume/index.d.ts +32 -0
- package/dist/resume/index.d.ts.map +1 -0
- package/dist/resume/index.js +142 -0
- package/dist/resume/index.js.map +1 -0
- package/dist/resume/state-machine.d.ts +21 -0
- package/dist/resume/state-machine.d.ts.map +1 -0
- package/dist/resume/state-machine.js +58 -0
- package/dist/resume/state-machine.js.map +1 -0
- package/dist/skill-registry/collector.d.ts +75 -0
- package/dist/skill-registry/collector.d.ts.map +1 -0
- package/dist/skill-registry/collector.js +334 -0
- package/dist/skill-registry/collector.js.map +1 -0
- package/dist/skill-registry/evolver.d.ts +84 -0
- package/dist/skill-registry/evolver.d.ts.map +1 -0
- package/dist/skill-registry/evolver.js +585 -0
- package/dist/skill-registry/evolver.js.map +1 -0
- package/dist/skill-registry/index.d.ts +73 -0
- package/dist/skill-registry/index.d.ts.map +1 -0
- package/dist/skill-registry/index.js +195 -0
- package/dist/skill-registry/index.js.map +1 -0
- package/dist/skill-registry/official-sync.d.ts +20 -0
- package/dist/skill-registry/official-sync.d.ts.map +1 -0
- package/dist/skill-registry/official-sync.js +576 -0
- package/dist/skill-registry/official-sync.js.map +1 -0
- package/dist/skill-registry/orchestration-config.d.ts +35 -0
- package/dist/skill-registry/orchestration-config.d.ts.map +1 -0
- package/dist/skill-registry/orchestration-config.js +125 -0
- package/dist/skill-registry/orchestration-config.js.map +1 -0
- package/dist/skill-registry/orchestrator.d.ts +45 -0
- package/dist/skill-registry/orchestrator.d.ts.map +1 -0
- package/dist/skill-registry/orchestrator.js +183 -0
- package/dist/skill-registry/orchestrator.js.map +1 -0
- package/dist/skill-registry/project-learner.d.ts +25 -0
- package/dist/skill-registry/project-learner.d.ts.map +1 -0
- package/dist/skill-registry/project-learner.js +176 -0
- package/dist/skill-registry/project-learner.js.map +1 -0
- package/dist/skill-registry/recommender.d.ts +25 -0
- package/dist/skill-registry/recommender.d.ts.map +1 -0
- package/dist/skill-registry/recommender.js +91 -0
- package/dist/skill-registry/recommender.js.map +1 -0
- package/dist/skill-registry/registry.d.ts +49 -0
- package/dist/skill-registry/registry.d.ts.map +1 -0
- package/dist/skill-registry/registry.js +160 -0
- package/dist/skill-registry/registry.js.map +1 -0
- package/dist/skill-registry/scanner.d.ts +36 -0
- package/dist/skill-registry/scanner.d.ts.map +1 -0
- package/dist/skill-registry/scanner.js +122 -0
- package/dist/skill-registry/scanner.js.map +1 -0
- package/dist/skill-registry/skills-config.d.ts +29 -0
- package/dist/skill-registry/skills-config.d.ts.map +1 -0
- package/dist/skill-registry/skills-config.js +86 -0
- package/dist/skill-registry/skills-config.js.map +1 -0
- package/dist/storage/index.d.ts +31 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/sqlite.d.ts +58 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +375 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/tests/claude-api.test.d.ts +2 -0
- package/dist/tests/claude-api.test.d.ts.map +1 -0
- package/dist/tests/claude-api.test.js +96 -0
- package/dist/tests/claude-api.test.js.map +1 -0
- package/dist/tests/conversational-config-handler.test.d.ts +2 -0
- package/dist/tests/conversational-config-handler.test.d.ts.map +1 -0
- package/dist/tests/conversational-config-handler.test.js +107 -0
- package/dist/tests/conversational-config-handler.test.js.map +1 -0
- package/dist/tests/doc-sync.test.d.ts +2 -0
- package/dist/tests/doc-sync.test.d.ts.map +1 -0
- package/dist/tests/doc-sync.test.js +148 -0
- package/dist/tests/doc-sync.test.js.map +1 -0
- package/dist/tests/orchestration-config.test.d.ts +2 -0
- package/dist/tests/orchestration-config.test.d.ts.map +1 -0
- package/dist/tests/orchestration-config.test.js +122 -0
- package/dist/tests/orchestration-config.test.js.map +1 -0
- package/dist/tests/pipeline-options.test.d.ts +2 -0
- package/dist/tests/pipeline-options.test.d.ts.map +1 -0
- package/dist/tests/pipeline-options.test.js +68 -0
- package/dist/tests/pipeline-options.test.js.map +1 -0
- package/dist/tests/resume-context-gen.test.d.ts +2 -0
- package/dist/tests/resume-context-gen.test.d.ts.map +1 -0
- package/dist/tests/resume-context-gen.test.js +93 -0
- package/dist/tests/resume-context-gen.test.js.map +1 -0
- package/dist/tests/sqlite.test.d.ts +2 -0
- package/dist/tests/sqlite.test.d.ts.map +1 -0
- package/dist/tests/sqlite.test.js +154 -0
- package/dist/tests/sqlite.test.js.map +1 -0
- package/dist/tests/tracker.test.d.ts +2 -0
- package/dist/tests/tracker.test.d.ts.map +1 -0
- package/dist/tests/tracker.test.js +75 -0
- package/dist/tests/tracker.test.js.map +1 -0
- package/dist/tests/tui.test.d.ts +2 -0
- package/dist/tests/tui.test.d.ts.map +1 -0
- package/dist/tests/tui.test.js +39 -0
- package/dist/tests/tui.test.js.map +1 -0
- package/dist/tests/user-prompt-handler.test.d.ts +2 -0
- package/dist/tests/user-prompt-handler.test.d.ts.map +1 -0
- package/dist/tests/user-prompt-handler.test.js +182 -0
- package/dist/tests/user-prompt-handler.test.js.map +1 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +486 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/types/event.d.ts +24 -0
- package/dist/types/event.d.ts.map +1 -0
- package/dist/types/event.js +2 -0
- package/dist/types/event.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/session.d.ts +11 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +2 -0
- package/dist/types/session.js.map +1 -0
- package/dist/utils/claude-api.d.ts +49 -0
- package/dist/utils/claude-api.d.ts.map +1 -0
- package/dist/utils/claude-api.js +233 -0
- package/dist/utils/claude-api.js.map +1 -0
- package/dist/utils/formatter.d.ts +57 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +109 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +136 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mutex-lock.d.ts +23 -0
- package/dist/utils/mutex-lock.d.ts.map +1 -0
- package/dist/utils/mutex-lock.js +42 -0
- package/dist/utils/mutex-lock.js.map +1 -0
- package/dist/utils/truncate.d.ts +30 -0
- package/dist/utils/truncate.d.ts.map +1 -0
- package/dist/utils/truncate.js +64 -0
- package/dist/utils/truncate.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
// 写操作工具名
|
|
5
|
+
const WRITE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit']);
|
|
6
|
+
// 扫描时排除的目录
|
|
7
|
+
const EXCLUDE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.claude-forge', 'coverage']);
|
|
8
|
+
/**
|
|
9
|
+
* 从会话事件中提取本次被修改的文件路径(去重)
|
|
10
|
+
*/
|
|
11
|
+
export function extractChangedFiles(events) {
|
|
12
|
+
const files = new Set();
|
|
13
|
+
for (const e of events) {
|
|
14
|
+
if (!WRITE_TOOLS.has(e.tool_name ?? ''))
|
|
15
|
+
continue;
|
|
16
|
+
const input = e.tool_input;
|
|
17
|
+
if (!input)
|
|
18
|
+
continue;
|
|
19
|
+
const p = (input['file_path'] ?? input['path']);
|
|
20
|
+
if (p && typeof p === 'string')
|
|
21
|
+
files.add(p);
|
|
22
|
+
}
|
|
23
|
+
return [...files];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 递归扫描 projectPath 下所有 .md 文件(排除常见无关目录)
|
|
27
|
+
*/
|
|
28
|
+
export function findProjectDocs(projectPath) {
|
|
29
|
+
const results = [];
|
|
30
|
+
function walk(dir) {
|
|
31
|
+
let entries;
|
|
32
|
+
try {
|
|
33
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (EXCLUDE_DIRS.has(entry.name))
|
|
40
|
+
continue;
|
|
41
|
+
const full = path.join(dir, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
walk(full);
|
|
44
|
+
}
|
|
45
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
46
|
+
results.push(full);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
walk(projectPath);
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
export class DocSyncEngine {
|
|
54
|
+
api;
|
|
55
|
+
constructor(api) {
|
|
56
|
+
this.api = api;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 主入口:根据本次会话事件,找出受影响的文档并更新
|
|
60
|
+
*/
|
|
61
|
+
async sync(sessionId, projectPath, events) {
|
|
62
|
+
const changedFiles = extractChangedFiles(events);
|
|
63
|
+
if (changedFiles.length === 0) {
|
|
64
|
+
logger.info('[Forge:文档同步] 本次会话无写操作,跳过');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const allDocs = findProjectDocs(projectPath);
|
|
68
|
+
if (allDocs.length === 0) {
|
|
69
|
+
logger.info('[Forge:文档同步] 项目内无 .md 文档,跳过');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
logger.info(`[Forge:文档同步] 本次改动文件 ${changedFiles.length} 个,扫描到文档 ${allDocs.length} 个`);
|
|
73
|
+
// 第一步:让 AI 判断哪些文档受影响
|
|
74
|
+
const affected = await this.detectAffectedDocs(changedFiles, allDocs, projectPath);
|
|
75
|
+
if (affected.length === 0) {
|
|
76
|
+
logger.info('[Forge:文档同步] AI 判断无文档需要更新');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
logger.info(`[Forge:文档同步] 受影响文档 ${affected.length} 个:${affected.map(p => path.relative(projectPath, p)).join(', ')}`);
|
|
80
|
+
// 第二步:逐个更新受影响的文档
|
|
81
|
+
for (const docPath of affected) {
|
|
82
|
+
await this.updateDoc(docPath, changedFiles, projectPath, sessionId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async detectAffectedDocs(changedFiles, allDocs, projectPath) {
|
|
86
|
+
const relChanged = changedFiles.map(f => path.relative(projectPath, f));
|
|
87
|
+
const relDocs = allDocs.map(f => path.relative(projectPath, f));
|
|
88
|
+
const prompt = `你是一个代码项目的文档维护助手。
|
|
89
|
+
|
|
90
|
+
本次会话修改了以下文件:
|
|
91
|
+
${relChanged.map(f => `- ${f}`).join('\n')}
|
|
92
|
+
|
|
93
|
+
项目中存在以下文档:
|
|
94
|
+
${relDocs.map(f => `- ${f}`).join('\n')}
|
|
95
|
+
|
|
96
|
+
请判断哪些文档的内容可能因上述文件改动而需要更新(例如:API 文档、设计文档、优化计划、README 等记录了相关模块功能或状态的文档)。
|
|
97
|
+
|
|
98
|
+
只返回需要更新的文档路径列表,每行一个相对路径,不需要解释。如果没有文档需要更新,返回空内容。`;
|
|
99
|
+
const result = await this.api.complete(prompt, 'doc-sync-detect', 2, 60_000);
|
|
100
|
+
return result
|
|
101
|
+
.split('\n')
|
|
102
|
+
.map(l => l.trim().replace(/^-\s*/, ''))
|
|
103
|
+
.filter(l => l.length > 0)
|
|
104
|
+
.map(rel => path.join(projectPath, rel))
|
|
105
|
+
.filter(abs => allDocs.includes(abs));
|
|
106
|
+
}
|
|
107
|
+
async updateDoc(docPath, changedFiles, projectPath, sessionId) {
|
|
108
|
+
let current;
|
|
109
|
+
try {
|
|
110
|
+
current = fs.readFileSync(docPath, 'utf-8');
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
logger.warn(`[Forge:文档同步] 读取文档失败:${docPath}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// 读取改动文件的内容摘要(只取前 300 字符)
|
|
117
|
+
const changedSummaries = changedFiles
|
|
118
|
+
.map(f => {
|
|
119
|
+
try {
|
|
120
|
+
const content = fs.readFileSync(f, 'utf-8');
|
|
121
|
+
return `### ${path.relative(projectPath, f)}\n${content}`;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return `### ${path.relative(projectPath, f)}\n(文件不存在或已删除)`;
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
.join('\n\n');
|
|
128
|
+
const prompt = `你是一个代码项目的文档维护助手。
|
|
129
|
+
|
|
130
|
+
以下是本次会话修改的文件内容摘要:
|
|
131
|
+
${changedSummaries}
|
|
132
|
+
|
|
133
|
+
以下是需要更新的文档(${path.relative(projectPath, docPath)})的当前内容:
|
|
134
|
+
${current}
|
|
135
|
+
|
|
136
|
+
请根据文件改动,以 JSON 数组格式返回需要修改的行(仅返回有变化的行),格式如下:
|
|
137
|
+
[{"old":"原始行内容(精确匹配)","new":"替换后的行内容"}]
|
|
138
|
+
|
|
139
|
+
规则:
|
|
140
|
+
- 将未完成的条目([ ])标记为已完成([x]),并在行末补充日期(如 [x] 2026-04-11)
|
|
141
|
+
- 若某功能被废弃,在行末标注(已废弃)
|
|
142
|
+
- 只返回 JSON 数组本身,不要用代码块包裹,不要任何解释
|
|
143
|
+
- 如果没有需要修改的行,返回空数组 []`;
|
|
144
|
+
let patchJson;
|
|
145
|
+
try {
|
|
146
|
+
patchJson = await this.api.complete(prompt, 'doc-sync-update', 1, 60_000);
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
logger.warn(`[Forge:文档同步] AI 更新文档失败(${path.relative(projectPath, docPath)}):${err}`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// 解析 patch JSON 并应用行级替换
|
|
153
|
+
let patches;
|
|
154
|
+
try {
|
|
155
|
+
// 优先从 ```json ... ``` 代码块中提取
|
|
156
|
+
const fenceMatch = patchJson.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
157
|
+
const jsonStr = fenceMatch ? fenceMatch[1].trim() : patchJson.trim();
|
|
158
|
+
// 从提取内容中找 JSON 数组
|
|
159
|
+
const jsonMatch = jsonStr.match(/\[\s*\{[\s\S]*\}\s*\]/) ?? jsonStr.match(/\[\s*\]/);
|
|
160
|
+
patches = jsonMatch ? JSON.parse(jsonMatch[0]) : [];
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
logger.warn(`[Forge:文档同步] patch 解析失败,跳过:${path.relative(projectPath, docPath)}`);
|
|
164
|
+
logger.warn(`[Forge:文档同步] AI 原始返回:${patchJson.slice(0, 300)}`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (!patches.length) {
|
|
168
|
+
logger.info(`[Forge:文档同步] 文档无变化:${path.relative(projectPath, docPath)}`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
let updated = current;
|
|
172
|
+
for (const { old: oldLine, new: newLine } of patches) {
|
|
173
|
+
if (oldLine && updated.includes(oldLine)) {
|
|
174
|
+
updated = updated.replace(oldLine, newLine);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (updated === current) {
|
|
178
|
+
logger.info(`[Forge:文档同步] patch 未命中任何行:${path.relative(projectPath, docPath)}`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
fs.writeFileSync(docPath, updated, 'utf-8');
|
|
183
|
+
logger.info(`[Forge:文档同步] 已更新(${patches.length} 处):${path.relative(projectPath, docPath)}`);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
logger.warn(`[Forge:文档同步] 写入文档失败(${path.relative(projectPath, docPath)}):${err}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doc-sync/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 检查当前 session 的 context token 使用量,接近限制时发出预警
|
|
3
|
+
|
|
4
|
+
WARN_THRESHOLD="${CONTEXT_WARN_THRESHOLD:-150000}"
|
|
5
|
+
ALERT_THRESHOLD="${CONTEXT_ALERT_THRESHOLD:-180000}"
|
|
6
|
+
|
|
7
|
+
# 从 stdin 读取 hook 输入,提取 session_id 和 cwd
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
SESSION_ID=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("session_id",""))' 2>/dev/null || echo "")
|
|
10
|
+
CWD=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo "")
|
|
11
|
+
|
|
12
|
+
# 定位 session 文件
|
|
13
|
+
find_session_file() {
|
|
14
|
+
local session_id="$1"
|
|
15
|
+
local cwd="$2"
|
|
16
|
+
|
|
17
|
+
if [ -n "$cwd" ]; then
|
|
18
|
+
local sanitized
|
|
19
|
+
sanitized=$(echo "$cwd" | sed 's|/|-|g')
|
|
20
|
+
local project_dir="$HOME/.claude/projects/${sanitized}"
|
|
21
|
+
if [ -n "$session_id" ] && [ -f "$project_dir/${session_id}.jsonl" ]; then
|
|
22
|
+
echo "$project_dir/${session_id}.jsonl"
|
|
23
|
+
return
|
|
24
|
+
fi
|
|
25
|
+
local latest
|
|
26
|
+
latest=$(ls -t "$project_dir"/*.jsonl 2>/dev/null | head -1)
|
|
27
|
+
[ -n "$latest" ] && echo "$latest"
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
SESSION_FILE=$(find_session_file "$SESSION_ID" "$CWD")
|
|
32
|
+
|
|
33
|
+
if [ -z "$SESSION_FILE" ] || [ ! -f "$SESSION_FILE" ]; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
CONTEXT_TOKENS=$(python3 - "$SESSION_FILE" <<'PYEOF'
|
|
38
|
+
import sys, json
|
|
39
|
+
|
|
40
|
+
session_file = sys.argv[1]
|
|
41
|
+
max_tokens = 0
|
|
42
|
+
|
|
43
|
+
with open(session_file) as f:
|
|
44
|
+
for line in f:
|
|
45
|
+
try:
|
|
46
|
+
d = json.loads(line)
|
|
47
|
+
if d.get('type') == 'assistant' and 'message' in d:
|
|
48
|
+
usage = d['message'].get('usage', {})
|
|
49
|
+
total = (usage.get('input_tokens', 0) +
|
|
50
|
+
usage.get('cache_read_input_tokens', 0) +
|
|
51
|
+
usage.get('cache_creation_input_tokens', 0))
|
|
52
|
+
if total > max_tokens:
|
|
53
|
+
max_tokens = total
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
print(max_tokens)
|
|
58
|
+
PYEOF
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
CONTEXT_TOKENS="${CONTEXT_TOKENS:-0}"
|
|
62
|
+
|
|
63
|
+
# 冷却机制:同一会话 60 秒内只触发一次告警,避免每次 PostToolUse 重复输出
|
|
64
|
+
COOLDOWN_SECS="${CONTEXT_ALERT_COOLDOWN:-60}"
|
|
65
|
+
ALERT_FLAG_DIR="${TMPDIR:-/tmp}/claude-forge-ctx"
|
|
66
|
+
mkdir -p "$ALERT_FLAG_DIR"
|
|
67
|
+
ALERT_FLAG="$ALERT_FLAG_DIR/${SESSION_ID}.alert"
|
|
68
|
+
|
|
69
|
+
is_in_cooldown() {
|
|
70
|
+
[ -f "$ALERT_FLAG" ] || return 1
|
|
71
|
+
local last_alert
|
|
72
|
+
last_alert=$(cat "$ALERT_FLAG" 2>/dev/null)
|
|
73
|
+
local now
|
|
74
|
+
now=$(date +%s)
|
|
75
|
+
[ -n "$last_alert" ] && [ $((now - last_alert)) -lt "$COOLDOWN_SECS" ]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if [ "$CONTEXT_TOKENS" -ge "$ALERT_THRESHOLD" ] 2>/dev/null; then
|
|
79
|
+
if ! is_in_cooldown; then
|
|
80
|
+
date +%s > "$ALERT_FLAG"
|
|
81
|
+
# 告急:注入 systemMessage 提示用户手动执行 /compact
|
|
82
|
+
echo "{\"systemMessage\": \"⚠️ Context 告急:当前已用 ${CONTEXT_TOKENS} tokens(阈值 ${ALERT_THRESHOLD}),请立即执行 /compact 压缩上下文。\"}"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
elif [ "$CONTEXT_TOKENS" -ge "$WARN_THRESHOLD" ] 2>/dev/null; then
|
|
86
|
+
if ! is_in_cooldown; then
|
|
87
|
+
date +%s > "$ALERT_FLAG"
|
|
88
|
+
# 预警:在命令行输出提示(stderr → 终端可见,不影响 Claude Code 响应)
|
|
89
|
+
echo "⚠️ Context 预警:已用 ${CONTEXT_TOKENS} tokens,建议执行 /compact" >&2
|
|
90
|
+
fi
|
|
91
|
+
exit 0
|
|
92
|
+
else
|
|
93
|
+
# 低于预警阈值时清除冷却标记,允许下次超限时重新告警
|
|
94
|
+
rm -f "$ALERT_FLAG"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
exit 0
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 检查当前 session 的 context token 使用量,接近限制时发出预警
|
|
3
|
+
|
|
4
|
+
WARN_THRESHOLD="${CONTEXT_WARN_THRESHOLD:-150000}"
|
|
5
|
+
ALERT_THRESHOLD="${CONTEXT_ALERT_THRESHOLD:-180000}"
|
|
6
|
+
|
|
7
|
+
# 从 stdin 读取 hook 输入,提取 session_id 和 cwd
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
SESSION_ID=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("session_id",""))' 2>/dev/null || echo "")
|
|
10
|
+
CWD=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo "")
|
|
11
|
+
|
|
12
|
+
# 定位 session 文件
|
|
13
|
+
find_session_file() {
|
|
14
|
+
local session_id="$1"
|
|
15
|
+
local cwd="$2"
|
|
16
|
+
|
|
17
|
+
if [ -n "$cwd" ]; then
|
|
18
|
+
local sanitized
|
|
19
|
+
sanitized=$(echo "$cwd" | sed 's|/|-|g')
|
|
20
|
+
local project_dir="$HOME/.claude/projects/${sanitized}"
|
|
21
|
+
if [ -n "$session_id" ] && [ -f "$project_dir/${session_id}.jsonl" ]; then
|
|
22
|
+
echo "$project_dir/${session_id}.jsonl"
|
|
23
|
+
return
|
|
24
|
+
fi
|
|
25
|
+
local latest
|
|
26
|
+
latest=$(ls -t "$project_dir"/*.jsonl 2>/dev/null | head -1)
|
|
27
|
+
[ -n "$latest" ] && echo "$latest"
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
SESSION_FILE=$(find_session_file "$SESSION_ID" "$CWD")
|
|
32
|
+
|
|
33
|
+
if [ -z "$SESSION_FILE" ] || [ ! -f "$SESSION_FILE" ]; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
CONTEXT_TOKENS=$(python3 - "$SESSION_FILE" <<'PYEOF'
|
|
38
|
+
import sys, json
|
|
39
|
+
|
|
40
|
+
session_file = sys.argv[1]
|
|
41
|
+
max_tokens = 0
|
|
42
|
+
|
|
43
|
+
with open(session_file) as f:
|
|
44
|
+
for line in f:
|
|
45
|
+
try:
|
|
46
|
+
d = json.loads(line)
|
|
47
|
+
if d.get('type') == 'assistant' and 'message' in d:
|
|
48
|
+
usage = d['message'].get('usage', {})
|
|
49
|
+
total = (usage.get('input_tokens', 0) +
|
|
50
|
+
usage.get('cache_read_input_tokens', 0) +
|
|
51
|
+
usage.get('cache_creation_input_tokens', 0))
|
|
52
|
+
if total > max_tokens:
|
|
53
|
+
max_tokens = total
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
print(max_tokens)
|
|
58
|
+
PYEOF
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
CONTEXT_TOKENS="${CONTEXT_TOKENS:-0}"
|
|
62
|
+
|
|
63
|
+
# 冷却机制:同一会话 60 秒内只触发一次告警,避免每次 PostToolUse 重复输出
|
|
64
|
+
COOLDOWN_SECS="${CONTEXT_ALERT_COOLDOWN:-60}"
|
|
65
|
+
ALERT_FLAG_DIR="${TMPDIR:-/tmp}/claude-forge-ctx"
|
|
66
|
+
mkdir -p "$ALERT_FLAG_DIR"
|
|
67
|
+
ALERT_FLAG="$ALERT_FLAG_DIR/${SESSION_ID}.alert"
|
|
68
|
+
|
|
69
|
+
is_in_cooldown() {
|
|
70
|
+
[ -f "$ALERT_FLAG" ] || return 1
|
|
71
|
+
local last_alert
|
|
72
|
+
last_alert=$(cat "$ALERT_FLAG" 2>/dev/null)
|
|
73
|
+
local now
|
|
74
|
+
now=$(date +%s)
|
|
75
|
+
[ -n "$last_alert" ] && [ $((now - last_alert)) -lt "$COOLDOWN_SECS" ]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if [ "$CONTEXT_TOKENS" -ge "$ALERT_THRESHOLD" ] 2>/dev/null; then
|
|
79
|
+
if ! is_in_cooldown; then
|
|
80
|
+
date +%s > "$ALERT_FLAG"
|
|
81
|
+
# 告急:注入 systemMessage 提示用户手动执行 /compact
|
|
82
|
+
echo "{\"systemMessage\": \"⚠️ Context 告急:当前已用 ${CONTEXT_TOKENS} tokens(阈值 ${ALERT_THRESHOLD}),请立即执行 /compact 压缩上下文。\"}"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
elif [ "$CONTEXT_TOKENS" -ge "$WARN_THRESHOLD" ] 2>/dev/null; then
|
|
86
|
+
if ! is_in_cooldown; then
|
|
87
|
+
date +%s > "$ALERT_FLAG"
|
|
88
|
+
# 预警:在命令行输出提示(stderr → 终端可见,不影响 Claude Code 响应)
|
|
89
|
+
echo "⚠️ Context 预警:已用 ${CONTEXT_TOKENS} tokens,建议执行 /compact" >&2
|
|
90
|
+
fi
|
|
91
|
+
exit 0
|
|
92
|
+
else
|
|
93
|
+
# 低于预警阈值时清除冷却标记,允许下次超限时重新告警
|
|
94
|
+
rm -f "$ALERT_FLAG"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
exit 0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - Notification Hook
|
|
3
|
+
|
|
4
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
5
|
+
|
|
6
|
+
# 读取 stdin
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# 提取 cwd
|
|
10
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
11
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
12
|
+
|
|
13
|
+
# 构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
14
|
+
EVENT=$(FORGE_PROJECT_PATH="$PROJECT_PATH" FORGE_INPUT="$INPUT" \
|
|
15
|
+
python3 -c "
|
|
16
|
+
import json, os
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
try:
|
|
19
|
+
tool_input = json.loads(os.environ.get('FORGE_INPUT', '{}'))
|
|
20
|
+
except Exception:
|
|
21
|
+
tool_input = {}
|
|
22
|
+
print(json.dumps({
|
|
23
|
+
'hook_type': 'Notification',
|
|
24
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
25
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
26
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
27
|
+
'tool_name': 'notification',
|
|
28
|
+
'tool_input': tool_input,
|
|
29
|
+
}))
|
|
30
|
+
" 2>/dev/null)
|
|
31
|
+
|
|
32
|
+
echo "$EVENT" | nc -U -w 1 "$SOCKET_PATH" 2>/dev/null || true
|
|
33
|
+
exit 0
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - PostToolUse Hook
|
|
3
|
+
|
|
4
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
5
|
+
|
|
6
|
+
# 读取 stdin
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# 提取字段(tool_response 是 Claude Code 的字段名)
|
|
10
|
+
TOOL_NAME="${CLAUDE_TOOL_NAME:-$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("tool_name",""))' 2>/dev/null || echo '')}"
|
|
11
|
+
TOOL_INPUT=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get("tool_input",{})))' 2>/dev/null || echo '{}')
|
|
12
|
+
TOOL_OUTPUT=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get("tool_response",{})))' 2>/dev/null || echo '{}')
|
|
13
|
+
# cwd 是 Claude Code 的项目根目录
|
|
14
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
15
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
16
|
+
|
|
17
|
+
# 构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
18
|
+
EVENT=$(FORGE_TOOL_NAME="$TOOL_NAME" FORGE_TOOL_INPUT="$TOOL_INPUT" FORGE_TOOL_OUTPUT="$TOOL_OUTPUT" FORGE_PROJECT_PATH="$PROJECT_PATH" \
|
|
19
|
+
python3 -c "
|
|
20
|
+
import json, os
|
|
21
|
+
from datetime import datetime
|
|
22
|
+
try:
|
|
23
|
+
tool_input = json.loads(os.environ.get('FORGE_TOOL_INPUT', '{}'))
|
|
24
|
+
except Exception:
|
|
25
|
+
tool_input = {}
|
|
26
|
+
try:
|
|
27
|
+
tool_output = json.loads(os.environ.get('FORGE_TOOL_OUTPUT', '{}'))
|
|
28
|
+
except Exception:
|
|
29
|
+
tool_output = {}
|
|
30
|
+
print(json.dumps({
|
|
31
|
+
'hook_type': 'PostToolUse',
|
|
32
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
33
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
34
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
35
|
+
'tool_name': os.environ.get('FORGE_TOOL_NAME', ''),
|
|
36
|
+
'tool_input': tool_input,
|
|
37
|
+
'tool_output': tool_output,
|
|
38
|
+
}))
|
|
39
|
+
" 2>/dev/null)
|
|
40
|
+
|
|
41
|
+
# 发送到 daemon(PostToolUse 也需要等待响应以支持通知注入)
|
|
42
|
+
RESPONSE=$(echo "$EVENT" | nc -U -w 5 "$SOCKET_PATH" 2>/dev/null || true)
|
|
43
|
+
if [ -n "$RESPONSE" ]; then
|
|
44
|
+
HAS_CONTEXT=$(echo "$RESPONSE" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("yes" if d.get("additionalContext") else "no")' 2>/dev/null || echo 'no')
|
|
45
|
+
if [ "$HAS_CONTEXT" = "yes" ]; then
|
|
46
|
+
echo "$RESPONSE"
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
exit 0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - PreToolUse Hook(双向通信)
|
|
3
|
+
|
|
4
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
5
|
+
|
|
6
|
+
# 读取 stdin(Claude Code 传入的 JSON)
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# 提取字段
|
|
10
|
+
TOOL_NAME="${CLAUDE_TOOL_NAME:-$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("tool_name",""))' 2>/dev/null || echo '')}"
|
|
11
|
+
TOOL_INPUT=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get("tool_input",{})))' 2>/dev/null || echo '{}')
|
|
12
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
13
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
14
|
+
|
|
15
|
+
# 构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
16
|
+
EVENT=$(FORGE_TOOL_NAME="$TOOL_NAME" FORGE_TOOL_INPUT="$TOOL_INPUT" FORGE_PROJECT_PATH="$PROJECT_PATH" \
|
|
17
|
+
python3 -c "
|
|
18
|
+
import json, os
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
tool_input_raw = os.environ.get('FORGE_TOOL_INPUT', '{}')
|
|
21
|
+
try:
|
|
22
|
+
tool_input = json.loads(tool_input_raw)
|
|
23
|
+
except Exception:
|
|
24
|
+
tool_input = {}
|
|
25
|
+
print(json.dumps({
|
|
26
|
+
'hook_type': 'PreToolUse',
|
|
27
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
28
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
29
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
30
|
+
'tool_name': os.environ.get('FORGE_TOOL_NAME', ''),
|
|
31
|
+
'tool_input': tool_input,
|
|
32
|
+
}))
|
|
33
|
+
" 2>/dev/null)
|
|
34
|
+
|
|
35
|
+
# 发送事件并等待响应(双向通信,5 秒超时)
|
|
36
|
+
RESPONSE=$(echo "$EVENT" | nc -U -w 5 "$SOCKET_PATH" 2>/dev/null)
|
|
37
|
+
|
|
38
|
+
if [ -n "$RESPONSE" ]; then
|
|
39
|
+
# 解析响应
|
|
40
|
+
ALLOW=$(echo "$RESPONSE" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(str(d.get("allow",True)).lower())' 2>/dev/null || echo 'true')
|
|
41
|
+
|
|
42
|
+
if [ "$ALLOW" = "false" ]; then
|
|
43
|
+
# 输出拦截 JSON 到 stdout(Claude Code 读取)
|
|
44
|
+
echo "$RESPONSE"
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# 有 additionalContext 时输出
|
|
49
|
+
HAS_CONTEXT=$(echo "$RESPONSE" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("yes" if d.get("additionalContext") else "no")' 2>/dev/null || echo 'no')
|
|
50
|
+
if [ "$HAS_CONTEXT" = "yes" ]; then
|
|
51
|
+
echo "$RESPONSE"
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
exit 0
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - Stop Hook
|
|
3
|
+
|
|
4
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
5
|
+
|
|
6
|
+
# 读取 stdin
|
|
7
|
+
INPUT=$(cat 2>/dev/null || echo '{}')
|
|
8
|
+
|
|
9
|
+
# 提取 cwd
|
|
10
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
11
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
12
|
+
|
|
13
|
+
# 构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
14
|
+
EVENT=$(FORGE_PROJECT_PATH="$PROJECT_PATH" \
|
|
15
|
+
python3 -c "
|
|
16
|
+
import json, os
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
print(json.dumps({
|
|
19
|
+
'hook_type': 'Stop',
|
|
20
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
21
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
22
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
23
|
+
'tool_name': 'stop',
|
|
24
|
+
'tool_input': {},
|
|
25
|
+
}))
|
|
26
|
+
" 2>/dev/null)
|
|
27
|
+
|
|
28
|
+
echo "$EVENT" | nc -U -w 1 "$SOCKET_PATH" 2>/dev/null || true
|
|
29
|
+
exit 0
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - UserPromptSubmit Hook
|
|
3
|
+
# 拦截用户输入,触发意图分析和自动 Pipeline 编排
|
|
4
|
+
|
|
5
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
6
|
+
|
|
7
|
+
# daemon 未运行,快速跳过
|
|
8
|
+
if [ ! -S "$SOCKET_PATH" ]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# 读取 stdin(Claude Code 传入的 JSON)
|
|
13
|
+
INPUT=$(cat)
|
|
14
|
+
|
|
15
|
+
# 提取字段
|
|
16
|
+
USER_PROMPT=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("prompt",""))' 2>/dev/null || echo '')
|
|
17
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
18
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
19
|
+
|
|
20
|
+
# 空 prompt 跳过
|
|
21
|
+
if [ -z "$USER_PROMPT" ]; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 安全地构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
26
|
+
EVENT=$(FORGE_USER_PROMPT="$USER_PROMPT" FORGE_PROJECT_PATH="$PROJECT_PATH" \
|
|
27
|
+
python3 -c "
|
|
28
|
+
import json, os
|
|
29
|
+
from datetime import datetime
|
|
30
|
+
print(json.dumps({
|
|
31
|
+
'hook_type': 'UserPromptSubmit',
|
|
32
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
33
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
34
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
35
|
+
'tool_name': 'UserPrompt',
|
|
36
|
+
'tool_input': {'user_prompt': os.environ.get('FORGE_USER_PROMPT', '')},
|
|
37
|
+
}))
|
|
38
|
+
" 2>/dev/null)
|
|
39
|
+
|
|
40
|
+
if [ -z "$EVENT" ]; then
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# 发送事件并等待响应(10 秒超时,AI 分析可能需要更多时间)
|
|
45
|
+
RESPONSE=$(echo "$EVENT" | nc -U -w 10 "$SOCKET_PATH" 2>/dev/null)
|
|
46
|
+
|
|
47
|
+
if [ -n "$RESPONSE" ]; then
|
|
48
|
+
HAS_CONTEXT=$(echo "$RESPONSE" | python3 -c 'import sys,json; d=json.load(sys.stdin); print("yes" if d.get("additionalContext") else "no")' 2>/dev/null || echo 'no')
|
|
49
|
+
if [ "$HAS_CONTEXT" = "yes" ]; then
|
|
50
|
+
# stderr 输出到终端,让用户实时看到决策过程
|
|
51
|
+
# 用 fd3 保存真实 stderr,python3 错误丢弃,面板输出保留
|
|
52
|
+
exec 3>&2
|
|
53
|
+
echo "$RESPONSE" | python3 -c '
|
|
54
|
+
import sys, json, os
|
|
55
|
+
d = json.load(sys.stdin)
|
|
56
|
+
ctx = d.get("additionalContext", "")
|
|
57
|
+
lines = []
|
|
58
|
+
for line in ctx.split("\n"):
|
|
59
|
+
if line.startswith("请在回复"):
|
|
60
|
+
break
|
|
61
|
+
if line.strip():
|
|
62
|
+
lines.append(line)
|
|
63
|
+
if lines:
|
|
64
|
+
os.write(3, ("\033[36m" + "\n".join(lines) + "\033[0m\n").encode())
|
|
65
|
+
' 2>/dev/null
|
|
66
|
+
exec 3>&-
|
|
67
|
+
# stdout 返回给 Claude Code
|
|
68
|
+
echo "$RESPONSE"
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
exit 0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claude Forge - Notification Hook
|
|
3
|
+
|
|
4
|
+
SOCKET_PATH="${CLAUDE_FORGE_SOCKET:-$HOME/.claude-forge/daemon.sock}"
|
|
5
|
+
|
|
6
|
+
# 读取 stdin
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# 提取 cwd
|
|
10
|
+
PROJECT_PATH=$(echo "$INPUT" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("cwd",""))' 2>/dev/null || echo '')
|
|
11
|
+
PROJECT_PATH="${PROJECT_PATH:-${PWD}}"
|
|
12
|
+
|
|
13
|
+
# 构造事件 JSON(通过环境变量传参,避免 shell 注入)
|
|
14
|
+
EVENT=$(FORGE_PROJECT_PATH="$PROJECT_PATH" FORGE_INPUT="$INPUT" \
|
|
15
|
+
python3 -c "
|
|
16
|
+
import json, os
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
try:
|
|
19
|
+
tool_input = json.loads(os.environ.get('FORGE_INPUT', '{}'))
|
|
20
|
+
except Exception:
|
|
21
|
+
tool_input = {}
|
|
22
|
+
print(json.dumps({
|
|
23
|
+
'hook_type': 'Notification',
|
|
24
|
+
'timestamp': datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
|
25
|
+
'session_id': os.environ.get('CLAUDE_CODE_SESSION_ID', 'cli'),
|
|
26
|
+
'project_path': os.environ.get('FORGE_PROJECT_PATH', ''),
|
|
27
|
+
'tool_name': 'notification',
|
|
28
|
+
'tool_input': tool_input,
|
|
29
|
+
}))
|
|
30
|
+
" 2>/dev/null)
|
|
31
|
+
|
|
32
|
+
echo "$EVENT" | nc -U -w 1 "$SOCKET_PATH" 2>/dev/null || true
|
|
33
|
+
exit 0
|