jun-claude-code 0.2.2 → 0.2.4
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.
|
@@ -335,6 +335,104 @@ function writeJson(filePath, data) {
|
|
|
335
335
|
const result = readJson(path.join(destDir, 'settings.json'));
|
|
336
336
|
(0, vitest_1.expect)(result.hooks.UserPromptSubmit[0].hooks[0].command).toBe('~/.claude/hooks/skill-forced.sh');
|
|
337
337
|
});
|
|
338
|
+
(0, vitest_1.it)('should not duplicate hooks when project=true and run 3 times (idempotency)', () => {
|
|
339
|
+
const sourceSettings = {
|
|
340
|
+
hooks: {
|
|
341
|
+
UserPromptSubmit: [
|
|
342
|
+
{
|
|
343
|
+
hooks: [
|
|
344
|
+
{ type: 'command', command: '~/.claude/hooks/skill-forced.sh' },
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
writeJson(path.join(sourceDir, 'settings.json'), sourceSettings);
|
|
351
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
352
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
353
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
354
|
+
const result = readJson(path.join(destDir, 'settings.json'));
|
|
355
|
+
(0, vitest_1.expect)(result.hooks.UserPromptSubmit).toHaveLength(1);
|
|
356
|
+
(0, vitest_1.expect)(result.hooks.UserPromptSubmit[0].hooks[0].command).toBe('.claude/hooks/skill-forced.sh');
|
|
357
|
+
});
|
|
358
|
+
(0, vitest_1.it)('should not duplicate hooks across multiple events in project mode', () => {
|
|
359
|
+
const sourceSettings = {
|
|
360
|
+
hooks: {
|
|
361
|
+
SubagentStart: [
|
|
362
|
+
{ hooks: [{ type: 'command', command: '~/.claude/hooks/subagent.sh' }] },
|
|
363
|
+
],
|
|
364
|
+
UserPromptSubmit: [
|
|
365
|
+
{ hooks: [{ type: 'command', command: '~/.claude/hooks/skill-forced.sh' }] },
|
|
366
|
+
],
|
|
367
|
+
PreToolUse: [
|
|
368
|
+
{
|
|
369
|
+
matcher: 'Bash',
|
|
370
|
+
hooks: [{ type: 'command', command: '~/.claude/hooks/blocker.sh' }],
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
};
|
|
375
|
+
writeJson(path.join(sourceDir, 'settings.json'), sourceSettings);
|
|
376
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
377
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
378
|
+
const result = readJson(path.join(destDir, 'settings.json'));
|
|
379
|
+
(0, vitest_1.expect)(result.hooks.SubagentStart).toHaveLength(1);
|
|
380
|
+
(0, vitest_1.expect)(result.hooks.UserPromptSubmit).toHaveLength(1);
|
|
381
|
+
(0, vitest_1.expect)(result.hooks.PreToolUse).toHaveLength(1);
|
|
382
|
+
});
|
|
383
|
+
(0, vitest_1.it)('should not duplicate matcher hooks in project mode on re-run', () => {
|
|
384
|
+
const sourceSettings = {
|
|
385
|
+
hooks: {
|
|
386
|
+
PreToolUse: [
|
|
387
|
+
{
|
|
388
|
+
matcher: 'Bash',
|
|
389
|
+
hooks: [{ type: 'command', command: '~/.claude/hooks/blocker.sh' }],
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
matcher: 'Write',
|
|
393
|
+
hooks: [{ type: 'command', command: '~/.claude/hooks/blocker.sh' }],
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
writeJson(path.join(sourceDir, 'settings.json'), sourceSettings);
|
|
399
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
400
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
401
|
+
const result = readJson(path.join(destDir, 'settings.json'));
|
|
402
|
+
(0, vitest_1.expect)(result.hooks.PreToolUse).toHaveLength(2);
|
|
403
|
+
(0, vitest_1.expect)(result.hooks.PreToolUse[0].matcher).toBe('Bash');
|
|
404
|
+
(0, vitest_1.expect)(result.hooks.PreToolUse[1].matcher).toBe('Write');
|
|
405
|
+
});
|
|
406
|
+
(0, vitest_1.it)('should dedup when dest has .claude/ paths and source has ~/.claude/ paths', () => {
|
|
407
|
+
const sourceSettings = {
|
|
408
|
+
hooks: {
|
|
409
|
+
UserPromptSubmit: [
|
|
410
|
+
{
|
|
411
|
+
hooks: [
|
|
412
|
+
{ type: 'command', command: '~/.claude/hooks/skill-forced.sh' },
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
writeJson(path.join(sourceDir, 'settings.json'), sourceSettings);
|
|
419
|
+
// Simulate dest from a previous project install (already converted)
|
|
420
|
+
const destSettings = {
|
|
421
|
+
hooks: {
|
|
422
|
+
UserPromptSubmit: [
|
|
423
|
+
{
|
|
424
|
+
hooks: [
|
|
425
|
+
{ type: 'command', command: '.claude/hooks/skill-forced.sh' },
|
|
426
|
+
],
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
writeJson(path.join(destDir, 'settings.json'), destSettings);
|
|
432
|
+
(0, copy_1.mergeSettingsJson)(sourceDir, destDir, { project: true });
|
|
433
|
+
const result = readJson(path.join(destDir, 'settings.json'));
|
|
434
|
+
(0, vitest_1.expect)(result.hooks.UserPromptSubmit).toHaveLength(1);
|
|
435
|
+
});
|
|
338
436
|
});
|
|
339
437
|
// ─── init-project.ts mergeSettingsJson (project) ───
|
|
340
438
|
(0, vitest_1.describe)('init-project.ts mergeSettingsJson', () => {
|
package/dist/copy.js
CHANGED
|
@@ -177,6 +177,10 @@ function mergeSettingsJson(sourceDir, destDir, options) {
|
|
|
177
177
|
destSettings = {};
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
+
// Convert ~/.claude/ → .claude/ paths in source BEFORE merge (for dedup key matching)
|
|
181
|
+
if (options?.project) {
|
|
182
|
+
sourceSettings = replaceClaudePaths(sourceSettings);
|
|
183
|
+
}
|
|
180
184
|
// Merge top-level keys (source fills in missing keys, dest's existing keys preserved)
|
|
181
185
|
for (const key of Object.keys(sourceSettings)) {
|
|
182
186
|
if (key === 'hooks' || key === 'statusLine') {
|
package/package.json
CHANGED
|
@@ -18,7 +18,8 @@ echo "✅ [Hook] Skill/Agent 평가 프로토콜 실행됨"
|
|
|
18
18
|
cat << 'EOF'
|
|
19
19
|
MANDATORY SKILL & AGENT EVALUATION PROTOCOL
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
BLOCKING REQUIREMENT: 응답 시작 시 아래 Skill/Agent 평가를 반드시 출력하세요.
|
|
22
|
+
평가 없이 작업을 시작하면 프로토콜 위반입니다.
|
|
22
23
|
|
|
23
24
|
<delegation_rules>
|
|
24
25
|
|
|
@@ -60,12 +61,12 @@ Main Agent의 Context Window는 제한적입니다.
|
|
|
60
61
|
|
|
61
62
|
## PART 1: SKILL 평가
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
- Skill 이름
|
|
65
|
-
- YES 또는 NO (이 요청에 해당 Skill이 필요한가?)
|
|
66
|
-
- 한 줄 이유
|
|
64
|
+
응답에 아래 형식으로 Skill 평가를 출력하세요:
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
- [Skill이름]: YES/NO - 이유
|
|
67
|
+
- 예: `Git: YES - 커밋 작업 필요`
|
|
68
|
+
|
|
69
|
+
YES인 Skill의 SKILL.md를 읽으세요.
|
|
69
70
|
|
|
70
71
|
---
|
|
71
72
|
|
|
@@ -180,13 +181,12 @@ cat << 'EOF'
|
|
|
180
181
|
|
|
181
182
|
## PART 2: AGENT 평가 (Context 절약 핵심)
|
|
182
183
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
응답에 아래 형식으로 Agent 평가를 출력하세요:
|
|
185
|
+
|
|
186
|
+
- [Agent이름]: YES/NO - 이유
|
|
187
|
+
- 예: `git-manager: YES - 커밋 작업 위임`
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
예: Task(subagent_type="task-planner", prompt="...")
|
|
189
|
+
YES인 Agent는 Task 도구로 호출하세요.
|
|
190
190
|
|
|
191
191
|
---
|
|
192
192
|
|
|
@@ -237,13 +237,11 @@ cat << 'EOF'
|
|
|
237
237
|
|
|
238
238
|
## PART 3: 구현
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
Skill/Agent 평가를 출력한 후에 구현을 시작하세요.
|
|
241
241
|
|
|
242
242
|
---
|
|
243
243
|
|
|
244
244
|
탐색은 Subagent 전담, 구현 후 검증(code-reviewer + qa-tester), 단순 작업은 직접 처리 가능
|
|
245
245
|
|
|
246
|
-
지금 바로 모든 사용 가능한 Skill과 Agent를 평가하세요.
|
|
247
|
-
|
|
248
246
|
</phase>
|
|
249
247
|
EOF
|