aiwcli 0.9.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.
- package/README.md +1248 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +16 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +19 -0
- package/dist/commands/branch.d.ts +45 -0
- package/dist/commands/branch.js +488 -0
- package/dist/commands/clean.d.ts +34 -0
- package/dist/commands/clean.js +186 -0
- package/dist/commands/clear.d.ts +51 -0
- package/dist/commands/clear.js +835 -0
- package/dist/commands/init/index.d.ts +107 -0
- package/dist/commands/init/index.js +565 -0
- package/dist/commands/launch.d.ts +21 -0
- package/dist/commands/launch.js +108 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/base-command.d.ts +114 -0
- package/dist/lib/base-command.js +153 -0
- package/dist/lib/bmad-installer.d.ts +38 -0
- package/dist/lib/bmad-installer.js +145 -0
- package/dist/lib/claude-settings-types.d.ts +102 -0
- package/dist/lib/claude-settings-types.js +5 -0
- package/dist/lib/config.d.ts +25 -0
- package/dist/lib/config.js +46 -0
- package/dist/lib/debug.d.ts +39 -0
- package/dist/lib/debug.js +74 -0
- package/dist/lib/env-compat.d.ts +26 -0
- package/dist/lib/env-compat.js +35 -0
- package/dist/lib/errors.d.ts +126 -0
- package/dist/lib/errors.js +145 -0
- package/dist/lib/generic-merge.d.ts +74 -0
- package/dist/lib/generic-merge.js +105 -0
- package/dist/lib/git/branch.d.ts +67 -0
- package/dist/lib/git/branch.js +155 -0
- package/dist/lib/git/index.d.ts +11 -0
- package/dist/lib/git/index.js +13 -0
- package/dist/lib/git/safety-checks.d.ts +44 -0
- package/dist/lib/git/safety-checks.js +102 -0
- package/dist/lib/git/types.d.ts +31 -0
- package/dist/lib/git/types.js +6 -0
- package/dist/lib/git/worktree.d.ts +67 -0
- package/dist/lib/git/worktree.js +220 -0
- package/dist/lib/gitignore-manager.d.ts +10 -0
- package/dist/lib/gitignore-manager.js +60 -0
- package/dist/lib/hooks-merger.d.ts +28 -0
- package/dist/lib/hooks-merger.js +94 -0
- package/dist/lib/ide-path-resolver.d.ts +102 -0
- package/dist/lib/ide-path-resolver.js +129 -0
- package/dist/lib/index.d.ts +13 -0
- package/dist/lib/index.js +22 -0
- package/dist/lib/output.d.ts +51 -0
- package/dist/lib/output.js +76 -0
- package/dist/lib/paths.d.ts +66 -0
- package/dist/lib/paths.js +136 -0
- package/dist/lib/quiet.d.ts +12 -0
- package/dist/lib/quiet.js +17 -0
- package/dist/lib/settings-hierarchy.d.ts +42 -0
- package/dist/lib/settings-hierarchy.js +105 -0
- package/dist/lib/spawn.d.ts +105 -0
- package/dist/lib/spawn.js +157 -0
- package/dist/lib/spinner.d.ts +19 -0
- package/dist/lib/spinner.js +34 -0
- package/dist/lib/stdin.d.ts +48 -0
- package/dist/lib/stdin.js +60 -0
- package/dist/lib/template-installer.d.ts +92 -0
- package/dist/lib/template-installer.js +375 -0
- package/dist/lib/template-linter.d.ts +49 -0
- package/dist/lib/template-linter.js +173 -0
- package/dist/lib/template-merger.d.ts +47 -0
- package/dist/lib/template-merger.js +173 -0
- package/dist/lib/template-resolver.d.ts +20 -0
- package/dist/lib/template-resolver.js +60 -0
- package/dist/lib/terminal.d.ts +102 -0
- package/dist/lib/terminal.js +245 -0
- package/dist/lib/tty-detection.d.ts +62 -0
- package/dist/lib/tty-detection.js +83 -0
- package/dist/lib/user-utils.d.ts +5 -0
- package/dist/lib/user-utils.js +23 -0
- package/dist/lib/version.d.ts +99 -0
- package/dist/lib/version.js +144 -0
- package/dist/lib/watch-templates.d.ts +6 -0
- package/dist/lib/watch-templates.js +73 -0
- package/dist/lib/windsurf-hooks-hierarchy.d.ts +30 -0
- package/dist/lib/windsurf-hooks-hierarchy.js +66 -0
- package/dist/lib/windsurf-hooks-merger.d.ts +26 -0
- package/dist/lib/windsurf-hooks-merger.js +53 -0
- package/dist/lib/windsurf-hooks-types.d.ts +33 -0
- package/dist/lib/windsurf-hooks-types.js +5 -0
- package/dist/templates/CLAUDE.md +174 -0
- package/dist/templates/_shared/.claude/commands/handoff.md +14 -0
- package/dist/templates/_shared/.claude/settings.json +61 -0
- package/dist/templates/_shared/.codex/workflows/handoff.md +14 -0
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +14 -0
- package/dist/templates/_shared/hooks/__init__.py +16 -0
- package/dist/templates/_shared/hooks/archive_plan.py +270 -0
- package/dist/templates/_shared/hooks/context_enforcer.py +621 -0
- package/dist/templates/_shared/hooks/context_monitor.py +322 -0
- package/dist/templates/_shared/hooks/file-suggestion.py +188 -0
- package/dist/templates/_shared/hooks/task_create_capture.py +194 -0
- package/dist/templates/_shared/hooks/task_update_capture.py +254 -0
- package/dist/templates/_shared/hooks/user_prompt_submit.py +157 -0
- package/dist/templates/_shared/lib/__init__.py +1 -0
- package/dist/templates/_shared/lib/base/__init__.py +49 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/atomic_write.py +180 -0
- package/dist/templates/_shared/lib/base/constants.py +299 -0
- package/dist/templates/_shared/lib/base/inference.py +189 -0
- package/dist/templates/_shared/lib/base/utils.py +216 -0
- package/dist/templates/_shared/lib/context/__init__.py +119 -0
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/cache.py +446 -0
- package/dist/templates/_shared/lib/context/context_manager.py +1171 -0
- package/dist/templates/_shared/lib/context/discovery.py +486 -0
- package/dist/templates/_shared/lib/context/event_log.py +308 -0
- package/dist/templates/_shared/lib/context/plan_archive.py +247 -0
- package/dist/templates/_shared/lib/context/task_sync.py +367 -0
- package/dist/templates/_shared/lib/handoff/__init__.py +22 -0
- package/dist/templates/_shared/lib/handoff/document_generator.py +307 -0
- package/dist/templates/_shared/lib/templates/README.md +215 -0
- package/dist/templates/_shared/lib/templates/__init__.py +40 -0
- package/dist/templates/_shared/lib/templates/formatters.py +147 -0
- package/dist/templates/_shared/lib/templates/plan_context.py +119 -0
- package/dist/templates/_shared/scripts/save_handoff.py +99 -0
- package/dist/templates/_shared/workflows/handoff.md +212 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +75 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +239 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +109 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +71 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +104 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +223 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +73 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +103 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +145 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +248 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +235 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +76 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +141 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +240 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +211 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +101 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +197 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +97 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +349 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +106 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +205 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -0
- package/dist/templates/cc-native/.claude/settings.json +119 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -0
- package/dist/templates/cc-native/CC-NATIVE-README.md +192 -0
- package/dist/templates/cc-native/MIGRATION.md +86 -0
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +331 -0
- package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +147 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +150 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +746 -0
- package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +339 -0
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +57 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/async_archive.py +68 -0
- package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +98 -0
- package/dist/templates/cc-native/_cc-native/lib/constants.py +45 -0
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +273 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +28 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +164 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +89 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +119 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +103 -0
- package/dist/templates/cc-native/_cc-native/lib/state.py +251 -0
- package/dist/templates/cc-native/_cc-native/lib/utils.py +830 -0
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +76 -0
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +151 -0
- package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +134 -0
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -0
- package/dist/types/exit-codes.d.ts +11 -0
- package/dist/types/exit-codes.js +10 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -0
- package/oclif.manifest.json +405 -0
- package/package.json +109 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTY Detection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides cross-platform TTY detection for controlling color output and spinners.
|
|
5
|
+
* Respects NO_COLOR and FORCE_COLOR environment variables per standard conventions.
|
|
6
|
+
*/
|
|
7
|
+
import { isQuietMode as getQuietMode } from './quiet.js';
|
|
8
|
+
/**
|
|
9
|
+
* Check if stdout is a TTY (terminal).
|
|
10
|
+
* Returns true for interactive terminal, false for piped/redirected output.
|
|
11
|
+
* @param proc - Optional process-like object for testing (defaults to global process)
|
|
12
|
+
*/
|
|
13
|
+
export function isTTY(proc = process) {
|
|
14
|
+
return proc.stdout.isTTY === true;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if stderr is a TTY (terminal).
|
|
18
|
+
* Useful for determining if error output should use colors.
|
|
19
|
+
* @param proc - Optional process-like object for testing (defaults to global process)
|
|
20
|
+
*/
|
|
21
|
+
export function isStderrTTY(proc = process) {
|
|
22
|
+
return proc.stderr?.isTTY === true;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Determine if colors should be used in output.
|
|
26
|
+
* Respects NO_COLOR and FORCE_COLOR environment variables.
|
|
27
|
+
*
|
|
28
|
+
* Priority:
|
|
29
|
+
* 1. NO_COLOR (if set, always disable)
|
|
30
|
+
* 2. FORCE_COLOR (if set, use level 0-3)
|
|
31
|
+
* 3. TTY detection (colors only in TTY)
|
|
32
|
+
*
|
|
33
|
+
* @param proc - Optional process-like object for testing (defaults to global process)
|
|
34
|
+
*/
|
|
35
|
+
export function shouldUseColors(proc = process) {
|
|
36
|
+
const env = proc.env ?? process.env;
|
|
37
|
+
const noColor = env.NO_COLOR;
|
|
38
|
+
const forceColor = env.FORCE_COLOR;
|
|
39
|
+
// NO_COLOR takes precedence (any value disables colors)
|
|
40
|
+
if (noColor !== undefined) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
// FORCE_COLOR overrides TTY detection
|
|
44
|
+
if (forceColor !== undefined) {
|
|
45
|
+
const level = Number.parseInt(forceColor, 10);
|
|
46
|
+
return level > 0;
|
|
47
|
+
}
|
|
48
|
+
// Default: colors only in TTY
|
|
49
|
+
return isTTY(proc);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if quiet mode is enabled from flags.
|
|
53
|
+
* Quiet mode suppresses informational output (errors still shown).
|
|
54
|
+
* @param flags - Optional flags object
|
|
55
|
+
* @param flags.quiet - Quiet mode flag
|
|
56
|
+
*/
|
|
57
|
+
export function isQuietMode(flags) {
|
|
58
|
+
// If flags provided, use them directly (for testing)
|
|
59
|
+
if (flags !== undefined) {
|
|
60
|
+
return flags?.quiet === true;
|
|
61
|
+
}
|
|
62
|
+
// Otherwise use module-level state
|
|
63
|
+
return getQuietMode();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Determine if progress spinners should be shown.
|
|
67
|
+
* Spinners only make sense in interactive terminals.
|
|
68
|
+
* Automatically disabled in CI environments and quiet mode.
|
|
69
|
+
* @param flags - Optional flags object with quiet mode
|
|
70
|
+
* @param proc - Optional process-like object for testing (defaults to global process)
|
|
71
|
+
*/
|
|
72
|
+
export function shouldShowSpinners(flags, proc = process) {
|
|
73
|
+
const env = proc.env ?? process.env;
|
|
74
|
+
// Spinners disabled in CI environments
|
|
75
|
+
if (env.CI) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// Spinners disabled in quiet mode
|
|
79
|
+
if (isQuietMode(flags)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return isTTY(proc);
|
|
83
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Detect username from git config or environment variables.
|
|
4
|
+
* Priority: git config user.name > USER env > USERNAME env > fallback to "User"
|
|
5
|
+
*/
|
|
6
|
+
export async function detectUsername() {
|
|
7
|
+
// Try git config first
|
|
8
|
+
try {
|
|
9
|
+
const gitUser = execSync('git config user.name', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
10
|
+
const username = gitUser.trim();
|
|
11
|
+
if (username)
|
|
12
|
+
return username;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Git command failed or not configured, continue to env vars
|
|
16
|
+
}
|
|
17
|
+
// Try environment variables
|
|
18
|
+
const envUser = process.env['USER'] ?? process.env['USERNAME'];
|
|
19
|
+
if (envUser)
|
|
20
|
+
return envUser;
|
|
21
|
+
// Fallback
|
|
22
|
+
return 'User';
|
|
23
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Version detection and compatibility checking for Claude Code CLI.
|
|
3
|
+
*
|
|
4
|
+
* This module provides:
|
|
5
|
+
* - Claude Code version detection via `claude --version`
|
|
6
|
+
* - Semantic version compatibility checking
|
|
7
|
+
* - Graceful degradation when version unavailable
|
|
8
|
+
*
|
|
9
|
+
* ## Usage Pattern
|
|
10
|
+
*
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import {getClaudeCodeVersion, checkVersionCompatibility} from '../lib/version.js'
|
|
13
|
+
*
|
|
14
|
+
* const version = await getClaudeCodeVersion()
|
|
15
|
+
* const versionCheck = checkVersionCompatibility(version)
|
|
16
|
+
*
|
|
17
|
+
* if (versionCheck.warning) {
|
|
18
|
+
* this.warn(versionCheck.warning)
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* if (this.debugEnabled) {
|
|
22
|
+
* this.debug(`Claude Code version: ${versionCheck.version || 'unknown'}`)
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @module lib/version
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Minimum supported Claude Code version.
|
|
30
|
+
* Versions below this will trigger a compatibility warning.
|
|
31
|
+
*/
|
|
32
|
+
export declare const MIN_CLAUDE_CODE_VERSION = "0.1.0";
|
|
33
|
+
/**
|
|
34
|
+
* Known incompatible Claude Code versions.
|
|
35
|
+
* These versions have confirmed issues with AI Workflow CLI.
|
|
36
|
+
*/
|
|
37
|
+
export declare const INCOMPATIBLE_VERSIONS: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Result of version compatibility check.
|
|
40
|
+
*/
|
|
41
|
+
export interface VersionCheckResult {
|
|
42
|
+
/**
|
|
43
|
+
* Whether the version is compatible with AI Workflow CLI.
|
|
44
|
+
* If version is unknown, assumes compatible (graceful degradation).
|
|
45
|
+
*/
|
|
46
|
+
compatible: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Detected version string (e.g., "0.1.0") or null if unavailable.
|
|
49
|
+
*/
|
|
50
|
+
version: null | string;
|
|
51
|
+
/**
|
|
52
|
+
* Warning message if incompatible or version unavailable.
|
|
53
|
+
* Undefined if version is compatible.
|
|
54
|
+
*/
|
|
55
|
+
warning?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detects Claude Code version by executing `claude --version`.
|
|
59
|
+
*
|
|
60
|
+
* Parses version output formats:
|
|
61
|
+
* - "claude 0.1.0"
|
|
62
|
+
* - "claude version 0.1.0"
|
|
63
|
+
*
|
|
64
|
+
* Returns null on any failure (command not found, invalid output, etc.)
|
|
65
|
+
* to support graceful degradation.
|
|
66
|
+
*
|
|
67
|
+
* @returns Version string (e.g., "0.1.0") or null if unavailable
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const version = await getClaudeCodeVersion()
|
|
72
|
+
* if (version) {
|
|
73
|
+
* console.log(`Claude Code version: ${version}`)
|
|
74
|
+
* } else {
|
|
75
|
+
* console.log('Claude Code version unavailable')
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function getClaudeCodeVersion(): Promise<null | string>;
|
|
80
|
+
/**
|
|
81
|
+
* Checks if a Claude Code version is compatible with AI Workflow CLI.
|
|
82
|
+
*
|
|
83
|
+
* Compatibility rules:
|
|
84
|
+
* 1. Version must be >= MIN_CLAUDE_CODE_VERSION
|
|
85
|
+
* 2. Version must not be in INCOMPATIBLE_VERSIONS list
|
|
86
|
+
* 3. If version is null/unknown, assumes compatible (graceful degradation)
|
|
87
|
+
*
|
|
88
|
+
* @param version - Version string (e.g., "0.1.0") or null if unavailable
|
|
89
|
+
* @returns Compatibility check result with version, compatible flag, and optional warning
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const result = checkVersionCompatibility('0.1.0')
|
|
94
|
+
* if (result.warning) {
|
|
95
|
+
* this.warn(result.warning)
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare function checkVersionCompatibility(version: null | string | undefined): VersionCheckResult;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Version detection and compatibility checking for Claude Code CLI.
|
|
3
|
+
*
|
|
4
|
+
* This module provides:
|
|
5
|
+
* - Claude Code version detection via `claude --version`
|
|
6
|
+
* - Semantic version compatibility checking
|
|
7
|
+
* - Graceful degradation when version unavailable
|
|
8
|
+
*
|
|
9
|
+
* ## Usage Pattern
|
|
10
|
+
*
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import {getClaudeCodeVersion, checkVersionCompatibility} from '../lib/version.js'
|
|
13
|
+
*
|
|
14
|
+
* const version = await getClaudeCodeVersion()
|
|
15
|
+
* const versionCheck = checkVersionCompatibility(version)
|
|
16
|
+
*
|
|
17
|
+
* if (versionCheck.warning) {
|
|
18
|
+
* this.warn(versionCheck.warning)
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* if (this.debugEnabled) {
|
|
22
|
+
* this.debug(`Claude Code version: ${versionCheck.version || 'unknown'}`)
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @module lib/version
|
|
27
|
+
*/
|
|
28
|
+
import { exec } from 'node:child_process';
|
|
29
|
+
import { promisify } from 'node:util';
|
|
30
|
+
const execAsync = promisify(exec);
|
|
31
|
+
/**
|
|
32
|
+
* Minimum supported Claude Code version.
|
|
33
|
+
* Versions below this will trigger a compatibility warning.
|
|
34
|
+
*/
|
|
35
|
+
export const MIN_CLAUDE_CODE_VERSION = '0.1.0';
|
|
36
|
+
/**
|
|
37
|
+
* Known incompatible Claude Code versions.
|
|
38
|
+
* These versions have confirmed issues with AI Workflow CLI.
|
|
39
|
+
*/
|
|
40
|
+
export const INCOMPATIBLE_VERSIONS = ['0.0.9'];
|
|
41
|
+
/**
|
|
42
|
+
* Detects Claude Code version by executing `claude --version`.
|
|
43
|
+
*
|
|
44
|
+
* Parses version output formats:
|
|
45
|
+
* - "claude 0.1.0"
|
|
46
|
+
* - "claude version 0.1.0"
|
|
47
|
+
*
|
|
48
|
+
* Returns null on any failure (command not found, invalid output, etc.)
|
|
49
|
+
* to support graceful degradation.
|
|
50
|
+
*
|
|
51
|
+
* @returns Version string (e.g., "0.1.0") or null if unavailable
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const version = await getClaudeCodeVersion()
|
|
56
|
+
* if (version) {
|
|
57
|
+
* console.log(`Claude Code version: ${version}`)
|
|
58
|
+
* } else {
|
|
59
|
+
* console.log('Claude Code version unavailable')
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export async function getClaudeCodeVersion() {
|
|
64
|
+
try {
|
|
65
|
+
// Set 5 second timeout to prevent hanging
|
|
66
|
+
const { stdout } = await execAsync('claude --version', { timeout: 5000 });
|
|
67
|
+
// Parse version from output formats:
|
|
68
|
+
// - New format: "2.1.3 (Claude Code)"
|
|
69
|
+
// - Old format: "claude 0.1.0" or "claude version 0.1.0"
|
|
70
|
+
const newFormatMatch = stdout.match(/^(\d+\.\d+\.\d+)\s+\(Claude Code\)/i);
|
|
71
|
+
if (newFormatMatch?.[1]) {
|
|
72
|
+
return newFormatMatch[1];
|
|
73
|
+
}
|
|
74
|
+
const oldFormatMatch = stdout.match(/claude\s+(?:version\s+)?(\d+\.\d+\.\d+)/i);
|
|
75
|
+
return oldFormatMatch?.[1] ?? null;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Command not found, execution failed, timeout, or other error
|
|
79
|
+
// Gracefully return null to allow launch to continue
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Checks if a Claude Code version is compatible with AI Workflow CLI.
|
|
85
|
+
*
|
|
86
|
+
* Compatibility rules:
|
|
87
|
+
* 1. Version must be >= MIN_CLAUDE_CODE_VERSION
|
|
88
|
+
* 2. Version must not be in INCOMPATIBLE_VERSIONS list
|
|
89
|
+
* 3. If version is null/unknown, assumes compatible (graceful degradation)
|
|
90
|
+
*
|
|
91
|
+
* @param version - Version string (e.g., "0.1.0") or null if unavailable
|
|
92
|
+
* @returns Compatibility check result with version, compatible flag, and optional warning
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const result = checkVersionCompatibility('0.1.0')
|
|
97
|
+
* if (result.warning) {
|
|
98
|
+
* this.warn(result.warning)
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function checkVersionCompatibility(version) {
|
|
103
|
+
// Handle null/undefined version (graceful degradation)
|
|
104
|
+
if (!version) {
|
|
105
|
+
return {
|
|
106
|
+
compatible: true, // Assume compatible if unknown
|
|
107
|
+
version: null,
|
|
108
|
+
warning: 'Claude Code version could not be determined. Proceeding with caution.',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Check known incompatible versions first
|
|
112
|
+
if (INCOMPATIBLE_VERSIONS.includes(version)) {
|
|
113
|
+
return {
|
|
114
|
+
compatible: false,
|
|
115
|
+
version,
|
|
116
|
+
warning: `Claude Code version ${version} has known issues with AI Workflow CLI. Please upgrade to ${MIN_CLAUDE_CODE_VERSION} or later.`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Parse version numbers for semantic comparison
|
|
120
|
+
const versionParts = version.split('.').map(Number);
|
|
121
|
+
const minVersionParts = MIN_CLAUDE_CODE_VERSION.split('.').map(Number);
|
|
122
|
+
const major = versionParts[0] ?? 0;
|
|
123
|
+
const minor = versionParts[1] ?? 0;
|
|
124
|
+
const patch = versionParts[2] ?? 0;
|
|
125
|
+
const minMajor = minVersionParts[0] ?? 0;
|
|
126
|
+
const minMinor = minVersionParts[1] ?? 0;
|
|
127
|
+
const minPatch = minVersionParts[2] ?? 0;
|
|
128
|
+
// Check if version meets minimum requirement
|
|
129
|
+
const isBelowMinimum = major < minMajor ||
|
|
130
|
+
(major === minMajor && minor < minMinor) ||
|
|
131
|
+
(major === minMajor && minor === minMinor && patch < minPatch);
|
|
132
|
+
if (isBelowMinimum) {
|
|
133
|
+
return {
|
|
134
|
+
compatible: false,
|
|
135
|
+
version,
|
|
136
|
+
warning: `Claude Code version ${version} is below minimum ${MIN_CLAUDE_CODE_VERSION}. Some features may not work correctly. Please upgrade Claude Code.`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Version is compatible
|
|
140
|
+
return {
|
|
141
|
+
compatible: true,
|
|
142
|
+
version,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Watch templates directory and copy changes to dist.
|
|
4
|
+
* Used for development workflow to auto-sync template changes.
|
|
5
|
+
*/
|
|
6
|
+
import { copyFile, mkdir } from 'node:fs/promises';
|
|
7
|
+
import { dirname, join, relative } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { watch } from 'chokidar';
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const SRC_TEMPLATES = join(__dirname, '..', 'templates');
|
|
12
|
+
const DIST_TEMPLATES = join(__dirname, '..', '..', 'dist', 'templates');
|
|
13
|
+
/**
|
|
14
|
+
* Copy a file from src/templates to dist/templates preserving structure.
|
|
15
|
+
*/
|
|
16
|
+
async function copyTemplate(filePath) {
|
|
17
|
+
const relativePath = relative(SRC_TEMPLATES, filePath);
|
|
18
|
+
const destPath = join(DIST_TEMPLATES, relativePath);
|
|
19
|
+
try {
|
|
20
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
21
|
+
await copyFile(filePath, destPath);
|
|
22
|
+
logChange('copied', relativePath);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logError(`Failed to copy ${relativePath}`, error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Log a change with timestamp.
|
|
30
|
+
*/
|
|
31
|
+
function logChange(action, path) {
|
|
32
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
33
|
+
const supportsColor = process.stdout.isTTY;
|
|
34
|
+
if (supportsColor) {
|
|
35
|
+
console.log(`\u001B[2m[${timestamp}]\u001B[0m \u001B[32m${action}\u001B[0m ${path}`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(`[${timestamp}] ${action} ${path}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Log an error.
|
|
43
|
+
*/
|
|
44
|
+
function logError(message, error) {
|
|
45
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
46
|
+
console.error(`[${timestamp}] \u001B[31merror\u001B[0m ${message}:`, error);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Start watching templates directory.
|
|
50
|
+
*/
|
|
51
|
+
function startWatching() {
|
|
52
|
+
console.log('Watching templates for changes...');
|
|
53
|
+
console.log(` Source: ${SRC_TEMPLATES}`);
|
|
54
|
+
console.log(` Dest: ${DIST_TEMPLATES}`);
|
|
55
|
+
console.log('');
|
|
56
|
+
const watcher = watch(SRC_TEMPLATES, {
|
|
57
|
+
ignoreInitial: true,
|
|
58
|
+
persistent: true,
|
|
59
|
+
});
|
|
60
|
+
watcher.on('add', copyTemplate);
|
|
61
|
+
watcher.on('change', copyTemplate);
|
|
62
|
+
watcher.on('error', (error) => logError('Watcher error', error));
|
|
63
|
+
// Handle graceful shutdown
|
|
64
|
+
process.on('SIGINT', () => {
|
|
65
|
+
console.log('\nStopping template watcher...');
|
|
66
|
+
watcher.close().catch(() => { });
|
|
67
|
+
});
|
|
68
|
+
process.on('SIGTERM', () => {
|
|
69
|
+
watcher.close().catch(() => { });
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Run if executed directly
|
|
73
|
+
startWatching();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { WindsurfHooks } from './windsurf-hooks-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Read Windsurf hooks from file
|
|
4
|
+
*
|
|
5
|
+
* @param path - Path to hooks.json file
|
|
6
|
+
* @returns Parsed hooks or undefined if file doesn't exist or is invalid
|
|
7
|
+
*/
|
|
8
|
+
export declare function readWindsurfHooks(path: string): Promise<undefined | WindsurfHooks>;
|
|
9
|
+
/**
|
|
10
|
+
* Write Windsurf hooks to file
|
|
11
|
+
*
|
|
12
|
+
* Creates parent directories if they don't exist
|
|
13
|
+
* Backs up existing file before writing
|
|
14
|
+
*
|
|
15
|
+
* @param path - Path to hooks.json file
|
|
16
|
+
* @param hooks - Hooks to write
|
|
17
|
+
* @throws Error if write fails
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeWindsurfHooks(path: string, hooks: WindsurfHooks): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Get the target hooks file for template hook merging
|
|
22
|
+
*
|
|
23
|
+
* Strategy:
|
|
24
|
+
* - If project hooks exist, merge into that file
|
|
25
|
+
* - Otherwise, create project hooks with template hooks
|
|
26
|
+
*
|
|
27
|
+
* @param projectDir - Project directory path
|
|
28
|
+
* @returns Path to target hooks file
|
|
29
|
+
*/
|
|
30
|
+
export declare function getTargetHooksFile(projectDir: string): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Check if file exists
|
|
5
|
+
*/
|
|
6
|
+
async function fileExists(path) {
|
|
7
|
+
try {
|
|
8
|
+
await fs.access(path);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read Windsurf hooks from file
|
|
17
|
+
*
|
|
18
|
+
* @param path - Path to hooks.json file
|
|
19
|
+
* @returns Parsed hooks or undefined if file doesn't exist or is invalid
|
|
20
|
+
*/
|
|
21
|
+
export async function readWindsurfHooks(path) {
|
|
22
|
+
try {
|
|
23
|
+
const content = await fs.readFile(path, 'utf8');
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// File doesn't exist or invalid JSON
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write Windsurf hooks to file
|
|
33
|
+
*
|
|
34
|
+
* Creates parent directories if they don't exist
|
|
35
|
+
* Backs up existing file before writing
|
|
36
|
+
*
|
|
37
|
+
* @param path - Path to hooks.json file
|
|
38
|
+
* @param hooks - Hooks to write
|
|
39
|
+
* @throws Error if write fails
|
|
40
|
+
*/
|
|
41
|
+
export async function writeWindsurfHooks(path, hooks) {
|
|
42
|
+
// Create parent directory if it doesn't exist
|
|
43
|
+
const dir = join(path, '..');
|
|
44
|
+
await fs.mkdir(dir, { recursive: true });
|
|
45
|
+
// Backup existing file if it exists
|
|
46
|
+
if (await fileExists(path)) {
|
|
47
|
+
const backupPath = `${path}.backup`;
|
|
48
|
+
await fs.copyFile(path, backupPath);
|
|
49
|
+
}
|
|
50
|
+
// Write hooks with pretty formatting
|
|
51
|
+
const content = JSON.stringify(hooks, null, 2);
|
|
52
|
+
await fs.writeFile(path, content, 'utf8');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the target hooks file for template hook merging
|
|
56
|
+
*
|
|
57
|
+
* Strategy:
|
|
58
|
+
* - If project hooks exist, merge into that file
|
|
59
|
+
* - Otherwise, create project hooks with template hooks
|
|
60
|
+
*
|
|
61
|
+
* @param projectDir - Project directory path
|
|
62
|
+
* @returns Path to target hooks file
|
|
63
|
+
*/
|
|
64
|
+
export function getTargetHooksFile(projectDir) {
|
|
65
|
+
return join(projectDir, '.windsurf', 'hooks.json');
|
|
66
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { WindsurfHooks, WindsurfHooksConfig } from './windsurf-hooks-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merge hooks configurations from template into existing
|
|
4
|
+
*
|
|
5
|
+
* Strategy:
|
|
6
|
+
* - For each event type in template hooks
|
|
7
|
+
* - Concatenate with existing hooks for that event
|
|
8
|
+
* - Deduplicate based on command configuration
|
|
9
|
+
* - Maintain order: existing hooks first, then template hooks
|
|
10
|
+
*
|
|
11
|
+
* @param existing - Existing hooks configuration (will not be modified)
|
|
12
|
+
* @param template - Template hooks configuration to merge
|
|
13
|
+
* @returns New merged hooks configuration
|
|
14
|
+
*/
|
|
15
|
+
export declare function mergeWindsurfHooksConfig(existing: undefined | WindsurfHooksConfig, template: undefined | WindsurfHooksConfig): WindsurfHooksConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Merge complete Windsurf hooks configurations
|
|
18
|
+
*
|
|
19
|
+
* Strategy:
|
|
20
|
+
* - Deep merge hooks using mergeWindsurfHooksConfig function
|
|
21
|
+
*
|
|
22
|
+
* @param existing - Existing hooks (will not be modified)
|
|
23
|
+
* @param template - Template hooks to merge
|
|
24
|
+
* @returns New merged hooks configuration
|
|
25
|
+
*/
|
|
26
|
+
export declare function mergeWindsurfHooks(existing: undefined | WindsurfHooks, template: undefined | WindsurfHooks): WindsurfHooks;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { mergeArraysWithDedup, mergeConfigByEventType } from './generic-merge.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check if two hook commands are equivalent
|
|
4
|
+
*/
|
|
5
|
+
function areHookCommandsEqual(a, b) {
|
|
6
|
+
return (a.command === b.command &&
|
|
7
|
+
a.timeout === b.timeout &&
|
|
8
|
+
a.show_output === b.show_output &&
|
|
9
|
+
a.once === b.once);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Merge hooks configurations from template into existing
|
|
13
|
+
*
|
|
14
|
+
* Strategy:
|
|
15
|
+
* - For each event type in template hooks
|
|
16
|
+
* - Concatenate with existing hooks for that event
|
|
17
|
+
* - Deduplicate based on command configuration
|
|
18
|
+
* - Maintain order: existing hooks first, then template hooks
|
|
19
|
+
*
|
|
20
|
+
* @param existing - Existing hooks configuration (will not be modified)
|
|
21
|
+
* @param template - Template hooks configuration to merge
|
|
22
|
+
* @returns New merged hooks configuration
|
|
23
|
+
*/
|
|
24
|
+
export function mergeWindsurfHooksConfig(existing, template) {
|
|
25
|
+
return mergeConfigByEventType(existing, template, (existingCommands, templateCommands) => mergeArraysWithDedup(existingCommands, templateCommands, areHookCommandsEqual));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Merge complete Windsurf hooks configurations
|
|
29
|
+
*
|
|
30
|
+
* Strategy:
|
|
31
|
+
* - Deep merge hooks using mergeWindsurfHooksConfig function
|
|
32
|
+
*
|
|
33
|
+
* @param existing - Existing hooks (will not be modified)
|
|
34
|
+
* @param template - Template hooks to merge
|
|
35
|
+
* @returns New merged hooks configuration
|
|
36
|
+
*/
|
|
37
|
+
export function mergeWindsurfHooks(existing, template) {
|
|
38
|
+
// If no template hooks, return existing (or empty hooks)
|
|
39
|
+
if (!template || !template.hooks || Object.keys(template.hooks).length === 0) {
|
|
40
|
+
return existing || { hooks: {} };
|
|
41
|
+
}
|
|
42
|
+
// If no existing hooks, return template
|
|
43
|
+
if (!existing || !existing.hooks || Object.keys(existing.hooks).length === 0) {
|
|
44
|
+
return template;
|
|
45
|
+
}
|
|
46
|
+
// Merge hooks using dedicated function
|
|
47
|
+
const mergedHooksConfig = mergeWindsurfHooksConfig(existing.hooks, template.hooks);
|
|
48
|
+
// Create merged hooks
|
|
49
|
+
const merged = {
|
|
50
|
+
hooks: mergedHooksConfig,
|
|
51
|
+
};
|
|
52
|
+
return merged;
|
|
53
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript interfaces for Windsurf Cascade hooks.json structure
|
|
3
|
+
* Based on Windsurf Cascade Hooks documentation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Hook command configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface WindsurfHookCommand {
|
|
9
|
+
/** Command to execute (bash, python, node, etc.) */
|
|
10
|
+
command: string;
|
|
11
|
+
/** Execute only once (for session-level hooks) */
|
|
12
|
+
once?: boolean;
|
|
13
|
+
/** Show output in Cascade UI */
|
|
14
|
+
show_output?: boolean;
|
|
15
|
+
/** Optional timeout in milliseconds */
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Hook event types supported by Windsurf Cascade
|
|
20
|
+
*/
|
|
21
|
+
export type WindsurfHookEventType = 'post_execute_command' | 'post_model_response' | 'post_read_code' | 'post_user_prompt' | 'post_write_code' | 'pre_execute_command' | 'pre_model_response' | 'pre_read_code' | 'pre_user_prompt' | 'pre_write_code';
|
|
22
|
+
/**
|
|
23
|
+
* Hooks configuration
|
|
24
|
+
* Maps event types to arrays of hook commands
|
|
25
|
+
*/
|
|
26
|
+
export type WindsurfHooksConfig = Partial<Record<WindsurfHookEventType, WindsurfHookCommand[]>>;
|
|
27
|
+
/**
|
|
28
|
+
* Complete Windsurf hooks.json structure
|
|
29
|
+
*/
|
|
30
|
+
export interface WindsurfHooks {
|
|
31
|
+
/** Hook configurations */
|
|
32
|
+
hooks: WindsurfHooksConfig;
|
|
33
|
+
}
|