awesome-slash 3.8.1 → 3.8.2
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 +10 -10
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +11 -0
- package/adapters/opencode/install.sh +63 -4
- package/bin/cli.js +1 -1
- package/lib/patterns/slop-patterns.js +18 -0
- package/package.json +1 -1
- package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
- package/plugins/audit-project/lib/patterns/slop-patterns.js +18 -0
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/patterns/slop-patterns.js +18 -0
- package/plugins/deslop/references/slop-categories.md +15 -0
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/patterns/slop-patterns.js +18 -0
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/patterns/slop-patterns.js +18 -0
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/commands/next-task.md +45 -18
- package/plugins/next-task/lib/patterns/slop-patterns.js +18 -0
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/patterns/slop-patterns.js +18 -0
- package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
- package/plugins/repo-map/lib/patterns/slop-patterns.js +18 -0
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/patterns/slop-patterns.js +18 -0
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/patterns/slop-patterns.js +18 -0
- package/scripts/dev-install.js +116 -34
- package/scripts/validate-opencode-install.js +16 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "awesome-slash",
|
|
3
3
|
"description": "9 specialized plugins for AI workflow automation - task orchestration, PR workflow, slop detection, code review, drift detection, enhancement analysis, documentation sync, repo mapping, and perf investigations",
|
|
4
|
-
"version": "3.8.
|
|
4
|
+
"version": "3.8.2",
|
|
5
5
|
"owner": {
|
|
6
6
|
"name": "Avi Fenesh",
|
|
7
7
|
"url": "https://github.com/avifenesh"
|
|
@@ -26,63 +26,63 @@
|
|
|
26
26
|
"name": "next-task",
|
|
27
27
|
"source": "./plugins/next-task",
|
|
28
28
|
"description": "Master workflow orchestrator: autonomous workflow with model optimization (opus/sonnet/haiku), two-file state management, workflow enforcement gates, 14 specialist agents",
|
|
29
|
-
"version": "3.8.
|
|
29
|
+
"version": "3.8.2",
|
|
30
30
|
"category": "productivity"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "ship",
|
|
34
34
|
"source": "./plugins/ship",
|
|
35
35
|
"description": "Complete PR workflow: commit to production, skips review when called from next-task, removes task from registry on cleanup, automatic rollback",
|
|
36
|
-
"version": "3.8.
|
|
36
|
+
"version": "3.8.2",
|
|
37
37
|
"category": "deployment"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"name": "deslop",
|
|
41
41
|
"source": "./plugins/deslop",
|
|
42
42
|
"description": "3-phase AI slop detection: regex patterns (HIGH), multi-pass analyzers (MEDIUM), CLI tools (LOW)",
|
|
43
|
-
"version": "3.8.
|
|
43
|
+
"version": "3.8.2",
|
|
44
44
|
"category": "development"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"name": "audit-project",
|
|
48
48
|
"source": "./plugins/audit-project",
|
|
49
49
|
"description": "Multi-agent iterative code review until zero issues remain",
|
|
50
|
-
"version": "3.8.
|
|
50
|
+
"version": "3.8.2",
|
|
51
51
|
"category": "development"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"name": "drift-detect",
|
|
55
55
|
"source": "./plugins/drift-detect",
|
|
56
56
|
"description": "Deep repository analysis to realign project plans with code reality - detects drift, gaps, and creates prioritized reconstruction plans",
|
|
57
|
-
"version": "3.8.
|
|
57
|
+
"version": "3.8.2",
|
|
58
58
|
"category": "productivity"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
"name": "enhance",
|
|
62
62
|
"source": "./plugins/enhance",
|
|
63
63
|
"description": "Master enhancement orchestrator: parallel analyzer execution for plugins, agents, docs, CLAUDE.md, and prompts with unified reporting",
|
|
64
|
-
"version": "3.8.
|
|
64
|
+
"version": "3.8.2",
|
|
65
65
|
"category": "development"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"name": "sync-docs",
|
|
69
69
|
"source": "./plugins/sync-docs",
|
|
70
70
|
"description": "Standalone documentation sync: find outdated refs, update CHANGELOG, flag stale examples based on code changes",
|
|
71
|
-
"version": "3.8.
|
|
71
|
+
"version": "3.8.2",
|
|
72
72
|
"category": "development"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"name": "repo-map",
|
|
76
76
|
"source": "./plugins/repo-map",
|
|
77
77
|
"description": "AST-based repository map generation using ast-grep with incremental updates for faster drift analysis",
|
|
78
|
-
"version": "3.8.
|
|
78
|
+
"version": "3.8.2",
|
|
79
79
|
"category": "development"
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"name": "perf",
|
|
83
83
|
"source": "./plugins/perf",
|
|
84
84
|
"description": "Rigorous performance investigation workflow with baselines, profiling, hypotheses, and evidence-backed decisions",
|
|
85
|
-
"version": "3.8.
|
|
85
|
+
"version": "3.8.2",
|
|
86
86
|
"category": "development"
|
|
87
87
|
}
|
|
88
88
|
]
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.8.2] - 2026-02-04
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Policy Questions Enforcement** - /next-task Phase 1 now explicitly requires all 3 policy questions (Source, Priority, Stop Point) with table and forbidden actions
|
|
14
|
+
- **Codex CLI Installer** - Fixed undefined `configPath` variable (should be `configDir`)
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **XML Tag Consistency** - All 12 workflow phases now wrapped in consistent `<phase-N>` tags
|
|
18
|
+
- **Constructive Language** - Replaced "you are wrong" with guidance pointing to consequences table
|
|
19
|
+
- **Redundancy Reduction** - Consolidated duplicate forbidden actions lists
|
|
20
|
+
|
|
10
21
|
## [3.8.1] - 2026-02-04
|
|
11
22
|
|
|
12
23
|
### Fixed
|
|
@@ -12,10 +12,22 @@ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
|
12
12
|
|
|
13
13
|
# Use $HOME which works correctly on all platforms including Git Bash on Windows
|
|
14
14
|
# (Git Bash sets HOME to Unix-style path like /c/Users/username)
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
# OpenCode global config follows XDG Base Directory Specification:
|
|
16
|
+
# - Default: ~/.config/opencode/
|
|
17
|
+
# - Override: $XDG_CONFIG_HOME/opencode/ (if XDG_CONFIG_HOME is set and not empty/whitespace)
|
|
18
|
+
# Note: Must match logic in scripts/dev-install.js getOpenCodeConfigDir()
|
|
19
|
+
if [[ -n "${XDG_CONFIG_HOME}" && "${XDG_CONFIG_HOME}" =~ [^[:space:]] ]]; then
|
|
20
|
+
OPENCODE_CONFIG_DIR="${XDG_CONFIG_HOME}/opencode"
|
|
21
|
+
else
|
|
22
|
+
OPENCODE_CONFIG_DIR="${HOME}/.config/opencode"
|
|
23
|
+
fi
|
|
24
|
+
# OpenCode expects commands directly in commands/, not a subdirectory
|
|
25
|
+
OPENCODE_COMMANDS_DIR="${OPENCODE_CONFIG_DIR}/commands"
|
|
17
26
|
LIB_DIR="${OPENCODE_COMMANDS_DIR}/lib"
|
|
18
27
|
|
|
28
|
+
# Legacy path for cleanup (incorrect, pre-XDG location)
|
|
29
|
+
LEGACY_OPENCODE_DIR="${HOME}/.opencode"
|
|
30
|
+
|
|
19
31
|
# Detect OS for platform-specific notes
|
|
20
32
|
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" || "$OSTYPE" == "cygwin" ]]; then
|
|
21
33
|
IS_WINDOWS=true
|
|
@@ -235,17 +247,64 @@ else
|
|
|
235
247
|
fi
|
|
236
248
|
echo
|
|
237
249
|
|
|
250
|
+
# Clean up legacy paths (~/.opencode/ - incorrect, pre-XDG location)
|
|
251
|
+
echo "[CLEANUP] Checking for legacy installations..."
|
|
252
|
+
LEGACY_COMMANDS_DIR="${LEGACY_OPENCODE_DIR}/commands/awesome-slash"
|
|
253
|
+
LEGACY_PLUGINS_DIR="${LEGACY_OPENCODE_DIR}/plugins/awesome-slash"
|
|
254
|
+
LEGACY_AGENTS_DIR="${LEGACY_OPENCODE_DIR}/agents"
|
|
255
|
+
|
|
256
|
+
cleaned_legacy=false
|
|
257
|
+
if [ -d "$LEGACY_COMMANDS_DIR" ]; then
|
|
258
|
+
rm -rf "$LEGACY_COMMANDS_DIR"
|
|
259
|
+
echo " [DEL] Removed legacy ~/.opencode/commands/awesome-slash"
|
|
260
|
+
cleaned_legacy=true
|
|
261
|
+
fi
|
|
262
|
+
if [ -d "$LEGACY_PLUGINS_DIR" ]; then
|
|
263
|
+
rm -rf "$LEGACY_PLUGINS_DIR"
|
|
264
|
+
echo " [DEL] Removed legacy ~/.opencode/plugins/awesome-slash"
|
|
265
|
+
cleaned_legacy=true
|
|
266
|
+
fi
|
|
267
|
+
if [ -d "$LEGACY_AGENTS_DIR" ]; then
|
|
268
|
+
# Only remove known agent files, not the whole directory
|
|
269
|
+
# Must match list in scripts/dev-install.js knownAgents array
|
|
270
|
+
# Generated from: ls plugins/*/agents/*.md | xargs basename | sort -u
|
|
271
|
+
known_agents=(
|
|
272
|
+
'agent-enhancer.md' 'ci-fixer.md' 'ci-monitor.md' 'claudemd-enhancer.md'
|
|
273
|
+
'delivery-validator.md' 'deslop-agent.md' 'docs-enhancer.md' 'enhancement-orchestrator.md'
|
|
274
|
+
'enhancement-reporter.md' 'exploration-agent.md' 'hooks-enhancer.md' 'implementation-agent.md'
|
|
275
|
+
'map-validator.md' 'perf-analyzer.md' 'perf-code-paths.md' 'perf-investigation-logger.md'
|
|
276
|
+
'perf-orchestrator.md' 'perf-theory-gatherer.md' 'perf-theory-tester.md' 'plan-synthesizer.md'
|
|
277
|
+
'planning-agent.md' 'plugin-enhancer.md' 'prompt-enhancer.md' 'simple-fixer.md'
|
|
278
|
+
'skills-enhancer.md' 'sync-docs-agent.md' 'task-discoverer.md' 'test-coverage-checker.md'
|
|
279
|
+
'worktree-manager.md'
|
|
280
|
+
)
|
|
281
|
+
for agent in "${known_agents[@]}"; do
|
|
282
|
+
if [ -f "$LEGACY_AGENTS_DIR/$agent" ]; then
|
|
283
|
+
rm "$LEGACY_AGENTS_DIR/$agent"
|
|
284
|
+
cleaned_legacy=true
|
|
285
|
+
fi
|
|
286
|
+
done
|
|
287
|
+
if [ "$cleaned_legacy" = true ]; then
|
|
288
|
+
echo " [DEL] Removed legacy agent files from ~/.opencode/agents"
|
|
289
|
+
fi
|
|
290
|
+
fi
|
|
291
|
+
if [ "$cleaned_legacy" = false ]; then
|
|
292
|
+
echo " [OK] No legacy installations found"
|
|
293
|
+
fi
|
|
294
|
+
echo
|
|
295
|
+
|
|
238
296
|
# Success message
|
|
239
297
|
echo "[OK] Installation complete!"
|
|
240
298
|
echo
|
|
241
299
|
echo "[LIST] Installed Commands:"
|
|
242
|
-
for
|
|
300
|
+
for mapping in "${COMMAND_MAPPINGS[@]}"; do
|
|
301
|
+
IFS=':' read -r cmd _ _ <<< "$mapping"
|
|
243
302
|
echo " • /$cmd"
|
|
244
303
|
done
|
|
245
304
|
echo
|
|
246
305
|
echo "[NEXT] Next Steps:"
|
|
247
306
|
echo " 1. Start OpenCode TUI: opencode"
|
|
248
|
-
echo " 2. Use commands:
|
|
307
|
+
echo " 2. Use commands: /next-task, /ship, etc."
|
|
249
308
|
echo " 3. See help: cat $OPENCODE_COMMANDS_DIR/README.md"
|
|
250
309
|
echo
|
|
251
310
|
echo "[TIP] OpenCode Pro Tips:"
|
package/bin/cli.js
CHANGED
|
@@ -797,7 +797,7 @@ function installForCodex(installDir) {
|
|
|
797
797
|
}
|
|
798
798
|
|
|
799
799
|
console.log('\n[OK] Codex CLI installation complete!');
|
|
800
|
-
console.log(` Config: ${
|
|
800
|
+
console.log(` Config: ${configDir}`);
|
|
801
801
|
console.log(` Skills: ${skillsDir}`);
|
|
802
802
|
console.log(' Access via: $next-task, $ship, $deslop, etc.\n');
|
|
803
803
|
return true;
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "awesome-slash",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.2",
|
|
4
4
|
"description": "9 specialized plugins for AI workflow automation (drift detection + AST repo maps) - works with Claude Code, OpenCode, and Codex CLI",
|
|
5
5
|
"main": "lib/platform/detect-platform.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -14,6 +14,21 @@ Detailed reference for all slop patterns detected by the pipeline.
|
|
|
14
14
|
|
|
15
15
|
**Excludes**: Test files, CLI entry points, config files
|
|
16
16
|
|
|
17
|
+
### Unsafe Error Handling (Rust)
|
|
18
|
+
|
|
19
|
+
| Pattern | Severity | Better Alternatives |
|
|
20
|
+
|---------|----------|---------------------|
|
|
21
|
+
| `.unwrap()` | medium | `.expect("msg")`, `.unwrap_or(default)`, `?` operator |
|
|
22
|
+
|
|
23
|
+
Bare `.unwrap()` calls can cause panics in production. Prefer:
|
|
24
|
+
- `.expect("descriptive message")` - panic with context
|
|
25
|
+
- `.unwrap_or(default)` / `.unwrap_or_default()` - provide fallback
|
|
26
|
+
- `.unwrap_or_else(\|\| ...)` - lazy fallback computation
|
|
27
|
+
- `?` operator - propagate errors to caller
|
|
28
|
+
- `.ok()` / `.map()` / `.and_then()` - transform Result/Option
|
|
29
|
+
|
|
30
|
+
**Excludes**: Test files, examples, benchmarks
|
|
31
|
+
|
|
17
32
|
### Placeholder Code
|
|
18
33
|
|
|
19
34
|
| Pattern | Language | Severity |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drift-detect",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.2",
|
|
4
4
|
"description": "Deep repository analysis to realign project plans with actual code reality - discovers drift, gaps, and produces prioritized reconstruction plans",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Avi Fenesh",
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -27,16 +27,13 @@ This workflow exists because each step serves a purpose. Taking shortcuts defeat
|
|
|
27
27
|
1. Every step is mandatory - not suggestions, not guidelines, requirements
|
|
28
28
|
2. Use the specified agents - do not substitute with manual commands
|
|
29
29
|
3. Output verification blocks - prove each step completed
|
|
30
|
-
4. If you think a step is unnecessary,
|
|
30
|
+
4. If you think a step is unnecessary, review the "What Happens If Skipped" column above
|
|
31
31
|
|
|
32
|
-
### Forbidden
|
|
32
|
+
### Forbidden Shortcuts
|
|
33
33
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
- Skipping the 3-minute wait for auto-reviewers
|
|
38
|
-
- Leaving PR comments unaddressed
|
|
39
|
-
- Rationalizing shortcuts ("it's faster", "not needed this time")
|
|
34
|
+
- `git checkout -b` or `git branch` instead of `worktree-manager` agent
|
|
35
|
+
- Single CI check instead of monitoring loop
|
|
36
|
+
- Rationalizing skips ("it's faster", "not needed this time")
|
|
40
37
|
</no-shortcuts-policy>
|
|
41
38
|
|
|
42
39
|
---
|
|
@@ -79,11 +76,8 @@ Each phase must complete before the next starts:
|
|
|
79
76
|
| Ship | Explicit /ship invocation (not hook-only) |
|
|
80
77
|
|
|
81
78
|
**Forbidden actions for agents:**
|
|
82
|
-
- No agent may create PRs (only /ship)
|
|
83
|
-
- No agent may
|
|
84
|
-
- No agent may skip Phase 9 review loop
|
|
85
|
-
- No agent may skip delivery-validator
|
|
86
|
-
- No agent may skip docs update (sync-docs-agent)
|
|
79
|
+
- No agent may create PRs or push to remote (only /ship)
|
|
80
|
+
- No agent may skip Phase 9, delivery-validator, or docs update
|
|
87
81
|
</workflow-gates>
|
|
88
82
|
|
|
89
83
|
## Arguments
|
|
@@ -170,18 +164,36 @@ if (args.includes('--resume')) {
|
|
|
170
164
|
}
|
|
171
165
|
```
|
|
172
166
|
|
|
167
|
+
<phase-1>
|
|
173
168
|
## Phase 1: Policy Selection
|
|
174
169
|
|
|
175
|
-
No agent needed. Use `lib/sources/policy-questions.js
|
|
170
|
+
No agent needed. Use AskUserQuestion tool with ALL 3 questions from `lib/sources/policy-questions.js`.
|
|
171
|
+
|
|
172
|
+
**MANDATORY - Ask ALL 3 Questions:**
|
|
173
|
+
|
|
174
|
+
| # | Header | Question | Options |
|
|
175
|
+
|---|--------|----------|---------|
|
|
176
|
+
| 1 | Source | Where should I look for tasks? | GitHub Issues, GitLab Issues, Local tasks.md, Custom, Other (+ cached if exists) |
|
|
177
|
+
| 2 | Priority | What type of tasks to prioritize? | All, Bugs, Security, Features |
|
|
178
|
+
| 3 | Stop Point | How far should I take this task? | Merged, PR Created, Implemented, Deployed, Production |
|
|
179
|
+
|
|
180
|
+
**Forbidden Actions:**
|
|
181
|
+
- Skipping any of the 3 questions
|
|
182
|
+
- Inventing your own questions instead of using the exact ones above
|
|
183
|
+
- Proceeding to Phase 2 without all 3 answers
|
|
176
184
|
|
|
177
185
|
```javascript
|
|
186
|
+
// Reference implementation - use ALL questions
|
|
178
187
|
const { sources } = require(path.join(pluginRoot, 'lib'));
|
|
179
188
|
const { questions, cachedPreference } = sources.getPolicyQuestions();
|
|
180
|
-
|
|
189
|
+
// questions array contains all 3 questions above
|
|
190
|
+
AskUserQuestion({ questions }); // Pass all 3 questions
|
|
181
191
|
const policy = sources.parseAndCachePolicy(responses);
|
|
182
192
|
workflowState.updateFlow({ policy, phase: 'task-discovery' });
|
|
183
193
|
```
|
|
194
|
+
</phase-1>
|
|
184
195
|
|
|
196
|
+
<phase-2>
|
|
185
197
|
## Phase 2: Task Discovery
|
|
186
198
|
|
|
187
199
|
**Agent**: `next-task:task-discoverer` (sonnet)
|
|
@@ -193,6 +205,7 @@ await Task({
|
|
|
193
205
|
prompt: `Discover tasks from source: ${JSON.stringify(policy.taskSource)}. Filter: ${policy.priorityFilter}. Present top 5 for selection.`
|
|
194
206
|
});
|
|
195
207
|
```
|
|
208
|
+
</phase-2>
|
|
196
209
|
|
|
197
210
|
<phase-3>
|
|
198
211
|
## Phase 3: Worktree Setup
|
|
@@ -224,6 +237,7 @@ console.log(`[VERIFIED] Worktree: ${worktreeResult.worktreePath}`);
|
|
|
224
237
|
- Skipping worktree "because branching is faster"
|
|
225
238
|
</phase-3>
|
|
226
239
|
|
|
240
|
+
<phase-4>
|
|
227
241
|
## Phase 4: Exploration
|
|
228
242
|
|
|
229
243
|
**Agent**: `next-task:exploration-agent` (opus)
|
|
@@ -236,7 +250,9 @@ await Task({
|
|
|
236
250
|
prompt: `Deep codebase analysis for task #${state.task.id}. Find key files, patterns, dependencies.`
|
|
237
251
|
});
|
|
238
252
|
```
|
|
253
|
+
</phase-4>
|
|
239
254
|
|
|
255
|
+
<phase-5>
|
|
240
256
|
## Phase 5: Planning
|
|
241
257
|
|
|
242
258
|
**Agent**: `next-task:planning-agent` (opus)
|
|
@@ -249,7 +265,9 @@ const planOutput = await Task({
|
|
|
249
265
|
prompt: `Design implementation plan for task #${state.task.id}. Output structured JSON between === PLAN_START === and === PLAN_END === markers.`
|
|
250
266
|
});
|
|
251
267
|
```
|
|
268
|
+
</phase-5>
|
|
252
269
|
|
|
270
|
+
<phase-6>
|
|
253
271
|
## Phase 6: User Approval (Plan Mode)
|
|
254
272
|
|
|
255
273
|
**Last human interaction point.** Present plan via EnterPlanMode/ExitPlanMode.
|
|
@@ -259,7 +277,9 @@ EnterPlanMode();
|
|
|
259
277
|
// User reviews and approves via ExitPlanMode
|
|
260
278
|
workflowState.completePhase({ planApproved: true, plan });
|
|
261
279
|
```
|
|
280
|
+
</phase-6>
|
|
262
281
|
|
|
282
|
+
<phase-7>
|
|
263
283
|
## Phase 7: Implementation
|
|
264
284
|
|
|
265
285
|
**Agent**: `next-task:implementation-agent` (opus)
|
|
@@ -273,7 +293,9 @@ await Task({
|
|
|
273
293
|
});
|
|
274
294
|
// → SubagentStop hook triggers pre-review gates
|
|
275
295
|
```
|
|
296
|
+
</phase-7>
|
|
276
297
|
|
|
298
|
+
<phase-8>
|
|
277
299
|
## Phase 8: Pre-Review Gates
|
|
278
300
|
|
|
279
301
|
**Agents** (parallel): `deslop:deslop-agent` + `next-task:test-coverage-checker` (sonnet)
|
|
@@ -318,6 +340,7 @@ Use Edit tool to apply. Commit message: "fix: clean up AI slop"`
|
|
|
318
340
|
});
|
|
319
341
|
}
|
|
320
342
|
```
|
|
343
|
+
</phase-8>
|
|
321
344
|
|
|
322
345
|
<phase-9>
|
|
323
346
|
## Phase 9: Review Loop
|
|
@@ -416,6 +439,7 @@ After review loop completes, output:
|
|
|
416
439
|
```
|
|
417
440
|
</phase-9>
|
|
418
441
|
|
|
442
|
+
<phase-10>
|
|
419
443
|
## Phase 10: Delivery Validation
|
|
420
444
|
|
|
421
445
|
**Agent**: `next-task:delivery-validator` (sonnet)
|
|
@@ -431,7 +455,9 @@ if (!result.approved) {
|
|
|
431
455
|
return; // Retries from implementation
|
|
432
456
|
}
|
|
433
457
|
```
|
|
458
|
+
</phase-10>
|
|
434
459
|
|
|
460
|
+
<phase-11>
|
|
435
461
|
## Phase 11: Docs Update
|
|
436
462
|
|
|
437
463
|
**Agent**: `sync-docs:sync-docs-agent` (sonnet)
|
|
@@ -474,9 +500,10 @@ Use the Edit tool to apply each fix. Commit message: "docs: sync documentation w
|
|
|
474
500
|
|
|
475
501
|
workflowState.completePhase({ docsUpdated: true, fixesApplied: result.fixes?.length || 0 });
|
|
476
502
|
```
|
|
503
|
+
</phase-11>
|
|
477
504
|
|
|
478
|
-
<
|
|
479
|
-
## Handoff to /ship
|
|
505
|
+
<phase-12>
|
|
506
|
+
## Phase 12: Handoff to /ship
|
|
480
507
|
|
|
481
508
|
After docs update (sync-docs-agent) completes, invoke /ship explicitly:
|
|
482
509
|
|
|
@@ -491,7 +518,7 @@ await Task({ subagent_type: "ship:ship", prompt: `Ship the task. State file: ${s
|
|
|
491
518
|
- Monitor CI and review comments
|
|
492
519
|
- Merge when approved
|
|
493
520
|
- Cleanup worktree and tasks.json
|
|
494
|
-
</
|
|
521
|
+
</phase-12>
|
|
495
522
|
|
|
496
523
|
## Error Handling
|
|
497
524
|
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
|
@@ -275,6 +275,24 @@ const slopPatterns = {
|
|
|
275
275
|
description: 'Rust panic!("TODO: ...") placeholder'
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Rust: Bare .unwrap() calls without error context
|
|
280
|
+
* Can cause panics in production - prefer:
|
|
281
|
+
* - .unwrap_or(default) / .unwrap_or_else(|| ...)
|
|
282
|
+
* - .unwrap_or_default()
|
|
283
|
+
* - .expect("descriptive message")
|
|
284
|
+
* - ? operator for propagation
|
|
285
|
+
* - .ok() / .map() / .and_then() for transformation
|
|
286
|
+
*/
|
|
287
|
+
rust_bare_unwrap: {
|
|
288
|
+
pattern: /\.unwrap\(\s*\)(?!\s*\.)/,
|
|
289
|
+
exclude: ['*_test.rs', '*_tests.rs', '**/tests/**', '**/examples/**', '**/benches/**'],
|
|
290
|
+
severity: 'medium',
|
|
291
|
+
autoFix: 'flag',
|
|
292
|
+
language: 'rust',
|
|
293
|
+
description: 'Bare .unwrap() can panic - use .expect(), .unwrap_or(), or ? operator'
|
|
294
|
+
},
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Python: raise NotImplementedError
|
|
280
298
|
*/
|
package/scripts/dev-install.js
CHANGED
|
@@ -30,8 +30,22 @@ const VERSION = require(path.join(SOURCE_DIR, 'package.json')).version;
|
|
|
30
30
|
// Target directories
|
|
31
31
|
const HOME = process.env.HOME || process.env.USERPROFILE;
|
|
32
32
|
const CLAUDE_PLUGINS_DIR = path.join(HOME, '.claude', 'plugins');
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get OpenCode config directory following XDG Base Directory Specification.
|
|
36
|
+
* OpenCode uses ~/.config/opencode/ by default, or $XDG_CONFIG_HOME/opencode if set.
|
|
37
|
+
*/
|
|
38
|
+
function getOpenCodeConfigDir() {
|
|
39
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
40
|
+
if (xdgConfigHome && xdgConfigHome.trim()) {
|
|
41
|
+
return path.join(xdgConfigHome, 'opencode');
|
|
42
|
+
}
|
|
43
|
+
return path.join(HOME, '.config', 'opencode');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const OPENCODE_CONFIG_DIR = getOpenCodeConfigDir();
|
|
47
|
+
// Legacy path - kept for cleanup of old installations
|
|
48
|
+
const LEGACY_OPENCODE_DIR = path.join(HOME, '.opencode');
|
|
35
49
|
const CODEX_DIR = path.join(HOME, '.codex');
|
|
36
50
|
const AWESOME_SLASH_DIR = path.join(HOME, '.awesome-slash');
|
|
37
51
|
|
|
@@ -66,33 +80,63 @@ function cleanAll() {
|
|
|
66
80
|
}
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
// Clean OpenCode
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
83
|
+
// Clean OpenCode (correct XDG path: ~/.config/opencode/)
|
|
84
|
+
// OpenCode expects commands directly in commands/, not a subdirectory
|
|
85
|
+
const opencodeCommandsDir = path.join(OPENCODE_CONFIG_DIR, 'commands');
|
|
86
|
+
const opencodePluginDir = path.join(OPENCODE_CONFIG_DIR, 'plugins');
|
|
87
|
+
const opencodeAgentsDir = path.join(OPENCODE_CONFIG_DIR, 'agents');
|
|
88
|
+
// Note: Skills cleanup not implemented yet - would need skill list similar to agents
|
|
89
|
+
|
|
90
|
+
// List of agent filenames we install (from plugins/*/agents/*.md)
|
|
91
|
+
// Generated from: ls plugins/*/agents/*.md | xargs basename | sort -u
|
|
92
|
+
const knownAgents = [
|
|
93
|
+
'agent-enhancer.md', 'ci-fixer.md', 'ci-monitor.md', 'claudemd-enhancer.md',
|
|
94
|
+
'delivery-validator.md', 'deslop-agent.md', 'docs-enhancer.md', 'enhancement-orchestrator.md',
|
|
95
|
+
'enhancement-reporter.md', 'exploration-agent.md', 'hooks-enhancer.md', 'implementation-agent.md',
|
|
96
|
+
'map-validator.md', 'perf-analyzer.md', 'perf-code-paths.md', 'perf-investigation-logger.md',
|
|
97
|
+
'perf-orchestrator.md', 'perf-theory-gatherer.md', 'perf-theory-tester.md', 'plan-synthesizer.md',
|
|
98
|
+
'planning-agent.md', 'plugin-enhancer.md', 'prompt-enhancer.md', 'simple-fixer.md',
|
|
99
|
+
'skills-enhancer.md', 'sync-docs-agent.md', 'task-discoverer.md', 'test-coverage-checker.md',
|
|
100
|
+
'worktree-manager.md'
|
|
101
|
+
];
|
|
73
102
|
|
|
103
|
+
// Known commands we install
|
|
104
|
+
const knownCommands = [
|
|
105
|
+
'deslop.md', 'enhance.md', 'next-task.md', 'delivery-approval.md',
|
|
106
|
+
'sync-docs.md', 'audit-project.md', 'ship.md', 'drift-detect.md',
|
|
107
|
+
'repo-map.md', 'perf.md'
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
// Clean commands (remove our files, not the whole directory)
|
|
74
111
|
if (fs.existsSync(opencodeCommandsDir)) {
|
|
75
|
-
|
|
76
|
-
|
|
112
|
+
let removedCount = 0;
|
|
113
|
+
for (const file of knownCommands) {
|
|
114
|
+
const filePath = path.join(opencodeCommandsDir, file);
|
|
115
|
+
if (fs.existsSync(filePath)) {
|
|
116
|
+
fs.unlinkSync(filePath);
|
|
117
|
+
removedCount++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Also clean lib directory we install
|
|
121
|
+
const libDir = path.join(opencodeCommandsDir, 'lib');
|
|
122
|
+
if (fs.existsSync(libDir)) {
|
|
123
|
+
fs.rmSync(libDir, { recursive: true, force: true });
|
|
124
|
+
removedCount++;
|
|
125
|
+
}
|
|
126
|
+
if (removedCount > 0) {
|
|
127
|
+
log(` Removed ${removedCount} OpenCode commands/lib`);
|
|
128
|
+
}
|
|
77
129
|
}
|
|
78
|
-
|
|
79
|
-
|
|
130
|
+
|
|
131
|
+
// Clean plugin file
|
|
132
|
+
const pluginFile = path.join(opencodePluginDir, 'awesome-slash.ts');
|
|
133
|
+
if (fs.existsSync(pluginFile)) {
|
|
134
|
+
fs.unlinkSync(pluginFile);
|
|
80
135
|
log(' Removed OpenCode plugin');
|
|
81
136
|
}
|
|
137
|
+
|
|
82
138
|
// Clean agent files installed by us - only known awesome-slash agents
|
|
83
139
|
if (fs.existsSync(opencodeAgentsDir)) {
|
|
84
|
-
// List of agent filenames we install (from plugins/*/agents/*.md)
|
|
85
|
-
const knownAgents = [
|
|
86
|
-
'plan-synthesizer.md', 'enhancement-reporter.md', 'ci-fixer.md',
|
|
87
|
-
'deslop-work.md', 'simple-fixer.md', 'perf-analyzer.md', 'perf-code-paths.md',
|
|
88
|
-
'perf-investigation-logger.md', 'perf-theory-gatherer.md', 'perf-theory-tester.md',
|
|
89
|
-
'map-validator.md', 'exploration-agent.md', 'perf-orchestrator.md', 'ci-monitor.md',
|
|
90
|
-
'implementation-agent.md', 'planning-agent.md', 'test-coverage-checker.md',
|
|
91
|
-
'plugin-enhancer.md', 'agent-enhancer.md', 'docs-enhancer.md', 'claudemd-enhancer.md',
|
|
92
|
-
'prompt-enhancer.md', 'hooks-enhancer.md', 'skills-enhancer.md', 'enhancement-orchestrator.md',
|
|
93
|
-
'task-discoverer.md', 'delivery-validator.md', 'docs-updater.md', 'worktree-manager.md',
|
|
94
|
-
'deslop-analyzer.md', 'docs-analyzer.md', 'docs-validator.md'
|
|
95
|
-
];
|
|
96
140
|
let removedCount = 0;
|
|
97
141
|
for (const file of knownAgents) {
|
|
98
142
|
const filePath = path.join(opencodeAgentsDir, file);
|
|
@@ -106,6 +150,33 @@ function cleanAll() {
|
|
|
106
150
|
}
|
|
107
151
|
}
|
|
108
152
|
|
|
153
|
+
// Clean legacy OpenCode paths (~/.opencode/ - incorrect, pre-XDG)
|
|
154
|
+
const legacyCommandsDir = path.join(LEGACY_OPENCODE_DIR, 'commands', 'awesome-slash');
|
|
155
|
+
const legacyPluginDir = path.join(LEGACY_OPENCODE_DIR, 'plugins', 'awesome-slash');
|
|
156
|
+
const legacyAgentsDir = path.join(LEGACY_OPENCODE_DIR, 'agents');
|
|
157
|
+
|
|
158
|
+
if (fs.existsSync(legacyCommandsDir)) {
|
|
159
|
+
fs.rmSync(legacyCommandsDir, { recursive: true, force: true });
|
|
160
|
+
log(' Removed legacy ~/.opencode/commands/awesome-slash');
|
|
161
|
+
}
|
|
162
|
+
if (fs.existsSync(legacyPluginDir)) {
|
|
163
|
+
fs.rmSync(legacyPluginDir, { recursive: true, force: true });
|
|
164
|
+
log(' Removed legacy ~/.opencode/plugins/awesome-slash');
|
|
165
|
+
}
|
|
166
|
+
if (fs.existsSync(legacyAgentsDir)) {
|
|
167
|
+
let removedCount = 0;
|
|
168
|
+
for (const file of knownAgents) {
|
|
169
|
+
const filePath = path.join(legacyAgentsDir, file);
|
|
170
|
+
if (fs.existsSync(filePath)) {
|
|
171
|
+
fs.unlinkSync(filePath);
|
|
172
|
+
removedCount++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (removedCount > 0) {
|
|
176
|
+
log(` Removed ${removedCount} legacy OpenCode agents from ~/.opencode/`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
109
180
|
// Clean Codex
|
|
110
181
|
const codexSkillsDir = path.join(CODEX_DIR, 'skills');
|
|
111
182
|
if (fs.existsSync(codexSkillsDir)) {
|
|
@@ -219,29 +290,40 @@ function installClaude() {
|
|
|
219
290
|
function installOpenCode() {
|
|
220
291
|
log('Installing for OpenCode...');
|
|
221
292
|
|
|
222
|
-
// Create directories
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
const
|
|
293
|
+
// Create directories in correct XDG location (~/.config/opencode/)
|
|
294
|
+
// OpenCode expects commands directly in commands/, not a subdirectory
|
|
295
|
+
const commandsDir = path.join(OPENCODE_CONFIG_DIR, 'commands');
|
|
296
|
+
const pluginDir = path.join(OPENCODE_CONFIG_DIR, 'plugins');
|
|
297
|
+
const agentsDir = path.join(OPENCODE_CONFIG_DIR, 'agents');
|
|
226
298
|
|
|
227
299
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
228
300
|
fs.mkdirSync(pluginDir, { recursive: true });
|
|
229
301
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
230
302
|
|
|
303
|
+
// Clean up legacy paths (~/.opencode/) if they exist
|
|
304
|
+
const legacyCommandsDir = path.join(LEGACY_OPENCODE_DIR, 'commands', 'awesome-slash');
|
|
305
|
+
const legacyPluginDir = path.join(LEGACY_OPENCODE_DIR, 'plugins', 'awesome-slash');
|
|
306
|
+
if (fs.existsSync(legacyCommandsDir)) {
|
|
307
|
+
fs.rmSync(legacyCommandsDir, { recursive: true, force: true });
|
|
308
|
+
log(' Cleaned up legacy ~/.opencode/commands/awesome-slash');
|
|
309
|
+
}
|
|
310
|
+
if (fs.existsSync(legacyPluginDir)) {
|
|
311
|
+
fs.rmSync(legacyPluginDir, { recursive: true, force: true });
|
|
312
|
+
log(' Cleaned up legacy ~/.opencode/plugins/awesome-slash');
|
|
313
|
+
}
|
|
314
|
+
|
|
231
315
|
// Copy to ~/.awesome-slash first (OpenCode needs local files)
|
|
232
316
|
copyToAwesomeSlash();
|
|
233
317
|
|
|
234
|
-
// Copy native plugin
|
|
318
|
+
// Copy native plugin (OpenCode expects plugins as single .ts files in ~/.config/opencode/plugins/)
|
|
235
319
|
const pluginSrcDir = path.join(SOURCE_DIR, 'adapters', 'opencode-plugin');
|
|
236
320
|
if (fs.existsSync(pluginSrcDir)) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
321
|
+
const srcPath = path.join(pluginSrcDir, 'index.ts');
|
|
322
|
+
const destPath = path.join(pluginDir, 'awesome-slash.ts');
|
|
323
|
+
if (fs.existsSync(srcPath)) {
|
|
324
|
+
fs.copyFileSync(srcPath, destPath);
|
|
325
|
+
log(' [OK] Native plugin');
|
|
243
326
|
}
|
|
244
|
-
log(' [OK] Native plugin');
|
|
245
327
|
}
|
|
246
328
|
|
|
247
329
|
// Transform helpers
|
|
@@ -14,7 +14,20 @@ const fs = require('fs');
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
|
|
16
16
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get OpenCode config directory following XDG Base Directory Specification.
|
|
20
|
+
* OpenCode uses ~/.config/opencode/ by default, or $XDG_CONFIG_HOME/opencode if set.
|
|
21
|
+
*/
|
|
22
|
+
function getOpenCodeConfigDir() {
|
|
23
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
24
|
+
if (xdgConfigHome && xdgConfigHome.trim()) {
|
|
25
|
+
return path.join(xdgConfigHome, 'opencode');
|
|
26
|
+
}
|
|
27
|
+
return path.join(home, '.config', 'opencode');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const OPENCODE_DIR = getOpenCodeConfigDir();
|
|
18
31
|
|
|
19
32
|
const issues = [];
|
|
20
33
|
|
|
@@ -119,7 +132,8 @@ console.log('Validating OpenCode Installation...\n');
|
|
|
119
132
|
console.log(`OpenCode directory: ${OPENCODE_DIR}\n`);
|
|
120
133
|
|
|
121
134
|
// Validate each type
|
|
122
|
-
|
|
135
|
+
// OpenCode expects commands directly in commands/, not a subdirectory
|
|
136
|
+
validateDirectory(path.join(OPENCODE_DIR, 'commands'), 'commands');
|
|
123
137
|
validateDirectory(path.join(OPENCODE_DIR, 'agents'), 'agents');
|
|
124
138
|
validateDirectory(path.join(OPENCODE_DIR, 'skills'), 'skills');
|
|
125
139
|
|