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.
Files changed (204) hide show
  1. package/README.md +1248 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +16 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +19 -0
  6. package/dist/commands/branch.d.ts +45 -0
  7. package/dist/commands/branch.js +488 -0
  8. package/dist/commands/clean.d.ts +34 -0
  9. package/dist/commands/clean.js +186 -0
  10. package/dist/commands/clear.d.ts +51 -0
  11. package/dist/commands/clear.js +835 -0
  12. package/dist/commands/init/index.d.ts +107 -0
  13. package/dist/commands/init/index.js +565 -0
  14. package/dist/commands/launch.d.ts +21 -0
  15. package/dist/commands/launch.js +108 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +1 -0
  18. package/dist/lib/base-command.d.ts +114 -0
  19. package/dist/lib/base-command.js +153 -0
  20. package/dist/lib/bmad-installer.d.ts +38 -0
  21. package/dist/lib/bmad-installer.js +145 -0
  22. package/dist/lib/claude-settings-types.d.ts +102 -0
  23. package/dist/lib/claude-settings-types.js +5 -0
  24. package/dist/lib/config.d.ts +25 -0
  25. package/dist/lib/config.js +46 -0
  26. package/dist/lib/debug.d.ts +39 -0
  27. package/dist/lib/debug.js +74 -0
  28. package/dist/lib/env-compat.d.ts +26 -0
  29. package/dist/lib/env-compat.js +35 -0
  30. package/dist/lib/errors.d.ts +126 -0
  31. package/dist/lib/errors.js +145 -0
  32. package/dist/lib/generic-merge.d.ts +74 -0
  33. package/dist/lib/generic-merge.js +105 -0
  34. package/dist/lib/git/branch.d.ts +67 -0
  35. package/dist/lib/git/branch.js +155 -0
  36. package/dist/lib/git/index.d.ts +11 -0
  37. package/dist/lib/git/index.js +13 -0
  38. package/dist/lib/git/safety-checks.d.ts +44 -0
  39. package/dist/lib/git/safety-checks.js +102 -0
  40. package/dist/lib/git/types.d.ts +31 -0
  41. package/dist/lib/git/types.js +6 -0
  42. package/dist/lib/git/worktree.d.ts +67 -0
  43. package/dist/lib/git/worktree.js +220 -0
  44. package/dist/lib/gitignore-manager.d.ts +10 -0
  45. package/dist/lib/gitignore-manager.js +60 -0
  46. package/dist/lib/hooks-merger.d.ts +28 -0
  47. package/dist/lib/hooks-merger.js +94 -0
  48. package/dist/lib/ide-path-resolver.d.ts +102 -0
  49. package/dist/lib/ide-path-resolver.js +129 -0
  50. package/dist/lib/index.d.ts +13 -0
  51. package/dist/lib/index.js +22 -0
  52. package/dist/lib/output.d.ts +51 -0
  53. package/dist/lib/output.js +76 -0
  54. package/dist/lib/paths.d.ts +66 -0
  55. package/dist/lib/paths.js +136 -0
  56. package/dist/lib/quiet.d.ts +12 -0
  57. package/dist/lib/quiet.js +17 -0
  58. package/dist/lib/settings-hierarchy.d.ts +42 -0
  59. package/dist/lib/settings-hierarchy.js +105 -0
  60. package/dist/lib/spawn.d.ts +105 -0
  61. package/dist/lib/spawn.js +157 -0
  62. package/dist/lib/spinner.d.ts +19 -0
  63. package/dist/lib/spinner.js +34 -0
  64. package/dist/lib/stdin.d.ts +48 -0
  65. package/dist/lib/stdin.js +60 -0
  66. package/dist/lib/template-installer.d.ts +92 -0
  67. package/dist/lib/template-installer.js +375 -0
  68. package/dist/lib/template-linter.d.ts +49 -0
  69. package/dist/lib/template-linter.js +173 -0
  70. package/dist/lib/template-merger.d.ts +47 -0
  71. package/dist/lib/template-merger.js +173 -0
  72. package/dist/lib/template-resolver.d.ts +20 -0
  73. package/dist/lib/template-resolver.js +60 -0
  74. package/dist/lib/terminal.d.ts +102 -0
  75. package/dist/lib/terminal.js +245 -0
  76. package/dist/lib/tty-detection.d.ts +62 -0
  77. package/dist/lib/tty-detection.js +83 -0
  78. package/dist/lib/user-utils.d.ts +5 -0
  79. package/dist/lib/user-utils.js +23 -0
  80. package/dist/lib/version.d.ts +99 -0
  81. package/dist/lib/version.js +144 -0
  82. package/dist/lib/watch-templates.d.ts +6 -0
  83. package/dist/lib/watch-templates.js +73 -0
  84. package/dist/lib/windsurf-hooks-hierarchy.d.ts +30 -0
  85. package/dist/lib/windsurf-hooks-hierarchy.js +66 -0
  86. package/dist/lib/windsurf-hooks-merger.d.ts +26 -0
  87. package/dist/lib/windsurf-hooks-merger.js +53 -0
  88. package/dist/lib/windsurf-hooks-types.d.ts +33 -0
  89. package/dist/lib/windsurf-hooks-types.js +5 -0
  90. package/dist/templates/CLAUDE.md +174 -0
  91. package/dist/templates/_shared/.claude/commands/handoff.md +14 -0
  92. package/dist/templates/_shared/.claude/settings.json +61 -0
  93. package/dist/templates/_shared/.codex/workflows/handoff.md +14 -0
  94. package/dist/templates/_shared/.windsurf/workflows/handoff.md +14 -0
  95. package/dist/templates/_shared/hooks/__init__.py +16 -0
  96. package/dist/templates/_shared/hooks/archive_plan.py +270 -0
  97. package/dist/templates/_shared/hooks/context_enforcer.py +621 -0
  98. package/dist/templates/_shared/hooks/context_monitor.py +322 -0
  99. package/dist/templates/_shared/hooks/file-suggestion.py +188 -0
  100. package/dist/templates/_shared/hooks/task_create_capture.py +194 -0
  101. package/dist/templates/_shared/hooks/task_update_capture.py +254 -0
  102. package/dist/templates/_shared/hooks/user_prompt_submit.py +157 -0
  103. package/dist/templates/_shared/lib/__init__.py +1 -0
  104. package/dist/templates/_shared/lib/base/__init__.py +49 -0
  105. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  106. package/dist/templates/_shared/lib/base/atomic_write.py +180 -0
  107. package/dist/templates/_shared/lib/base/constants.py +299 -0
  108. package/dist/templates/_shared/lib/base/inference.py +189 -0
  109. package/dist/templates/_shared/lib/base/utils.py +216 -0
  110. package/dist/templates/_shared/lib/context/__init__.py +119 -0
  111. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  112. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  113. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  114. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  115. package/dist/templates/_shared/lib/context/cache.py +446 -0
  116. package/dist/templates/_shared/lib/context/context_manager.py +1171 -0
  117. package/dist/templates/_shared/lib/context/discovery.py +486 -0
  118. package/dist/templates/_shared/lib/context/event_log.py +308 -0
  119. package/dist/templates/_shared/lib/context/plan_archive.py +247 -0
  120. package/dist/templates/_shared/lib/context/task_sync.py +367 -0
  121. package/dist/templates/_shared/lib/handoff/__init__.py +22 -0
  122. package/dist/templates/_shared/lib/handoff/document_generator.py +307 -0
  123. package/dist/templates/_shared/lib/templates/README.md +215 -0
  124. package/dist/templates/_shared/lib/templates/__init__.py +40 -0
  125. package/dist/templates/_shared/lib/templates/formatters.py +147 -0
  126. package/dist/templates/_shared/lib/templates/plan_context.py +119 -0
  127. package/dist/templates/_shared/scripts/save_handoff.py +99 -0
  128. package/dist/templates/_shared/workflows/handoff.md +212 -0
  129. package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +80 -0
  130. package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +75 -0
  131. package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +239 -0
  132. package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +109 -0
  133. package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +71 -0
  134. package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +104 -0
  135. package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +93 -0
  136. package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +223 -0
  137. package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +73 -0
  138. package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +93 -0
  139. package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +103 -0
  140. package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +145 -0
  141. package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +248 -0
  142. package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +235 -0
  143. package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +80 -0
  144. package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +76 -0
  145. package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +141 -0
  146. package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +240 -0
  147. package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +211 -0
  148. package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +101 -0
  149. package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +197 -0
  150. package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +97 -0
  151. package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +349 -0
  152. package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +106 -0
  153. package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +205 -0
  154. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +8 -0
  155. package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -0
  156. package/dist/templates/cc-native/.claude/settings.json +119 -0
  157. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -0
  158. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +8 -0
  159. package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -0
  160. package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -0
  161. package/dist/templates/cc-native/CC-NATIVE-README.md +192 -0
  162. package/dist/templates/cc-native/MIGRATION.md +86 -0
  163. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +331 -0
  164. package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +147 -0
  165. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  166. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  167. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
  168. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  169. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
  170. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +150 -0
  171. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +746 -0
  172. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +339 -0
  173. package/dist/templates/cc-native/_cc-native/lib/__init__.py +57 -0
  174. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  175. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  176. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  177. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  178. package/dist/templates/cc-native/_cc-native/lib/async_archive.py +68 -0
  179. package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +98 -0
  180. package/dist/templates/cc-native/_cc-native/lib/constants.py +45 -0
  181. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +273 -0
  182. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +28 -0
  183. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  184. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  185. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  186. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  187. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  188. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +164 -0
  189. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +89 -0
  190. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +119 -0
  191. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +103 -0
  192. package/dist/templates/cc-native/_cc-native/lib/state.py +251 -0
  193. package/dist/templates/cc-native/_cc-native/lib/utils.py +830 -0
  194. package/dist/templates/cc-native/_cc-native/plan-review.config.json +76 -0
  195. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  196. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +151 -0
  197. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +134 -0
  198. package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -0
  199. package/dist/types/exit-codes.d.ts +11 -0
  200. package/dist/types/exit-codes.js +10 -0
  201. package/dist/types/index.d.ts +5 -0
  202. package/dist/types/index.js +7 -0
  203. package/oclif.manifest.json +405 -0
  204. 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,5 @@
1
+ /**
2
+ * Detect username from git config or environment variables.
3
+ * Priority: git config user.name > USER env > USERNAME env > fallback to "User"
4
+ */
5
+ export declare function detectUsername(): Promise<string>;
@@ -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,6 @@
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
+ export {};
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TypeScript interfaces for Windsurf Cascade hooks.json structure
3
+ * Based on Windsurf Cascade Hooks documentation
4
+ */
5
+ export {};