kld-sdd 2.4.13 → 2.4.14
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/lib/init.js +36 -3
- package/package.json +1 -1
- package/templates/git-hooks/pre-push-sdd-check.cjs +10 -3
- package/templates/hooks/claude/hooks/sdd-post-tool.cjs +29 -3
- package/templates/hooks/claude/hooks/sdd-prompt.cjs +23 -1
- package/templates/hooks/claude/hooks/sdd-stop.cjs +29 -3
- package/templates/hooks/claude/settings.json +4 -4
package/lib/init.js
CHANGED
|
@@ -599,6 +599,36 @@ function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
599
599
|
* 部署 Claude Code Hook Pack(可选增强)
|
|
600
600
|
* Hook 只调用 skywalk-sdd/log.cjs,不写私有日志,不替代 OPSX 模板采集。
|
|
601
601
|
*/
|
|
602
|
+
function hookCommandText(hook) {
|
|
603
|
+
const args = Array.isArray(hook.args) ? hook.args : [];
|
|
604
|
+
return [hook.command, ...args].filter(Boolean).join(' ').replace(/\s+/g, ' ').trim();
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function isSddClaudeHook(hook) {
|
|
608
|
+
const text = hookCommandText(hook);
|
|
609
|
+
return /(?:^|\s|["'])\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop)\.(?:cjs|js)(?=$|\s|["'])/i.test(text) ||
|
|
610
|
+
/(?:^|\s|["'])\$\{CLAUDE_PROJECT_DIR\}[\\/]+\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop)\.(?:cjs|js)(?=$|\s|["'])/i.test(text);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function sameHookCommand(left, right) {
|
|
614
|
+
return hookCommandText(left) === hookCommandText(right) &&
|
|
615
|
+
String(left.type || '') === String(right.type || '');
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function removeManagedSddHooks(entries) {
|
|
619
|
+
return entries
|
|
620
|
+
.map(entry => {
|
|
621
|
+
if (!Array.isArray(entry.hooks)) {
|
|
622
|
+
return entry;
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
...entry,
|
|
626
|
+
hooks: entry.hooks.filter(hook => !isSddClaudeHook(hook)),
|
|
627
|
+
};
|
|
628
|
+
})
|
|
629
|
+
.filter(entry => !Array.isArray(entry.hooks) || entry.hooks.length > 0);
|
|
630
|
+
}
|
|
631
|
+
|
|
602
632
|
function deployClaudeHookPack(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
603
633
|
if (!selectedTools.includes('claude')) {
|
|
604
634
|
return true;
|
|
@@ -642,11 +672,14 @@ function deployClaudeHookPack(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
642
672
|
|
|
643
673
|
existingSettings.hooks = existingSettings.hooks || {};
|
|
644
674
|
for (const [eventName, entries] of Object.entries(templateSettings.hooks || {})) {
|
|
645
|
-
existingSettings.hooks[eventName] = existingSettings.hooks[eventName] || [];
|
|
675
|
+
existingSettings.hooks[eventName] = removeManagedSddHooks(existingSettings.hooks[eventName] || []);
|
|
646
676
|
for (const entry of entries) {
|
|
647
|
-
const
|
|
677
|
+
const templateHooks = entry.hooks || [];
|
|
648
678
|
const exists = existingSettings.hooks[eventName].some(existingEntry => {
|
|
649
|
-
|
|
679
|
+
const existingHooks = existingEntry.hooks || [];
|
|
680
|
+
return templateHooks.every(templateHook => {
|
|
681
|
+
return existingHooks.some(existingHook => sameHookCommand(existingHook, templateHook));
|
|
682
|
+
});
|
|
650
683
|
});
|
|
651
684
|
if (!exists) {
|
|
652
685
|
existingSettings.hooks[eventName].push(entry);
|
package/package.json
CHANGED
|
@@ -39,11 +39,18 @@ function main() {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
if (result.error) {
|
|
42
|
-
console.
|
|
43
|
-
|
|
42
|
+
console.warn(`SDD pre-push: failed to run doctor: ${result.error.message}; push will continue.`);
|
|
43
|
+
return;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
if (result.status && result.status !== 0) {
|
|
47
|
+
console.warn(`SDD pre-push: doctor reported issues with exit code ${result.status}; push will continue.`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (result.signal) {
|
|
52
|
+
console.warn(`SDD pre-push: doctor stopped by signal ${result.signal}; push will continue.`);
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
main();
|
|
@@ -19,16 +19,38 @@ function parseInput(raw) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function hasTelemetryCli(dir) {
|
|
23
|
+
return fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.cjs')) ||
|
|
24
|
+
fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.js'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findTelemetryRoot(startDir) {
|
|
28
|
+
if (!startDir) return '';
|
|
29
|
+
|
|
30
|
+
let current = path.resolve(startDir);
|
|
31
|
+
while (true) {
|
|
32
|
+
if (hasTelemetryCli(current)) return current;
|
|
33
|
+
const parent = path.dirname(current);
|
|
34
|
+
if (parent === current) return '';
|
|
35
|
+
current = parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
22
39
|
function findProjectRoot(input) {
|
|
23
40
|
const toolInput = input.tool_input || input.toolInput || {};
|
|
24
41
|
const candidates = [
|
|
25
42
|
toolInput.cwd,
|
|
26
43
|
input.cwd,
|
|
27
44
|
input.project_root,
|
|
45
|
+
process.env.CLAUDE_PROJECT_DIR,
|
|
28
46
|
process.env.PWD,
|
|
29
47
|
process.cwd(),
|
|
30
48
|
].filter(Boolean);
|
|
31
|
-
|
|
49
|
+
for (const dir of candidates) {
|
|
50
|
+
const root = findTelemetryRoot(dir);
|
|
51
|
+
if (root) return root;
|
|
52
|
+
}
|
|
53
|
+
return process.cwd();
|
|
32
54
|
}
|
|
33
55
|
|
|
34
56
|
function latestActiveStage(projectRoot) {
|
|
@@ -75,7 +97,11 @@ function inferRecord(command) {
|
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
function recordTelemetry(projectRoot, activeStage, record, result) {
|
|
78
|
-
const logPath = path.join(projectRoot, 'skywalk-sdd', 'log.
|
|
100
|
+
const logPath = path.join(projectRoot, 'skywalk-sdd', 'log.cjs');
|
|
101
|
+
const legacyLogPath = path.join(projectRoot, 'skywalk-sdd', 'log.js');
|
|
102
|
+
const logCli = fs.existsSync(logPath) ? logPath : legacyLogPath;
|
|
103
|
+
if (!fs.existsSync(logCli)) return;
|
|
104
|
+
|
|
79
105
|
const details = { [record.detailsKey]: { ...record.details } };
|
|
80
106
|
if (record.type === 'build_result') {
|
|
81
107
|
details.build_results.success = result === 'success';
|
|
@@ -83,7 +109,7 @@ function recordTelemetry(projectRoot, activeStage, record, result) {
|
|
|
83
109
|
}
|
|
84
110
|
|
|
85
111
|
const args = [
|
|
86
|
-
|
|
112
|
+
logCli,
|
|
87
113
|
'record',
|
|
88
114
|
`--type=${record.type}`,
|
|
89
115
|
`--command=${activeStage.command || activeStage.stage || 'unknown'}`,
|
|
@@ -18,14 +18,36 @@ function parseInput(raw) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function hasTelemetryCli(dir) {
|
|
22
|
+
return fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.cjs')) ||
|
|
23
|
+
fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.js'));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function findTelemetryRoot(startDir) {
|
|
27
|
+
if (!startDir) return '';
|
|
28
|
+
|
|
29
|
+
let current = path.resolve(startDir);
|
|
30
|
+
while (true) {
|
|
31
|
+
if (hasTelemetryCli(current)) return current;
|
|
32
|
+
const parent = path.dirname(current);
|
|
33
|
+
if (parent === current) return '';
|
|
34
|
+
current = parent;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
function findProjectRoot(input) {
|
|
22
39
|
const candidates = [
|
|
23
40
|
input.cwd,
|
|
24
41
|
input.project_root,
|
|
42
|
+
process.env.CLAUDE_PROJECT_DIR,
|
|
25
43
|
process.env.PWD,
|
|
26
44
|
process.cwd(),
|
|
27
45
|
].filter(Boolean);
|
|
28
|
-
|
|
46
|
+
for (const dir of candidates) {
|
|
47
|
+
const root = findTelemetryRoot(dir);
|
|
48
|
+
if (root) return root;
|
|
49
|
+
}
|
|
50
|
+
return process.cwd();
|
|
29
51
|
}
|
|
30
52
|
|
|
31
53
|
function readActiveStages(projectRoot) {
|
|
@@ -19,14 +19,36 @@ function parseInput(raw) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function hasTelemetryCli(dir) {
|
|
23
|
+
return fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.cjs')) ||
|
|
24
|
+
fs.existsSync(path.join(dir, 'skywalk-sdd', 'log.js'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findTelemetryRoot(startDir) {
|
|
28
|
+
if (!startDir) return '';
|
|
29
|
+
|
|
30
|
+
let current = path.resolve(startDir);
|
|
31
|
+
while (true) {
|
|
32
|
+
if (hasTelemetryCli(current)) return current;
|
|
33
|
+
const parent = path.dirname(current);
|
|
34
|
+
if (parent === current) return '';
|
|
35
|
+
current = parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
22
39
|
function findProjectRoot(input) {
|
|
23
40
|
const candidates = [
|
|
24
41
|
input.cwd,
|
|
25
42
|
input.project_root,
|
|
43
|
+
process.env.CLAUDE_PROJECT_DIR,
|
|
26
44
|
process.env.PWD,
|
|
27
45
|
process.cwd(),
|
|
28
46
|
].filter(Boolean);
|
|
29
|
-
|
|
47
|
+
for (const dir of candidates) {
|
|
48
|
+
const root = findTelemetryRoot(dir);
|
|
49
|
+
if (root) return root;
|
|
50
|
+
}
|
|
51
|
+
return process.cwd();
|
|
30
52
|
}
|
|
31
53
|
|
|
32
54
|
function readActiveStages(projectRoot) {
|
|
@@ -45,9 +67,13 @@ function readActiveStages(projectRoot) {
|
|
|
45
67
|
}
|
|
46
68
|
|
|
47
69
|
function writeWarning(projectRoot, event) {
|
|
48
|
-
const logPath = path.join(projectRoot, 'skywalk-sdd', 'log.
|
|
70
|
+
const logPath = path.join(projectRoot, 'skywalk-sdd', 'log.cjs');
|
|
71
|
+
const legacyLogPath = path.join(projectRoot, 'skywalk-sdd', 'log.js');
|
|
72
|
+
const logCli = fs.existsSync(logPath) ? logPath : legacyLogPath;
|
|
73
|
+
if (!fs.existsSync(logCli)) return;
|
|
74
|
+
|
|
49
75
|
const args = [
|
|
50
|
-
|
|
76
|
+
logCli,
|
|
51
77
|
'record',
|
|
52
78
|
'--type=telemetry_warning',
|
|
53
79
|
`--command=${event.command || event.stage || 'unknown'}`,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "node
|
|
8
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/sdd-prompt.cjs\""
|
|
9
9
|
}
|
|
10
10
|
]
|
|
11
11
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "node
|
|
19
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/sdd-pre-tool.cjs\""
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "node
|
|
30
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/sdd-post-tool.cjs\""
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"hooks": [
|
|
38
38
|
{
|
|
39
39
|
"type": "command",
|
|
40
|
-
"command": "node
|
|
40
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/hooks/sdd-stop.cjs\""
|
|
41
41
|
}
|
|
42
42
|
]
|
|
43
43
|
}
|