bazaar.it 0.1.0 ā 0.2.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.
- package/README.md +489 -3
- package/bin/baz.js +6 -1
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +109 -0
- package/dist/commands/capabilities.d.ts +2 -0
- package/dist/commands/capabilities.js +44 -0
- package/dist/commands/context.d.ts +13 -0
- package/dist/commands/context.js +498 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/export.js +360 -0
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +180 -0
- package/dist/commands/loop.d.ts +2 -0
- package/dist/commands/loop.js +538 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +143 -0
- package/dist/commands/media.d.ts +2 -0
- package/dist/commands/media.js +362 -0
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +786 -0
- package/dist/commands/prompt.d.ts +2 -0
- package/dist/commands/prompt.js +529 -0
- package/dist/commands/recipe.d.ts +15 -0
- package/dist/commands/recipe.js +607 -0
- package/dist/commands/review.d.ts +17 -0
- package/dist/commands/review.js +345 -0
- package/dist/commands/scenes.d.ts +2 -0
- package/dist/commands/scenes.js +481 -0
- package/dist/commands/share.d.ts +2 -0
- package/dist/commands/share.js +226 -0
- package/dist/commands/state.d.ts +2 -0
- package/dist/commands/state.js +171 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +219 -0
- package/dist/commands/template.d.ts +2 -0
- package/dist/commands/template.js +123 -0
- package/dist/commands/verify.d.ts +2 -0
- package/dist/commands/verify.js +150 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +124 -0
- package/dist/lib/api.d.ts +186 -0
- package/dist/lib/api.js +717 -0
- package/dist/lib/banner.d.ts +12 -0
- package/dist/lib/banner.js +69 -0
- package/dist/lib/config.d.ts +33 -0
- package/dist/lib/config.js +99 -0
- package/dist/lib/output.d.ts +52 -0
- package/dist/lib/output.js +162 -0
- package/dist/lib/project-state.d.ts +52 -0
- package/dist/lib/project-state.js +178 -0
- package/dist/lib/sse.d.ts +168 -0
- package/dist/lib/sse.js +227 -0
- package/dist/lib/version.d.ts +1 -0
- package/dist/lib/version.js +3 -0
- package/dist/repl.d.ts +4 -0
- package/dist/repl.js +764 -0
- package/package.json +39 -5
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Commands - Project context for agent handshake
|
|
3
|
+
*
|
|
4
|
+
* Store and retrieve flexible context for projects:
|
|
5
|
+
* - Goals, requirements, specs
|
|
6
|
+
* - Reference URLs, videos
|
|
7
|
+
* - Uploaded files (PDFs, images)
|
|
8
|
+
* - Any other context the agent needs
|
|
9
|
+
*
|
|
10
|
+
* The AI uses this context when generating content.
|
|
11
|
+
*/
|
|
12
|
+
import { Command } from 'commander';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import ora from 'ora';
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { loadConfig, hasAuth, getProjectId } from '../lib/config.js';
|
|
18
|
+
import { apiRequest, uploadMedia, ApiError } from '../lib/api.js';
|
|
19
|
+
import { output } from '../lib/output.js';
|
|
20
|
+
function exitContextAuthError(globalOpts) {
|
|
21
|
+
if (globalOpts.json) {
|
|
22
|
+
output({
|
|
23
|
+
type: 'error',
|
|
24
|
+
code: 'AUTH_MISSING',
|
|
25
|
+
message: 'Not authenticated',
|
|
26
|
+
category: 'auth',
|
|
27
|
+
retryable: false,
|
|
28
|
+
transient: false,
|
|
29
|
+
exitCode: 13,
|
|
30
|
+
suggestion: 'Run: baz auth login <api-key>',
|
|
31
|
+
}, { json: true, compact: globalOpts.compact });
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.error(chalk.red('Not authenticated. Run: baz auth login <api-key>'));
|
|
35
|
+
}
|
|
36
|
+
process.exit(13);
|
|
37
|
+
}
|
|
38
|
+
function exitContextProjectValidationError(message, globalOpts) {
|
|
39
|
+
if (globalOpts.json) {
|
|
40
|
+
output({
|
|
41
|
+
type: 'error',
|
|
42
|
+
code: 'VALIDATION',
|
|
43
|
+
message,
|
|
44
|
+
category: 'validation',
|
|
45
|
+
retryable: false,
|
|
46
|
+
transient: false,
|
|
47
|
+
exitCode: 64,
|
|
48
|
+
}, { json: true, compact: globalOpts.compact });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.error(chalk.red(message));
|
|
52
|
+
}
|
|
53
|
+
process.exit(64);
|
|
54
|
+
}
|
|
55
|
+
export const contextCommand = new Command('context')
|
|
56
|
+
.description('Manage project context (goals, requirements, references)');
|
|
57
|
+
/**
|
|
58
|
+
* baz context add "<content>" [--label <label>] [--file <path>]
|
|
59
|
+
*/
|
|
60
|
+
contextCommand
|
|
61
|
+
.command('add')
|
|
62
|
+
.description('Add context to the current project')
|
|
63
|
+
.argument('[content]', 'Text content, URL, or description')
|
|
64
|
+
.option('--label <label>', 'Label for this context (e.g., "goal", "requirement", "brand")')
|
|
65
|
+
.option('--file <path>', 'Upload a file as context (PDF, image, video)')
|
|
66
|
+
.option('--type <type>', 'Content type: text, url, file, image, video', 'text')
|
|
67
|
+
.action(async (content, options, cmd) => {
|
|
68
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
69
|
+
const config = loadConfig({
|
|
70
|
+
configPath: globalOpts.config,
|
|
71
|
+
apiUrl: globalOpts.apiUrl,
|
|
72
|
+
projectId: globalOpts.projectId,
|
|
73
|
+
});
|
|
74
|
+
if (!hasAuth(config)) {
|
|
75
|
+
exitContextAuthError(globalOpts);
|
|
76
|
+
}
|
|
77
|
+
let projectId;
|
|
78
|
+
try {
|
|
79
|
+
projectId = getProjectId(config, globalOpts.projectId);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
exitContextProjectValidationError(err.message, globalOpts);
|
|
83
|
+
}
|
|
84
|
+
// Handle file upload
|
|
85
|
+
if (options.file) {
|
|
86
|
+
const filePath = path.resolve(options.file);
|
|
87
|
+
if (!fs.existsSync(filePath)) {
|
|
88
|
+
console.error(chalk.red(`File not found: ${filePath}`));
|
|
89
|
+
process.exit(64);
|
|
90
|
+
}
|
|
91
|
+
const spinner = globalOpts.json ? null : ora('Uploading file...').start();
|
|
92
|
+
try {
|
|
93
|
+
const buffer = fs.readFileSync(filePath);
|
|
94
|
+
const fileName = path.basename(filePath);
|
|
95
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
96
|
+
// Determine content type from extension
|
|
97
|
+
const mimeTypes = {
|
|
98
|
+
'.pdf': 'application/pdf',
|
|
99
|
+
'.png': 'image/png',
|
|
100
|
+
'.jpg': 'image/jpeg',
|
|
101
|
+
'.jpeg': 'image/jpeg',
|
|
102
|
+
'.gif': 'image/gif',
|
|
103
|
+
'.webp': 'image/webp',
|
|
104
|
+
'.mp4': 'video/mp4',
|
|
105
|
+
'.mov': 'video/quicktime',
|
|
106
|
+
'.webm': 'video/webm',
|
|
107
|
+
};
|
|
108
|
+
const mimeType = mimeTypes[ext] || 'application/octet-stream';
|
|
109
|
+
const contentType = ext === '.pdf' ? 'file'
|
|
110
|
+
: mimeType.startsWith('image/') ? 'image'
|
|
111
|
+
: mimeType.startsWith('video/') ? 'video'
|
|
112
|
+
: 'file';
|
|
113
|
+
const uploadResult = await uploadMedia(config, {
|
|
114
|
+
projectId,
|
|
115
|
+
buffer,
|
|
116
|
+
filename: fileName,
|
|
117
|
+
mimeType,
|
|
118
|
+
});
|
|
119
|
+
if (spinner)
|
|
120
|
+
spinner.text = 'Saving context...';
|
|
121
|
+
const result = await apiRequest(config, 'context.add', {
|
|
122
|
+
projectId,
|
|
123
|
+
content: content || `Uploaded file: ${fileName}`,
|
|
124
|
+
label: options.label,
|
|
125
|
+
contentType,
|
|
126
|
+
fileUrl: uploadResult.url,
|
|
127
|
+
fileName: uploadResult.originalName,
|
|
128
|
+
fileSizeBytes: uploadResult.size,
|
|
129
|
+
});
|
|
130
|
+
spinner?.stop();
|
|
131
|
+
if (globalOpts.json) {
|
|
132
|
+
output({
|
|
133
|
+
type: 'context_added',
|
|
134
|
+
...result.context,
|
|
135
|
+
fileUrl: uploadResult.url,
|
|
136
|
+
}, { json: true, compact: globalOpts.compact });
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log(chalk.green(`ā Added context with file: ${fileName}`));
|
|
140
|
+
if (options.label)
|
|
141
|
+
console.log(chalk.gray(` Label: ${options.label}`));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
spinner?.stop();
|
|
146
|
+
if (err instanceof ApiError) {
|
|
147
|
+
if (globalOpts.json) {
|
|
148
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
152
|
+
if (err.suggestion)
|
|
153
|
+
console.error(chalk.gray(`Suggestion: ${err.suggestion}`));
|
|
154
|
+
}
|
|
155
|
+
process.exit(err.exitCode);
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Text/URL content
|
|
162
|
+
if (!content) {
|
|
163
|
+
console.error(chalk.red('Content is required. Provide text, URL, or use --file'));
|
|
164
|
+
process.exit(65);
|
|
165
|
+
}
|
|
166
|
+
// Auto-detect URL
|
|
167
|
+
const isUrl = content.startsWith('http://') || content.startsWith('https://');
|
|
168
|
+
const contentType = options.type || (isUrl ? 'url' : 'text');
|
|
169
|
+
const spinner = globalOpts.json ? null : ora('Adding context...').start();
|
|
170
|
+
try {
|
|
171
|
+
const result = await apiRequest(config, 'context.add', {
|
|
172
|
+
projectId,
|
|
173
|
+
content,
|
|
174
|
+
label: options.label,
|
|
175
|
+
contentType,
|
|
176
|
+
});
|
|
177
|
+
spinner?.stop();
|
|
178
|
+
if (globalOpts.json) {
|
|
179
|
+
output({
|
|
180
|
+
type: 'context_added',
|
|
181
|
+
...result.context,
|
|
182
|
+
}, { json: true, compact: globalOpts.compact });
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.log(chalk.green('ā Context added'));
|
|
186
|
+
if (options.label)
|
|
187
|
+
console.log(chalk.gray(` Label: ${options.label}`));
|
|
188
|
+
console.log(chalk.gray(` "${content.slice(0, 60)}${content.length > 60 ? '...' : ''}"`));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
spinner?.stop();
|
|
193
|
+
if (err instanceof ApiError) {
|
|
194
|
+
if (globalOpts.json) {
|
|
195
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
199
|
+
if (err.suggestion)
|
|
200
|
+
console.error(chalk.gray(`Suggestion: ${err.suggestion}`));
|
|
201
|
+
}
|
|
202
|
+
process.exit(err.exitCode);
|
|
203
|
+
}
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
/**
|
|
208
|
+
* baz context list [--label <label>]
|
|
209
|
+
*/
|
|
210
|
+
contextCommand
|
|
211
|
+
.command('list')
|
|
212
|
+
.description('List all context for the current project')
|
|
213
|
+
.option('--label <label>', 'Filter by label')
|
|
214
|
+
.action(async (options, cmd) => {
|
|
215
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
216
|
+
const config = loadConfig({
|
|
217
|
+
configPath: globalOpts.config,
|
|
218
|
+
apiUrl: globalOpts.apiUrl,
|
|
219
|
+
projectId: globalOpts.projectId,
|
|
220
|
+
});
|
|
221
|
+
if (!hasAuth(config)) {
|
|
222
|
+
exitContextAuthError(globalOpts);
|
|
223
|
+
}
|
|
224
|
+
let projectId;
|
|
225
|
+
try {
|
|
226
|
+
projectId = getProjectId(config, globalOpts.projectId);
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
exitContextProjectValidationError(err.message, globalOpts);
|
|
230
|
+
}
|
|
231
|
+
const spinner = globalOpts.json ? null : ora('Fetching context...').start();
|
|
232
|
+
try {
|
|
233
|
+
const result = await apiRequest(config, 'context.list', {
|
|
234
|
+
projectId,
|
|
235
|
+
label: options.label,
|
|
236
|
+
});
|
|
237
|
+
spinner?.stop();
|
|
238
|
+
if (globalOpts.json) {
|
|
239
|
+
output({
|
|
240
|
+
type: 'context_list',
|
|
241
|
+
projectId,
|
|
242
|
+
count: result.length,
|
|
243
|
+
entries: result,
|
|
244
|
+
}, { json: true, compact: globalOpts.compact });
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
if (result.length === 0) {
|
|
248
|
+
console.log(chalk.gray('No context found for this project.'));
|
|
249
|
+
console.log(chalk.gray('Add context with: baz context add "<content>" --label "goal"'));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
console.log(chalk.bold(`\nš Project Context (${result.length} entries)\n`));
|
|
253
|
+
// Group by label
|
|
254
|
+
const grouped = {};
|
|
255
|
+
for (const entry of result) {
|
|
256
|
+
const key = entry.label || '(no label)';
|
|
257
|
+
if (!grouped[key])
|
|
258
|
+
grouped[key] = [];
|
|
259
|
+
grouped[key].push(entry);
|
|
260
|
+
}
|
|
261
|
+
for (const [label, entries] of Object.entries(grouped)) {
|
|
262
|
+
console.log(chalk.cyan.bold(` ${label}:`));
|
|
263
|
+
for (const entry of entries) {
|
|
264
|
+
const preview = entry.content.slice(0, 70);
|
|
265
|
+
const suffix = entry.content.length > 70 ? '...' : '';
|
|
266
|
+
const typeIcon = entry.contentType === 'url' ? 'š'
|
|
267
|
+
: entry.contentType === 'file' ? 'š'
|
|
268
|
+
: entry.contentType === 'image' ? 'š¼ļø'
|
|
269
|
+
: entry.contentType === 'video' ? 'š¬'
|
|
270
|
+
: 'š';
|
|
271
|
+
console.log(` ${typeIcon} ${preview}${suffix}`);
|
|
272
|
+
console.log(chalk.gray(` ID: ${entry.id.slice(0, 8)}`));
|
|
273
|
+
}
|
|
274
|
+
console.log();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
spinner?.stop();
|
|
280
|
+
if (err instanceof ApiError) {
|
|
281
|
+
if (globalOpts.json) {
|
|
282
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
286
|
+
}
|
|
287
|
+
process.exit(err.exitCode);
|
|
288
|
+
}
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
/**
|
|
293
|
+
* baz context remove <id>
|
|
294
|
+
*/
|
|
295
|
+
contextCommand
|
|
296
|
+
.command('remove')
|
|
297
|
+
.description('Remove a specific context entry')
|
|
298
|
+
.argument('<id>', 'Context entry ID (or partial ID)')
|
|
299
|
+
.action(async (contextId, options, cmd) => {
|
|
300
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
301
|
+
const config = loadConfig({
|
|
302
|
+
configPath: globalOpts.config,
|
|
303
|
+
apiUrl: globalOpts.apiUrl,
|
|
304
|
+
projectId: globalOpts.projectId,
|
|
305
|
+
});
|
|
306
|
+
if (!hasAuth(config)) {
|
|
307
|
+
exitContextAuthError(globalOpts);
|
|
308
|
+
}
|
|
309
|
+
let projectId;
|
|
310
|
+
try {
|
|
311
|
+
projectId = getProjectId(config, globalOpts.projectId);
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
exitContextProjectValidationError(err.message, globalOpts);
|
|
315
|
+
}
|
|
316
|
+
const spinner = globalOpts.json ? null : ora('Removing context...').start();
|
|
317
|
+
try {
|
|
318
|
+
let resolvedContextId = contextId;
|
|
319
|
+
const uuidLike = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
320
|
+
// Resolve partial IDs against project context entries for better agent ergonomics.
|
|
321
|
+
if (!uuidLike.test(resolvedContextId)) {
|
|
322
|
+
const entries = await apiRequest(config, 'context.list', { projectId });
|
|
323
|
+
const match = entries.find((entry) => entry.id.startsWith(resolvedContextId));
|
|
324
|
+
if (!match) {
|
|
325
|
+
spinner?.stop();
|
|
326
|
+
console.error(chalk.red(`Context not found: ${contextId}`));
|
|
327
|
+
process.exit(64);
|
|
328
|
+
}
|
|
329
|
+
resolvedContextId = match.id;
|
|
330
|
+
}
|
|
331
|
+
await apiRequest(config, 'context.remove', { contextId: resolvedContextId });
|
|
332
|
+
spinner?.stop();
|
|
333
|
+
if (globalOpts.json) {
|
|
334
|
+
output({
|
|
335
|
+
type: 'context_removed',
|
|
336
|
+
contextId: resolvedContextId,
|
|
337
|
+
success: true,
|
|
338
|
+
}, { json: true, compact: globalOpts.compact });
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.log(chalk.green('ā Context removed'));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (err) {
|
|
345
|
+
spinner?.stop();
|
|
346
|
+
if (err instanceof ApiError) {
|
|
347
|
+
if (globalOpts.json) {
|
|
348
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
352
|
+
}
|
|
353
|
+
process.exit(err.exitCode);
|
|
354
|
+
}
|
|
355
|
+
throw err;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
/**
|
|
359
|
+
* baz context clear [--label <label>]
|
|
360
|
+
*/
|
|
361
|
+
contextCommand
|
|
362
|
+
.command('clear')
|
|
363
|
+
.description('Clear all context for the current project')
|
|
364
|
+
.option('--label <label>', 'Only clear context with this label')
|
|
365
|
+
.action(async (options, cmd) => {
|
|
366
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
367
|
+
const config = loadConfig({
|
|
368
|
+
configPath: globalOpts.config,
|
|
369
|
+
apiUrl: globalOpts.apiUrl,
|
|
370
|
+
projectId: globalOpts.projectId,
|
|
371
|
+
});
|
|
372
|
+
if (!hasAuth(config)) {
|
|
373
|
+
exitContextAuthError(globalOpts);
|
|
374
|
+
}
|
|
375
|
+
let projectId;
|
|
376
|
+
try {
|
|
377
|
+
projectId = getProjectId(config, globalOpts.projectId);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
exitContextProjectValidationError(err.message, globalOpts);
|
|
381
|
+
}
|
|
382
|
+
const spinner = globalOpts.json ? null : ora('Clearing context...').start();
|
|
383
|
+
try {
|
|
384
|
+
const result = await apiRequest(config, 'context.clear', {
|
|
385
|
+
projectId,
|
|
386
|
+
label: options.label,
|
|
387
|
+
});
|
|
388
|
+
spinner?.stop();
|
|
389
|
+
if (globalOpts.json) {
|
|
390
|
+
output({
|
|
391
|
+
type: 'context_cleared',
|
|
392
|
+
projectId,
|
|
393
|
+
deletedCount: result.deletedCount,
|
|
394
|
+
label: options.label,
|
|
395
|
+
}, { json: true, compact: globalOpts.compact });
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
const labelSuffix = options.label ? ` with label "${options.label}"` : '';
|
|
399
|
+
console.log(chalk.green(`ā Cleared ${result.deletedCount} context entries${labelSuffix}`));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
spinner?.stop();
|
|
404
|
+
if (err instanceof ApiError) {
|
|
405
|
+
if (globalOpts.json) {
|
|
406
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
410
|
+
}
|
|
411
|
+
process.exit(err.exitCode);
|
|
412
|
+
}
|
|
413
|
+
throw err;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
/**
|
|
417
|
+
* baz context show (alias for list with full details)
|
|
418
|
+
*/
|
|
419
|
+
contextCommand
|
|
420
|
+
.command('show')
|
|
421
|
+
.description('Show all context for the current project (alias for list)')
|
|
422
|
+
.option('--label <label>', 'Filter by label')
|
|
423
|
+
.action(async (options, cmd) => {
|
|
424
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
425
|
+
const config = loadConfig({
|
|
426
|
+
configPath: globalOpts.config,
|
|
427
|
+
apiUrl: globalOpts.apiUrl,
|
|
428
|
+
projectId: globalOpts.projectId,
|
|
429
|
+
});
|
|
430
|
+
if (!hasAuth(config)) {
|
|
431
|
+
exitContextAuthError(globalOpts);
|
|
432
|
+
}
|
|
433
|
+
let projectId;
|
|
434
|
+
try {
|
|
435
|
+
projectId = getProjectId(config, globalOpts.projectId);
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
exitContextProjectValidationError(err.message, globalOpts);
|
|
439
|
+
}
|
|
440
|
+
const spinner = globalOpts.json ? null : ora('Fetching context...').start();
|
|
441
|
+
try {
|
|
442
|
+
const result = await apiRequest(config, 'context.list', {
|
|
443
|
+
projectId,
|
|
444
|
+
label: options.label,
|
|
445
|
+
});
|
|
446
|
+
spinner?.stop();
|
|
447
|
+
if (globalOpts.json) {
|
|
448
|
+
output({
|
|
449
|
+
type: 'context_list',
|
|
450
|
+
projectId,
|
|
451
|
+
count: result.length,
|
|
452
|
+
entries: result,
|
|
453
|
+
}, { json: true, compact: globalOpts.compact });
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (result.length === 0) {
|
|
457
|
+
console.log(chalk.gray('No context found for this project.'));
|
|
458
|
+
console.log(chalk.gray('Add context with: baz context add "<content>" --label "goal"'));
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
console.log(chalk.bold(`\nš Project Context (${result.length} entries)\n`));
|
|
462
|
+
const grouped = {};
|
|
463
|
+
for (const entry of result) {
|
|
464
|
+
const key = entry.label || '(no label)';
|
|
465
|
+
if (!grouped[key])
|
|
466
|
+
grouped[key] = [];
|
|
467
|
+
grouped[key].push(entry);
|
|
468
|
+
}
|
|
469
|
+
for (const [label, entries] of Object.entries(grouped)) {
|
|
470
|
+
console.log(chalk.cyan.bold(` ${label}:`));
|
|
471
|
+
for (const entry of entries) {
|
|
472
|
+
const preview = entry.content.slice(0, 70);
|
|
473
|
+
const suffix = entry.content.length > 70 ? '...' : '';
|
|
474
|
+
const typeIcon = entry.contentType === 'url' ? 'š'
|
|
475
|
+
: entry.contentType === 'file' ? 'š'
|
|
476
|
+
: entry.contentType === 'image' ? 'š¼ļø'
|
|
477
|
+
: entry.contentType === 'video' ? 'š¬'
|
|
478
|
+
: 'š';
|
|
479
|
+
console.log(` ${typeIcon} ${preview}${suffix}`);
|
|
480
|
+
console.log(chalk.gray(` ID: ${entry.id.slice(0, 8)}`));
|
|
481
|
+
}
|
|
482
|
+
console.log();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
catch (err) {
|
|
486
|
+
spinner?.stop();
|
|
487
|
+
if (err instanceof ApiError) {
|
|
488
|
+
if (globalOpts.json) {
|
|
489
|
+
output(err.toJSON(), { json: true, compact: globalOpts.compact });
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
493
|
+
}
|
|
494
|
+
process.exit(err.exitCode);
|
|
495
|
+
}
|
|
496
|
+
throw err;
|
|
497
|
+
}
|
|
498
|
+
});
|