@sylix/coworker 1.3.0 → 1.3.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.
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +145 -292
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/slash/advanced.d.ts +3 -0
- package/dist/commands/slash/advanced.d.ts.map +1 -0
- package/dist/commands/slash/advanced.js +225 -0
- package/dist/commands/slash/advanced.js.map +1 -0
- package/dist/commands/slash/config.d.ts +3 -0
- package/dist/commands/slash/config.d.ts.map +1 -0
- package/dist/commands/slash/config.js +161 -0
- package/dist/commands/slash/config.js.map +1 -0
- package/dist/commands/slash/context.d.ts +3 -0
- package/dist/commands/slash/context.d.ts.map +1 -0
- package/dist/commands/slash/context.js +127 -0
- package/dist/commands/slash/context.js.map +1 -0
- package/dist/commands/slash/core.d.ts +3 -0
- package/dist/commands/slash/core.d.ts.map +1 -0
- package/dist/commands/slash/core.js +112 -0
- package/dist/commands/slash/core.js.map +1 -0
- package/dist/commands/slash/developer.d.ts +3 -0
- package/dist/commands/slash/developer.d.ts.map +1 -0
- package/dist/commands/slash/developer.js +174 -0
- package/dist/commands/slash/developer.js.map +1 -0
- package/dist/commands/slash/files.d.ts +3 -0
- package/dist/commands/slash/files.d.ts.map +1 -0
- package/dist/commands/slash/files.js +216 -0
- package/dist/commands/slash/files.js.map +1 -0
- package/dist/commands/slash/registry.d.ts +36 -0
- package/dist/commands/slash/registry.d.ts.map +1 -0
- package/dist/commands/slash/registry.js +69 -0
- package/dist/commands/slash/registry.js.map +1 -0
- package/dist/commands/slash/session.d.ts +3 -0
- package/dist/commands/slash/session.d.ts.map +1 -0
- package/dist/commands/slash/session.js +144 -0
- package/dist/commands/slash/session.js.map +1 -0
- package/dist/core/CoWorkerAgent.d.ts +8 -3
- package/dist/core/CoWorkerAgent.d.ts.map +1 -1
- package/dist/core/CoWorkerAgent.js +99 -32
- package/dist/core/CoWorkerAgent.js.map +1 -1
- package/dist/session/SessionManager.js +10 -5
- package/dist/session/SessionManager.js.map +1 -1
- package/dist/skills/HookAndSkillManager.js +2 -1
- package/dist/skills/HookAndSkillManager.js.map +1 -1
- package/dist/utils/conversations.d.ts +14 -0
- package/dist/utils/conversations.d.ts.map +1 -0
- package/dist/utils/conversations.js +100 -0
- package/dist/utils/conversations.js.map +1 -0
- package/dist/utils/inputbar.d.ts +87 -0
- package/dist/utils/inputbar.d.ts.map +1 -0
- package/dist/utils/inputbar.js +263 -0
- package/dist/utils/inputbar.js.map +1 -0
- package/dist/utils/output.d.ts +48 -42
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +233 -186
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/palette.d.ts +25 -0
- package/dist/utils/palette.d.ts.map +1 -0
- package/dist/utils/palette.js +92 -0
- package/dist/utils/palette.js.map +1 -0
- package/dist/utils/welcome.d.ts +2 -0
- package/dist/utils/welcome.d.ts.map +1 -0
- package/dist/utils/welcome.js +130 -0
- package/dist/utils/welcome.js.map +1 -0
- package/package.json +1 -1
package/dist/utils/output.js
CHANGED
|
@@ -33,14 +33,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.Timer = exports.ThinkingAnimation = exports.theme = exports.CW_VERSION = void 0;
|
|
36
|
+
exports.Timer = exports.StreamRenderer = exports.ThinkingAnimation = exports.theme = exports.CW_VERSION = void 0;
|
|
37
37
|
exports.getTermWidth = getTermWidth;
|
|
38
38
|
exports.showBanner = showBanner;
|
|
39
39
|
exports.showStaticBanner = showStaticBanner;
|
|
40
40
|
exports.showSessionInfo = showSessionInfo;
|
|
41
|
-
exports.renderMarkdown = renderMarkdown;
|
|
42
41
|
exports.printResponseHeader = printResponseHeader;
|
|
43
|
-
exports.printResponseLine = printResponseLine;
|
|
44
42
|
exports.printResponseFooter = printResponseFooter;
|
|
45
43
|
exports.streamResponseChunk = streamResponseChunk;
|
|
46
44
|
exports.printUserPrompt = printUserPrompt;
|
|
@@ -54,24 +52,21 @@ exports.printToolError = printToolError;
|
|
|
54
52
|
exports.printScoreCard = printScoreCard;
|
|
55
53
|
exports.printCommitBox = printCommitBox;
|
|
56
54
|
exports.printDiff = printDiff;
|
|
55
|
+
exports.checkWorkspaceTrust = checkWorkspaceTrust;
|
|
57
56
|
exports.printHelp = printHelp;
|
|
58
57
|
exports.printCompact = printCompact;
|
|
59
|
-
exports.getSlashCompletions = getSlashCompletions;
|
|
60
|
-
exports.renderSlashMenu = renderSlashMenu;
|
|
61
58
|
exports.printBox = printBox;
|
|
59
|
+
exports.renderMarkdown = renderMarkdown;
|
|
62
60
|
const chalk = __importStar(require("chalk"));
|
|
63
61
|
/**
|
|
64
62
|
* ═══════════════════════════════════════════════════════════════════
|
|
65
63
|
* CoWorker v1.3.0 by Sylix — Premium Output System
|
|
66
64
|
* ═══════════════════════════════════════════════════════════════════
|
|
67
65
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* - Thinking animation with rotating messages
|
|
71
|
-
* - Markdown-aware response rendering (code blocks, bold, inline code)
|
|
72
|
-
* - Score cards, commit boxes, diff previews
|
|
66
|
+
* Premium terminal rendering with true streaming support.
|
|
67
|
+
* All response text renders inside ╷│╵ borders as it arrives.
|
|
73
68
|
*/
|
|
74
|
-
exports.CW_VERSION = '1.3.
|
|
69
|
+
exports.CW_VERSION = '1.3.1';
|
|
75
70
|
// ============================================================================
|
|
76
71
|
// THEME SYSTEM
|
|
77
72
|
// ============================================================================
|
|
@@ -88,16 +83,17 @@ function hex(color) {
|
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
85
|
exports.theme = {
|
|
91
|
-
brand: hex('#00D4FF'),
|
|
92
|
-
accent: hex('#7C3AED'),
|
|
93
|
-
success: hex('#10B981'),
|
|
94
|
-
error: hex('#EF4444'),
|
|
95
|
-
warning: hex('#F59E0B'),
|
|
96
|
-
ai: hex('#A78BFA'),
|
|
97
|
-
dim: hex('#6B7280'),
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
brand: hex('#00D4FF'),
|
|
87
|
+
accent: hex('#7C3AED'),
|
|
88
|
+
success: hex('#10B981'),
|
|
89
|
+
error: hex('#EF4444'),
|
|
90
|
+
warning: hex('#F59E0B'),
|
|
91
|
+
ai: hex('#A78BFA'),
|
|
92
|
+
dim: hex('#6B7280'),
|
|
93
|
+
border: hex('#4B5563'),
|
|
94
|
+
white: hex('#F9FAFB'),
|
|
95
|
+
code: hex('#FCD34D'),
|
|
96
|
+
purple: hex('#A78BFA'),
|
|
101
97
|
};
|
|
102
98
|
// ============================================================================
|
|
103
99
|
// TERMINAL UTILS
|
|
@@ -105,9 +101,6 @@ exports.theme = {
|
|
|
105
101
|
function getTermWidth() {
|
|
106
102
|
return process.stdout.columns || 80;
|
|
107
103
|
}
|
|
108
|
-
function isNarrow() {
|
|
109
|
-
return getTermWidth() < 60;
|
|
110
|
-
}
|
|
111
104
|
function sleep(ms) {
|
|
112
105
|
return new Promise(r => setTimeout(r, ms));
|
|
113
106
|
}
|
|
@@ -120,7 +113,7 @@ function showCursor() {
|
|
|
120
113
|
process.stdout.write('\x1b[?25h');
|
|
121
114
|
}
|
|
122
115
|
// ============================================================================
|
|
123
|
-
//
|
|
116
|
+
// ANIMATED BANNER
|
|
124
117
|
// ============================================================================
|
|
125
118
|
const LOGO_LINES = [
|
|
126
119
|
' ██████╗ ██████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗ ██╗███████╗██████╗ ',
|
|
@@ -130,29 +123,18 @@ const LOGO_LINES = [
|
|
|
130
123
|
'╚██████╗╚██████╔╝╚███╔███╔╝╚██████╔╝██║ ██║██║ ██╗███████╗██║ ██║',
|
|
131
124
|
' ╚═════╝ ╚═════╝ ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝',
|
|
132
125
|
];
|
|
133
|
-
/**
|
|
134
|
-
* Full animated startup banner for CoWorker v1.3.0.
|
|
135
|
-
*
|
|
136
|
-
* 1. Logo slides in line-by-line (60ms between lines)
|
|
137
|
-
* 2. Tagline fades in word-by-word with semantic coloring
|
|
138
|
-
* 3. Divider draws left-to-right (3ms/char)
|
|
139
|
-
* 4. Info line fades in
|
|
140
|
-
* 5. Session info appears with 50ms delay between lines
|
|
141
|
-
* Total: under 1.5 seconds
|
|
142
|
-
*/
|
|
143
126
|
async function showBanner(version, userEmail, model = 'helix-1.2') {
|
|
144
127
|
if (IS_PIPE || process.env.CW_NO_BANNER === '1')
|
|
145
128
|
return;
|
|
146
129
|
hideCursor();
|
|
147
130
|
console.log('');
|
|
148
131
|
try {
|
|
149
|
-
// Step 1: Logo — line by line, each types across
|
|
132
|
+
// Step 1: Logo — line by line, each types across
|
|
150
133
|
for (const line of LOGO_LINES) {
|
|
151
134
|
const chars = [...line];
|
|
152
135
|
let buffer = '';
|
|
153
136
|
for (let i = 0; i < chars.length; i++) {
|
|
154
137
|
buffer += chars[i];
|
|
155
|
-
// Batch 6 chars at a time for speed
|
|
156
138
|
if (i % 6 === 5 || i === chars.length - 1) {
|
|
157
139
|
process.stdout.write(exports.theme.brand(buffer));
|
|
158
140
|
buffer = '';
|
|
@@ -160,9 +142,9 @@ async function showBanner(version, userEmail, model = 'helix-1.2') {
|
|
|
160
142
|
}
|
|
161
143
|
}
|
|
162
144
|
process.stdout.write('\n');
|
|
163
|
-
await sleep(60);
|
|
145
|
+
await sleep(60);
|
|
164
146
|
}
|
|
165
|
-
// Step 2: Tagline — word by word
|
|
147
|
+
// Step 2: Tagline — word by word with semantic colors
|
|
166
148
|
console.log('');
|
|
167
149
|
const taglineWords = [
|
|
168
150
|
{ text: 'by', color: exports.theme.dim },
|
|
@@ -179,7 +161,7 @@ async function showBanner(version, userEmail, model = 'helix-1.2') {
|
|
|
179
161
|
await sleep(100);
|
|
180
162
|
}
|
|
181
163
|
console.log('');
|
|
182
|
-
// Step 3: Divider
|
|
164
|
+
// Step 3: Divider draws left to right
|
|
183
165
|
console.log('');
|
|
184
166
|
const lineWidth = Math.min(getTermWidth() - 4, 60);
|
|
185
167
|
process.stdout.write(' ');
|
|
@@ -189,7 +171,7 @@ async function showBanner(version, userEmail, model = 'helix-1.2') {
|
|
|
189
171
|
await sleep(3);
|
|
190
172
|
}
|
|
191
173
|
console.log('');
|
|
192
|
-
// Step 4: Info line
|
|
174
|
+
// Step 4: Info line
|
|
193
175
|
console.log('');
|
|
194
176
|
const userStr = userEmail ? `Signed in as ${userEmail}` : 'Not signed in';
|
|
195
177
|
console.log(` ${exports.theme.brand('◆')} ${exports.theme.dim(`${userStr} · Model: ${model} · v${version}`)}`);
|
|
@@ -199,9 +181,6 @@ async function showBanner(version, userEmail, model = 'helix-1.2') {
|
|
|
199
181
|
showCursor();
|
|
200
182
|
}
|
|
201
183
|
}
|
|
202
|
-
/**
|
|
203
|
-
* Static banner for non-TTY / piped / quick modes.
|
|
204
|
-
*/
|
|
205
184
|
function showStaticBanner(version) {
|
|
206
185
|
console.log('');
|
|
207
186
|
for (const line of LOGO_LINES) {
|
|
@@ -209,9 +188,6 @@ function showStaticBanner(version) {
|
|
|
209
188
|
}
|
|
210
189
|
console.log(exports.theme.dim(`\n by Sylix · v${version}\n`));
|
|
211
190
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Session info lines — appear with delay between each.
|
|
214
|
-
*/
|
|
215
191
|
async function showSessionInfo(cwd, sessionId) {
|
|
216
192
|
if (IS_PIPE) {
|
|
217
193
|
console.log(` cwd: ${cwd}`);
|
|
@@ -231,7 +207,7 @@ async function showSessionInfo(cwd, sessionId) {
|
|
|
231
207
|
console.log('');
|
|
232
208
|
}
|
|
233
209
|
// ============================================================================
|
|
234
|
-
//
|
|
210
|
+
// THINKING ANIMATION — Rotating messages with pulsing dots
|
|
235
211
|
// ============================================================================
|
|
236
212
|
const THINKING_MESSAGES = [
|
|
237
213
|
'working',
|
|
@@ -239,8 +215,6 @@ const THINKING_MESSAGES = [
|
|
|
239
215
|
'reading codebase',
|
|
240
216
|
'analyzing',
|
|
241
217
|
'on it',
|
|
242
|
-
'crafting something',
|
|
243
|
-
'processing',
|
|
244
218
|
];
|
|
245
219
|
class ThinkingAnimation {
|
|
246
220
|
constructor(customMessage) {
|
|
@@ -253,11 +227,10 @@ class ThinkingAnimation {
|
|
|
253
227
|
return;
|
|
254
228
|
hideCursor();
|
|
255
229
|
this.interval = setInterval(() => {
|
|
256
|
-
// Pulsing dots: working· working·· working··· working
|
|
257
230
|
const dotCount = (this.frame % 4);
|
|
258
231
|
const dots = '.'.repeat(dotCount);
|
|
259
|
-
const pad = '
|
|
260
|
-
process.stdout.write(`\r ${exports.theme.brand('◆')} ${exports.theme.dim(this.message + dots)}${
|
|
232
|
+
const pad = ' '.repeat(3 - dotCount);
|
|
233
|
+
process.stdout.write(`\r ${exports.theme.brand('◆')} ${exports.theme.dim(this.message + dots)}${pad}` + ' '.repeat(10));
|
|
261
234
|
this.frame++;
|
|
262
235
|
}, 400);
|
|
263
236
|
}
|
|
@@ -266,130 +239,129 @@ class ThinkingAnimation {
|
|
|
266
239
|
clearInterval(this.interval);
|
|
267
240
|
this.interval = null;
|
|
268
241
|
}
|
|
269
|
-
// Clear the line
|
|
270
242
|
process.stdout.write('\r' + ' '.repeat(getTermWidth()) + '\r');
|
|
271
243
|
showCursor();
|
|
272
244
|
}
|
|
273
245
|
}
|
|
274
246
|
exports.ThinkingAnimation = ThinkingAnimation;
|
|
275
247
|
// ============================================================================
|
|
276
|
-
//
|
|
248
|
+
// STREAMING RESPONSE RENDERER
|
|
277
249
|
// ============================================================================
|
|
278
250
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
251
|
+
* Manages the response box state during streaming.
|
|
252
|
+
*
|
|
253
|
+
* Correct output:
|
|
254
|
+
* ╷
|
|
255
|
+
* │ Hi! I'm CoWorker, your AI coding assistant.
|
|
256
|
+
* │
|
|
257
|
+
* │ I can help you with:
|
|
258
|
+
* │ · Writing and debugging code
|
|
259
|
+
* │
|
|
260
|
+
* ╵ ✦ 1.2s · 34 tokens
|
|
261
|
+
*
|
|
262
|
+
* Rules:
|
|
263
|
+
* - ALL text inside ╷│╵ border
|
|
264
|
+
* - Border chars (╷ │ ╵) in dim gray #4B5563
|
|
265
|
+
* - Response text in purple #A78BFA
|
|
266
|
+
* - Code blocks switch to yellow #FCD34D
|
|
267
|
+
* - On every \n → print "\n │ "
|
|
281
268
|
*/
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
269
|
+
class StreamRenderer {
|
|
270
|
+
constructor() {
|
|
271
|
+
this.started = false;
|
|
272
|
+
this.inCodeBlock = false;
|
|
273
|
+
this.charCount = 0;
|
|
274
|
+
this.startTime = Date.now();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Call this for EACH chunk as it arrives from the SSE stream.
|
|
278
|
+
* Renders immediately — no buffering.
|
|
279
|
+
*/
|
|
280
|
+
write(chunk) {
|
|
281
|
+
if (!this.started) {
|
|
282
|
+
// Open the response border
|
|
283
|
+
console.log(exports.theme.border(' ╷'));
|
|
284
|
+
process.stdout.write(exports.theme.border(' │') + ' ');
|
|
285
|
+
this.started = true;
|
|
295
286
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
rendered.push('');
|
|
303
|
-
rendered.push(` ${exports.theme.dim(`┌─ ${codeLanguage} ${'─'.repeat(Math.max(0, boxWidth - codeLanguage.length - 5))}┐`)}`);
|
|
304
|
-
for (const codeLine of codeBuffer) {
|
|
305
|
-
const padded = codeLine + ' '.repeat(Math.max(0, boxWidth - codeLine.length - 4));
|
|
306
|
-
rendered.push(` ${exports.theme.dim('│')} ${exports.theme.code(padded)}${exports.theme.dim('│')}`);
|
|
287
|
+
for (const char of chunk) {
|
|
288
|
+
this.charCount++;
|
|
289
|
+
if (char === '\n') {
|
|
290
|
+
// Start a new bordered line
|
|
291
|
+
process.stdout.write('\n' + exports.theme.border(' │') + ' ');
|
|
292
|
+
continue;
|
|
307
293
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// ## Headers
|
|
319
|
-
if (line.match(/^#{1,3}\s+/)) {
|
|
320
|
-
const headerText = line.replace(/^#{1,3}\s+/, '');
|
|
321
|
-
rendered.push('');
|
|
322
|
-
rendered.push(exports.theme.brand(headerText));
|
|
323
|
-
continue;
|
|
294
|
+
// Detect code block toggle
|
|
295
|
+
// We track ``` by checking accumulated chars, but simplified:
|
|
296
|
+
// the chunk itself may contain ```. We'll track via state.
|
|
297
|
+
if (char === '`') {
|
|
298
|
+
// Just render it — code block detection is per-line in the final text
|
|
299
|
+
// For streaming, we use simple color: ai color for prose, code color inside ```
|
|
300
|
+
}
|
|
301
|
+
// Choose color based on whether we're in a code block
|
|
302
|
+
const color = this.inCodeBlock ? exports.theme.code : exports.theme.ai;
|
|
303
|
+
process.stdout.write(color(char));
|
|
324
304
|
}
|
|
325
|
-
//
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
305
|
+
// Check for code block toggles in the chunk
|
|
306
|
+
const backtickMatches = chunk.match(/```/g);
|
|
307
|
+
if (backtickMatches) {
|
|
308
|
+
for (const _match of backtickMatches) {
|
|
309
|
+
this.inCodeBlock = !this.inCodeBlock;
|
|
310
|
+
}
|
|
330
311
|
}
|
|
331
|
-
// Regular text with inline formatting
|
|
332
|
-
rendered.push(renderInline(line));
|
|
333
312
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// ── Response box rendering ──
|
|
347
|
-
function printResponseHeader() {
|
|
348
|
-
console.log(exports.theme.dim(' ╷'));
|
|
349
|
-
}
|
|
350
|
-
function printResponseLine(text) {
|
|
351
|
-
// Wrap text to terminal width
|
|
352
|
-
const maxWidth = getTermWidth() - 6;
|
|
353
|
-
const words = text.split(' ');
|
|
354
|
-
let currentLine = '';
|
|
355
|
-
for (const word of words) {
|
|
356
|
-
if (currentLine.length + word.length + 1 > maxWidth && currentLine.length > 0) {
|
|
357
|
-
console.log(`${exports.theme.dim(' │')} ${exports.theme.ai(currentLine)}`);
|
|
358
|
-
currentLine = word;
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
|
362
|
-
}
|
|
313
|
+
/**
|
|
314
|
+
* Close the response box and print footer.
|
|
315
|
+
*/
|
|
316
|
+
finish() {
|
|
317
|
+
if (!this.started)
|
|
318
|
+
return;
|
|
319
|
+
const elapsed = Date.now() - this.startTime;
|
|
320
|
+
const elapsedStr = elapsed < 1000 ? `${elapsed}ms` : `${(elapsed / 1000).toFixed(1)}s`;
|
|
321
|
+
const tokenEst = Math.ceil(this.charCount / 4);
|
|
322
|
+
console.log(''); // end the last │ line
|
|
323
|
+
console.log(exports.theme.border(` ╵`) + exports.theme.dim(` ✦ ${elapsedStr} · ${tokenEst} tokens`));
|
|
324
|
+
console.log('');
|
|
363
325
|
}
|
|
364
|
-
|
|
365
|
-
|
|
326
|
+
/** Returns the estimated token count. */
|
|
327
|
+
getTokenEstimate() {
|
|
328
|
+
return Math.ceil(this.charCount / 4);
|
|
329
|
+
}
|
|
330
|
+
/** Returns elapsed ms. */
|
|
331
|
+
getElapsed() {
|
|
332
|
+
return Date.now() - this.startTime;
|
|
366
333
|
}
|
|
367
334
|
}
|
|
335
|
+
exports.StreamRenderer = StreamRenderer;
|
|
336
|
+
// ============================================================================
|
|
337
|
+
// LEGACY COMPAT — printResponseHeader/Footer for tool outputs
|
|
338
|
+
// ============================================================================
|
|
339
|
+
function printResponseHeader() {
|
|
340
|
+
console.log(exports.theme.border(' ╷'));
|
|
341
|
+
process.stdout.write(exports.theme.border(' │') + ' ');
|
|
342
|
+
}
|
|
368
343
|
function printResponseFooter(elapsed, tokenEstimate) {
|
|
369
344
|
const elapsedStr = elapsed < 1000 ? `${elapsed}ms` : `${(elapsed / 1000).toFixed(1)}s`;
|
|
370
345
|
const tokenStr = tokenEstimate ? ` · ${tokenEstimate} tokens` : '';
|
|
371
|
-
console.log(exports.theme.dim(`
|
|
346
|
+
console.log(exports.theme.border(` ╵`) + exports.theme.dim(` ✦ ${elapsedStr}${tokenStr}`));
|
|
372
347
|
}
|
|
373
|
-
/**
|
|
374
|
-
* Streams AI response text into the response box with markdown rendering.
|
|
375
|
-
* Call printResponseHeader() first, then stream chunks, then printResponseFooter().
|
|
376
|
-
*/
|
|
377
348
|
function streamResponseChunk(chunk) {
|
|
378
|
-
// Split by newlines and render each part within the box
|
|
379
349
|
const parts = chunk.split('\n');
|
|
380
350
|
for (let i = 0; i < parts.length; i++) {
|
|
381
351
|
if (i > 0) {
|
|
382
|
-
|
|
383
|
-
process.stdout.write(`\n${exports.theme.dim(' │')} `);
|
|
352
|
+
process.stdout.write('\n' + exports.theme.border(' │') + ' ');
|
|
384
353
|
}
|
|
385
354
|
process.stdout.write(exports.theme.ai(parts[i]));
|
|
386
355
|
}
|
|
387
356
|
}
|
|
388
357
|
// ============================================================================
|
|
389
|
-
// PROMPT RENDERING
|
|
358
|
+
// PROMPT RENDERING — Only called ONCE after user hits Enter
|
|
390
359
|
// ============================================================================
|
|
391
360
|
function printUserPrompt(input) {
|
|
392
|
-
|
|
361
|
+
// NOTE: Do NOT call this if readline already echoed the prompt.
|
|
362
|
+
// In the REPL, readline shows "you › input" automatically.
|
|
363
|
+
// This is ONLY for re-printing in non-readline contexts.
|
|
364
|
+
console.log(` ${exports.theme.dim('you')} ${exports.theme.brand('›')} ${input}`);
|
|
393
365
|
}
|
|
394
366
|
// ============================================================================
|
|
395
367
|
// ERROR / SUCCESS / WARNING
|
|
@@ -418,7 +390,7 @@ function printWarning(message) {
|
|
|
418
390
|
console.log(exports.theme.warning(` ⚠ ${message}`));
|
|
419
391
|
}
|
|
420
392
|
// ============================================================================
|
|
421
|
-
// EXIT
|
|
393
|
+
// EXIT
|
|
422
394
|
// ============================================================================
|
|
423
395
|
function printExit() {
|
|
424
396
|
if (IS_PIPE)
|
|
@@ -441,12 +413,9 @@ function printToolError(toolName, error) {
|
|
|
441
413
|
process.stdout.write(`\r ${exports.theme.error('✗')} ${exports.theme.code(toolName)} ${exports.theme.dim(error.substring(0, 60))}` + ' '.repeat(10) + '\n');
|
|
442
414
|
}
|
|
443
415
|
// ============================================================================
|
|
444
|
-
// SCORE CARD
|
|
416
|
+
// SCORE CARD
|
|
445
417
|
// ============================================================================
|
|
446
418
|
function printScoreCard(fileName, scores) {
|
|
447
|
-
const w = Math.min(getTermWidth() - 4, 50);
|
|
448
|
-
const iw = w - 2;
|
|
449
|
-
const title = `Code Review · ${fileName}`;
|
|
450
419
|
console.log('');
|
|
451
420
|
console.log(exports.theme.dim(` ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄`));
|
|
452
421
|
for (const { label, score, max = 10 } of scores) {
|
|
@@ -461,7 +430,7 @@ function printScoreCard(fileName, scores) {
|
|
|
461
430
|
console.log('');
|
|
462
431
|
}
|
|
463
432
|
// ============================================================================
|
|
464
|
-
// COMMIT BOX
|
|
433
|
+
// COMMIT BOX
|
|
465
434
|
// ============================================================================
|
|
466
435
|
function printCommitBox(commitMessage) {
|
|
467
436
|
const w = Math.min(getTermWidth() - 2, 55);
|
|
@@ -470,7 +439,6 @@ function printCommitBox(commitMessage) {
|
|
|
470
439
|
console.log('');
|
|
471
440
|
console.log(exports.theme.brand(` ╭─ ${label} ${'─'.repeat(Math.max(0, headerPad))}╮`));
|
|
472
441
|
console.log(exports.theme.brand(` │`) + ' '.repeat(w - 2) + exports.theme.brand(`│`));
|
|
473
|
-
// Wrap message to fit box
|
|
474
442
|
const maxMsgWidth = w - 6;
|
|
475
443
|
const msgLines = commitMessage.match(new RegExp(`.{1,${maxMsgWidth}}`, 'g')) || [commitMessage];
|
|
476
444
|
for (const msgLine of msgLines) {
|
|
@@ -482,7 +450,7 @@ function printCommitBox(commitMessage) {
|
|
|
482
450
|
console.log('');
|
|
483
451
|
}
|
|
484
452
|
// ============================================================================
|
|
485
|
-
// DIFF PREVIEW
|
|
453
|
+
// DIFF PREVIEW
|
|
486
454
|
// ============================================================================
|
|
487
455
|
function printDiff(fileName, changes) {
|
|
488
456
|
const w = Math.min(getTermWidth() - 4, 60);
|
|
@@ -505,7 +473,80 @@ function printDiff(fileName, changes) {
|
|
|
505
473
|
console.log('');
|
|
506
474
|
}
|
|
507
475
|
// ============================================================================
|
|
508
|
-
//
|
|
476
|
+
// TRUST PROMPT — Branded CoWorker workspace verification
|
|
477
|
+
// ============================================================================
|
|
478
|
+
const fs = __importStar(require("fs"));
|
|
479
|
+
const path = __importStar(require("path"));
|
|
480
|
+
const os = __importStar(require("os"));
|
|
481
|
+
const readline = __importStar(require("readline"));
|
|
482
|
+
const TRUSTED_PATH = path.join(os.homedir(), '.coworker', 'trusted.json');
|
|
483
|
+
function loadTrustedPaths() {
|
|
484
|
+
try {
|
|
485
|
+
if (fs.existsSync(TRUSTED_PATH)) {
|
|
486
|
+
const data = JSON.parse(fs.readFileSync(TRUSTED_PATH, 'utf8'));
|
|
487
|
+
return Array.isArray(data?.trustedPaths) ? data.trustedPaths : [];
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch { /* ignore */ }
|
|
491
|
+
return [];
|
|
492
|
+
}
|
|
493
|
+
function saveTrustedPaths(paths) {
|
|
494
|
+
try {
|
|
495
|
+
const dir = path.dirname(TRUSTED_PATH);
|
|
496
|
+
if (!fs.existsSync(dir)) {
|
|
497
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
498
|
+
}
|
|
499
|
+
fs.writeFileSync(TRUSTED_PATH, JSON.stringify({ trustedPaths: paths }, null, 2));
|
|
500
|
+
}
|
|
501
|
+
catch { /* ignore */ }
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Shows the CoWorker branded workspace trust prompt.
|
|
505
|
+
* Returns true if user trusts, false if they want to exit.
|
|
506
|
+
* Skips silently if the directory is already trusted.
|
|
507
|
+
*/
|
|
508
|
+
async function checkWorkspaceTrust(cwd) {
|
|
509
|
+
if (IS_PIPE)
|
|
510
|
+
return true; // Non-interactive mode — skip
|
|
511
|
+
const trustedPaths = loadTrustedPaths();
|
|
512
|
+
const normalizedCwd = cwd.replace(/\\/g, '/').toLowerCase();
|
|
513
|
+
// Check if already trusted
|
|
514
|
+
const isTrusted = trustedPaths.some(p => {
|
|
515
|
+
const normalized = p.replace(/\\/g, '/').toLowerCase();
|
|
516
|
+
return normalizedCwd.startsWith(normalized) || normalizedCwd === normalized;
|
|
517
|
+
});
|
|
518
|
+
if (isTrusted)
|
|
519
|
+
return true;
|
|
520
|
+
// Show the branded trust prompt
|
|
521
|
+
const lineWidth = Math.min(getTermWidth() - 4, 50);
|
|
522
|
+
console.log('');
|
|
523
|
+
console.log(exports.theme.dim(` ${'─'.repeat(lineWidth)}`));
|
|
524
|
+
console.log(` ${exports.theme.brand('◆')} ${exports.theme.brand('Workspace:')} ${exports.theme.white(cwd)}`);
|
|
525
|
+
console.log(exports.theme.dim(` ${'─'.repeat(lineWidth)}`));
|
|
526
|
+
console.log('');
|
|
527
|
+
console.log(exports.theme.dim(' CoWorker can read, edit, and run files here.'));
|
|
528
|
+
console.log(exports.theme.dim(' Only use in folders you own or trust.'));
|
|
529
|
+
console.log('');
|
|
530
|
+
console.log(` ${exports.theme.brand('›')} ${exports.theme.white('1. Got it, let\'s go')}`);
|
|
531
|
+
console.log(` ${exports.theme.dim('2. Exit')}`);
|
|
532
|
+
console.log('');
|
|
533
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
534
|
+
const answer = await new Promise((resolve) => {
|
|
535
|
+
rl.question(exports.theme.dim(' Enter to confirm · Esc to cancel › '), (a) => {
|
|
536
|
+
resolve(a.trim());
|
|
537
|
+
rl.close();
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
if (answer === '2' || answer.toLowerCase() === 'exit') {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
// Trust this directory
|
|
544
|
+
trustedPaths.push(cwd);
|
|
545
|
+
saveTrustedPaths(trustedPaths);
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
// ============================================================================
|
|
549
|
+
// HELP + COMPACT
|
|
509
550
|
// ============================================================================
|
|
510
551
|
function printHelp() {
|
|
511
552
|
console.log(`
|
|
@@ -531,36 +572,8 @@ function printCompact(msgCount, tokenEst, sessionId) {
|
|
|
531
572
|
exports.theme.dim(` │ Session: ${sessionId.substring(0, 8)}`));
|
|
532
573
|
console.log('');
|
|
533
574
|
}
|
|
534
|
-
const BUILTIN_COMMANDS = [
|
|
535
|
-
{ name: '/help', desc: 'show all commands' },
|
|
536
|
-
{ name: '/clear', desc: 'clear the screen' },
|
|
537
|
-
{ name: '/review', desc: 'review current branch' },
|
|
538
|
-
{ name: '/commit', desc: 'generate commit message' },
|
|
539
|
-
{ name: '/status', desc: 'show auth & session' },
|
|
540
|
-
{ name: '/compact', desc: 'context window usage' },
|
|
541
|
-
{ name: '/exit', desc: 'end session' },
|
|
542
|
-
];
|
|
543
|
-
/**
|
|
544
|
-
* Returns matching slash commands for a partial input.
|
|
545
|
-
*/
|
|
546
|
-
function getSlashCompletions(partial) {
|
|
547
|
-
if (!partial.startsWith('/'))
|
|
548
|
-
return [];
|
|
549
|
-
return BUILTIN_COMMANDS.filter(cmd => cmd.name.startsWith(partial));
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Renders the slash completion menu below the input.
|
|
553
|
-
*/
|
|
554
|
-
function renderSlashMenu(matches) {
|
|
555
|
-
const lines = [];
|
|
556
|
-
for (let i = 0; i < matches.length; i++) {
|
|
557
|
-
const prefix = i === matches.length - 1 ? '└' : '├';
|
|
558
|
-
lines.push(` ${exports.theme.dim(prefix)} ${exports.theme.code(matches[i].name.padEnd(12))} ${exports.theme.dim(matches[i].desc)}`);
|
|
559
|
-
}
|
|
560
|
-
return lines.join('\n');
|
|
561
|
-
}
|
|
562
575
|
// ============================================================================
|
|
563
|
-
// GENERIC BOX
|
|
576
|
+
// GENERIC BOX + TIMER
|
|
564
577
|
// ============================================================================
|
|
565
578
|
function printBox(label, lines) {
|
|
566
579
|
const w = Math.min(getTermWidth() - 2, 70);
|
|
@@ -572,9 +585,6 @@ function printBox(label, lines) {
|
|
|
572
585
|
}
|
|
573
586
|
console.log(exports.theme.brand(` ╰${'─'.repeat(w - 3)}╯`));
|
|
574
587
|
}
|
|
575
|
-
// ============================================================================
|
|
576
|
-
// TIMER
|
|
577
|
-
// ============================================================================
|
|
578
588
|
class Timer {
|
|
579
589
|
constructor() {
|
|
580
590
|
this.start = Date.now();
|
|
@@ -588,4 +598,41 @@ class Timer {
|
|
|
588
598
|
}
|
|
589
599
|
}
|
|
590
600
|
exports.Timer = Timer;
|
|
601
|
+
// ============================================================================
|
|
602
|
+
// RENDER MARKDOWN (for buffered final rendering)
|
|
603
|
+
// ============================================================================
|
|
604
|
+
function renderMarkdown(text) {
|
|
605
|
+
const lines = text.split('\n');
|
|
606
|
+
const rendered = [];
|
|
607
|
+
let inCodeBlock = false;
|
|
608
|
+
for (const line of lines) {
|
|
609
|
+
if (line.trim().startsWith('```') && !inCodeBlock) {
|
|
610
|
+
inCodeBlock = true;
|
|
611
|
+
const lang = line.trim().replace('```', '').trim() || 'code';
|
|
612
|
+
rendered.push(` ${exports.theme.dim(`┌─ ${lang} ──`)}`);
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
if (line.trim() === '```' && inCodeBlock) {
|
|
616
|
+
inCodeBlock = false;
|
|
617
|
+
rendered.push(` ${exports.theme.dim('└──')}`);
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (inCodeBlock) {
|
|
621
|
+
rendered.push(` ${exports.theme.dim('│')} ${exports.theme.code(line)}`);
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
if (line.match(/^#{1,3}\s+/)) {
|
|
625
|
+
rendered.push(exports.theme.brand(line.replace(/^#{1,3}\s+/, '')));
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (line.match(/^\s*[-*]\s+/)) {
|
|
629
|
+
rendered.push(`${exports.theme.dim('·')} ${line.replace(/^\s*[-*]\s+/, '')}`);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
let result = line.replace(/\*\*(.+?)\*\*/g, (_, c) => exports.theme.white(c));
|
|
633
|
+
result = result.replace(/`(.+?)`/g, (_, c) => exports.theme.code(c));
|
|
634
|
+
rendered.push(result);
|
|
635
|
+
}
|
|
636
|
+
return rendered.join('\n');
|
|
637
|
+
}
|
|
591
638
|
//# sourceMappingURL=output.js.map
|