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.
- package/README.md +40 -1
- package/commands/hud.md +37 -5
- package/commands/omc-setup.md +105 -0
- package/dist/__tests__/delegation-enforcement-levels.test.d.ts +9 -0
- package/dist/__tests__/delegation-enforcement-levels.test.d.ts.map +1 -0
- package/dist/__tests__/delegation-enforcement-levels.test.js +550 -0
- package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -0
- package/dist/__tests__/hud/analytics-display.test.js +137 -1
- package/dist/__tests__/hud/analytics-display.test.js.map +1 -1
- package/dist/__tests__/hud-windows.test.d.ts +2 -0
- package/dist/__tests__/hud-windows.test.d.ts.map +1 -0
- package/dist/__tests__/hud-windows.test.js +91 -0
- package/dist/__tests__/hud-windows.test.js.map +1 -0
- package/dist/__tests__/installer.test.js +1 -1
- package/dist/__tests__/rate-limit-wait/daemon.test.d.ts +5 -0
- package/dist/__tests__/rate-limit-wait/daemon.test.d.ts.map +1 -0
- package/dist/__tests__/rate-limit-wait/daemon.test.js +313 -0
- package/dist/__tests__/rate-limit-wait/daemon.test.js.map +1 -0
- package/dist/__tests__/rate-limit-wait/integration.test.d.ts +8 -0
- package/dist/__tests__/rate-limit-wait/integration.test.d.ts.map +1 -0
- package/dist/__tests__/rate-limit-wait/integration.test.js +329 -0
- package/dist/__tests__/rate-limit-wait/integration.test.js.map +1 -0
- package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.d.ts +5 -0
- package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.d.ts.map +1 -0
- package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js +167 -0
- package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js.map +1 -0
- package/dist/__tests__/rate-limit-wait/tmux-detector.test.d.ts +5 -0
- package/dist/__tests__/rate-limit-wait/tmux-detector.test.d.ts.map +1 -0
- package/dist/__tests__/rate-limit-wait/tmux-detector.test.js +295 -0
- package/dist/__tests__/rate-limit-wait/tmux-detector.test.js.map +1 -0
- package/dist/cli/commands/wait.d.ts +52 -0
- package/dist/cli/commands/wait.d.ts.map +1 -0
- package/dist/cli/commands/wait.js +229 -0
- package/dist/cli/commands/wait.js.map +1 -0
- package/dist/cli/index.js +54 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/features/rate-limit-wait/daemon.d.ts +52 -0
- package/dist/features/rate-limit-wait/daemon.d.ts.map +1 -0
- package/dist/features/rate-limit-wait/daemon.js +585 -0
- package/dist/features/rate-limit-wait/daemon.js.map +1 -0
- package/dist/features/rate-limit-wait/index.d.ts +16 -0
- package/dist/features/rate-limit-wait/index.d.ts.map +1 -0
- package/dist/features/rate-limit-wait/index.js +18 -0
- package/dist/features/rate-limit-wait/index.js.map +1 -0
- package/dist/features/rate-limit-wait/rate-limit-monitor.d.ts +22 -0
- package/dist/features/rate-limit-wait/rate-limit-monitor.d.ts.map +1 -0
- package/dist/features/rate-limit-wait/rate-limit-monitor.js +99 -0
- package/dist/features/rate-limit-wait/rate-limit-monitor.js.map +1 -0
- package/dist/features/rate-limit-wait/tmux-detector.d.ts +59 -0
- package/dist/features/rate-limit-wait/tmux-detector.d.ts.map +1 -0
- package/dist/features/rate-limit-wait/tmux-detector.js +304 -0
- package/dist/features/rate-limit-wait/tmux-detector.js.map +1 -0
- package/dist/features/rate-limit-wait/types.d.ts +121 -0
- package/dist/features/rate-limit-wait/types.d.ts.map +1 -0
- package/dist/features/rate-limit-wait/types.js +8 -0
- package/dist/features/rate-limit-wait/types.js.map +1 -0
- package/dist/features/state-manager/index.d.ts.map +1 -1
- package/dist/features/state-manager/index.js +4 -1
- package/dist/features/state-manager/index.js.map +1 -1
- package/dist/hooks/bridge.d.ts +1 -1
- package/dist/hooks/bridge.d.ts.map +1 -1
- package/dist/hooks/bridge.js +50 -4
- package/dist/hooks/bridge.js.map +1 -1
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +15 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/omc-orchestrator/audit.d.ts +2 -1
- package/dist/hooks/omc-orchestrator/audit.d.ts.map +1 -1
- package/dist/hooks/omc-orchestrator/audit.js.map +1 -1
- package/dist/hooks/omc-orchestrator/index.d.ts +7 -0
- package/dist/hooks/omc-orchestrator/index.d.ts.map +1 -1
- package/dist/hooks/omc-orchestrator/index.js +95 -8
- package/dist/hooks/omc-orchestrator/index.js.map +1 -1
- package/dist/hooks/permission-handler/__tests__/index.test.d.ts +2 -0
- package/dist/hooks/permission-handler/__tests__/index.test.d.ts.map +1 -0
- package/dist/hooks/permission-handler/__tests__/index.test.js +291 -0
- package/dist/hooks/permission-handler/__tests__/index.test.js.map +1 -0
- package/dist/hooks/permission-handler/index.d.ts +42 -0
- package/dist/hooks/permission-handler/index.d.ts.map +1 -0
- package/dist/hooks/permission-handler/index.js +107 -0
- package/dist/hooks/permission-handler/index.js.map +1 -0
- package/dist/hooks/plugin-patterns/index.d.ts +5 -0
- package/dist/hooks/plugin-patterns/index.d.ts.map +1 -1
- package/dist/hooks/plugin-patterns/index.js +26 -1
- package/dist/hooks/plugin-patterns/index.js.map +1 -1
- package/dist/hooks/pre-compact/index.d.ts +82 -0
- package/dist/hooks/pre-compact/index.d.ts.map +1 -0
- package/dist/hooks/pre-compact/index.js +265 -0
- package/dist/hooks/pre-compact/index.js.map +1 -0
- package/dist/hooks/session-end/index.d.ts +42 -0
- package/dist/hooks/session-end/index.d.ts.map +1 -0
- package/dist/hooks/session-end/index.js +200 -0
- package/dist/hooks/session-end/index.js.map +1 -0
- package/dist/hooks/setup/index.d.ts +66 -0
- package/dist/hooks/setup/index.d.ts.map +1 -0
- package/dist/hooks/setup/index.js +299 -0
- package/dist/hooks/setup/index.js.map +1 -0
- package/dist/hooks/setup/types.d.ts +25 -0
- package/dist/hooks/setup/types.d.ts.map +1 -0
- package/dist/hooks/setup/types.js +5 -0
- package/dist/hooks/setup/types.js.map +1 -0
- package/dist/hooks/subagent-tracker/index.d.ts +68 -29
- package/dist/hooks/subagent-tracker/index.d.ts.map +1 -1
- package/dist/hooks/subagent-tracker/index.js +316 -131
- package/dist/hooks/subagent-tracker/index.js.map +1 -1
- package/dist/hud/analytics-display.d.ts +16 -0
- package/dist/hud/analytics-display.d.ts.map +1 -1
- package/dist/hud/analytics-display.js +35 -9
- package/dist/hud/analytics-display.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +49 -18
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/types.d.ts +2 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +14 -0
- package/dist/hud/types.js.map +1 -1
- package/dist/installer/index.d.ts +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +4 -3
- package/dist/installer/index.js.map +1 -1
- package/hooks/hooks.json +83 -1
- package/hooks/keyword-detector.sh +4 -4
- package/hooks/persistent-mode.sh +10 -10
- package/hooks/session-start.sh +4 -4
- package/package.json +3 -1
- package/scripts/keyword-detector.mjs +4 -4
- package/scripts/permission-handler.mjs +23 -0
- package/scripts/persistent-mode.mjs +6 -6
- package/scripts/persistent-mode.sh +10 -10
- package/scripts/pre-compact.mjs +23 -0
- package/scripts/session-end.mjs +23 -0
- package/scripts/session-start.mjs +4 -4
- package/scripts/setup-init.mjs +23 -0
- package/scripts/setup-maintenance.mjs +23 -0
- package/scripts/subagent-tracker.mjs +35 -0
- package/skills/hud/SKILL.md +37 -5
- package/skills/omc-setup/SKILL.md +162 -4
- package/skills/writer-memory/SKILL.md +443 -0
- package/skills/writer-memory/lib/character-tracker.ts +338 -0
- package/skills/writer-memory/lib/memory-manager.ts +804 -0
- package/skills/writer-memory/lib/relationship-graph.ts +400 -0
- package/skills/writer-memory/lib/scene-organizer.ts +544 -0
- package/skills/writer-memory/lib/synopsis-builder.ts +339 -0
- package/skills/writer-memory/templates/synopsis-template.md +46 -0
- package/templates/hooks/keyword-detector.mjs +198 -0
- package/templates/hooks/keyword-detector.sh +102 -0
- package/templates/hooks/persistent-mode.mjs +249 -0
- package/templates/hooks/persistent-mode.sh +187 -0
- package/templates/hooks/post-tool-use.mjs +133 -0
- package/templates/hooks/post-tool-use.sh +90 -0
- package/templates/hooks/pre-tool-use.mjs +145 -0
- package/templates/hooks/pre-tool-use.sh +113 -0
- package/templates/hooks/session-start.mjs +100 -0
- package/templates/hooks/session-start.sh +62 -0
- package/templates/hooks/stop-continuation.mjs +80 -0
- package/templates/hooks/stop-continuation.sh +40 -0
- package/templates/rules/README.md +40 -0
- package/templates/rules/coding-style.md +74 -0
- package/templates/rules/git-workflow.md +41 -0
- package/templates/rules/performance.md +40 -0
- package/templates/rules/security.md +41 -0
- package/templates/rules/testing.md +42 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synopsis Builder - 정서 중심 시놉시스 생성기
|
|
3
|
+
*
|
|
4
|
+
* Korean writers think: emotion → relationship → event → plot
|
|
5
|
+
* NOT plot-first!
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { loadMemory, saveMemory, now } from './memory-manager';
|
|
9
|
+
import type { WriterMemory, Character, Relationship, Scene, SynopsisState } from './memory-manager';
|
|
10
|
+
|
|
11
|
+
// === Synopsis Generation ===
|
|
12
|
+
|
|
13
|
+
export function generateSynopsis(options?: {
|
|
14
|
+
protagonist?: string;
|
|
15
|
+
format?: 'full' | 'brief' | 'pitch';
|
|
16
|
+
}): string | null {
|
|
17
|
+
const memory = loadMemory();
|
|
18
|
+
if (!memory) return null;
|
|
19
|
+
|
|
20
|
+
const format = options?.format || 'full';
|
|
21
|
+
const protagonist = options?.protagonist;
|
|
22
|
+
|
|
23
|
+
const attitude = extractProtagonistAttitude(memory, protagonist);
|
|
24
|
+
const relationships = extractCoreRelationships(memory, protagonist);
|
|
25
|
+
const theme = extractEmotionalTheme(memory);
|
|
26
|
+
const genreContrast = extractGenreVsEmotion(memory);
|
|
27
|
+
const aftertaste = extractEndingAftertaste(memory);
|
|
28
|
+
|
|
29
|
+
switch (format) {
|
|
30
|
+
case 'brief':
|
|
31
|
+
return formatBriefSynopsis(attitude, relationships, theme, memory);
|
|
32
|
+
case 'pitch':
|
|
33
|
+
return formatPitchSynopsis(attitude, relationships, theme, genreContrast, memory);
|
|
34
|
+
default:
|
|
35
|
+
return formatFullSynopsis(attitude, relationships, theme, genreContrast, aftertaste, memory);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// === 5 Essential Element Extractors ===
|
|
40
|
+
|
|
41
|
+
function findProtagonist(memory: WriterMemory, name?: string): Character | null {
|
|
42
|
+
const chars = Object.values(memory.characters);
|
|
43
|
+
if (name) {
|
|
44
|
+
return chars.find(c => c.name === name || c.aliases?.includes(name)) || null;
|
|
45
|
+
}
|
|
46
|
+
return chars[0] || null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function extractProtagonistAttitude(memory: WriterMemory, protagonistName?: string): string {
|
|
50
|
+
const protagonist = findProtagonist(memory, protagonistName);
|
|
51
|
+
|
|
52
|
+
if (!protagonist) {
|
|
53
|
+
return '⚠️ 주인공 정보 없음. 캐릭터를 먼저 등록하세요.';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parts: string[] = [];
|
|
57
|
+
if (protagonist.arc) parts.push(protagonist.arc);
|
|
58
|
+
if (protagonist.attitude) parts.push(protagonist.attitude);
|
|
59
|
+
|
|
60
|
+
if (parts.length === 0) {
|
|
61
|
+
return `⚠️ ${protagonist.name}의 태도 정보 미입력. arc와 attitude 필드를 채우세요.`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return parts.join('. ');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function extractCoreRelationships(memory: WriterMemory, protagonistName?: string): string {
|
|
68
|
+
const protagonist = findProtagonist(memory, protagonistName);
|
|
69
|
+
|
|
70
|
+
if (!protagonist) {
|
|
71
|
+
return '⚠️ 주인공 정보 없음.';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const rels = memory.relationships.filter(
|
|
75
|
+
r => r.from === protagonist.name || r.to === protagonist.name
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (rels.length === 0) {
|
|
79
|
+
return `⚠️ ${protagonist.name} 중심의 관계 정보 없음. 관계를 등록하세요.`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return rels.map(r => {
|
|
83
|
+
const other = r.from === protagonist.name ? r.to : r.from;
|
|
84
|
+
return `${protagonist.name}-${other}: ${r.dynamic || r.type}`;
|
|
85
|
+
}).join('\n');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function extractEmotionalTheme(memory: WriterMemory): string {
|
|
89
|
+
if (memory.themes.length === 0) {
|
|
90
|
+
return '⚠️ 테마 정보 없음. 작품의 정서적 주제를 입력하세요.';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return memory.themes.map(t => t.description || t.name).join('. ');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function extractGenreVsEmotion(memory: WriterMemory): string {
|
|
97
|
+
const synopsis = memory.synopsis;
|
|
98
|
+
if (synopsis?.genreVsRealEmotion) {
|
|
99
|
+
return synopsis.genreVsRealEmotion;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const genre = memory.project.genre || '미지정';
|
|
103
|
+
return `장르: ${genre}. 실제 정서: 미정의. genreVsRealEmotion 필드를 입력하세요.`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function extractEndingAftertaste(memory: WriterMemory): string {
|
|
107
|
+
const synopsis = memory.synopsis;
|
|
108
|
+
if (synopsis?.endingAftertaste) {
|
|
109
|
+
return synopsis.endingAftertaste;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return '❌ 엔딩 정서 잔상 미입력. synopsis update endingAftertaste "..." 로 추가하세요.';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// === Synopsis State Management ===
|
|
116
|
+
|
|
117
|
+
export function saveSynopsisState(state: SynopsisState): boolean {
|
|
118
|
+
const memory = loadMemory();
|
|
119
|
+
if (!memory) return false;
|
|
120
|
+
|
|
121
|
+
memory.synopsis = { ...state, lastGenerated: now() };
|
|
122
|
+
return saveMemory(memory);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function loadSynopsisState(): SynopsisState | null {
|
|
126
|
+
const memory = loadMemory();
|
|
127
|
+
return memory?.synopsis || null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function updateSynopsisElement(element: keyof SynopsisState, value: string): boolean {
|
|
131
|
+
const memory = loadMemory();
|
|
132
|
+
if (!memory) return false;
|
|
133
|
+
|
|
134
|
+
memory.synopsis = memory.synopsis || {
|
|
135
|
+
protagonistAttitude: '',
|
|
136
|
+
coreRelationships: '',
|
|
137
|
+
emotionalTheme: '',
|
|
138
|
+
genreVsRealEmotion: '',
|
|
139
|
+
endingAftertaste: ''
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
(memory.synopsis as any)[element] = value;
|
|
143
|
+
memory.synopsis.lastGenerated = now();
|
|
144
|
+
return saveMemory(memory);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// === Format Functions ===
|
|
148
|
+
|
|
149
|
+
export function formatFullSynopsis(
|
|
150
|
+
attitude: string,
|
|
151
|
+
relationships: string,
|
|
152
|
+
theme: string,
|
|
153
|
+
genreContrast: string,
|
|
154
|
+
aftertaste: string,
|
|
155
|
+
memory: WriterMemory
|
|
156
|
+
): string {
|
|
157
|
+
const projectName = memory.project.name || '제목 미정';
|
|
158
|
+
const chars = Object.values(memory.characters);
|
|
159
|
+
const charList = chars.map(c => `- **${c.name}**: ${c.attitude || c.arc || '설명 없음'}`).join('\n');
|
|
160
|
+
const emotionFlow = memory.scenes
|
|
161
|
+
.filter(s => s.emotionTags?.length > 0)
|
|
162
|
+
.map(s => s.emotionTags[0])
|
|
163
|
+
.join(' → ') || '아직 정의되지 않음';
|
|
164
|
+
|
|
165
|
+
return `═══════════════════════════════
|
|
166
|
+
시놉시스: ${projectName}
|
|
167
|
+
═══════════════════════════════
|
|
168
|
+
|
|
169
|
+
## 1. 주인공의 태도
|
|
170
|
+
${attitude}
|
|
171
|
+
|
|
172
|
+
## 2. 관계의 핵심 구도
|
|
173
|
+
${relationships}
|
|
174
|
+
|
|
175
|
+
## 3. 정서적 테마
|
|
176
|
+
${theme}
|
|
177
|
+
|
|
178
|
+
## 4. 장르와 실제 감정의 거리
|
|
179
|
+
${genreContrast}
|
|
180
|
+
|
|
181
|
+
## 5. 엔딩이 남기는 잔상
|
|
182
|
+
${aftertaste}
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
**등장인물**:
|
|
186
|
+
${charList || '(등장인물 없음)'}
|
|
187
|
+
|
|
188
|
+
**장면 수**: ${memory.scenes.length}개
|
|
189
|
+
|
|
190
|
+
**감정 흐름**: ${emotionFlow}
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function formatBriefSynopsis(
|
|
195
|
+
attitude: string,
|
|
196
|
+
relationships: string,
|
|
197
|
+
theme: string,
|
|
198
|
+
memory: WriterMemory
|
|
199
|
+
): string {
|
|
200
|
+
const chars = Object.values(memory.characters);
|
|
201
|
+
const protagonist = chars[0];
|
|
202
|
+
const name = protagonist?.name || '주인공';
|
|
203
|
+
|
|
204
|
+
return `${name}은 ${attitude.split('.')[0]}. ${theme.split('.')[0]}을 통해 ${relationships.split('\n')[0] || '관계를 형성하며'} 변화한다.`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function formatPitchSynopsis(
|
|
208
|
+
attitude: string,
|
|
209
|
+
relationships: string,
|
|
210
|
+
theme: string,
|
|
211
|
+
genreContrast: string,
|
|
212
|
+
memory: WriterMemory
|
|
213
|
+
): string {
|
|
214
|
+
const projectName = memory.project.name || '이 이야기';
|
|
215
|
+
const chars = Object.values(memory.characters);
|
|
216
|
+
const protagonist = chars[0];
|
|
217
|
+
const name = protagonist?.name || '주인공';
|
|
218
|
+
|
|
219
|
+
return `${projectName}는 ${attitude.split('.')[0]} ${name}이 ${theme.split('.')[0]}을 깨닫는 이야기. ${genreContrast.split('.')[0]}.`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// === Checklist ===
|
|
223
|
+
|
|
224
|
+
export interface ChecklistItem {
|
|
225
|
+
element: string;
|
|
226
|
+
elementKr: string;
|
|
227
|
+
status: 'complete' | 'partial' | 'missing';
|
|
228
|
+
source: string;
|
|
229
|
+
suggestion: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function getSynopsisChecklist(memory: WriterMemory): ChecklistItem[] {
|
|
233
|
+
const chars = Object.values(memory.characters);
|
|
234
|
+
const protagonist = chars[0];
|
|
235
|
+
|
|
236
|
+
const checklist: ChecklistItem[] = [];
|
|
237
|
+
|
|
238
|
+
// 1. Protagonist Attitude
|
|
239
|
+
const hasArc = protagonist?.arc ? true : false;
|
|
240
|
+
const hasAttitude = protagonist?.attitude ? true : false;
|
|
241
|
+
checklist.push({
|
|
242
|
+
element: 'protagonistAttitude',
|
|
243
|
+
elementKr: '주인공 태도 요약',
|
|
244
|
+
status: hasArc && hasAttitude ? 'complete' : hasArc || hasAttitude ? 'partial' : 'missing',
|
|
245
|
+
source: protagonist ? `캐릭터 '${protagonist.name}'에서 추출` : '주인공 없음',
|
|
246
|
+
suggestion: hasArc && hasAttitude ? '' : 'char update <name> arc "..." attitude "..."'
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// 2. Core Relationships
|
|
250
|
+
const relCount = protagonist ? memory.relationships.filter(
|
|
251
|
+
r => r.from === protagonist.name || r.to === protagonist.name
|
|
252
|
+
).length : 0;
|
|
253
|
+
checklist.push({
|
|
254
|
+
element: 'coreRelationships',
|
|
255
|
+
elementKr: '관계 핵심 구도',
|
|
256
|
+
status: relCount >= 2 ? 'complete' : relCount === 1 ? 'partial' : 'missing',
|
|
257
|
+
source: `관계 ${relCount}개 등록됨`,
|
|
258
|
+
suggestion: relCount >= 2 ? '' : 'rel add <from> <to> <type>'
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// 3. Emotional Theme
|
|
262
|
+
checklist.push({
|
|
263
|
+
element: 'emotionalTheme',
|
|
264
|
+
elementKr: '정서적 테마',
|
|
265
|
+
status: memory.themes.length > 0 ? 'complete' : 'missing',
|
|
266
|
+
source: `테마 ${memory.themes.length}개 등록됨`,
|
|
267
|
+
suggestion: memory.themes.length > 0 ? '' : 'theme add <name>'
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// 4. Genre vs Emotion
|
|
271
|
+
const hasGenreContrast = memory.synopsis?.genreVsRealEmotion ? true : false;
|
|
272
|
+
checklist.push({
|
|
273
|
+
element: 'genreVsEmotion',
|
|
274
|
+
elementKr: '장르와 실제 감정의 거리',
|
|
275
|
+
status: hasGenreContrast ? 'complete' : 'missing',
|
|
276
|
+
source: hasGenreContrast ? '명시적으로 입력됨' : '미입력',
|
|
277
|
+
suggestion: hasGenreContrast ? '' : 'synopsis update genreVsRealEmotion "..."'
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// 5. Ending Aftertaste
|
|
281
|
+
const hasAftertaste = memory.synopsis?.endingAftertaste ? true : false;
|
|
282
|
+
checklist.push({
|
|
283
|
+
element: 'endingAftertaste',
|
|
284
|
+
elementKr: '엔딩 정서 잔상',
|
|
285
|
+
status: hasAftertaste ? 'complete' : 'missing',
|
|
286
|
+
source: hasAftertaste ? '명시적으로 입력됨' : '미입력',
|
|
287
|
+
suggestion: hasAftertaste ? '' : 'synopsis update endingAftertaste "..."'
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return checklist;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// === Export ===
|
|
294
|
+
|
|
295
|
+
export function exportSynopsisAsMarkdown(): string {
|
|
296
|
+
const memory = loadMemory();
|
|
297
|
+
if (!memory) return '# Error: No memory found';
|
|
298
|
+
|
|
299
|
+
const synopsis = generateSynopsis({ format: 'full' });
|
|
300
|
+
if (!synopsis) return '# Error: Could not generate synopsis';
|
|
301
|
+
|
|
302
|
+
const meta = `---
|
|
303
|
+
project: ${memory.project.name || 'Untitled'}
|
|
304
|
+
genre: ${memory.project.genre || 'Unspecified'}
|
|
305
|
+
generated: ${new Date().toISOString()}
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
`;
|
|
309
|
+
|
|
310
|
+
return meta + synopsis;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function exportSynopsisAsJSON(): object {
|
|
314
|
+
const memory = loadMemory();
|
|
315
|
+
if (!memory) return { error: 'No memory found' };
|
|
316
|
+
|
|
317
|
+
const checklist = getSynopsisChecklist(memory);
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
metadata: {
|
|
321
|
+
project: memory.project.name,
|
|
322
|
+
genre: memory.project.genre,
|
|
323
|
+
generated: new Date().toISOString()
|
|
324
|
+
},
|
|
325
|
+
elements: {
|
|
326
|
+
protagonistAttitude: extractProtagonistAttitude(memory),
|
|
327
|
+
coreRelationships: extractCoreRelationships(memory),
|
|
328
|
+
emotionalTheme: extractEmotionalTheme(memory),
|
|
329
|
+
genreVsEmotion: extractGenreVsEmotion(memory),
|
|
330
|
+
endingAftertaste: extractEndingAftertaste(memory)
|
|
331
|
+
},
|
|
332
|
+
checklist,
|
|
333
|
+
formats: {
|
|
334
|
+
full: generateSynopsis({ format: 'full' }),
|
|
335
|
+
brief: generateSynopsis({ format: 'brief' }),
|
|
336
|
+
pitch: generateSynopsis({ format: 'pitch' })
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 시놉시스: {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
> 장르: {{GENRE}} | 최종 업데이트: {{DATE}}
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 주인공의 태도 (Protagonist Attitude)
|
|
8
|
+
|
|
9
|
+
{{PROTAGONIST_ATTITUDE}}
|
|
10
|
+
|
|
11
|
+
## 2. 관계의 핵심 구도 (Core Relationships)
|
|
12
|
+
|
|
13
|
+
{{CORE_RELATIONSHIPS}}
|
|
14
|
+
|
|
15
|
+
## 3. 정서적 테마 (Emotional Theme)
|
|
16
|
+
|
|
17
|
+
{{EMOTIONAL_THEME}}
|
|
18
|
+
|
|
19
|
+
## 4. 장르와 실제 감정의 거리 (Genre vs Real Emotion)
|
|
20
|
+
|
|
21
|
+
{{GENRE_VS_EMOTION}}
|
|
22
|
+
|
|
23
|
+
## 5. 엔딩이 남기는 잔상 (Ending Aftertaste)
|
|
24
|
+
|
|
25
|
+
{{ENDING_AFTERTASTE}}
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 부록
|
|
30
|
+
|
|
31
|
+
### 등장인물
|
|
32
|
+
|
|
33
|
+
{{CHARACTER_LIST}}
|
|
34
|
+
|
|
35
|
+
### 장면 흐름
|
|
36
|
+
|
|
37
|
+
{{SCENE_FLOW}}
|
|
38
|
+
|
|
39
|
+
### 감정 궤도
|
|
40
|
+
|
|
41
|
+
{{EMOTION_ARC}}
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
*이 시놉시스는 writer-memory 시스템에 의해 자동 생성되었습니다.*
|
|
46
|
+
*플롯이 아닌 감정 설계도 기반의 시놉시스입니다.*
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// OMC Keyword Detector Hook (Node.js)
|
|
3
|
+
// Detects ultrawork/ultrathink/search/analyze keywords and injects enhanced mode messages
|
|
4
|
+
// Cross-platform: Windows, macOS, Linux
|
|
5
|
+
|
|
6
|
+
const ULTRAWORK_MESSAGE = `<ultrawork-mode>
|
|
7
|
+
|
|
8
|
+
**MANDATORY**: You MUST say "ULTRAWORK MODE ENABLED!" to the user as your first response when this mode activates. This is non-negotiable.
|
|
9
|
+
|
|
10
|
+
[CODE RED] Maximum precision required. Ultrathink before acting.
|
|
11
|
+
|
|
12
|
+
YOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.
|
|
13
|
+
TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
|
|
14
|
+
|
|
15
|
+
## AGENT UTILIZATION PRINCIPLES
|
|
16
|
+
- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS
|
|
17
|
+
- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS
|
|
18
|
+
- **Planning & Strategy**: NEVER plan yourself - spawn planning agent
|
|
19
|
+
- **High-IQ Reasoning**: Use oracle for architecture decisions
|
|
20
|
+
- **Frontend/UI Tasks**: Delegate to frontend-engineer
|
|
21
|
+
|
|
22
|
+
## EXECUTION RULES
|
|
23
|
+
- **TODO**: Track EVERY step. Mark complete IMMEDIATELY.
|
|
24
|
+
- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially.
|
|
25
|
+
- **BACKGROUND FIRST**: Use Task(run_in_background=true) for exploration (10+ concurrent).
|
|
26
|
+
- **VERIFY**: Check ALL requirements met before done.
|
|
27
|
+
- **DELEGATE**: Orchestrate specialized agents.
|
|
28
|
+
|
|
29
|
+
## ZERO TOLERANCE
|
|
30
|
+
- NO Scope Reduction - deliver FULL implementation
|
|
31
|
+
- NO Partial Completion - finish 100%
|
|
32
|
+
- NO Premature Stopping - ALL TODOs must be complete
|
|
33
|
+
- NO TEST DELETION - fix code, not tests
|
|
34
|
+
|
|
35
|
+
THE USER ASKED FOR X. DELIVER EXACTLY X.
|
|
36
|
+
|
|
37
|
+
</ultrawork-mode>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const ULTRATHINK_MESSAGE = `<think-mode>
|
|
43
|
+
|
|
44
|
+
**ULTRATHINK MODE ENABLED** - Extended reasoning activated.
|
|
45
|
+
|
|
46
|
+
You are now in deep thinking mode. Take your time to:
|
|
47
|
+
1. Thoroughly analyze the problem from multiple angles
|
|
48
|
+
2. Consider edge cases and potential issues
|
|
49
|
+
3. Think through the implications of each approach
|
|
50
|
+
4. Reason step-by-step before acting
|
|
51
|
+
|
|
52
|
+
Use your extended thinking capabilities to provide the most thorough and well-reasoned response.
|
|
53
|
+
|
|
54
|
+
</think-mode>
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const SEARCH_MESSAGE = `<search-mode>
|
|
60
|
+
MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL:
|
|
61
|
+
- explore agents (codebase patterns, file structures)
|
|
62
|
+
- librarian agents (remote repos, official docs, GitHub examples)
|
|
63
|
+
Plus direct tools: Grep, Glob
|
|
64
|
+
NEVER stop at first result - be exhaustive.
|
|
65
|
+
</search-mode>
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const ANALYZE_MESSAGE = `<analyze-mode>
|
|
71
|
+
ANALYSIS MODE. Gather context before diving deep:
|
|
72
|
+
|
|
73
|
+
CONTEXT GATHERING (parallel):
|
|
74
|
+
- 1-2 explore agents (codebase patterns, implementations)
|
|
75
|
+
- 1-2 librarian agents (if external library involved)
|
|
76
|
+
- Direct tools: Grep, Glob, LSP for targeted searches
|
|
77
|
+
|
|
78
|
+
IF COMPLEX (architecture, multi-system, debugging after 2+ failures):
|
|
79
|
+
- Consult oracle agent for strategic guidance
|
|
80
|
+
|
|
81
|
+
SYNTHESIZE findings before proceeding.
|
|
82
|
+
</analyze-mode>
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
// Read all stdin
|
|
88
|
+
async function readStdin() {
|
|
89
|
+
const chunks = [];
|
|
90
|
+
for await (const chunk of process.stdin) {
|
|
91
|
+
chunks.push(chunk);
|
|
92
|
+
}
|
|
93
|
+
return Buffer.concat(chunks).toString('utf-8');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Extract prompt from various JSON structures
|
|
97
|
+
function extractPrompt(input) {
|
|
98
|
+
try {
|
|
99
|
+
const data = JSON.parse(input);
|
|
100
|
+
if (data.prompt) return data.prompt;
|
|
101
|
+
if (data.message?.content) return data.message.content;
|
|
102
|
+
if (Array.isArray(data.parts)) {
|
|
103
|
+
return data.parts
|
|
104
|
+
.filter(p => p.type === 'text')
|
|
105
|
+
.map(p => p.text)
|
|
106
|
+
.join(' ');
|
|
107
|
+
}
|
|
108
|
+
return '';
|
|
109
|
+
} catch {
|
|
110
|
+
// Fallback: try to extract with regex
|
|
111
|
+
const match = input.match(/"(?:prompt|content|text)"\s*:\s*"([^"]+)"/);
|
|
112
|
+
return match ? match[1] : '';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Remove code blocks to prevent false positives
|
|
117
|
+
function removeCodeBlocks(text) {
|
|
118
|
+
return text
|
|
119
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
120
|
+
.replace(/`[^`]+`/g, '');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
124
|
+
import { join } from 'path';
|
|
125
|
+
import { homedir } from 'os';
|
|
126
|
+
|
|
127
|
+
// Create ultrawork state file
|
|
128
|
+
function activateUltraworkState(directory, prompt) {
|
|
129
|
+
const state = {
|
|
130
|
+
active: true,
|
|
131
|
+
started_at: new Date().toISOString(),
|
|
132
|
+
original_prompt: prompt,
|
|
133
|
+
reinforcement_count: 0,
|
|
134
|
+
last_checked_at: new Date().toISOString()
|
|
135
|
+
};
|
|
136
|
+
const localDir = join(directory, '.omc');
|
|
137
|
+
if (!existsSync(localDir)) { try { mkdirSync(localDir, { recursive: true }); } catch {} }
|
|
138
|
+
try { writeFileSync(join(localDir, 'ultrawork-state.json'), JSON.stringify(state, null, 2)); } catch {}
|
|
139
|
+
const globalDir = join(homedir(), '.claude');
|
|
140
|
+
if (!existsSync(globalDir)) { try { mkdirSync(globalDir, { recursive: true }); } catch {} }
|
|
141
|
+
try { writeFileSync(join(globalDir, 'ultrawork-state.json'), JSON.stringify(state, null, 2)); } catch {}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Main
|
|
145
|
+
async function main() {
|
|
146
|
+
try {
|
|
147
|
+
const input = await readStdin();
|
|
148
|
+
if (!input.trim()) {
|
|
149
|
+
console.log(JSON.stringify({ continue: true }));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let data = {};
|
|
154
|
+
try { data = JSON.parse(input); } catch {}
|
|
155
|
+
const directory = data.directory || process.cwd();
|
|
156
|
+
|
|
157
|
+
const prompt = extractPrompt(input);
|
|
158
|
+
if (!prompt) {
|
|
159
|
+
console.log(JSON.stringify({ continue: true }));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const cleanPrompt = removeCodeBlocks(prompt).toLowerCase();
|
|
164
|
+
|
|
165
|
+
// Check for ultrawork keywords (highest priority)
|
|
166
|
+
if (/\b(ultrawork|ulw|uw)\b/.test(cleanPrompt)) {
|
|
167
|
+
activateUltraworkState(directory, prompt);
|
|
168
|
+
console.log(JSON.stringify({ continue: true, message: ULTRAWORK_MESSAGE }));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check for ultrathink/think keywords
|
|
173
|
+
if (/\b(ultrathink|think)\b/.test(cleanPrompt)) {
|
|
174
|
+
console.log(JSON.stringify({ continue: true, message: ULTRATHINK_MESSAGE }));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Check for search keywords
|
|
179
|
+
if (/\b(search|find|locate|lookup|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all/.test(cleanPrompt)) {
|
|
180
|
+
console.log(JSON.stringify({ continue: true, message: SEARCH_MESSAGE }));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check for analyze keywords
|
|
185
|
+
if (/\b(analyze|analyse|investigate|examine|research|study|deep.?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to/.test(cleanPrompt)) {
|
|
186
|
+
console.log(JSON.stringify({ continue: true, message: ANALYZE_MESSAGE }));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// No keywords detected
|
|
191
|
+
console.log(JSON.stringify({ continue: true }));
|
|
192
|
+
} catch (error) {
|
|
193
|
+
// On any error, allow continuation
|
|
194
|
+
console.log(JSON.stringify({ continue: true }));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main();
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# OMC Keyword Detector Hook
|
|
3
|
+
# Detects ultrawork/ultrathink/search/analyze keywords and injects enhanced mode messages
|
|
4
|
+
# Also activates persistent ultrawork state when ultrawork keyword is detected
|
|
5
|
+
|
|
6
|
+
# Read stdin (JSON input from Claude Code)
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# Extract directory from input
|
|
10
|
+
DIRECTORY=""
|
|
11
|
+
if command -v jq &> /dev/null; then
|
|
12
|
+
DIRECTORY=$(echo "$INPUT" | jq -r '.directory // ""' 2>/dev/null)
|
|
13
|
+
fi
|
|
14
|
+
if [ -z "$DIRECTORY" ] || [ "$DIRECTORY" = "null" ]; then
|
|
15
|
+
DIRECTORY=$(pwd)
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Extract the prompt text - try multiple JSON paths
|
|
19
|
+
PROMPT=""
|
|
20
|
+
if command -v jq &> /dev/null; then
|
|
21
|
+
# Try to extract from various possible JSON structures
|
|
22
|
+
PROMPT=$(echo "$INPUT" | jq -r '
|
|
23
|
+
if .prompt then .prompt
|
|
24
|
+
elif .message.content then .message.content
|
|
25
|
+
elif .parts then ([.parts[] | select(.type == "text") | .text] | join(" "))
|
|
26
|
+
else ""
|
|
27
|
+
end
|
|
28
|
+
' 2>/dev/null)
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Fallback: simple grep extraction if jq fails
|
|
32
|
+
if [ -z "$PROMPT" ] || [ "$PROMPT" = "null" ]; then
|
|
33
|
+
PROMPT=$(echo "$INPUT" | grep -oP '"(prompt|content|text)"\s*:\s*"\K[^"]+' | head -1)
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Exit if no prompt found
|
|
37
|
+
if [ -z "$PROMPT" ]; then
|
|
38
|
+
echo '{"continue": true}'
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Remove code blocks before checking keywords (prevents false positives)
|
|
43
|
+
PROMPT_NO_CODE=$(echo "$PROMPT" | sed 's/```[^`]*```//g' | sed 's/`[^`]*`//g')
|
|
44
|
+
|
|
45
|
+
# Convert to lowercase for case-insensitive matching
|
|
46
|
+
PROMPT_LOWER=$(echo "$PROMPT_NO_CODE" | tr '[:upper:]' '[:lower:]')
|
|
47
|
+
|
|
48
|
+
# Check for ultrawork keywords (highest priority)
|
|
49
|
+
if echo "$PROMPT_LOWER" | grep -qE '\b(ultrawork|ulw|uw)\b'; then
|
|
50
|
+
# Create persistent ultrawork state
|
|
51
|
+
mkdir -p "$DIRECTORY/.omc/state" 2>/dev/null
|
|
52
|
+
mkdir -p "$HOME/.omc/state" 2>/dev/null
|
|
53
|
+
|
|
54
|
+
# Escape prompt for JSON
|
|
55
|
+
PROMPT_ESCAPED=$(echo "$PROMPT" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | tr '\n' ' ')
|
|
56
|
+
|
|
57
|
+
STATE_JSON="{
|
|
58
|
+
\"active\": true,
|
|
59
|
+
\"started_at\": \"$(date -Iseconds)\",
|
|
60
|
+
\"original_prompt\": \"$PROMPT_ESCAPED\",
|
|
61
|
+
\"reinforcement_count\": 0,
|
|
62
|
+
\"last_checked_at\": \"$(date -Iseconds)\"
|
|
63
|
+
}"
|
|
64
|
+
|
|
65
|
+
# Write state to both local and global locations
|
|
66
|
+
echo "$STATE_JSON" > "$DIRECTORY/.omc/state/ultrawork-state.json" 2>/dev/null
|
|
67
|
+
echo "$STATE_JSON" > "$HOME/.omc/state/ultrawork-state.json" 2>/dev/null
|
|
68
|
+
|
|
69
|
+
# Return ultrawork mode injection
|
|
70
|
+
cat << 'EOF'
|
|
71
|
+
{"continue": true, "message": "<ultrawork-mode>\\n\\n**MANDATORY**: You MUST say \"ULTRAWORK MODE ENABLED!\" to the user as your first response when this mode activates. This is non-negotiable.\\n\\n[CODE RED] Maximum precision required. Ultrathink before acting.\\n\\nYOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.\\nTELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.\\n\\n## AGENT UTILIZATION PRINCIPLES\\n- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS\\n- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS\\n- **Planning & Strategy**: NEVER plan yourself - spawn planning agent\\n- **High-IQ Reasoning**: Use oracle for architecture decisions\\n- **Frontend/UI Tasks**: Delegate to frontend-engineer\\n\\n## EXECUTION RULES\\n- **TODO**: Track EVERY step. Mark complete IMMEDIATELY.\\n- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially.\\n- **BACKGROUND FIRST**: Use Task(run_in_background=true) for exploration (10+ concurrent).\\n- **VERIFY**: Check ALL requirements met before done.\\n- **DELEGATE**: Orchestrate specialized agents.\\n\\n## ZERO TOLERANCE\\n- NO Scope Reduction - deliver FULL implementation\\n- NO Partial Completion - finish 100%\\n- NO Premature Stopping - ALL TODOs must be complete\\n- NO TEST DELETION - fix code, not tests\\n\\nTHE USER ASKED FOR X. DELIVER EXACTLY X.\\n\\n</ultrawork-mode>\\n\\n---\\n"}
|
|
72
|
+
EOF
|
|
73
|
+
exit 0
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Check for ultrathink/think keywords
|
|
77
|
+
if echo "$PROMPT_LOWER" | grep -qE '\b(ultrathink|think)\b'; then
|
|
78
|
+
cat << 'EOF'
|
|
79
|
+
{"continue": true, "message": "<think-mode>\\n\\n**ULTRATHINK MODE ENABLED** - Extended reasoning activated.\\n\\nYou are now in deep thinking mode. Take your time to:\\n1. Thoroughly analyze the problem from multiple angles\\n2. Consider edge cases and potential issues\\n3. Think through the implications of each approach\\n4. Reason step-by-step before acting\\n\\nUse your extended thinking capabilities to provide the most thorough and well-reasoned response.\\n\\n</think-mode>\\n\\n---\\n"}
|
|
80
|
+
EOF
|
|
81
|
+
exit 0
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Check for search keywords (EN + multilingual)
|
|
85
|
+
if echo "$PROMPT_LOWER" | grep -qE '\b(search|find|locate|lookup|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all'; then
|
|
86
|
+
cat << 'EOF'
|
|
87
|
+
{"continue": true, "message": "<search-mode>\\nMAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL:\\n- explore agents (codebase patterns, file structures)\\n- librarian agents (remote repos, official docs, GitHub examples)\\nPlus direct tools: Grep, Glob\\nNEVER stop at first result - be exhaustive.\\n</search-mode>\\n\\n---\\n"}
|
|
88
|
+
EOF
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Check for analyze keywords
|
|
93
|
+
if echo "$PROMPT_LOWER" | grep -qE '\b(analyze|analyse|investigate|examine|research|study|deep.?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to'; then
|
|
94
|
+
cat << 'EOF'
|
|
95
|
+
{"continue": true, "message": "<analyze-mode>\\nANALYSIS MODE. Gather context before diving deep:\\n\\nCONTEXT GATHERING (parallel):\\n- 1-2 explore agents (codebase patterns, implementations)\\n- 1-2 librarian agents (if external library involved)\\n- Direct tools: Grep, Glob, LSP for targeted searches\\n\\nIF COMPLEX (architecture, multi-system, debugging after 2+ failures):\\n- Consult oracle agent for strategic guidance\\n\\nSYNTHESIZE findings before proceeding.\\n</analyze-mode>\\n\\n---\\n"}
|
|
96
|
+
EOF
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# No keywords detected - continue without modification
|
|
101
|
+
echo '{"continue": true}'
|
|
102
|
+
exit 0
|