oh-my-claude-sisyphus 3.6.3 → 3.7.2

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 (163) hide show
  1. package/README.md +40 -1
  2. package/commands/hud.md +37 -5
  3. package/commands/omc-setup.md +105 -0
  4. package/dist/__tests__/delegation-enforcement-levels.test.d.ts +9 -0
  5. package/dist/__tests__/delegation-enforcement-levels.test.d.ts.map +1 -0
  6. package/dist/__tests__/delegation-enforcement-levels.test.js +550 -0
  7. package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -0
  8. package/dist/__tests__/hud/analytics-display.test.js +137 -1
  9. package/dist/__tests__/hud/analytics-display.test.js.map +1 -1
  10. package/dist/__tests__/hud-windows.test.d.ts +2 -0
  11. package/dist/__tests__/hud-windows.test.d.ts.map +1 -0
  12. package/dist/__tests__/hud-windows.test.js +91 -0
  13. package/dist/__tests__/hud-windows.test.js.map +1 -0
  14. package/dist/__tests__/installer.test.js +1 -1
  15. package/dist/__tests__/rate-limit-wait/daemon.test.d.ts +5 -0
  16. package/dist/__tests__/rate-limit-wait/daemon.test.d.ts.map +1 -0
  17. package/dist/__tests__/rate-limit-wait/daemon.test.js +313 -0
  18. package/dist/__tests__/rate-limit-wait/daemon.test.js.map +1 -0
  19. package/dist/__tests__/rate-limit-wait/integration.test.d.ts +8 -0
  20. package/dist/__tests__/rate-limit-wait/integration.test.d.ts.map +1 -0
  21. package/dist/__tests__/rate-limit-wait/integration.test.js +329 -0
  22. package/dist/__tests__/rate-limit-wait/integration.test.js.map +1 -0
  23. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.d.ts +5 -0
  24. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.d.ts.map +1 -0
  25. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js +167 -0
  26. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js.map +1 -0
  27. package/dist/__tests__/rate-limit-wait/tmux-detector.test.d.ts +5 -0
  28. package/dist/__tests__/rate-limit-wait/tmux-detector.test.d.ts.map +1 -0
  29. package/dist/__tests__/rate-limit-wait/tmux-detector.test.js +295 -0
  30. package/dist/__tests__/rate-limit-wait/tmux-detector.test.js.map +1 -0
  31. package/dist/cli/commands/wait.d.ts +52 -0
  32. package/dist/cli/commands/wait.d.ts.map +1 -0
  33. package/dist/cli/commands/wait.js +229 -0
  34. package/dist/cli/commands/wait.js.map +1 -0
  35. package/dist/cli/index.js +54 -0
  36. package/dist/cli/index.js.map +1 -1
  37. package/dist/features/rate-limit-wait/daemon.d.ts +52 -0
  38. package/dist/features/rate-limit-wait/daemon.d.ts.map +1 -0
  39. package/dist/features/rate-limit-wait/daemon.js +585 -0
  40. package/dist/features/rate-limit-wait/daemon.js.map +1 -0
  41. package/dist/features/rate-limit-wait/index.d.ts +16 -0
  42. package/dist/features/rate-limit-wait/index.d.ts.map +1 -0
  43. package/dist/features/rate-limit-wait/index.js +18 -0
  44. package/dist/features/rate-limit-wait/index.js.map +1 -0
  45. package/dist/features/rate-limit-wait/rate-limit-monitor.d.ts +22 -0
  46. package/dist/features/rate-limit-wait/rate-limit-monitor.d.ts.map +1 -0
  47. package/dist/features/rate-limit-wait/rate-limit-monitor.js +99 -0
  48. package/dist/features/rate-limit-wait/rate-limit-monitor.js.map +1 -0
  49. package/dist/features/rate-limit-wait/tmux-detector.d.ts +59 -0
  50. package/dist/features/rate-limit-wait/tmux-detector.d.ts.map +1 -0
  51. package/dist/features/rate-limit-wait/tmux-detector.js +304 -0
  52. package/dist/features/rate-limit-wait/tmux-detector.js.map +1 -0
  53. package/dist/features/rate-limit-wait/types.d.ts +121 -0
  54. package/dist/features/rate-limit-wait/types.d.ts.map +1 -0
  55. package/dist/features/rate-limit-wait/types.js +8 -0
  56. package/dist/features/rate-limit-wait/types.js.map +1 -0
  57. package/dist/features/state-manager/index.d.ts.map +1 -1
  58. package/dist/features/state-manager/index.js +4 -1
  59. package/dist/features/state-manager/index.js.map +1 -1
  60. package/dist/hooks/bridge.d.ts +1 -1
  61. package/dist/hooks/bridge.d.ts.map +1 -1
  62. package/dist/hooks/bridge.js +50 -4
  63. package/dist/hooks/bridge.js.map +1 -1
  64. package/dist/hooks/index.d.ts +5 -0
  65. package/dist/hooks/index.d.ts.map +1 -1
  66. package/dist/hooks/index.js +15 -0
  67. package/dist/hooks/index.js.map +1 -1
  68. package/dist/hooks/omc-orchestrator/audit.d.ts +2 -1
  69. package/dist/hooks/omc-orchestrator/audit.d.ts.map +1 -1
  70. package/dist/hooks/omc-orchestrator/audit.js.map +1 -1
  71. package/dist/hooks/omc-orchestrator/index.d.ts +7 -0
  72. package/dist/hooks/omc-orchestrator/index.d.ts.map +1 -1
  73. package/dist/hooks/omc-orchestrator/index.js +95 -8
  74. package/dist/hooks/omc-orchestrator/index.js.map +1 -1
  75. package/dist/hooks/permission-handler/__tests__/index.test.d.ts +2 -0
  76. package/dist/hooks/permission-handler/__tests__/index.test.d.ts.map +1 -0
  77. package/dist/hooks/permission-handler/__tests__/index.test.js +291 -0
  78. package/dist/hooks/permission-handler/__tests__/index.test.js.map +1 -0
  79. package/dist/hooks/permission-handler/index.d.ts +42 -0
  80. package/dist/hooks/permission-handler/index.d.ts.map +1 -0
  81. package/dist/hooks/permission-handler/index.js +107 -0
  82. package/dist/hooks/permission-handler/index.js.map +1 -0
  83. package/dist/hooks/plugin-patterns/index.d.ts +5 -0
  84. package/dist/hooks/plugin-patterns/index.d.ts.map +1 -1
  85. package/dist/hooks/plugin-patterns/index.js +26 -1
  86. package/dist/hooks/plugin-patterns/index.js.map +1 -1
  87. package/dist/hooks/pre-compact/index.d.ts +82 -0
  88. package/dist/hooks/pre-compact/index.d.ts.map +1 -0
  89. package/dist/hooks/pre-compact/index.js +265 -0
  90. package/dist/hooks/pre-compact/index.js.map +1 -0
  91. package/dist/hooks/session-end/index.d.ts +42 -0
  92. package/dist/hooks/session-end/index.d.ts.map +1 -0
  93. package/dist/hooks/session-end/index.js +200 -0
  94. package/dist/hooks/session-end/index.js.map +1 -0
  95. package/dist/hooks/setup/index.d.ts +66 -0
  96. package/dist/hooks/setup/index.d.ts.map +1 -0
  97. package/dist/hooks/setup/index.js +299 -0
  98. package/dist/hooks/setup/index.js.map +1 -0
  99. package/dist/hooks/setup/types.d.ts +25 -0
  100. package/dist/hooks/setup/types.d.ts.map +1 -0
  101. package/dist/hooks/setup/types.js +5 -0
  102. package/dist/hooks/setup/types.js.map +1 -0
  103. package/dist/hooks/subagent-tracker/index.d.ts +68 -29
  104. package/dist/hooks/subagent-tracker/index.d.ts.map +1 -1
  105. package/dist/hooks/subagent-tracker/index.js +316 -131
  106. package/dist/hooks/subagent-tracker/index.js.map +1 -1
  107. package/dist/hud/analytics-display.d.ts +16 -0
  108. package/dist/hud/analytics-display.d.ts.map +1 -1
  109. package/dist/hud/analytics-display.js +35 -9
  110. package/dist/hud/analytics-display.js.map +1 -1
  111. package/dist/hud/render.d.ts.map +1 -1
  112. package/dist/hud/render.js +49 -18
  113. package/dist/hud/render.js.map +1 -1
  114. package/dist/hud/types.d.ts +2 -0
  115. package/dist/hud/types.d.ts.map +1 -1
  116. package/dist/hud/types.js +14 -0
  117. package/dist/hud/types.js.map +1 -1
  118. package/dist/installer/index.d.ts +1 -1
  119. package/dist/installer/index.d.ts.map +1 -1
  120. package/dist/installer/index.js +4 -3
  121. package/dist/installer/index.js.map +1 -1
  122. package/hooks/hooks.json +83 -1
  123. package/hooks/keyword-detector.sh +4 -4
  124. package/hooks/persistent-mode.sh +10 -10
  125. package/hooks/session-start.sh +4 -4
  126. package/package.json +3 -1
  127. package/scripts/keyword-detector.mjs +4 -4
  128. package/scripts/permission-handler.mjs +23 -0
  129. package/scripts/persistent-mode.mjs +6 -6
  130. package/scripts/persistent-mode.sh +10 -10
  131. package/scripts/pre-compact.mjs +23 -0
  132. package/scripts/session-end.mjs +23 -0
  133. package/scripts/session-start.mjs +4 -4
  134. package/scripts/setup-init.mjs +23 -0
  135. package/scripts/setup-maintenance.mjs +23 -0
  136. package/scripts/subagent-tracker.mjs +35 -0
  137. package/skills/hud/SKILL.md +37 -5
  138. package/skills/omc-setup/SKILL.md +162 -4
  139. package/skills/writer-memory/SKILL.md +443 -0
  140. package/skills/writer-memory/lib/character-tracker.ts +338 -0
  141. package/skills/writer-memory/lib/memory-manager.ts +804 -0
  142. package/skills/writer-memory/lib/relationship-graph.ts +400 -0
  143. package/skills/writer-memory/lib/scene-organizer.ts +544 -0
  144. package/skills/writer-memory/lib/synopsis-builder.ts +339 -0
  145. package/skills/writer-memory/templates/synopsis-template.md +46 -0
  146. package/templates/hooks/keyword-detector.mjs +198 -0
  147. package/templates/hooks/keyword-detector.sh +102 -0
  148. package/templates/hooks/persistent-mode.mjs +249 -0
  149. package/templates/hooks/persistent-mode.sh +187 -0
  150. package/templates/hooks/post-tool-use.mjs +133 -0
  151. package/templates/hooks/post-tool-use.sh +90 -0
  152. package/templates/hooks/pre-tool-use.mjs +145 -0
  153. package/templates/hooks/pre-tool-use.sh +113 -0
  154. package/templates/hooks/session-start.mjs +100 -0
  155. package/templates/hooks/session-start.sh +62 -0
  156. package/templates/hooks/stop-continuation.mjs +80 -0
  157. package/templates/hooks/stop-continuation.sh +40 -0
  158. package/templates/rules/README.md +40 -0
  159. package/templates/rules/coding-style.md +74 -0
  160. package/templates/rules/git-workflow.md +41 -0
  161. package/templates/rules/performance.md +40 -0
  162. package/templates/rules/security.md +41 -0
  163. package/templates/rules/testing.md +42 -0
@@ -0,0 +1,400 @@
1
+ /**
2
+ * Relationship Graph Module for Writer Memory System
3
+ *
4
+ * Tracks character relationships with evolution over time,
5
+ * Korean relationship types, and graph-based analysis.
6
+ */
7
+
8
+ import { loadMemory, saveMemory, generateId, now } from './memory-manager';
9
+ import type {
10
+ Relationship,
11
+ RelationshipType,
12
+ RelationshipEvent,
13
+ SpeechLevel,
14
+ WriterMemory
15
+ } from './memory-manager';
16
+
17
+ // ============================================================================
18
+ // Relationship CRUD Operations
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Create a new relationship between two characters
23
+ *
24
+ * @param char1Name - First character name
25
+ * @param char2Name - Second character name
26
+ * @param type - Relationship type
27
+ * @param options - Optional relationship properties
28
+ * @returns Created relationship
29
+ */
30
+ export function addRelationship(
31
+ char1Name: string,
32
+ char2Name: string,
33
+ type: RelationshipType,
34
+ options?: {
35
+ dynamic?: Relationship['dynamic'];
36
+ speechLevel?: SpeechLevel;
37
+ notes?: string;
38
+ }
39
+ ): Relationship | null {
40
+ const memory = loadMemory();
41
+ if (!memory) return null;
42
+
43
+ // Check if relationship already exists
44
+ const existing = memory.relationships.find(r =>
45
+ (r.from === char1Name && r.to === char2Name) ||
46
+ (r.from === char2Name && r.to === char1Name)
47
+ );
48
+
49
+ if (existing) {
50
+ return null;
51
+ }
52
+
53
+ const relationship: Relationship = {
54
+ id: generateId('rel'),
55
+ from: char1Name,
56
+ to: char2Name,
57
+ type,
58
+ dynamic: options?.dynamic || 'stable',
59
+ speechLevel: options?.speechLevel,
60
+ notes: options?.notes,
61
+ evolution: [],
62
+ created: now()
63
+ };
64
+
65
+ memory.relationships.push(relationship);
66
+ saveMemory(memory);
67
+
68
+ return relationship;
69
+ }
70
+
71
+ /**
72
+ * Update an existing relationship with partial data
73
+ *
74
+ * @param char1Name - First character name
75
+ * @param char2Name - Second character name
76
+ * @param updates - Partial relationship updates
77
+ * @returns Updated relationship
78
+ */
79
+ export function updateRelationship(
80
+ char1Name: string,
81
+ char2Name: string,
82
+ updates: Partial<Omit<Relationship, 'id' | 'from' | 'to' | 'created'>>
83
+ ): Relationship | null {
84
+ const memory = loadMemory();
85
+ if (!memory) return null;
86
+
87
+ const relationship = getRelationship(char1Name, char2Name);
88
+
89
+ if (!relationship) {
90
+ return null;
91
+ }
92
+
93
+ Object.assign(relationship, updates);
94
+ saveMemory(memory);
95
+
96
+ return relationship;
97
+ }
98
+
99
+ /**
100
+ * Remove a relationship between two characters
101
+ *
102
+ * @param char1Name - First character name
103
+ * @param char2Name - Second character name
104
+ */
105
+ export function removeRelationship(char1Name: string, char2Name: string): boolean {
106
+ const memory = loadMemory();
107
+ if (!memory) return false;
108
+
109
+ const index = memory.relationships.findIndex(r =>
110
+ (r.from === char1Name && r.to === char2Name) ||
111
+ (r.from === char2Name && r.to === char1Name)
112
+ );
113
+
114
+ if (index === -1) {
115
+ return false;
116
+ }
117
+
118
+ memory.relationships.splice(index, 1);
119
+ saveMemory(memory);
120
+ return true;
121
+ }
122
+
123
+ /**
124
+ * Get relationship between two characters (direction-agnostic)
125
+ *
126
+ * @param char1Name - First character name
127
+ * @param char2Name - Second character name
128
+ * @returns Relationship or undefined
129
+ */
130
+ export function getRelationship(char1Name: string, char2Name: string): Relationship | undefined {
131
+ const memory = loadMemory();
132
+ if (!memory) return undefined;
133
+
134
+ return memory.relationships.find(r =>
135
+ (r.from === char1Name && r.to === char2Name) ||
136
+ (r.from === char2Name && r.to === char1Name)
137
+ );
138
+ }
139
+
140
+ /**
141
+ * List all relationships, optionally filtered by character
142
+ *
143
+ * @param characterName - Optional character to filter by
144
+ * @returns Array of relationships
145
+ */
146
+ export function listRelationships(characterName?: string): Relationship[] {
147
+ const memory = loadMemory();
148
+ if (!memory) return [];
149
+
150
+ if (!characterName) {
151
+ return memory.relationships;
152
+ }
153
+
154
+ return memory.relationships.filter(r =>
155
+ r.from === characterName || r.to === characterName
156
+ );
157
+ }
158
+
159
+ // ============================================================================
160
+ // Relationship Evolution
161
+ // ============================================================================
162
+
163
+ /**
164
+ * Add a timeline event to a relationship
165
+ *
166
+ * @param char1Name - First character name
167
+ * @param char2Name - Second character name
168
+ * @param change - Description of relationship change
169
+ * @param catalyst - What caused the change
170
+ * @param sceneId - Optional scene reference
171
+ * @returns Created event
172
+ */
173
+ export function addRelationshipEvent(
174
+ char1Name: string,
175
+ char2Name: string,
176
+ change: string,
177
+ catalyst: string,
178
+ sceneId?: string
179
+ ): RelationshipEvent | null {
180
+ const relationship = getRelationship(char1Name, char2Name);
181
+
182
+ if (!relationship) {
183
+ return null;
184
+ }
185
+
186
+ const event: RelationshipEvent = {
187
+ timestamp: now(),
188
+ change,
189
+ catalyst,
190
+ sceneId
191
+ };
192
+
193
+ relationship.evolution.push(event);
194
+
195
+ const memory = loadMemory();
196
+ if (!memory) return null;
197
+
198
+ saveMemory(memory);
199
+
200
+ return event;
201
+ }
202
+
203
+ /**
204
+ * Get all timeline events for a relationship
205
+ *
206
+ * @param char1Name - First character name
207
+ * @param char2Name - Second character name
208
+ * @returns Array of events sorted by timestamp
209
+ */
210
+ export function getRelationshipTimeline(char1Name: string, char2Name: string): RelationshipEvent[] {
211
+ const relationship = getRelationship(char1Name, char2Name);
212
+
213
+ if (!relationship) {
214
+ return [];
215
+ }
216
+
217
+ return relationship.evolution.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
218
+ }
219
+
220
+ /**
221
+ * Get relationship arc summary (e.g., "첫만남 → 오해 → 화해")
222
+ *
223
+ * @param char1Name - First character name
224
+ * @param char2Name - Second character name
225
+ * @returns Arc summary string
226
+ */
227
+ export function getRelationshipArc(char1Name: string, char2Name: string): string {
228
+ const timeline = getRelationshipTimeline(char1Name, char2Name);
229
+
230
+ if (timeline.length === 0) {
231
+ return '변화 없음';
232
+ }
233
+
234
+ return timeline.map(e => e.change).join(' → ');
235
+ }
236
+
237
+ // ============================================================================
238
+ // Graph Operations
239
+ // ============================================================================
240
+
241
+ /**
242
+ * Get all connections for a character with direction info
243
+ *
244
+ * @param characterName - Character name
245
+ * @returns Connections with direction (outgoing/incoming/mutual)
246
+ */
247
+ export function getCharacterConnections(characterName: string): Array<{
248
+ relationship: Relationship;
249
+ direction: 'outgoing' | 'incoming' | 'mutual';
250
+ otherCharacter: string;
251
+ }> {
252
+ const relationships = listRelationships(characterName);
253
+
254
+ return relationships.map(r => {
255
+ const isFrom = r.from === characterName;
256
+ return {
257
+ relationship: r,
258
+ direction: 'mutual' as const, // Most relationships are bidirectional
259
+ otherCharacter: isFrom ? r.to : r.from
260
+ };
261
+ });
262
+ }
263
+
264
+ /**
265
+ * Get full relationship graph
266
+ *
267
+ * @returns Graph with nodes (characters) and edges (relationships)
268
+ */
269
+ export function getRelationshipWeb(): {
270
+ nodes: string[];
271
+ edges: Array<{ from: string; to: string; type: RelationshipType }>
272
+ } {
273
+ const memory = loadMemory();
274
+ if (!memory) return { nodes: [], edges: [] };
275
+
276
+ const nodes = new Set<string>();
277
+ const edges: Array<{ from: string; to: string; type: RelationshipType }> = [];
278
+
279
+ memory.relationships.forEach(r => {
280
+ nodes.add(r.from);
281
+ nodes.add(r.to);
282
+ edges.push({ from: r.from, to: r.to, type: r.type });
283
+ });
284
+
285
+ return {
286
+ nodes: Array.from(nodes),
287
+ edges
288
+ };
289
+ }
290
+
291
+ // ============================================================================
292
+ // Korean Labels
293
+ // ============================================================================
294
+
295
+ /**
296
+ * Get Korean label for relationship type
297
+ *
298
+ * @param type - Relationship type
299
+ * @returns Korean label
300
+ */
301
+ export function getKoreanRelationType(type: RelationshipType): string {
302
+ const labels: Record<RelationshipType, string> = {
303
+ romantic: '연인',
304
+ familial: '가족',
305
+ friendship: '우정',
306
+ antagonistic: '적대',
307
+ professional: '직업적',
308
+ mentor: '사제',
309
+ complex: '복합적'
310
+ };
311
+
312
+ return labels[type];
313
+ }
314
+
315
+ // ============================================================================
316
+ // Profile Generation
317
+ // ============================================================================
318
+
319
+ /**
320
+ * Generate markdown profile for a relationship
321
+ *
322
+ * @param char1Name - First character name
323
+ * @param char2Name - Second character name
324
+ * @returns Markdown profile
325
+ */
326
+ export function generateRelationshipProfile(char1Name: string, char2Name: string): string {
327
+ const relationship = getRelationship(char1Name, char2Name);
328
+
329
+ if (!relationship) {
330
+ return `# ${char1Name} ↔ ${char2Name}\n\n관계 정보 없음`;
331
+ }
332
+
333
+ const timeline = getRelationshipTimeline(char1Name, char2Name);
334
+ const arc = getRelationshipArc(char1Name, char2Name);
335
+
336
+ let profile = `# ${char1Name} ↔ ${char2Name}\n\n`;
337
+ profile += `**관계 유형**: ${getKoreanRelationType(relationship.type)}\n`;
338
+ profile += `**상태**: ${relationship.dynamic}\n`;
339
+
340
+ if (relationship.speechLevel) {
341
+ profile += `**말투**: ${relationship.speechLevel}\n`;
342
+ }
343
+
344
+ if (relationship.notes) {
345
+ profile += `\n## 설명\n${relationship.notes}\n`;
346
+ }
347
+
348
+ if (timeline.length > 0) {
349
+ profile += `\n## 관계 흐름\n${arc}\n\n`;
350
+ profile += `## 주요 사건\n`;
351
+ timeline.forEach(e => {
352
+ profile += `- **${e.change}**: ${e.catalyst}`;
353
+ if (e.sceneId) {
354
+ profile += ` (${e.sceneId})`;
355
+ }
356
+ profile += '\n';
357
+ });
358
+ }
359
+
360
+ return profile;
361
+ }
362
+
363
+ /**
364
+ * Generate ASCII map of all relationships with symbols
365
+ *
366
+ * @returns ASCII relationship map
367
+ */
368
+ export function generateRelationshipMap(): string {
369
+ const web = getRelationshipWeb();
370
+
371
+ if (web.nodes.length === 0) {
372
+ return '관계 없음';
373
+ }
374
+
375
+ const symbols: Record<RelationshipType, string> = {
376
+ romantic: '♥',
377
+ familial: '家',
378
+ friendship: '友',
379
+ antagonistic: '敵',
380
+ professional: '職',
381
+ mentor: '師',
382
+ complex: '複'
383
+ };
384
+
385
+ let map = '# 관계 지도\n\n';
386
+
387
+ web.nodes.forEach(node => {
388
+ const connections = getCharacterConnections(node);
389
+ if (connections.length > 0) {
390
+ map += `${node}:\n`;
391
+ connections.forEach(conn => {
392
+ const symbol = symbols[conn.relationship.type];
393
+ map += ` ${symbol} ${conn.otherCharacter} (${getKoreanRelationType(conn.relationship.type)})\n`;
394
+ });
395
+ map += '\n';
396
+ }
397
+ });
398
+
399
+ return map;
400
+ }