awesome-slash 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +6 -6
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +35 -0
- package/README.md +23 -8
- package/lib/platform/state-dir.js +122 -0
- package/lib/sources/source-cache.js +26 -11
- package/lib/state/workflow-state.js +18 -13
- package/mcp-server/index.js +7 -11
- package/package.json +1 -1
- package/plugins/deslop-around/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop-around/lib/patterns/slop-patterns.js +2 -3
- package/plugins/deslop-around/lib/platform/detect-platform.js +44 -287
- package/plugins/deslop-around/lib/platform/state-dir.js +122 -0
- package/plugins/deslop-around/lib/platform/verify-tools.js +11 -88
- package/plugins/deslop-around/lib/schemas/validator.js +44 -2
- package/plugins/deslop-around/lib/sources/source-cache.js +26 -11
- package/plugins/deslop-around/lib/state/workflow-state.js +18 -13
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/lib/patterns/slop-patterns.js +2 -3
- package/plugins/next-task/lib/platform/detect-platform.js +44 -287
- package/plugins/next-task/lib/platform/state-dir.js +122 -0
- package/plugins/next-task/lib/platform/verify-tools.js +11 -88
- package/plugins/next-task/lib/schemas/validator.js +44 -2
- package/plugins/next-task/lib/sources/source-cache.js +26 -11
- package/plugins/next-task/lib/state/workflow-state.js +18 -13
- package/plugins/project-review/.claude-plugin/plugin.json +1 -1
- package/plugins/project-review/lib/patterns/slop-patterns.js +2 -3
- package/plugins/project-review/lib/platform/detect-platform.js +44 -287
- package/plugins/project-review/lib/platform/state-dir.js +122 -0
- package/plugins/project-review/lib/platform/verify-tools.js +11 -88
- package/plugins/project-review/lib/schemas/validator.js +44 -2
- package/plugins/project-review/lib/sources/source-cache.js +26 -11
- package/plugins/project-review/lib/state/workflow-state.js +18 -13
- package/plugins/reality-check/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/patterns/slop-patterns.js +2 -3
- package/plugins/ship/lib/platform/detect-platform.js +44 -287
- package/plugins/ship/lib/platform/state-dir.js +122 -0
- package/plugins/ship/lib/platform/verify-tools.js +11 -88
- package/plugins/ship/lib/schemas/validator.js +44 -2
- package/plugins/ship/lib/sources/source-cache.js +26 -11
- package/plugins/ship/lib/state/workflow-state.js +18 -13
- package/scripts/install/codex.sh +216 -72
- package/scripts/install/opencode.sh +197 -21
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "awesome-slash",
|
|
3
3
|
"description": "Professional-grade slash commands for Claude Code with cross-platform support (OpenCode, Codex CLI)",
|
|
4
|
-
"version": "2.5.
|
|
4
|
+
"version": "2.5.1",
|
|
5
5
|
"owner": {
|
|
6
6
|
"name": "Avi Fenesh",
|
|
7
7
|
"url": "https://github.com/avifenesh"
|
|
@@ -13,35 +13,35 @@
|
|
|
13
13
|
"name": "next-task",
|
|
14
14
|
"source": "./plugins/next-task",
|
|
15
15
|
"description": "Master workflow orchestrator: autonomous workflow with model optimization (opus/sonnet/haiku), two-file state management, workflow enforcement gates, 14 specialist agents",
|
|
16
|
-
"version": "2.5.
|
|
16
|
+
"version": "2.5.1",
|
|
17
17
|
"category": "productivity"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"name": "ship",
|
|
21
21
|
"source": "./plugins/ship",
|
|
22
22
|
"description": "Complete PR workflow: commit to production, skips review when called from next-task, removes task from registry on cleanup, automatic rollback",
|
|
23
|
-
"version": "2.5.
|
|
23
|
+
"version": "2.5.1",
|
|
24
24
|
"category": "deployment"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"name": "deslop-around",
|
|
28
28
|
"source": "./plugins/deslop-around",
|
|
29
29
|
"description": "AI slop cleanup with minimal diffs and behavior preservation",
|
|
30
|
-
"version": "2.5.
|
|
30
|
+
"version": "2.5.1",
|
|
31
31
|
"category": "development"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"name": "project-review",
|
|
35
35
|
"source": "./plugins/project-review",
|
|
36
36
|
"description": "Multi-agent iterative code review until zero issues remain",
|
|
37
|
-
"version": "2.5.
|
|
37
|
+
"version": "2.5.1",
|
|
38
38
|
"category": "development"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"name": "reality-check",
|
|
42
42
|
"source": "./plugins/reality-check",
|
|
43
43
|
"description": "Deep repository analysis to realign project plans with code reality - detects drift, gaps, and creates prioritized reconstruction plans",
|
|
44
|
-
"version": "2.5.
|
|
44
|
+
"version": "2.5.1",
|
|
45
45
|
"category": "productivity"
|
|
46
46
|
}
|
|
47
47
|
],
|
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
No unreleased changes documented.
|
|
11
11
|
|
|
12
|
+
## [2.5.1] - 2026-01-19
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Platform-Aware State Directories** - State files now stored in platform-specific directories
|
|
16
|
+
- Claude Code: `.claude/`
|
|
17
|
+
- OpenCode: `.opencode/`
|
|
18
|
+
- Codex CLI: `.codex/`
|
|
19
|
+
- Override with `AI_STATE_DIR` environment variable
|
|
20
|
+
- **New lib/platform/state-dir.js** - Centralized platform detection module
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **OpenCode Installer** - Fixed config format (uses `mcp` key, `type: local`)
|
|
24
|
+
- **Codex Installer** - Fixed to use `config.toml` with Windows-style paths
|
|
25
|
+
- **MCP Server Bugs** - Fixed `state.workflow.id` → `state.task.id` references
|
|
26
|
+
- **MCP Resume Logic** - Fixed `checkpoints.canResume` to use correct state fields
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **Codex Skills** - Added explicit instructions to get files from git diff or ask user
|
|
30
|
+
- **OpenCode Commands** - Added "CRITICAL: Always Ask User First" sections
|
|
31
|
+
- **Documentation** - Added note that Codex uses `$` prefix instead of `/` for commands
|
|
32
|
+
|
|
33
|
+
## [2.5.0] - 2026-01-19
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- **Multi-Source Task Discovery** - Support for GitHub, GitLab, local files, custom CLI tools
|
|
37
|
+
- **Source Preference Caching** - Last-used source cached in `sources/preference.json`
|
|
38
|
+
- **Large Backlog Handling** - Pagination and priority filtering for repos with many issues
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- **Streamlined Policy Selection** - Direct questions from orchestrator, removed separate agent
|
|
42
|
+
|
|
43
|
+
### Security
|
|
44
|
+
- **Command Injection** - Fixed shell command injection vulnerabilities
|
|
45
|
+
- **Path Traversal** - Fixed path traversal in source-cache.js
|
|
46
|
+
|
|
12
47
|
## [2.4.7] - 2026-01-18
|
|
13
48
|
|
|
14
49
|
### Changed
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A cross-platform plugin providing powerful, zero-configuration slash commands fo
|
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/awesome-slash)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
|
-
[](https://github.com/avifenesh/awesome-slash/releases)
|
|
10
10
|
[](https://github.com/avifenesh/awesome-slash/stargazers)
|
|
11
11
|
[](https://docs.anthropic.com/en/docs/claude-code)
|
|
12
12
|
[](https://developers.openai.com/codex/cli)
|
|
@@ -16,13 +16,18 @@ A cross-platform plugin providing powerful, zero-configuration slash commands fo
|
|
|
16
16
|
|
|
17
17
|
> **💡 Model Recommendation**: Using **Opus** as the main agent model produces significantly better results and follows workflow phases more tightly. While Sonnet works for simpler tasks, Opus is recommended for complex multi-step workflows.
|
|
18
18
|
|
|
19
|
+
## What's New in v2.5.1
|
|
20
|
+
|
|
21
|
+
- **Platform-Aware State Directories** - State now stored in `.opencode/` for OpenCode, `.codex/` for Codex
|
|
22
|
+
- **Fixed OpenCode/Codex Installers** - Correct config formats and Windows path handling
|
|
23
|
+
- **MCP Server Bug Fixes** - Fixed workflow state references and resume logic
|
|
24
|
+
- **Documentation Updates** - Added note that Codex uses `$` prefix instead of `/`
|
|
25
|
+
|
|
19
26
|
## What's New in v2.5.0
|
|
20
27
|
|
|
21
|
-
- **Multi-Source Task Discovery** - Support for GitHub, GitLab, local files, custom CLI tools
|
|
28
|
+
- **Multi-Source Task Discovery** - Support for GitHub, GitLab, local files, custom CLI tools
|
|
22
29
|
- **Source Preference Caching** - Your last-used source appears first on subsequent runs
|
|
23
30
|
- **Security Hardening** - Fixed command injection and path traversal vulnerabilities
|
|
24
|
-
- **Large Backlog Handling** - Intelligent pagination and priority filtering for repos with many issues
|
|
25
|
-
- **Streamlined Policy Selection** - Direct questions from orchestrator, removed separate agent
|
|
26
31
|
|
|
27
32
|
## What's New in v2.4.7
|
|
28
33
|
|
|
@@ -54,6 +59,8 @@ git clone https://github.com/avifenesh/awesome-slash.git
|
|
|
54
59
|
|
|
55
60
|
## Available Commands
|
|
56
61
|
|
|
62
|
+
> **Platform Note:** Commands use `/` prefix in Claude Code and OpenCode, but `$` prefix in Codex CLI (e.g., `$next-task` instead of `/next-task`).
|
|
63
|
+
|
|
57
64
|
### `/next-task` - Master Workflow Orchestrator
|
|
58
65
|
|
|
59
66
|
Complete task-to-production automation with state management and resume capability.
|
|
@@ -243,9 +250,17 @@ See [docs/CROSS_PLATFORM.md](./docs/CROSS_PLATFORM.md) for details.
|
|
|
243
250
|
|
|
244
251
|
### State Management
|
|
245
252
|
|
|
246
|
-
Simple state tracking with
|
|
253
|
+
Simple state tracking with platform-aware directories:
|
|
254
|
+
|
|
255
|
+
| Platform | State Directory |
|
|
256
|
+
|----------|-----------------|
|
|
257
|
+
| Claude Code | `.claude/` |
|
|
258
|
+
| OpenCode | `.opencode/` |
|
|
259
|
+
| Codex CLI | `.codex/` |
|
|
260
|
+
|
|
261
|
+
Override with `AI_STATE_DIR` environment variable.
|
|
247
262
|
|
|
248
|
-
**Main project:
|
|
263
|
+
**Main project: `{state-dir}/tasks.json`** - Tracks active worktree/task:
|
|
249
264
|
```json
|
|
250
265
|
{
|
|
251
266
|
"active": {
|
|
@@ -257,7 +272,7 @@ Simple state tracking with three locations:
|
|
|
257
272
|
}
|
|
258
273
|
```
|
|
259
274
|
|
|
260
|
-
**Worktree:
|
|
275
|
+
**Worktree: `{state-dir}/flow.json`** - Tracks workflow progress:
|
|
261
276
|
```json
|
|
262
277
|
{
|
|
263
278
|
"task": { "id": "123", "title": "Fix auth timeout" },
|
|
@@ -270,7 +285,7 @@ Simple state tracking with three locations:
|
|
|
270
285
|
}
|
|
271
286
|
```
|
|
272
287
|
|
|
273
|
-
**Source Preferences:
|
|
288
|
+
**Source Preferences: `{state-dir}/sources/preference.json`** - Caches task source selection:
|
|
274
289
|
```json
|
|
275
290
|
{
|
|
276
291
|
"source": "custom",
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-aware state directory detection
|
|
3
|
+
*
|
|
4
|
+
* Determines the appropriate state directory based on the AI coding assistant
|
|
5
|
+
* being used (Claude Code, OpenCode, or Codex CLI).
|
|
6
|
+
*
|
|
7
|
+
* @module lib/platform/state-dir
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Cached state directory name (relative, without leading dot handling)
|
|
15
|
+
* @type {string|null}
|
|
16
|
+
*/
|
|
17
|
+
let _cachedStateDir = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Detect which AI coding assistant is running and return appropriate state directory
|
|
21
|
+
*
|
|
22
|
+
* Detection order:
|
|
23
|
+
* 1. AI_STATE_DIR env var (user override)
|
|
24
|
+
* 2. OpenCode detection (OPENCODE_CONFIG env or .opencode/ exists)
|
|
25
|
+
* 3. Codex detection (CODEX_HOME env or .codex/ exists)
|
|
26
|
+
* 4. Default to .claude (Claude Code or unknown)
|
|
27
|
+
*
|
|
28
|
+
* @param {string} [basePath=process.cwd()] - Base path to check for project directories
|
|
29
|
+
* @returns {string} State directory name (e.g., '.claude', '.opencode', '.codex')
|
|
30
|
+
*/
|
|
31
|
+
function getStateDir(basePath = process.cwd()) {
|
|
32
|
+
// Check user override first
|
|
33
|
+
if (process.env.AI_STATE_DIR) {
|
|
34
|
+
return process.env.AI_STATE_DIR;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Return cached value if available
|
|
38
|
+
if (_cachedStateDir) {
|
|
39
|
+
return _cachedStateDir;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// OpenCode detection
|
|
43
|
+
if (process.env.OPENCODE_CONFIG || process.env.OPENCODE_CONFIG_DIR) {
|
|
44
|
+
_cachedStateDir = '.opencode';
|
|
45
|
+
return _cachedStateDir;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check for .opencode directory in project
|
|
49
|
+
try {
|
|
50
|
+
const opencodePath = path.join(basePath, '.opencode');
|
|
51
|
+
if (fs.existsSync(opencodePath) && fs.statSync(opencodePath).isDirectory()) {
|
|
52
|
+
_cachedStateDir = '.opencode';
|
|
53
|
+
return _cachedStateDir;
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
// Ignore errors, continue detection
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Codex detection
|
|
60
|
+
if (process.env.CODEX_HOME) {
|
|
61
|
+
_cachedStateDir = '.codex';
|
|
62
|
+
return _cachedStateDir;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check for .codex directory in project
|
|
66
|
+
try {
|
|
67
|
+
const codexPath = path.join(basePath, '.codex');
|
|
68
|
+
if (fs.existsSync(codexPath) && fs.statSync(codexPath).isDirectory()) {
|
|
69
|
+
_cachedStateDir = '.codex';
|
|
70
|
+
return _cachedStateDir;
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// Ignore errors, continue detection
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Default to Claude Code
|
|
77
|
+
_cachedStateDir = '.claude';
|
|
78
|
+
return _cachedStateDir;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the full path to the state directory
|
|
83
|
+
* @param {string} [basePath=process.cwd()] - Base path
|
|
84
|
+
* @returns {string} Full path to state directory
|
|
85
|
+
*/
|
|
86
|
+
function getStateDirPath(basePath = process.cwd()) {
|
|
87
|
+
return path.join(basePath, getStateDir(basePath));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the detected platform name
|
|
92
|
+
* @param {string} [basePath=process.cwd()] - Base path
|
|
93
|
+
* @returns {string} Platform name ('claude', 'opencode', 'codex', or 'custom')
|
|
94
|
+
*/
|
|
95
|
+
function getPlatformName(basePath = process.cwd()) {
|
|
96
|
+
const stateDir = getStateDir(basePath);
|
|
97
|
+
|
|
98
|
+
if (process.env.AI_STATE_DIR) {
|
|
99
|
+
return 'custom';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
switch (stateDir) {
|
|
103
|
+
case '.opencode': return 'opencode';
|
|
104
|
+
case '.codex': return 'codex';
|
|
105
|
+
case '.claude': return 'claude';
|
|
106
|
+
default: return 'unknown';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Clear the cached state directory (useful for testing)
|
|
112
|
+
*/
|
|
113
|
+
function clearCache() {
|
|
114
|
+
_cachedStateDir = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
getStateDir,
|
|
119
|
+
getStateDirPath,
|
|
120
|
+
getPlatformName,
|
|
121
|
+
clearCache
|
|
122
|
+
};
|
|
@@ -2,15 +2,28 @@
|
|
|
2
2
|
* Source Cache
|
|
3
3
|
* File-based persistence for task source preferences
|
|
4
4
|
*
|
|
5
|
+
* State directory is platform-aware:
|
|
6
|
+
* - Claude Code: .claude/sources/
|
|
7
|
+
* - OpenCode: .opencode/sources/
|
|
8
|
+
* - Codex CLI: .codex/sources/
|
|
9
|
+
*
|
|
5
10
|
* @module lib/sources/source-cache
|
|
6
11
|
*/
|
|
7
12
|
|
|
8
13
|
const fs = require('fs');
|
|
9
14
|
const path = require('path');
|
|
15
|
+
const { getStateDir } = require('../platform/state-dir');
|
|
10
16
|
|
|
11
|
-
const SOURCES_DIR = '.claude/sources';
|
|
12
17
|
const PREFERENCE_FILE = 'preference.json';
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Get the sources directory path (platform-aware)
|
|
21
|
+
* @returns {string} Path to sources directory
|
|
22
|
+
*/
|
|
23
|
+
function getSourcesDir() {
|
|
24
|
+
return path.join(getStateDir(), 'sources');
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
/**
|
|
15
28
|
* Validate tool name to prevent path traversal
|
|
16
29
|
* @param {string} toolName - Tool name to validate
|
|
@@ -26,10 +39,11 @@ function isValidToolName(toolName) {
|
|
|
26
39
|
* @returns {string} Path to sources directory
|
|
27
40
|
*/
|
|
28
41
|
function ensureDir() {
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
const sourcesDir = getSourcesDir();
|
|
43
|
+
if (!fs.existsSync(sourcesDir)) {
|
|
44
|
+
fs.mkdirSync(sourcesDir, { recursive: true });
|
|
31
45
|
}
|
|
32
|
-
return
|
|
46
|
+
return sourcesDir;
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
/**
|
|
@@ -40,7 +54,7 @@ function ensureDir() {
|
|
|
40
54
|
* // Or: { source: 'custom', type: 'cli', tool: 'tea' }
|
|
41
55
|
*/
|
|
42
56
|
function getPreference() {
|
|
43
|
-
const filePath = path.join(
|
|
57
|
+
const filePath = path.join(getSourcesDir(), PREFERENCE_FILE);
|
|
44
58
|
if (!fs.existsSync(filePath)) {
|
|
45
59
|
return null;
|
|
46
60
|
}
|
|
@@ -62,7 +76,7 @@ function getPreference() {
|
|
|
62
76
|
*/
|
|
63
77
|
function savePreference(preference) {
|
|
64
78
|
ensureDir();
|
|
65
|
-
const filePath = path.join(
|
|
79
|
+
const filePath = path.join(getSourcesDir(), PREFERENCE_FILE);
|
|
66
80
|
fs.writeFileSync(filePath, JSON.stringify({
|
|
67
81
|
...preference,
|
|
68
82
|
savedAt: new Date().toISOString()
|
|
@@ -80,7 +94,7 @@ function getToolCapabilities(toolName) {
|
|
|
80
94
|
console.error(`Invalid tool name: ${toolName}`);
|
|
81
95
|
return null;
|
|
82
96
|
}
|
|
83
|
-
const filePath = path.join(
|
|
97
|
+
const filePath = path.join(getSourcesDir(), `${toolName}.json`);
|
|
84
98
|
if (!fs.existsSync(filePath)) {
|
|
85
99
|
return null;
|
|
86
100
|
}
|
|
@@ -106,7 +120,7 @@ function saveToolCapabilities(toolName, capabilities) {
|
|
|
106
120
|
return;
|
|
107
121
|
}
|
|
108
122
|
ensureDir();
|
|
109
|
-
const filePath = path.join(
|
|
123
|
+
const filePath = path.join(getSourcesDir(), `${toolName}.json`);
|
|
110
124
|
fs.writeFileSync(filePath, JSON.stringify({
|
|
111
125
|
...capabilities,
|
|
112
126
|
discoveredAt: new Date().toISOString()
|
|
@@ -117,10 +131,11 @@ function saveToolCapabilities(toolName, capabilities) {
|
|
|
117
131
|
* Clear all cached preferences
|
|
118
132
|
*/
|
|
119
133
|
function clearCache() {
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
const sourcesDir = getSourcesDir();
|
|
135
|
+
if (fs.existsSync(sourcesDir)) {
|
|
136
|
+
const files = fs.readdirSync(sourcesDir);
|
|
122
137
|
for (const file of files) {
|
|
123
|
-
const filePath = path.join(
|
|
138
|
+
const filePath = path.join(sourcesDir, file);
|
|
124
139
|
const stats = fs.statSync(filePath);
|
|
125
140
|
if (stats.isFile()) {
|
|
126
141
|
fs.unlinkSync(filePath);
|
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
* Simplified workflow state management
|
|
3
3
|
*
|
|
4
4
|
* Two files:
|
|
5
|
-
* - Main project:
|
|
6
|
-
* - Worktree:
|
|
5
|
+
* - Main project: {stateDir}/tasks.json (tracks active worktree/task)
|
|
6
|
+
* - Worktree: {stateDir}/flow.json (tracks workflow progress)
|
|
7
|
+
*
|
|
8
|
+
* State directory is platform-aware:
|
|
9
|
+
* - Claude Code: .claude/
|
|
10
|
+
* - OpenCode: .opencode/
|
|
11
|
+
* - Codex CLI: .codex/
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
14
|
const fs = require('fs');
|
|
10
15
|
const path = require('path');
|
|
11
16
|
const crypto = require('crypto');
|
|
17
|
+
const { getStateDir } = require('../platform/state-dir');
|
|
12
18
|
|
|
13
19
|
// File paths
|
|
14
|
-
const CLAUDE_DIR = '.claude';
|
|
15
20
|
const TASKS_FILE = 'tasks.json';
|
|
16
21
|
const FLOW_FILE = 'flow.json';
|
|
17
22
|
|
|
@@ -74,14 +79,14 @@ const PHASES = [
|
|
|
74
79
|
];
|
|
75
80
|
|
|
76
81
|
/**
|
|
77
|
-
* Ensure
|
|
82
|
+
* Ensure state directory exists (platform-aware)
|
|
78
83
|
*/
|
|
79
|
-
function
|
|
80
|
-
const
|
|
81
|
-
if (!fs.existsSync(
|
|
82
|
-
fs.mkdirSync(
|
|
84
|
+
function ensureStateDir(basePath) {
|
|
85
|
+
const stateDir = path.join(basePath, getStateDir(basePath));
|
|
86
|
+
if (!fs.existsSync(stateDir)) {
|
|
87
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
83
88
|
}
|
|
84
|
-
return
|
|
89
|
+
return stateDir;
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
// =============================================================================
|
|
@@ -93,7 +98,7 @@ function ensureClaudeDir(basePath) {
|
|
|
93
98
|
*/
|
|
94
99
|
function getTasksPath(projectPath = process.cwd()) {
|
|
95
100
|
const validatedBase = validatePath(projectPath);
|
|
96
|
-
const tasksPath = path.join(validatedBase,
|
|
101
|
+
const tasksPath = path.join(validatedBase, getStateDir(projectPath), TASKS_FILE);
|
|
97
102
|
validatePathWithinBase(tasksPath, validatedBase);
|
|
98
103
|
return tasksPath;
|
|
99
104
|
}
|
|
@@ -125,7 +130,7 @@ function readTasks(projectPath = process.cwd()) {
|
|
|
125
130
|
* Write tasks.json to main project
|
|
126
131
|
*/
|
|
127
132
|
function writeTasks(tasks, projectPath = process.cwd()) {
|
|
128
|
-
|
|
133
|
+
ensureStateDir(projectPath);
|
|
129
134
|
const tasksPath = getTasksPath(projectPath);
|
|
130
135
|
fs.writeFileSync(tasksPath, JSON.stringify(tasks, null, 2), 'utf8');
|
|
131
136
|
return true;
|
|
@@ -170,7 +175,7 @@ function hasActiveTask(projectPath = process.cwd()) {
|
|
|
170
175
|
*/
|
|
171
176
|
function getFlowPath(worktreePath = process.cwd()) {
|
|
172
177
|
const validatedBase = validatePath(worktreePath);
|
|
173
|
-
const flowPath = path.join(validatedBase,
|
|
178
|
+
const flowPath = path.join(validatedBase, getStateDir(worktreePath), FLOW_FILE);
|
|
174
179
|
validatePathWithinBase(flowPath, validatedBase);
|
|
175
180
|
return flowPath;
|
|
176
181
|
}
|
|
@@ -198,7 +203,7 @@ function readFlow(worktreePath = process.cwd()) {
|
|
|
198
203
|
* Creates a copy to avoid mutating the original object
|
|
199
204
|
*/
|
|
200
205
|
function writeFlow(flow, worktreePath = process.cwd()) {
|
|
201
|
-
|
|
206
|
+
ensureStateDir(worktreePath);
|
|
202
207
|
// Clone to avoid mutating the original object
|
|
203
208
|
const flowCopy = JSON.parse(JSON.stringify(flow));
|
|
204
209
|
flowCopy.lastUpdate = new Date().toISOString();
|
package/mcp-server/index.js
CHANGED
|
@@ -178,7 +178,7 @@ const toolHandlers = {
|
|
|
178
178
|
return {
|
|
179
179
|
content: [{
|
|
180
180
|
type: 'text',
|
|
181
|
-
text: `Workflow started: ${state.
|
|
181
|
+
text: `Workflow started: ${state.task.id}\nPolicy: ${JSON.stringify(policy, null, 2)}`
|
|
182
182
|
}]
|
|
183
183
|
};
|
|
184
184
|
},
|
|
@@ -199,7 +199,7 @@ const toolHandlers = {
|
|
|
199
199
|
};
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
if (
|
|
202
|
+
if (state.status !== 'in_progress' || state.phase === 'complete') {
|
|
203
203
|
return {
|
|
204
204
|
content: [{ type: 'text', text: 'Workflow cannot be resumed from current state.' }],
|
|
205
205
|
isError: true
|
|
@@ -209,7 +209,7 @@ const toolHandlers = {
|
|
|
209
209
|
return {
|
|
210
210
|
content: [{
|
|
211
211
|
type: 'text',
|
|
212
|
-
text: `Resuming workflow ${state.
|
|
212
|
+
text: `Resuming workflow ${state.task.id} from phase: ${state.phase}`
|
|
213
213
|
}]
|
|
214
214
|
};
|
|
215
215
|
},
|
|
@@ -234,7 +234,7 @@ const toolHandlers = {
|
|
|
234
234
|
return {
|
|
235
235
|
content: [{
|
|
236
236
|
type: 'text',
|
|
237
|
-
text: `Workflow ${state.
|
|
237
|
+
text: `Workflow ${state.task.id} aborted. Cleanup: worktree and branches should be removed manually.`
|
|
238
238
|
}]
|
|
239
239
|
};
|
|
240
240
|
},
|
|
@@ -383,8 +383,7 @@ const toolHandlers = {
|
|
|
383
383
|
foundFile = file;
|
|
384
384
|
break;
|
|
385
385
|
} catch (e) {
|
|
386
|
-
//
|
|
387
|
-
console.error(`Could not read ${file}: ${e.message}`);
|
|
386
|
+
// File doesn't exist, try next one
|
|
388
387
|
}
|
|
389
388
|
}
|
|
390
389
|
|
|
@@ -430,10 +429,7 @@ const toolHandlers = {
|
|
|
430
429
|
|
|
431
430
|
// Validate file path - prevent path traversal
|
|
432
431
|
const normalizedPath = path.normalize(customFile);
|
|
433
|
-
|
|
434
|
-
// Allow absolute paths but log for awareness
|
|
435
|
-
console.error(`Custom task file: ${normalizedPath}`);
|
|
436
|
-
}
|
|
432
|
+
// Note: absolute paths and '..' are allowed but monitored via file access
|
|
437
433
|
|
|
438
434
|
try {
|
|
439
435
|
const content = await fs.readFile(customFile, 'utf-8');
|
|
@@ -669,7 +665,7 @@ async function main() {
|
|
|
669
665
|
const server = new Server(
|
|
670
666
|
{
|
|
671
667
|
name: 'awesome-slash',
|
|
672
|
-
version: '2.
|
|
668
|
+
version: '2.5.1',
|
|
673
669
|
},
|
|
674
670
|
{
|
|
675
671
|
capabilities: {
|
package/package.json
CHANGED
|
@@ -644,9 +644,8 @@ function isFileExcluded(filePath, excludePatterns) {
|
|
|
644
644
|
const cacheKey = JSON.stringify([filePath, excludePatterns]);
|
|
645
645
|
|
|
646
646
|
// Check cache first (O(1) lookup)
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
647
|
+
const cached = _excludeResultCache.get(cacheKey);
|
|
648
|
+
if (cached !== undefined) return cached;
|
|
650
649
|
|
|
651
650
|
// Compute result
|
|
652
651
|
const result = excludePatterns.some(pattern => {
|