specweave 1.0.460 → 1.0.462
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/dist/plugins/specweave-ado/lib/ado-ac-checkbox-sync.d.ts +1 -2
- package/dist/plugins/specweave-ado/lib/ado-ac-checkbox-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-ac-checkbox-sync.js +3 -9
- package/dist/plugins/specweave-ado/lib/ado-ac-checkbox-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-ac-checkbox-sync.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/github-ac-checkbox-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-ac-checkbox-sync.js +5 -5
- package/dist/plugins/specweave-github/lib/github-ac-checkbox-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-ac-checkbox-sync.d.ts +1 -2
- package/dist/plugins/specweave-jira/lib/jira-ac-checkbox-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-ac-checkbox-sync.js +4 -11
- package/dist/plugins/specweave-jira/lib/jira-ac-checkbox-sync.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/lib/vendor/sync/config.d.ts +73 -0
- package/plugins/specweave/lib/vendor/sync/config.js +132 -0
- package/plugins/specweave/lib/vendor/sync/config.js.map +1 -0
- package/plugins/specweave/lib/vendor/sync/provider-router.d.ts +86 -0
- package/plugins/specweave/lib/vendor/sync/provider-router.js +147 -0
- package/plugins/specweave/lib/vendor/sync/provider-router.js.map +1 -0
- package/plugins/specweave/lib/vendor/sync/status-mapper.d.ts +120 -0
- package/plugins/specweave/lib/vendor/sync/status-mapper.js +164 -0
- package/plugins/specweave/lib/vendor/sync/status-mapper.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/clean-env.d.ts +47 -0
- package/plugins/specweave/lib/vendor/utils/clean-env.js +63 -0
- package/plugins/specweave/lib/vendor/utils/clean-env.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/execFileNoThrow.d.ts +99 -0
- package/plugins/specweave/lib/vendor/utils/execFileNoThrow.js +149 -0
- package/plugins/specweave/lib/vendor/utils/execFileNoThrow.js.map +1 -0
- package/plugins/specweave-ado/lib/ado-ac-checkbox-sync.js +2 -7
- package/plugins/specweave-ado/lib/ado-ac-checkbox-sync.ts +3 -9
- package/plugins/specweave-github/lib/github-ac-checkbox-sync.js +5 -5
- package/plugins/specweave-github/lib/github-ac-checkbox-sync.ts +5 -5
- package/plugins/specweave-github/lib/github-client-v2.js +1 -1
- package/plugins/specweave-github/lib/github-client-v2.ts +1 -1
- package/plugins/specweave-jira/lib/jira-ac-checkbox-sync.js +3 -9
- package/plugins/specweave-jira/lib/jira-ac-checkbox-sync.ts +4 -11
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean Environment Utility
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: This module MUST have NO imports from modules that spawn child processes
|
|
5
|
+
* to avoid circular dependencies. This is a foundational utility.
|
|
6
|
+
*
|
|
7
|
+
* This utility is used by:
|
|
8
|
+
* - execFileNoThrow.ts (core exec utility)
|
|
9
|
+
* - claude-cli-detector.ts (CLI detection)
|
|
10
|
+
* - Test files (via tests/test-utils/clean-env.ts)
|
|
11
|
+
*
|
|
12
|
+
* @module clean-env
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Create a clean environment for spawning child processes.
|
|
16
|
+
*
|
|
17
|
+
* CRITICAL: Removes env vars that can cause child processes to fail:
|
|
18
|
+
*
|
|
19
|
+
* - CLAUDECODE: Nested session guard (Claude Code v2.1.39+) blocks `claude -p`
|
|
20
|
+
* when running inside a Claude Code session. Unsetting is the official bypass.
|
|
21
|
+
* See: https://github.com/anthropics/claude-code/issues/25434
|
|
22
|
+
* Same fix applied in Python Agent SDK PR #594.
|
|
23
|
+
* - VSCode Debug: NODE_OPTIONS contains --inspect-brk flags
|
|
24
|
+
* - WebStorm/IntelliJ: NODE_OPTIONS or IDEA-specific vars
|
|
25
|
+
* - CI/CD (GitHub Actions, etc.): May set NODE_OPTIONS for coverage
|
|
26
|
+
* - Jest/Vitest: May set NODE_OPTIONS for debugging
|
|
27
|
+
*
|
|
28
|
+
* This function is safe to use in ALL environments:
|
|
29
|
+
* - Windows, macOS, Linux
|
|
30
|
+
* - Local development, CI/CD pipelines
|
|
31
|
+
* - Debug mode, run mode, production
|
|
32
|
+
*
|
|
33
|
+
* If a variable is not set, delete is a no-op (safe).
|
|
34
|
+
*
|
|
35
|
+
* @returns A copy of process.env with problematic vars removed
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { getCleanEnv } from './clean-env.js';
|
|
40
|
+
*
|
|
41
|
+
* // Spawn a child process without debugger interference
|
|
42
|
+
* execSync('node script.js', { env: getCleanEnv() });
|
|
43
|
+
* spawnSync('claude', ['--version'], { env: getCleanEnv() });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function getCleanEnv(): NodeJS.ProcessEnv;
|
|
47
|
+
//# sourceMappingURL=clean-env.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean Environment Utility
|
|
3
|
+
*
|
|
4
|
+
* CRITICAL: This module MUST have NO imports from modules that spawn child processes
|
|
5
|
+
* to avoid circular dependencies. This is a foundational utility.
|
|
6
|
+
*
|
|
7
|
+
* This utility is used by:
|
|
8
|
+
* - execFileNoThrow.ts (core exec utility)
|
|
9
|
+
* - claude-cli-detector.ts (CLI detection)
|
|
10
|
+
* - Test files (via tests/test-utils/clean-env.ts)
|
|
11
|
+
*
|
|
12
|
+
* @module clean-env
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Create a clean environment for spawning child processes.
|
|
16
|
+
*
|
|
17
|
+
* CRITICAL: Removes env vars that can cause child processes to fail:
|
|
18
|
+
*
|
|
19
|
+
* - CLAUDECODE: Nested session guard (Claude Code v2.1.39+) blocks `claude -p`
|
|
20
|
+
* when running inside a Claude Code session. Unsetting is the official bypass.
|
|
21
|
+
* See: https://github.com/anthropics/claude-code/issues/25434
|
|
22
|
+
* Same fix applied in Python Agent SDK PR #594.
|
|
23
|
+
* - VSCode Debug: NODE_OPTIONS contains --inspect-brk flags
|
|
24
|
+
* - WebStorm/IntelliJ: NODE_OPTIONS or IDEA-specific vars
|
|
25
|
+
* - CI/CD (GitHub Actions, etc.): May set NODE_OPTIONS for coverage
|
|
26
|
+
* - Jest/Vitest: May set NODE_OPTIONS for debugging
|
|
27
|
+
*
|
|
28
|
+
* This function is safe to use in ALL environments:
|
|
29
|
+
* - Windows, macOS, Linux
|
|
30
|
+
* - Local development, CI/CD pipelines
|
|
31
|
+
* - Debug mode, run mode, production
|
|
32
|
+
*
|
|
33
|
+
* If a variable is not set, delete is a no-op (safe).
|
|
34
|
+
*
|
|
35
|
+
* @returns A copy of process.env with problematic vars removed
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { getCleanEnv } from './clean-env.js';
|
|
40
|
+
*
|
|
41
|
+
* // Spawn a child process without debugger interference
|
|
42
|
+
* execSync('node script.js', { env: getCleanEnv() });
|
|
43
|
+
* spawnSync('claude', ['--version'], { env: getCleanEnv() });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function getCleanEnv() {
|
|
47
|
+
const cleanEnv = { ...process.env };
|
|
48
|
+
// Remove Claude Code nested session guard (v2.1.39+)
|
|
49
|
+
// When CLAUDECODE=1, `claude -p` refuses to start with:
|
|
50
|
+
// "Claude Code cannot be launched inside another Claude Code session"
|
|
51
|
+
// This is safe: we're spawning a one-shot pipe-mode call, not a competing session.
|
|
52
|
+
delete cleanEnv.CLAUDECODE;
|
|
53
|
+
// Remove Node.js debugger/inspector flags (VSCode, WebStorm, etc.)
|
|
54
|
+
delete cleanEnv.NODE_OPTIONS;
|
|
55
|
+
delete cleanEnv.NODE_INSPECT;
|
|
56
|
+
delete cleanEnv.NODE_INSPECT_RESUME_ON_START;
|
|
57
|
+
// Remove coverage instrumentation that can interfere with spawned processes
|
|
58
|
+
delete cleanEnv.NODE_V8_COVERAGE;
|
|
59
|
+
// Remove test runner debug vars
|
|
60
|
+
delete cleanEnv.VSCODE_INSPECTOR_OPTIONS;
|
|
61
|
+
return cleanEnv;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=clean-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean-env.js","sourceRoot":"","sources":["../../../src/utils/clean-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAEpC,qDAAqD;IACrD,wDAAwD;IACxD,wEAAwE;IACxE,mFAAmF;IACnF,OAAO,QAAQ,CAAC,UAAU,CAAC;IAE3B,mEAAmE;IACnE,OAAO,QAAQ,CAAC,YAAY,CAAC;IAC7B,OAAO,QAAQ,CAAC,YAAY,CAAC;IAC7B,OAAO,QAAQ,CAAC,4BAA4B,CAAC;IAE7C,4EAA4E;IAC5E,OAAO,QAAQ,CAAC,gBAAgB,CAAC;IAEjC,gCAAgC;IAChC,OAAO,QAAQ,CAAC,wBAAwB,CAAC;IAEzC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ExecFileException } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Result from command execution
|
|
4
|
+
*/
|
|
5
|
+
export interface ExecResult {
|
|
6
|
+
/** Standard output from command */
|
|
7
|
+
stdout: string;
|
|
8
|
+
/** Standard error from command */
|
|
9
|
+
stderr: string;
|
|
10
|
+
/** Exit code (0 = success) */
|
|
11
|
+
exitCode: number;
|
|
12
|
+
/** Whether command succeeded (exitCode === 0) */
|
|
13
|
+
success: boolean;
|
|
14
|
+
/** Error object if command failed */
|
|
15
|
+
error?: ExecFileException;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Safely execute a command without throwing errors
|
|
19
|
+
*
|
|
20
|
+
* This utility uses child_process.execFile instead of exec/execSync:
|
|
21
|
+
* - ✅ Prevents command injection vulnerabilities (no shell interpolation)
|
|
22
|
+
* - ✅ Cross-platform compatible (Windows, Mac, Linux)
|
|
23
|
+
* - ✅ Proper error handling (returns result instead of throwing)
|
|
24
|
+
* - ✅ Structured output (stdout, stderr, exitCode)
|
|
25
|
+
*
|
|
26
|
+
* @param command - Command to execute (must be in PATH or absolute path)
|
|
27
|
+
* @param args - Array of arguments (safely escaped automatically)
|
|
28
|
+
* @param options - Additional execution options
|
|
29
|
+
* @returns Promise resolving to execution result
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // ✅ Safe: Arguments automatically escaped
|
|
34
|
+
* const result = await execFileNoThrow('git', ['add', userProvidedFilename]);
|
|
35
|
+
* if (result.success) {
|
|
36
|
+
* console.log('Git add succeeded:', result.stdout);
|
|
37
|
+
* } else {
|
|
38
|
+
* console.error('Git add failed:', result.stderr);
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* // ✅ Check if command exists
|
|
42
|
+
* const which = process.platform === 'win32' ? 'where' : 'which';
|
|
43
|
+
* const checkResult = await execFileNoThrow(which, ['claude']);
|
|
44
|
+
* if (checkResult.success) {
|
|
45
|
+
* console.log('Claude CLI found at:', checkResult.stdout.trim());
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function execFileNoThrow(command: string, args?: string[], options?: {
|
|
50
|
+
cwd?: string;
|
|
51
|
+
env?: NodeJS.ProcessEnv;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
maxBuffer?: number;
|
|
54
|
+
shell?: boolean;
|
|
55
|
+
}): Promise<ExecResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Synchronous version of execFileNoThrow
|
|
58
|
+
*
|
|
59
|
+
* Use sparingly - prefer async version when possible.
|
|
60
|
+
* Useful for initialization code that needs to be synchronous.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const result = execFileNoThrowSync('claude', ['--version']);
|
|
65
|
+
* if (result.success) {
|
|
66
|
+
* console.log('Claude version:', result.stdout.trim());
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function execFileNoThrowSync(command: string, args?: string[], options?: {
|
|
71
|
+
cwd?: string;
|
|
72
|
+
env?: NodeJS.ProcessEnv;
|
|
73
|
+
timeout?: number;
|
|
74
|
+
maxBuffer?: number;
|
|
75
|
+
shell?: boolean;
|
|
76
|
+
}): ExecResult;
|
|
77
|
+
/**
|
|
78
|
+
* Check if a command is available in PATH
|
|
79
|
+
*
|
|
80
|
+
* Cross-platform helper that uses 'which' (Unix) or 'where' (Windows)
|
|
81
|
+
*
|
|
82
|
+
* @param command - Command name to check (e.g., 'claude', 'git', 'node')
|
|
83
|
+
* @returns Promise resolving to true if command exists, false otherwise
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* if (await isCommandAvailable('claude')) {
|
|
88
|
+
* console.log('Claude CLI is installed');
|
|
89
|
+
* } else {
|
|
90
|
+
* console.log('Claude CLI not found - install from https://claude.com/code');
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function isCommandAvailable(command: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Synchronous version of isCommandAvailable
|
|
97
|
+
*/
|
|
98
|
+
export declare function isCommandAvailableSync(command: string): boolean;
|
|
99
|
+
//# sourceMappingURL=execFileNoThrow.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { execFile, execFileSync } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { getCleanEnv } from './clean-env.js';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
/**
|
|
6
|
+
* Safely execute a command without throwing errors
|
|
7
|
+
*
|
|
8
|
+
* This utility uses child_process.execFile instead of exec/execSync:
|
|
9
|
+
* - ✅ Prevents command injection vulnerabilities (no shell interpolation)
|
|
10
|
+
* - ✅ Cross-platform compatible (Windows, Mac, Linux)
|
|
11
|
+
* - ✅ Proper error handling (returns result instead of throwing)
|
|
12
|
+
* - ✅ Structured output (stdout, stderr, exitCode)
|
|
13
|
+
*
|
|
14
|
+
* @param command - Command to execute (must be in PATH or absolute path)
|
|
15
|
+
* @param args - Array of arguments (safely escaped automatically)
|
|
16
|
+
* @param options - Additional execution options
|
|
17
|
+
* @returns Promise resolving to execution result
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // ✅ Safe: Arguments automatically escaped
|
|
22
|
+
* const result = await execFileNoThrow('git', ['add', userProvidedFilename]);
|
|
23
|
+
* if (result.success) {
|
|
24
|
+
* console.log('Git add succeeded:', result.stdout);
|
|
25
|
+
* } else {
|
|
26
|
+
* console.error('Git add failed:', result.stderr);
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // ✅ Check if command exists
|
|
30
|
+
* const which = process.platform === 'win32' ? 'where' : 'which';
|
|
31
|
+
* const checkResult = await execFileNoThrow(which, ['claude']);
|
|
32
|
+
* if (checkResult.success) {
|
|
33
|
+
* console.log('Claude CLI found at:', checkResult.stdout.trim());
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export async function execFileNoThrow(command, args = [], options = {}) {
|
|
38
|
+
try {
|
|
39
|
+
// CRITICAL: On Windows, shell is needed for .cmd/.bat files
|
|
40
|
+
// Without shell, execFileAsync can't find 'claude.cmd' even if it's in PATH
|
|
41
|
+
const needsShell = process.platform === 'win32' && options.shell !== false;
|
|
42
|
+
// CRITICAL: Use clean environment to prevent debugger/instrumentation from breaking child processes
|
|
43
|
+
// If caller provides custom env, merge with clean env (caller's values take precedence)
|
|
44
|
+
const cleanEnv = getCleanEnv();
|
|
45
|
+
const mergedEnv = options.env ? { ...cleanEnv, ...options.env } : cleanEnv;
|
|
46
|
+
const { stdout, stderr } = await execFileAsync(command, args, {
|
|
47
|
+
...options,
|
|
48
|
+
env: mergedEnv,
|
|
49
|
+
encoding: 'utf-8',
|
|
50
|
+
windowsHide: true, // Don't show console window on Windows
|
|
51
|
+
shell: needsShell,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
stdout: stdout || '',
|
|
55
|
+
stderr: stderr || '',
|
|
56
|
+
exitCode: 0,
|
|
57
|
+
success: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const execError = error;
|
|
62
|
+
return {
|
|
63
|
+
stdout: execError.stdout || '',
|
|
64
|
+
stderr: execError.stderr || '',
|
|
65
|
+
exitCode: typeof execError.code === 'number' ? execError.code : 1,
|
|
66
|
+
success: false,
|
|
67
|
+
error: execError,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Synchronous version of execFileNoThrow
|
|
73
|
+
*
|
|
74
|
+
* Use sparingly - prefer async version when possible.
|
|
75
|
+
* Useful for initialization code that needs to be synchronous.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const result = execFileNoThrowSync('claude', ['--version']);
|
|
80
|
+
* if (result.success) {
|
|
81
|
+
* console.log('Claude version:', result.stdout.trim());
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function execFileNoThrowSync(command, args = [], options = {}) {
|
|
86
|
+
try {
|
|
87
|
+
// CRITICAL: On Windows, shell is needed for .cmd/.bat files
|
|
88
|
+
// Without shell, execFileSync can't find 'claude.cmd' even if it's in PATH
|
|
89
|
+
const needsShell = process.platform === 'win32' && options.shell !== false;
|
|
90
|
+
// CRITICAL: Use clean environment to prevent debugger/instrumentation from breaking child processes
|
|
91
|
+
// If caller provides custom env, merge with clean env (caller's values take precedence)
|
|
92
|
+
const cleanEnv = getCleanEnv();
|
|
93
|
+
const mergedEnv = options.env ? { ...cleanEnv, ...options.env } : cleanEnv;
|
|
94
|
+
const stdout = execFileSync(command, args, {
|
|
95
|
+
...options,
|
|
96
|
+
env: mergedEnv,
|
|
97
|
+
encoding: 'utf-8',
|
|
98
|
+
windowsHide: true,
|
|
99
|
+
shell: needsShell,
|
|
100
|
+
stdio: ['pipe', 'pipe', 'pipe'], // Capture all streams, don't leak to terminal
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
stdout: stdout || '',
|
|
104
|
+
stderr: '',
|
|
105
|
+
exitCode: 0,
|
|
106
|
+
success: true,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
stdout: error.stdout || '',
|
|
112
|
+
stderr: error.stderr || '',
|
|
113
|
+
exitCode: typeof error.status === 'number' ? error.status : 1,
|
|
114
|
+
success: false,
|
|
115
|
+
error: error,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if a command is available in PATH
|
|
121
|
+
*
|
|
122
|
+
* Cross-platform helper that uses 'which' (Unix) or 'where' (Windows)
|
|
123
|
+
*
|
|
124
|
+
* @param command - Command name to check (e.g., 'claude', 'git', 'node')
|
|
125
|
+
* @returns Promise resolving to true if command exists, false otherwise
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* if (await isCommandAvailable('claude')) {
|
|
130
|
+
* console.log('Claude CLI is installed');
|
|
131
|
+
* } else {
|
|
132
|
+
* console.log('Claude CLI not found - install from https://claude.com/code');
|
|
133
|
+
* }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export async function isCommandAvailable(command) {
|
|
137
|
+
const whichCommand = process.platform === 'win32' ? 'where' : 'which';
|
|
138
|
+
const result = await execFileNoThrow(whichCommand, [command]);
|
|
139
|
+
return result.success;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Synchronous version of isCommandAvailable
|
|
143
|
+
*/
|
|
144
|
+
export function isCommandAvailableSync(command) {
|
|
145
|
+
const whichCommand = process.platform === 'win32' ? 'where' : 'which';
|
|
146
|
+
const result = execFileNoThrowSync(whichCommand, [command]);
|
|
147
|
+
return result.success;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=execFileNoThrow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execFileNoThrow.js","sourceRoot":"","sources":["../../../src/utils/execFileNoThrow.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,16 +2,14 @@ import { promises as fs, existsSync } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import yaml from "yaml";
|
|
4
4
|
import axios from "axios";
|
|
5
|
-
import { consoleLogger } from "
|
|
6
|
-
import {
|
|
7
|
-
import { deriveFeatureId } from "../../../src/utils/feature-id-derivation.js";
|
|
5
|
+
import { consoleLogger } from "../../specweave/lib/vendor/utils/logger.js";
|
|
6
|
+
import { deriveFeatureId } from "../../specweave/lib/vendor/utils/feature-id-derivation.js";
|
|
8
7
|
import { GitHubACCheckboxSync } from "../../specweave-github/lib/github-ac-checkbox-sync.js";
|
|
9
8
|
class AdoACCheckboxSync {
|
|
10
9
|
constructor(options) {
|
|
11
10
|
this.projectRoot = options.projectRoot;
|
|
12
11
|
this.incrementId = options.incrementId;
|
|
13
12
|
this.logger = options.logger ?? consoleLogger;
|
|
14
|
-
this.projectId = autoDetectProjectIdSync(this.projectRoot) || "default";
|
|
15
13
|
}
|
|
16
14
|
async syncACCheckboxesToAdo(config) {
|
|
17
15
|
const result = { success: true, updated: 0, issues: [] };
|
|
@@ -202,12 +200,9 @@ ${acLines}
|
|
|
202
200
|
const specsRoot = path.join(this.projectRoot, ".specweave/docs/internal/specs");
|
|
203
201
|
const usFiles = [];
|
|
204
202
|
const projectDirs = [];
|
|
205
|
-
const primary = path.join(specsRoot, this.projectId, featureId);
|
|
206
|
-
if (existsSync(primary)) projectDirs.push(primary);
|
|
207
203
|
if (existsSync(specsRoot)) {
|
|
208
204
|
try {
|
|
209
205
|
for (const proj of await fs.readdir(specsRoot)) {
|
|
210
|
-
if (proj === this.projectId) continue;
|
|
211
206
|
const p = path.join(specsRoot, proj, featureId);
|
|
212
207
|
if (existsSync(p)) projectDirs.push(p);
|
|
213
208
|
}
|
|
@@ -12,9 +12,8 @@ import { promises as fs, existsSync } from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import yaml from 'yaml';
|
|
14
14
|
import axios, { AxiosInstance } from 'axios';
|
|
15
|
-
import { Logger, consoleLogger } from '
|
|
16
|
-
import {
|
|
17
|
-
import { deriveFeatureId } from '../../../src/utils/feature-id-derivation.js';
|
|
15
|
+
import { Logger, consoleLogger } from '../../specweave/lib/vendor/utils/logger.js';
|
|
16
|
+
import { deriveFeatureId } from '../../specweave/lib/vendor/utils/feature-id-derivation.js';
|
|
18
17
|
import { GitHubACCheckboxSync } from '../../specweave-github/lib/github-ac-checkbox-sync.js';
|
|
19
18
|
import type { SpecWeaveConfig } from '../../../src/core/config/types.js';
|
|
20
19
|
import type { LivingDocsUSFile } from '../../../src/types/living-docs-us-file.js';
|
|
@@ -28,7 +27,6 @@ export interface AdoACCheckboxSyncResult {
|
|
|
28
27
|
export class AdoACCheckboxSync {
|
|
29
28
|
private projectRoot: string;
|
|
30
29
|
private incrementId: string;
|
|
31
|
-
private projectId: string;
|
|
32
30
|
private logger: Logger;
|
|
33
31
|
|
|
34
32
|
constructor(options: {
|
|
@@ -39,7 +37,6 @@ export class AdoACCheckboxSync {
|
|
|
39
37
|
this.projectRoot = options.projectRoot;
|
|
40
38
|
this.incrementId = options.incrementId;
|
|
41
39
|
this.logger = options.logger ?? consoleLogger;
|
|
42
|
-
this.projectId = autoDetectProjectIdSync(this.projectRoot) || 'default';
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
async syncACCheckboxesToAdo(config: SpecWeaveConfig): Promise<AdoACCheckboxSyncResult> {
|
|
@@ -271,13 +268,10 @@ ${acLines}
|
|
|
271
268
|
const usFiles: LivingDocsUSFile[] = [];
|
|
272
269
|
const projectDirs: string[] = [];
|
|
273
270
|
|
|
274
|
-
|
|
275
|
-
if (existsSync(primary)) projectDirs.push(primary);
|
|
276
|
-
|
|
271
|
+
// Search all project directories for the feature
|
|
277
272
|
if (existsSync(specsRoot)) {
|
|
278
273
|
try {
|
|
279
274
|
for (const proj of await fs.readdir(specsRoot)) {
|
|
280
|
-
if (proj === this.projectId) continue;
|
|
281
275
|
const p = path.join(specsRoot, proj, featureId);
|
|
282
276
|
if (existsSync(p)) projectDirs.push(p);
|
|
283
277
|
}
|
|
@@ -2,16 +2,16 @@ import { promises as fs, existsSync } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import yaml from "yaml";
|
|
4
4
|
import { GitHubClientV2 } from "./github-client-v2.js";
|
|
5
|
-
import { consoleLogger } from "
|
|
5
|
+
import { consoleLogger } from "../../specweave/lib/vendor/utils/logger.js";
|
|
6
6
|
import { autoDetectProjectIdSync } from "../../../src/utils/project-detection.js";
|
|
7
|
-
import { deriveFeatureId } from "
|
|
7
|
+
import { deriveFeatureId } from "../../specweave/lib/vendor/utils/feature-id-derivation.js";
|
|
8
8
|
import {
|
|
9
9
|
ProviderRouter
|
|
10
|
-
} from "
|
|
10
|
+
} from "../../specweave/lib/vendor/sync/provider-router.js";
|
|
11
11
|
import {
|
|
12
12
|
isProviderEnabled
|
|
13
|
-
} from "
|
|
14
|
-
import { resolvePermissions } from "
|
|
13
|
+
} from "../../specweave/lib/vendor/sync/status-mapper.js";
|
|
14
|
+
import { resolvePermissions } from "../../specweave/lib/vendor/sync/config.js";
|
|
15
15
|
class GitHubACCheckboxSync {
|
|
16
16
|
constructor(options) {
|
|
17
17
|
this.projectRoot = options.projectRoot;
|
|
@@ -12,17 +12,17 @@ import { promises as fs, existsSync } from 'fs';
|
|
|
12
12
|
import path from 'path';
|
|
13
13
|
import yaml from 'yaml';
|
|
14
14
|
import { GitHubClientV2 } from './github-client-v2.js';
|
|
15
|
-
import { Logger, consoleLogger } from '
|
|
15
|
+
import { Logger, consoleLogger } from '../../specweave/lib/vendor/utils/logger.js';
|
|
16
16
|
import { autoDetectProjectIdSync } from '../../../src/utils/project-detection.js';
|
|
17
|
-
import { deriveFeatureId } from '
|
|
17
|
+
import { deriveFeatureId } from '../../specweave/lib/vendor/utils/feature-id-derivation.js';
|
|
18
18
|
import {
|
|
19
19
|
ProviderRouter,
|
|
20
20
|
GitHubRepoConfig,
|
|
21
|
-
} from '
|
|
21
|
+
} from '../../specweave/lib/vendor/sync/provider-router.js';
|
|
22
22
|
import {
|
|
23
23
|
isProviderEnabled,
|
|
24
|
-
} from '
|
|
25
|
-
import { resolvePermissions, SyncPreset } from '
|
|
24
|
+
} from '../../specweave/lib/vendor/sync/status-mapper.js';
|
|
25
|
+
import { resolvePermissions, SyncPreset } from '../../specweave/lib/vendor/sync/config.js';
|
|
26
26
|
import type { SpecWeaveConfig } from '../../../src/core/config/types.js';
|
|
27
27
|
import type { LivingDocsUSFile } from '../../../src/types/living-docs-us-file.js';
|
|
28
28
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Secure command execution (no shell injection)
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { execFileNoThrow } from '
|
|
11
|
+
import { execFileNoThrow } from '../../specweave/lib/vendor/utils/execFileNoThrow.js';
|
|
12
12
|
import { GitHubIssue, GitHubMilestone, GitHubExternalChange } from './types';
|
|
13
13
|
import { SyncProfile, GitHubConfig, TimeRangePreset } from '../../../src/core/types/sync-profile';
|
|
14
14
|
|
|
@@ -2,9 +2,8 @@ import { promises as fs, existsSync } from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import yaml from "yaml";
|
|
4
4
|
import axios from "axios";
|
|
5
|
-
import { consoleLogger } from "
|
|
6
|
-
import {
|
|
7
|
-
import { deriveFeatureId } from "../../../src/utils/feature-id-derivation.js";
|
|
5
|
+
import { consoleLogger } from "../../specweave/lib/vendor/utils/logger.js";
|
|
6
|
+
import { deriveFeatureId } from "../../specweave/lib/vendor/utils/feature-id-derivation.js";
|
|
8
7
|
import { getApiBaseUrl } from "./jira-deployment-detector.js";
|
|
9
8
|
import { GitHubACCheckboxSync } from "../../specweave-github/lib/github-ac-checkbox-sync.js";
|
|
10
9
|
class JiraACCheckboxSync {
|
|
@@ -12,7 +11,6 @@ class JiraACCheckboxSync {
|
|
|
12
11
|
this.projectRoot = options.projectRoot;
|
|
13
12
|
this.incrementId = options.incrementId;
|
|
14
13
|
this.logger = options.logger ?? consoleLogger;
|
|
15
|
-
this.projectId = autoDetectProjectIdSync(this.projectRoot) || "default";
|
|
16
14
|
}
|
|
17
15
|
async syncACCheckboxesToJira(config) {
|
|
18
16
|
const result = { success: true, updated: 0, issues: [] };
|
|
@@ -224,13 +222,9 @@ class JiraACCheckboxSync {
|
|
|
224
222
|
const specsRoot = path.join(this.projectRoot, ".specweave/docs/internal/specs");
|
|
225
223
|
const usFiles = [];
|
|
226
224
|
const projectDirs = [];
|
|
227
|
-
const primaryPath = path.join(specsRoot, this.projectId, featureId);
|
|
228
|
-
if (existsSync(primaryPath)) projectDirs.push(primaryPath);
|
|
229
225
|
if (existsSync(specsRoot)) {
|
|
230
226
|
try {
|
|
231
|
-
const
|
|
232
|
-
for (const proj of allProjects) {
|
|
233
|
-
if (proj === this.projectId) continue;
|
|
227
|
+
for (const proj of await fs.readdir(specsRoot)) {
|
|
234
228
|
const p = path.join(specsRoot, proj, featureId);
|
|
235
229
|
if (existsSync(p)) projectDirs.push(p);
|
|
236
230
|
}
|
|
@@ -15,9 +15,8 @@ import { promises as fs, existsSync } from 'fs';
|
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import yaml from 'yaml';
|
|
17
17
|
import axios, { AxiosInstance } from 'axios';
|
|
18
|
-
import { Logger, consoleLogger } from '
|
|
19
|
-
import {
|
|
20
|
-
import { deriveFeatureId } from '../../../src/utils/feature-id-derivation.js';
|
|
18
|
+
import { Logger, consoleLogger } from '../../specweave/lib/vendor/utils/logger.js';
|
|
19
|
+
import { deriveFeatureId } from '../../specweave/lib/vendor/utils/feature-id-derivation.js';
|
|
21
20
|
import { detectDeploymentType, getApiBaseUrl } from './jira-deployment-detector.js';
|
|
22
21
|
import type { SpecWeaveConfig } from '../../../src/core/config/types.js';
|
|
23
22
|
import type { LivingDocsUSFile } from '../../../src/types/living-docs-us-file.js';
|
|
@@ -32,7 +31,6 @@ export interface JiraACCheckboxSyncResult {
|
|
|
32
31
|
export class JiraACCheckboxSync {
|
|
33
32
|
private projectRoot: string;
|
|
34
33
|
private incrementId: string;
|
|
35
|
-
private projectId: string;
|
|
36
34
|
private logger: Logger;
|
|
37
35
|
|
|
38
36
|
constructor(options: {
|
|
@@ -43,7 +41,6 @@ export class JiraACCheckboxSync {
|
|
|
43
41
|
this.projectRoot = options.projectRoot;
|
|
44
42
|
this.incrementId = options.incrementId;
|
|
45
43
|
this.logger = options.logger ?? consoleLogger;
|
|
46
|
-
this.projectId = autoDetectProjectIdSync(this.projectRoot) || 'default';
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
async syncACCheckboxesToJira(config: SpecWeaveConfig): Promise<JiraACCheckboxSyncResult> {
|
|
@@ -299,15 +296,11 @@ export class JiraACCheckboxSync {
|
|
|
299
296
|
const specsRoot = path.join(this.projectRoot, '.specweave/docs/internal/specs');
|
|
300
297
|
const usFiles: LivingDocsUSFile[] = [];
|
|
301
298
|
|
|
299
|
+
// Search all project directories for the feature
|
|
302
300
|
const projectDirs: string[] = [];
|
|
303
|
-
const primaryPath = path.join(specsRoot, this.projectId, featureId);
|
|
304
|
-
if (existsSync(primaryPath)) projectDirs.push(primaryPath);
|
|
305
|
-
|
|
306
301
|
if (existsSync(specsRoot)) {
|
|
307
302
|
try {
|
|
308
|
-
const
|
|
309
|
-
for (const proj of allProjects) {
|
|
310
|
-
if (proj === this.projectId) continue;
|
|
303
|
+
for (const proj of await fs.readdir(specsRoot)) {
|
|
311
304
|
const p = path.join(specsRoot, proj, featureId);
|
|
312
305
|
if (existsSync(p)) projectDirs.push(p);
|
|
313
306
|
}
|