awesome-slash 2.4.3 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/.claude-plugin/marketplace.json +6 -6
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +99 -1
  4. package/README.md +173 -161
  5. package/SECURITY.md +25 -81
  6. package/adapters/codex/install.sh +58 -16
  7. package/adapters/opencode/install.sh +92 -23
  8. package/lib/index.js +47 -4
  9. package/lib/patterns/review-patterns.js +58 -11
  10. package/lib/patterns/slop-patterns.js +154 -147
  11. package/lib/platform/detect-platform.js +99 -350
  12. package/lib/platform/detection-configs.js +93 -0
  13. package/lib/platform/verify-tools.js +10 -78
  14. package/lib/schemas/README.md +195 -0
  15. package/lib/schemas/validator.js +247 -0
  16. package/lib/sources/custom-handler.js +199 -0
  17. package/lib/sources/policy-questions.js +239 -0
  18. package/lib/sources/source-cache.js +149 -0
  19. package/lib/state/workflow-state.js +363 -665
  20. package/lib/types/README.md +292 -0
  21. package/lib/types/agent-frontmatter.d.ts +134 -0
  22. package/lib/types/command-frontmatter.d.ts +107 -0
  23. package/lib/types/hook-frontmatter.d.ts +115 -0
  24. package/lib/types/index.d.ts +84 -0
  25. package/lib/types/plugin-manifest.d.ts +102 -0
  26. package/lib/types/skill-frontmatter.d.ts +89 -0
  27. package/lib/utils/cache-manager.js +154 -0
  28. package/lib/utils/context-optimizer.js +5 -36
  29. package/lib/utils/deprecation.js +37 -0
  30. package/lib/utils/shell-escape.js +88 -0
  31. package/mcp-server/index.js +513 -18
  32. package/package.json +6 -2
  33. package/plugins/deslop-around/.claude-plugin/plugin.json +1 -1
  34. package/plugins/deslop-around/lib/index.js +170 -0
  35. package/plugins/deslop-around/lib/patterns/review-patterns.js +58 -11
  36. package/plugins/deslop-around/lib/patterns/slop-patterns.js +170 -129
  37. package/plugins/deslop-around/lib/platform/detect-platform.js +212 -123
  38. package/plugins/deslop-around/lib/platform/detection-configs.js +93 -0
  39. package/plugins/deslop-around/lib/platform/verify-tools.js +10 -1
  40. package/plugins/deslop-around/lib/schemas/README.md +195 -0
  41. package/plugins/deslop-around/lib/schemas/validator.js +205 -0
  42. package/plugins/deslop-around/lib/sources/custom-handler.js +199 -0
  43. package/plugins/deslop-around/lib/sources/policy-questions.js +239 -0
  44. package/plugins/deslop-around/lib/sources/source-cache.js +149 -0
  45. package/plugins/deslop-around/lib/state/workflow-state.js +382 -484
  46. package/plugins/deslop-around/lib/types/README.md +292 -0
  47. package/plugins/deslop-around/lib/types/agent-frontmatter.d.ts +134 -0
  48. package/plugins/deslop-around/lib/types/command-frontmatter.d.ts +107 -0
  49. package/plugins/deslop-around/lib/types/hook-frontmatter.d.ts +115 -0
  50. package/plugins/deslop-around/lib/types/index.d.ts +84 -0
  51. package/plugins/deslop-around/lib/types/plugin-manifest.d.ts +102 -0
  52. package/plugins/deslop-around/lib/types/skill-frontmatter.d.ts +89 -0
  53. package/plugins/deslop-around/lib/utils/cache-manager.js +154 -0
  54. package/plugins/deslop-around/lib/utils/context-optimizer.js +115 -37
  55. package/plugins/deslop-around/lib/utils/deprecation.js +37 -0
  56. package/plugins/deslop-around/lib/utils/shell-escape.js +88 -0
  57. package/plugins/next-task/.claude-plugin/plugin.json +1 -1
  58. package/plugins/next-task/agents/ci-monitor.md +19 -0
  59. package/plugins/next-task/agents/delivery-validator.md +2 -2
  60. package/plugins/next-task/agents/implementation-agent.md +3 -4
  61. package/plugins/next-task/agents/planning-agent.md +77 -19
  62. package/plugins/next-task/agents/review-orchestrator.md +21 -122
  63. package/plugins/next-task/agents/task-discoverer.md +164 -23
  64. package/plugins/next-task/commands/next-task.md +180 -14
  65. package/plugins/next-task/lib/index.js +170 -0
  66. package/plugins/next-task/lib/patterns/review-patterns.js +58 -11
  67. package/plugins/next-task/lib/patterns/slop-patterns.js +170 -129
  68. package/plugins/next-task/lib/platform/detect-platform.js +212 -123
  69. package/plugins/next-task/lib/platform/detection-configs.js +93 -0
  70. package/plugins/next-task/lib/platform/verify-tools.js +10 -1
  71. package/plugins/next-task/lib/schemas/README.md +195 -0
  72. package/plugins/next-task/lib/schemas/validator.js +205 -0
  73. package/plugins/next-task/lib/sources/custom-handler.js +199 -0
  74. package/plugins/next-task/lib/sources/policy-questions.js +239 -0
  75. package/plugins/next-task/lib/sources/source-cache.js +149 -0
  76. package/plugins/next-task/lib/state/workflow-state.js +382 -484
  77. package/plugins/next-task/lib/types/README.md +292 -0
  78. package/plugins/next-task/lib/types/agent-frontmatter.d.ts +134 -0
  79. package/plugins/next-task/lib/types/command-frontmatter.d.ts +107 -0
  80. package/plugins/next-task/lib/types/hook-frontmatter.d.ts +115 -0
  81. package/plugins/next-task/lib/types/index.d.ts +84 -0
  82. package/plugins/next-task/lib/types/plugin-manifest.d.ts +102 -0
  83. package/plugins/next-task/lib/types/skill-frontmatter.d.ts +89 -0
  84. package/plugins/next-task/lib/utils/cache-manager.js +154 -0
  85. package/plugins/next-task/lib/utils/context-optimizer.js +115 -37
  86. package/plugins/next-task/lib/utils/deprecation.js +37 -0
  87. package/plugins/next-task/lib/utils/shell-escape.js +88 -0
  88. package/plugins/project-review/.claude-plugin/plugin.json +1 -1
  89. package/plugins/project-review/lib/index.js +170 -0
  90. package/plugins/project-review/lib/patterns/review-patterns.js +58 -11
  91. package/plugins/project-review/lib/patterns/slop-patterns.js +170 -129
  92. package/plugins/project-review/lib/platform/detect-platform.js +212 -123
  93. package/plugins/project-review/lib/platform/detection-configs.js +93 -0
  94. package/plugins/project-review/lib/platform/verify-tools.js +10 -1
  95. package/plugins/project-review/lib/schemas/README.md +195 -0
  96. package/plugins/project-review/lib/schemas/validator.js +205 -0
  97. package/plugins/project-review/lib/sources/custom-handler.js +199 -0
  98. package/plugins/project-review/lib/sources/policy-questions.js +239 -0
  99. package/plugins/project-review/lib/sources/source-cache.js +149 -0
  100. package/plugins/project-review/lib/state/workflow-state.js +382 -484
  101. package/plugins/project-review/lib/types/README.md +292 -0
  102. package/plugins/project-review/lib/types/agent-frontmatter.d.ts +134 -0
  103. package/plugins/project-review/lib/types/command-frontmatter.d.ts +107 -0
  104. package/plugins/project-review/lib/types/hook-frontmatter.d.ts +115 -0
  105. package/plugins/project-review/lib/types/index.d.ts +84 -0
  106. package/plugins/project-review/lib/types/plugin-manifest.d.ts +102 -0
  107. package/plugins/project-review/lib/types/skill-frontmatter.d.ts +89 -0
  108. package/plugins/project-review/lib/utils/cache-manager.js +154 -0
  109. package/plugins/project-review/lib/utils/context-optimizer.js +115 -37
  110. package/plugins/project-review/lib/utils/deprecation.js +37 -0
  111. package/plugins/project-review/lib/utils/shell-escape.js +88 -0
  112. package/plugins/reality-check/.claude-plugin/plugin.json +1 -1
  113. package/plugins/reality-check/agents/code-explorer.md +1 -1
  114. package/plugins/ship/.claude-plugin/plugin.json +1 -1
  115. package/plugins/ship/commands/ship-ci-review-loop.md +19 -0
  116. package/plugins/ship/lib/index.js +170 -0
  117. package/plugins/ship/lib/patterns/review-patterns.js +58 -11
  118. package/plugins/ship/lib/patterns/slop-patterns.js +170 -129
  119. package/plugins/ship/lib/platform/detect-platform.js +212 -123
  120. package/plugins/ship/lib/platform/detection-configs.js +93 -0
  121. package/plugins/ship/lib/platform/verify-tools.js +10 -1
  122. package/plugins/ship/lib/schemas/README.md +195 -0
  123. package/plugins/ship/lib/schemas/validator.js +205 -0
  124. package/plugins/ship/lib/sources/custom-handler.js +199 -0
  125. package/plugins/ship/lib/sources/policy-questions.js +239 -0
  126. package/plugins/ship/lib/sources/source-cache.js +149 -0
  127. package/plugins/ship/lib/state/workflow-state.js +382 -484
  128. package/plugins/ship/lib/types/README.md +292 -0
  129. package/plugins/ship/lib/types/agent-frontmatter.d.ts +134 -0
  130. package/plugins/ship/lib/types/command-frontmatter.d.ts +107 -0
  131. package/plugins/ship/lib/types/hook-frontmatter.d.ts +115 -0
  132. package/plugins/ship/lib/types/index.d.ts +84 -0
  133. package/plugins/ship/lib/types/plugin-manifest.d.ts +102 -0
  134. package/plugins/ship/lib/types/skill-frontmatter.d.ts +89 -0
  135. package/plugins/ship/lib/utils/cache-manager.js +154 -0
  136. package/plugins/ship/lib/utils/context-optimizer.js +115 -37
  137. package/plugins/ship/lib/utils/deprecation.js +37 -0
  138. package/plugins/ship/lib/utils/shell-escape.js +88 -0
  139. package/lib/state/workflow-state.schema.json +0 -282
  140. package/plugins/deslop-around/lib/state/workflow-state.schema.json +0 -282
  141. package/plugins/next-task/agents/policy-selector.md +0 -248
  142. package/plugins/next-task/lib/state/tasks-registry.schema.json +0 -85
  143. package/plugins/next-task/lib/state/workflow-state.schema.json +0 -282
  144. package/plugins/next-task/lib/state/worktree-status.schema.json +0 -219
  145. package/plugins/project-review/lib/state/workflow-state.schema.json +0 -282
  146. package/plugins/ship/lib/state/workflow-state.schema.json +0 -282
@@ -84,32 +84,74 @@ echo
84
84
  # Install commands with path adjustments
85
85
  echo "⚙️ Installing commands..."
86
86
 
87
- COMMANDS=(
88
- "deslop-around"
89
- "next-task"
90
- "project-review"
91
- "ship"
92
- "pr-merge"
87
+ # Command mappings: target_name:plugin:source_file
88
+ # Format allows commands from different plugins
89
+ COMMAND_MAPPINGS=(
90
+ "deslop-around:deslop-around:deslop-around"
91
+ "next-task:next-task:next-task"
92
+ "delivery-approval:next-task:delivery-approval"
93
+ "update-docs-around:next-task:update-docs-around"
94
+ "project-review:project-review:project-review"
95
+ "ship:ship:ship"
96
+ "reality-check-scan:reality-check:scan"
97
+ "reality-check-set:reality-check:set"
93
98
  )
94
99
 
95
- for cmd in "${COMMANDS[@]}"; do
96
- SOURCE_FILE="$REPO_ROOT/plugins/$cmd/commands/$cmd.md"
97
- # Install directly in prompts directory (Codex looks here)
98
- TARGET_FILE="$CODEX_PROMPTS_DIR/$cmd.md"
100
+ for mapping in "${COMMAND_MAPPINGS[@]}"; do
101
+ IFS=':' read -r TARGET_NAME PLUGIN SOURCE_NAME <<< "$mapping"
102
+ SOURCE_FILE="$REPO_ROOT/plugins/$PLUGIN/commands/$SOURCE_NAME.md"
103
+ TARGET_FILE="$CODEX_PROMPTS_DIR/$TARGET_NAME.md"
99
104
 
100
105
  if [ -f "$SOURCE_FILE" ]; then
101
- # Replace Claude-specific path variables with Codex lib paths
102
- # Escape sed special characters in path to prevent injection
103
- SAFE_LIB_DIR=$(echo "${CODEX_LIB_DIR}/.." | sed 's/[&/\]/\\&/g')
104
- sed "s|\${CLAUDE_PLUGIN_ROOT}|${SAFE_LIB_DIR}|g" "$SOURCE_FILE" > "$TARGET_FILE"
105
- echo " ✓ Installed /prompts:$cmd"
106
+ # Copy command file to prompts directory
107
+ cp "$SOURCE_FILE" "$TARGET_FILE"
108
+ echo " Installed /prompts:$TARGET_NAME"
106
109
  else
107
- echo " ⚠️ Skipped /$cmd (source not found)"
110
+ echo " ⚠️ Skipped /$TARGET_NAME (source not found: $SOURCE_FILE)"
111
+ fi
112
+ done
113
+
114
+ # Remove old/legacy commands that no longer exist
115
+ OLD_COMMANDS=("pr-merge")
116
+ for old_cmd in "${OLD_COMMANDS[@]}"; do
117
+ if [ -f "$CODEX_PROMPTS_DIR/$old_cmd.md" ]; then
118
+ rm "$CODEX_PROMPTS_DIR/$old_cmd.md"
119
+ echo " 🗑️ Removed legacy /prompts:$old_cmd"
108
120
  fi
109
121
  done
110
122
 
111
123
  echo
112
124
 
125
+ # Configure MCP server
126
+ echo "🔌 Configuring MCP server..."
127
+ CONFIG_TOML="$CODEX_CONFIG_DIR/config.toml"
128
+
129
+ # Convert repo path to forward slashes for config
130
+ MCP_PATH="${REPO_ROOT//\\//}"
131
+
132
+ # Check if config.toml exists and has MCP section
133
+ if [ -f "$CONFIG_TOML" ]; then
134
+ # Remove old awesome-slash MCP config if exists
135
+ if grep -q "\[mcp_servers.awesome-slash\]" "$CONFIG_TOML" 2>/dev/null; then
136
+ # Use sed to remove the old section (everything between [mcp_servers.awesome-slash] and next section or EOF)
137
+ sed -i '/\[mcp_servers.awesome-slash\]/,/^\[/{ /^\[mcp_servers.awesome-slash\]/d; /^\[/!d; }' "$CONFIG_TOML" 2>/dev/null || true
138
+ fi
139
+ fi
140
+
141
+ # Append MCP server config
142
+ cat >> "$CONFIG_TOML" << EOF
143
+
144
+ [mcp_servers.awesome-slash]
145
+ command = "node"
146
+ args = ["${MCP_PATH}/mcp-server/index.js"]
147
+
148
+ [mcp_servers.awesome-slash.env]
149
+ PLUGIN_ROOT = "${MCP_PATH}"
150
+ EOF
151
+
152
+ echo " ✓ Added MCP server to config.toml"
153
+ echo
154
+
113
155
  # Create README
114
156
  cat > "$CODEX_CONFIG_DIR/AWESOME_SLASH_README.md" << 'EOF'
115
157
  # awesome-slash for Codex CLI
@@ -9,19 +9,16 @@ echo
9
9
 
10
10
  # Configuration
11
11
  REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
12
+
13
+ # Use $HOME which works correctly on all platforms including Git Bash on Windows
14
+ # (Git Bash sets HOME to Unix-style path like /c/Users/username)
12
15
  OPENCODE_CONFIG_DIR="${HOME}/.opencode"
13
16
  OPENCODE_COMMANDS_DIR="${OPENCODE_CONFIG_DIR}/commands/awesome-slash"
14
17
  LIB_DIR="${OPENCODE_COMMANDS_DIR}/lib"
15
18
 
16
- # Detect OS and normalize paths
17
- if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
19
+ # Detect OS for platform-specific notes
20
+ if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" || "$OSTYPE" == "cygwin" ]]; then
18
21
  IS_WINDOWS=true
19
- # Convert Windows path to Unix-style for bash compatibility
20
- OPENCODE_CONFIG_DIR="${USERPROFILE}/.opencode"
21
- # Replace backslashes with forward slashes
22
- OPENCODE_CONFIG_DIR="${OPENCODE_CONFIG_DIR//\\//}"
23
- OPENCODE_COMMANDS_DIR="${OPENCODE_CONFIG_DIR}/commands/awesome-slash"
24
- LIB_DIR="${OPENCODE_COMMANDS_DIR}/lib"
25
22
  else
26
23
  IS_WINDOWS=false
27
24
  fi
@@ -83,26 +80,39 @@ echo
83
80
  # Install commands with path adjustments
84
81
  echo "⚙️ Installing commands..."
85
82
 
86
- COMMANDS=(
87
- "deslop-around"
88
- "next-task"
89
- "project-review"
90
- "ship"
91
- "pr-merge"
83
+ # Command mappings: target_name:plugin:source_file
84
+ # Format allows commands from different plugins
85
+ COMMAND_MAPPINGS=(
86
+ "deslop-around:deslop-around:deslop-around"
87
+ "next-task:next-task:next-task"
88
+ "delivery-approval:next-task:delivery-approval"
89
+ "update-docs-around:next-task:update-docs-around"
90
+ "project-review:project-review:project-review"
91
+ "ship:ship:ship"
92
+ "reality-check-scan:reality-check:scan"
93
+ "reality-check-set:reality-check:set"
92
94
  )
93
95
 
94
- for cmd in "${COMMANDS[@]}"; do
95
- SOURCE_FILE="$REPO_ROOT/plugins/$cmd/commands/$cmd.md"
96
- TARGET_FILE="$OPENCODE_COMMANDS_DIR/$cmd.md"
96
+ for mapping in "${COMMAND_MAPPINGS[@]}"; do
97
+ IFS=':' read -r TARGET_NAME PLUGIN SOURCE_NAME <<< "$mapping"
98
+ SOURCE_FILE="$REPO_ROOT/plugins/$PLUGIN/commands/$SOURCE_NAME.md"
99
+ TARGET_FILE="$OPENCODE_COMMANDS_DIR/$TARGET_NAME.md"
97
100
 
98
101
  if [ -f "$SOURCE_FILE" ]; then
99
- # Replace Claude-specific path variables with OpenCode paths
100
- # Escape sed special characters in path to prevent injection
101
- SAFE_COMMANDS_DIR=$(echo "${OPENCODE_COMMANDS_DIR}" | sed 's/[&/\]/\\&/g')
102
- sed "s|\${CLAUDE_PLUGIN_ROOT}|${SAFE_COMMANDS_DIR}|g" "$SOURCE_FILE" > "$TARGET_FILE"
103
- echo " ✓ Installed /$cmd"
102
+ # Copy command file to commands directory
103
+ cp "$SOURCE_FILE" "$TARGET_FILE"
104
+ echo " Installed /$TARGET_NAME"
104
105
  else
105
- echo " ⚠️ Skipped /$cmd (source not found)"
106
+ echo " ⚠️ Skipped /$TARGET_NAME (source not found: $SOURCE_FILE)"
107
+ fi
108
+ done
109
+
110
+ # Remove old/legacy commands that no longer exist
111
+ OLD_COMMANDS=("pr-merge")
112
+ for old_cmd in "${OLD_COMMANDS[@]}"; do
113
+ if [ -f "$OPENCODE_COMMANDS_DIR/$old_cmd.md" ]; then
114
+ rm "$OPENCODE_COMMANDS_DIR/$old_cmd.md"
115
+ echo " 🗑️ Removed legacy /$old_cmd"
106
116
  fi
107
117
  done
108
118
 
@@ -129,6 +139,65 @@ chmod +x "$OPENCODE_COMMANDS_DIR/env.sh"
129
139
  echo " ✓ Created environment setup script"
130
140
  echo
131
141
 
142
+ # Configure MCP server
143
+ echo "🔌 Configuring MCP server..."
144
+ OPENCODE_GLOBAL_CONFIG_DIR="${HOME}/.config/opencode"
145
+ CONFIG_JSON="$OPENCODE_GLOBAL_CONFIG_DIR/opencode.json"
146
+
147
+ # Convert repo path to forward slashes for config
148
+ MCP_PATH="${REPO_ROOT//\\//}"
149
+
150
+ # Ensure config directory exists
151
+ mkdir -p "$OPENCODE_GLOBAL_CONFIG_DIR"
152
+
153
+ # Create or update opencode.json with MCP config
154
+ if [ -f "$CONFIG_JSON" ]; then
155
+ # Check if we have jq for proper JSON manipulation
156
+ if command -v jq &> /dev/null; then
157
+ # Update existing config with jq
158
+ jq --arg path "$MCP_PATH" '.mcp["awesome-slash"] = {
159
+ "type": "local",
160
+ "command": ["node", ($path + "/mcp-server/index.js")],
161
+ "environment": {"PLUGIN_ROOT": $path},
162
+ "enabled": true
163
+ }' "$CONFIG_JSON" > "$CONFIG_JSON.tmp" && mv "$CONFIG_JSON.tmp" "$CONFIG_JSON"
164
+ else
165
+ # Fallback: Use node to update JSON
166
+ node -e "
167
+ const fs = require('fs');
168
+ const config = JSON.parse(fs.readFileSync('$CONFIG_JSON', 'utf8'));
169
+ config.mcp = config.mcp || {};
170
+ config.mcp['awesome-slash'] = {
171
+ type: 'local',
172
+ command: ['node', '$MCP_PATH/mcp-server/index.js'],
173
+ environment: { PLUGIN_ROOT: '$MCP_PATH' },
174
+ enabled: true
175
+ };
176
+ fs.writeFileSync('$CONFIG_JSON', JSON.stringify(config, null, 2));
177
+ "
178
+ fi
179
+ else
180
+ # Create new config
181
+ cat > "$CONFIG_JSON" << EOF
182
+ {
183
+ "mcp": {
184
+ "awesome-slash": {
185
+ "type": "local",
186
+ "command": ["node", "${MCP_PATH}/mcp-server/index.js"],
187
+ "environment": {
188
+ "PLUGIN_ROOT": "${MCP_PATH}"
189
+ },
190
+ "enabled": true
191
+ }
192
+ },
193
+ "\$schema": "https://opencode.ai/config.json"
194
+ }
195
+ EOF
196
+ fi
197
+
198
+ echo " ✓ Added MCP server to opencode.json"
199
+ echo
200
+
132
201
  # Create README
133
202
  cat > "$OPENCODE_COMMANDS_DIR/README.md" << 'EOF'
134
203
  # awesome-slash for OpenCode
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Unified entry point for all core library modules.
5
5
  * Provides platform detection, pattern matching, workflow state management,
6
- * and context optimization utilities.
6
+ * configuration management, and context optimization utilities.
7
7
  *
8
8
  * @module awesome-slash/lib
9
9
  * @author Avi Fenesh
@@ -16,6 +16,11 @@ const reviewPatterns = require('./patterns/review-patterns');
16
16
  const slopPatterns = require('./patterns/slop-patterns');
17
17
  const workflowState = require('./state/workflow-state');
18
18
  const contextOptimizer = require('./utils/context-optimizer');
19
+ const shellEscape = require('./utils/shell-escape');
20
+ const config = require('./config');
21
+ const sourceCache = require('./sources/source-cache');
22
+ const customHandler = require('./sources/custom-handler');
23
+ const policyQuestions = require('./sources/policy-questions');
19
24
 
20
25
  /**
21
26
  * Platform detection and verification utilities
@@ -77,6 +82,7 @@ const state = {
77
82
  generateWorkflowId: workflowState.generateWorkflowId,
78
83
  getStatePath: workflowState.getStatePath,
79
84
  ensureStateDir: workflowState.ensureStateDir,
85
+ validateStateSchema: workflowState.validateStateSchema,
80
86
 
81
87
  // CRUD operations
82
88
  createState: workflowState.createState,
@@ -103,11 +109,42 @@ const state = {
103
109
  };
104
110
 
105
111
  /**
106
- * Git command optimization utilities
112
+ * Git command optimization and string escaping utilities
107
113
  * @see module:utils/context-optimizer
114
+ * @see module:utils/shell-escape
108
115
  */
109
116
  const utils = {
110
- contextOptimizer
117
+ contextOptimizer,
118
+ shellEscape
119
+ };
120
+
121
+ /**
122
+ * Task source management
123
+ * @see module:sources/source-cache
124
+ * @see module:sources/custom-handler
125
+ * @see module:sources/policy-questions
126
+ */
127
+ const sources = {
128
+ // Main entry point - returns ready-to-use question structure
129
+ getPolicyQuestions: policyQuestions.getPolicyQuestions,
130
+ getCustomTypeQuestions: policyQuestions.getCustomTypeQuestions,
131
+ getCustomNameQuestion: policyQuestions.getCustomNameQuestion,
132
+ parseAndCachePolicy: policyQuestions.parseAndCachePolicy,
133
+ isUsingCached: policyQuestions.isUsingCached,
134
+ needsCustomFollowUp: policyQuestions.needsCustomFollowUp,
135
+ needsOtherDescription: policyQuestions.needsOtherDescription,
136
+
137
+ // Cache operations (direct access if needed)
138
+ getPreference: sourceCache.getPreference,
139
+ savePreference: sourceCache.savePreference,
140
+ getToolCapabilities: sourceCache.getToolCapabilities,
141
+ saveToolCapabilities: sourceCache.saveToolCapabilities,
142
+ clearCache: sourceCache.clearCache,
143
+
144
+ // Custom source handling (direct access if needed)
145
+ SOURCE_TYPES: customHandler.SOURCE_TYPES,
146
+ probeCLI: customHandler.probeCLI,
147
+ buildCustomConfig: customHandler.buildCustomConfig
111
148
  };
112
149
 
113
150
  // Main exports
@@ -116,6 +153,8 @@ module.exports = {
116
153
  patterns,
117
154
  state,
118
155
  utils,
156
+ config,
157
+ sources,
119
158
 
120
159
  // Direct module access for backward compatibility
121
160
  detectPlatform,
@@ -123,5 +162,9 @@ module.exports = {
123
162
  reviewPatterns,
124
163
  slopPatterns,
125
164
  workflowState,
126
- contextOptimizer
165
+ contextOptimizer,
166
+ shellEscape,
167
+ sourceCache,
168
+ customHandler,
169
+ policyQuestions
127
170
  };
@@ -328,8 +328,24 @@ const _patternCountByFramework = new Map();
328
328
  */
329
329
  const _flattenedPatterns = new Map();
330
330
 
331
- // Build indexes at module load time
332
- (function buildIndexes() {
331
+ /**
332
+ * Track if indexes have been built (lazy initialization)
333
+ */
334
+ let _indexesBuilt = false;
335
+
336
+ /**
337
+ * Cached arrays for getAvailableFrameworks/Categories (computed once)
338
+ */
339
+ let _cachedFrameworks = null;
340
+ let _cachedCategories = null;
341
+
342
+ /**
343
+ * Build indexes on first access (lazy initialization)
344
+ * This improves module load time by deferring work until needed
345
+ */
346
+ function ensureIndexesBuilt() {
347
+ if (_indexesBuilt) return;
348
+
333
349
  for (const [framework, categories] of Object.entries(reviewPatterns)) {
334
350
  let totalPatterns = 0;
335
351
  const flattened = [];
@@ -355,11 +371,13 @@ const _flattenedPatterns = new Map();
355
371
  _patternCountByFramework.set(framework, totalPatterns);
356
372
  _flattenedPatterns.set(framework, flattened);
357
373
  }
358
- })();
359
374
 
360
- // Freeze the index Sets
361
- Object.freeze(_frameworksSet);
362
- Object.freeze(_categoriesSet);
375
+ // Cache the arrays (avoid repeated Array.from calls)
376
+ _cachedFrameworks = Array.from(_frameworksSet);
377
+ _cachedCategories = Array.from(_categoriesSet);
378
+
379
+ _indexesBuilt = true;
380
+ }
363
381
 
364
382
  /**
365
383
  * Get review patterns for a detected framework (O(1) lookup)
@@ -377,6 +395,7 @@ function getPatternsForFramework(framework) {
377
395
  * @returns {Map<string, Array>} Map of framework -> patterns for that category
378
396
  */
379
397
  function getPatternsByCategory(category) {
398
+ ensureIndexesBuilt();
380
399
  return _patternsByCategory.get(category) || new Map();
381
400
  }
382
401
 
@@ -393,19 +412,23 @@ function getPatternsForFrameworkCategory(framework, category) {
393
412
  }
394
413
 
395
414
  /**
396
- * Get all available frameworks (O(1) via pre-computed Set)
415
+ * Get all available frameworks (O(1) via cached array)
416
+ * Optimized: returns cached array instead of Array.from() on every call
397
417
  * @returns {Array<string>} List of framework names
398
418
  */
399
419
  function getAvailableFrameworks() {
400
- return Array.from(_frameworksSet);
420
+ ensureIndexesBuilt();
421
+ return _cachedFrameworks;
401
422
  }
402
423
 
403
424
  /**
404
- * Get all available categories across all frameworks
425
+ * Get all available categories across all frameworks (O(1) via cached array)
426
+ * Optimized: returns cached array instead of Array.from() on every call
405
427
  * @returns {Array<string>} List of category names
406
428
  */
407
429
  function getAvailableCategories() {
408
- return Array.from(_categoriesSet);
430
+ ensureIndexesBuilt();
431
+ return _cachedCategories;
409
432
  }
410
433
 
411
434
  /**
@@ -435,6 +458,7 @@ function hasPatternsFor(framework) {
435
458
  * @returns {boolean} True if category exists
436
459
  */
437
460
  function hasCategory(category) {
461
+ ensureIndexesBuilt();
438
462
  return _categoriesSet.has(category);
439
463
  }
440
464
 
@@ -444,6 +468,7 @@ function hasCategory(category) {
444
468
  * @returns {number} Number of patterns
445
469
  */
446
470
  function getPatternCount(framework) {
471
+ ensureIndexesBuilt();
447
472
  return _patternCountByFramework.get(framework.toLowerCase()) || 0;
448
473
  }
449
474
 
@@ -452,6 +477,7 @@ function getPatternCount(framework) {
452
477
  * @returns {number} Total pattern count
453
478
  */
454
479
  function getTotalPatternCount() {
480
+ ensureIndexesBuilt();
455
481
  let total = 0;
456
482
  for (const count of _patternCountByFramework.values()) {
457
483
  total += count;
@@ -461,17 +487,37 @@ function getTotalPatternCount() {
461
487
 
462
488
  /**
463
489
  * Search patterns by keyword across all frameworks
490
+ * Optimized: supports pagination to avoid returning thousands of results
464
491
  * @param {string} keyword - Search term (case-insensitive)
492
+ * @param {Object} [options] - Search options
493
+ * @param {number} [options.limit] - Maximum number of results (default: unlimited)
494
+ * @param {number} [options.offset=0] - Number of results to skip
465
495
  * @returns {Array<{framework: string, category: string, pattern: string}>} Matching patterns
466
496
  */
467
- function searchPatterns(keyword) {
497
+ function searchPatterns(keyword, options = {}) {
498
+ ensureIndexesBuilt();
468
499
  const lowerKeyword = keyword.toLowerCase();
500
+ const { limit, offset = 0 } = options;
469
501
  const results = [];
502
+ let skipped = 0;
503
+ let collected = 0;
470
504
 
471
505
  for (const [framework, patterns] of _flattenedPatterns) {
472
506
  for (const { category, pattern } of patterns) {
473
507
  if (pattern.toLowerCase().includes(lowerKeyword)) {
508
+ // Skip results until we reach offset
509
+ if (skipped < offset) {
510
+ skipped++;
511
+ continue;
512
+ }
513
+
474
514
  results.push({ framework, category, pattern });
515
+ collected++;
516
+
517
+ // Stop if we've collected enough results
518
+ if (limit && collected >= limit) {
519
+ return results;
520
+ }
475
521
  }
476
522
  }
477
523
  }
@@ -485,6 +531,7 @@ function searchPatterns(keyword) {
485
531
  * @returns {Array<string>} List of frameworks with this category
486
532
  */
487
533
  function getFrameworksWithCategory(category) {
534
+ ensureIndexesBuilt();
488
535
  const categoryMap = _patternsByCategory.get(category);
489
536
  if (!categoryMap) return [];
490
537
  return Array.from(categoryMap.keys());