codekin 0.3.7 → 0.4.1

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 (50) hide show
  1. package/README.md +2 -1
  2. package/dist/assets/index-BAdQqYEY.js +182 -0
  3. package/dist/assets/index-CeZYNLWt.css +1 -0
  4. package/dist/index.html +2 -2
  5. package/package.json +8 -2
  6. package/server/dist/approval-manager.d.ts +44 -8
  7. package/server/dist/approval-manager.js +262 -23
  8. package/server/dist/approval-manager.js.map +1 -1
  9. package/server/dist/claude-process.d.ts +16 -0
  10. package/server/dist/claude-process.js +42 -10
  11. package/server/dist/claude-process.js.map +1 -1
  12. package/server/dist/commit-event-handler.d.ts +41 -0
  13. package/server/dist/commit-event-handler.js +99 -0
  14. package/server/dist/commit-event-handler.js.map +1 -0
  15. package/server/dist/commit-event-hooks.d.ts +35 -0
  16. package/server/dist/commit-event-hooks.js +177 -0
  17. package/server/dist/commit-event-hooks.js.map +1 -0
  18. package/server/dist/crypto-utils.js +10 -5
  19. package/server/dist/crypto-utils.js.map +1 -1
  20. package/server/dist/diff-parser.d.ts +23 -0
  21. package/server/dist/diff-parser.js +242 -0
  22. package/server/dist/diff-parser.js.map +1 -0
  23. package/server/dist/session-manager.d.ts +27 -8
  24. package/server/dist/session-manager.js +375 -35
  25. package/server/dist/session-manager.js.map +1 -1
  26. package/server/dist/session-routes.js +109 -4
  27. package/server/dist/session-routes.js.map +1 -1
  28. package/server/dist/stepflow-handler.js +17 -3
  29. package/server/dist/stepflow-handler.js.map +1 -1
  30. package/server/dist/tsconfig.tsbuildinfo +1 -1
  31. package/server/dist/types.d.ts +62 -1
  32. package/server/dist/upload-routes.d.ts +1 -1
  33. package/server/dist/upload-routes.js +46 -16
  34. package/server/dist/upload-routes.js.map +1 -1
  35. package/server/dist/webhook-workspace.js +5 -2
  36. package/server/dist/webhook-workspace.js.map +1 -1
  37. package/server/dist/workflow-loader.d.ts +6 -0
  38. package/server/dist/workflow-loader.js +11 -0
  39. package/server/dist/workflow-loader.js.map +1 -1
  40. package/server/dist/workflow-routes.d.ts +5 -1
  41. package/server/dist/workflow-routes.js +48 -7
  42. package/server/dist/workflow-routes.js.map +1 -1
  43. package/server/dist/ws-message-handler.js +20 -0
  44. package/server/dist/ws-message-handler.js.map +1 -1
  45. package/server/dist/ws-server.js +19 -3
  46. package/server/dist/ws-server.js.map +1 -1
  47. package/server/workflows/commit-review.md +22 -0
  48. package/server/workflows/docs-audit.weekly.md +97 -0
  49. package/dist/assets/index-Dc76fIdG.js +0 -174
  50. package/dist/assets/index-DoL2Uppj.css +0 -1
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Parses raw `git diff` output into structured DiffFile[] objects.
3
+ *
4
+ * Handles unified diff format with rename detection, binary files,
5
+ * and optional size-based truncation.
6
+ */
7
+ /** 2 MB default cap on raw diff output before truncation. */
8
+ const DEFAULT_MAX_BYTES = 2 * 1024 * 1024;
9
+ /**
10
+ * Parse raw unified diff output into structured file/hunk/line objects.
11
+ * If `maxBytes` is provided and the input exceeds it, parsing stops early
12
+ * and `truncated` is set to true.
13
+ */
14
+ export function parseDiff(raw, maxBytes = DEFAULT_MAX_BYTES) {
15
+ let truncated = false;
16
+ let truncationReason;
17
+ let input = raw;
18
+ if (Buffer.byteLength(raw, 'utf-8') > maxBytes) {
19
+ truncated = true;
20
+ truncationReason = `Diff output exceeded ${Math.round(maxBytes / (1024 * 1024))} MB limit`;
21
+ // Truncate to roughly maxBytes — walk back to a valid UTF-8 boundary
22
+ // to avoid splitting multibyte characters (emoji, CJK, etc.)
23
+ const buf = Buffer.from(raw, 'utf-8');
24
+ let end = maxBytes;
25
+ // UTF-8 continuation bytes start with 0b10xxxxxx (0x80–0xBF).
26
+ // Walk back past any continuation bytes so we don't split a code point.
27
+ while (end > 0 && (buf[end] & 0xC0) === 0x80)
28
+ end--;
29
+ const sliced = buf.subarray(0, end).toString('utf-8');
30
+ const lastNewline = sliced.lastIndexOf('\n');
31
+ input = lastNewline > 0 ? sliced.slice(0, lastNewline) : sliced;
32
+ }
33
+ const files = [];
34
+ // Split on diff headers: "diff --git a/... b/..."
35
+ const fileSections = input.split(/^diff --git /m);
36
+ for (let i = 1; i < fileSections.length; i++) {
37
+ const section = fileSections[i];
38
+ const file = parseFileSection(section);
39
+ if (file)
40
+ files.push(file);
41
+ }
42
+ return { files, truncated, truncationReason };
43
+ }
44
+ function parseFileSection(section) {
45
+ const lines = section.split('\n');
46
+ if (lines.length === 0)
47
+ return null;
48
+ // First line: "a/path b/path"
49
+ const headerLine = lines[0];
50
+ const pathMatch = headerLine.match(/^a\/(.+?) b\/(.+?)$/);
51
+ if (!pathMatch)
52
+ return null;
53
+ const bPath = pathMatch[2];
54
+ let status = 'modified';
55
+ let oldPath;
56
+ let isBinary = false;
57
+ const hunks = [];
58
+ let additions = 0;
59
+ let deletions = 0;
60
+ let lineIdx = 1;
61
+ // Parse extended header lines (new file, deleted file, rename, binary, etc.)
62
+ while (lineIdx < lines.length) {
63
+ const line = lines[lineIdx];
64
+ if (line.startsWith('new file mode')) {
65
+ status = 'added';
66
+ }
67
+ else if (line.startsWith('deleted file mode')) {
68
+ status = 'deleted';
69
+ }
70
+ else if (line.startsWith('rename from ')) {
71
+ status = 'renamed';
72
+ oldPath = line.slice('rename from '.length);
73
+ }
74
+ else if (line.startsWith('similarity index') || line.startsWith('dissimilarity index')) {
75
+ // part of rename/copy header, skip
76
+ }
77
+ else if (line.startsWith('rename to ')) {
78
+ // already captured via bPath
79
+ }
80
+ else if (line.startsWith('index ')) {
81
+ // index line, skip
82
+ }
83
+ else if (line === 'GIT binary patch' || line.startsWith('Binary files ')) {
84
+ isBinary = true;
85
+ }
86
+ else if (line.startsWith('--- ') || line.startsWith('+++ ')) {
87
+ // file marker lines — skip but keep going for hunks
88
+ }
89
+ else if (line.startsWith('@@')) {
90
+ // Start of hunks — break out to hunk parsing
91
+ break;
92
+ }
93
+ else if (line.startsWith('old mode') || line.startsWith('new mode')) {
94
+ // mode change, skip
95
+ }
96
+ else {
97
+ // Unknown header line or empty — if we hit content, stop
98
+ if (!line.startsWith('\\') && line !== '') {
99
+ break;
100
+ }
101
+ }
102
+ lineIdx++;
103
+ }
104
+ // Parse hunks
105
+ if (!isBinary) {
106
+ while (lineIdx < lines.length) {
107
+ const line = lines[lineIdx];
108
+ if (line.startsWith('@@')) {
109
+ const hunkResult = parseHunk(lines, lineIdx);
110
+ if (hunkResult) {
111
+ hunks.push(hunkResult.hunk);
112
+ additions += hunkResult.additions;
113
+ deletions += hunkResult.deletions;
114
+ lineIdx = hunkResult.nextIdx;
115
+ }
116
+ else {
117
+ lineIdx++;
118
+ }
119
+ }
120
+ else {
121
+ lineIdx++;
122
+ }
123
+ }
124
+ }
125
+ return {
126
+ path: bPath,
127
+ status,
128
+ oldPath: status === 'renamed' ? oldPath : undefined,
129
+ isBinary,
130
+ additions,
131
+ deletions,
132
+ hunks,
133
+ };
134
+ }
135
+ function parseHunk(lines, startIdx) {
136
+ const headerLine = lines[startIdx];
137
+ // Parse "@@ -10,7 +10,8 @@ optional context"
138
+ const hunkMatch = headerLine.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);
139
+ if (!hunkMatch)
140
+ return null;
141
+ const oldStart = parseInt(hunkMatch[1], 10);
142
+ const oldLines = hunkMatch[2] !== undefined ? parseInt(hunkMatch[2], 10) : 1;
143
+ const newStart = parseInt(hunkMatch[3], 10);
144
+ const newLines = hunkMatch[4] !== undefined ? parseInt(hunkMatch[4], 10) : 1;
145
+ const diffLines = [];
146
+ let additions = 0;
147
+ let deletions = 0;
148
+ let oldLineNo = oldStart;
149
+ let newLineNo = newStart;
150
+ let idx = startIdx + 1;
151
+ while (idx < lines.length) {
152
+ const line = lines[idx];
153
+ // Next hunk or next file
154
+ if (line.startsWith('@@') || line.startsWith('diff --git '))
155
+ break;
156
+ if (line.startsWith('+')) {
157
+ diffLines.push({
158
+ type: 'add',
159
+ content: line.slice(1),
160
+ newLineNo: newLineNo,
161
+ });
162
+ additions++;
163
+ newLineNo++;
164
+ }
165
+ else if (line.startsWith('-')) {
166
+ diffLines.push({
167
+ type: 'delete',
168
+ content: line.slice(1),
169
+ oldLineNo: oldLineNo,
170
+ });
171
+ deletions++;
172
+ oldLineNo++;
173
+ }
174
+ else if (line.startsWith(' ')) {
175
+ diffLines.push({
176
+ type: 'context',
177
+ content: line.slice(1),
178
+ oldLineNo: oldLineNo,
179
+ newLineNo: newLineNo,
180
+ });
181
+ oldLineNo++;
182
+ newLineNo++;
183
+ }
184
+ else if (line.startsWith('\\')) {
185
+ // "" — skip
186
+ }
187
+ else if (line === '') {
188
+ // Unified diff always prefixes lines with ' ', '+', or '-'.
189
+ // An empty string means end-of-section (from split at file boundaries).
190
+ break;
191
+ }
192
+ else {
193
+ break;
194
+ }
195
+ idx++;
196
+ }
197
+ return {
198
+ hunk: {
199
+ header: headerLine,
200
+ oldStart,
201
+ oldLines,
202
+ newStart,
203
+ newLines,
204
+ lines: diffLines,
205
+ },
206
+ additions,
207
+ deletions,
208
+ nextIdx: idx,
209
+ };
210
+ }
211
+ /**
212
+ * Generate a synthetic diff for an untracked file, treating it as fully added.
213
+ * Reads the file content and produces a single hunk with all lines as additions.
214
+ */
215
+ export function createUntrackedFileDiff(relativePath, content) {
216
+ const fileLines = content.split('\n');
217
+ // Remove trailing empty line from split if file ends with newline
218
+ if (fileLines.length > 0 && fileLines[fileLines.length - 1] === '') {
219
+ fileLines.pop();
220
+ }
221
+ const diffLines = fileLines.map((line, i) => ({
222
+ type: 'add',
223
+ content: line,
224
+ newLineNo: i + 1,
225
+ }));
226
+ return {
227
+ path: relativePath,
228
+ status: 'added',
229
+ isBinary: false,
230
+ additions: fileLines.length,
231
+ deletions: 0,
232
+ hunks: fileLines.length > 0 ? [{
233
+ header: `@@ -0,0 +1,${fileLines.length} @@`,
234
+ oldStart: 0,
235
+ oldLines: 0,
236
+ newStart: 1,
237
+ newLines: fileLines.length,
238
+ lines: diffLines,
239
+ }] : [],
240
+ };
241
+ }
242
+ //# sourceMappingURL=diff-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-parser.js","sourceRoot":"","sources":["../diff-parser.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import type { WebSocket } from 'ws';
19
19
  import { SessionArchive } from './session-archive.js';
20
- import type { Session, SessionInfo, WsServerMessage } from './types.js';
20
+ import type { DiffFileStatus, DiffScope, Session, SessionInfo, WsServerMessage } from './types.js';
21
21
  export interface CreateSessionOptions {
22
22
  source?: 'manual' | 'webhook' | 'workflow' | 'stepflow';
23
23
  id?: string;
@@ -25,22 +25,25 @@ export interface CreateSessionOptions {
25
25
  model?: string;
26
26
  }
27
27
  export declare class SessionManager {
28
+ /** All active (non-archived) sessions, keyed by session UUID. */
28
29
  private sessions;
29
- /** SQLite archive for closed sessions. */
30
+ /** Reverse lookup: WebSocket → session ID for O(1) client-to-session resolution. */
31
+ private clientSessionMap;
32
+ /** SQLite archive for closed sessions (persists conversation summaries across restarts). */
30
33
  readonly archive: SessionArchive;
31
34
  /** Exposed so ws-server can pass its port to child Claude processes. */
32
35
  _serverPort: number;
33
36
  /** Exposed so ws-server can pass the auth token to child Claude processes. */
34
37
  _authToken: string;
35
- /** Callback to broadcast a message to ALL connected WebSocket clients (set by ws-server). */
38
+ /** Callback to broadcast a message to ALL connected WebSocket clients (set by ws-server on startup). */
36
39
  _globalBroadcast: ((msg: WsServerMessage) => void) | null;
37
- /** Registered listeners notified when a session's Claude process exits. */
40
+ /** Registered listeners notified when a session's Claude process exits (used by webhook-handler for chained workflows). */
38
41
  private _exitListeners;
39
- /** Delegated approval logic. */
42
+ /** Delegated approval logic (auto-approve patterns, deny-lists, pattern management). */
40
43
  private approvalManager;
41
- /** Delegated naming logic. */
44
+ /** Delegated auto-naming logic (generates session names from first user message via Claude API). */
42
45
  private sessionNaming;
43
- /** Delegated persistence logic. */
46
+ /** Delegated persistence logic (saves/restores session metadata to disk across server restarts). */
44
47
  private sessionPersistence;
45
48
  constructor();
46
49
  /** Check if a tool/command is auto-approved for a repo. */
@@ -53,6 +56,12 @@ export declare class SessionManager {
53
56
  commands: string[];
54
57
  patterns: string[];
55
58
  };
59
+ /** Return approvals effective globally via cross-repo inference. */
60
+ getGlobalApprovals(): {
61
+ tools: Record<string, string[]>;
62
+ commands: Record<string, string[]>;
63
+ patterns: Record<string, string[]>;
64
+ };
56
65
  /** Remove an auto-approval rule for a repo (workingDir) and persist to disk. */
57
66
  removeApproval(workingDir: string, opts: {
58
67
  tool?: string;
@@ -81,7 +90,7 @@ export declare class SessionManager {
81
90
  /** Add a WebSocket client to a session. Returns the session or undefined if not found.
82
91
  * Re-broadcasts any pending approval/control prompts so the joining client sees them. */
83
92
  join(sessionId: string, ws: WebSocket): Session | undefined;
84
- /** Remove a WebSocket client from a session. Auto-denies pending prompts if last client leaves. */
93
+ /** Remove a WebSocket client from a session. Auto-denies pending prompts if last client leaves (after grace period). */
85
94
  leave(sessionId: string, ws: WebSocket): void;
86
95
  /** Delete a session: kill its process, notify clients, remove from memory and disk. */
87
96
  delete(sessionId: string): boolean;
@@ -183,6 +192,16 @@ export declare class SessionManager {
183
192
  broadcast(session: Session, msg: WsServerMessage): void;
184
193
  findSessionForClient(ws: WebSocket): Session | undefined;
185
194
  removeClient(ws: WebSocket): void;
195
+ /**
196
+ * Run git diff in a session's workingDir and return structured results.
197
+ * Includes untracked file discovery for 'unstaged' and 'all' scopes.
198
+ */
199
+ getDiff(sessionId: string, scope?: DiffScope): Promise<WsServerMessage>;
200
+ /**
201
+ * Discard changes in a session's workingDir per the given scope and paths.
202
+ * Returns a fresh diff_result after discarding.
203
+ */
204
+ discardChanges(sessionId: string, scope: DiffScope, paths?: string[], statuses?: Record<string, DiffFileStatus>): Promise<WsServerMessage>;
186
205
  /** Graceful shutdown: complete in-progress tasks, persist state, kill all processes. */
187
206
  shutdown(): void;
188
207
  /**