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,157 @@
1
+ /**
2
+ * @file Process spawning utilities for AI Workflow CLI.
3
+ *
4
+ * This module provides utilities for spawning external processes (e.g., Claude Code)
5
+ * with proper error handling, stdio configuration, and debug logging.
6
+ *
7
+ * ## Key Features
8
+ * - Spawn external processes with configurable stdio (inherit, pipe)
9
+ * - Exit code capture and error handling
10
+ * - Detached mode for parallel sessions
11
+ * - Debug logging integration
12
+ * - Cross-platform compatibility
13
+ *
14
+ * ## Usage Examples
15
+ *
16
+ * ### Basic Spawn (Interactive)
17
+ * ```typescript
18
+ * import {spawnProcess} from '../lib/spawn.js'
19
+ *
20
+ * const exitCode = await spawnProcess('claude', ['--dangerously-skip-permissions'])
21
+ * if (exitCode !== 0) {
22
+ * console.error('Claude Code exited with error')
23
+ * }
24
+ * ```
25
+ *
26
+ * ### Parallel Sessions (Detached Mode)
27
+ * ```typescript
28
+ * // Launch multiple Claude Code sessions concurrently
29
+ * const session1 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
30
+ * const session2 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
31
+ * await Promise.all([session1, session2])
32
+ * ```
33
+ *
34
+ * ### Custom Working Directory
35
+ * ```typescript
36
+ * await spawnProcess('npm', ['install'], {cwd: '/path/to/project'})
37
+ * ```
38
+ *
39
+ * @module lib/spawn
40
+ */
41
+ import { execSync, spawn as nodeSpawn } from 'node:child_process';
42
+ import { debug, debugSpawn } from './debug.js';
43
+ import { ProcessSpawnError } from './errors.js';
44
+ /**
45
+ * Spawn an external process and return its exit code.
46
+ *
47
+ * This function wraps Node.js child_process.spawn with AIW-specific
48
+ * error handling, debug logging, and parallel session support.
49
+ *
50
+ * ## Exit Code Mapping
51
+ * - 0: Success
52
+ * - Non-zero: Error (actual code from child process)
53
+ * - null code: Defaults to 1
54
+ *
55
+ * ## Error Handling
56
+ * - ENOENT: Command not found → ProcessSpawnError with install instructions
57
+ * - EACCES: Permission denied → ProcessSpawnError with permission fix
58
+ * - Other errors: ProcessSpawnError with error details
59
+ *
60
+ * ## Parallel Sessions
61
+ * Use `detached: true` to spawn independent processes that don't block parent.
62
+ * Multiple calls can run concurrently without conflicts.
63
+ *
64
+ * @param command - Command to execute (e.g., 'claude', 'npm', 'git')
65
+ * @param args - Arguments array (e.g., ['--dangerously-skip-permissions'])
66
+ * @param options - Spawn configuration options
67
+ * @returns Promise<number> - Exit code (0 = success, non-zero = error)
68
+ * @throws ProcessSpawnError - When spawn fails (command not found, permissions, etc.)
69
+ *
70
+ * @example
71
+ * // Launch Claude Code with sandbox disabled
72
+ * const exitCode = await spawnProcess('claude', ['--dangerously-skip-permissions'])
73
+ *
74
+ * @example
75
+ * // Parallel session with detached mode
76
+ * const session1 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
77
+ * const session2 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
78
+ * await Promise.all([session1, session2])
79
+ *
80
+ * @example
81
+ * // Custom working directory
82
+ * await spawnProcess('npm', ['test'], {cwd: '/path/to/project'})
83
+ */
84
+ export async function spawnProcess(command, args = [], options = {}) {
85
+ const { cwd, stdio = 'inherit', detached = false } = options;
86
+ // Log spawn details in debug mode
87
+ debugSpawn(command, args);
88
+ // Windows hybrid approach: try without shell first, fallback to .cmd if ENOENT
89
+ // This preserves error detection while supporting .cmd files from npm
90
+ if (process.platform === 'win32') {
91
+ try {
92
+ return await attemptSpawn(command, args, { cwd, stdio, detached, shell: false });
93
+ }
94
+ catch (error) {
95
+ // If command not found and .cmd file exists, use cmd.exe wrapper
96
+ // This avoids DEP0190 deprecation warning while supporting npm-installed commands
97
+ if (error instanceof ProcessSpawnError && error.code === 'ENOENT' && commandExistsInPath(`${command}.cmd`)) {
98
+ // Use cmd.exe /c to execute .cmd file without shell mode or deprecation warning
99
+ return attemptSpawn('cmd.exe', ['/c', command, ...args], { cwd, stdio, detached, shell: false });
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ // Unix: always use shell: false for security
105
+ return attemptSpawn(command, args, { cwd, stdio, detached, shell: false });
106
+ }
107
+ /**
108
+ * Check if a command exists in PATH (Windows only).
109
+ * Uses 'where' command to check if file exists in PATH.
110
+ */
111
+ function commandExistsInPath(command) {
112
+ try {
113
+ execSync(`where ${command}`, { stdio: 'ignore', windowsHide: true });
114
+ return true;
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ }
120
+ /**
121
+ * Internal helper to attempt process spawn with given options.
122
+ */
123
+ function attemptSpawn(command, args, spawnOptions) {
124
+ return new Promise((resolve, reject) => {
125
+ try {
126
+ const childProcess = nodeSpawn(command, args, spawnOptions);
127
+ // Handle spawn errors (ENOENT, EACCES, etc.)
128
+ childProcess.on('error', (error) => {
129
+ if (error.code === 'ENOENT') {
130
+ reject(new ProcessSpawnError(`Command not found: ${command}. Install Claude Code from https://claude.ai/download.`, 'ENOENT'));
131
+ }
132
+ else if (error.code === 'EACCES') {
133
+ reject(new ProcessSpawnError(`Permission denied: ${command}. Check file permissions.`, 'EACCES'));
134
+ }
135
+ else {
136
+ reject(new ProcessSpawnError(`Failed to spawn ${command}: ${error.message}. Check that the command exists and is executable.`, error.code));
137
+ }
138
+ });
139
+ // Capture exit code on process close
140
+ childProcess.on('close', (code, signal) => {
141
+ const exitCode = code ?? 1; // Default to error if no code
142
+ if (signal) {
143
+ debug(`Process terminated by signal: ${signal}`);
144
+ }
145
+ debug(`Process exited with code: ${exitCode}`);
146
+ resolve(exitCode);
147
+ });
148
+ // Unref detached processes to allow parent to exit
149
+ if (spawnOptions.detached && childProcess.unref) {
150
+ childProcess.unref();
151
+ }
152
+ }
153
+ catch (error) {
154
+ reject(new ProcessSpawnError(`Spawn error: ${error instanceof Error ? error.message : String(error)}`));
155
+ }
156
+ });
157
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Spinner Utilities
3
+ *
4
+ * Provides TTY-aware spinner wrapper using ora library.
5
+ * Spinners automatically disable in non-TTY contexts (piped, redirected, CI).
6
+ */
7
+ import { type Ora } from 'ora';
8
+ /**
9
+ * Create a TTY-aware spinner.
10
+ * Automatically disables in non-TTY contexts (piped, redirected, CI, quiet mode).
11
+ */
12
+ export declare function createSpinner(text: string, flags?: {
13
+ quiet?: boolean;
14
+ }): Ora;
15
+ /**
16
+ * Helper for common "loading" operations with spinner.
17
+ * Automatically handles success/failure and cleanup.
18
+ */
19
+ export declare function withSpinner<T>(text: string, operation: () => Promise<T>): Promise<T>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Spinner Utilities
3
+ *
4
+ * Provides TTY-aware spinner wrapper using ora library.
5
+ * Spinners automatically disable in non-TTY contexts (piped, redirected, CI).
6
+ */
7
+ import ora from 'ora';
8
+ import { shouldShowSpinners } from './tty-detection.js';
9
+ /**
10
+ * Create a TTY-aware spinner.
11
+ * Automatically disables in non-TTY contexts (piped, redirected, CI, quiet mode).
12
+ */
13
+ export function createSpinner(text, flags) {
14
+ return ora({
15
+ isEnabled: shouldShowSpinners(flags),
16
+ text,
17
+ });
18
+ }
19
+ /**
20
+ * Helper for common "loading" operations with spinner.
21
+ * Automatically handles success/failure and cleanup.
22
+ */
23
+ export async function withSpinner(text, operation) {
24
+ const spinner = createSpinner(text).start();
25
+ try {
26
+ const result = await operation();
27
+ spinner.succeed();
28
+ return result;
29
+ }
30
+ catch (error) {
31
+ spinner.fail();
32
+ throw error;
33
+ }
34
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * stdin Detection and Reading Utilities
3
+ *
4
+ * Provides utilities for detecting and reading piped input from stdin.
5
+ * Used by commands that need to accept piped data from other commands.
6
+ *
7
+ * @example Basic stdin detection
8
+ * ```typescript
9
+ * if (hasStdin()) {
10
+ * const input = await readStdin()
11
+ * // Process piped input
12
+ * } else {
13
+ * // Interactive mode - prompt user
14
+ * }
15
+ * ```
16
+ */
17
+ /**
18
+ * Check if stdin has piped data available.
19
+ * Returns true when data is piped into the command, false in interactive terminals.
20
+ *
21
+ * @returns True if stdin is piped (not a TTY), false if interactive terminal
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // echo "data" | pai process
26
+ * hasStdin() // Returns true
27
+ *
28
+ * // pai process (no pipe)
29
+ * hasStdin() // Returns false
30
+ * ```
31
+ */
32
+ export declare function hasStdin(): boolean;
33
+ /**
34
+ * Read all data from stdin.
35
+ * Reads piped input data and returns as UTF-8 string.
36
+ * Returns empty string if no stdin available.
37
+ *
38
+ * @returns Promise resolving to stdin content as string, or empty string if no stdin
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const input = await readStdin()
43
+ * if (input) {
44
+ * console.log(`Received: ${input}`)
45
+ * }
46
+ * ```
47
+ */
48
+ export declare function readStdin(): Promise<string>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * stdin Detection and Reading Utilities
3
+ *
4
+ * Provides utilities for detecting and reading piped input from stdin.
5
+ * Used by commands that need to accept piped data from other commands.
6
+ *
7
+ * @example Basic stdin detection
8
+ * ```typescript
9
+ * if (hasStdin()) {
10
+ * const input = await readStdin()
11
+ * // Process piped input
12
+ * } else {
13
+ * // Interactive mode - prompt user
14
+ * }
15
+ * ```
16
+ */
17
+ import { stdin } from 'node:process';
18
+ /**
19
+ * Check if stdin has piped data available.
20
+ * Returns true when data is piped into the command, false in interactive terminals.
21
+ *
22
+ * @returns True if stdin is piped (not a TTY), false if interactive terminal
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // echo "data" | pai process
27
+ * hasStdin() // Returns true
28
+ *
29
+ * // pai process (no pipe)
30
+ * hasStdin() // Returns false
31
+ * ```
32
+ */
33
+ export function hasStdin() {
34
+ return stdin.isTTY !== true;
35
+ }
36
+ /**
37
+ * Read all data from stdin.
38
+ * Reads piped input data and returns as UTF-8 string.
39
+ * Returns empty string if no stdin available.
40
+ *
41
+ * @returns Promise resolving to stdin content as string, or empty string if no stdin
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const input = await readStdin()
46
+ * if (input) {
47
+ * console.log(`Received: ${input}`)
48
+ * }
49
+ * ```
50
+ */
51
+ export async function readStdin() {
52
+ if (!hasStdin()) {
53
+ return '';
54
+ }
55
+ const chunks = [];
56
+ for await (const chunk of stdin) {
57
+ chunks.push(chunk);
58
+ }
59
+ return Buffer.concat(chunks).toString('utf8');
60
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Configuration for template installation
3
+ */
4
+ export interface TemplateInstallConfig {
5
+ /** List of IDE names to install (e.g., ['claude', 'windsurf']) */
6
+ ides: string[];
7
+ /** Project name for configuration generation */
8
+ projectName: string;
9
+ /** Target directory where template will be installed */
10
+ targetDir: string;
11
+ /** Name of the template to install (e.g., 'bmad') */
12
+ templateName: string;
13
+ /** Absolute path to the template directory */
14
+ templatePath: string;
15
+ /** Username for configuration generation */
16
+ username: string;
17
+ }
18
+ /**
19
+ * Status of a single template item (file or folder)
20
+ */
21
+ export interface TemplateItemStatus {
22
+ /** Whether the item exists in target directory */
23
+ exists: boolean;
24
+ /** Whether the item is a directory */
25
+ isDirectory: boolean;
26
+ /** The item name */
27
+ name: string;
28
+ }
29
+ /**
30
+ * Result of checking template installation status
31
+ */
32
+ export interface TemplateInstallationStatus {
33
+ /** Items that already exist in target directory */
34
+ existing: TemplateItemStatus[];
35
+ /** Items that are missing from target directory */
36
+ missing: TemplateItemStatus[];
37
+ /** The method-specific workflow folder name (e.g., '_gsd', '_bmad') */
38
+ workflowFolder: null | string;
39
+ /** Whether the workflow folder exists */
40
+ workflowFolderExists: boolean;
41
+ }
42
+ /**
43
+ * Result of template installation
44
+ */
45
+ export interface InstallationResult {
46
+ /** List of folder names that were installed (for gitignore) */
47
+ installedFolders: string[];
48
+ /** Number of files that were merged into existing folders */
49
+ mergedFileCount: number;
50
+ /** List of folder names that had content merged */
51
+ mergedFolders: string[];
52
+ /** Whether shared settings were merged into IDE settings */
53
+ sharedSettingsMerged: boolean;
54
+ /** List of folder names that were skipped (already exist) */
55
+ skippedFolders: string[];
56
+ /** Absolute path to the template that was installed */
57
+ templatePath: string;
58
+ }
59
+ /**
60
+ * Check template installation status for a method.
61
+ * Returns which items exist and which are missing.
62
+ *
63
+ * @param templatePath - Path to the template directory
64
+ * @param targetDir - Target directory to check
65
+ * @param ides - List of IDEs to check (for dot folders)
66
+ * @param templateName - Name of the template (for identifying workflow folder)
67
+ * @returns Status of template items
68
+ */
69
+ export declare function checkTemplateStatus(templatePath: string, targetDir: string, ides: string[], templateName: string): Promise<TemplateInstallationStatus>;
70
+ /**
71
+ * Copy directory recursively with proper error handling.
72
+ * Excludes test files, cache directories, and output folders.
73
+ *
74
+ * @param src - Source directory path
75
+ * @param dest - Destination directory path
76
+ * @param excludeIdeFolders - If true, exclude IDE config folders (.claude, .windsurf, etc.)
77
+ */
78
+ export declare function copyDir(src: string, dest: string, excludeIdeFolders?: boolean): Promise<void>;
79
+ /**
80
+ * Install template with IDE-specific folder selection.
81
+ * Supports selective installation - only installs items that don't already exist.
82
+ *
83
+ * Template structure:
84
+ * - Non-dot folders (e.g., _bmad/, GSR/) are installed if not already present
85
+ * - Dot folders (e.g., .claude/, .windsurf/) are installed only if matching IDE flag and not already present
86
+ *
87
+ * @param config - Installation configuration
88
+ * @param skipExisting - If true, skip items that already exist (default: true for regeneration support)
89
+ * @returns Installation result with list of installed and skipped folders
90
+ * @throws Error if template doesn't exist or requested IDE folder not found
91
+ */
92
+ export declare function installTemplate(config: TemplateInstallConfig, skipExisting?: boolean): Promise<InstallationResult>;