aiwcli 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1248 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +16 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +19 -0
- package/dist/commands/branch.d.ts +45 -0
- package/dist/commands/branch.js +488 -0
- package/dist/commands/clean.d.ts +34 -0
- package/dist/commands/clean.js +186 -0
- package/dist/commands/clear.d.ts +51 -0
- package/dist/commands/clear.js +835 -0
- package/dist/commands/init/index.d.ts +107 -0
- package/dist/commands/init/index.js +565 -0
- package/dist/commands/launch.d.ts +21 -0
- package/dist/commands/launch.js +108 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/base-command.d.ts +114 -0
- package/dist/lib/base-command.js +153 -0
- package/dist/lib/bmad-installer.d.ts +38 -0
- package/dist/lib/bmad-installer.js +145 -0
- package/dist/lib/claude-settings-types.d.ts +102 -0
- package/dist/lib/claude-settings-types.js +5 -0
- package/dist/lib/config.d.ts +25 -0
- package/dist/lib/config.js +46 -0
- package/dist/lib/debug.d.ts +39 -0
- package/dist/lib/debug.js +74 -0
- package/dist/lib/env-compat.d.ts +26 -0
- package/dist/lib/env-compat.js +35 -0
- package/dist/lib/errors.d.ts +126 -0
- package/dist/lib/errors.js +145 -0
- package/dist/lib/generic-merge.d.ts +74 -0
- package/dist/lib/generic-merge.js +105 -0
- package/dist/lib/git/branch.d.ts +67 -0
- package/dist/lib/git/branch.js +155 -0
- package/dist/lib/git/index.d.ts +11 -0
- package/dist/lib/git/index.js +13 -0
- package/dist/lib/git/safety-checks.d.ts +44 -0
- package/dist/lib/git/safety-checks.js +102 -0
- package/dist/lib/git/types.d.ts +31 -0
- package/dist/lib/git/types.js +6 -0
- package/dist/lib/git/worktree.d.ts +67 -0
- package/dist/lib/git/worktree.js +220 -0
- package/dist/lib/gitignore-manager.d.ts +10 -0
- package/dist/lib/gitignore-manager.js +60 -0
- package/dist/lib/hooks-merger.d.ts +28 -0
- package/dist/lib/hooks-merger.js +94 -0
- package/dist/lib/ide-path-resolver.d.ts +102 -0
- package/dist/lib/ide-path-resolver.js +129 -0
- package/dist/lib/index.d.ts +13 -0
- package/dist/lib/index.js +22 -0
- package/dist/lib/output.d.ts +51 -0
- package/dist/lib/output.js +76 -0
- package/dist/lib/paths.d.ts +66 -0
- package/dist/lib/paths.js +136 -0
- package/dist/lib/quiet.d.ts +12 -0
- package/dist/lib/quiet.js +17 -0
- package/dist/lib/settings-hierarchy.d.ts +42 -0
- package/dist/lib/settings-hierarchy.js +105 -0
- package/dist/lib/spawn.d.ts +105 -0
- package/dist/lib/spawn.js +157 -0
- package/dist/lib/spinner.d.ts +19 -0
- package/dist/lib/spinner.js +34 -0
- package/dist/lib/stdin.d.ts +48 -0
- package/dist/lib/stdin.js +60 -0
- package/dist/lib/template-installer.d.ts +92 -0
- package/dist/lib/template-installer.js +375 -0
- package/dist/lib/template-linter.d.ts +49 -0
- package/dist/lib/template-linter.js +173 -0
- package/dist/lib/template-merger.d.ts +47 -0
- package/dist/lib/template-merger.js +173 -0
- package/dist/lib/template-resolver.d.ts +20 -0
- package/dist/lib/template-resolver.js +60 -0
- package/dist/lib/terminal.d.ts +102 -0
- package/dist/lib/terminal.js +245 -0
- package/dist/lib/tty-detection.d.ts +62 -0
- package/dist/lib/tty-detection.js +83 -0
- package/dist/lib/user-utils.d.ts +5 -0
- package/dist/lib/user-utils.js +23 -0
- package/dist/lib/version.d.ts +99 -0
- package/dist/lib/version.js +144 -0
- package/dist/lib/watch-templates.d.ts +6 -0
- package/dist/lib/watch-templates.js +73 -0
- package/dist/lib/windsurf-hooks-hierarchy.d.ts +30 -0
- package/dist/lib/windsurf-hooks-hierarchy.js +66 -0
- package/dist/lib/windsurf-hooks-merger.d.ts +26 -0
- package/dist/lib/windsurf-hooks-merger.js +53 -0
- package/dist/lib/windsurf-hooks-types.d.ts +33 -0
- package/dist/lib/windsurf-hooks-types.js +5 -0
- package/dist/templates/CLAUDE.md +174 -0
- package/dist/templates/_shared/.claude/commands/handoff.md +14 -0
- package/dist/templates/_shared/.claude/settings.json +61 -0
- package/dist/templates/_shared/.codex/workflows/handoff.md +14 -0
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +14 -0
- package/dist/templates/_shared/hooks/__init__.py +16 -0
- package/dist/templates/_shared/hooks/archive_plan.py +270 -0
- package/dist/templates/_shared/hooks/context_enforcer.py +621 -0
- package/dist/templates/_shared/hooks/context_monitor.py +322 -0
- package/dist/templates/_shared/hooks/file-suggestion.py +188 -0
- package/dist/templates/_shared/hooks/task_create_capture.py +194 -0
- package/dist/templates/_shared/hooks/task_update_capture.py +254 -0
- package/dist/templates/_shared/hooks/user_prompt_submit.py +157 -0
- package/dist/templates/_shared/lib/__init__.py +1 -0
- package/dist/templates/_shared/lib/base/__init__.py +49 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/atomic_write.py +180 -0
- package/dist/templates/_shared/lib/base/constants.py +299 -0
- package/dist/templates/_shared/lib/base/inference.py +189 -0
- package/dist/templates/_shared/lib/base/utils.py +216 -0
- package/dist/templates/_shared/lib/context/__init__.py +119 -0
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/cache.py +446 -0
- package/dist/templates/_shared/lib/context/context_manager.py +1171 -0
- package/dist/templates/_shared/lib/context/discovery.py +486 -0
- package/dist/templates/_shared/lib/context/event_log.py +308 -0
- package/dist/templates/_shared/lib/context/plan_archive.py +247 -0
- package/dist/templates/_shared/lib/context/task_sync.py +367 -0
- package/dist/templates/_shared/lib/handoff/__init__.py +22 -0
- package/dist/templates/_shared/lib/handoff/document_generator.py +307 -0
- package/dist/templates/_shared/lib/templates/README.md +215 -0
- package/dist/templates/_shared/lib/templates/__init__.py +40 -0
- package/dist/templates/_shared/lib/templates/formatters.py +147 -0
- package/dist/templates/_shared/lib/templates/plan_context.py +119 -0
- package/dist/templates/_shared/scripts/save_handoff.py +99 -0
- package/dist/templates/_shared/workflows/handoff.md +212 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +75 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +239 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +109 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +71 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +104 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +223 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +73 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +93 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +103 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +145 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +248 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +235 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +80 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +76 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +141 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +240 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +211 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +101 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +197 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +97 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +349 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +106 -0
- package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +205 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -0
- package/dist/templates/cc-native/.claude/settings.json +119 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -0
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -0
- package/dist/templates/cc-native/CC-NATIVE-README.md +192 -0
- package/dist/templates/cc-native/MIGRATION.md +86 -0
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +331 -0
- package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +147 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +150 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +746 -0
- package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +339 -0
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +57 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/async_archive.py +68 -0
- package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +98 -0
- package/dist/templates/cc-native/_cc-native/lib/constants.py +45 -0
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +273 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +28 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +164 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +89 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +119 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +103 -0
- package/dist/templates/cc-native/_cc-native/lib/state.py +251 -0
- package/dist/templates/cc-native/_cc-native/lib/utils.py +830 -0
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +76 -0
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +151 -0
- package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +134 -0
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -0
- package/dist/types/exit-codes.d.ts +11 -0
- package/dist/types/exit-codes.js +10 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -0
- package/oclif.manifest.json +405 -0
- package/package.json +109 -0
|
@@ -0,0 +1,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>;
|