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,51 @@
1
+ /**
2
+ * Output Utilities
3
+ *
4
+ * Provides TTY-aware output functions with automatic color support.
5
+ * Colors automatically disabled when output is piped or redirected.
6
+ * Respects NO_COLOR and FORCE_COLOR environment variables.
7
+ */
8
+ import { type ProcessLike } from './tty-detection.js';
9
+ /**
10
+ * Dependencies for output functions.
11
+ * Allows tests to inject mock values without mutating global state.
12
+ */
13
+ export interface OutputDependencies {
14
+ proc?: ProcessLike;
15
+ }
16
+ /**
17
+ * Log informational message (stdout, no color).
18
+ * Suppressed in quiet mode.
19
+ * @param message - Message to log
20
+ * @param quiet - If true, suppress output
21
+ */
22
+ export declare function logInfo(message: string, quiet?: boolean): void;
23
+ /**
24
+ * Log success message (stdout, green in TTY).
25
+ * Suppressed in quiet mode.
26
+ * @param message - Message to log
27
+ * @param quiet - If true, suppress output
28
+ * @param deps - Optional dependencies for testing
29
+ */
30
+ export declare function logSuccess(message: string, quiet?: boolean, deps?: OutputDependencies): void;
31
+ /**
32
+ * Log error message (stderr, red in TTY).
33
+ * NEVER suppressed - errors always output even in quiet mode.
34
+ * @param message - Message to log
35
+ * @param deps - Optional dependencies for testing
36
+ */
37
+ export declare function logError(message: string, deps?: OutputDependencies): void;
38
+ /**
39
+ * Log warning message (stdout, yellow in TTY).
40
+ * Suppressed in quiet mode.
41
+ * @param message - Message to log
42
+ * @param quiet - If true, suppress output
43
+ * @param deps - Optional dependencies for testing
44
+ */
45
+ export declare function logWarning(message: string, quiet?: boolean, deps?: OutputDependencies): void;
46
+ /**
47
+ * Log debug message (stdout, dim in TTY).
48
+ * @param message - Message to log
49
+ * @param deps - Optional dependencies for testing
50
+ */
51
+ export declare function logDebug(message: string, deps?: OutputDependencies): void;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Output Utilities
3
+ *
4
+ * Provides TTY-aware output functions with automatic color support.
5
+ * Colors automatically disabled when output is piped or redirected.
6
+ * Respects NO_COLOR and FORCE_COLOR environment variables.
7
+ */
8
+ import chalk from 'chalk';
9
+ import { shouldUseColors } from './tty-detection.js';
10
+ /**
11
+ * Get whether colors should be used, evaluating lazily.
12
+ * Internal helper that checks TTY state at call time.
13
+ */
14
+ function getUseColors(deps) {
15
+ return shouldUseColors(deps?.proc);
16
+ }
17
+ /**
18
+ * Log informational message (stdout, no color).
19
+ * Suppressed in quiet mode.
20
+ * @param message - Message to log
21
+ * @param quiet - If true, suppress output
22
+ */
23
+ export function logInfo(message, quiet = false) {
24
+ if (quiet)
25
+ return;
26
+ console.log(message);
27
+ }
28
+ /**
29
+ * Log success message (stdout, green in TTY).
30
+ * Suppressed in quiet mode.
31
+ * @param message - Message to log
32
+ * @param quiet - If true, suppress output
33
+ * @param deps - Optional dependencies for testing
34
+ */
35
+ export function logSuccess(message, quiet = false, deps) {
36
+ if (quiet)
37
+ return;
38
+ const useColors = getUseColors(deps);
39
+ const formatted = useColors ? chalk.green(message) : message;
40
+ console.log(formatted);
41
+ }
42
+ /**
43
+ * Log error message (stderr, red in TTY).
44
+ * NEVER suppressed - errors always output even in quiet mode.
45
+ * @param message - Message to log
46
+ * @param deps - Optional dependencies for testing
47
+ */
48
+ export function logError(message, deps) {
49
+ const useColors = getUseColors(deps);
50
+ const formatted = useColors ? chalk.red(message) : message;
51
+ console.error(formatted);
52
+ }
53
+ /**
54
+ * Log warning message (stdout, yellow in TTY).
55
+ * Suppressed in quiet mode.
56
+ * @param message - Message to log
57
+ * @param quiet - If true, suppress output
58
+ * @param deps - Optional dependencies for testing
59
+ */
60
+ export function logWarning(message, quiet = false, deps) {
61
+ if (quiet)
62
+ return;
63
+ const useColors = getUseColors(deps);
64
+ const formatted = useColors ? chalk.yellow(message) : message;
65
+ console.log(formatted);
66
+ }
67
+ /**
68
+ * Log debug message (stdout, dim in TTY).
69
+ * @param message - Message to log
70
+ * @param deps - Optional dependencies for testing
71
+ */
72
+ export function logDebug(message, deps) {
73
+ const useColors = getUseColors(deps);
74
+ const formatted = useColors ? chalk.dim(message) : message;
75
+ console.log(formatted);
76
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Get the user's home directory path.
3
+ * Wrapper around os.homedir() for consistency.
4
+ * @returns Absolute path to user's home directory
5
+ */
6
+ export declare function getHomePath(): string;
7
+ /**
8
+ * Expand a path that may contain ~ (tilde) home directory shorthand.
9
+ * @param inputPath - Path that may start with ~
10
+ * @returns Path with ~ expanded to home directory, or original path
11
+ */
12
+ export declare function expandPath(inputPath: string): string;
13
+ /**
14
+ * Convert a path to Unix-style forward slashes.
15
+ * Useful for cross-platform logging or display.
16
+ * @param inputPath - Path with any separator style
17
+ * @returns Path with forward slashes only
18
+ */
19
+ export declare function toUnixPath(inputPath: string): string;
20
+ /**
21
+ * Convert a path to Windows-style backslashes.
22
+ * Useful for cross-platform logging or display.
23
+ * @param inputPath - Path with any separator style
24
+ * @returns Path with backslashes only
25
+ */
26
+ export declare function toWindowsPath(inputPath: string): string;
27
+ /**
28
+ * Normalize a path to use platform-native separators.
29
+ * Handles mixed forward/back slashes and removes redundant separators.
30
+ * @param inputPath - Path with potentially mixed separators
31
+ * @returns Path with platform-native separators
32
+ */
33
+ export declare function normalizePath(inputPath: string): string;
34
+ /**
35
+ * Check if a path exists asynchronously.
36
+ *
37
+ * WARNING: Subject to Time-of-Check-Time-of-Use (TOCTOU) race condition.
38
+ * The path may be created/deleted between checking and using it.
39
+ * For critical operations, use try/catch around the actual file operation instead.
40
+ *
41
+ * @param pathToCheck - Path to check for existence
42
+ * @returns Promise resolving to true if path exists, false otherwise
43
+ */
44
+ export declare function pathExists(pathToCheck: string): Promise<boolean>;
45
+ /**
46
+ * Join path segments using platform-appropriate separator.
47
+ */
48
+ export declare function resolvePath(...segments: string[]): string;
49
+ /**
50
+ * Check if directory is an AI Workflow workspace (contains .aiw directory marker).
51
+ * Per AC3: The marker must be a directory, not a file.
52
+ */
53
+ export declare function isWorkspace(dir: string): boolean;
54
+ /**
55
+ * Search up the directory tree for a .aiw workspace marker.
56
+ * @param startDir - Directory to start searching from
57
+ * @returns Path to workspace root, or null if not found
58
+ */
59
+ export declare function findWorkspaceRoot(startDir: string): null | string;
60
+ /**
61
+ * Get the workspace path if in an AI Workflow workspace, or null otherwise.
62
+ * Alias for findWorkspaceRoot with current directory as default.
63
+ * @param startDir - Directory to start searching from (defaults to cwd)
64
+ * @returns Path to workspace root, or null if not in a workspace or cwd unavailable
65
+ */
66
+ export declare function getWorkspacePath(startDir?: string): null | string;
@@ -0,0 +1,136 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import { access } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join, normalize } from 'node:path';
5
+ /**
6
+ * Get the user's home directory path.
7
+ * Wrapper around os.homedir() for consistency.
8
+ * @returns Absolute path to user's home directory
9
+ */
10
+ export function getHomePath() {
11
+ return homedir();
12
+ }
13
+ /**
14
+ * Expand a path that may contain ~ (tilde) home directory shorthand.
15
+ * @param inputPath - Path that may start with ~
16
+ * @returns Path with ~ expanded to home directory, or original path
17
+ */
18
+ export function expandPath(inputPath) {
19
+ if (!inputPath) {
20
+ return inputPath;
21
+ }
22
+ // Only expand ~ at the start of the path
23
+ if (inputPath === '~') {
24
+ return homedir();
25
+ }
26
+ if (inputPath.startsWith('~/') || inputPath.startsWith('~\\')) {
27
+ return join(homedir(), inputPath.slice(2));
28
+ }
29
+ return inputPath;
30
+ }
31
+ /**
32
+ * Convert a path to Unix-style forward slashes.
33
+ * Useful for cross-platform logging or display.
34
+ * @param inputPath - Path with any separator style
35
+ * @returns Path with forward slashes only
36
+ */
37
+ export function toUnixPath(inputPath) {
38
+ return inputPath.replaceAll('\\', '/');
39
+ }
40
+ /**
41
+ * Convert a path to Windows-style backslashes.
42
+ * Useful for cross-platform logging or display.
43
+ * @param inputPath - Path with any separator style
44
+ * @returns Path with backslashes only
45
+ */
46
+ export function toWindowsPath(inputPath) {
47
+ return inputPath.replaceAll('/', '\\');
48
+ }
49
+ /**
50
+ * Normalize a path to use platform-native separators.
51
+ * Handles mixed forward/back slashes and removes redundant separators.
52
+ * @param inputPath - Path with potentially mixed separators
53
+ * @returns Path with platform-native separators
54
+ */
55
+ export function normalizePath(inputPath) {
56
+ if (!inputPath) {
57
+ return '.';
58
+ }
59
+ // Replace all forward and back slashes with forward slashes first,
60
+ // then let normalize() handle the platform conversion
61
+ const unified = inputPath.replaceAll(/[\\/]+/g, '/');
62
+ return normalize(unified);
63
+ }
64
+ /**
65
+ * Check if a path exists asynchronously.
66
+ *
67
+ * WARNING: Subject to Time-of-Check-Time-of-Use (TOCTOU) race condition.
68
+ * The path may be created/deleted between checking and using it.
69
+ * For critical operations, use try/catch around the actual file operation instead.
70
+ *
71
+ * @param pathToCheck - Path to check for existence
72
+ * @returns Promise resolving to true if path exists, false otherwise
73
+ */
74
+ export async function pathExists(pathToCheck) {
75
+ try {
76
+ await access(pathToCheck);
77
+ return true;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ /**
84
+ * Join path segments using platform-appropriate separator.
85
+ */
86
+ export function resolvePath(...segments) {
87
+ return join(...segments);
88
+ }
89
+ /**
90
+ * Check if directory is an AI Workflow workspace (contains .aiw directory marker).
91
+ * Per AC3: The marker must be a directory, not a file.
92
+ */
93
+ export function isWorkspace(dir) {
94
+ const aiwPath = join(dir, '.aiw');
95
+ try {
96
+ return existsSync(aiwPath) && statSync(aiwPath).isDirectory();
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ }
102
+ /**
103
+ * Search up the directory tree for a .aiw workspace marker.
104
+ * @param startDir - Directory to start searching from
105
+ * @returns Path to workspace root, or null if not found
106
+ */
107
+ export function findWorkspaceRoot(startDir) {
108
+ let currentDir = normalize(startDir);
109
+ while (true) {
110
+ if (isWorkspace(currentDir)) {
111
+ return currentDir;
112
+ }
113
+ const parentDir = dirname(currentDir);
114
+ // Reached filesystem root
115
+ if (parentDir === currentDir) {
116
+ return null;
117
+ }
118
+ currentDir = parentDir;
119
+ }
120
+ }
121
+ /**
122
+ * Get the workspace path if in an AI Workflow workspace, or null otherwise.
123
+ * Alias for findWorkspaceRoot with current directory as default.
124
+ * @param startDir - Directory to start searching from (defaults to cwd)
125
+ * @returns Path to workspace root, or null if not in a workspace or cwd unavailable
126
+ */
127
+ export function getWorkspacePath(startDir) {
128
+ try {
129
+ const dir = startDir ?? process.cwd();
130
+ return findWorkspaceRoot(dir);
131
+ }
132
+ catch {
133
+ // process.cwd() can throw ENOENT if current directory was deleted
134
+ return null;
135
+ }
136
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Quiet mode state management for AI Workflow CLI.
3
+ * Provides global quiet mode state for suppressing informational output.
4
+ */
5
+ /**
6
+ * Check if quiet mode is enabled.
7
+ */
8
+ export declare function isQuietMode(): boolean;
9
+ /**
10
+ * Enable or disable quiet mode.
11
+ */
12
+ export declare function setQuietMode(enabled: boolean): void;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Quiet mode state management for AI Workflow CLI.
3
+ * Provides global quiet mode state for suppressing informational output.
4
+ */
5
+ let quietMode = false;
6
+ /**
7
+ * Check if quiet mode is enabled.
8
+ */
9
+ export function isQuietMode() {
10
+ return quietMode;
11
+ }
12
+ /**
13
+ * Enable or disable quiet mode.
14
+ */
15
+ export function setQuietMode(enabled) {
16
+ quietMode = enabled;
17
+ }
@@ -0,0 +1,42 @@
1
+ import type { ClaudeSettings, SettingsLocation } from './claude-settings-types.js';
2
+ /**
3
+ * Discover Claude settings files in the hierarchy
4
+ *
5
+ * Settings hierarchy (in order of precedence):
6
+ * 1. Local Project Settings: `.claude/settings.local.json` (gitignored)
7
+ * 2. Project Settings: `.claude/settings.json` (shared with team)
8
+ * 3. User Settings: `~/.claude/settings.json` (global)
9
+ *
10
+ * @param projectDir - Project directory path
11
+ * @returns Array of settings locations in order of precedence
12
+ */
13
+ export declare function discoverSettingsFiles(projectDir: string): Promise<SettingsLocation[]>;
14
+ /**
15
+ * Read Claude settings from file
16
+ *
17
+ * @param path - Path to settings.json file
18
+ * @returns Parsed settings or undefined if file doesn't exist or is invalid
19
+ */
20
+ export declare function readClaudeSettings(path: string): Promise<ClaudeSettings | undefined>;
21
+ /**
22
+ * Write Claude settings to file
23
+ *
24
+ * Creates parent directories if they don't exist
25
+ * Backs up existing file before writing
26
+ *
27
+ * @param path - Path to settings.json file
28
+ * @param settings - Settings to write
29
+ * @throws Error if write fails
30
+ */
31
+ export declare function writeClaudeSettings(path: string, settings: ClaudeSettings): Promise<void>;
32
+ /**
33
+ * Get the target settings file for template hook merging
34
+ *
35
+ * Strategy:
36
+ * - If project settings exist, merge into that file
37
+ * - Otherwise, create project settings with template hooks
38
+ *
39
+ * @param projectDir - Project directory path
40
+ * @returns Path to target settings file
41
+ */
42
+ export declare function getTargetSettingsFile(projectDir: string): string;
@@ -0,0 +1,105 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { IdePathResolver } from './ide-path-resolver.js';
5
+ /**
6
+ * Discover Claude settings files in the hierarchy
7
+ *
8
+ * Settings hierarchy (in order of precedence):
9
+ * 1. Local Project Settings: `.claude/settings.local.json` (gitignored)
10
+ * 2. Project Settings: `.claude/settings.json` (shared with team)
11
+ * 3. User Settings: `~/.claude/settings.json` (global)
12
+ *
13
+ * @param projectDir - Project directory path
14
+ * @returns Array of settings locations in order of precedence
15
+ */
16
+ export async function discoverSettingsFiles(projectDir) {
17
+ const locations = [];
18
+ // User settings (global)
19
+ const userSettingsPath = join(homedir(), '.claude', 'settings.json');
20
+ locations.push({
21
+ type: 'user',
22
+ path: userSettingsPath,
23
+ exists: await fileExists(userSettingsPath),
24
+ });
25
+ // Project settings (shared)
26
+ const projectSettingsPath = join(projectDir, '.claude', 'settings.json');
27
+ locations.push({
28
+ type: 'project',
29
+ path: projectSettingsPath,
30
+ exists: await fileExists(projectSettingsPath),
31
+ });
32
+ // Local project settings (gitignored)
33
+ const localSettingsPath = join(projectDir, '.claude', 'settings.local.json');
34
+ locations.push({
35
+ type: 'local',
36
+ path: localSettingsPath,
37
+ exists: await fileExists(localSettingsPath),
38
+ });
39
+ return locations;
40
+ }
41
+ /**
42
+ * Check if file exists
43
+ */
44
+ async function fileExists(path) {
45
+ try {
46
+ await fs.access(path);
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Read Claude settings from file
55
+ *
56
+ * @param path - Path to settings.json file
57
+ * @returns Parsed settings or undefined if file doesn't exist or is invalid
58
+ */
59
+ export async function readClaudeSettings(path) {
60
+ try {
61
+ const content = await fs.readFile(path, 'utf8');
62
+ return JSON.parse(content);
63
+ }
64
+ catch {
65
+ // File doesn't exist or invalid JSON
66
+ return undefined;
67
+ }
68
+ }
69
+ /**
70
+ * Write Claude settings to file
71
+ *
72
+ * Creates parent directories if they don't exist
73
+ * Backs up existing file before writing
74
+ *
75
+ * @param path - Path to settings.json file
76
+ * @param settings - Settings to write
77
+ * @throws Error if write fails
78
+ */
79
+ export async function writeClaudeSettings(path, settings) {
80
+ // Create parent directory if it doesn't exist
81
+ const dir = join(path, '..');
82
+ await fs.mkdir(dir, { recursive: true });
83
+ // Backup existing file if it exists
84
+ if (await fileExists(path)) {
85
+ const backupPath = `${path}.backup`;
86
+ await fs.copyFile(path, backupPath);
87
+ }
88
+ // Write settings with pretty formatting
89
+ const content = JSON.stringify(settings, null, 2);
90
+ await fs.writeFile(path, content, 'utf8');
91
+ }
92
+ /**
93
+ * Get the target settings file for template hook merging
94
+ *
95
+ * Strategy:
96
+ * - If project settings exist, merge into that file
97
+ * - Otherwise, create project settings with template hooks
98
+ *
99
+ * @param projectDir - Project directory path
100
+ * @returns Path to target settings file
101
+ */
102
+ export function getTargetSettingsFile(projectDir) {
103
+ const resolver = new IdePathResolver(projectDir);
104
+ return resolver.getClaudeSettings();
105
+ }
@@ -0,0 +1,105 @@
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
+ /**
42
+ * Spawn options for process execution.
43
+ */
44
+ export interface SpawnProcessOptions {
45
+ /**
46
+ * Working directory for spawned process.
47
+ * Defaults to current working directory if not specified.
48
+ */
49
+ cwd?: string;
50
+ /**
51
+ * Spawn detached process for parallel sessions.
52
+ * When true, process runs independently and parent can exit without waiting.
53
+ * Useful for launching multiple Claude Code sessions concurrently.
54
+ *
55
+ * @default false
56
+ */
57
+ detached?: boolean;
58
+ /**
59
+ * Stdio configuration.
60
+ * - 'inherit': Connect child stdio to parent (default, for interactive sessions)
61
+ * - 'pipe': Capture child stdio for programmatic access
62
+ */
63
+ stdio?: 'inherit' | 'pipe';
64
+ }
65
+ /**
66
+ * Spawn an external process and return its exit code.
67
+ *
68
+ * This function wraps Node.js child_process.spawn with AIW-specific
69
+ * error handling, debug logging, and parallel session support.
70
+ *
71
+ * ## Exit Code Mapping
72
+ * - 0: Success
73
+ * - Non-zero: Error (actual code from child process)
74
+ * - null code: Defaults to 1
75
+ *
76
+ * ## Error Handling
77
+ * - ENOENT: Command not found → ProcessSpawnError with install instructions
78
+ * - EACCES: Permission denied → ProcessSpawnError with permission fix
79
+ * - Other errors: ProcessSpawnError with error details
80
+ *
81
+ * ## Parallel Sessions
82
+ * Use `detached: true` to spawn independent processes that don't block parent.
83
+ * Multiple calls can run concurrently without conflicts.
84
+ *
85
+ * @param command - Command to execute (e.g., 'claude', 'npm', 'git')
86
+ * @param args - Arguments array (e.g., ['--dangerously-skip-permissions'])
87
+ * @param options - Spawn configuration options
88
+ * @returns Promise<number> - Exit code (0 = success, non-zero = error)
89
+ * @throws ProcessSpawnError - When spawn fails (command not found, permissions, etc.)
90
+ *
91
+ * @example
92
+ * // Launch Claude Code with sandbox disabled
93
+ * const exitCode = await spawnProcess('claude', ['--dangerously-skip-permissions'])
94
+ *
95
+ * @example
96
+ * // Parallel session with detached mode
97
+ * const session1 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
98
+ * const session2 = spawnProcess('claude', ['--dangerously-skip-permissions'], {detached: true})
99
+ * await Promise.all([session1, session2])
100
+ *
101
+ * @example
102
+ * // Custom working directory
103
+ * await spawnProcess('npm', ['test'], {cwd: '/path/to/project'})
104
+ */
105
+ export declare function spawnProcess(command: string, args?: string[], options?: SpawnProcessOptions): Promise<number>;