codekin 0.1.3
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.
Potentially problematic release.
This version of codekin might be problematic. Click here for more details.
- package/README.md +83 -0
- package/bin/codekin.mjs +372 -0
- package/dist/assets/index-BrKgETi_.css +1 -0
- package/dist/assets/index-C8gwtjTl.js +105 -0
- package/dist/data/repos.json +33 -0
- package/dist/favicon.svg +15 -0
- package/dist/index.html +14 -0
- package/package.json +53 -0
- package/server/dist/auth-routes.d.ts +12 -0
- package/server/dist/auth-routes.js +29 -0
- package/server/dist/auth-routes.js.map +1 -0
- package/server/dist/claude-process.d.ts +103 -0
- package/server/dist/claude-process.js +524 -0
- package/server/dist/claude-process.js.map +1 -0
- package/server/dist/config.d.ts +27 -0
- package/server/dist/config.js +54 -0
- package/server/dist/config.js.map +1 -0
- package/server/dist/crypto-utils.d.ts +12 -0
- package/server/dist/crypto-utils.js +22 -0
- package/server/dist/crypto-utils.js.map +1 -0
- package/server/dist/session-archive.d.ts +53 -0
- package/server/dist/session-archive.js +160 -0
- package/server/dist/session-archive.js.map +1 -0
- package/server/dist/session-manager.d.ts +226 -0
- package/server/dist/session-manager.js +1476 -0
- package/server/dist/session-manager.js.map +1 -0
- package/server/dist/session-routes.d.ts +12 -0
- package/server/dist/session-routes.js +207 -0
- package/server/dist/session-routes.js.map +1 -0
- package/server/dist/stepflow-handler.d.ts +141 -0
- package/server/dist/stepflow-handler.js +445 -0
- package/server/dist/stepflow-handler.js.map +1 -0
- package/server/dist/stepflow-prompt.d.ts +29 -0
- package/server/dist/stepflow-prompt.js +119 -0
- package/server/dist/stepflow-prompt.js.map +1 -0
- package/server/dist/stepflow-types.d.ts +249 -0
- package/server/dist/stepflow-types.js +30 -0
- package/server/dist/stepflow-types.js.map +1 -0
- package/server/dist/types.d.ts +362 -0
- package/server/dist/types.js +9 -0
- package/server/dist/types.js.map +1 -0
- package/server/dist/upload-routes.d.ts +12 -0
- package/server/dist/upload-routes.js +217 -0
- package/server/dist/upload-routes.js.map +1 -0
- package/server/dist/webhook-config.d.ts +9 -0
- package/server/dist/webhook-config.js +55 -0
- package/server/dist/webhook-config.js.map +1 -0
- package/server/dist/webhook-dedup.d.ts +21 -0
- package/server/dist/webhook-dedup.js +122 -0
- package/server/dist/webhook-dedup.js.map +1 -0
- package/server/dist/webhook-github.d.ts +50 -0
- package/server/dist/webhook-github.js +175 -0
- package/server/dist/webhook-github.js.map +1 -0
- package/server/dist/webhook-handler.d.ts +69 -0
- package/server/dist/webhook-handler.js +368 -0
- package/server/dist/webhook-handler.js.map +1 -0
- package/server/dist/webhook-prompt.d.ts +5 -0
- package/server/dist/webhook-prompt.js +67 -0
- package/server/dist/webhook-prompt.js.map +1 -0
- package/server/dist/webhook-rate-limiter.d.ts +30 -0
- package/server/dist/webhook-rate-limiter.js +78 -0
- package/server/dist/webhook-rate-limiter.js.map +1 -0
- package/server/dist/webhook-routes.d.ts +16 -0
- package/server/dist/webhook-routes.js +58 -0
- package/server/dist/webhook-routes.js.map +1 -0
- package/server/dist/webhook-types.d.ts +98 -0
- package/server/dist/webhook-types.js +2 -0
- package/server/dist/webhook-types.js.map +1 -0
- package/server/dist/webhook-workspace.d.ts +11 -0
- package/server/dist/webhook-workspace.js +124 -0
- package/server/dist/webhook-workspace.js.map +1 -0
- package/server/dist/workflow-config.d.ts +24 -0
- package/server/dist/workflow-config.js +66 -0
- package/server/dist/workflow-config.js.map +1 -0
- package/server/dist/workflow-engine.d.ts +130 -0
- package/server/dist/workflow-engine.js +529 -0
- package/server/dist/workflow-engine.js.map +1 -0
- package/server/dist/workflow-loader.d.ts +31 -0
- package/server/dist/workflow-loader.js +297 -0
- package/server/dist/workflow-loader.js.map +1 -0
- package/server/dist/workflow-routes.d.ts +14 -0
- package/server/dist/workflow-routes.js +222 -0
- package/server/dist/workflow-routes.js.map +1 -0
- package/server/dist/ws-server.d.ts +14 -0
- package/server/dist/ws-server.js +441 -0
- package/server/dist/ws-server.js.map +1 -0
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages a single Claude CLI child process using stream-json protocol.
|
|
3
|
+
*
|
|
4
|
+
* Spawns `claude` with --output-format stream-json --input-format stream-json,
|
|
5
|
+
* parses the NDJSON stdout line by line, and emits typed events for:
|
|
6
|
+
* - Streaming text deltas (batched from content_block_delta events)
|
|
7
|
+
* - Tool lifecycle (active → done with input summary)
|
|
8
|
+
* - Extended thinking (first-sentence summary extraction)
|
|
9
|
+
* - Permission prompts and control requests
|
|
10
|
+
* - Task/todo tracking (TodoWrite, TaskCreate, TaskUpdate)
|
|
11
|
+
* - Turn results and process exit
|
|
12
|
+
*/
|
|
13
|
+
import { spawn } from 'child_process';
|
|
14
|
+
import { createInterface } from 'readline';
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import { randomUUID } from 'crypto';
|
|
17
|
+
import { homedir } from 'os';
|
|
18
|
+
import { SCREENSHOTS_DIR } from './config.js';
|
|
19
|
+
/**
|
|
20
|
+
* Wraps a Claude CLI child process. Parses stream-json NDJSON output from
|
|
21
|
+
* stdout and emits structured events consumed by SessionManager.
|
|
22
|
+
*/
|
|
23
|
+
export class ClaudeProcess extends EventEmitter {
|
|
24
|
+
workingDir;
|
|
25
|
+
model;
|
|
26
|
+
proc = null;
|
|
27
|
+
rl = null;
|
|
28
|
+
sessionId;
|
|
29
|
+
alive = false;
|
|
30
|
+
// Tool tracking: accumulates partial_json input during streaming
|
|
31
|
+
currentToolName = null;
|
|
32
|
+
currentToolInput = '';
|
|
33
|
+
textBuffer = '';
|
|
34
|
+
// Extended thinking: extract a short summary from the thinking block
|
|
35
|
+
inThinkingBlock = false;
|
|
36
|
+
thinkingText = '';
|
|
37
|
+
thinkingSummaryEmitted = false;
|
|
38
|
+
// Deferred ExitPlanMode: only emit planning_mode false after tool_result confirms success.
|
|
39
|
+
// Stores the tool_use_id from content_block_start so we can match it in the tool_result.
|
|
40
|
+
pendingExitPlanModeId = null;
|
|
41
|
+
// Task/todo state: mirrors Claude's internal todo list for the UI
|
|
42
|
+
tasks = new Map();
|
|
43
|
+
taskSeq = 0;
|
|
44
|
+
/** Additional env vars passed to the child process (session ID, port, token). */
|
|
45
|
+
extraEnv;
|
|
46
|
+
constructor(workingDir, sessionId, extraEnv, model) {
|
|
47
|
+
super();
|
|
48
|
+
this.workingDir = workingDir;
|
|
49
|
+
this.model = model;
|
|
50
|
+
this.sessionId = sessionId || randomUUID();
|
|
51
|
+
this.extraEnv = extraEnv || {};
|
|
52
|
+
}
|
|
53
|
+
/** Spawn the Claude CLI process with stream-json I/O and acceptEdits mode. */
|
|
54
|
+
start() {
|
|
55
|
+
if (this.proc)
|
|
56
|
+
return;
|
|
57
|
+
const env = {
|
|
58
|
+
PATH: process.env.PATH || '/usr/local/bin:/usr/bin:/bin',
|
|
59
|
+
HOME: process.env.HOME || homedir(),
|
|
60
|
+
USER: process.env.USER || 'dev',
|
|
61
|
+
LANG: process.env.LANG || 'en_US.UTF-8',
|
|
62
|
+
...this.extraEnv,
|
|
63
|
+
};
|
|
64
|
+
// Pass through third-party API keys for skills (validate-gemini, validate-gpt).
|
|
65
|
+
// Do NOT pass ANTHROPIC_API_KEY / CLAUDE_CODE_API_KEY — let the CLI use the
|
|
66
|
+
// user's authenticated Max plan instead of billing via API.
|
|
67
|
+
for (const key of ['GEMINI_API_KEY', 'OPENAI_API_KEY', 'OPENAI_MODEL', 'GEMINI_MODEL']) {
|
|
68
|
+
if (process.env[key])
|
|
69
|
+
env[key] = process.env[key];
|
|
70
|
+
}
|
|
71
|
+
// Suppress Node.js deprecation warnings in child tools
|
|
72
|
+
env.NODE_NO_WARNINGS = '1';
|
|
73
|
+
const args = [
|
|
74
|
+
'--output-format', 'stream-json',
|
|
75
|
+
'--input-format', 'stream-json',
|
|
76
|
+
'--permission-mode', 'acceptEdits',
|
|
77
|
+
'--allowedTools', 'Bash(git:*)',
|
|
78
|
+
'--add-dir', SCREENSHOTS_DIR,
|
|
79
|
+
'--include-partial-messages',
|
|
80
|
+
'--verbose',
|
|
81
|
+
'--session-id', this.sessionId,
|
|
82
|
+
...(this.model ? ['--model', this.model] : []),
|
|
83
|
+
'--append-system-prompt', [
|
|
84
|
+
'You are running inside a web-based terminal (Codekin).',
|
|
85
|
+
'Tool permissions are managed by the system through an approval hook.',
|
|
86
|
+
'File operations (Read, Write, Edit, Glob, Grep) are pre-approved and work without prompts.',
|
|
87
|
+
'Bash commands may require user approval — the system handles this automatically via a UI prompt.',
|
|
88
|
+
'Do not tell the user to click approve or grant permission. Just proceed with your work.',
|
|
89
|
+
'If a tool call fails, read the error message carefully. Common causes: wrong file path, missing dependency, syntax error, or network issue.',
|
|
90
|
+
].join(' '),
|
|
91
|
+
];
|
|
92
|
+
console.log(`[claude-spawn] cwd=${this.workingDir} args=${JSON.stringify(args)}`);
|
|
93
|
+
this.proc = spawn('claude', args, {
|
|
94
|
+
cwd: this.workingDir,
|
|
95
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
96
|
+
env,
|
|
97
|
+
});
|
|
98
|
+
this.alive = true;
|
|
99
|
+
this.rl = createInterface({ input: this.proc.stdout });
|
|
100
|
+
this.rl.on('line', (line) => this.handleLine(line));
|
|
101
|
+
this.proc.stderr.on('data', (data) => {
|
|
102
|
+
const text = data.toString().trim();
|
|
103
|
+
console.error('[claude stderr]', text);
|
|
104
|
+
if (text)
|
|
105
|
+
this.emit('error', `[stderr] ${text.slice(0, 500)}`);
|
|
106
|
+
});
|
|
107
|
+
this.proc.on('error', (err) => {
|
|
108
|
+
console.error('[claude process error]', err.message);
|
|
109
|
+
this.emit('error', err.message);
|
|
110
|
+
});
|
|
111
|
+
this.proc.on('close', (code, signal) => {
|
|
112
|
+
this.alive = false;
|
|
113
|
+
this.rl?.close();
|
|
114
|
+
this.rl = null;
|
|
115
|
+
this.proc = null;
|
|
116
|
+
this.tasks.clear();
|
|
117
|
+
this.emit('exit', code, signal);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/** Parse a single NDJSON line from Claude's stdout and dispatch to the appropriate handler. */
|
|
121
|
+
handleLine(line) {
|
|
122
|
+
let event;
|
|
123
|
+
try {
|
|
124
|
+
event = JSON.parse(line);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
console.warn(`[claude stdout] unparseable line: ${line.slice(0, 200)}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.emit('event', event);
|
|
131
|
+
// Log non-streaming event types for diagnostics
|
|
132
|
+
if (event.type !== 'stream_event') {
|
|
133
|
+
const subtype = 'subtype' in event ? event.subtype : '-';
|
|
134
|
+
console.log(`[event] type=${event.type} subtype=${subtype || '-'}`);
|
|
135
|
+
}
|
|
136
|
+
// Log all event types we DON'T handle to catch unknown protocol messages
|
|
137
|
+
if (!['system', 'stream_event', 'assistant', 'user', 'result', 'control_request', 'rate_limit_event'].includes(event.type)) {
|
|
138
|
+
console.log(`[event-unhandled] type=${event.type} data=${JSON.stringify(event).slice(0, 300)}`);
|
|
139
|
+
}
|
|
140
|
+
switch (event.type) {
|
|
141
|
+
case 'system':
|
|
142
|
+
if (event.subtype === 'init') {
|
|
143
|
+
this.sessionId = event.session_id || this.sessionId;
|
|
144
|
+
const model = ('model' in event ? event.model : 'unknown');
|
|
145
|
+
this.emit('system_init', model);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
case 'stream_event':
|
|
149
|
+
this.handleStreamEvent(event);
|
|
150
|
+
break;
|
|
151
|
+
case 'assistant':
|
|
152
|
+
this.handleAssistantMessage();
|
|
153
|
+
break;
|
|
154
|
+
case 'user':
|
|
155
|
+
this.handleUserEvent(event);
|
|
156
|
+
break;
|
|
157
|
+
case 'result': {
|
|
158
|
+
const resultEvent = event;
|
|
159
|
+
this.emit('result', resultEvent.result || '', resultEvent.is_error || false);
|
|
160
|
+
// The result message signals end of turn, ready for next input
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'control_request': {
|
|
164
|
+
const ctrlEvent = event;
|
|
165
|
+
console.log(`[control_request] requestId=${ctrlEvent.request_id} tool=${ctrlEvent.request?.tool_name}`);
|
|
166
|
+
this.handleControlRequest(ctrlEvent);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Process incremental stream events (content_block_start/delta/stop).
|
|
173
|
+
* Handles text deltas, tool input accumulation, thinking blocks, and
|
|
174
|
+
* planning mode detection.
|
|
175
|
+
*/
|
|
176
|
+
handleStreamEvent(event) {
|
|
177
|
+
const inner = event.event;
|
|
178
|
+
if (!inner)
|
|
179
|
+
return;
|
|
180
|
+
switch (inner.type) {
|
|
181
|
+
case 'content_block_start':
|
|
182
|
+
if (inner.content_block?.type === 'tool_use') {
|
|
183
|
+
this.currentToolName = inner.content_block.name || null;
|
|
184
|
+
this.currentToolInput = '';
|
|
185
|
+
console.log('[tool-debug] tool_start:', this.currentToolName);
|
|
186
|
+
// Detect planning mode tools
|
|
187
|
+
if (this.currentToolName === 'EnterPlanMode') {
|
|
188
|
+
this.emit('planning_mode', true);
|
|
189
|
+
}
|
|
190
|
+
else if (this.currentToolName === 'ExitPlanMode') {
|
|
191
|
+
// Defer planning_mode false until tool_result confirms the tool was allowed.
|
|
192
|
+
// The PreToolUse hook prompts the user for approval; if denied, we should
|
|
193
|
+
// NOT show "Exited plan mode". Use tool_use id for matching; fall back to
|
|
194
|
+
// a sentinel so the flag-based check in handleUserEvent still works.
|
|
195
|
+
this.pendingExitPlanModeId = inner.content_block.id || '__pending__';
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this.emit('tool_active', this.currentToolName, undefined);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (inner.content_block?.type === 'thinking') {
|
|
202
|
+
this.inThinkingBlock = true;
|
|
203
|
+
this.thinkingText = '';
|
|
204
|
+
this.thinkingSummaryEmitted = false;
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case 'content_block_delta':
|
|
208
|
+
if (inner.delta?.type === 'text_delta' && inner.delta.text) {
|
|
209
|
+
this.emit('text', inner.delta.text);
|
|
210
|
+
}
|
|
211
|
+
else if (inner.delta?.type === 'input_json_delta' && inner.delta.partial_json) {
|
|
212
|
+
this.currentToolInput += inner.delta.partial_json;
|
|
213
|
+
}
|
|
214
|
+
else if (inner.delta?.type === 'thinking_delta' && inner.delta.thinking && this.inThinkingBlock) {
|
|
215
|
+
this.thinkingText += inner.delta.thinking;
|
|
216
|
+
if (!this.thinkingSummaryEmitted) {
|
|
217
|
+
const summary = this.extractThinkingSummary(this.thinkingText);
|
|
218
|
+
if (summary) {
|
|
219
|
+
this.thinkingSummaryEmitted = true;
|
|
220
|
+
this.emit('thinking', summary);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
break;
|
|
225
|
+
case 'content_block_stop':
|
|
226
|
+
if (this.inThinkingBlock) {
|
|
227
|
+
// Emit summary if we didn't get enough text earlier
|
|
228
|
+
if (!this.thinkingSummaryEmitted && this.thinkingText.length > 0) {
|
|
229
|
+
const summary = this.extractThinkingSummary(this.thinkingText) || this.thinkingText.slice(0, 80).trim();
|
|
230
|
+
this.emit('thinking', summary);
|
|
231
|
+
}
|
|
232
|
+
this.inThinkingBlock = false;
|
|
233
|
+
this.thinkingText = '';
|
|
234
|
+
this.thinkingSummaryEmitted = false;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
if (this.currentToolName) {
|
|
238
|
+
// Parse tool input and emit structured tool_done with summary
|
|
239
|
+
let summary;
|
|
240
|
+
try {
|
|
241
|
+
const parsed = JSON.parse(this.currentToolInput);
|
|
242
|
+
summary = this.summarizeToolInput(this.currentToolName, parsed) || undefined;
|
|
243
|
+
// Handle task tools
|
|
244
|
+
const isTask = this.currentToolName === 'TaskCreate' || this.currentToolName === 'TaskUpdate' || this.currentToolName === 'TodoWrite' || this.currentToolName === 'TodoRead';
|
|
245
|
+
if (isTask)
|
|
246
|
+
console.log('[task-debug] tool:', this.currentToolName, 'input:', JSON.stringify(parsed).slice(0, 200));
|
|
247
|
+
if (this.handleTaskTool(this.currentToolName, parsed)) {
|
|
248
|
+
console.log('[task-debug] emitting todo_update, tasks:', this.tasks.size);
|
|
249
|
+
this.emit('todo_update', Array.from(this.tasks.values()));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch { /* ignore parse errors */ }
|
|
253
|
+
this.emit('tool_done', this.currentToolName, summary);
|
|
254
|
+
this.currentToolName = null;
|
|
255
|
+
this.currentToolInput = '';
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/** No-op: assistant messages are handled via stream_event deltas instead. */
|
|
261
|
+
handleAssistantMessage() {
|
|
262
|
+
// assistant events with --include-partial-messages contain tool_use blocks
|
|
263
|
+
// but tool_results come in separate 'user' events — see handleUserEvent
|
|
264
|
+
}
|
|
265
|
+
/** Extract tool_result blocks from 'user' events and emit as tool_output. */
|
|
266
|
+
handleUserEvent(event) {
|
|
267
|
+
const msg = event.message;
|
|
268
|
+
if (!msg?.content)
|
|
269
|
+
return;
|
|
270
|
+
const blocks = Array.isArray(msg.content) ? msg.content : [];
|
|
271
|
+
for (const block of blocks) {
|
|
272
|
+
if (block.type === 'tool_result') {
|
|
273
|
+
const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
274
|
+
const isError = block.is_error === true;
|
|
275
|
+
console.log(`[tool-result] id=${block.tool_use_id} error=${isError} content=${content.slice(0, 300)}`);
|
|
276
|
+
// Deferred ExitPlanMode: emit planning_mode only after tool_result confirms success.
|
|
277
|
+
// Match by tool_use_id, or use flag-based fallback when id wasn't available.
|
|
278
|
+
if (this.pendingExitPlanModeId &&
|
|
279
|
+
(block.tool_use_id === this.pendingExitPlanModeId || this.pendingExitPlanModeId === '__pending__')) {
|
|
280
|
+
this.pendingExitPlanModeId = null;
|
|
281
|
+
if (!isError) {
|
|
282
|
+
this.emit('planning_mode', false);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Emit non-empty tool results as dedicated tool_output events
|
|
286
|
+
if (content.trim()) {
|
|
287
|
+
const truncated = content.length > 2000
|
|
288
|
+
? content.slice(0, 2000) + `\n… (truncated, ${content.length} chars total)`
|
|
289
|
+
: content;
|
|
290
|
+
this.emit('tool_output', truncated, isError);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Handle a control_request from the CLI.
|
|
297
|
+
* With acceptEdits mode + PermissionRequest hook, most permissions go through hooks.
|
|
298
|
+
* This handler remains as fallback and for AskUserQuestion (which uses control_request
|
|
299
|
+
* for user interaction, not permissions).
|
|
300
|
+
*/
|
|
301
|
+
handleControlRequest(event) {
|
|
302
|
+
const { request_id, request } = event;
|
|
303
|
+
const toolName = request.tool_name;
|
|
304
|
+
const toolInput = request.input;
|
|
305
|
+
if (toolName === 'AskUserQuestion') {
|
|
306
|
+
// Parse questions from input and emit as a single prompt with all questions bundled.
|
|
307
|
+
// Each question has its own options and multiSelect flag; the frontend
|
|
308
|
+
// walks the user through them one-by-one and returns all answers at once.
|
|
309
|
+
const questions = toolInput?.questions;
|
|
310
|
+
if (!Array.isArray(questions) || questions.length === 0)
|
|
311
|
+
return;
|
|
312
|
+
const structuredQuestions = questions.map(q => ({
|
|
313
|
+
question: q.question,
|
|
314
|
+
header: q.header,
|
|
315
|
+
multiSelect: q.multiSelect ?? false,
|
|
316
|
+
options: (q.options || []).map((opt) => ({
|
|
317
|
+
label: opt.label,
|
|
318
|
+
value: opt.label,
|
|
319
|
+
description: opt.description,
|
|
320
|
+
})),
|
|
321
|
+
}));
|
|
322
|
+
// Emit a single prompt with the first question's options for display,
|
|
323
|
+
// plus the full questions array for the multi-question flow
|
|
324
|
+
const first = structuredQuestions[0];
|
|
325
|
+
this.emit('prompt', 'question', first.question, first.options, first.multiSelect, undefined, toolInput, request_id, structuredQuestions);
|
|
326
|
+
}
|
|
327
|
+
else if (toolName === 'ExitPlanMode') {
|
|
328
|
+
// ExitPlanMode needs user confirmation — forward to UI as a prompt
|
|
329
|
+
console.log(`[control_request] forwarding ExitPlanMode to session manager for user approval`);
|
|
330
|
+
this.emit('control_request', request_id, toolName, toolInput);
|
|
331
|
+
}
|
|
332
|
+
else if (toolName === 'Bash') {
|
|
333
|
+
// Bash runs arbitrary commands — forward to session manager for registry check / UI prompt
|
|
334
|
+
console.log(`[control_request] forwarding Bash to session manager: ${String(toolInput.command || '').slice(0, 80)}`);
|
|
335
|
+
this.emit('control_request', request_id, toolName, toolInput);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
// All other tools (Write, Edit, Read, Glob, Grep, Task, TodoWrite,
|
|
339
|
+
// EnterPlanMode, etc.) are safe — auto-approve
|
|
340
|
+
console.log(`[control_request] auto-approving: ${toolName}`);
|
|
341
|
+
this.sendControlResponse(request_id, 'allow');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
/** Send a control_response back to the CLI to allow or deny a pending request. */
|
|
345
|
+
sendControlResponse(requestId, behavior, updatedInput, message) {
|
|
346
|
+
const response = {
|
|
347
|
+
type: 'control_response',
|
|
348
|
+
request_id: requestId,
|
|
349
|
+
behavior,
|
|
350
|
+
};
|
|
351
|
+
if (updatedInput !== undefined)
|
|
352
|
+
response.updatedInput = updatedInput;
|
|
353
|
+
if (message !== undefined)
|
|
354
|
+
response.message = message;
|
|
355
|
+
this.sendRaw(JSON.stringify(response));
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Update internal task state from TodoWrite/TaskCreate/TaskUpdate tool calls.
|
|
359
|
+
* Returns true if the task list changed (caller should emit todo_update).
|
|
360
|
+
*/
|
|
361
|
+
handleTaskTool(toolName, input) {
|
|
362
|
+
// TodoWrite sends the entire list at once
|
|
363
|
+
if (toolName === 'TodoWrite') {
|
|
364
|
+
const todos = input.todos;
|
|
365
|
+
if (!Array.isArray(todos))
|
|
366
|
+
return false;
|
|
367
|
+
this.tasks.clear();
|
|
368
|
+
this.taskSeq = 0;
|
|
369
|
+
for (const item of todos) {
|
|
370
|
+
const id = String(item.id || ++this.taskSeq);
|
|
371
|
+
const status = item.status;
|
|
372
|
+
if (status !== 'pending' && status !== 'in_progress' && status !== 'completed')
|
|
373
|
+
continue;
|
|
374
|
+
this.tasks.set(id, {
|
|
375
|
+
id,
|
|
376
|
+
subject: String(item.content || item.subject || ''),
|
|
377
|
+
status,
|
|
378
|
+
activeForm: item.activeForm ? String(item.activeForm) : undefined,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
// TaskCreate/TaskUpdate are the newer tool names
|
|
384
|
+
if (toolName === 'TaskCreate') {
|
|
385
|
+
const id = String(++this.taskSeq);
|
|
386
|
+
this.tasks.set(id, {
|
|
387
|
+
id,
|
|
388
|
+
subject: String(input.subject || ''),
|
|
389
|
+
status: 'pending',
|
|
390
|
+
activeForm: input.activeForm ? String(input.activeForm) : undefined,
|
|
391
|
+
});
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
if (toolName === 'TaskUpdate') {
|
|
395
|
+
const id = String(input.taskId || '');
|
|
396
|
+
const task = this.tasks.get(id);
|
|
397
|
+
if (!task)
|
|
398
|
+
return false;
|
|
399
|
+
const status = input.status;
|
|
400
|
+
if (status === 'deleted') {
|
|
401
|
+
this.tasks.delete(id);
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
if (status === 'pending' || status === 'in_progress' || status === 'completed') {
|
|
405
|
+
task.status = status;
|
|
406
|
+
}
|
|
407
|
+
if (input.subject)
|
|
408
|
+
task.subject = String(input.subject);
|
|
409
|
+
if (input.activeForm !== undefined)
|
|
410
|
+
task.activeForm = input.activeForm ? String(input.activeForm) : undefined;
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Extract a short summary from extended thinking text.
|
|
417
|
+
* Tries to grab the first sentence (up to 120 chars), or truncates at a
|
|
418
|
+
* word boundary if no sentence ending is found after 60+ chars.
|
|
419
|
+
*/
|
|
420
|
+
extractThinkingSummary(text) {
|
|
421
|
+
if (text.length < 20)
|
|
422
|
+
return null;
|
|
423
|
+
// Try to extract the first sentence (up to ~100 chars)
|
|
424
|
+
const match = text.match(/^(.+?[.!?\n])/);
|
|
425
|
+
if (match && match[1].length <= 120) {
|
|
426
|
+
return match[1].replace(/\n/g, ' ').trim();
|
|
427
|
+
}
|
|
428
|
+
// If no sentence boundary yet but we have enough text, truncate to word boundary
|
|
429
|
+
if (text.length >= 60) {
|
|
430
|
+
const truncated = text.slice(0, 80);
|
|
431
|
+
const lastSpace = truncated.lastIndexOf(' ');
|
|
432
|
+
return (lastSpace > 20 ? truncated.slice(0, lastSpace) : truncated).trim();
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
/** Generate a short human-readable summary of a tool invocation for the UI chip. */
|
|
437
|
+
summarizeToolInput(toolName, input) {
|
|
438
|
+
switch (toolName) {
|
|
439
|
+
case 'Bash': {
|
|
440
|
+
const cmd = String(input.command || '');
|
|
441
|
+
// Truncate long commands to first line
|
|
442
|
+
const firstLine = cmd.split('\n')[0];
|
|
443
|
+
return firstLine.length < cmd.length ? `$ ${firstLine}...` : `$ ${cmd}`;
|
|
444
|
+
}
|
|
445
|
+
case 'Read':
|
|
446
|
+
return String(input.file_path || '');
|
|
447
|
+
case 'Write':
|
|
448
|
+
case 'Edit':
|
|
449
|
+
return String(input.file_path || '');
|
|
450
|
+
case 'Glob':
|
|
451
|
+
return String(input.pattern || '');
|
|
452
|
+
case 'Grep':
|
|
453
|
+
return String(input.pattern || '');
|
|
454
|
+
case 'Task':
|
|
455
|
+
return String(input.description || '');
|
|
456
|
+
case 'EnterPlanMode':
|
|
457
|
+
return 'Entering plan mode';
|
|
458
|
+
case 'ExitPlanMode':
|
|
459
|
+
return 'Exiting plan mode';
|
|
460
|
+
case 'TaskCreate':
|
|
461
|
+
return String(input.subject || '');
|
|
462
|
+
case 'TaskUpdate':
|
|
463
|
+
return `#${input.taskId || ''} → ${input.status || ''}`;
|
|
464
|
+
case 'TaskList':
|
|
465
|
+
return 'Listing tasks';
|
|
466
|
+
case 'TaskGet':
|
|
467
|
+
return `#${input.taskId || ''}`;
|
|
468
|
+
case 'TodoWrite': {
|
|
469
|
+
const todos = input.todos;
|
|
470
|
+
return todos ? `${todos.length} tasks` : '';
|
|
471
|
+
}
|
|
472
|
+
case 'TodoRead':
|
|
473
|
+
return 'Reading tasks';
|
|
474
|
+
default:
|
|
475
|
+
return '';
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/** Send a user message to the Claude CLI via stdin (stream-json format). */
|
|
479
|
+
sendMessage(content) {
|
|
480
|
+
if (!this.proc?.stdin?.writable) {
|
|
481
|
+
this.emit('error', 'Claude process stdin is not writable');
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const msg = JSON.stringify({
|
|
485
|
+
type: 'user',
|
|
486
|
+
message: {
|
|
487
|
+
role: 'user',
|
|
488
|
+
content,
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
const ok = this.proc.stdin.write(msg + '\n');
|
|
492
|
+
if (!ok) {
|
|
493
|
+
this.proc.stdin.once('drain', () => { });
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/** Write raw data to stdin (used for control_response messages). */
|
|
497
|
+
sendRaw(data) {
|
|
498
|
+
if (!this.proc?.stdin?.writable)
|
|
499
|
+
return;
|
|
500
|
+
const ok = this.proc.stdin.write(data + '\n');
|
|
501
|
+
if (!ok) {
|
|
502
|
+
this.proc.stdin.once('drain', () => { });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** Gracefully stop the process (SIGTERM, then SIGKILL after 5s timeout). */
|
|
506
|
+
stop() {
|
|
507
|
+
if (this.proc) {
|
|
508
|
+
this.proc.kill('SIGTERM');
|
|
509
|
+
// Force kill after 5 seconds
|
|
510
|
+
setTimeout(() => {
|
|
511
|
+
if (this.proc) {
|
|
512
|
+
this.proc.kill('SIGKILL');
|
|
513
|
+
}
|
|
514
|
+
}, 5000);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
isAlive() {
|
|
518
|
+
return this.alive;
|
|
519
|
+
}
|
|
520
|
+
getSessionId() {
|
|
521
|
+
return this.sessionId;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
//# sourceMappingURL=claude-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-process.js","sourceRoot":"","sources":["../claude-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized configuration for the Codekin server.
|
|
3
|
+
*
|
|
4
|
+
* All hardcoded paths, ports, and settings are replaced with environment
|
|
5
|
+
* variables that have sensible defaults for bare-metal (dev) and can be
|
|
6
|
+
* overridden in Docker / production environments.
|
|
7
|
+
*/
|
|
8
|
+
/** Main server port (WebSocket + REST + uploads). */
|
|
9
|
+
export declare const PORT: number;
|
|
10
|
+
/** CORS allowed origin. */
|
|
11
|
+
export declare const CORS_ORIGIN: string;
|
|
12
|
+
export declare const AUTH_TOKEN: string;
|
|
13
|
+
/** Root directory for cloned repositories. */
|
|
14
|
+
export declare const REPOS_ROOT: string;
|
|
15
|
+
/** Codekin data directory (sessions, approvals, workflows, etc.). */
|
|
16
|
+
export declare const DATA_DIR: string;
|
|
17
|
+
/** Directory for uploaded screenshots / file attachments. */
|
|
18
|
+
export declare const SCREENSHOTS_DIR: string;
|
|
19
|
+
/**
|
|
20
|
+
* Path to the built frontend dist directory.
|
|
21
|
+
* When set and the directory exists, the server serves the frontend via express.static,
|
|
22
|
+
* removing the need for nginx inside a Docker container.
|
|
23
|
+
* Bare-metal deploys can leave this unset and continue using nginx.
|
|
24
|
+
*/
|
|
25
|
+
export declare const FRONTEND_DIST: string;
|
|
26
|
+
/** GitHub organizations for repo listing (comma-separated). Empty string disables org listing. */
|
|
27
|
+
export declare const GH_ORGS: string[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized configuration for the Codekin server.
|
|
3
|
+
*
|
|
4
|
+
* All hardcoded paths, ports, and settings are replaced with environment
|
|
5
|
+
* variables that have sensible defaults for bare-metal (dev) and can be
|
|
6
|
+
* overridden in Docker / production environments.
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { readFileSync, existsSync } from 'fs';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Network
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/** Main server port (WebSocket + REST + uploads). */
|
|
15
|
+
export const PORT = parseInt(process.env.PORT || '32352', 10);
|
|
16
|
+
/** CORS allowed origin. */
|
|
17
|
+
export const CORS_ORIGIN = process.env.CORS_ORIGIN || '*';
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Authentication
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/**
|
|
22
|
+
* Auth token for the server. Loaded from AUTH_TOKEN env var, or falls back
|
|
23
|
+
* to reading from AUTH_TOKEN_FILE (legacy --auth-file behavior).
|
|
24
|
+
*/
|
|
25
|
+
function loadAuthToken() {
|
|
26
|
+
if (process.env.AUTH_TOKEN)
|
|
27
|
+
return process.env.AUTH_TOKEN;
|
|
28
|
+
// Legacy: read from file path (bare-metal deploy compat)
|
|
29
|
+
const tokenFile = process.env.AUTH_TOKEN_FILE || '';
|
|
30
|
+
if (tokenFile && existsSync(tokenFile)) {
|
|
31
|
+
return readFileSync(tokenFile, 'utf-8').trim();
|
|
32
|
+
}
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
export const AUTH_TOKEN = loadAuthToken();
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Paths
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/** Root directory for cloned repositories. */
|
|
40
|
+
export const REPOS_ROOT = process.env.REPOS_ROOT || join(homedir(), 'repos');
|
|
41
|
+
/** Codekin data directory (sessions, approvals, workflows, etc.). */
|
|
42
|
+
export const DATA_DIR = process.env.DATA_DIR || join(homedir(), '.codekin');
|
|
43
|
+
/** Directory for uploaded screenshots / file attachments. */
|
|
44
|
+
export const SCREENSHOTS_DIR = process.env.SCREENSHOTS_DIR || join(DATA_DIR, 'screenshots');
|
|
45
|
+
/**
|
|
46
|
+
* Path to the built frontend dist directory.
|
|
47
|
+
* When set and the directory exists, the server serves the frontend via express.static,
|
|
48
|
+
* removing the need for nginx inside a Docker container.
|
|
49
|
+
* Bare-metal deploys can leave this unset and continue using nginx.
|
|
50
|
+
*/
|
|
51
|
+
export const FRONTEND_DIST = process.env.FRONTEND_DIST || '';
|
|
52
|
+
/** GitHub organizations for repo listing (comma-separated). Empty string disables org listing. */
|
|
53
|
+
export const GH_ORGS = (process.env.GH_ORG || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAE7C,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,qDAAqD;AACrD,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,CAAC,CAAA;AAE7D,2BAA2B;AAC3B,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAA;AAEzD,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;GAGG;AACH,SAAS,aAAa;IACpB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAA;IAEzD,yDAAyD;IACzD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAA;IACnD,IAAI,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,OAAO,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;IAChD,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;AAEzC,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,8CAA8C;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAA;AAE5E,qEAAqE;AACrE,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAA;AAE3E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;AAE3F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAA;AAE5D,kGAAkG;AAClG,MAAM,CAAC,MAAM,OAAO,GAAa,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared cryptographic utilities for webhook signature verification.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Verify an HMAC-SHA256 signature over a payload.
|
|
6
|
+
* Comparison uses timingSafeEqual to resist timing oracle attacks.
|
|
7
|
+
* Signature format: `sha256=<hex>` (GitHub/Stepflow convention).
|
|
8
|
+
*
|
|
9
|
+
* Returns false if the signature or expected lengths differ,
|
|
10
|
+
* preventing timing leaks from the comparison itself.
|
|
11
|
+
*/
|
|
12
|
+
export declare function verifyHmacSignature(payload: Buffer, signature: string, secret: string): boolean;
|