claude-flow-novice 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/commands/guidance.js +487 -668
- package/dist/src/cli/commands/index-validate.js +18 -29
- package/dist/src/cli/commands/mcp-troubleshoot.js +230 -282
- package/dist/src/cli/commands/neural-goal-init.js +92 -125
- package/dist/src/cli/commands/swarm-exec.js +317 -393
- package/dist/src/cli/commands/swarm.js +1 -1
- package/dist/src/cli/commands/validate-framework.js +983 -1100
- package/dist/src/cli/commands/validate.js +144 -223
- package/dist/src/cli/simple-commands/__tests__/agent.test.js +265 -277
- package/dist/src/cli/simple-commands/__tests__/memory.test.js +6 -7
- package/dist/src/cli/simple-commands/__tests__/swarm.test.js +373 -356
- package/dist/src/cli/simple-commands/__tests__/task.test.js +6 -7
- package/dist/src/cli/simple-commands/agent.js +157 -193
- package/dist/src/cli/simple-commands/analysis.js +336 -446
- package/dist/src/cli/simple-commands/automation-executor.js +1095 -1339
- package/dist/src/cli/simple-commands/automation.js +481 -469
- package/dist/src/cli/simple-commands/batch-manager.js +261 -313
- package/dist/src/cli/simple-commands/claude-telemetry.js +241 -267
- package/dist/src/cli/simple-commands/claude-track.js +68 -90
- package/dist/src/cli/simple-commands/concurrent-display.js +266 -320
- package/dist/src/cli/simple-commands/config.js +245 -290
- package/dist/src/cli/simple-commands/coordination.js +182 -234
- package/dist/src/cli/simple-commands/enhanced-ui-views.js +812 -615
- package/dist/src/cli/simple-commands/enhanced-webui-complete.js +922 -981
- package/dist/src/cli/simple-commands/fix-hook-variables.js +274 -294
- package/dist/src/cli/simple-commands/github/gh-coordinator.js +378 -457
- package/dist/src/cli/simple-commands/github/github-api.js +535 -574
- package/dist/src/cli/simple-commands/github/init.js +276 -303
- package/dist/src/cli/simple-commands/github.js +222 -247
- package/dist/src/cli/simple-commands/goal.js +51 -63
- package/dist/src/cli/simple-commands/hive-mind/auto-save-middleware.js +208 -278
- package/dist/src/cli/simple-commands/hive-mind/communication.js +601 -696
- package/dist/src/cli/simple-commands/hive-mind/core.js +907 -979
- package/dist/src/cli/simple-commands/hive-mind/db-optimizer.js +406 -655
- package/dist/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1125 -1245
- package/dist/src/cli/simple-commands/hive-mind/memory.js +854 -1090
- package/dist/src/cli/simple-commands/hive-mind/performance-optimizer.js +459 -574
- package/dist/src/cli/simple-commands/hive-mind/performance-test.js +263 -347
- package/dist/src/cli/simple-commands/hive-mind/queen.js +727 -768
- package/dist/src/cli/simple-commands/hive-mind/session-manager.js +745 -1049
- package/dist/src/cli/simple-commands/hive-mind-optimize.js +227 -283
- package/dist/src/cli/simple-commands/hive-mind-wizard.js +174 -217
- package/dist/src/cli/simple-commands/hive-mind.js +1842 -2283
- package/dist/src/cli/simple-commands/hive.js +90 -79
- package/dist/src/cli/simple-commands/hook-safety.js +431 -521
- package/dist/src/cli/simple-commands/hooks/session-start-soul.js +203 -254
- package/dist/src/cli/simple-commands/hooks.js +1064 -1204
- package/dist/src/cli/simple-commands/init/agent-copier.js +294 -319
- package/dist/src/cli/simple-commands/init/batch-init.js +496 -562
- package/dist/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +61 -88
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +125 -150
- package/dist/src/cli/simple-commands/init/claude-commands/slash-commands.js +42 -49
- package/dist/src/cli/simple-commands/init/claude-commands/sparc-commands.js +43 -61
- package/dist/src/cli/simple-commands/init/copy-revised-templates.js +141 -147
- package/dist/src/cli/simple-commands/init/executable-wrapper.js +31 -44
- package/dist/src/cli/simple-commands/init/gitignore-updater.js +64 -90
- package/dist/src/cli/simple-commands/init/help.js +104 -107
- package/dist/src/cli/simple-commands/init/hive-mind-init.js +509 -528
- package/dist/src/cli/simple-commands/init/index.js +1510 -1759
- package/dist/src/cli/simple-commands/init/performance-monitor.js +234 -317
- package/dist/src/cli/simple-commands/init/rollback/backup-manager.js +441 -504
- package/dist/src/cli/simple-commands/init/rollback/index.js +289 -364
- package/dist/src/cli/simple-commands/init/rollback/recovery-manager.js +652 -728
- package/dist/src/cli/simple-commands/init/rollback/rollback-executor.js +416 -481
- package/dist/src/cli/simple-commands/init/rollback/state-tracker.js +369 -448
- package/dist/src/cli/simple-commands/init/sparc/roo-readme.js +1 -2
- package/dist/src/cli/simple-commands/init/sparc/roomodes-config.js +122 -99
- package/dist/src/cli/simple-commands/init/sparc/workflows.js +32 -37
- package/dist/src/cli/simple-commands/init/sparc-structure.js +55 -62
- package/dist/src/cli/simple-commands/init/template-copier.js +421 -533
- package/dist/src/cli/simple-commands/init/templates/coordination-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/enhanced-templates.js +344 -318
- package/dist/src/cli/simple-commands/init/templates/github-safe-enhanced.js +173 -218
- package/dist/src/cli/simple-commands/init/templates/github-safe.js +65 -75
- package/dist/src/cli/simple-commands/init/templates/memory-bank-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/readme-files.js +2 -4
- package/dist/src/cli/simple-commands/init/templates/safe-hook-patterns.js +187 -230
- package/dist/src/cli/simple-commands/init/templates/sparc-modes.js +53 -80
- package/dist/src/cli/simple-commands/init/templates/verification-claude-md.js +101 -85
- package/dist/src/cli/simple-commands/init/validation/config-validator.js +283 -330
- package/dist/src/cli/simple-commands/init/validation/health-checker.js +495 -561
- package/dist/src/cli/simple-commands/init/validation/index.js +302 -358
- package/dist/src/cli/simple-commands/init/validation/mode-validator.js +308 -359
- package/dist/src/cli/simple-commands/init/validation/post-init-validator.js +389 -366
- package/dist/src/cli/simple-commands/init/validation/pre-init-validator.js +270 -268
- package/dist/src/cli/simple-commands/init/validation/test-runner.js +427 -447
- package/dist/src/cli/simple-commands/init.js +1 -2
- package/dist/src/cli/simple-commands/mcp-health.js +131 -158
- package/dist/src/cli/simple-commands/mcp-integration-layer.js +533 -634
- package/dist/src/cli/simple-commands/mcp.js +345 -400
- package/dist/src/cli/simple-commands/memory-consolidation.js +426 -537
- package/dist/src/cli/simple-commands/memory.js +247 -311
- package/dist/src/cli/simple-commands/migrate-hooks.js +39 -46
- package/dist/src/cli/simple-commands/monitor.js +294 -363
- package/dist/src/cli/simple-commands/neural.js +51 -65
- package/dist/src/cli/simple-commands/pair-autofix-only.js +538 -662
- package/dist/src/cli/simple-commands/pair-basic.js +528 -656
- package/dist/src/cli/simple-commands/pair-old.js +430 -543
- package/dist/src/cli/simple-commands/pair-working.js +615 -751
- package/dist/src/cli/simple-commands/pair.js +615 -751
- package/dist/src/cli/simple-commands/performance-hooks.js +83 -111
- package/dist/src/cli/simple-commands/performance-metrics.js +348 -433
- package/dist/src/cli/simple-commands/process-ui-enhanced.js +708 -787
- package/dist/src/cli/simple-commands/process-ui.js +230 -254
- package/dist/src/cli/simple-commands/realtime-update-system.js +525 -611
- package/dist/src/cli/simple-commands/sparc/architecture.js +1704 -1530
- package/dist/src/cli/simple-commands/sparc/commands.js +438 -516
- package/dist/src/cli/simple-commands/sparc/completion.js +1224 -1481
- package/dist/src/cli/simple-commands/sparc/coordinator.js +913 -978
- package/dist/src/cli/simple-commands/sparc/index.js +241 -298
- package/dist/src/cli/simple-commands/sparc/phase-base.js +314 -390
- package/dist/src/cli/simple-commands/sparc/pseudocode.js +965 -869
- package/dist/src/cli/simple-commands/sparc/refinement.js +980 -1273
- package/dist/src/cli/simple-commands/sparc/specification.js +559 -645
- package/dist/src/cli/simple-commands/sparc-modes/architect.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/ask.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/code.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/debug.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/devops.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/docs-writer.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/generic.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/index.js +47 -55
- package/dist/src/cli/simple-commands/sparc-modes/integration.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/mcp.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/monitoring.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/optimization.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/security-review.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/supabase-admin.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/swarm.js +101 -87
- package/dist/src/cli/simple-commands/sparc-modes/tdd.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/tutorial.js +1 -1
- package/dist/src/cli/simple-commands/sparc.js +465 -493
- package/dist/src/cli/simple-commands/start-ui.js +108 -132
- package/dist/src/cli/simple-commands/start-wrapper.js +240 -268
- package/dist/src/cli/simple-commands/start.js +1 -1
- package/dist/src/cli/simple-commands/status.js +254 -275
- package/dist/src/cli/simple-commands/stream-chain-clean.js +128 -171
- package/dist/src/cli/simple-commands/stream-chain-fixed.js +61 -82
- package/dist/src/cli/simple-commands/stream-chain-real.js +267 -331
- package/dist/src/cli/simple-commands/stream-chain-working.js +211 -263
- package/dist/src/cli/simple-commands/stream-chain.js +260 -318
- package/dist/src/cli/simple-commands/stream-processor.js +290 -315
- package/dist/src/cli/simple-commands/swarm-executor.js +189 -222
- package/dist/src/cli/simple-commands/swarm-metrics-integration.js +208 -300
- package/dist/src/cli/simple-commands/swarm-ui.js +623 -703
- package/dist/src/cli/simple-commands/swarm-webui-integration.js +258 -286
- package/dist/src/cli/simple-commands/swarm.js +887 -1082
- package/dist/src/cli/simple-commands/task.js +161 -206
- package/dist/src/cli/simple-commands/timestamp-fix.js +59 -89
- package/dist/src/cli/simple-commands/token-tracker.js +258 -316
- package/dist/src/cli/simple-commands/tool-execution-framework.js +433 -519
- package/dist/src/cli/simple-commands/train-and-stream.js +275 -331
- package/dist/src/cli/simple-commands/training-pipeline.js +619 -725
- package/dist/src/cli/simple-commands/training.js +170 -227
- package/dist/src/cli/simple-commands/verification-hooks.js +261 -284
- package/dist/src/cli/simple-commands/verification-integration.js +389 -417
- package/dist/src/cli/simple-commands/verification-training-integration.js +486 -606
- package/dist/src/cli/simple-commands/verification.js +493 -513
- package/dist/src/cli/simple-commands/web-server.js +766 -836
- package/dist/src/cli/simple-commands/webui-validator.js +106 -124
- package/dist/src/coordination/event-bus/demo-wasm-integration.js +212 -251
- package/dist/src/coordination/event-bus/qe-event-bus.js +608 -748
- package/dist/src/coordination/event-bus/qe-event-bus.test.js +379 -454
- package/dist/src/coordination/iteration-tracker.js +363 -454
- package/dist/src/enterprise/analytics-manager.js +1135 -0
- package/dist/src/enterprise/audit-manager.js +1115 -0
- package/dist/src/enterprise/cloud-manager.js +891 -0
- package/dist/src/enterprise/deployment-manager.js +966 -0
- package/dist/src/enterprise/index.js +6 -0
- package/dist/src/enterprise/project-manager.js +584 -0
- package/dist/src/enterprise/security-manager.js +991 -0
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/DEPRECATED.js +46 -60
- package/dist/src/mcp/fixes/mcp-error-fixes.js +115 -134
- package/dist/src/mcp/implementations/agent-tracker.js +114 -128
- package/dist/src/mcp/implementations/daa-tools.js +292 -350
- package/dist/src/mcp/implementations/workflow-tools.js +329 -361
- package/dist/src/mcp/mcp-config-manager.js +1183 -1331
- package/dist/src/mcp/mcp-server-novice-simplified.js +11 -17
- package/dist/src/mcp/mcp-server-novice.js +11 -17
- package/dist/src/mcp/mcp-server-sdk.js +11 -17
- package/dist/src/mcp/mcp-server.js +1620 -1484
- package/dist/src/mcp/ruv-swarm-wrapper.js +209 -239
- package/dist/src/memory/advanced-serializer.js +609 -589
- package/dist/src/memory/enhanced-examples.js +220 -305
- package/dist/src/memory/enhanced-memory.js +295 -336
- package/dist/src/memory/enhanced-session-serializer.js +408 -492
- package/dist/src/memory/fallback-memory-system.js +900 -1021
- package/dist/src/memory/fallback-store.js +93 -131
- package/dist/src/memory/high-performance-serialization.js +592 -730
- package/dist/src/memory/in-memory-store.js +161 -213
- package/dist/src/memory/index.js +123 -157
- package/dist/src/memory/lock-free-structures.js +578 -764
- package/dist/src/memory/memory-mapped-persistence.js +585 -766
- package/dist/src/memory/memory-pressure-manager.js +569 -707
- package/dist/src/memory/migration.js +358 -445
- package/dist/src/memory/shared-memory.js +641 -768
- package/dist/src/memory/sqlite-store.js +245 -325
- package/dist/src/memory/sqlite-wrapper.js +122 -151
- package/dist/src/memory/swarm-memory.js +470 -603
- package/dist/src/memory/test-example.js +126 -134
- package/dist/src/memory/ultra-fast-memory-store.js +622 -821
- package/dist/src/memory/unified-memory-manager.js +356 -437
- package/dist/src/migration/index.js +92 -0
- package/dist/src/migration/logger.js +121 -0
- package/dist/src/migration/migration-analyzer.js +268 -0
- package/dist/src/migration/migration-runner.js +522 -0
- package/dist/src/migration/migration-validator.js +285 -0
- package/dist/src/migration/progress-reporter.js +150 -0
- package/dist/src/migration/rollback-manager.js +321 -0
- package/dist/src/migration/tests/migration-system.test.js +7 -0
- package/dist/src/migration/types.js +3 -0
- package/dist/src/swarm/CodeRefactoringSwarm.js +777 -952
- package/dist/src/swarm/__tests__/integration.test.js +227 -0
- package/dist/src/swarm/__tests__/prompt-copier.test.js +344 -0
- package/dist/src/swarm/advanced-orchestrator.js +1095 -0
- package/dist/src/swarm/claude-code-interface.js +961 -0
- package/dist/src/swarm/claude-flow-executor.js +229 -0
- package/dist/src/swarm/consensus-coordinator.js +475 -0
- package/dist/src/swarm/coordinator.js +2993 -0
- package/dist/src/swarm/direct-executor.js +1180 -0
- package/dist/src/swarm/error-recovery/advanced-error-detection.js +691 -0
- package/dist/src/swarm/error-recovery/automated-recovery-workflows.js +998 -0
- package/dist/src/swarm/error-recovery/error-recovery-coordinator.js +1197 -0
- package/dist/src/swarm/error-recovery/recovery-monitoring.js +772 -0
- package/dist/src/swarm/error-recovery/resilience-architecture.js +714 -0
- package/dist/src/swarm/error-recovery/self-healing-mechanisms.js +1319 -0
- package/dist/src/swarm/error-recovery/test-error-recovery-effectiveness.js +808 -0
- package/dist/src/swarm/executor-v2.js +322 -0
- package/dist/src/swarm/executor.js +815 -0
- package/dist/src/swarm/hive-mind-integration.js +703 -0
- package/dist/src/swarm/index.js +41 -0
- package/dist/src/swarm/json-output-aggregator.js +267 -0
- package/dist/src/swarm/large-scale-coordinator.js +542 -0
- package/dist/src/swarm/mcp-integration-wrapper.js +628 -0
- package/dist/src/swarm/memory.js +1117 -0
- package/dist/src/swarm/optimizations/__tests__/optimization.test.js +348 -0
- package/dist/src/swarm/optimizations/async-file-manager.js +285 -0
- package/dist/src/swarm/optimizations/circular-buffer.js +162 -0
- package/dist/src/swarm/optimizations/connection-pool.js +244 -0
- package/dist/src/swarm/optimizations/index.js +28 -0
- package/dist/src/swarm/optimizations/optimized-executor.js +320 -0
- package/dist/src/swarm/optimizations/ttl-map.js +234 -0
- package/dist/src/swarm/prompt-cli.js +200 -0
- package/dist/src/swarm/prompt-copier-enhanced.js +202 -0
- package/dist/src/swarm/prompt-copier.js +381 -0
- package/dist/src/swarm/prompt-manager.js +295 -0
- package/dist/src/swarm/prompt-utils.js +310 -0
- package/dist/src/swarm/result-aggregator.js +718 -0
- package/dist/src/swarm/sparc-executor.js +1568 -0
- package/dist/src/swarm/strategies/auto.js +758 -0
- package/dist/src/swarm/strategies/base.js +128 -0
- package/dist/src/swarm/strategies/research.js +914 -0
- package/dist/src/swarm/strategies/strategy-metrics-patch.js +2 -0
- package/dist/src/swarm/types.js +52 -0
- package/dist/src/swarm/workers/copy-worker.js +56 -0
- package/dist/src/utils/__tests__/github-cli-safety-wrapper.test.js +332 -400
- package/dist/src/utils/github-cli-safe.js +56 -64
- package/dist/src/utils/github-cli-safety-wrapper.js +451 -546
- package/dist/src/utils/npx-isolated-cache.js +104 -119
- package/dist/src/utils/preference-manager.js +622 -652
- package/dist/src/utils/timezone-utils.js +86 -105
- package/dist/src/validators/epic-config-schema.js +214 -0
- package/dist/src/validators/index.js +10 -0
- package/dist/src/validators/swarm-init-validator.js +259 -0
- package/dist/src/validators/todowrite-batching-validator.js +215 -0
- package/dist/src/validators/todowrite-integration.js +187 -0
- package/package.json +2 -2
|
@@ -14,596 +14,501 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @version 2.0.0
|
|
16
16
|
* @license MIT
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { spawn, execSync } from 'child_process';
|
|
24
|
-
import { performance } from 'perf_hooks';
|
|
25
|
-
|
|
17
|
+
*/ import { promises as fs } from "fs";
|
|
18
|
+
import { tmpdir } from "os";
|
|
19
|
+
import { resolve } from "path";
|
|
20
|
+
import { randomBytes } from "crypto";
|
|
21
|
+
import { spawn, execSync } from "child_process";
|
|
22
|
+
import { performance } from "perf_hooks";
|
|
26
23
|
/**
|
|
27
24
|
* Configuration constants
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
],
|
|
25
|
+
*/ const CONFIG = {
|
|
26
|
+
DEFAULT_TIMEOUT: 30000,
|
|
27
|
+
MAX_TIMEOUT: 300000,
|
|
28
|
+
MAX_RETRIES: 3,
|
|
29
|
+
RETRY_BASE_DELAY: 1000,
|
|
30
|
+
MAX_BODY_SIZE: 1024 * 1024,
|
|
31
|
+
RATE_LIMIT_WINDOW: 60000,
|
|
32
|
+
MAX_REQUESTS_PER_WINDOW: 50,
|
|
33
|
+
TEMP_FILE_PREFIX: 'gh-safe-',
|
|
34
|
+
ALLOWED_COMMANDS: [
|
|
35
|
+
'auth',
|
|
36
|
+
'repo',
|
|
37
|
+
'issue',
|
|
38
|
+
'pr',
|
|
39
|
+
'release',
|
|
40
|
+
'gist',
|
|
41
|
+
'run',
|
|
42
|
+
'workflow',
|
|
43
|
+
'api',
|
|
44
|
+
'browse',
|
|
45
|
+
'config',
|
|
46
|
+
'extension',
|
|
47
|
+
'gpg-key',
|
|
48
|
+
'label',
|
|
49
|
+
'project',
|
|
50
|
+
'secret',
|
|
51
|
+
'ssh-key',
|
|
52
|
+
'status',
|
|
53
|
+
'variable',
|
|
54
|
+
'cache',
|
|
55
|
+
'codespace'
|
|
56
|
+
],
|
|
57
|
+
DANGEROUS_PATTERNS: [
|
|
58
|
+
/\$\([^)]*\)/g,
|
|
59
|
+
/`[^`]*`/g,
|
|
60
|
+
/&&|\|\||;|&/g,
|
|
61
|
+
/<\(/g,
|
|
62
|
+
/>\s*\/dev\/null/g,
|
|
63
|
+
/\|\s*sh/g,
|
|
64
|
+
/eval\s*\(/g,
|
|
65
|
+
/exec\s*\(/g
|
|
66
|
+
]
|
|
71
67
|
};
|
|
72
|
-
|
|
73
68
|
/**
|
|
74
69
|
* Custom error classes for better error handling
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
class GitHubCliValidationError extends GitHubCliError {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
*/ let GitHubCliError = class GitHubCliError extends Error {
|
|
71
|
+
constructor(message, code = 'GITHUB_CLI_ERROR', details = {}){
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = 'GitHubCliError';
|
|
74
|
+
this.code = code;
|
|
75
|
+
this.details = details;
|
|
76
|
+
this.timestamp = new Date().toISOString();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
let GitHubCliTimeoutError = class GitHubCliTimeoutError extends GitHubCliError {
|
|
80
|
+
constructor(timeout, command){
|
|
81
|
+
super(`Command timed out after ${timeout}ms: ${command}`, 'TIMEOUT', {
|
|
82
|
+
timeout,
|
|
83
|
+
command
|
|
84
|
+
});
|
|
85
|
+
this.name = 'GitHubCliTimeoutError';
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
let GitHubCliValidationError = class GitHubCliValidationError extends GitHubCliError {
|
|
89
|
+
constructor(message, field, value){
|
|
90
|
+
super(message, 'VALIDATION_ERROR', {
|
|
91
|
+
field,
|
|
92
|
+
value
|
|
93
|
+
});
|
|
94
|
+
this.name = 'GitHubCliValidationError';
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
let GitHubCliRateLimitError = class GitHubCliRateLimitError extends GitHubCliError {
|
|
98
|
+
constructor(message){
|
|
99
|
+
super(message, 'RATE_LIMIT_ERROR');
|
|
100
|
+
this.name = 'GitHubCliRateLimitError';
|
|
101
|
+
}
|
|
102
|
+
};
|
|
107
103
|
/**
|
|
108
104
|
* Rate limiter to prevent API abuse
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (this.requests.length >= this.maxRequests) {
|
|
122
|
-
const oldestRequest = Math.min(...this.requests);
|
|
123
|
-
const resetTime = oldestRequest + this.windowMs;
|
|
124
|
-
const waitTime = resetTime - now;
|
|
125
|
-
|
|
126
|
-
throw new GitHubCliRateLimitError(
|
|
127
|
-
`Rate limit exceeded. Try again in ${Math.ceil(waitTime / 1000)} seconds`,
|
|
128
|
-
);
|
|
105
|
+
*/ let RateLimiter = class RateLimiter {
|
|
106
|
+
async checkLimit() {
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
this.requests = this.requests.filter((time)=>now - time < this.windowMs);
|
|
109
|
+
if (this.requests.length >= this.maxRequests) {
|
|
110
|
+
const oldestRequest = Math.min(...this.requests);
|
|
111
|
+
const resetTime = oldestRequest + this.windowMs;
|
|
112
|
+
const waitTime = resetTime - now;
|
|
113
|
+
throw new GitHubCliRateLimitError(`Rate limit exceeded. Try again in ${Math.ceil(waitTime / 1000)} seconds`);
|
|
114
|
+
}
|
|
115
|
+
this.requests.push(now);
|
|
129
116
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
constructor(maxRequests = CONFIG.MAX_REQUESTS_PER_WINDOW, windowMs = CONFIG.RATE_LIMIT_WINDOW){
|
|
118
|
+
this.maxRequests = maxRequests;
|
|
119
|
+
this.windowMs = windowMs;
|
|
120
|
+
this.requests = [];
|
|
121
|
+
}
|
|
122
|
+
};
|
|
135
123
|
/**
|
|
136
124
|
* Main GitHub CLI Safety Wrapper Class
|
|
137
|
-
*/
|
|
138
|
-
|
|
139
|
-
constructor(options = {}) {
|
|
140
|
-
this.options = {
|
|
141
|
-
timeout: options.timeout || CONFIG.DEFAULT_TIMEOUT,
|
|
142
|
-
maxRetries: options.maxRetries || CONFIG.MAX_RETRIES,
|
|
143
|
-
retryDelay: options.retryDelay || CONFIG.RETRY_BASE_DELAY,
|
|
144
|
-
enableRateLimit: options.enableRateLimit !== false,
|
|
145
|
-
enableLogging: options.enableLogging !== false,
|
|
146
|
-
tempDir: options.tempDir || tmpdir(),
|
|
147
|
-
...options,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
this.rateLimiter = new RateLimiter();
|
|
151
|
-
this.activeProcesses = new Map();
|
|
152
|
-
this.stats = {
|
|
153
|
-
totalRequests: 0,
|
|
154
|
-
successfulRequests: 0,
|
|
155
|
-
failedRequests: 0,
|
|
156
|
-
timeoutRequests: 0,
|
|
157
|
-
retriedRequests: 0,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
125
|
+
*/ export class GitHubCliSafe {
|
|
126
|
+
/**
|
|
162
127
|
* Input validation and sanitization
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
throw new GitHubCliValidationError(
|
|
174
|
-
`Command '${mainCommand}' is not allowed`,
|
|
175
|
-
'command',
|
|
176
|
-
mainCommand,
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return command;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
sanitizeInput(input) {
|
|
184
|
-
if (typeof input !== 'string') {
|
|
185
|
-
input = String(input);
|
|
128
|
+
*/ validateCommand(command) {
|
|
129
|
+
if (typeof command !== 'string' || !command.trim()) {
|
|
130
|
+
throw new GitHubCliValidationError('Command must be a non-empty string', 'command', command);
|
|
131
|
+
}
|
|
132
|
+
const parts = command.trim().split(' ');
|
|
133
|
+
const mainCommand = parts[0];
|
|
134
|
+
if (!CONFIG.ALLOWED_COMMANDS.includes(mainCommand)) {
|
|
135
|
+
throw new GitHubCliValidationError(`Command '${mainCommand}' is not allowed`, 'command', mainCommand);
|
|
136
|
+
}
|
|
137
|
+
return command;
|
|
186
138
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
139
|
+
sanitizeInput(input) {
|
|
140
|
+
if (typeof input !== 'string') {
|
|
141
|
+
input = String(input);
|
|
142
|
+
}
|
|
143
|
+
// Check for dangerous patterns
|
|
144
|
+
for (const pattern of CONFIG.DANGEROUS_PATTERNS){
|
|
145
|
+
if (pattern.test(input)) {
|
|
146
|
+
throw new GitHubCliValidationError(`Input contains potentially dangerous pattern: ${pattern}`, 'input', input);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return input;
|
|
197
150
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
validateBodySize(body) {
|
|
203
|
-
if (Buffer.byteLength(body, 'utf8') > CONFIG.MAX_BODY_SIZE) {
|
|
204
|
-
throw new GitHubCliValidationError(
|
|
205
|
-
`Body size exceeds maximum allowed size of ${CONFIG.MAX_BODY_SIZE} bytes`,
|
|
206
|
-
'body',
|
|
207
|
-
body.length,
|
|
208
|
-
);
|
|
151
|
+
validateBodySize(body) {
|
|
152
|
+
if (Buffer.byteLength(body, 'utf8') > CONFIG.MAX_BODY_SIZE) {
|
|
153
|
+
throw new GitHubCliValidationError(`Body size exceeds maximum allowed size of ${CONFIG.MAX_BODY_SIZE} bytes`, 'body', body.length);
|
|
154
|
+
}
|
|
209
155
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
/**
|
|
156
|
+
/**
|
|
213
157
|
* Secure temporary file handling
|
|
214
|
-
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return filepath;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
async cleanupTempFile(filepath) {
|
|
229
|
-
try {
|
|
230
|
-
await fs.unlink(filepath);
|
|
231
|
-
} catch (error) {
|
|
232
|
-
if (this.options.enableLogging) {
|
|
233
|
-
console.warn(`Failed to cleanup temp file ${filepath}:`, error.message);
|
|
234
|
-
}
|
|
158
|
+
*/ async createSecureTempFile(content, suffix = '.tmp') {
|
|
159
|
+
const filename = `${CONFIG.TEMP_FILE_PREFIX}${randomBytes(16).toString('hex')}${suffix}`;
|
|
160
|
+
const filepath = resolve(this.options.tempDir, filename);
|
|
161
|
+
// Validate content size
|
|
162
|
+
this.validateBodySize(content);
|
|
163
|
+
// Create file with restricted permissions (600 - owner read/write only)
|
|
164
|
+
await fs.writeFile(filepath, content, {
|
|
165
|
+
mode: 0o600
|
|
166
|
+
});
|
|
167
|
+
return filepath;
|
|
235
168
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const processId = randomBytes(8).toString('hex');
|
|
244
|
-
|
|
245
|
-
return new Promise((resolve, reject) => {
|
|
246
|
-
const startTime = performance.now();
|
|
247
|
-
|
|
248
|
-
const child = spawn('gh', args, {
|
|
249
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
250
|
-
shell: false, // Critical: prevent shell injection
|
|
251
|
-
env: { ...process.env, ...options.env },
|
|
252
|
-
cwd: options.cwd || process.cwd(),
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
this.activeProcesses.set(processId, child);
|
|
256
|
-
|
|
257
|
-
let stdout = '';
|
|
258
|
-
let stderr = '';
|
|
259
|
-
let isTimedOut = false;
|
|
260
|
-
let isResolved = false;
|
|
261
|
-
|
|
262
|
-
// Timeout handler
|
|
263
|
-
const timer = setTimeout(() => {
|
|
264
|
-
if (!isResolved) {
|
|
265
|
-
isTimedOut = true;
|
|
266
|
-
this.killProcess(child, processId);
|
|
267
|
-
this.stats.timeoutRequests++;
|
|
268
|
-
reject(new GitHubCliTimeoutError(timeout, `gh ${args.join(' ')}`));
|
|
269
|
-
}
|
|
270
|
-
}, timeout);
|
|
271
|
-
|
|
272
|
-
// Data handlers
|
|
273
|
-
child.stdout?.on('data', (data) => {
|
|
274
|
-
stdout += data.toString();
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
child.stderr?.on('data', (data) => {
|
|
278
|
-
stderr += data.toString();
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// Process completion handler
|
|
282
|
-
child.on('close', (code, signal) => {
|
|
283
|
-
if (isResolved) return;
|
|
284
|
-
|
|
285
|
-
isResolved = true;
|
|
286
|
-
clearTimeout(timer);
|
|
287
|
-
this.activeProcesses.delete(processId);
|
|
288
|
-
|
|
289
|
-
const duration = performance.now() - startTime;
|
|
290
|
-
|
|
291
|
-
if (isTimedOut) {
|
|
292
|
-
return; // Already handled by timeout
|
|
169
|
+
async cleanupTempFile(filepath) {
|
|
170
|
+
try {
|
|
171
|
+
await fs.unlink(filepath);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (this.options.enableLogging) {
|
|
174
|
+
console.warn(`Failed to cleanup temp file ${filepath}:`, error.message);
|
|
175
|
+
}
|
|
293
176
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Process management with timeout and cleanup
|
|
180
|
+
*/ async executeWithTimeout(command, args, options = {}) {
|
|
181
|
+
const timeout = Math.min(options.timeout || this.options.timeout, CONFIG.MAX_TIMEOUT);
|
|
182
|
+
const processId = randomBytes(8).toString('hex');
|
|
183
|
+
return new Promise((resolve, reject)=>{
|
|
184
|
+
const startTime = performance.now();
|
|
185
|
+
const child = spawn('gh', args, {
|
|
186
|
+
stdio: [
|
|
187
|
+
'ignore',
|
|
188
|
+
'pipe',
|
|
189
|
+
'pipe'
|
|
190
|
+
],
|
|
191
|
+
shell: false,
|
|
192
|
+
env: {
|
|
193
|
+
...process.env,
|
|
194
|
+
...options.env
|
|
195
|
+
},
|
|
196
|
+
cwd: options.cwd || process.cwd()
|
|
197
|
+
});
|
|
198
|
+
this.activeProcesses.set(processId, child);
|
|
199
|
+
let stdout = '';
|
|
200
|
+
let stderr = '';
|
|
201
|
+
let isTimedOut = false;
|
|
202
|
+
let isResolved = false;
|
|
203
|
+
// Timeout handler
|
|
204
|
+
const timer = setTimeout(()=>{
|
|
205
|
+
if (!isResolved) {
|
|
206
|
+
isTimedOut = true;
|
|
207
|
+
this.killProcess(child, processId);
|
|
208
|
+
this.stats.timeoutRequests++;
|
|
209
|
+
reject(new GitHubCliTimeoutError(timeout, `gh ${args.join(' ')}`));
|
|
210
|
+
}
|
|
211
|
+
}, timeout);
|
|
212
|
+
// Data handlers
|
|
213
|
+
child.stdout?.on('data', (data)=>{
|
|
214
|
+
stdout += data.toString();
|
|
215
|
+
});
|
|
216
|
+
child.stderr?.on('data', (data)=>{
|
|
217
|
+
stderr += data.toString();
|
|
218
|
+
});
|
|
219
|
+
// Process completion handler
|
|
220
|
+
child.on('close', (code, signal)=>{
|
|
221
|
+
if (isResolved) return;
|
|
222
|
+
isResolved = true;
|
|
223
|
+
clearTimeout(timer);
|
|
224
|
+
this.activeProcesses.delete(processId);
|
|
225
|
+
const duration = performance.now() - startTime;
|
|
226
|
+
if (isTimedOut) {
|
|
227
|
+
return; // Already handled by timeout
|
|
228
|
+
}
|
|
229
|
+
if (signal === 'SIGKILL' || signal === 'SIGTERM') {
|
|
230
|
+
reject(new GitHubCliError(`Process terminated by signal ${signal}`, 'PROCESS_TERMINATED', {
|
|
231
|
+
signal,
|
|
232
|
+
code,
|
|
233
|
+
duration
|
|
234
|
+
}));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (code !== 0) {
|
|
238
|
+
this.stats.failedRequests++;
|
|
239
|
+
reject(new GitHubCliError(`Command failed with exit code ${code}: ${stderr || 'No error details'}`, 'COMMAND_FAILED', {
|
|
240
|
+
code,
|
|
241
|
+
stderr,
|
|
242
|
+
stdout,
|
|
243
|
+
duration,
|
|
244
|
+
command: `gh ${args.join(' ')}`
|
|
245
|
+
}));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
this.stats.successfulRequests++;
|
|
249
|
+
resolve({
|
|
250
|
+
stdout: stdout.trim(),
|
|
251
|
+
stderr: stderr.trim(),
|
|
252
|
+
code,
|
|
253
|
+
duration,
|
|
254
|
+
command: `gh ${args.join(' ')}`
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
// Error handler
|
|
258
|
+
child.on('error', (error)=>{
|
|
259
|
+
if (isResolved) return;
|
|
260
|
+
isResolved = true;
|
|
261
|
+
clearTimeout(timer);
|
|
262
|
+
this.activeProcesses.delete(processId);
|
|
263
|
+
this.stats.failedRequests++;
|
|
264
|
+
reject(new GitHubCliError(`Process error: ${error.message}`, 'PROCESS_ERROR', {
|
|
265
|
+
originalError: error
|
|
266
|
+
}));
|
|
267
|
+
});
|
|
325
268
|
});
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
killProcess(child, processId) {
|
|
347
|
-
try {
|
|
348
|
-
// Graceful termination first
|
|
349
|
-
child.kill('SIGTERM');
|
|
350
|
-
|
|
351
|
-
// Force kill after 5 seconds if still running
|
|
352
|
-
setTimeout(() => {
|
|
353
|
-
if (this.activeProcesses.has(processId)) {
|
|
354
|
-
child.kill('SIGKILL');
|
|
355
|
-
this.activeProcesses.delete(processId);
|
|
269
|
+
}
|
|
270
|
+
killProcess(child, processId) {
|
|
271
|
+
try {
|
|
272
|
+
// Graceful termination first
|
|
273
|
+
child.kill('SIGTERM');
|
|
274
|
+
// Force kill after 5 seconds if still running
|
|
275
|
+
setTimeout(()=>{
|
|
276
|
+
if (this.activeProcesses.has(processId)) {
|
|
277
|
+
child.kill('SIGKILL');
|
|
278
|
+
this.activeProcesses.delete(processId);
|
|
279
|
+
}
|
|
280
|
+
}, 5000);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (this.options.enableLogging) {
|
|
283
|
+
console.warn(`Failed to kill process ${processId}:`, error.message);
|
|
284
|
+
}
|
|
356
285
|
}
|
|
357
|
-
}, 5000);
|
|
358
|
-
} catch (error) {
|
|
359
|
-
if (this.options.enableLogging) {
|
|
360
|
-
console.warn(`Failed to kill process ${processId}:`, error.message);
|
|
361
|
-
}
|
|
362
286
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
/**
|
|
287
|
+
/**
|
|
366
288
|
* Retry logic with exponential backoff
|
|
367
|
-
*/
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
289
|
+
*/ async withRetry(operation, maxRetries = this.options.maxRetries) {
|
|
290
|
+
let lastError;
|
|
291
|
+
for(let attempt = 0; attempt <= maxRetries; attempt++){
|
|
292
|
+
try {
|
|
293
|
+
if (attempt > 0) {
|
|
294
|
+
this.stats.retriedRequests++;
|
|
295
|
+
const delay = this.options.retryDelay * Math.pow(2, attempt - 1);
|
|
296
|
+
await this.sleep(delay);
|
|
297
|
+
}
|
|
298
|
+
return await operation();
|
|
299
|
+
} catch (error) {
|
|
300
|
+
lastError = error;
|
|
301
|
+
// Don't retry on validation errors or rate limits
|
|
302
|
+
if (error instanceof GitHubCliValidationError || error instanceof GitHubCliRateLimitError) {
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
if (attempt === maxRetries) {
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
if (this.options.enableLogging) {
|
|
309
|
+
console.warn(`Attempt ${attempt + 1} failed, retrying:`, error.message);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
390
312
|
}
|
|
391
|
-
|
|
392
|
-
if (this.options.enableLogging) {
|
|
393
|
-
console.warn(`Attempt ${attempt + 1} failed, retrying:`, error.message);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
313
|
+
throw lastError;
|
|
396
314
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
async sleep(ms) {
|
|
402
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Core execution method with all safety features
|
|
407
|
-
*/
|
|
408
|
-
async execute(command, options = {}) {
|
|
409
|
-
this.stats.totalRequests++;
|
|
410
|
-
|
|
411
|
-
// Rate limiting check
|
|
412
|
-
if (this.options.enableRateLimit) {
|
|
413
|
-
await this.rateLimiter.checkLimit();
|
|
315
|
+
async sleep(ms) {
|
|
316
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
414
317
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Core execution method with all safety features
|
|
320
|
+
*/ async execute(command, options = {}) {
|
|
321
|
+
this.stats.totalRequests++;
|
|
322
|
+
// Rate limiting check
|
|
323
|
+
if (this.options.enableRateLimit) {
|
|
324
|
+
await this.rateLimiter.checkLimit();
|
|
325
|
+
}
|
|
326
|
+
// Validate and sanitize command
|
|
327
|
+
const validatedCommand = this.validateCommand(command);
|
|
328
|
+
const args = validatedCommand.split(' ');
|
|
329
|
+
// Handle body content if provided
|
|
330
|
+
let tempFile = null;
|
|
331
|
+
try {
|
|
332
|
+
if (options.body) {
|
|
333
|
+
const sanitizedBody = this.sanitizeInput(options.body);
|
|
334
|
+
tempFile = await this.createSecureTempFile(sanitizedBody);
|
|
335
|
+
args.push('--body-file', tempFile);
|
|
336
|
+
}
|
|
337
|
+
// Add other options
|
|
338
|
+
if (options.title) {
|
|
339
|
+
args.push('--title', this.sanitizeInput(options.title));
|
|
340
|
+
}
|
|
341
|
+
if (options.labels && Array.isArray(options.labels)) {
|
|
342
|
+
const sanitizedLabels = options.labels.map((label)=>this.sanitizeInput(label));
|
|
343
|
+
args.push('--label', sanitizedLabels.join(','));
|
|
344
|
+
}
|
|
345
|
+
if (options.assignees && Array.isArray(options.assignees)) {
|
|
346
|
+
const sanitizedAssignees = options.assignees.map((assignee)=>this.sanitizeInput(assignee));
|
|
347
|
+
args.push('--assignee', sanitizedAssignees.join(','));
|
|
348
|
+
}
|
|
349
|
+
// Add any additional flags
|
|
350
|
+
if (options.flags) {
|
|
351
|
+
for (const [flag, value] of Object.entries(options.flags)){
|
|
352
|
+
args.push(`--${flag}`);
|
|
353
|
+
if (value !== true) {
|
|
354
|
+
args.push(this.sanitizeInput(String(value)));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Execute with retry logic
|
|
359
|
+
return await this.withRetry(async ()=>{
|
|
360
|
+
return await this.executeWithTimeout(validatedCommand, args.slice(1), options);
|
|
361
|
+
});
|
|
362
|
+
} finally{
|
|
363
|
+
// Always cleanup temp file
|
|
364
|
+
if (tempFile) {
|
|
365
|
+
await this.cleanupTempFile(tempFile);
|
|
366
|
+
}
|
|
453
367
|
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Execute with retry logic
|
|
457
|
-
return await this.withRetry(async () => {
|
|
458
|
-
return await this.executeWithTimeout(validatedCommand, args.slice(1), options);
|
|
459
|
-
});
|
|
460
|
-
} finally {
|
|
461
|
-
// Always cleanup temp file
|
|
462
|
-
if (tempFile) {
|
|
463
|
-
await this.cleanupTempFile(tempFile);
|
|
464
|
-
}
|
|
465
368
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
/**
|
|
369
|
+
/**
|
|
469
370
|
* High-level methods for common GitHub operations
|
|
470
|
-
*/
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
})
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
371
|
+
*/ async createIssue({ title, body, labels = [], assignees = [], ...options }) {
|
|
372
|
+
return await this.execute('issue create', {
|
|
373
|
+
title,
|
|
374
|
+
body,
|
|
375
|
+
labels,
|
|
376
|
+
assignees,
|
|
377
|
+
...options
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
async createPR({ title, body, base = 'main', head, draft = false, ...options }) {
|
|
381
|
+
const flags = {
|
|
382
|
+
base
|
|
383
|
+
};
|
|
384
|
+
if (head) flags.head = head;
|
|
385
|
+
if (draft) flags.draft = true;
|
|
386
|
+
return await this.execute('pr create', {
|
|
387
|
+
title,
|
|
388
|
+
body,
|
|
389
|
+
flags,
|
|
390
|
+
...options
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
async addIssueComment(issueNumber, body, options = {}) {
|
|
394
|
+
return await this.execute(`issue comment ${issueNumber}`, {
|
|
395
|
+
body,
|
|
396
|
+
...options
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
async addPRComment(prNumber, body, options = {}) {
|
|
400
|
+
return await this.execute(`pr comment ${prNumber}`, {
|
|
401
|
+
body,
|
|
402
|
+
...options
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
async createRelease({ tag, title, body, prerelease = false, draft = false, ...options }) {
|
|
406
|
+
const flags = {
|
|
407
|
+
tag
|
|
408
|
+
};
|
|
409
|
+
if (prerelease) flags.prerelease = true;
|
|
410
|
+
if (draft) flags.draft = true;
|
|
411
|
+
return await this.execute('release create', {
|
|
412
|
+
title,
|
|
413
|
+
body,
|
|
414
|
+
flags,
|
|
415
|
+
...options
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
522
419
|
* Utility methods
|
|
523
|
-
*/
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
420
|
+
*/ async checkGitHubCli() {
|
|
421
|
+
try {
|
|
422
|
+
execSync('gh --version', {
|
|
423
|
+
stdio: 'ignore'
|
|
424
|
+
});
|
|
425
|
+
return true;
|
|
426
|
+
} catch {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
530
429
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
430
|
+
async checkAuthentication() {
|
|
431
|
+
try {
|
|
432
|
+
const result = await this.execute('auth status');
|
|
433
|
+
return result.code === 0;
|
|
434
|
+
} catch {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
getStats() {
|
|
439
|
+
return {
|
|
440
|
+
...this.stats
|
|
441
|
+
};
|
|
539
442
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
443
|
+
getActiveProcessCount() {
|
|
444
|
+
return this.activeProcesses.size;
|
|
445
|
+
}
|
|
446
|
+
async cleanup() {
|
|
447
|
+
// Kill all active processes
|
|
448
|
+
for (const [processId, child] of this.activeProcesses){
|
|
449
|
+
this.killProcess(child, processId);
|
|
450
|
+
}
|
|
451
|
+
this.activeProcesses.clear();
|
|
452
|
+
}
|
|
453
|
+
constructor(options = {}){
|
|
454
|
+
this.options = {
|
|
455
|
+
timeout: options.timeout || CONFIG.DEFAULT_TIMEOUT,
|
|
456
|
+
maxRetries: options.maxRetries || CONFIG.MAX_RETRIES,
|
|
457
|
+
retryDelay: options.retryDelay || CONFIG.RETRY_BASE_DELAY,
|
|
458
|
+
enableRateLimit: options.enableRateLimit !== false,
|
|
459
|
+
enableLogging: options.enableLogging !== false,
|
|
460
|
+
tempDir: options.tempDir || tmpdir(),
|
|
461
|
+
...options
|
|
462
|
+
};
|
|
463
|
+
this.rateLimiter = new RateLimiter();
|
|
464
|
+
this.activeProcesses = new Map();
|
|
465
|
+
this.stats = {
|
|
466
|
+
totalRequests: 0,
|
|
467
|
+
successfulRequests: 0,
|
|
468
|
+
failedRequests: 0,
|
|
469
|
+
timeoutRequests: 0,
|
|
470
|
+
retriedRequests: 0
|
|
471
|
+
};
|
|
554
472
|
}
|
|
555
|
-
this.activeProcesses.clear();
|
|
556
|
-
}
|
|
557
473
|
}
|
|
558
|
-
|
|
559
474
|
/**
|
|
560
475
|
* Factory function for creating configured instances
|
|
561
|
-
*/
|
|
562
|
-
|
|
563
|
-
return new GitHubCliSafe(options);
|
|
476
|
+
*/ export function createGitHubCliSafe(options = {}) {
|
|
477
|
+
return new GitHubCliSafe(options);
|
|
564
478
|
}
|
|
565
|
-
|
|
566
479
|
/**
|
|
567
480
|
* Default singleton instance
|
|
568
|
-
*/
|
|
569
|
-
export const githubCli = new GitHubCliSafe();
|
|
570
|
-
|
|
481
|
+
*/ export const githubCli = new GitHubCliSafe();
|
|
571
482
|
/**
|
|
572
483
|
* Legacy compatibility functions
|
|
573
|
-
*/
|
|
574
|
-
|
|
575
|
-
|
|
484
|
+
*/ export async function safeGhCommand(command, target, body, options = {}) {
|
|
485
|
+
return await githubCli.execute(`${command} ${target}`, {
|
|
486
|
+
body,
|
|
487
|
+
...options
|
|
488
|
+
});
|
|
576
489
|
}
|
|
577
|
-
|
|
578
490
|
export const gh = {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
async createPR(params) {
|
|
592
|
-
return await githubCli.createPR(params);
|
|
593
|
-
},
|
|
491
|
+
async issueComment (issue, body, options = {}) {
|
|
492
|
+
return await githubCli.addIssueComment(issue, body, options);
|
|
493
|
+
},
|
|
494
|
+
async prComment (pr, body, options = {}) {
|
|
495
|
+
return await githubCli.addPRComment(pr, body, options);
|
|
496
|
+
},
|
|
497
|
+
async createIssue (params) {
|
|
498
|
+
return await githubCli.createIssue(params);
|
|
499
|
+
},
|
|
500
|
+
async createPR (params) {
|
|
501
|
+
return await githubCli.createPR(params);
|
|
502
|
+
}
|
|
594
503
|
};
|
|
595
|
-
|
|
596
504
|
/**
|
|
597
505
|
* Process cleanup on exit
|
|
598
|
-
*/
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
process.exit(0);
|
|
506
|
+
*/ process.on('SIGINT', async ()=>{
|
|
507
|
+
await githubCli.cleanup();
|
|
508
|
+
process.exit(0);
|
|
602
509
|
});
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
process.exit(0);
|
|
510
|
+
process.on('SIGTERM', async ()=>{
|
|
511
|
+
await githubCli.cleanup();
|
|
512
|
+
process.exit(0);
|
|
607
513
|
});
|
|
608
|
-
|
|
609
514
|
export default GitHubCliSafe;
|