olympus-ai 3.2.2 → 3.3.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 (158) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/__tests__/ascent-checkpoint.test.d.ts +2 -0
  3. package/dist/__tests__/ascent-checkpoint.test.d.ts.map +1 -0
  4. package/dist/__tests__/ascent-checkpoint.test.js +261 -0
  5. package/dist/__tests__/ascent-checkpoint.test.js.map +1 -0
  6. package/dist/__tests__/config-ascent.test.d.ts +2 -0
  7. package/dist/__tests__/config-ascent.test.d.ts.map +1 -0
  8. package/dist/__tests__/config-ascent.test.js +134 -0
  9. package/dist/__tests__/config-ascent.test.js.map +1 -0
  10. package/dist/__tests__/hook-blocking.test.d.ts +8 -0
  11. package/dist/__tests__/hook-blocking.test.d.ts.map +1 -0
  12. package/dist/__tests__/hook-blocking.test.js +277 -0
  13. package/dist/__tests__/hook-blocking.test.js.map +1 -0
  14. package/dist/__tests__/installer.test.js +1 -1
  15. package/dist/__tests__/metrics-cli.test.d.ts +5 -0
  16. package/dist/__tests__/metrics-cli.test.d.ts.map +1 -0
  17. package/dist/__tests__/metrics-cli.test.js +24 -0
  18. package/dist/__tests__/metrics-cli.test.js.map +1 -0
  19. package/dist/__tests__/skill-auto-detection.test.d.ts +2 -0
  20. package/dist/__tests__/skill-auto-detection.test.d.ts.map +1 -0
  21. package/dist/__tests__/skill-auto-detection.test.js +255 -0
  22. package/dist/__tests__/skill-auto-detection.test.js.map +1 -0
  23. package/dist/__tests__/token-estimator.test.d.ts +5 -0
  24. package/dist/__tests__/token-estimator.test.d.ts.map +1 -0
  25. package/dist/__tests__/token-estimator.test.js +192 -0
  26. package/dist/__tests__/token-estimator.test.js.map +1 -0
  27. package/dist/agents/definitions.d.ts.map +1 -1
  28. package/dist/agents/definitions.js +83 -1
  29. package/dist/agents/definitions.js.map +1 -1
  30. package/dist/agents/document-writer.d.ts.map +1 -1
  31. package/dist/agents/document-writer.js +38 -0
  32. package/dist/agents/document-writer.js.map +1 -1
  33. package/dist/agents/frontend-engineer.d.ts.map +1 -1
  34. package/dist/agents/frontend-engineer.js +16 -0
  35. package/dist/agents/frontend-engineer.js.map +1 -1
  36. package/dist/agents/olympian.d.ts.map +1 -1
  37. package/dist/agents/olympian.js +15 -0
  38. package/dist/agents/olympian.js.map +1 -1
  39. package/dist/cli/commands/metrics.d.ts +31 -0
  40. package/dist/cli/commands/metrics.d.ts.map +1 -0
  41. package/dist/cli/commands/metrics.js +266 -0
  42. package/dist/cli/commands/metrics.js.map +1 -0
  43. package/dist/cli/index.js +39 -0
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/config/loader.d.ts.map +1 -1
  46. package/dist/config/loader.js +16 -0
  47. package/dist/config/loader.js.map +1 -1
  48. package/dist/features/ascent-checkpoint/index.d.ts +48 -0
  49. package/dist/features/ascent-checkpoint/index.d.ts.map +1 -0
  50. package/dist/features/ascent-checkpoint/index.js +144 -0
  51. package/dist/features/ascent-checkpoint/index.js.map +1 -0
  52. package/dist/features/hook-logging/index.d.ts +37 -0
  53. package/dist/features/hook-logging/index.d.ts.map +1 -0
  54. package/dist/features/hook-logging/index.js +120 -0
  55. package/dist/features/hook-logging/index.js.map +1 -0
  56. package/dist/features/hook-logging/index.test.d.ts +5 -0
  57. package/dist/features/hook-logging/index.test.d.ts.map +1 -0
  58. package/dist/features/hook-logging/index.test.js +268 -0
  59. package/dist/features/hook-logging/index.test.js.map +1 -0
  60. package/dist/features/index.d.ts +3 -0
  61. package/dist/features/index.d.ts.map +1 -1
  62. package/dist/features/index.js +8 -0
  63. package/dist/features/index.js.map +1 -1
  64. package/dist/features/magic-keywords.d.ts +51 -0
  65. package/dist/features/magic-keywords.d.ts.map +1 -1
  66. package/dist/features/magic-keywords.js +172 -0
  67. package/dist/features/magic-keywords.js.map +1 -1
  68. package/dist/features/session-state/index.d.ts +50 -0
  69. package/dist/features/session-state/index.d.ts.map +1 -0
  70. package/dist/features/session-state/index.js +64 -0
  71. package/dist/features/session-state/index.js.map +1 -0
  72. package/dist/features/session-state/index.test.d.ts +5 -0
  73. package/dist/features/session-state/index.test.d.ts.map +1 -0
  74. package/dist/features/session-state/index.test.js +221 -0
  75. package/dist/features/session-state/index.test.js.map +1 -0
  76. package/dist/features/token-metrics/index.d.ts +6 -0
  77. package/dist/features/token-metrics/index.d.ts.map +1 -0
  78. package/dist/features/token-metrics/index.js +5 -0
  79. package/dist/features/token-metrics/index.js.map +1 -0
  80. package/dist/features/token-metrics/storage.d.ts +16 -0
  81. package/dist/features/token-metrics/storage.d.ts.map +1 -0
  82. package/dist/features/token-metrics/storage.js +144 -0
  83. package/dist/features/token-metrics/storage.js.map +1 -0
  84. package/dist/features/token-metrics/token-estimator.d.ts +66 -0
  85. package/dist/features/token-metrics/token-estimator.d.ts.map +1 -0
  86. package/dist/features/token-metrics/token-estimator.js +230 -0
  87. package/dist/features/token-metrics/token-estimator.js.map +1 -0
  88. package/dist/features/token-metrics/types.d.ts +63 -0
  89. package/dist/features/token-metrics/types.d.ts.map +1 -0
  90. package/dist/features/token-metrics/types.js +5 -0
  91. package/dist/features/token-metrics/types.js.map +1 -0
  92. package/dist/hooks/olympus-orchestrator/constants.d.ts +2 -0
  93. package/dist/hooks/olympus-orchestrator/constants.d.ts.map +1 -1
  94. package/dist/hooks/olympus-orchestrator/constants.js +41 -0
  95. package/dist/hooks/olympus-orchestrator/constants.js.map +1 -1
  96. package/dist/hooks/olympus-orchestrator/index.d.ts +10 -1
  97. package/dist/hooks/olympus-orchestrator/index.d.ts.map +1 -1
  98. package/dist/hooks/olympus-orchestrator/index.js +108 -14
  99. package/dist/hooks/olympus-orchestrator/index.js.map +1 -1
  100. package/dist/hooks/registrations/index.d.ts +2 -1
  101. package/dist/hooks/registrations/index.d.ts.map +1 -1
  102. package/dist/hooks/registrations/index.js +3 -1
  103. package/dist/hooks/registrations/index.js.map +1 -1
  104. package/dist/hooks/registrations/token-metrics.d.ts +11 -0
  105. package/dist/hooks/registrations/token-metrics.d.ts.map +1 -0
  106. package/dist/hooks/registrations/token-metrics.js +119 -0
  107. package/dist/hooks/registrations/token-metrics.js.map +1 -0
  108. package/dist/installer/index.d.ts +1 -1
  109. package/dist/installer/index.d.ts.map +1 -1
  110. package/dist/installer/index.js +334 -9
  111. package/dist/installer/index.js.map +1 -1
  112. package/dist/shared/types.d.ts +16 -0
  113. package/dist/shared/types.d.ts.map +1 -1
  114. package/package.json +3 -3
  115. package/scripts/.olympus/token-metrics.jsonl +1 -0
  116. package/scripts/dist/hooks/olympus-hooks.cjs +127 -128
  117. package/scripts/esbuild.hooks.mjs +1 -1
  118. package/.claude/.olympus-version.json +0 -6
  119. package/.claude/CLAUDE.md +0 -339
  120. package/.claude/agents/document-writer.md +0 -152
  121. package/.claude/agents/explore-medium.md +0 -25
  122. package/.claude/agents/explore.md +0 -86
  123. package/.claude/agents/frontend-engineer-high.md +0 -17
  124. package/.claude/agents/frontend-engineer-low.md +0 -17
  125. package/.claude/agents/frontend-engineer.md +0 -80
  126. package/.claude/agents/librarian-low.md +0 -22
  127. package/.claude/agents/librarian.md +0 -70
  128. package/.claude/agents/metis.md +0 -85
  129. package/.claude/agents/momus.md +0 -97
  130. package/.claude/agents/multimodal-looker.md +0 -39
  131. package/.claude/agents/olympian-high.md +0 -32
  132. package/.claude/agents/olympian-low.md +0 -22
  133. package/.claude/agents/olympian.md +0 -78
  134. package/.claude/agents/oracle-low.md +0 -23
  135. package/.claude/agents/oracle-medium.md +0 -28
  136. package/.claude/agents/oracle.md +0 -77
  137. package/.claude/agents/prometheus.md +0 -125
  138. package/.claude/agents/qa-tester.md +0 -220
  139. package/.claude/commands/analyze/skill.md +0 -14
  140. package/.claude/commands/ascent/skill.md +0 -152
  141. package/.claude/commands/cancel-ascent.md +0 -9
  142. package/.claude/commands/complete-plan.md +0 -101
  143. package/.claude/commands/deepsearch/skill.md +0 -15
  144. package/.claude/commands/olympus/skill.md +0 -82
  145. package/.claude/commands/olympus-default.md +0 -26
  146. package/.claude/commands/plan.md +0 -71
  147. package/.claude/commands/prometheus/skill.md +0 -38
  148. package/.claude/commands/review/skill.md +0 -34
  149. package/.claude/commands/ultrawork/skill.md +0 -90
  150. package/.claude/commands/update.md +0 -38
  151. package/scripts/generate-logo-hybrid-v2.mjs +0 -213
  152. package/scripts/generate-logo-hybrid.mjs +0 -209
  153. package/scripts/generate-logo-infinity.mjs +0 -239
  154. package/scripts/generate-logo-mythology.mjs +0 -190
  155. package/scripts/generate-logo-orchestration.mjs +0 -228
  156. package/scripts/generate-logo-recraft.mjs +0 -147
  157. package/scripts/generate-logo-simple.mjs +0 -154
  158. package/scripts/generate-logo.mjs +0 -117
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Ascent Checkpoint System
3
+ *
4
+ * Manages checkpoints for ascent tasks to enable safe resumption after max iterations.
5
+ */
6
+ import type { AscentCheckpoint } from '../../shared/types.js';
7
+ export type { AscentCheckpoint } from '../../shared/types.js';
8
+ /**
9
+ * Get the checkpoints directory path
10
+ * @param testDir Optional test directory override for testing
11
+ */
12
+ export declare function getCheckpointsDir(testDir?: string): string;
13
+ /**
14
+ * Generate a hash of plan content for drift detection
15
+ */
16
+ export declare function hashPlanContent(planContent: string): string;
17
+ /**
18
+ * Get current git SHA
19
+ */
20
+ export declare function getGitSha(): string;
21
+ /**
22
+ * Save a checkpoint for an ascent task
23
+ * @param planName Name of the plan
24
+ * @param state Checkpoint state
25
+ * @param testDir Optional test directory override for testing
26
+ */
27
+ export declare function saveCheckpoint(planName: string, state: Omit<AscentCheckpoint, 'planName' | 'timestamp'>, testDir?: string): void;
28
+ /**
29
+ * Load the most recent checkpoint for a plan
30
+ * @param planName Name of the plan
31
+ * @param testDir Optional test directory override for testing
32
+ */
33
+ export declare function loadCheckpoint(planName: string, testDir?: string): AscentCheckpoint | null;
34
+ /**
35
+ * List all checkpoint files for a plan, sorted by most recent first
36
+ * @param planName Name of the plan
37
+ * @param testDir Optional test directory override for testing
38
+ */
39
+ export declare function listCheckpoints(planName: string, testDir?: string): string[];
40
+ /**
41
+ * Validate a checkpoint for resumption
42
+ * Returns warnings if git SHA or plan hash has changed
43
+ */
44
+ export declare function validateCheckpoint(checkpoint: AscentCheckpoint, currentGitSha: string, currentPlanHash: string): {
45
+ valid: boolean;
46
+ warnings: string[];
47
+ };
48
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/ascent-checkpoint/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,CASlC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,WAAW,CAAC,EACvD,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAcN;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAwB1F;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAuB5E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,gBAAgB,EAC5B,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACtB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAyBxC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Ascent Checkpoint System
3
+ *
4
+ * Manages checkpoints for ascent tasks to enable safe resumption after max iterations.
5
+ */
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { createHash } from 'crypto';
9
+ /**
10
+ * Get the checkpoints directory path
11
+ * @param testDir Optional test directory override for testing
12
+ */
13
+ export function getCheckpointsDir(testDir) {
14
+ if (testDir) {
15
+ return testDir;
16
+ }
17
+ const cwd = process.cwd();
18
+ return join(cwd, '.olympus', 'checkpoints');
19
+ }
20
+ /**
21
+ * Ensure checkpoints directory exists
22
+ * @param testDir Optional test directory override for testing
23
+ */
24
+ function ensureCheckpointsDir(testDir) {
25
+ const dir = getCheckpointsDir(testDir);
26
+ if (!existsSync(dir)) {
27
+ mkdirSync(dir, { recursive: true });
28
+ }
29
+ }
30
+ /**
31
+ * Generate a hash of plan content for drift detection
32
+ */
33
+ export function hashPlanContent(planContent) {
34
+ return createHash('sha256').update(planContent).digest('hex').substring(0, 16);
35
+ }
36
+ /**
37
+ * Get current git SHA
38
+ */
39
+ export function getGitSha() {
40
+ try {
41
+ const { execSync } = require('child_process');
42
+ const sha = execSync('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
43
+ return sha;
44
+ }
45
+ catch (error) {
46
+ console.warn('Warning: Could not get git SHA:', error);
47
+ return 'unknown';
48
+ }
49
+ }
50
+ /**
51
+ * Save a checkpoint for an ascent task
52
+ * @param planName Name of the plan
53
+ * @param state Checkpoint state
54
+ * @param testDir Optional test directory override for testing
55
+ */
56
+ export function saveCheckpoint(planName, state, testDir) {
57
+ ensureCheckpointsDir(testDir);
58
+ const checkpoint = {
59
+ planName,
60
+ timestamp: new Date().toISOString(),
61
+ ...state
62
+ };
63
+ const filename = `${planName}-${Date.now()}.json`;
64
+ const filepath = join(getCheckpointsDir(testDir), filename);
65
+ writeFileSync(filepath, JSON.stringify(checkpoint, null, 2), 'utf-8');
66
+ console.log(`Checkpoint saved: ${filepath}`);
67
+ }
68
+ /**
69
+ * Load the most recent checkpoint for a plan
70
+ * @param planName Name of the plan
71
+ * @param testDir Optional test directory override for testing
72
+ */
73
+ export function loadCheckpoint(planName, testDir) {
74
+ const dir = getCheckpointsDir(testDir);
75
+ if (!existsSync(dir)) {
76
+ return null;
77
+ }
78
+ const checkpoints = listCheckpoints(planName, testDir);
79
+ if (checkpoints.length === 0) {
80
+ return null;
81
+ }
82
+ // Most recent is first in sorted list
83
+ const latestFile = checkpoints[0];
84
+ const filepath = join(dir, latestFile);
85
+ try {
86
+ const content = readFileSync(filepath, 'utf-8');
87
+ return JSON.parse(content);
88
+ }
89
+ catch (error) {
90
+ console.error(`Error loading checkpoint ${latestFile}:`, error);
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * List all checkpoint files for a plan, sorted by most recent first
96
+ * @param planName Name of the plan
97
+ * @param testDir Optional test directory override for testing
98
+ */
99
+ export function listCheckpoints(planName, testDir) {
100
+ const dir = getCheckpointsDir(testDir);
101
+ if (!existsSync(dir)) {
102
+ return [];
103
+ }
104
+ try {
105
+ const files = readdirSync(dir);
106
+ const checkpointFiles = files
107
+ .filter(f => f.startsWith(`${planName}-`) && f.endsWith('.json'))
108
+ .sort((a, b) => {
109
+ // Extract timestamps from filenames
110
+ const tsA = parseInt(a.split('-').pop()?.replace('.json', '') || '0');
111
+ const tsB = parseInt(b.split('-').pop()?.replace('.json', '') || '0');
112
+ return tsB - tsA; // Most recent first
113
+ });
114
+ return checkpointFiles;
115
+ }
116
+ catch (error) {
117
+ console.error('Error listing checkpoints:', error);
118
+ return [];
119
+ }
120
+ }
121
+ /**
122
+ * Validate a checkpoint for resumption
123
+ * Returns warnings if git SHA or plan hash has changed
124
+ */
125
+ export function validateCheckpoint(checkpoint, currentGitSha, currentPlanHash) {
126
+ const warnings = [];
127
+ if (checkpoint.gitSha !== currentGitSha && checkpoint.gitSha !== 'unknown') {
128
+ warnings.push(`WARNING: Git SHA has changed since checkpoint.\n` +
129
+ `Checkpoint SHA: ${checkpoint.gitSha}\n` +
130
+ `Current SHA: ${currentGitSha}\n` +
131
+ `Code changes may have occurred.`);
132
+ }
133
+ if (checkpoint.planHash !== currentPlanHash) {
134
+ warnings.push(`WARNING: Plan has been modified since checkpoint.\n` +
135
+ `Checkpoint hash: ${checkpoint.planHash}\n` +
136
+ `Current hash: ${currentPlanHash}\n` +
137
+ `Plan drift detected - review changes before resuming.`);
138
+ }
139
+ return {
140
+ valid: true,
141
+ warnings
142
+ };
143
+ }
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/features/ascent-checkpoint/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Hook Violation Logging
3
+ *
4
+ * Logs all hook violations (blocked and allowed) for debugging and analysis.
5
+ * Violations are appended to .olympus/logs/hook-violations.jsonl
6
+ */
7
+ export interface HookViolation {
8
+ timestamp: string;
9
+ filePath: string;
10
+ toolName: string;
11
+ linesChanged?: number;
12
+ wasBlocked: boolean;
13
+ reason: string;
14
+ }
15
+ /**
16
+ * Log a hook violation to .olympus/logs/hook-violations.jsonl
17
+ */
18
+ export declare function logViolation(violation: HookViolation, workDir?: string): void;
19
+ /**
20
+ * Get violation statistics from the log
21
+ */
22
+ export declare function getViolationStats(workDir?: string): {
23
+ total: number;
24
+ byFile: Record<string, number>;
25
+ byTool: Record<string, number>;
26
+ blocked: number;
27
+ allowed: number;
28
+ };
29
+ /**
30
+ * Read all violations from the log
31
+ */
32
+ export declare function readViolations(workDir?: string): HookViolation[];
33
+ /**
34
+ * Clear the violations log (for testing)
35
+ */
36
+ export declare function clearViolations(workDir?: string): void;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/hook-logging/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAkB7E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CA+CA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CA0BhE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAYtD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Hook Violation Logging
3
+ *
4
+ * Logs all hook violations (blocked and allowed) for debugging and analysis.
5
+ * Violations are appended to .olympus/logs/hook-violations.jsonl
6
+ */
7
+ import { mkdirSync, appendFileSync, readFileSync, existsSync } from 'fs';
8
+ import { join } from 'path';
9
+ /**
10
+ * Log a hook violation to .olympus/logs/hook-violations.jsonl
11
+ */
12
+ export function logViolation(violation, workDir) {
13
+ const baseDir = workDir || process.cwd();
14
+ const logDir = join(baseDir, '.olympus', 'logs');
15
+ const logPath = join(logDir, 'hook-violations.jsonl');
16
+ try {
17
+ // Create directory if needed
18
+ if (!existsSync(logDir)) {
19
+ mkdirSync(logDir, { recursive: true });
20
+ }
21
+ // Append violation as JSON line
22
+ const line = JSON.stringify(violation) + '\n';
23
+ appendFileSync(logPath, line, 'utf-8');
24
+ }
25
+ catch (error) {
26
+ // Silently fail - don't block hook execution due to logging errors
27
+ console.error('[Hook Logging] Failed to log violation:', error);
28
+ }
29
+ }
30
+ /**
31
+ * Get violation statistics from the log
32
+ */
33
+ export function getViolationStats(workDir) {
34
+ const baseDir = workDir || process.cwd();
35
+ const logPath = join(baseDir, '.olympus', 'logs', 'hook-violations.jsonl');
36
+ const stats = {
37
+ total: 0,
38
+ byFile: {},
39
+ byTool: {},
40
+ blocked: 0,
41
+ allowed: 0,
42
+ };
43
+ try {
44
+ if (!existsSync(logPath)) {
45
+ return stats;
46
+ }
47
+ const content = readFileSync(logPath, 'utf-8');
48
+ const lines = content.trim().split('\n').filter(Boolean);
49
+ for (const line of lines) {
50
+ try {
51
+ const violation = JSON.parse(line);
52
+ stats.total++;
53
+ // Count by file
54
+ stats.byFile[violation.filePath] = (stats.byFile[violation.filePath] || 0) + 1;
55
+ // Count by tool
56
+ stats.byTool[violation.toolName] = (stats.byTool[violation.toolName] || 0) + 1;
57
+ // Count blocked vs allowed
58
+ if (violation.wasBlocked) {
59
+ stats.blocked++;
60
+ }
61
+ else {
62
+ stats.allowed++;
63
+ }
64
+ }
65
+ catch {
66
+ // Skip malformed lines
67
+ continue;
68
+ }
69
+ }
70
+ return stats;
71
+ }
72
+ catch {
73
+ return stats;
74
+ }
75
+ }
76
+ /**
77
+ * Read all violations from the log
78
+ */
79
+ export function readViolations(workDir) {
80
+ const baseDir = workDir || process.cwd();
81
+ const logPath = join(baseDir, '.olympus', 'logs', 'hook-violations.jsonl');
82
+ try {
83
+ if (!existsSync(logPath)) {
84
+ return [];
85
+ }
86
+ const content = readFileSync(logPath, 'utf-8');
87
+ const lines = content.trim().split('\n').filter(Boolean);
88
+ const violations = [];
89
+ for (const line of lines) {
90
+ try {
91
+ violations.push(JSON.parse(line));
92
+ }
93
+ catch {
94
+ // Skip malformed lines
95
+ continue;
96
+ }
97
+ }
98
+ return violations;
99
+ }
100
+ catch {
101
+ return [];
102
+ }
103
+ }
104
+ /**
105
+ * Clear the violations log (for testing)
106
+ */
107
+ export function clearViolations(workDir) {
108
+ const baseDir = workDir || process.cwd();
109
+ const logPath = join(baseDir, '.olympus', 'logs', 'hook-violations.jsonl');
110
+ try {
111
+ if (existsSync(logPath)) {
112
+ const { unlinkSync } = require('fs');
113
+ unlinkSync(logPath);
114
+ }
115
+ }
116
+ catch {
117
+ // Silently fail
118
+ }
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/features/hook-logging/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for Hook Violation Logging
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/features/hook-logging/index.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Tests for Hook Violation Logging
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { mkdirSync, rmSync, existsSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { tmpdir } from 'os';
8
+ import { logViolation, getViolationStats, readViolations, } from './index.js';
9
+ describe('Hook Logging', () => {
10
+ let testDir;
11
+ beforeEach(() => {
12
+ // Create unique test directory
13
+ testDir = join(tmpdir(), `olympus-test-${Date.now()}`);
14
+ mkdirSync(testDir, { recursive: true });
15
+ });
16
+ afterEach(() => {
17
+ // Clean up test directory
18
+ if (existsSync(testDir)) {
19
+ rmSync(testDir, { recursive: true, force: true });
20
+ }
21
+ });
22
+ describe('logViolation', () => {
23
+ it('should create log directory if it does not exist', () => {
24
+ const violation = {
25
+ timestamp: new Date().toISOString(),
26
+ filePath: 'src/index.ts',
27
+ toolName: 'Edit',
28
+ wasBlocked: true,
29
+ reason: 'Test violation',
30
+ };
31
+ logViolation(violation, testDir);
32
+ const logDir = join(testDir, '.olympus', 'logs');
33
+ expect(existsSync(logDir)).toBe(true);
34
+ });
35
+ it('should append violation to log file', () => {
36
+ const violation = {
37
+ timestamp: new Date().toISOString(),
38
+ filePath: 'src/index.ts',
39
+ toolName: 'Edit',
40
+ wasBlocked: true,
41
+ reason: 'Test violation',
42
+ };
43
+ logViolation(violation, testDir);
44
+ const violations = readViolations(testDir);
45
+ expect(violations).toHaveLength(1);
46
+ expect(violations[0]).toEqual(violation);
47
+ });
48
+ it('should append multiple violations', () => {
49
+ const violation1 = {
50
+ timestamp: new Date().toISOString(),
51
+ filePath: 'src/index.ts',
52
+ toolName: 'Edit',
53
+ wasBlocked: true,
54
+ reason: 'Violation 1',
55
+ };
56
+ const violation2 = {
57
+ timestamp: new Date().toISOString(),
58
+ filePath: 'src/utils.ts',
59
+ toolName: 'Write',
60
+ wasBlocked: false,
61
+ reason: 'Violation 2',
62
+ };
63
+ logViolation(violation1, testDir);
64
+ logViolation(violation2, testDir);
65
+ const violations = readViolations(testDir);
66
+ expect(violations).toHaveLength(2);
67
+ expect(violations[0]).toEqual(violation1);
68
+ expect(violations[1]).toEqual(violation2);
69
+ });
70
+ it('should handle violations with linesChanged', () => {
71
+ const violation = {
72
+ timestamp: new Date().toISOString(),
73
+ filePath: 'src/index.ts',
74
+ toolName: 'Edit',
75
+ linesChanged: 25,
76
+ wasBlocked: true,
77
+ reason: 'Large edit',
78
+ };
79
+ logViolation(violation, testDir);
80
+ const violations = readViolations(testDir);
81
+ expect(violations[0].linesChanged).toBe(25);
82
+ });
83
+ });
84
+ describe('getViolationStats', () => {
85
+ it('should return empty stats when no violations', () => {
86
+ const stats = getViolationStats(testDir);
87
+ expect(stats.total).toBe(0);
88
+ expect(stats.blocked).toBe(0);
89
+ expect(stats.allowed).toBe(0);
90
+ expect(stats.byFile).toEqual({});
91
+ expect(stats.byTool).toEqual({});
92
+ });
93
+ it('should count total violations', () => {
94
+ logViolation({
95
+ timestamp: new Date().toISOString(),
96
+ filePath: 'file1.ts',
97
+ toolName: 'Edit',
98
+ wasBlocked: true,
99
+ reason: 'Test',
100
+ }, testDir);
101
+ logViolation({
102
+ timestamp: new Date().toISOString(),
103
+ filePath: 'file2.ts',
104
+ toolName: 'Write',
105
+ wasBlocked: false,
106
+ reason: 'Test',
107
+ }, testDir);
108
+ const stats = getViolationStats(testDir);
109
+ expect(stats.total).toBe(2);
110
+ });
111
+ it('should count violations by file', () => {
112
+ logViolation({
113
+ timestamp: new Date().toISOString(),
114
+ filePath: 'file1.ts',
115
+ toolName: 'Edit',
116
+ wasBlocked: true,
117
+ reason: 'Test',
118
+ }, testDir);
119
+ logViolation({
120
+ timestamp: new Date().toISOString(),
121
+ filePath: 'file1.ts',
122
+ toolName: 'Edit',
123
+ wasBlocked: true,
124
+ reason: 'Test',
125
+ }, testDir);
126
+ logViolation({
127
+ timestamp: new Date().toISOString(),
128
+ filePath: 'file2.ts',
129
+ toolName: 'Write',
130
+ wasBlocked: false,
131
+ reason: 'Test',
132
+ }, testDir);
133
+ const stats = getViolationStats(testDir);
134
+ expect(stats.byFile['file1.ts']).toBe(2);
135
+ expect(stats.byFile['file2.ts']).toBe(1);
136
+ });
137
+ it('should count violations by tool', () => {
138
+ logViolation({
139
+ timestamp: new Date().toISOString(),
140
+ filePath: 'file1.ts',
141
+ toolName: 'Edit',
142
+ wasBlocked: true,
143
+ reason: 'Test',
144
+ }, testDir);
145
+ logViolation({
146
+ timestamp: new Date().toISOString(),
147
+ filePath: 'file2.ts',
148
+ toolName: 'Edit',
149
+ wasBlocked: true,
150
+ reason: 'Test',
151
+ }, testDir);
152
+ logViolation({
153
+ timestamp: new Date().toISOString(),
154
+ filePath: 'file3.ts',
155
+ toolName: 'Write',
156
+ wasBlocked: false,
157
+ reason: 'Test',
158
+ }, testDir);
159
+ const stats = getViolationStats(testDir);
160
+ expect(stats.byTool['Edit']).toBe(2);
161
+ expect(stats.byTool['Write']).toBe(1);
162
+ });
163
+ it('should count blocked vs allowed violations', () => {
164
+ logViolation({
165
+ timestamp: new Date().toISOString(),
166
+ filePath: 'file1.ts',
167
+ toolName: 'Edit',
168
+ wasBlocked: true,
169
+ reason: 'Blocked',
170
+ }, testDir);
171
+ logViolation({
172
+ timestamp: new Date().toISOString(),
173
+ filePath: 'file2.ts',
174
+ toolName: 'Write',
175
+ wasBlocked: true,
176
+ reason: 'Blocked',
177
+ }, testDir);
178
+ logViolation({
179
+ timestamp: new Date().toISOString(),
180
+ filePath: 'file3.ts',
181
+ toolName: 'Edit',
182
+ wasBlocked: false,
183
+ reason: 'Allowed',
184
+ }, testDir);
185
+ const stats = getViolationStats(testDir);
186
+ expect(stats.blocked).toBe(2);
187
+ expect(stats.allowed).toBe(1);
188
+ });
189
+ it('should handle malformed log lines gracefully', () => {
190
+ const logPath = join(testDir, '.olympus', 'logs', 'hook-violations.jsonl');
191
+ mkdirSync(join(testDir, '.olympus', 'logs'), { recursive: true });
192
+ // Write valid and invalid lines
193
+ const fs = require('fs');
194
+ fs.writeFileSync(logPath, JSON.stringify({
195
+ timestamp: new Date().toISOString(),
196
+ filePath: 'file1.ts',
197
+ toolName: 'Edit',
198
+ wasBlocked: true,
199
+ reason: 'Valid',
200
+ }) +
201
+ '\n' +
202
+ 'invalid json line\n' +
203
+ JSON.stringify({
204
+ timestamp: new Date().toISOString(),
205
+ filePath: 'file2.ts',
206
+ toolName: 'Write',
207
+ wasBlocked: false,
208
+ reason: 'Valid',
209
+ }) +
210
+ '\n');
211
+ const stats = getViolationStats(testDir);
212
+ expect(stats.total).toBe(2); // Should skip invalid line
213
+ });
214
+ });
215
+ describe('readViolations', () => {
216
+ it('should return empty array when no log file exists', () => {
217
+ const violations = readViolations(testDir);
218
+ expect(violations).toEqual([]);
219
+ });
220
+ it('should read all violations from log', () => {
221
+ const violation1 = {
222
+ timestamp: new Date().toISOString(),
223
+ filePath: 'file1.ts',
224
+ toolName: 'Edit',
225
+ wasBlocked: true,
226
+ reason: 'Test 1',
227
+ };
228
+ const violation2 = {
229
+ timestamp: new Date().toISOString(),
230
+ filePath: 'file2.ts',
231
+ toolName: 'Write',
232
+ wasBlocked: false,
233
+ reason: 'Test 2',
234
+ };
235
+ logViolation(violation1, testDir);
236
+ logViolation(violation2, testDir);
237
+ const violations = readViolations(testDir);
238
+ expect(violations).toHaveLength(2);
239
+ expect(violations[0]).toEqual(violation1);
240
+ expect(violations[1]).toEqual(violation2);
241
+ });
242
+ it('should skip malformed lines', () => {
243
+ const logPath = join(testDir, '.olympus', 'logs', 'hook-violations.jsonl');
244
+ mkdirSync(join(testDir, '.olympus', 'logs'), { recursive: true });
245
+ const fs = require('fs');
246
+ fs.writeFileSync(logPath, JSON.stringify({
247
+ timestamp: new Date().toISOString(),
248
+ filePath: 'file1.ts',
249
+ toolName: 'Edit',
250
+ wasBlocked: true,
251
+ reason: 'Valid',
252
+ }) +
253
+ '\n' +
254
+ 'invalid\n' +
255
+ JSON.stringify({
256
+ timestamp: new Date().toISOString(),
257
+ filePath: 'file2.ts',
258
+ toolName: 'Write',
259
+ wasBlocked: false,
260
+ reason: 'Valid',
261
+ }) +
262
+ '\n');
263
+ const violations = readViolations(testDir);
264
+ expect(violations).toHaveLength(2);
265
+ });
266
+ });
267
+ });
268
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/features/hook-logging/index.test.ts"],"names":[],"mappings":"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"}