@stackmemoryai/stackmemory 0.5.59 → 0.5.61
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 +105 -1
- package/dist/src/cli/claude-sm.js +130 -50
- package/dist/src/cli/claude-sm.js.map +2 -2
- package/dist/src/cli/index.js +18 -3
- package/dist/src/cli/index.js.map +3 -3
- package/dist/src/core/extensions/custom-tools.js +567 -0
- package/dist/src/core/extensions/custom-tools.js.map +7 -0
- package/dist/src/core/extensions/index.js +55 -0
- package/dist/src/core/extensions/index.js.map +7 -0
- package/dist/src/core/extensions/loader.js +709 -0
- package/dist/src/core/extensions/loader.js.map +7 -0
- package/dist/src/core/extensions/plugin-system.js +506 -0
- package/dist/src/core/extensions/plugin-system.js.map +7 -0
- package/dist/src/core/extensions/provider-adapter.js +617 -0
- package/dist/src/core/extensions/provider-adapter.js.map +7 -0
- package/dist/src/core/extensions/sandbox-runtime.js +664 -0
- package/dist/src/core/extensions/sandbox-runtime.js.map +7 -0
- package/dist/src/core/storage/chromadb-adapter.js +32 -6
- package/dist/src/core/storage/chromadb-adapter.js.map +2 -2
- package/dist/src/skills/repo-ingestion-skill.js +35 -12
- package/dist/src/skills/repo-ingestion-skill.js.map +2 -2
- package/package.json +11 -7
- package/scripts/background-sync-manager.js +145 -83
- package/scripts/claude-sm-autostart.js +17 -12
- package/scripts/gepa/README.md +275 -0
- package/scripts/gepa/config.json +53 -0
- package/scripts/gepa/evals/coding-tasks.jsonl +5 -0
- package/scripts/gepa/evals/fixtures/buggy-loop.js +18 -0
- package/scripts/gepa/evals/fixtures/callback-hell.js +53 -0
- package/scripts/gepa/generations/gen-000/baseline.md +124 -0
- package/scripts/gepa/hooks/auto-optimize.js +494 -0
- package/scripts/gepa/hooks/eval-tracker.js +203 -0
- package/scripts/gepa/hooks/reflect.js +311 -0
- package/scripts/gepa/optimize.js +611 -0
- package/scripts/gepa/state.json +14 -0
- package/scripts/test-pre-publish-quick.sh +1 -1
- package/dist/agents/core/agent-task-manager.js +0 -527
- package/dist/agents/core/agent-task-manager.js.map +0 -7
- package/dist/agents/testing-agent.js +0 -614
- package/dist/agents/testing-agent.js.map +0 -7
- package/dist/agents/verifiers/base-verifier.js +0 -133
- package/dist/agents/verifiers/base-verifier.js.map +0 -7
- package/dist/agents/verifiers/formatter-verifier.js +0 -130
- package/dist/agents/verifiers/formatter-verifier.js.map +0 -7
- package/dist/agents/verifiers/llm-judge.js +0 -252
- package/dist/agents/verifiers/llm-judge.js.map +0 -7
- package/dist/cli/auto-detect.js +0 -321
- package/dist/cli/auto-detect.js.map +0 -7
- package/dist/cli/browser-test.js +0 -33
- package/dist/cli/browser-test.js.map +0 -7
- package/dist/cli/claude-sm-danger.js +0 -21
- package/dist/cli/claude-sm-danger.js.map +0 -7
- package/dist/cli/claude-sm.js +0 -1156
- package/dist/cli/claude-sm.js.map +0 -7
- package/dist/cli/codex-sm-danger.js +0 -21
- package/dist/cli/codex-sm-danger.js.map +0 -7
- package/dist/cli/codex-sm.js +0 -349
- package/dist/cli/codex-sm.js.map +0 -7
- package/dist/cli/commands/api.js +0 -232
- package/dist/cli/commands/api.js.map +0 -7
- package/dist/cli/commands/auto-background.js +0 -180
- package/dist/cli/commands/auto-background.js.map +0 -7
- package/dist/cli/commands/cleanup-processes.js +0 -68
- package/dist/cli/commands/cleanup-processes.js.map +0 -7
- package/dist/cli/commands/clear.js +0 -202
- package/dist/cli/commands/clear.js.map +0 -7
- package/dist/cli/commands/config.js +0 -445
- package/dist/cli/commands/config.js.map +0 -7
- package/dist/cli/commands/context-rehydrate.js +0 -751
- package/dist/cli/commands/context-rehydrate.js.map +0 -7
- package/dist/cli/commands/context.js +0 -343
- package/dist/cli/commands/context.js.map +0 -7
- package/dist/cli/commands/daemon.js +0 -392
- package/dist/cli/commands/daemon.js.map +0 -7
- package/dist/cli/commands/dashboard.js +0 -210
- package/dist/cli/commands/dashboard.js.map +0 -7
- package/dist/cli/commands/db.js +0 -147
- package/dist/cli/commands/db.js.map +0 -7
- package/dist/cli/commands/decision.js +0 -266
- package/dist/cli/commands/decision.js.map +0 -7
- package/dist/cli/commands/discovery.js +0 -279
- package/dist/cli/commands/discovery.js.map +0 -7
- package/dist/cli/commands/handoff.js +0 -624
- package/dist/cli/commands/handoff.js.map +0 -7
- package/dist/cli/commands/hooks.js +0 -298
- package/dist/cli/commands/hooks.js.map +0 -7
- package/dist/cli/commands/linear-unified.js +0 -353
- package/dist/cli/commands/linear-unified.js.map +0 -7
- package/dist/cli/commands/linear.js +0 -529
- package/dist/cli/commands/linear.js.map +0 -7
- package/dist/cli/commands/log.js +0 -169
- package/dist/cli/commands/log.js.map +0 -7
- package/dist/cli/commands/login.js +0 -172
- package/dist/cli/commands/login.js.map +0 -7
- package/dist/cli/commands/migrate.js +0 -240
- package/dist/cli/commands/migrate.js.map +0 -7
- package/dist/cli/commands/model.js +0 -533
- package/dist/cli/commands/model.js.map +0 -7
- package/dist/cli/commands/monitor.js +0 -313
- package/dist/cli/commands/monitor.js.map +0 -7
- package/dist/cli/commands/onboard.js +0 -536
- package/dist/cli/commands/onboard.js.map +0 -7
- package/dist/cli/commands/projects.js +0 -199
- package/dist/cli/commands/projects.js.map +0 -7
- package/dist/cli/commands/quality.js +0 -413
- package/dist/cli/commands/quality.js.map +0 -7
- package/dist/cli/commands/ralph.js +0 -909
- package/dist/cli/commands/ralph.js.map +0 -7
- package/dist/cli/commands/retrieval.js +0 -248
- package/dist/cli/commands/retrieval.js.map +0 -7
- package/dist/cli/commands/search.js +0 -173
- package/dist/cli/commands/search.js.map +0 -7
- package/dist/cli/commands/service.js +0 -749
- package/dist/cli/commands/service.js.map +0 -7
- package/dist/cli/commands/session.js +0 -200
- package/dist/cli/commands/session.js.map +0 -7
- package/dist/cli/commands/settings.js +0 -306
- package/dist/cli/commands/settings.js.map +0 -7
- package/dist/cli/commands/setup.js +0 -701
- package/dist/cli/commands/setup.js.map +0 -7
- package/dist/cli/commands/shell.js +0 -249
- package/dist/cli/commands/shell.js.map +0 -7
- package/dist/cli/commands/signup.js +0 -50
- package/dist/cli/commands/signup.js.map +0 -7
- package/dist/cli/commands/skills.js +0 -470
- package/dist/cli/commands/skills.js.map +0 -7
- package/dist/cli/commands/sms-notify.js +0 -795
- package/dist/cli/commands/sms-notify.js.map +0 -7
- package/dist/cli/commands/storage-tier.js +0 -183
- package/dist/cli/commands/storage-tier.js.map +0 -7
- package/dist/cli/commands/storage.js +0 -360
- package/dist/cli/commands/storage.js.map +0 -7
- package/dist/cli/commands/sweep.js +0 -249
- package/dist/cli/commands/sweep.js.map +0 -7
- package/dist/cli/commands/tasks.js +0 -213
- package/dist/cli/commands/tasks.js.map +0 -7
- package/dist/cli/commands/test.js +0 -286
- package/dist/cli/commands/test.js.map +0 -7
- package/dist/cli/commands/workflow.js +0 -142
- package/dist/cli/commands/workflow.js.map +0 -7
- package/dist/cli/commands/worktree.js +0 -319
- package/dist/cli/commands/worktree.js.map +0 -7
- package/dist/cli/index.js +0 -594
- package/dist/cli/index.js.map +0 -7
- package/dist/cli/opencode-sm.js +0 -448
- package/dist/cli/opencode-sm.js.map +0 -7
- package/dist/cli/utils/viewer.js +0 -96
- package/dist/cli/utils/viewer.js.map +0 -7
- package/dist/core/analytics/team-analytics.js +0 -378
- package/dist/core/analytics/team-analytics.js.map +0 -7
- package/dist/core/config/config-manager.js +0 -398
- package/dist/core/config/config-manager.js.map +0 -7
- package/dist/core/config/feature-flags.js +0 -76
- package/dist/core/config/feature-flags.js.map +0 -7
- package/dist/core/config/storage-config.js +0 -115
- package/dist/core/config/storage-config.js.map +0 -7
- package/dist/core/config/types.js +0 -144
- package/dist/core/config/types.js.map +0 -7
- package/dist/core/context/auto-context.js +0 -80
- package/dist/core/context/auto-context.js.map +0 -7
- package/dist/core/context/dual-stack-manager.js +0 -870
- package/dist/core/context/dual-stack-manager.js.map +0 -7
- package/dist/core/context/enhanced-rehydration.js +0 -994
- package/dist/core/context/enhanced-rehydration.js.map +0 -7
- package/dist/core/context/frame-database.js +0 -479
- package/dist/core/context/frame-database.js.map +0 -7
- package/dist/core/context/frame-digest.js +0 -250
- package/dist/core/context/frame-digest.js.map +0 -7
- package/dist/core/context/frame-handoff-manager.js +0 -778
- package/dist/core/context/frame-handoff-manager.js.map +0 -7
- package/dist/core/context/frame-lifecycle-hooks.js +0 -119
- package/dist/core/context/frame-lifecycle-hooks.js.map +0 -7
- package/dist/core/context/frame-manager.js +0 -1069
- package/dist/core/context/frame-manager.js.map +0 -7
- package/dist/core/context/frame-recovery.js +0 -302
- package/dist/core/context/frame-recovery.js.map +0 -7
- package/dist/core/context/frame-stack.js +0 -314
- package/dist/core/context/frame-stack.js.map +0 -7
- package/dist/core/context/frame-types.js +0 -5
- package/dist/core/context/frame-types.js.map +0 -7
- package/dist/core/context/incremental-gc.js +0 -290
- package/dist/core/context/incremental-gc.js.map +0 -7
- package/dist/core/context/index.js +0 -25
- package/dist/core/context/index.js.map +0 -7
- package/dist/core/context/model-aware-compaction.js +0 -623
- package/dist/core/context/model-aware-compaction.js.map +0 -7
- package/dist/core/context/permission-manager.js +0 -185
- package/dist/core/context/permission-manager.js.map +0 -7
- package/dist/core/context/recursive-context-manager.js +0 -592
- package/dist/core/context/recursive-context-manager.js.map +0 -7
- package/dist/core/context/refactored-frame-manager.js +0 -754
- package/dist/core/context/refactored-frame-manager.js.map +0 -7
- package/dist/core/context/shared-context-layer.js +0 -621
- package/dist/core/context/shared-context-layer.js.map +0 -7
- package/dist/core/context/stack-merge-resolver.js +0 -749
- package/dist/core/context/stack-merge-resolver.js.map +0 -7
- package/dist/core/context/validation.js +0 -130
- package/dist/core/context/validation.js.map +0 -7
- package/dist/core/database/batch-operations.js +0 -384
- package/dist/core/database/batch-operations.js.map +0 -7
- package/dist/core/database/connection-pool.js +0 -330
- package/dist/core/database/connection-pool.js.map +0 -7
- package/dist/core/database/database-adapter.js +0 -60
- package/dist/core/database/database-adapter.js.map +0 -7
- package/dist/core/database/migration-manager.js +0 -614
- package/dist/core/database/migration-manager.js.map +0 -7
- package/dist/core/database/paradedb-adapter.js +0 -990
- package/dist/core/database/paradedb-adapter.js.map +0 -7
- package/dist/core/database/query-cache.js +0 -298
- package/dist/core/database/query-cache.js.map +0 -7
- package/dist/core/database/query-router.js +0 -430
- package/dist/core/database/query-router.js.map +0 -7
- package/dist/core/database/sqlite-adapter.js +0 -738
- package/dist/core/database/sqlite-adapter.js.map +0 -7
- package/dist/core/digest/enhanced-hybrid-digest.js +0 -277
- package/dist/core/digest/enhanced-hybrid-digest.js.map +0 -7
- package/dist/core/digest/frame-digest-integration.js +0 -176
- package/dist/core/digest/frame-digest-integration.js.map +0 -7
- package/dist/core/digest/hybrid-digest-generator.js +0 -553
- package/dist/core/digest/hybrid-digest-generator.js.map +0 -7
- package/dist/core/digest/index.js +0 -9
- package/dist/core/digest/index.js.map +0 -7
- package/dist/core/digest/types.js +0 -25
- package/dist/core/digest/types.js.map +0 -7
- package/dist/core/errors/error-utils.js +0 -208
- package/dist/core/errors/error-utils.js.map +0 -7
- package/dist/core/errors/index.js +0 -521
- package/dist/core/errors/index.js.map +0 -7
- package/dist/core/errors/recovery.js +0 -269
- package/dist/core/errors/recovery.js.map +0 -7
- package/dist/core/execution/parallel-executor.js +0 -258
- package/dist/core/execution/parallel-executor.js.map +0 -7
- package/dist/core/frame/workflow-templates.js +0 -319
- package/dist/core/frame/workflow-templates.js.map +0 -7
- package/dist/core/merge/conflict-detector.js +0 -431
- package/dist/core/merge/conflict-detector.js.map +0 -7
- package/dist/core/merge/index.js +0 -9
- package/dist/core/merge/index.js.map +0 -7
- package/dist/core/merge/resolution-engine.js +0 -558
- package/dist/core/merge/resolution-engine.js.map +0 -7
- package/dist/core/merge/stack-diff.js +0 -532
- package/dist/core/merge/stack-diff.js.map +0 -7
- package/dist/core/merge/unified-merge-resolver.js +0 -303
- package/dist/core/merge/unified-merge-resolver.js.map +0 -7
- package/dist/core/models/fallback-monitor.js +0 -232
- package/dist/core/models/fallback-monitor.js.map +0 -7
- package/dist/core/models/model-router.js +0 -340
- package/dist/core/models/model-router.js.map +0 -7
- package/dist/core/monitoring/error-handler.js +0 -49
- package/dist/core/monitoring/error-handler.js.map +0 -7
- package/dist/core/monitoring/logger.js +0 -202
- package/dist/core/monitoring/logger.js.map +0 -7
- package/dist/core/monitoring/metrics.js +0 -172
- package/dist/core/monitoring/metrics.js.map +0 -7
- package/dist/core/monitoring/progress-tracker.js +0 -189
- package/dist/core/monitoring/progress-tracker.js.map +0 -7
- package/dist/core/monitoring/session-monitor.js +0 -300
- package/dist/core/monitoring/session-monitor.js.map +0 -7
- package/dist/core/performance/context-cache.js +0 -273
- package/dist/core/performance/context-cache.js.map +0 -7
- package/dist/core/performance/index.js +0 -11
- package/dist/core/performance/index.js.map +0 -7
- package/dist/core/performance/lazy-context-loader.js +0 -327
- package/dist/core/performance/lazy-context-loader.js.map +0 -7
- package/dist/core/performance/monitor.js +0 -221
- package/dist/core/performance/monitor.js.map +0 -7
- package/dist/core/performance/optimized-frame-context.js +0 -345
- package/dist/core/performance/optimized-frame-context.js.map +0 -7
- package/dist/core/performance/performance-benchmark.js +0 -277
- package/dist/core/performance/performance-benchmark.js.map +0 -7
- package/dist/core/performance/performance-profiler.js +0 -370
- package/dist/core/performance/performance-profiler.js.map +0 -7
- package/dist/core/performance/streaming-jsonl-parser.js +0 -195
- package/dist/core/performance/streaming-jsonl-parser.js.map +0 -7
- package/dist/core/persistence/postgres-adapter.js +0 -349
- package/dist/core/persistence/postgres-adapter.js.map +0 -7
- package/dist/core/projects/project-isolation.js +0 -201
- package/dist/core/projects/project-isolation.js.map +0 -7
- package/dist/core/projects/project-manager.js +0 -697
- package/dist/core/projects/project-manager.js.map +0 -7
- package/dist/core/query/query-parser.js +0 -370
- package/dist/core/query/query-parser.js.map +0 -7
- package/dist/core/query/query-templates.js +0 -321
- package/dist/core/query/query-templates.js.map +0 -7
- package/dist/core/retrieval/context-retriever.js +0 -479
- package/dist/core/retrieval/context-retriever.js.map +0 -7
- package/dist/core/retrieval/graph-retrieval.js +0 -662
- package/dist/core/retrieval/graph-retrieval.js.map +0 -7
- package/dist/core/retrieval/hierarchical-retrieval.js +0 -656
- package/dist/core/retrieval/hierarchical-retrieval.js.map +0 -7
- package/dist/core/retrieval/index.js +0 -8
- package/dist/core/retrieval/index.js.map +0 -7
- package/dist/core/retrieval/llm-context-retrieval.js +0 -613
- package/dist/core/retrieval/llm-context-retrieval.js.map +0 -7
- package/dist/core/retrieval/llm-provider.js +0 -151
- package/dist/core/retrieval/llm-provider.js.map +0 -7
- package/dist/core/retrieval/retrieval-audit.js +0 -236
- package/dist/core/retrieval/retrieval-audit.js.map +0 -7
- package/dist/core/retrieval/retrieval-benchmarks.js +0 -521
- package/dist/core/retrieval/retrieval-benchmarks.js.map +0 -7
- package/dist/core/retrieval/summary-generator.js +0 -589
- package/dist/core/retrieval/summary-generator.js.map +0 -7
- package/dist/core/retrieval/types.js +0 -21
- package/dist/core/retrieval/types.js.map +0 -7
- package/dist/core/security/index.js +0 -35
- package/dist/core/security/index.js.map +0 -7
- package/dist/core/security/input-sanitizer.js +0 -321
- package/dist/core/security/input-sanitizer.js.map +0 -7
- package/dist/core/session/clear-survival.js +0 -465
- package/dist/core/session/clear-survival.js.map +0 -7
- package/dist/core/session/enhanced-handoff.js +0 -792
- package/dist/core/session/enhanced-handoff.js.map +0 -7
- package/dist/core/session/handoff-generator.js +0 -343
- package/dist/core/session/handoff-generator.js.map +0 -7
- package/dist/core/session/index.js +0 -15
- package/dist/core/session/index.js.map +0 -7
- package/dist/core/session/session-manager.js +0 -347
- package/dist/core/session/session-manager.js.map +0 -7
- package/dist/core/skills/index.js +0 -7
- package/dist/core/skills/index.js.map +0 -7
- package/dist/core/skills/skill-storage.js +0 -764
- package/dist/core/skills/skill-storage.js.map +0 -7
- package/dist/core/skills/types.js +0 -193
- package/dist/core/skills/types.js.map +0 -7
- package/dist/core/storage/chromadb-adapter.js +0 -354
- package/dist/core/storage/chromadb-adapter.js.map +0 -7
- package/dist/core/storage/infinite-storage.js +0 -510
- package/dist/core/storage/infinite-storage.js.map +0 -7
- package/dist/core/storage/railway-optimized-storage.js +0 -591
- package/dist/core/storage/railway-optimized-storage.js.map +0 -7
- package/dist/core/storage/remote-storage.js +0 -489
- package/dist/core/storage/remote-storage.js.map +0 -7
- package/dist/core/storage/two-tier-storage.js +0 -766
- package/dist/core/storage/two-tier-storage.js.map +0 -7
- package/dist/core/trace/cli-trace-wrapper.js +0 -132
- package/dist/core/trace/cli-trace-wrapper.js.map +0 -7
- package/dist/core/trace/db-trace-wrapper.js +0 -247
- package/dist/core/trace/db-trace-wrapper.js.map +0 -7
- package/dist/core/trace/debug-trace.js +0 -417
- package/dist/core/trace/debug-trace.js.map +0 -7
- package/dist/core/trace/index.js +0 -109
- package/dist/core/trace/index.js.map +0 -7
- package/dist/core/trace/linear-api-wrapper.js +0 -178
- package/dist/core/trace/linear-api-wrapper.js.map +0 -7
- package/dist/core/trace/trace-demo.js +0 -154
- package/dist/core/trace/trace-demo.js.map +0 -7
- package/dist/core/trace/trace-detector.demo.js +0 -142
- package/dist/core/trace/trace-detector.demo.js.map +0 -7
- package/dist/core/trace/trace-detector.js +0 -528
- package/dist/core/trace/trace-detector.js.map +0 -7
- package/dist/core/trace/trace-store.js +0 -345
- package/dist/core/trace/trace-store.js.map +0 -7
- package/dist/core/trace/types.js +0 -77
- package/dist/core/trace/types.js.map +0 -7
- package/dist/core/types.js +0 -5
- package/dist/core/types.js.map +0 -7
- package/dist/core/utils/async-mutex.js +0 -114
- package/dist/core/utils/async-mutex.js.map +0 -7
- package/dist/core/utils/compression.js +0 -83
- package/dist/core/utils/compression.js.map +0 -7
- package/dist/core/utils/update-checker.js +0 -218
- package/dist/core/utils/update-checker.js.map +0 -7
- package/dist/core/worktree/worktree-manager.js +0 -465
- package/dist/core/worktree/worktree-manager.js.map +0 -7
- package/dist/daemon/daemon-config.js +0 -149
- package/dist/daemon/daemon-config.js.map +0 -7
- package/dist/daemon/services/context-service.js +0 -122
- package/dist/daemon/services/context-service.js.map +0 -7
- package/dist/daemon/services/linear-service.js +0 -136
- package/dist/daemon/services/linear-service.js.map +0 -7
- package/dist/daemon/session-daemon.js +0 -312
- package/dist/daemon/session-daemon.js.map +0 -7
- package/dist/daemon/unified-daemon.js +0 -276
- package/dist/daemon/unified-daemon.js.map +0 -7
- package/dist/features/analytics/api/analytics-api.js +0 -287
- package/dist/features/analytics/api/analytics-api.js.map +0 -7
- package/dist/features/analytics/core/analytics-service.js +0 -282
- package/dist/features/analytics/core/analytics-service.js.map +0 -7
- package/dist/features/analytics/index.js +0 -18
- package/dist/features/analytics/index.js.map +0 -7
- package/dist/features/analytics/queries/metrics-queries.js +0 -277
- package/dist/features/analytics/queries/metrics-queries.js.map +0 -7
- package/dist/features/analytics/types/metrics.js +0 -5
- package/dist/features/analytics/types/metrics.js.map +0 -7
- package/dist/features/browser/browser-mcp.js +0 -492
- package/dist/features/browser/browser-mcp.js.map +0 -7
- package/dist/features/sweep/index.js +0 -20
- package/dist/features/sweep/index.js.map +0 -7
- package/dist/features/sweep/prediction-client.js +0 -155
- package/dist/features/sweep/prediction-client.js.map +0 -7
- package/dist/features/sweep/prompt-builder.js +0 -85
- package/dist/features/sweep/prompt-builder.js.map +0 -7
- package/dist/features/sweep/pty-wrapper.js +0 -171
- package/dist/features/sweep/pty-wrapper.js.map +0 -7
- package/dist/features/sweep/state-watcher.js +0 -87
- package/dist/features/sweep/state-watcher.js.map +0 -7
- package/dist/features/sweep/status-bar.js +0 -88
- package/dist/features/sweep/status-bar.js.map +0 -7
- package/dist/features/sweep/sweep-server-manager.js +0 -226
- package/dist/features/sweep/sweep-server-manager.js.map +0 -7
- package/dist/features/sweep/tab-interceptor.js +0 -38
- package/dist/features/sweep/tab-interceptor.js.map +0 -7
- package/dist/features/sweep/types.js +0 -18
- package/dist/features/sweep/types.js.map +0 -7
- package/dist/features/tasks/linear-task-manager.js +0 -487
- package/dist/features/tasks/linear-task-manager.js.map +0 -7
- package/dist/features/tasks/task-aware-context.js +0 -410
- package/dist/features/tasks/task-aware-context.js.map +0 -7
- package/dist/features/tui/simple-monitor.js +0 -116
- package/dist/features/tui/simple-monitor.js.map +0 -7
- package/dist/features/tui/swarm-monitor.js +0 -648
- package/dist/features/tui/swarm-monitor.js.map +0 -7
- package/dist/features/web/client/stores/task-store.js +0 -26
- package/dist/features/web/client/stores/task-store.js.map +0 -7
- package/dist/features/web/server/index.js +0 -194
- package/dist/features/web/server/index.js.map +0 -7
- package/dist/hooks/auto-background.js +0 -151
- package/dist/hooks/auto-background.js.map +0 -7
- package/dist/hooks/claude-code-whatsapp-hook.js +0 -197
- package/dist/hooks/claude-code-whatsapp-hook.js.map +0 -7
- package/dist/hooks/config.js +0 -150
- package/dist/hooks/config.js.map +0 -7
- package/dist/hooks/daemon.js +0 -364
- package/dist/hooks/daemon.js.map +0 -7
- package/dist/hooks/events.js +0 -58
- package/dist/hooks/events.js.map +0 -7
- package/dist/hooks/index.js +0 -12
- package/dist/hooks/index.js.map +0 -7
- package/dist/hooks/linear-task-picker.js +0 -186
- package/dist/hooks/linear-task-picker.js.map +0 -7
- package/dist/hooks/schemas.js +0 -197
- package/dist/hooks/schemas.js.map +0 -7
- package/dist/hooks/secure-fs.js +0 -49
- package/dist/hooks/secure-fs.js.map +0 -7
- package/dist/hooks/security-logger.js +0 -155
- package/dist/hooks/security-logger.js.map +0 -7
- package/dist/hooks/session-summary.js +0 -222
- package/dist/hooks/session-summary.js.map +0 -7
- package/dist/hooks/sms-action-runner.js +0 -371
- package/dist/hooks/sms-action-runner.js.map +0 -7
- package/dist/hooks/sms-notify.js +0 -506
- package/dist/hooks/sms-notify.js.map +0 -7
- package/dist/hooks/sms-watcher.js +0 -93
- package/dist/hooks/sms-watcher.js.map +0 -7
- package/dist/hooks/sms-webhook.js +0 -555
- package/dist/hooks/sms-webhook.js.map +0 -7
- package/dist/hooks/whatsapp-commands.js +0 -479
- package/dist/hooks/whatsapp-commands.js.map +0 -7
- package/dist/hooks/whatsapp-scheduler.js +0 -317
- package/dist/hooks/whatsapp-scheduler.js.map +0 -7
- package/dist/hooks/whatsapp-sync.js +0 -409
- package/dist/hooks/whatsapp-sync.js.map +0 -7
- package/dist/index.js +0 -25
- package/dist/index.js.map +0 -7
- package/dist/integrations/anthropic/client.js +0 -263
- package/dist/integrations/anthropic/client.js.map +0 -7
- package/dist/integrations/claude-code/agent-bridge.js +0 -768
- package/dist/integrations/claude-code/agent-bridge.js.map +0 -7
- package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -459
- package/dist/integrations/claude-code/enhanced-pre-clear-hooks.js.map +0 -7
- package/dist/integrations/claude-code/lifecycle-hooks.js +0 -254
- package/dist/integrations/claude-code/lifecycle-hooks.js.map +0 -7
- package/dist/integrations/claude-code/post-task-hooks.js +0 -545
- package/dist/integrations/claude-code/post-task-hooks.js.map +0 -7
- package/dist/integrations/claude-code/subagent-client-stub.js +0 -20
- package/dist/integrations/claude-code/subagent-client-stub.js.map +0 -7
- package/dist/integrations/claude-code/subagent-client.js +0 -511
- package/dist/integrations/claude-code/subagent-client.js.map +0 -7
- package/dist/integrations/claude-code/task-coordinator.js +0 -360
- package/dist/integrations/claude-code/task-coordinator.js.map +0 -7
- package/dist/integrations/linear/auth.js +0 -337
- package/dist/integrations/linear/auth.js.map +0 -7
- package/dist/integrations/linear/auto-sync.js +0 -258
- package/dist/integrations/linear/auto-sync.js.map +0 -7
- package/dist/integrations/linear/client.js +0 -634
- package/dist/integrations/linear/client.js.map +0 -7
- package/dist/integrations/linear/config.js +0 -130
- package/dist/integrations/linear/config.js.map +0 -7
- package/dist/integrations/linear/migration.js +0 -361
- package/dist/integrations/linear/migration.js.map +0 -7
- package/dist/integrations/linear/oauth-server.js +0 -454
- package/dist/integrations/linear/oauth-server.js.map +0 -7
- package/dist/integrations/linear/rest-client.js +0 -213
- package/dist/integrations/linear/rest-client.js.map +0 -7
- package/dist/integrations/linear/sync-manager.js +0 -236
- package/dist/integrations/linear/sync-manager.js.map +0 -7
- package/dist/integrations/linear/sync-service.js +0 -231
- package/dist/integrations/linear/sync-service.js.map +0 -7
- package/dist/integrations/linear/sync.js +0 -782
- package/dist/integrations/linear/sync.js.map +0 -7
- package/dist/integrations/linear/types.js +0 -5
- package/dist/integrations/linear/types.js.map +0 -7
- package/dist/integrations/linear/unified-sync.js +0 -589
- package/dist/integrations/linear/unified-sync.js.map +0 -7
- package/dist/integrations/linear/webhook-handler.js +0 -219
- package/dist/integrations/linear/webhook-handler.js.map +0 -7
- package/dist/integrations/linear/webhook-server.js +0 -218
- package/dist/integrations/linear/webhook-server.js.map +0 -7
- package/dist/integrations/linear/webhook.js +0 -291
- package/dist/integrations/linear/webhook.js.map +0 -7
- package/dist/integrations/mcp/handlers/code-execution-handlers.js +0 -266
- package/dist/integrations/mcp/handlers/code-execution-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/context-handlers.js +0 -257
- package/dist/integrations/mcp/handlers/context-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/discovery-handlers.js +0 -497
- package/dist/integrations/mcp/handlers/discovery-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/index.js +0 -166
- package/dist/integrations/mcp/handlers/index.js.map +0 -7
- package/dist/integrations/mcp/handlers/linear-handlers.js +0 -247
- package/dist/integrations/mcp/handlers/linear-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/skill-handlers.js +0 -529
- package/dist/integrations/mcp/handlers/skill-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/task-handlers.js +0 -239
- package/dist/integrations/mcp/handlers/task-handlers.js.map +0 -7
- package/dist/integrations/mcp/handlers/trace-handlers.js +0 -308
- package/dist/integrations/mcp/handlers/trace-handlers.js.map +0 -7
- package/dist/integrations/mcp/index.js +0 -23
- package/dist/integrations/mcp/index.js.map +0 -7
- package/dist/integrations/mcp/middleware/tool-scoring.js +0 -356
- package/dist/integrations/mcp/middleware/tool-scoring.js.map +0 -7
- package/dist/integrations/mcp/refactored-server.js +0 -374
- package/dist/integrations/mcp/refactored-server.js.map +0 -7
- package/dist/integrations/mcp/remote-server.js +0 -682
- package/dist/integrations/mcp/remote-server.js.map +0 -7
- package/dist/integrations/mcp/schemas.js +0 -147
- package/dist/integrations/mcp/schemas.js.map +0 -7
- package/dist/integrations/mcp/server.js +0 -1975
- package/dist/integrations/mcp/server.js.map +0 -7
- package/dist/integrations/mcp/tool-definitions-code.js +0 -125
- package/dist/integrations/mcp/tool-definitions-code.js.map +0 -7
- package/dist/integrations/mcp/tool-definitions.js +0 -702
- package/dist/integrations/mcp/tool-definitions.js.map +0 -7
- package/dist/integrations/mcp/trace-test.js +0 -48
- package/dist/integrations/mcp/trace-test.js.map +0 -7
- package/dist/integrations/pg-aiguide/embedding-provider.js +0 -189
- package/dist/integrations/pg-aiguide/embedding-provider.js.map +0 -7
- package/dist/integrations/pg-aiguide/semantic-search.js +0 -187
- package/dist/integrations/pg-aiguide/semantic-search.js.map +0 -7
- package/dist/integrations/pg-aiguide/timescale-analytics.js +0 -224
- package/dist/integrations/pg-aiguide/timescale-analytics.js.map +0 -7
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -860
- package/dist/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +0 -7
- package/dist/integrations/ralph/context/context-budget-manager.js +0 -301
- package/dist/integrations/ralph/context/context-budget-manager.js.map +0 -7
- package/dist/integrations/ralph/context/stackmemory-context-loader.js +0 -360
- package/dist/integrations/ralph/context/stackmemory-context-loader.js.map +0 -7
- package/dist/integrations/ralph/coordination/enhanced-coordination.js +0 -410
- package/dist/integrations/ralph/coordination/enhanced-coordination.js.map +0 -7
- package/dist/integrations/ralph/index.js +0 -18
- package/dist/integrations/ralph/index.js.map +0 -7
- package/dist/integrations/ralph/learning/pattern-learner.js +0 -401
- package/dist/integrations/ralph/learning/pattern-learner.js.map +0 -7
- package/dist/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/integrations/ralph/lifecycle/iteration-lifecycle.js.map +0 -7
- package/dist/integrations/ralph/monitoring/swarm-dashboard.js +0 -294
- package/dist/integrations/ralph/monitoring/swarm-dashboard.js.map +0 -7
- package/dist/integrations/ralph/monitoring/swarm-registry.js +0 -108
- package/dist/integrations/ralph/monitoring/swarm-registry.js.map +0 -7
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -463
- package/dist/integrations/ralph/orchestration/multi-loop-orchestrator.js.map +0 -7
- package/dist/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -400
- package/dist/integrations/ralph/patterns/compounding-engineering-pattern.js.map +0 -7
- package/dist/integrations/ralph/patterns/extended-coherence-sessions.js +0 -473
- package/dist/integrations/ralph/patterns/extended-coherence-sessions.js.map +0 -7
- package/dist/integrations/ralph/patterns/oracle-worker-pattern.js +0 -388
- package/dist/integrations/ralph/patterns/oracle-worker-pattern.js.map +0 -7
- package/dist/integrations/ralph/performance/performance-optimizer.js +0 -358
- package/dist/integrations/ralph/performance/performance-optimizer.js.map +0 -7
- package/dist/integrations/ralph/ralph-integration-demo.js +0 -182
- package/dist/integrations/ralph/ralph-integration-demo.js.map +0 -7
- package/dist/integrations/ralph/recovery/crash-recovery.js +0 -462
- package/dist/integrations/ralph/recovery/crash-recovery.js.map +0 -7
- package/dist/integrations/ralph/state/state-reconciler.js +0 -404
- package/dist/integrations/ralph/state/state-reconciler.js.map +0 -7
- package/dist/integrations/ralph/swarm/git-workflow-manager.js +0 -428
- package/dist/integrations/ralph/swarm/git-workflow-manager.js.map +0 -7
- package/dist/integrations/ralph/swarm/swarm-coordinator.js +0 -996
- package/dist/integrations/ralph/swarm/swarm-coordinator.js.map +0 -7
- package/dist/integrations/ralph/types.js +0 -5
- package/dist/integrations/ralph/types.js.map +0 -7
- package/dist/integrations/ralph/visualization/ralph-debugger.js +0 -585
- package/dist/integrations/ralph/visualization/ralph-debugger.js.map +0 -7
- package/dist/mcp/stackmemory-mcp-server.js +0 -554
- package/dist/mcp/stackmemory-mcp-server.js.map +0 -7
- package/dist/middleware/exponential-rate-limiter.js +0 -289
- package/dist/middleware/exponential-rate-limiter.js.map +0 -7
- package/dist/models/user.model.js +0 -358
- package/dist/models/user.model.js.map +0 -7
- package/dist/servers/production/auth-middleware.js +0 -528
- package/dist/servers/production/auth-middleware.js.map +0 -7
- package/dist/servers/railway/config.js +0 -55
- package/dist/servers/railway/config.js.map +0 -7
- package/dist/servers/railway/index-enhanced.js +0 -160
- package/dist/servers/railway/index-enhanced.js.map +0 -7
- package/dist/servers/railway/index.js +0 -1349
- package/dist/servers/railway/index.js.map +0 -7
- package/dist/servers/railway/simple.js +0 -64
- package/dist/servers/railway/simple.js.map +0 -7
- package/dist/servers/railway/storage-test.js +0 -459
- package/dist/servers/railway/storage-test.js.map +0 -7
- package/dist/services/config-service.js +0 -65
- package/dist/services/config-service.js.map +0 -7
- package/dist/services/context-service.js +0 -194
- package/dist/services/context-service.js.map +0 -7
- package/dist/skills/api-discovery.js +0 -354
- package/dist/skills/api-discovery.js.map +0 -7
- package/dist/skills/api-skill.js +0 -475
- package/dist/skills/api-skill.js.map +0 -7
- package/dist/skills/claude-skills.js +0 -1061
- package/dist/skills/claude-skills.js.map +0 -7
- package/dist/skills/dashboard-launcher.js +0 -216
- package/dist/skills/dashboard-launcher.js.map +0 -7
- package/dist/skills/recursive-agent-orchestrator.js +0 -575
- package/dist/skills/recursive-agent-orchestrator.js.map +0 -7
- package/dist/skills/repo-ingestion-skill.js +0 -609
- package/dist/skills/repo-ingestion-skill.js.map +0 -7
- package/dist/skills/security-secrets-scanner.js +0 -284
- package/dist/skills/security-secrets-scanner.js.map +0 -7
- package/dist/skills/unified-rlm-orchestrator.js +0 -404
- package/dist/skills/unified-rlm-orchestrator.js.map +0 -7
- package/dist/types/task.js +0 -5
- package/dist/types/task.js.map +0 -7
- package/dist/utils/env.js +0 -50
- package/dist/utils/env.js.map +0 -7
- package/dist/utils/formatting.js +0 -62
- package/dist/utils/formatting.js.map +0 -7
- package/dist/utils/process-cleanup.js +0 -136
- package/dist/utils/process-cleanup.js.map +0 -7
- package/dist/validation/schemas.js +0 -222
- package/dist/validation/schemas.js.map +0 -7
- /package/dist/{core/merge → src/core/extensions}/types.js +0 -0
- /package/dist/{core/merge → src/core/extensions}/types.js.map +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/hooks/sms-webhook.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * SMS Webhook Handler for receiving Twilio responses\n * Can run as standalone server or integrate with existing Express app\n *\n * Security features:\n * - Twilio signature verification\n * - Rate limiting per IP\n * - Body size limits\n * - Content-type validation\n * - Safe action execution (no shell injection)\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport { parse as parseUrl } from 'url';\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { createHmac } from 'crypto';\nimport { execFileSync } from 'child_process';\nimport {\n processIncomingResponse,\n loadSMSConfig,\n cleanupExpiredPrompts,\n sendNotification,\n} from './sms-notify.js';\nimport {\n queueAction,\n executeActionSafe,\n cleanupOldActions,\n type ActionResult,\n} from './sms-action-runner.js';\nimport {\n isCommand,\n processCommand,\n sendCommandResponse,\n} from './whatsapp-commands.js';\nimport { writeFileSecure, ensureSecureDir } from './secure-fs.js';\nimport {\n logWebhookRequest,\n logRateLimit,\n logSignatureInvalid,\n logBodyTooLarge,\n logContentTypeInvalid,\n logActionAllowed,\n logActionBlocked,\n logCleanup,\n} from './security-logger.js';\n\n// Cleanup interval (5 minutes)\nconst CLEANUP_INTERVAL_MS = 5 * 60 * 1000;\n\n// Input validation constants\nconst MAX_SMS_BODY_LENGTH = 1000;\nconst MAX_PHONE_LENGTH = 50; // WhatsApp format: whatsapp:+12345678901\n\n// Security constants\nconst MAX_BODY_SIZE = 50 * 1024; // 50KB max body\nconst RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute\nconst RATE_LIMIT_MAX_REQUESTS = 30; // 30 requests per minute per IP\nconst ACTION_TIMEOUT_MS = 60000; // 60 second timeout for action execution\n\n/**\n * Execute action with timeout to prevent hanging requests\n */\nasync function executeActionWithTimeout(\n action: string,\n response: string\n): Promise<ActionResult> {\n return Promise.race([\n executeActionSafe(action, response),\n new Promise<ActionResult>((_, reject) =>\n setTimeout(\n () =>\n reject(new Error(`Action timed out after ${ACTION_TIMEOUT_MS}ms`)),\n ACTION_TIMEOUT_MS\n )\n ),\n ]).catch((error) => ({\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }));\n}\n\n// Rate limiting store - persisted to disk to survive restarts\nconst RATE_LIMIT_PATH = join(homedir(), '.stackmemory', 'rate-limits.json');\n\ninterface RateLimitRecord {\n count: number;\n resetTime: number;\n}\n\ninterface RateLimitStore {\n [ip: string]: RateLimitRecord;\n}\n\n// In-memory cache with periodic persistence\nlet rateLimitCache: RateLimitStore = {};\nlet rateLimitCacheDirty = false;\n\nfunction loadRateLimits(): RateLimitStore {\n try {\n if (existsSync(RATE_LIMIT_PATH)) {\n const data = JSON.parse(readFileSync(RATE_LIMIT_PATH, 'utf8'));\n // Clean up expired entries on load\n const now = Date.now();\n const cleaned: RateLimitStore = {};\n for (const [ip, record] of Object.entries(data)) {\n const r = record as RateLimitRecord;\n if (r.resetTime > now) {\n cleaned[ip] = r;\n }\n }\n return cleaned;\n }\n } catch {\n // Use empty store on error\n }\n return {};\n}\n\nfunction saveRateLimits(): void {\n if (!rateLimitCacheDirty) return;\n try {\n ensureSecureDir(join(homedir(), '.stackmemory'));\n writeFileSecure(RATE_LIMIT_PATH, JSON.stringify(rateLimitCache));\n rateLimitCacheDirty = false;\n } catch {\n // Ignore save errors - rate limiting is best-effort\n }\n}\n\n// Persist rate limits periodically (every 30 seconds)\nsetInterval(saveRateLimits, 30000);\n\n// Load on startup\nrateLimitCache = loadRateLimits();\n\nfunction checkRateLimit(ip: string): boolean {\n const now = Date.now();\n const record = rateLimitCache[ip];\n\n if (!record || now > record.resetTime) {\n rateLimitCache[ip] = { count: 1, resetTime: now + RATE_LIMIT_WINDOW_MS };\n rateLimitCacheDirty = true;\n return true;\n }\n\n if (record.count >= RATE_LIMIT_MAX_REQUESTS) {\n return false;\n }\n\n record.count++;\n rateLimitCacheDirty = true;\n return true;\n}\n\n// Twilio signature verification\nfunction verifyTwilioSignature(\n url: string,\n params: Record<string, string>,\n signature: string\n): boolean {\n const authToken = process.env['TWILIO_AUTH_TOKEN'];\n if (!authToken) {\n // Only allow bypass in explicit development mode\n const isDev =\n process.env['NODE_ENV'] === 'development' ||\n process.env['SKIP_TWILIO_VERIFICATION'] === 'true';\n\n if (isDev) {\n console.warn(\n '[sms-webhook] TWILIO_AUTH_TOKEN not set, skipping verification (dev mode)'\n );\n return true;\n }\n\n // In production, reject requests without auth token configured\n console.error(\n '[sms-webhook] TWILIO_AUTH_TOKEN not set - rejecting request in production'\n );\n return false;\n }\n\n // Build the data string (URL + sorted params)\n const sortedKeys = Object.keys(params).sort();\n let data = url;\n for (const key of sortedKeys) {\n data += key + params[key];\n }\n\n // Calculate expected signature\n const hmac = createHmac('sha1', authToken);\n hmac.update(data);\n const expectedSignature = hmac.digest('base64');\n\n return signature === expectedSignature;\n}\n\ninterface TwilioWebhookPayload {\n From: string;\n To: string;\n Body: string;\n MessageSid: string;\n}\n\nfunction parseFormData(body: string): Record<string, string> {\n const params = new URLSearchParams(body);\n const result: Record<string, string> = {};\n params.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n\n// Store response for Claude hook to pick up\nfunction storeLatestResponse(\n promptId: string,\n response: string,\n action?: string\n): void {\n ensureSecureDir(join(homedir(), '.stackmemory'));\n const responsePath = join(\n homedir(),\n '.stackmemory',\n 'sms-latest-response.json'\n );\n writeFileSecure(\n responsePath,\n JSON.stringify({\n promptId,\n response,\n action,\n timestamp: new Date().toISOString(),\n })\n );\n}\n\n/**\n * Store incoming request for Claude to pick up\n * Used when a WhatsApp/SMS message arrives without a pending prompt\n */\nfunction storeIncomingRequest(from: string, message: string): void {\n ensureSecureDir(join(homedir(), '.stackmemory'));\n const requestPath = join(\n homedir(),\n '.stackmemory',\n 'sms-incoming-request.json'\n );\n writeFileSecure(\n requestPath,\n JSON.stringify({\n from,\n message,\n timestamp: new Date().toISOString(),\n processed: false,\n })\n );\n}\n\n/**\n * Get pending incoming request (if any)\n */\nexport function getIncomingRequest(): {\n from: string;\n message: string;\n timestamp: string;\n processed: boolean;\n} | null {\n const requestPath = join(\n homedir(),\n '.stackmemory',\n 'sms-incoming-request.json'\n );\n if (!existsSync(requestPath)) {\n return null;\n }\n try {\n const data = JSON.parse(readFileSync(requestPath, 'utf-8'));\n if (data.processed) {\n return null;\n }\n return data;\n } catch {\n return null;\n }\n}\n\n/**\n * Mark incoming request as processed\n */\nexport function markRequestProcessed(): void {\n const requestPath = join(\n homedir(),\n '.stackmemory',\n 'sms-incoming-request.json'\n );\n if (!existsSync(requestPath)) {\n return;\n }\n try {\n const data = JSON.parse(readFileSync(requestPath, 'utf-8'));\n data.processed = true;\n writeFileSecure(requestPath, JSON.stringify(data));\n } catch {\n // Ignore errors\n }\n}\n\nexport async function handleSMSWebhook(payload: TwilioWebhookPayload): Promise<{\n response: string;\n action?: string;\n queued?: boolean;\n}> {\n const { From, Body } = payload;\n\n // Input length validation\n if (Body && Body.length > MAX_SMS_BODY_LENGTH) {\n console.log(`[sms-webhook] Body too long: ${Body.length} chars`);\n return { response: 'Message too long. Max 1000 characters.' };\n }\n\n if (From && From.length > MAX_PHONE_LENGTH) {\n console.log(\n `[sms-webhook] Phone number too long: ${From.length} chars (max ${MAX_PHONE_LENGTH}): ${From.substring(0, 30)}...`\n );\n return { response: 'Invalid phone number.' };\n }\n\n console.log(`[sms-webhook] Received from ${From}: ${Body}`);\n\n // Check for command prefix before prompt matching\n if (isCommand(Body)) {\n console.log(`[sms-webhook] Processing command: ${Body}`);\n const cmdResult = await processCommand(From, Body);\n\n if (cmdResult.handled) {\n // Send response back if we have one\n if (cmdResult.response) {\n // Don't await - fire and forget the response notification\n sendCommandResponse(cmdResult.response).catch(console.error);\n }\n\n return {\n response: cmdResult.response || 'Command processed',\n action: cmdResult.action,\n queued: false,\n };\n }\n // If not handled, fall through to regular prompt matching\n }\n\n const result = processIncomingResponse(From, Body);\n\n if (!result.matched) {\n if (result.prompt) {\n return {\n response: `Invalid response. Expected: ${result.prompt.options.map((o) => o.key).join(', ')}`,\n };\n }\n // No pending prompt - store as new incoming request for Claude\n storeIncomingRequest(From, Body);\n console.log(\n `[sms-webhook] Stored new request from ${From}: ${Body.substring(0, 50)}...`\n );\n return { response: 'Got it! Your request has been queued.' };\n }\n\n // Store response for Claude hook\n storeLatestResponse(\n result.prompt?.id || 'unknown',\n result.response || Body,\n result.action\n );\n\n // Trigger notification to alert user/Claude\n triggerResponseNotification(result.response || Body);\n\n // Execute action safely if present (no shell injection, with timeout)\n if (result.action) {\n console.log(`[sms-webhook] Executing action: ${result.action}`);\n\n const actionResult = await executeActionWithTimeout(\n result.action,\n result.response || Body\n );\n\n if (actionResult.success) {\n logActionAllowed('sms-webhook', result.action);\n console.log(\n `[sms-webhook] Action completed: ${(actionResult.output || '').substring(0, 200)}`\n );\n\n return {\n response: `Done! Action executed successfully.`,\n action: result.action,\n queued: false,\n };\n } else {\n logActionBlocked(\n 'sms-webhook',\n result.action,\n actionResult.error || 'unknown'\n );\n console.log(`[sms-webhook] Action failed: ${actionResult.error}`);\n\n // Queue for retry\n queueAction(\n result.prompt?.id || 'unknown',\n result.response || Body,\n result.action\n );\n\n return {\n response: `Action failed, queued for retry: ${(actionResult.error || '').substring(0, 50)}`,\n action: result.action,\n queued: true,\n };\n }\n }\n\n return {\n response: `Received: ${result.response}. Next action will be triggered.`,\n };\n}\n\n// Escape string for AppleScript (prevent injection)\nfunction escapeAppleScript(str: string): string {\n return str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .substring(0, 200); // Limit length\n}\n\n// Trigger notification when response received\nfunction triggerResponseNotification(response: string): void {\n const safeMessage = escapeAppleScript(`SMS Response: ${response}`);\n\n // macOS notification using execFile (safer than execSync with shell)\n try {\n execFileSync(\n 'osascript',\n [\n '-e',\n `display notification \"${safeMessage}\" with title \"StackMemory\" sound name \"Glass\"`,\n ],\n { stdio: 'ignore', timeout: 5000 }\n );\n } catch {\n // Ignore if not on macOS\n }\n\n // Write signal file for other processes\n try {\n const signalPath = join(homedir(), '.stackmemory', 'sms-signal.txt');\n writeFileSecure(\n signalPath,\n JSON.stringify({\n type: 'sms_response',\n response,\n timestamp: new Date().toISOString(),\n })\n );\n } catch {\n // Ignore\n }\n\n console.log(`\\n*** SMS RESPONSE RECEIVED: \"${response}\" ***`);\n console.log(`*** Run: stackmemory notify run-actions ***\\n`);\n}\n\n// TwiML response helper\nfunction twimlResponse(message: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Message>${escapeXml(message)}</Message>\n</Response>`;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// Standalone webhook server\nexport function startWebhookServer(port: number = 3456): void {\n const server = createServer(\n async (req: IncomingMessage, res: ServerResponse) => {\n const url = parseUrl(req.url || '/', true);\n\n // Health check\n if (url.pathname === '/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n // SMS webhook endpoint (incoming messages)\n if (\n (url.pathname === '/sms' ||\n url.pathname === '/sms/incoming' ||\n url.pathname === '/webhook') &&\n req.method === 'POST'\n ) {\n const clientIp = req.socket.remoteAddress || 'unknown';\n\n // Log webhook request\n logWebhookRequest(\n 'sms-webhook',\n req.method || 'POST',\n url.pathname || '/sms',\n clientIp\n );\n\n // Rate limiting\n if (!checkRateLimit(clientIp)) {\n logRateLimit('sms-webhook', clientIp);\n res.writeHead(429, {\n 'Content-Type': 'text/xml',\n 'Retry-After': '60',\n });\n res.end(twimlResponse('Too many requests. Please try again later.'));\n return;\n }\n\n // Content-type validation\n const contentType = req.headers['content-type'] || '';\n if (!contentType.includes('application/x-www-form-urlencoded')) {\n logContentTypeInvalid('sms-webhook', contentType, clientIp);\n res.writeHead(400, { 'Content-Type': 'text/xml' });\n res.end(twimlResponse('Invalid content type'));\n return;\n }\n\n let body = '';\n let bodyTooLarge = false;\n\n req.on('data', (chunk) => {\n body += chunk;\n // Body size limit\n if (body.length > MAX_BODY_SIZE) {\n bodyTooLarge = true;\n logBodyTooLarge('sms-webhook', body.length, clientIp);\n req.destroy();\n }\n });\n\n req.on('end', async () => {\n if (bodyTooLarge) {\n res.writeHead(413, { 'Content-Type': 'text/xml' });\n res.end(twimlResponse('Request too large'));\n return;\n }\n\n try {\n const payload = parseFormData(\n body\n ) as unknown as TwilioWebhookPayload;\n\n // Verify Twilio signature\n const twilioSignature = req.headers['x-twilio-signature'] as string;\n const webhookUrl = `${req.headers['x-forwarded-proto'] || 'http'}://${req.headers.host}${req.url}`;\n\n if (\n twilioSignature &&\n !verifyTwilioSignature(\n webhookUrl,\n payload as unknown as Record<string, string>,\n twilioSignature\n )\n ) {\n logSignatureInvalid('sms-webhook', clientIp);\n console.error('[sms-webhook] Invalid Twilio signature');\n res.writeHead(401, { 'Content-Type': 'text/xml' });\n res.end(twimlResponse('Unauthorized'));\n return;\n }\n\n const result = await handleSMSWebhook(payload);\n\n res.writeHead(200, { 'Content-Type': 'text/xml' });\n res.end(twimlResponse(result.response));\n } catch (err) {\n console.error('[sms-webhook] Error:', err);\n res.writeHead(500, { 'Content-Type': 'text/xml' });\n res.end(twimlResponse('Error processing message'));\n }\n });\n return;\n }\n\n // Status callback endpoint (delivery status updates)\n if (url.pathname === '/sms/status' && req.method === 'POST') {\n let body = '';\n req.on('data', (chunk) => {\n body += chunk;\n });\n\n req.on('end', () => {\n try {\n const payload = parseFormData(body);\n console.log(\n `[sms-webhook] Status update: ${payload['MessageSid']} -> ${payload['MessageStatus']}`\n );\n\n // Store status for tracking\n const statusPath = join(\n homedir(),\n '.stackmemory',\n 'sms-status.json'\n );\n const statuses: Record<string, string> = existsSync(statusPath)\n ? JSON.parse(readFileSync(statusPath, 'utf8'))\n : {};\n statuses[payload['MessageSid']] = payload['MessageStatus'];\n writeFileSecure(statusPath, JSON.stringify(statuses, null, 2));\n\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end('OK');\n } catch (err) {\n console.error('[sms-webhook] Status error:', err);\n res.writeHead(500);\n res.end('Error');\n }\n });\n return;\n }\n\n // Server status endpoint\n if (url.pathname === '/status') {\n const config = loadSMSConfig();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n enabled: config.enabled,\n pendingPrompts: config.pendingPrompts.length,\n })\n );\n return;\n }\n\n // Get pending incoming request endpoint\n if (url.pathname === '/request' && req.method === 'GET') {\n const request = getIncomingRequest();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ request }));\n return;\n }\n\n // Mark request as processed endpoint\n if (url.pathname === '/request/ack' && req.method === 'POST') {\n markRequestProcessed();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ success: true }));\n return;\n }\n\n // Send outgoing notification endpoint\n if (url.pathname === '/send' && req.method === 'POST') {\n let body = '';\n req.on('data', (chunk) => {\n body += chunk;\n if (body.length > MAX_BODY_SIZE) {\n req.destroy();\n }\n });\n\n req.on('end', async () => {\n try {\n const payload = JSON.parse(body);\n const message = payload.message || payload.body || '';\n const title = payload.title || 'Notification';\n const type = payload.type || 'custom';\n\n if (!message) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ success: false, error: 'Message required' })\n );\n return;\n }\n\n const result = await sendNotification({\n type: type as\n | 'task_complete'\n | 'review_ready'\n | 'error'\n | 'custom',\n title,\n message,\n });\n\n res.writeHead(result.success ? 200 : 500, {\n 'Content-Type': 'application/json',\n });\n res.end(JSON.stringify(result));\n } catch (err) {\n console.error('[sms-webhook] Send error:', err);\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n success: false,\n error: err instanceof Error ? err.message : 'Send failed',\n })\n );\n }\n });\n return;\n }\n\n res.writeHead(404);\n res.end('Not found');\n }\n );\n\n server.listen(port, () => {\n console.log(`[sms-webhook] Server listening on port ${port}`);\n console.log(\n `[sms-webhook] Incoming messages: http://localhost:${port}/sms/incoming`\n );\n console.log(\n `[sms-webhook] Status callback: http://localhost:${port}/sms/status`\n );\n console.log(`[sms-webhook] Configure these URLs in Twilio console`);\n\n // Start timed cleanup of expired prompts and old actions\n setInterval(() => {\n try {\n const expiredPrompts = cleanupExpiredPrompts();\n const oldActions = cleanupOldActions();\n if (expiredPrompts > 0 || oldActions > 0) {\n logCleanup('sms-webhook', expiredPrompts, oldActions);\n console.log(\n `[sms-webhook] Cleanup: ${expiredPrompts} expired prompts, ${oldActions} old actions`\n );\n }\n } catch {\n // Ignore cleanup errors\n }\n }, CLEANUP_INTERVAL_MS);\n console.log(\n `[sms-webhook] Cleanup interval: every ${CLEANUP_INTERVAL_MS / 1000}s`\n );\n });\n}\n\n// Express middleware for integration\nexport async function smsWebhookMiddleware(\n req: { body: TwilioWebhookPayload },\n res: { type: (t: string) => void; send: (s: string) => void }\n): Promise<void> {\n const result = await handleSMSWebhook(req.body);\n res.type('text/xml');\n res.send(twimlResponse(result.response));\n}\n\n// CLI entry\nif (process.argv[1]?.endsWith('sms-webhook.js')) {\n const port = parseInt(process.env['SMS_WEBHOOK_PORT'] || '3456', 10);\n startWebhookServer(port);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
-
import { dirname as __pathDirname } from 'path';
|
|
3
|
-
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
-
const __dirname = __pathDirname(__filename);
|
|
5
|
-
import { existsSync, readFileSync } from "fs";
|
|
6
|
-
import { join } from "path";
|
|
7
|
-
import { homedir } from "os";
|
|
8
|
-
import { execFileSync } from "child_process";
|
|
9
|
-
import { writeFileSecure, ensureSecureDir } from "./secure-fs.js";
|
|
10
|
-
import { WhatsAppCommandsConfigSchema, parseConfigSafe } from "./schemas.js";
|
|
11
|
-
import { executeActionSafe } from "./sms-action-runner.js";
|
|
12
|
-
import {
|
|
13
|
-
syncContext,
|
|
14
|
-
getFrameDigestData,
|
|
15
|
-
generateMobileDigest,
|
|
16
|
-
loadSyncOptions
|
|
17
|
-
} from "./whatsapp-sync.js";
|
|
18
|
-
import { sendNotification } from "./sms-notify.js";
|
|
19
|
-
const MAX_REGEX_INPUT_LENGTH = 200;
|
|
20
|
-
const DANGEROUS_PATTERNS = [
|
|
21
|
-
/(\+|\*|\?)\s*(\+|\*|\?)/,
|
|
22
|
-
// Nested quantifiers like .+* or .*+
|
|
23
|
-
/\(\?[^)]*\)\s*[+*]/,
|
|
24
|
-
// Quantified groups with + or *
|
|
25
|
-
/\[[^\]]*\]\s*[+*]\s*[+*]/,
|
|
26
|
-
// Character classes with nested quantifiers
|
|
27
|
-
/(\.\*|\.\+)\s*(\.\*|\.\+)/,
|
|
28
|
-
// Overlapping .* or .+
|
|
29
|
-
/\(\[[^\]]+\]\+\)\+/,
|
|
30
|
-
// Nested + with character class
|
|
31
|
-
/\(.*\+\).*\+/
|
|
32
|
-
// Nested + quantifiers
|
|
33
|
-
];
|
|
34
|
-
function isPatternSafe(pattern) {
|
|
35
|
-
for (const dangerous of DANGEROUS_PATTERNS) {
|
|
36
|
-
if (dangerous.test(pattern)) {
|
|
37
|
-
console.warn(
|
|
38
|
-
`[whatsapp-commands] Potentially dangerous regex pattern blocked: ${pattern}`
|
|
39
|
-
);
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const quantifierCount = (pattern.match(/[+*?]/g) || []).length;
|
|
44
|
-
const groupCount = (pattern.match(/\(/g) || []).length;
|
|
45
|
-
if (quantifierCount > 5 || groupCount > 3) {
|
|
46
|
-
console.warn(
|
|
47
|
-
`[whatsapp-commands] Complex regex pattern blocked: ${pattern} (${quantifierCount} quantifiers, ${groupCount} groups)`
|
|
48
|
-
);
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
function safeRegexTest(pattern, input) {
|
|
54
|
-
if (!isPatternSafe(pattern)) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
const safeInput = input.slice(0, MAX_REGEX_INPUT_LENGTH);
|
|
58
|
-
try {
|
|
59
|
-
const regex = new RegExp(pattern);
|
|
60
|
-
return regex.test(safeInput);
|
|
61
|
-
} catch {
|
|
62
|
-
console.warn(`[whatsapp-commands] Invalid regex pattern: ${pattern}`);
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const CONFIG_PATH = join(homedir(), ".stackmemory", "whatsapp-commands.json");
|
|
67
|
-
const REMOTE_SESSIONS_PATH = join(
|
|
68
|
-
homedir(),
|
|
69
|
-
".stackmemory",
|
|
70
|
-
"remote-sessions.json"
|
|
71
|
-
);
|
|
72
|
-
function loadRemoteSessions() {
|
|
73
|
-
try {
|
|
74
|
-
if (existsSync(REMOTE_SESSIONS_PATH)) {
|
|
75
|
-
return JSON.parse(readFileSync(REMOTE_SESSIONS_PATH, "utf8"));
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
}
|
|
79
|
-
return { sessions: [] };
|
|
80
|
-
}
|
|
81
|
-
function saveRemoteSessions(store) {
|
|
82
|
-
try {
|
|
83
|
-
ensureSecureDir(join(homedir(), ".stackmemory"));
|
|
84
|
-
writeFileSecure(REMOTE_SESSIONS_PATH, JSON.stringify(store, null, 2));
|
|
85
|
-
} catch {
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function addRemoteSession(session) {
|
|
89
|
-
const store = loadRemoteSessions();
|
|
90
|
-
store.sessions = [session, ...store.sessions.slice(0, 19)];
|
|
91
|
-
saveRemoteSessions(store);
|
|
92
|
-
}
|
|
93
|
-
function getRemoteSessions() {
|
|
94
|
-
return loadRemoteSessions().sessions;
|
|
95
|
-
}
|
|
96
|
-
function getActiveRemoteSessions() {
|
|
97
|
-
return loadRemoteSessions().sessions.filter((s) => s.status === "active");
|
|
98
|
-
}
|
|
99
|
-
const DEFAULT_COMMANDS = [
|
|
100
|
-
{
|
|
101
|
-
name: "help",
|
|
102
|
-
description: "List available commands",
|
|
103
|
-
enabled: true
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
name: "status",
|
|
107
|
-
description: "Get current task/frame status",
|
|
108
|
-
enabled: true
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: "sessions",
|
|
112
|
-
description: "List active remote sessions with URLs",
|
|
113
|
-
enabled: true
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: "remote",
|
|
117
|
-
description: "Launch remote Claude session (requires task prompt)",
|
|
118
|
-
enabled: true,
|
|
119
|
-
requiresArg: true
|
|
120
|
-
},
|
|
121
|
-
// Disabled by default - can be enabled in config if needed
|
|
122
|
-
{
|
|
123
|
-
name: "context",
|
|
124
|
-
description: "Get latest context digest",
|
|
125
|
-
enabled: false
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: "sync",
|
|
129
|
-
description: "Push current context to WhatsApp",
|
|
130
|
-
enabled: false
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: "tasks",
|
|
134
|
-
description: "List active tasks",
|
|
135
|
-
enabled: false
|
|
136
|
-
}
|
|
137
|
-
];
|
|
138
|
-
const DEFAULT_CONFIG = {
|
|
139
|
-
enabled: true,
|
|
140
|
-
commands: DEFAULT_COMMANDS
|
|
141
|
-
};
|
|
142
|
-
function loadCommandsConfig() {
|
|
143
|
-
try {
|
|
144
|
-
if (existsSync(CONFIG_PATH)) {
|
|
145
|
-
const data = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
146
|
-
return parseConfigSafe(
|
|
147
|
-
WhatsAppCommandsConfigSchema,
|
|
148
|
-
{ ...DEFAULT_CONFIG, ...data },
|
|
149
|
-
DEFAULT_CONFIG,
|
|
150
|
-
"whatsapp-commands"
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
} catch {
|
|
154
|
-
}
|
|
155
|
-
return { ...DEFAULT_CONFIG };
|
|
156
|
-
}
|
|
157
|
-
function saveCommandsConfig(config) {
|
|
158
|
-
try {
|
|
159
|
-
ensureSecureDir(join(homedir(), ".stackmemory"));
|
|
160
|
-
writeFileSecure(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
161
|
-
} catch {
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function isCommand(message) {
|
|
165
|
-
const trimmed = message.trim().toLowerCase();
|
|
166
|
-
const config = loadCommandsConfig();
|
|
167
|
-
if (!config.enabled) return false;
|
|
168
|
-
const words = trimmed.split(/\s+/);
|
|
169
|
-
const firstWord = words[0];
|
|
170
|
-
return config.commands.some(
|
|
171
|
-
(cmd) => cmd.enabled && cmd.name.toLowerCase() === firstWord
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
function parseCommand(message) {
|
|
175
|
-
const trimmed = message.trim();
|
|
176
|
-
const words = trimmed.split(/\s+/);
|
|
177
|
-
if (words.length === 0) return null;
|
|
178
|
-
const name = words[0].toLowerCase();
|
|
179
|
-
const arg = words.slice(1).join(" ").trim() || void 0;
|
|
180
|
-
return { name, arg };
|
|
181
|
-
}
|
|
182
|
-
function generateHelpText(config) {
|
|
183
|
-
const lines = ["Available commands:"];
|
|
184
|
-
config.commands.filter((cmd) => cmd.enabled).forEach((cmd) => {
|
|
185
|
-
const argHint = cmd.requiresArg ? " <arg>" : "";
|
|
186
|
-
lines.push(` ${cmd.name}${argHint} - ${cmd.description}`);
|
|
187
|
-
});
|
|
188
|
-
lines.push("");
|
|
189
|
-
lines.push("Reply with command name to execute");
|
|
190
|
-
return lines.join("\n");
|
|
191
|
-
}
|
|
192
|
-
async function handleContextCommand() {
|
|
193
|
-
const data = await getFrameDigestData();
|
|
194
|
-
if (!data) {
|
|
195
|
-
return "No context available. Start a task first.";
|
|
196
|
-
}
|
|
197
|
-
const options = loadSyncOptions();
|
|
198
|
-
return generateMobileDigest(data, options);
|
|
199
|
-
}
|
|
200
|
-
async function handleSyncCommand() {
|
|
201
|
-
const result = await syncContext();
|
|
202
|
-
if (result.success) {
|
|
203
|
-
return `Context synced (${result.digestLength} chars)`;
|
|
204
|
-
} else {
|
|
205
|
-
return `Sync failed: ${result.error}`;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
async function handleStatusCommand() {
|
|
209
|
-
try {
|
|
210
|
-
const data = await getFrameDigestData();
|
|
211
|
-
if (!data) {
|
|
212
|
-
return "No active session. Start with: claude-sm";
|
|
213
|
-
}
|
|
214
|
-
const lines = [];
|
|
215
|
-
lines.push(`Frame: ${data.name || data.frameId}`);
|
|
216
|
-
lines.push(`Status: ${data.status}`);
|
|
217
|
-
lines.push(`Files: ${data.filesModified?.length || 0} modified`);
|
|
218
|
-
lines.push(`Tools: ${data.toolCallCount || 0} calls`);
|
|
219
|
-
if (data.errors?.length > 0) {
|
|
220
|
-
const unresolved = data.errors.filter((e) => !e.resolved).length;
|
|
221
|
-
if (unresolved > 0) lines.push(`Errors: ${unresolved} unresolved`);
|
|
222
|
-
}
|
|
223
|
-
lines.push(`Duration: ${Math.round(data.durationSeconds / 60)}min`);
|
|
224
|
-
return lines.join("\n");
|
|
225
|
-
} catch {
|
|
226
|
-
return "Status unavailable";
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
async function handleTasksCommand() {
|
|
230
|
-
try {
|
|
231
|
-
const data = await getFrameDigestData();
|
|
232
|
-
if (!data) {
|
|
233
|
-
return "No active tasks";
|
|
234
|
-
}
|
|
235
|
-
const lines = [];
|
|
236
|
-
if (data.decisions?.length > 0) {
|
|
237
|
-
lines.push("Recent decisions:");
|
|
238
|
-
data.decisions.slice(0, 3).forEach((d, i) => {
|
|
239
|
-
lines.push(
|
|
240
|
-
`${i + 1}. ${d.substring(0, 50)}${d.length > 50 ? "..." : ""}`
|
|
241
|
-
);
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
if (data.risks?.length > 0) {
|
|
245
|
-
lines.push("");
|
|
246
|
-
lines.push("Risks:");
|
|
247
|
-
data.risks.slice(0, 2).forEach((r) => {
|
|
248
|
-
lines.push(`- ${r.substring(0, 50)}${r.length > 50 ? "..." : ""}`);
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (lines.length === 0) {
|
|
252
|
-
return "No active tasks or decisions";
|
|
253
|
-
}
|
|
254
|
-
return lines.join("\n");
|
|
255
|
-
} catch {
|
|
256
|
-
return "Tasks unavailable";
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async function handleRemoteCommand(prompt) {
|
|
260
|
-
try {
|
|
261
|
-
const sanitizedPrompt = prompt.replace(/[`$\\]/g, "").replace(/["']/g, "'").substring(0, 500);
|
|
262
|
-
if (!sanitizedPrompt.trim()) {
|
|
263
|
-
return "Please provide a task prompt. Usage: remote <your task>";
|
|
264
|
-
}
|
|
265
|
-
console.log(
|
|
266
|
-
`[whatsapp-commands] Launching remote session: ${sanitizedPrompt.substring(0, 50)}...`
|
|
267
|
-
);
|
|
268
|
-
const output = execFileSync("claude", ["--remote", sanitizedPrompt], {
|
|
269
|
-
encoding: "utf8",
|
|
270
|
-
timeout: 3e4,
|
|
271
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
272
|
-
});
|
|
273
|
-
const urlMatch = output.match(
|
|
274
|
-
/https:\/\/claude\.ai\/code\/session_[a-zA-Z0-9]+/
|
|
275
|
-
);
|
|
276
|
-
if (urlMatch) {
|
|
277
|
-
const sessionUrl = urlMatch[0];
|
|
278
|
-
const sessionId = sessionUrl.split("/").pop() || "unknown";
|
|
279
|
-
addRemoteSession({
|
|
280
|
-
id: sessionId,
|
|
281
|
-
url: sessionUrl,
|
|
282
|
-
prompt: sanitizedPrompt,
|
|
283
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
284
|
-
status: "active"
|
|
285
|
-
});
|
|
286
|
-
return `Remote session launched!
|
|
287
|
-
|
|
288
|
-
${sessionUrl}
|
|
289
|
-
|
|
290
|
-
Task: ${sanitizedPrompt.substring(0, 100)}`;
|
|
291
|
-
}
|
|
292
|
-
return `Session launched:
|
|
293
|
-
${output.substring(0, 300)}`;
|
|
294
|
-
} catch (err) {
|
|
295
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
296
|
-
console.error(`[whatsapp-commands] Remote launch failed: ${error}`);
|
|
297
|
-
return `Failed to launch remote session: ${error.substring(0, 100)}`;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
function handleSessionsCommand() {
|
|
301
|
-
const sessions = getActiveRemoteSessions();
|
|
302
|
-
if (sessions.length === 0) {
|
|
303
|
-
return "No active remote sessions";
|
|
304
|
-
}
|
|
305
|
-
const lines = ["Active remote sessions:"];
|
|
306
|
-
sessions.slice(0, 5).forEach((s, i) => {
|
|
307
|
-
const age = Math.round(
|
|
308
|
-
(Date.now() - new Date(s.createdAt).getTime()) / 6e4
|
|
309
|
-
);
|
|
310
|
-
const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
|
|
311
|
-
lines.push(`${i + 1}. ${s.prompt.substring(0, 40)}... (${ageStr})`);
|
|
312
|
-
lines.push(` ${s.url}`);
|
|
313
|
-
});
|
|
314
|
-
return lines.join("\n");
|
|
315
|
-
}
|
|
316
|
-
async function processCommand(from, message) {
|
|
317
|
-
const config = loadCommandsConfig();
|
|
318
|
-
if (!config.enabled) {
|
|
319
|
-
return { handled: false };
|
|
320
|
-
}
|
|
321
|
-
const parsed = parseCommand(message);
|
|
322
|
-
if (!parsed) {
|
|
323
|
-
return { handled: false };
|
|
324
|
-
}
|
|
325
|
-
const command = config.commands.find(
|
|
326
|
-
(cmd) => cmd.enabled && cmd.name.toLowerCase() === parsed.name
|
|
327
|
-
);
|
|
328
|
-
if (!command) {
|
|
329
|
-
return { handled: false };
|
|
330
|
-
}
|
|
331
|
-
if (command.name === "help") {
|
|
332
|
-
const helpText = generateHelpText(config);
|
|
333
|
-
return { handled: true, response: helpText };
|
|
334
|
-
}
|
|
335
|
-
if (command.name === "context") {
|
|
336
|
-
const contextText = await handleContextCommand();
|
|
337
|
-
return { handled: true, response: contextText };
|
|
338
|
-
}
|
|
339
|
-
if (command.name === "sync") {
|
|
340
|
-
const syncText = await handleSyncCommand();
|
|
341
|
-
return { handled: true, response: syncText };
|
|
342
|
-
}
|
|
343
|
-
if (command.name === "status") {
|
|
344
|
-
const statusText = await handleStatusCommand();
|
|
345
|
-
return { handled: true, response: statusText };
|
|
346
|
-
}
|
|
347
|
-
if (command.name === "tasks") {
|
|
348
|
-
const tasksText = await handleTasksCommand();
|
|
349
|
-
return { handled: true, response: tasksText };
|
|
350
|
-
}
|
|
351
|
-
if (command.name === "remote") {
|
|
352
|
-
if (!parsed.arg) {
|
|
353
|
-
return {
|
|
354
|
-
handled: true,
|
|
355
|
-
response: "Usage: remote <task prompt>\nExample: remote Fix the login bug",
|
|
356
|
-
error: "Missing prompt"
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
const remoteText = await handleRemoteCommand(parsed.arg);
|
|
360
|
-
return { handled: true, response: remoteText };
|
|
361
|
-
}
|
|
362
|
-
if (command.name === "sessions") {
|
|
363
|
-
const sessionsText = handleSessionsCommand();
|
|
364
|
-
return { handled: true, response: sessionsText };
|
|
365
|
-
}
|
|
366
|
-
if (command.requiresArg && !parsed.arg) {
|
|
367
|
-
return {
|
|
368
|
-
handled: true,
|
|
369
|
-
response: `${command.name} requires an argument. Usage: ${command.name} <arg>`,
|
|
370
|
-
error: "Missing argument"
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
if (command.argPattern && parsed.arg) {
|
|
374
|
-
if (!safeRegexTest(command.argPattern, parsed.arg)) {
|
|
375
|
-
return {
|
|
376
|
-
handled: true,
|
|
377
|
-
response: `Invalid argument format for ${command.name}`,
|
|
378
|
-
error: "Invalid argument format"
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
let action = command.action;
|
|
383
|
-
if (action && parsed.arg) {
|
|
384
|
-
if (command.name === "approve") {
|
|
385
|
-
action = `gh pr review ${parsed.arg} --approve`;
|
|
386
|
-
} else if (command.name === "merge") {
|
|
387
|
-
action = `gh pr merge ${parsed.arg} --squash`;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
if (action) {
|
|
391
|
-
console.log(`[whatsapp-commands] Executing: ${action}`);
|
|
392
|
-
const result = await executeActionSafe(action, message);
|
|
393
|
-
if (result.success) {
|
|
394
|
-
const output = result.output?.slice(0, 200) || "Done";
|
|
395
|
-
return {
|
|
396
|
-
handled: true,
|
|
397
|
-
response: `${command.name}: ${output}`,
|
|
398
|
-
action
|
|
399
|
-
};
|
|
400
|
-
} else {
|
|
401
|
-
return {
|
|
402
|
-
handled: true,
|
|
403
|
-
response: `${command.name} failed: ${result.error?.slice(0, 100)}`,
|
|
404
|
-
error: result.error,
|
|
405
|
-
action
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return {
|
|
410
|
-
handled: true,
|
|
411
|
-
response: `Command ${command.name} acknowledged`
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
async function sendCommandResponse(response) {
|
|
415
|
-
const result = await sendNotification({
|
|
416
|
-
type: "custom",
|
|
417
|
-
title: "Command Result",
|
|
418
|
-
message: response
|
|
419
|
-
});
|
|
420
|
-
return { success: result.success, error: result.error };
|
|
421
|
-
}
|
|
422
|
-
function enableCommands() {
|
|
423
|
-
const config = loadCommandsConfig();
|
|
424
|
-
config.enabled = true;
|
|
425
|
-
saveCommandsConfig(config);
|
|
426
|
-
}
|
|
427
|
-
function disableCommands() {
|
|
428
|
-
const config = loadCommandsConfig();
|
|
429
|
-
config.enabled = false;
|
|
430
|
-
saveCommandsConfig(config);
|
|
431
|
-
}
|
|
432
|
-
function isCommandsEnabled() {
|
|
433
|
-
const config = loadCommandsConfig();
|
|
434
|
-
return config.enabled;
|
|
435
|
-
}
|
|
436
|
-
function addCommand(command) {
|
|
437
|
-
const config = loadCommandsConfig();
|
|
438
|
-
const existingIndex = config.commands.findIndex(
|
|
439
|
-
(c) => c.name.toLowerCase() === command.name.toLowerCase()
|
|
440
|
-
);
|
|
441
|
-
if (existingIndex >= 0) {
|
|
442
|
-
config.commands[existingIndex] = command;
|
|
443
|
-
} else {
|
|
444
|
-
config.commands.push(command);
|
|
445
|
-
}
|
|
446
|
-
saveCommandsConfig(config);
|
|
447
|
-
}
|
|
448
|
-
function removeCommand(name) {
|
|
449
|
-
const config = loadCommandsConfig();
|
|
450
|
-
const initialLength = config.commands.length;
|
|
451
|
-
config.commands = config.commands.filter(
|
|
452
|
-
(c) => c.name.toLowerCase() !== name.toLowerCase()
|
|
453
|
-
);
|
|
454
|
-
if (config.commands.length < initialLength) {
|
|
455
|
-
saveCommandsConfig(config);
|
|
456
|
-
return true;
|
|
457
|
-
}
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
function getAvailableCommands() {
|
|
461
|
-
const config = loadCommandsConfig();
|
|
462
|
-
return config.commands.filter((c) => c.enabled);
|
|
463
|
-
}
|
|
464
|
-
export {
|
|
465
|
-
addCommand,
|
|
466
|
-
disableCommands,
|
|
467
|
-
enableCommands,
|
|
468
|
-
getActiveRemoteSessions,
|
|
469
|
-
getAvailableCommands,
|
|
470
|
-
getRemoteSessions,
|
|
471
|
-
isCommand,
|
|
472
|
-
isCommandsEnabled,
|
|
473
|
-
loadCommandsConfig,
|
|
474
|
-
processCommand,
|
|
475
|
-
removeCommand,
|
|
476
|
-
saveCommandsConfig,
|
|
477
|
-
sendCommandResponse
|
|
478
|
-
};
|
|
479
|
-
//# sourceMappingURL=whatsapp-commands.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/hooks/whatsapp-commands.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WhatsApp Inbound Command Processor\n * Process WhatsApp messages as commands\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { execFileSync } from 'child_process';\nimport { writeFileSecure, ensureSecureDir } from './secure-fs.js';\nimport { WhatsAppCommandsConfigSchema, parseConfigSafe } from './schemas.js';\nimport { executeActionSafe } from './sms-action-runner.js';\nimport {\n syncContext,\n getFrameDigestData,\n generateMobileDigest,\n loadSyncOptions,\n} from './whatsapp-sync.js';\nimport { sendNotification } from './sms-notify.js';\n\n// Max input length for regex matching to prevent catastrophic backtracking\nconst MAX_REGEX_INPUT_LENGTH = 200;\n\n// Dangerous regex patterns that can cause ReDoS (catastrophic backtracking)\n// These patterns have nested quantifiers or overlapping alternatives\nconst DANGEROUS_PATTERNS = [\n /(\\+|\\*|\\?)\\s*(\\+|\\*|\\?)/, // Nested quantifiers like .+* or .*+\n /\\(\\?[^)]*\\)\\s*[+*]/, // Quantified groups with + or *\n /\\[[^\\]]*\\]\\s*[+*]\\s*[+*]/, // Character classes with nested quantifiers\n /(\\.\\*|\\.\\+)\\s*(\\.\\*|\\.\\+)/, // Overlapping .* or .+\n /\\(\\[[^\\]]+\\]\\+\\)\\+/, // Nested + with character class\n /\\(.*\\+\\).*\\+/, // Nested + quantifiers\n];\n\n/**\n * Check if a regex pattern might be vulnerable to ReDoS\n * Returns true if the pattern appears safe, false if potentially dangerous\n */\nfunction isPatternSafe(pattern: string): boolean {\n // Check against known dangerous patterns\n for (const dangerous of DANGEROUS_PATTERNS) {\n if (dangerous.test(pattern)) {\n console.warn(\n `[whatsapp-commands] Potentially dangerous regex pattern blocked: ${pattern}`\n );\n return false;\n }\n }\n\n // Additional heuristics: limit pattern complexity\n const quantifierCount = (pattern.match(/[+*?]/g) || []).length;\n const groupCount = (pattern.match(/\\(/g) || []).length;\n\n // If too many quantifiers or groups, consider it risky\n if (quantifierCount > 5 || groupCount > 3) {\n console.warn(\n `[whatsapp-commands] Complex regex pattern blocked: ${pattern} (${quantifierCount} quantifiers, ${groupCount} groups)`\n );\n return false;\n }\n\n return true;\n}\n\n/**\n * Safely test a regex pattern against input with ReDoS protection\n * Pre-validates the pattern for dangerous constructs before testing\n * Returns false if pattern is dangerous, invalid, or doesn't match\n */\nfunction safeRegexTest(pattern: string, input: string): boolean {\n // Pre-validate pattern for ReDoS safety BEFORE running it\n if (!isPatternSafe(pattern)) {\n return false;\n }\n\n // Truncate input to prevent catastrophic backtracking\n const safeInput = input.slice(0, MAX_REGEX_INPUT_LENGTH);\n\n try {\n const regex = new RegExp(pattern);\n return regex.test(safeInput);\n } catch {\n // Invalid regex pattern\n console.warn(`[whatsapp-commands] Invalid regex pattern: ${pattern}`);\n return false;\n }\n}\n\nexport interface WhatsAppCommand {\n name: string;\n description: string;\n enabled: boolean;\n action?: string; // Safe action to execute\n requiresArg?: boolean;\n argPattern?: string; // Regex pattern for arg validation\n}\n\nexport interface CommandsConfig {\n enabled: boolean;\n commands: WhatsAppCommand[];\n}\n\nexport interface CommandResult {\n handled: boolean;\n response?: string;\n action?: string;\n error?: string;\n}\n\nconst CONFIG_PATH = join(homedir(), '.stackmemory', 'whatsapp-commands.json');\nconst REMOTE_SESSIONS_PATH = join(\n homedir(),\n '.stackmemory',\n 'remote-sessions.json'\n);\n\n/**\n * Remote session tracking\n */\nexport interface RemoteSession {\n id: string;\n url: string;\n prompt: string;\n createdAt: string;\n status: 'active' | 'completed' | 'failed';\n lastActivity?: string;\n}\n\ninterface RemoteSessionsStore {\n sessions: RemoteSession[];\n}\n\nfunction loadRemoteSessions(): RemoteSessionsStore {\n try {\n if (existsSync(REMOTE_SESSIONS_PATH)) {\n return JSON.parse(readFileSync(REMOTE_SESSIONS_PATH, 'utf8'));\n }\n } catch {\n // Use defaults\n }\n return { sessions: [] };\n}\n\nfunction saveRemoteSessions(store: RemoteSessionsStore): void {\n try {\n ensureSecureDir(join(homedir(), '.stackmemory'));\n writeFileSecure(REMOTE_SESSIONS_PATH, JSON.stringify(store, null, 2));\n } catch {\n // Silently fail\n }\n}\n\nfunction addRemoteSession(session: RemoteSession): void {\n const store = loadRemoteSessions();\n // Keep last 20 sessions\n store.sessions = [session, ...store.sessions.slice(0, 19)];\n saveRemoteSessions(store);\n}\n\nexport function getRemoteSessions(): RemoteSession[] {\n return loadRemoteSessions().sessions;\n}\n\nexport function getActiveRemoteSessions(): RemoteSession[] {\n return loadRemoteSessions().sessions.filter((s) => s.status === 'active');\n}\n\n// Default supported commands - simplified for notifications + choices\nconst DEFAULT_COMMANDS: WhatsAppCommand[] = [\n {\n name: 'help',\n description: 'List available commands',\n enabled: true,\n },\n {\n name: 'status',\n description: 'Get current task/frame status',\n enabled: true,\n },\n {\n name: 'sessions',\n description: 'List active remote sessions with URLs',\n enabled: true,\n },\n {\n name: 'remote',\n description: 'Launch remote Claude session (requires task prompt)',\n enabled: true,\n requiresArg: true,\n },\n // Disabled by default - can be enabled in config if needed\n {\n name: 'context',\n description: 'Get latest context digest',\n enabled: false,\n },\n {\n name: 'sync',\n description: 'Push current context to WhatsApp',\n enabled: false,\n },\n {\n name: 'tasks',\n description: 'List active tasks',\n enabled: false,\n },\n];\n\nconst DEFAULT_CONFIG: CommandsConfig = {\n enabled: true,\n commands: DEFAULT_COMMANDS,\n};\n\n/**\n * Load commands config\n */\nexport function loadCommandsConfig(): CommandsConfig {\n try {\n if (existsSync(CONFIG_PATH)) {\n const data = JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));\n return parseConfigSafe(\n WhatsAppCommandsConfigSchema,\n { ...DEFAULT_CONFIG, ...data },\n DEFAULT_CONFIG,\n 'whatsapp-commands'\n );\n }\n } catch {\n // Use defaults\n }\n return { ...DEFAULT_CONFIG };\n}\n\n/**\n * Save commands config\n */\nexport function saveCommandsConfig(config: CommandsConfig): void {\n try {\n ensureSecureDir(join(homedir(), '.stackmemory'));\n writeFileSecure(CONFIG_PATH, JSON.stringify(config, null, 2));\n } catch {\n // Silently fail\n }\n}\n\n/**\n * Check if a message is a command\n */\nexport function isCommand(message: string): boolean {\n const trimmed = message.trim().toLowerCase();\n\n // Check if it's a single word command\n const config = loadCommandsConfig();\n if (!config.enabled) return false;\n\n const words = trimmed.split(/\\s+/);\n const firstWord = words[0];\n\n return config.commands.some(\n (cmd) => cmd.enabled && cmd.name.toLowerCase() === firstWord\n );\n}\n\n/**\n * Parse command from message\n */\nfunction parseCommand(message: string): { name: string; arg?: string } | null {\n const trimmed = message.trim();\n const words = trimmed.split(/\\s+/);\n\n if (words.length === 0) return null;\n\n const name = words[0].toLowerCase();\n const arg = words.slice(1).join(' ').trim() || undefined;\n\n return { name, arg };\n}\n\n/**\n * Generate help text for available commands\n */\nfunction generateHelpText(config: CommandsConfig): string {\n const lines: string[] = ['Available commands:'];\n\n config.commands\n .filter((cmd) => cmd.enabled)\n .forEach((cmd) => {\n const argHint = cmd.requiresArg ? ' <arg>' : '';\n lines.push(` ${cmd.name}${argHint} - ${cmd.description}`);\n });\n\n lines.push('');\n lines.push('Reply with command name to execute');\n\n return lines.join('\\n');\n}\n\n/**\n * Handle the 'context' command specially\n */\nasync function handleContextCommand(): Promise<string> {\n const data = await getFrameDigestData();\n\n if (!data) {\n return 'No context available. Start a task first.';\n }\n\n const options = loadSyncOptions();\n return generateMobileDigest(data, options);\n}\n\n/**\n * Handle the 'sync' command specially\n */\nasync function handleSyncCommand(): Promise<string> {\n const result = await syncContext();\n\n if (result.success) {\n return `Context synced (${result.digestLength} chars)`;\n } else {\n return `Sync failed: ${result.error}`;\n }\n}\n\n/**\n * Handle the 'status' command - get current frame/task status\n */\nasync function handleStatusCommand(): Promise<string> {\n try {\n const data = await getFrameDigestData();\n if (!data) {\n return 'No active session. Start with: claude-sm';\n }\n\n const lines: string[] = [];\n lines.push(`Frame: ${data.name || data.frameId}`);\n lines.push(`Status: ${data.status}`);\n lines.push(`Files: ${data.filesModified?.length || 0} modified`);\n lines.push(`Tools: ${data.toolCallCount || 0} calls`);\n if (data.errors?.length > 0) {\n const unresolved = data.errors.filter((e) => !e.resolved).length;\n if (unresolved > 0) lines.push(`Errors: ${unresolved} unresolved`);\n }\n lines.push(`Duration: ${Math.round(data.durationSeconds / 60)}min`);\n\n return lines.join('\\n');\n } catch {\n return 'Status unavailable';\n }\n}\n\n/**\n * Handle the 'tasks' command - list recent decisions/risks\n */\nasync function handleTasksCommand(): Promise<string> {\n try {\n const data = await getFrameDigestData();\n if (!data) {\n return 'No active tasks';\n }\n\n const lines: string[] = [];\n\n if (data.decisions?.length > 0) {\n lines.push('Recent decisions:');\n data.decisions.slice(0, 3).forEach((d, i) => {\n lines.push(\n `${i + 1}. ${d.substring(0, 50)}${d.length > 50 ? '...' : ''}`\n );\n });\n }\n\n if (data.risks?.length > 0) {\n lines.push('');\n lines.push('Risks:');\n data.risks.slice(0, 2).forEach((r) => {\n lines.push(`- ${r.substring(0, 50)}${r.length > 50 ? '...' : ''}`);\n });\n }\n\n if (lines.length === 0) {\n return 'No active tasks or decisions';\n }\n\n return lines.join('\\n');\n } catch {\n return 'Tasks unavailable';\n }\n}\n\n/**\n * Handle the 'remote' command - launch a remote Claude session\n */\nasync function handleRemoteCommand(prompt: string): Promise<string> {\n try {\n // Sanitize prompt - remove any shell-dangerous characters\n const sanitizedPrompt = prompt\n .replace(/[`$\\\\]/g, '')\n .replace(/[\"']/g, \"'\")\n .substring(0, 500);\n\n if (!sanitizedPrompt.trim()) {\n return 'Please provide a task prompt. Usage: remote <your task>';\n }\n\n console.log(\n `[whatsapp-commands] Launching remote session: ${sanitizedPrompt.substring(0, 50)}...`\n );\n\n // Execute claude --remote with the prompt\n const output = execFileSync('claude', ['--remote', sanitizedPrompt], {\n encoding: 'utf8',\n timeout: 30000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Parse session URL from output\n // Expected format contains: https://claude.ai/code/session_...\n const urlMatch = output.match(\n /https:\\/\\/claude\\.ai\\/code\\/session_[a-zA-Z0-9]+/\n );\n\n if (urlMatch) {\n const sessionUrl = urlMatch[0];\n const sessionId = sessionUrl.split('/').pop() || 'unknown';\n\n // Store the session\n addRemoteSession({\n id: sessionId,\n url: sessionUrl,\n prompt: sanitizedPrompt,\n createdAt: new Date().toISOString(),\n status: 'active',\n });\n\n return `Remote session launched!\\n\\n${sessionUrl}\\n\\nTask: ${sanitizedPrompt.substring(0, 100)}`;\n }\n\n // No URL found - return raw output\n return `Session launched:\\n${output.substring(0, 300)}`;\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n console.error(`[whatsapp-commands] Remote launch failed: ${error}`);\n return `Failed to launch remote session: ${error.substring(0, 100)}`;\n }\n}\n\n/**\n * Handle the 'sessions' command - list active remote sessions\n */\nfunction handleSessionsCommand(): string {\n const sessions = getActiveRemoteSessions();\n\n if (sessions.length === 0) {\n return 'No active remote sessions';\n }\n\n const lines: string[] = ['Active remote sessions:'];\n\n sessions.slice(0, 5).forEach((s, i) => {\n const age = Math.round(\n (Date.now() - new Date(s.createdAt).getTime()) / 60000\n );\n const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;\n lines.push(`${i + 1}. ${s.prompt.substring(0, 40)}... (${ageStr})`);\n lines.push(` ${s.url}`);\n });\n\n return lines.join('\\n');\n}\n\n/**\n * Process an incoming WhatsApp command\n */\nexport async function processCommand(\n from: string,\n message: string\n): Promise<CommandResult> {\n const config = loadCommandsConfig();\n\n if (!config.enabled) {\n return { handled: false };\n }\n\n const parsed = parseCommand(message);\n if (!parsed) {\n return { handled: false };\n }\n\n const command = config.commands.find(\n (cmd) => cmd.enabled && cmd.name.toLowerCase() === parsed.name\n );\n\n if (!command) {\n return { handled: false };\n }\n\n // Handle special commands\n if (command.name === 'help') {\n const helpText = generateHelpText(config);\n return { handled: true, response: helpText };\n }\n\n if (command.name === 'context') {\n const contextText = await handleContextCommand();\n return { handled: true, response: contextText };\n }\n\n if (command.name === 'sync') {\n const syncText = await handleSyncCommand();\n return { handled: true, response: syncText };\n }\n\n if (command.name === 'status') {\n const statusText = await handleStatusCommand();\n return { handled: true, response: statusText };\n }\n\n if (command.name === 'tasks') {\n const tasksText = await handleTasksCommand();\n return { handled: true, response: tasksText };\n }\n\n if (command.name === 'remote') {\n if (!parsed.arg) {\n return {\n handled: true,\n response:\n 'Usage: remote <task prompt>\\nExample: remote Fix the login bug',\n error: 'Missing prompt',\n };\n }\n const remoteText = await handleRemoteCommand(parsed.arg);\n return { handled: true, response: remoteText };\n }\n\n if (command.name === 'sessions') {\n const sessionsText = handleSessionsCommand();\n return { handled: true, response: sessionsText };\n }\n\n // Check if argument is required\n if (command.requiresArg && !parsed.arg) {\n return {\n handled: true,\n response: `${command.name} requires an argument. Usage: ${command.name} <arg>`,\n error: 'Missing argument',\n };\n }\n\n // Validate argument pattern if specified (with ReDoS protection)\n if (command.argPattern && parsed.arg) {\n if (!safeRegexTest(command.argPattern, parsed.arg)) {\n return {\n handled: true,\n response: `Invalid argument format for ${command.name}`,\n error: 'Invalid argument format',\n };\n }\n }\n\n // Build the action command\n let action = command.action;\n\n if (action && parsed.arg) {\n // Special handling for PR commands\n if (command.name === 'approve') {\n action = `gh pr review ${parsed.arg} --approve`;\n } else if (command.name === 'merge') {\n action = `gh pr merge ${parsed.arg} --squash`;\n }\n }\n\n // Execute the action if defined\n if (action) {\n console.log(`[whatsapp-commands] Executing: ${action}`);\n\n const result = await executeActionSafe(action, message);\n\n if (result.success) {\n const output = result.output?.slice(0, 200) || 'Done';\n return {\n handled: true,\n response: `${command.name}: ${output}`,\n action,\n };\n } else {\n return {\n handled: true,\n response: `${command.name} failed: ${result.error?.slice(0, 100)}`,\n error: result.error,\n action,\n };\n }\n }\n\n return {\n handled: true,\n response: `Command ${command.name} acknowledged`,\n };\n}\n\n/**\n * Send command result back via WhatsApp\n */\nexport async function sendCommandResponse(\n response: string\n): Promise<{ success: boolean; error?: string }> {\n const result = await sendNotification({\n type: 'custom',\n title: 'Command Result',\n message: response,\n });\n\n return { success: result.success, error: result.error };\n}\n\n/**\n * Enable command processing\n */\nexport function enableCommands(): void {\n const config = loadCommandsConfig();\n config.enabled = true;\n saveCommandsConfig(config);\n}\n\n/**\n * Disable command processing\n */\nexport function disableCommands(): void {\n const config = loadCommandsConfig();\n config.enabled = false;\n saveCommandsConfig(config);\n}\n\n/**\n * Check if commands are enabled\n */\nexport function isCommandsEnabled(): boolean {\n const config = loadCommandsConfig();\n return config.enabled;\n}\n\n/**\n * Add a custom command\n */\nexport function addCommand(command: WhatsAppCommand): void {\n const config = loadCommandsConfig();\n\n // Check if command already exists\n const existingIndex = config.commands.findIndex(\n (c) => c.name.toLowerCase() === command.name.toLowerCase()\n );\n\n if (existingIndex >= 0) {\n config.commands[existingIndex] = command;\n } else {\n config.commands.push(command);\n }\n\n saveCommandsConfig(config);\n}\n\n/**\n * Remove a custom command\n */\nexport function removeCommand(name: string): boolean {\n const config = loadCommandsConfig();\n const initialLength = config.commands.length;\n\n config.commands = config.commands.filter(\n (c) => c.name.toLowerCase() !== name.toLowerCase()\n );\n\n if (config.commands.length < initialLength) {\n saveCommandsConfig(config);\n return true;\n }\n\n return false;\n}\n\n/**\n * Get list of available commands\n */\nexport function getAvailableCommands(): WhatsAppCommand[] {\n const config = loadCommandsConfig();\n return config.commands.filter((c) => c.enabled);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|