@opencoven/coven-code 0.0.3 → 0.0.4

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 CHANGED
@@ -34,7 +34,7 @@ filtering and a details panel for commands, skills, and plugin actions.
34
34
 
35
35
  ```text
36
36
  $ coven-code
37
- Coven Code 0.0.3
37
+ Coven Code 0.0.4
38
38
  /Users/example/project
39
39
  [chat] lane tools threads config help mode: smart effort: high
40
40
  --------------------------------------------------------------------------------
package/docs/CLI.md CHANGED
@@ -99,7 +99,7 @@ transcript, tabs, compact status line, command palette, slash-command menu, and
99
99
  composer. It keeps a current local thread and accepts slash commands:
100
100
 
101
101
  ```text
102
- Coven Code 0.0.3
102
+ Coven Code 0.0.4
103
103
  [chat] lane tools threads config help mode: smart effort: high
104
104
  --------------------------------------------------------------------------------
105
105
  Ready. Type a prompt or /help.
package/docs/DEMO.md CHANGED
@@ -147,7 +147,7 @@ rm -rf "$DEMO_HOME" # the script prints the exact path at the end
147
147
  works without any account or API key.
148
148
 
149
149
  ```sh
150
- node ./bin/coven-code.mjs --version # prints 0.0.3
150
+ node ./bin/coven-code.mjs --version # prints 0.0.4
151
151
  node ./bin/coven-code.mjs --help # full option and command reference
152
152
  node ./bin/coven-code.mjs login # printable instructions (no token yet)
153
153
  node ./bin/coven-code.mjs login status # auth_status: logged_out
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencoven/coven-code",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,33 +1,24 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import path from 'node:path';
4
- import { BUILTIN_TOOLS } from '../constants.mjs';
5
4
  import { estimateUsage, fixtureAgentResponse } from '../agent/fixture.mjs';
6
- import {
7
- listActiveMcpServerEntries,
8
- } from '../mcp/discover.mjs';
9
- import { discoverMcpToolRows } from '../mcp/probe.mjs';
10
5
  import {
11
6
  loadPlugins,
12
7
  runPluginEventHandlers,
13
8
  } from '../plugins/discover.mjs';
14
9
  import { discoverAgentFiles, firstGuidanceInDir } from '../commands/agents.mjs';
15
- import {
16
- isToolDisabled,
17
- listToolboxTools,
18
- toolKindForName,
19
- } from '../tools/toolbox.mjs';
20
10
  import { executePromptToolRequest } from '../tools/builtin/index.mjs';
21
11
  import { toolResultContent } from '../tools/builtin/runtime.mjs';
22
12
  import { persistThreadMessages, threadContinuationPrompt } from '../threads/store.mjs';
23
13
  import { readEffectiveSettings } from '../settings/load.mjs';
24
14
  import { expandFileReferences, expandThreadReferences } from './refs.mjs';
25
15
  import { UsageError } from './parse.mjs';
26
- import { reasoningEffortForMode } from './reasoning.mjs';
27
16
  import { notifyAgentComplete } from './notifications.mjs';
28
17
  import { globToRegex } from '../util/glob.mjs';
29
- import { displayCwd, emitJson } from '../util/fs.mjs';
18
+ import { emitJson } from '../util/fs.mjs';
30
19
  import {
20
+ emitStreamJsonInit,
21
+ emitStreamJsonTurn,
31
22
  streamJsonInputMessages,
32
23
  streamJsonOutputUserContent,
33
24
  streamJsonPermissionDenials,
@@ -60,83 +51,21 @@ export async function runExecute(parsed, stdin, options = {}) {
60
51
  const result = turns.at(-1)?.result ?? '';
61
52
 
62
53
  if (parsed.streamJson) {
63
- const activeMcpServers = listActiveMcpServerEntries(parsed, turns.map((turn) => turn.prompt).join('\n\n'));
64
- const tools = [
65
- ...BUILTIN_TOOLS.map(([name]) => name),
66
- ...listToolboxTools(parsed).map((tool) => tool.name),
67
- ...plugins.tools.map((tool) => tool.name),
68
- ...(await discoverMcpToolRows(activeMcpServers)).map(([name]) => name),
69
- ].filter((name) => !isToolDisabled(name, toolKindForName(name), parsed));
70
- emitJson({
71
- type: 'system',
72
- subtype: 'init',
73
- cwd: displayCwd(),
74
- session_id: sessionId,
75
- tools,
76
- mcp_servers: activeMcpServers.map(({ name }) => ({ name, status: 'connected' })),
77
- agent_mode: parsed.mode,
78
- reasoning_effort: reasoningEffortForMode(parsed.mode, parsed.reasoningEffort),
54
+ await emitStreamJsonInit({
55
+ parsed,
56
+ plugins,
57
+ sessionId,
58
+ promptForMcpDiscovery: turns.map((turn) => turn.prompt).join('\n\n'),
79
59
  });
80
60
  for (const turn of turns) {
81
- emitJson({
82
- type: 'user',
83
- message: { role: 'user', content: [{ type: 'text', text: turn.prompt }] },
84
- parent_tool_use_id: null,
85
- session_id: sessionId,
86
- });
87
- if (turn.toolRun?.toolUse) {
88
- emitJson({
89
- type: 'assistant',
90
- message: {
91
- type: 'message',
92
- role: 'assistant',
93
- content: [turn.toolRun.toolUse],
94
- stop_reason: 'tool_use',
95
- usage: estimateUsage(turn.prompt, JSON.stringify(turn.toolRun.toolUse.input)),
96
- },
97
- parent_tool_use_id: null,
98
- session_id: sessionId,
99
- });
100
- for (const subagentMessage of turn.toolRun.subagentMessages ?? []) {
101
- emitJson({
102
- type: 'assistant',
103
- message: {
104
- type: 'message',
105
- role: 'assistant',
106
- content: assistantStreamContent(subagentMessage.text ?? '', parsed),
107
- stop_reason: 'end_turn',
108
- usage: estimateUsage(turn.prompt, subagentMessage.text ?? ''),
109
- },
110
- parent_tool_use_id: turn.toolRun.toolUse.id,
111
- session_id: sessionId,
112
- });
113
- }
114
- emitJson({
115
- type: 'user',
116
- message: {
117
- role: 'user',
118
- content: [{
119
- type: 'tool_result',
120
- tool_use_id: turn.toolRun.toolUse.id,
121
- content: toolResultContent(turn.toolRun),
122
- is_error: turn.toolRun.exitCode !== 0,
123
- }],
124
- },
125
- parent_tool_use_id: toolRunParent(turn.toolRun, 'toolResultParentToolUseId', null),
126
- session_id: sessionId,
127
- });
128
- }
129
- emitJson({
130
- type: 'assistant',
131
- message: {
132
- type: 'message',
133
- role: 'assistant',
134
- content: assistantStreamContent(turn.result, parsed),
135
- stop_reason: 'end_turn',
136
- usage: estimateUsage(turn.prompt, turn.result),
137
- },
138
- parent_tool_use_id: turn.toolRun ? toolRunParent(turn.toolRun, 'finalParentToolUseId', null) : null,
139
- session_id: sessionId,
61
+ emitStreamJsonTurn({
62
+ userContent: [{ type: 'text', text: turn.prompt }],
63
+ promptText: turn.prompt,
64
+ toolRun: turn.toolRun,
65
+ result: turn.result,
66
+ parsed,
67
+ sessionId,
68
+ assistantParentToolUseId: turn.toolRun ? toolRunParent(turn.toolRun, 'finalParentToolUseId', null) : null,
140
69
  });
141
70
  }
142
71
  emitJson(streamJsonResultMessage({
@@ -312,22 +241,11 @@ async function runStreamJsonInputExecute(parsed, stdin, options = {}, started =
312
241
  const combinedPrompt = inputMessages.map((message) => message.text).filter(Boolean).join('\n\n');
313
242
  const plugins = await loadPlugins(process.cwd());
314
243
  await runSessionStartHandlers(plugins, sessionId);
315
- const activeMcpServers = listActiveMcpServerEntries(parsed, combinedPrompt);
316
- const tools = [
317
- ...BUILTIN_TOOLS.map(([name]) => name),
318
- ...listToolboxTools(parsed).map((tool) => tool.name),
319
- ...plugins.tools.map((tool) => tool.name),
320
- ...(await discoverMcpToolRows(activeMcpServers)).map(([name]) => name),
321
- ].filter((name) => !isToolDisabled(name, toolKindForName(name), parsed));
322
- emitJson({
323
- type: 'system',
324
- subtype: 'init',
325
- cwd: displayCwd(),
326
- session_id: sessionId,
327
- tools,
328
- mcp_servers: activeMcpServers.map(({ name }) => ({ name, status: 'connected' })),
329
- agent_mode: parsed.mode,
330
- reasoning_effort: reasoningEffortForMode(parsed.mode, parsed.reasoningEffort),
244
+ await emitStreamJsonInit({
245
+ parsed,
246
+ plugins,
247
+ sessionId,
248
+ promptForMcpDiscovery: combinedPrompt,
331
249
  });
332
250
 
333
251
  const transcript = [];
@@ -356,67 +274,18 @@ async function runStreamJsonInputExecute(parsed, stdin, options = {}, started =
356
274
  if (toolRun?.permissionDenials) permissionDenials.push(...toolRun.permissionDenials);
357
275
  if ((toolRun?.exitCode ?? 0) !== 0) isError = true;
358
276
 
359
- emitJson({
360
- type: 'user',
361
- ...(input.steer ? { steer: true } : {}),
362
- message: { role: 'user', content: streamJsonOutputUserContent(input.content) },
363
- parent_tool_use_id: null,
364
- session_id: sessionId,
365
- });
366
277
  if (toolRun?.toolUse) {
367
- emitJson({
368
- type: 'assistant',
369
- message: {
370
- type: 'message',
371
- role: 'assistant',
372
- content: [toolRun.toolUse],
373
- stop_reason: 'tool_use',
374
- usage: estimateUsage(input.text, JSON.stringify(toolRun.toolUse.input)),
375
- },
376
- parent_tool_use_id: null,
377
- session_id: sessionId,
378
- });
379
- for (const subagentMessage of toolRun.subagentMessages ?? []) {
380
- emitJson({
381
- type: 'assistant',
382
- message: {
383
- type: 'message',
384
- role: 'assistant',
385
- content: assistantStreamContent(subagentMessage.text ?? '', parsed),
386
- stop_reason: 'end_turn',
387
- usage: estimateUsage(input.text, subagentMessage.text ?? ''),
388
- },
389
- parent_tool_use_id: toolRun.toolUse.id,
390
- session_id: sessionId,
391
- });
392
- }
393
- emitJson({
394
- type: 'user',
395
- message: {
396
- role: 'user',
397
- content: [{
398
- type: 'tool_result',
399
- tool_use_id: toolRun.toolUse.id,
400
- content: toolResultContent(toolRun),
401
- is_error: toolRun.exitCode !== 0,
402
- }],
403
- },
404
- parent_tool_use_id: toolRunParent(toolRun, 'toolResultParentToolUseId', null),
405
- session_id: sessionId,
406
- });
407
278
  parentToolUseId = toolRunParent(toolRun, 'finalParentToolUseId', null);
408
279
  }
409
- emitJson({
410
- type: 'assistant',
411
- message: {
412
- type: 'message',
413
- role: 'assistant',
414
- content: assistantStreamContent(result, parsed),
415
- stop_reason: 'end_turn',
416
- usage: estimateUsage(input.text, result),
417
- },
418
- parent_tool_use_id: parentToolUseId,
419
- session_id: sessionId,
280
+ emitStreamJsonTurn({
281
+ userContent: streamJsonOutputUserContent(input.content),
282
+ steer: input.steer,
283
+ promptText: input.text,
284
+ toolRun,
285
+ result,
286
+ parsed,
287
+ sessionId,
288
+ assistantParentToolUseId: parentToolUseId,
420
289
  });
421
290
  await runPluginEventHandlers(plugins.handlers['agent.end'], {
422
291
  message: input.text,
@@ -453,13 +322,6 @@ async function runSessionStartHandlers(plugins, sessionId) {
453
322
  });
454
323
  }
455
324
 
456
- function assistantStreamContent(result, parsed = {}) {
457
- if (parsed.streamJsonThinking && readEffectiveSettings(parsed)['covenCode.thinking.enabled'] !== false) {
458
- return [{ type: 'thinking', thinking: 'Using the local deterministic recreation.' }, { type: 'text', text: result }];
459
- }
460
- return [{ type: 'text', text: result }];
461
- }
462
-
463
325
  function modelPromptWithTranscript(turnPrompt, transcript, thread, parsed = {}) {
464
326
  const context = transcript.length > 0
465
327
  ? `[conversation:${thread?.id ?? 'stream-json-input'}]\n${transcript
@@ -1,6 +1,15 @@
1
1
  import { fileURLToPath } from 'node:url';
2
+ import { BUILTIN_TOOLS } from '../constants.mjs';
3
+ import { estimateUsage } from '../agent/fixture.mjs';
4
+ import { listActiveMcpServerEntries } from '../mcp/discover.mjs';
5
+ import { discoverMcpToolRows } from '../mcp/probe.mjs';
6
+ import { readEffectiveSettings } from '../settings/load.mjs';
7
+ import { isToolDisabled, listToolboxTools, toolKindForName } from '../tools/toolbox.mjs';
8
+ import { toolResultContent } from '../tools/builtin/runtime.mjs';
2
9
  import { detectImageMediaType, imageMediaTypeExtension } from '../util/media.mjs';
10
+ import { displayCwd, emitJson } from '../util/fs.mjs';
3
11
  import { UsageError } from './parse.mjs';
12
+ import { reasoningEffortForMode } from './reasoning.mjs';
4
13
  import { imageMentionBlock } from './refs.mjs';
5
14
 
6
15
  export function streamJsonInputMessages(prompt, stdin) {
@@ -90,6 +99,106 @@ export function streamJsonPermissionDenials(denials = []) {
90
99
  });
91
100
  }
92
101
 
102
+ export function assistantStreamContent(result, parsed = {}) {
103
+ if (parsed.streamJsonThinking && readEffectiveSettings(parsed)['covenCode.thinking.enabled'] !== false) {
104
+ return [{ type: 'thinking', thinking: 'Using the local deterministic recreation.' }, { type: 'text', text: result }];
105
+ }
106
+ return [{ type: 'text', text: result }];
107
+ }
108
+
109
+ export async function emitStreamJsonInit({ parsed, plugins, sessionId, promptForMcpDiscovery }) {
110
+ const activeMcpServers = listActiveMcpServerEntries(parsed, promptForMcpDiscovery);
111
+ const tools = [
112
+ ...BUILTIN_TOOLS.map(([name]) => name),
113
+ ...listToolboxTools(parsed).map((tool) => tool.name),
114
+ ...plugins.tools.map((tool) => tool.name),
115
+ ...(await discoverMcpToolRows(activeMcpServers)).map(([name]) => name),
116
+ ].filter((name) => !isToolDisabled(name, toolKindForName(name), parsed));
117
+ emitJson({
118
+ type: 'system',
119
+ subtype: 'init',
120
+ cwd: displayCwd(),
121
+ session_id: sessionId,
122
+ tools,
123
+ mcp_servers: activeMcpServers.map(({ name }) => ({ name, status: 'connected' })),
124
+ agent_mode: parsed.mode,
125
+ reasoning_effort: reasoningEffortForMode(parsed.mode, parsed.reasoningEffort),
126
+ });
127
+ }
128
+
129
+ export function emitStreamJsonTurn({
130
+ userContent,
131
+ steer = false,
132
+ promptText,
133
+ toolRun,
134
+ result,
135
+ parsed,
136
+ sessionId,
137
+ assistantParentToolUseId,
138
+ }) {
139
+ emitJson({
140
+ type: 'user',
141
+ ...(steer ? { steer: true } : {}),
142
+ message: { role: 'user', content: userContent },
143
+ parent_tool_use_id: null,
144
+ session_id: sessionId,
145
+ });
146
+ if (toolRun?.toolUse) {
147
+ emitJson({
148
+ type: 'assistant',
149
+ message: {
150
+ type: 'message',
151
+ role: 'assistant',
152
+ content: [toolRun.toolUse],
153
+ stop_reason: 'tool_use',
154
+ usage: estimateUsage(promptText, JSON.stringify(toolRun.toolUse.input)),
155
+ },
156
+ parent_tool_use_id: null,
157
+ session_id: sessionId,
158
+ });
159
+ for (const subagentMessage of toolRun.subagentMessages ?? []) {
160
+ emitJson({
161
+ type: 'assistant',
162
+ message: {
163
+ type: 'message',
164
+ role: 'assistant',
165
+ content: assistantStreamContent(subagentMessage.text ?? '', parsed),
166
+ stop_reason: 'end_turn',
167
+ usage: estimateUsage(promptText, subagentMessage.text ?? ''),
168
+ },
169
+ parent_tool_use_id: toolRun.toolUse.id,
170
+ session_id: sessionId,
171
+ });
172
+ }
173
+ emitJson({
174
+ type: 'user',
175
+ message: {
176
+ role: 'user',
177
+ content: [{
178
+ type: 'tool_result',
179
+ tool_use_id: toolRun.toolUse.id,
180
+ content: toolResultContent(toolRun),
181
+ is_error: toolRun.exitCode !== 0,
182
+ }],
183
+ },
184
+ parent_tool_use_id: toolRunParent(toolRun, 'toolResultParentToolUseId', null),
185
+ session_id: sessionId,
186
+ });
187
+ }
188
+ emitJson({
189
+ type: 'assistant',
190
+ message: {
191
+ type: 'message',
192
+ role: 'assistant',
193
+ content: assistantStreamContent(result, parsed),
194
+ stop_reason: 'end_turn',
195
+ usage: estimateUsage(promptText, result),
196
+ },
197
+ parent_tool_use_id: assistantParentToolUseId,
198
+ session_id: sessionId,
199
+ });
200
+ }
201
+
93
202
  export function streamJsonResultMessage({ started, isError, errorSubtype, numTurns, result, sessionId, usage, permissionDenials }) {
94
203
  const common = {
95
204
  type: 'result',