@cmdctrl/claude-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/adapter/claude-cli.d.ts +41 -0
  2. package/dist/adapter/claude-cli.d.ts.map +1 -0
  3. package/dist/adapter/claude-cli.js +525 -0
  4. package/dist/adapter/claude-cli.js.map +1 -0
  5. package/dist/adapter/events.d.ts +52 -0
  6. package/dist/adapter/events.d.ts.map +1 -0
  7. package/dist/adapter/events.js +134 -0
  8. package/dist/adapter/events.js.map +1 -0
  9. package/dist/client/messages.d.ts +140 -0
  10. package/dist/client/messages.d.ts.map +1 -0
  11. package/dist/client/messages.js +6 -0
  12. package/dist/client/messages.js.map +1 -0
  13. package/dist/client/websocket.d.ts +115 -0
  14. package/dist/client/websocket.d.ts.map +1 -0
  15. package/dist/client/websocket.js +434 -0
  16. package/dist/client/websocket.js.map +1 -0
  17. package/dist/commands/register.d.ts +10 -0
  18. package/dist/commands/register.d.ts.map +1 -0
  19. package/dist/commands/register.js +175 -0
  20. package/dist/commands/register.js.map +1 -0
  21. package/dist/commands/start.d.ts +9 -0
  22. package/dist/commands/start.d.ts.map +1 -0
  23. package/dist/commands/start.js +54 -0
  24. package/dist/commands/start.js.map +1 -0
  25. package/dist/commands/status.d.ts +5 -0
  26. package/dist/commands/status.d.ts.map +1 -0
  27. package/dist/commands/status.js +38 -0
  28. package/dist/commands/status.js.map +1 -0
  29. package/dist/commands/stop.d.ts +5 -0
  30. package/dist/commands/stop.d.ts.map +1 -0
  31. package/dist/commands/stop.js +59 -0
  32. package/dist/commands/stop.js.map +1 -0
  33. package/dist/commands/unregister.d.ts +5 -0
  34. package/dist/commands/unregister.d.ts.map +1 -0
  35. package/dist/commands/unregister.js +28 -0
  36. package/dist/commands/unregister.js.map +1 -0
  37. package/dist/config/config.d.ts +68 -0
  38. package/dist/config/config.d.ts.map +1 -0
  39. package/dist/config/config.js +193 -0
  40. package/dist/config/config.js.map +1 -0
  41. package/dist/handlers/context-handler.d.ts +37 -0
  42. package/dist/handlers/context-handler.d.ts.map +1 -0
  43. package/dist/handlers/context-handler.js +303 -0
  44. package/dist/handlers/context-handler.js.map +1 -0
  45. package/dist/index.d.ts +3 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +39 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/message-reader.d.ts +25 -0
  50. package/dist/message-reader.d.ts.map +1 -0
  51. package/dist/message-reader.js +454 -0
  52. package/dist/message-reader.js.map +1 -0
  53. package/dist/session-discovery.d.ts +48 -0
  54. package/dist/session-discovery.d.ts.map +1 -0
  55. package/dist/session-discovery.js +496 -0
  56. package/dist/session-discovery.js.map +1 -0
  57. package/dist/session-watcher.d.ts +92 -0
  58. package/dist/session-watcher.d.ts.map +1 -0
  59. package/dist/session-watcher.js +494 -0
  60. package/dist/session-watcher.js.map +1 -0
  61. package/dist/session-watcher.test.d.ts +9 -0
  62. package/dist/session-watcher.test.d.ts.map +1 -0
  63. package/dist/session-watcher.test.js +149 -0
  64. package/dist/session-watcher.test.js.map +1 -0
  65. package/jest.config.js +8 -0
  66. package/package.json +42 -0
  67. package/src/adapter/claude-cli.ts +591 -0
  68. package/src/adapter/events.ts +186 -0
  69. package/src/client/messages.ts +193 -0
  70. package/src/client/websocket.ts +509 -0
  71. package/src/commands/register.ts +201 -0
  72. package/src/commands/start.ts +70 -0
  73. package/src/commands/status.ts +47 -0
  74. package/src/commands/stop.ts +58 -0
  75. package/src/commands/unregister.ts +30 -0
  76. package/src/config/config.ts +163 -0
  77. package/src/handlers/context-handler.ts +337 -0
  78. package/src/index.ts +45 -0
  79. package/src/message-reader.ts +485 -0
  80. package/src/session-discovery.ts +557 -0
  81. package/src/session-watcher.test.ts +141 -0
  82. package/src/session-watcher.ts +560 -0
  83. package/tsconfig.json +19 -0
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Types for Claude CLI stream-json output
3
+ */
4
+
5
+ export interface StreamEvent {
6
+ type: 'system' | 'assistant' | 'result' | 'user';
7
+ subtype?: string;
8
+ session_id?: string;
9
+ message?: MessageContent;
10
+ result?: string;
11
+ permission_denials?: PermissionDenial[];
12
+ }
13
+
14
+ export interface MessageContent {
15
+ content: ContentBlock[];
16
+ }
17
+
18
+ export interface ContentBlock {
19
+ type: 'text' | 'tool_use' | 'tool_result' | 'thinking';
20
+ text?: string;
21
+ name?: string;
22
+ input?: unknown;
23
+ id?: string;
24
+ }
25
+
26
+ export interface PermissionDenial {
27
+ tool_name: string;
28
+ id: string;
29
+ }
30
+
31
+ export interface AskUserInput {
32
+ questions: Question[];
33
+ }
34
+
35
+ export interface Question {
36
+ question: string;
37
+ header?: string;
38
+ options: QuestionOption[];
39
+ multiSelect?: boolean;
40
+ }
41
+
42
+ export interface QuestionOption {
43
+ label: string;
44
+ description?: string;
45
+ }
46
+
47
+ export interface ProgressInfo {
48
+ action: string;
49
+ target: string;
50
+ }
51
+
52
+ /**
53
+ * Format raw stream output into human-readable string for verbose display
54
+ * Returns null if the event should be skipped
55
+ */
56
+ export function formatVerboseOutput(line: string): string | null {
57
+ try {
58
+ const data = JSON.parse(line) as StreamEvent;
59
+
60
+ if (data.type === 'system' && data.subtype === 'init') {
61
+ return '● Task started';
62
+ }
63
+
64
+ if (data.type === 'assistant' && data.message?.content) {
65
+ // Check for text content first
66
+ const texts = data.message.content
67
+ .filter(c => c.type === 'text' && c.text)
68
+ .map(c => c.text!.substring(0, 100));
69
+ if (texts.length > 0) {
70
+ const joined = texts.join(' ');
71
+ const truncated = joined.length > 80 ? joined.substring(0, 80) + '...' : joined;
72
+ return `💬 ${truncated}`;
73
+ }
74
+
75
+ // Check for tool use
76
+ const tools = data.message.content.filter(c => c.type === 'tool_use');
77
+ if (tools.length > 0) {
78
+ const tool = tools[0];
79
+ const name = tool.name || 'unknown';
80
+ const input = tool.input as Record<string, unknown> | undefined;
81
+
82
+ switch (name) {
83
+ case 'Read': return `📖 Reading ${input?.file_path || 'file'}`;
84
+ case 'Write': return `✏️ Writing ${input?.file_path || 'file'}`;
85
+ case 'Edit': return `🔧 Editing ${input?.file_path || 'file'}`;
86
+ case 'Bash': {
87
+ const cmd = String(input?.command || '').substring(0, 60);
88
+ return `⚡ ${cmd}`;
89
+ }
90
+ case 'Glob': return `🔍 Searching: ${input?.pattern || ''}`;
91
+ case 'Grep': return `🔎 Grepping: ${input?.pattern || ''}`;
92
+ case 'Task': return `📋 Spawning agent`;
93
+ case 'TodoWrite': return `📝 Updating todos`;
94
+ case 'WebSearch': return `🌐 Searching: ${input?.query || ''}`;
95
+ case 'WebFetch': return `🌐 Fetching: ${input?.url || ''}`;
96
+ default: return `🔧 ${name}`;
97
+ }
98
+ }
99
+ }
100
+
101
+ if (data.type === 'result') {
102
+ // Check for permission denials
103
+ if (data.permission_denials?.length) {
104
+ const denial = data.permission_denials[0];
105
+ const toolName = denial.tool_name;
106
+ if (toolName === 'AskUserQuestion') {
107
+ return '❓ Waiting for your input';
108
+ } else {
109
+ return `⚠️ Permission required: ${toolName}`;
110
+ }
111
+ }
112
+ return '✓ Completed';
113
+ }
114
+
115
+ // Skip uninteresting events
116
+ return null;
117
+ } catch {
118
+ // Not JSON - show raw if short enough
119
+ const trimmed = line.trim();
120
+ if (trimmed && trimmed.length < 100) {
121
+ return trimmed;
122
+ }
123
+ return null;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Extract progress info from tool use
129
+ */
130
+ export function extractProgressFromToolUse(
131
+ toolName: string,
132
+ input: unknown
133
+ ): ProgressInfo | null {
134
+ const inputObj = input as Record<string, unknown>;
135
+
136
+ switch (toolName) {
137
+ case 'Read':
138
+ return {
139
+ action: 'Reading',
140
+ target: (inputObj?.file_path as string) || 'file'
141
+ };
142
+ case 'Write':
143
+ return {
144
+ action: 'Writing',
145
+ target: (inputObj?.file_path as string) || 'file'
146
+ };
147
+ case 'Edit':
148
+ return {
149
+ action: 'Editing',
150
+ target: (inputObj?.file_path as string) || 'file'
151
+ };
152
+ case 'Bash':
153
+ const cmd = (inputObj?.command as string) || '';
154
+ return {
155
+ action: 'Running',
156
+ target: cmd.length > 30 ? cmd.substring(0, 30) + '...' : cmd
157
+ };
158
+ case 'Glob':
159
+ return {
160
+ action: 'Searching',
161
+ target: (inputObj?.pattern as string) || 'files'
162
+ };
163
+ case 'Grep':
164
+ return {
165
+ action: 'Searching',
166
+ target: (inputObj?.pattern as string) || 'pattern'
167
+ };
168
+ case 'WebSearch':
169
+ return {
170
+ action: 'Searching web',
171
+ target: (inputObj?.query as string) || ''
172
+ };
173
+ case 'WebFetch':
174
+ return {
175
+ action: 'Fetching',
176
+ target: (inputObj?.url as string) || 'URL'
177
+ };
178
+ case 'Task':
179
+ return {
180
+ action: 'Running agent',
181
+ target: (inputObj?.description as string) || ''
182
+ };
183
+ default:
184
+ return null;
185
+ }
186
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Message types for daemon <-> server communication
3
+ */
4
+
5
+ // Server -> Daemon messages
6
+
7
+ export interface PingMessage {
8
+ type: 'ping';
9
+ }
10
+
11
+ export interface TaskStartMessage {
12
+ type: 'task_start';
13
+ task_id: string;
14
+ instruction: string;
15
+ project_path?: string;
16
+ }
17
+
18
+ export interface TaskResumeMessage {
19
+ type: 'task_resume';
20
+ task_id: string;
21
+ session_id: string;
22
+ message: string;
23
+ project_path?: string;
24
+ }
25
+
26
+ export interface TaskCancelMessage {
27
+ type: 'task_cancel';
28
+ task_id: string;
29
+ }
30
+
31
+ export interface GetMessagesMessage {
32
+ type: 'get_messages';
33
+ request_id: string;
34
+ session_id: string;
35
+ limit: number;
36
+ before_uuid?: string; // Cursor for backwards pagination (load older)
37
+ after_uuid?: string; // Cursor for forwards pagination (load newer)
38
+ }
39
+
40
+ export interface WatchSessionMessage {
41
+ type: 'watch_session';
42
+ session_id: string;
43
+ file_path: string;
44
+ }
45
+
46
+ export interface UnwatchSessionMessage {
47
+ type: 'unwatch_session';
48
+ session_id: string;
49
+ }
50
+
51
+ export interface ContextRequestMessage {
52
+ type: 'context_request';
53
+ request_id: string;
54
+ session_id: string;
55
+ include: {
56
+ initial_prompt?: boolean;
57
+ recent_messages?: number; // Number of recent messages to include
58
+ last_tool_use?: boolean;
59
+ };
60
+ }
61
+
62
+ export type ServerMessage =
63
+ | PingMessage
64
+ | TaskStartMessage
65
+ | TaskResumeMessage
66
+ | TaskCancelMessage
67
+ | GetMessagesMessage
68
+ | WatchSessionMessage
69
+ | UnwatchSessionMessage
70
+ | ContextRequestMessage;
71
+
72
+ // Daemon -> Server messages
73
+
74
+ export interface PongMessage {
75
+ type: 'pong';
76
+ }
77
+
78
+ export interface StatusMessage {
79
+ type: 'status';
80
+ running_tasks: string[];
81
+ }
82
+
83
+ export interface EventMessage {
84
+ type: 'event';
85
+ task_id: string;
86
+ event_type: string;
87
+ [key: string]: unknown;
88
+ }
89
+
90
+ export interface SessionInfo {
91
+ session_id: string;
92
+ slug: string;
93
+ title: string;
94
+ project: string;
95
+ project_name: string;
96
+ file_path: string;
97
+ last_message: string;
98
+ last_activity: string;
99
+ is_active: boolean;
100
+ message_count: number;
101
+ }
102
+
103
+ export interface ReportSessionsMessage {
104
+ type: 'report_sessions';
105
+ sessions: SessionInfo[];
106
+ }
107
+
108
+ export interface MessageEntry {
109
+ uuid: string;
110
+ role: 'USER' | 'AGENT' | 'SYSTEM';
111
+ content: string;
112
+ timestamp: string;
113
+ }
114
+
115
+ export interface MessagesResponseMessage {
116
+ type: 'messages';
117
+ request_id: string;
118
+ session_id: string;
119
+ messages: MessageEntry[];
120
+ has_more: boolean;
121
+ oldest_uuid?: string;
122
+ newest_uuid?: string;
123
+ error?: string;
124
+ }
125
+
126
+ export interface SessionActivityMessage {
127
+ type: 'session_activity';
128
+ session_id: string;
129
+ file_path: string;
130
+ last_message: string;
131
+ message_count: number;
132
+ is_completion: boolean; // True when last message is from assistant (agent finished)
133
+ user_message_uuid?: string; // UUID of the triggering user message (for positioning verbose output)
134
+ last_activity: string; // ISO timestamp of the last message (not file mtime)
135
+ }
136
+
137
+ // Session status for dashboard summaries
138
+ export type SessionStatus = 'working' | 'waiting_for_input' | 'completed' | 'errored' | 'stale';
139
+
140
+ export interface SessionStatusMessage {
141
+ type: 'session_status';
142
+ session_id: string;
143
+ status: SessionStatus;
144
+ status_detail?: string; // e.g., "Asked: Which database should I use?"
145
+ last_tool_use?: string; // e.g., "Read file: schema.sql"
146
+ message_count: number;
147
+ elapsed_minutes: number;
148
+ }
149
+
150
+ export interface ContextResponseMessage {
151
+ type: 'context_response';
152
+ request_id: string;
153
+ session_id: string;
154
+ context: {
155
+ title: string;
156
+ project_path: string;
157
+ initial_prompt?: string;
158
+ recent_messages?: Array<{
159
+ role: 'USER' | 'AGENT';
160
+ content: string;
161
+ }>;
162
+ last_tool_use?: string;
163
+ message_count: number;
164
+ started_at?: string;
165
+ last_activity_at: string;
166
+ status: SessionStatus;
167
+ status_detail?: string;
168
+ };
169
+ error?: string;
170
+ }
171
+
172
+ export type DaemonMessage =
173
+ | PongMessage
174
+ | StatusMessage
175
+ | EventMessage
176
+ | ReportSessionsMessage
177
+ | MessagesResponseMessage
178
+ | SessionActivityMessage
179
+ | SessionStatusMessage
180
+ | ContextResponseMessage;
181
+
182
+ // Event types sent from daemon to server
183
+ export type EventType =
184
+ | 'SESSION_STARTED' // Internal: triggers file watching (not sent to server)
185
+ | 'WAIT_FOR_USER'
186
+ | 'TASK_COMPLETE'
187
+ | 'OUTPUT' // Legacy: verbose output from CLI stream (being phased out)
188
+ | 'PROGRESS'
189
+ | 'ERROR'
190
+ // New JSONL-based event types
191
+ | 'AGENT_RESPONSE' // Assistant entry with text content
192
+ | 'VERBOSE' // Tool use, thinking, tool result
193
+ | 'USER_MESSAGE'; // User message (for passive observers)