@zibby/cli 0.1.26 → 0.1.28

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 (46) hide show
  1. package/README.md +44 -44
  2. package/dist/auth/cli-login.js +18 -0
  3. package/dist/bin/zibby.js +2 -0
  4. package/dist/commands/agent-reliability.js +8 -0
  5. package/dist/commands/analyze-graph.js +18 -0
  6. package/dist/commands/chat-session-store.js +1 -0
  7. package/dist/commands/chat.js +79 -0
  8. package/dist/commands/ci-setup.js +18 -0
  9. package/dist/commands/generate.js +69 -0
  10. package/dist/commands/implement.js +65 -0
  11. package/dist/commands/init.js +344 -0
  12. package/dist/commands/list-projects.js +11 -0
  13. package/dist/commands/memory.js +39 -0
  14. package/dist/commands/run-capacity-queue-cli.js +4 -0
  15. package/dist/commands/run.js +112 -0
  16. package/dist/commands/setup-scripts.js +15 -0
  17. package/dist/commands/studio.js +33 -0
  18. package/dist/commands/upload.js +22 -0
  19. package/dist/commands/video.js +6 -0
  20. package/dist/commands/workflow.js +45 -0
  21. package/dist/config/config.js +1 -0
  22. package/dist/config/environments.js +1 -0
  23. package/dist/utils/chat-run-lifecycle.js +3 -0
  24. package/dist/utils/execution-context.js +1 -0
  25. package/dist/utils/progress-reporter.js +1 -0
  26. package/dist/utils/studio-cli-log-mirror.js +1 -0
  27. package/dist/utils/studio-installer.js +7 -0
  28. package/dist/utils/studio-launcher.js +1 -0
  29. package/package.json +20 -16
  30. package/bin/zibby.js +0 -273
  31. package/src/auth/cli-login.js +0 -404
  32. package/src/commands/analyze-graph.js +0 -336
  33. package/src/commands/ci-setup.js +0 -65
  34. package/src/commands/implement.js +0 -664
  35. package/src/commands/init.js +0 -770
  36. package/src/commands/list-projects.js +0 -77
  37. package/src/commands/memory.js +0 -171
  38. package/src/commands/run.js +0 -919
  39. package/src/commands/setup-scripts.js +0 -114
  40. package/src/commands/upload.js +0 -162
  41. package/src/commands/video.js +0 -30
  42. package/src/commands/workflow.js +0 -368
  43. package/src/config/config.js +0 -117
  44. package/src/config/environments.js +0 -145
  45. package/src/utils/execution-context.js +0 -25
  46. package/src/utils/progress-reporter.js +0 -155
@@ -1,336 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Analyze Command with Graph Architecture
5
- *
6
- * Uses multi-node graph workflow for comprehensive analysis:
7
- * - Ticket analysis
8
- * - Code implementation generation (with git diff)
9
- * - Test case generation
10
- * - Complexity assessment
11
- */
12
-
13
- import { dirname, join, resolve } from 'path';
14
- import { fileURLToPath } from 'url';
15
- import { readFileSync, existsSync } from 'fs';
16
- import { compileGraph, validateGraphConfig } from '@zibby/core/framework/graph-compiler.js';
17
- import { WorkflowGraph } from '@zibby/core/framework/graph.js';
18
- import { buildAnalysisGraph } from '@zibby/core/templates/code-analysis/graph.js';
19
- import { analysisStateSchema } from '@zibby/core/templates/code-analysis/state.js';
20
- import '@zibby/core/templates/register-nodes.js';
21
- import { fetchExecutionContext } from '../utils/execution-context.js';
22
- import { reportProgress, reportArtifact, reportFinalStatus } from '../utils/progress-reporter.js';
23
- import { writeMcpConfig } from '@zibby/core/utils/mcp-config-writer.js';
24
-
25
- const __filename = fileURLToPath(import.meta.url);
26
- const __dirname = dirname(__filename);
27
- const cliPackageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
28
-
29
- /**
30
- * Node execution middleware - Captures logs and reports progress
31
- * This is configured OUTSIDE the framework and passed in
32
- */
33
- // Maps node names → how to extract their artifact from the node result
34
- const NODE_ARTIFACT_MAP = {
35
- analyze_ticket: (result) => ({
36
- key: 'analysis',
37
- value: { raw: result.raw, structured: result.output }
38
- }),
39
- generate_code: (result) => ({
40
- key: 'codeImplementation',
41
- value: result.output?.codeImplementation
42
- }),
43
- generate_test_cases: (result) => ({
44
- key: 'tests',
45
- value: result.output?.tests
46
- }),
47
- finalize: (result) => ({
48
- key: 'report',
49
- value: result.output?.report
50
- }),
51
- };
52
-
53
- function createLogCapturingMiddleware(reportProgressFn, reportArtifactFn) {
54
- return async function nodeMiddleware(nodeName, executeNode, state) {
55
- const startTime = Date.now();
56
- const logBuffer = [];
57
- let lastSentLogs = '';
58
-
59
- const originalLog = console.log;
60
- const originalStdoutWrite = process.stdout.write.bind(process.stdout);
61
- const originalStderrWrite = process.stderr.write.bind(process.stderr);
62
-
63
- // Flag to prevent double-capture: console.log internally calls process.stdout.write
64
- let insideConsoleLog = false;
65
-
66
- console.log = (...args) => {
67
- const message = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
68
- logBuffer.push(message);
69
- insideConsoleLog = true;
70
- originalLog(...args);
71
- insideConsoleLog = false;
72
- };
73
-
74
- // Capture direct process.stdout.write (agent streaming output) but skip console.log echoes
75
- let stdoutLineBuffer = '';
76
- process.stdout.write = (chunk, encoding, callback) => {
77
- if (!insideConsoleLog) {
78
- const text = typeof chunk === 'string' ? chunk : chunk.toString();
79
- stdoutLineBuffer += text;
80
- const lines = stdoutLineBuffer.split('\n');
81
- stdoutLineBuffer = lines.pop() || '';
82
- for (const line of lines) {
83
- const trimmed = line.trim();
84
- if (trimmed) {
85
- logBuffer.push(trimmed);
86
- }
87
- }
88
- }
89
- return originalStdoutWrite(chunk, encoding, callback);
90
- };
91
-
92
- originalLog(`[Middleware] Started capturing logs for ${nodeName}`);
93
-
94
- let timerCleared = false;
95
- const liveLogInterval = setInterval(() => {
96
- if (timerCleared) return;
97
-
98
- const currentLogs = logBuffer.join('\n');
99
- if (currentLogs !== lastSentLogs && currentLogs.length > 0) {
100
- lastSentLogs = currentLogs;
101
- // Write middleware status to stderr to avoid interleaving with agent streaming on stdout
102
- originalStderrWrite(`šŸ“” [Middleware] Sending live update for ${nodeName}: ${currentLogs.length} chars, ${logBuffer.length} lines\n`);
103
- reportProgressFn(nodeName, 'in_progress', currentLogs, state).catch((err) => {
104
- originalStderrWrite(`āš ļø [Middleware] Failed to send live update: ${err.message}\n`);
105
- });
106
- }
107
- }, 500);
108
-
109
- try {
110
- await reportProgressFn(nodeName, 'in_progress', '', state);
111
-
112
- const result = await executeNode();
113
- const duration = ((Date.now() - startTime) / 1000).toFixed(1);
114
-
115
- timerCleared = true;
116
- clearInterval(liveLogInterval);
117
- await new Promise(resolveFn => setImmediate(resolveFn));
118
- console.log = originalLog;
119
- process.stdout.write = originalStdoutWrite;
120
- // Flush any remaining partial line
121
- if (stdoutLineBuffer.trim()) {
122
- logBuffer.push(stdoutLineBuffer.trim());
123
- stdoutLineBuffer = '';
124
- }
125
-
126
- const finalLogs = logBuffer.join('\n');
127
- originalStderrWrite(`šŸ“” [Middleware] Sending final update for ${nodeName}: ${finalLogs.length} chars, ${logBuffer.length} total lines captured\n`);
128
- if (result.success) {
129
- await reportProgressFn(nodeName, 'success', finalLogs || `Completed in ${duration}s`, state);
130
-
131
- // Send artifact for this node immediately (survives even if later nodes fail)
132
- const extractor = NODE_ARTIFACT_MAP[nodeName];
133
- if (extractor) {
134
- const { key, value } = extractor(result);
135
- if (value) {
136
- await reportArtifactFn(state, key, value);
137
- }
138
- }
139
- } else {
140
- await reportProgressFn(nodeName, 'failed', `${finalLogs }\n\nError: ${result.error}`, state);
141
- }
142
-
143
- return result;
144
- } catch (error) {
145
- timerCleared = true;
146
- clearInterval(liveLogInterval);
147
- await new Promise(resolveFn => setImmediate(resolveFn));
148
- console.log = originalLog;
149
- process.stdout.write = originalStdoutWrite;
150
-
151
- const errorLogs = `${logBuffer.join('\n') }\n\nError: ${error.message}`;
152
- await reportProgressFn(nodeName, 'failed', errorLogs, state);
153
- throw error;
154
- }
155
- };
156
- }
157
-
158
- /**
159
- * Main analyze command
160
- */
161
- export async function analyzeCommand(options) {
162
- const {
163
- EXECUTION_ID,
164
- TICKET_KEY,
165
- PROJECT_ID,
166
- REPOS,
167
- PROGRESS_QUEUE_URL,
168
- PROGRESS_API_URL,
169
- SQS_AUTH_TOKEN,
170
- PROJECT_API_TOKEN,
171
- GITHUB_TOKEN,
172
- MODEL
173
- } = process.env;
174
-
175
- // Validate required env vars
176
- if (!EXECUTION_ID || !TICKET_KEY || !PROJECT_ID) {
177
- console.error('āŒ Missing required environment variables');
178
- console.error(' Required: EXECUTION_ID, TICKET_KEY, PROJECT_ID');
179
- process.exit(1);
180
- }
181
-
182
- // Fetch large data (ticketContext, nodeConfigs) from DynamoDB instead of env vars
183
- // This avoids the ECS 8192-char container overrides limit
184
- const execCtx = await fetchExecutionContext(EXECUTION_ID, PROJECT_ID);
185
- const ticketContext = execCtx.ticketContext;
186
- let nodeConfigs = execCtx.nodeConfigs || {};
187
- const repos = REPOS ? JSON.parse(REPOS) : execCtx.repos;
188
- const workspace = process.env.WORKSPACE || '/workspace';
189
- const promptsDir = join(dirname(dirname(dirname(__dirname))), 'core', 'templates', 'code-analysis', 'prompts');
190
-
191
- console.log('\nšŸš€ Zibby Analysis (Graph Mode)');
192
- console.log(`@zibby/cli v${cliPackageJson.version} | Node.js ${process.version}`);
193
- console.log('─'.repeat(60));
194
- console.log(`Ticket: ${TICKET_KEY}`);
195
- console.log(`Repositories: ${repos.length}`);
196
- console.log(`Workspace: ${workspace}`);
197
- console.log(`AI Model: ${MODEL || 'auto'}`);
198
- console.log('─'.repeat(60));
199
-
200
- // Compile graph from: --workflow flag (local file) > S3 config > default
201
- const logMiddleware = createLogCapturingMiddleware(reportProgress, reportArtifact);
202
- let graphConfig;
203
- let graphSource;
204
-
205
- let jsWorkflowModule = null;
206
-
207
- if (options?.workflow) {
208
- const workflowPath = resolve(process.cwd(), options.workflow);
209
- if (!existsSync(workflowPath)) {
210
- console.error(`āŒ Workflow file not found: ${workflowPath}`);
211
- process.exit(1);
212
- }
213
-
214
- if (workflowPath.endsWith('.js') || workflowPath.endsWith('.mjs')) {
215
- try {
216
- const { pathToFileURL } = await import('url');
217
- jsWorkflowModule = await import(pathToFileURL(workflowPath).href);
218
- graphSource = `local JS module (${workflowPath})`;
219
- } catch (err) {
220
- console.error(`āŒ Failed to load workflow JS module: ${err.message}`);
221
- process.exit(1);
222
- }
223
- } else {
224
- try {
225
- const fileContent = JSON.parse(readFileSync(workflowPath, 'utf-8'));
226
- const { _meta, ...config } = fileContent;
227
- graphConfig = config;
228
- graphSource = `local file (${workflowPath})`;
229
- } catch (err) {
230
- console.error(`āŒ Failed to parse workflow file: ${err.message}`);
231
- process.exit(1);
232
- }
233
- const validation = validateGraphConfig(graphConfig);
234
- if (!validation.valid) {
235
- console.error('āŒ Invalid workflow file:');
236
- validation.errors.forEach(e => console.error(` - ${e}`));
237
- process.exit(1);
238
- }
239
- }
240
- } else if (execCtx.graphConfig) {
241
- graphConfig = execCtx.graphConfig;
242
- graphSource = 'custom (from project workflow)';
243
- } else {
244
- const graph = new WorkflowGraph();
245
- buildAnalysisGraph(graph);
246
- graphConfig = graph.serialize();
247
- graphSource = 'default';
248
- }
249
-
250
- let graph;
251
-
252
- if (jsWorkflowModule) {
253
- const jsNodeConfigs = jsWorkflowModule.nodeConfigs || {};
254
- const mergedNodeConfigs = { ...jsNodeConfigs, ...nodeConfigs };
255
- graph = jsWorkflowModule.buildGraph({ nodeMiddleware: logMiddleware });
256
- console.log(`šŸ“ Graph source: ${graphSource}`);
257
- console.log(` Nodes: ${graph.nodes.size}`);
258
- nodeConfigs = mergedNodeConfigs;
259
- } else {
260
- if (nodeConfigs && Object.keys(nodeConfigs).length > 0) {
261
- const base = graphConfig.nodeConfigs || {};
262
- const merged = { ...base };
263
- for (const [nodeId, overrides] of Object.entries(nodeConfigs)) {
264
- merged[nodeId] = { ...base[nodeId], ...overrides };
265
- }
266
- graphConfig.nodeConfigs = merged;
267
- }
268
-
269
- console.log(`šŸ“ Graph source: ${graphSource}`);
270
- console.log(` Nodes: ${graphConfig.nodes?.length || 0}`);
271
- console.log(` Edges: ${graphConfig.edges?.length || 0}`);
272
-
273
- graph = compileGraph(graphConfig, { nodeMiddleware: logMiddleware, stateSchema: analysisStateSchema });
274
- }
275
-
276
- // Write MCP config for any tools required by custom nodes (jira, slack_notify, github)
277
- // Must be done before graph.run() so Cursor agent has MCP servers configured
278
- writeMcpConfig(nodeConfigs);
279
-
280
- // Execute graph
281
- const initialState = {
282
- EXECUTION_ID,
283
- PROGRESS_QUEUE_URL,
284
- PROGRESS_API_URL,
285
- SQS_AUTH_TOKEN,
286
- PROJECT_API_TOKEN,
287
- workspace,
288
- repos,
289
- ticketContext,
290
- promptsDir,
291
- githubToken: GITHUB_TOKEN,
292
- model: MODEL,
293
- nodeConfigs
294
- };
295
-
296
- try {
297
- const result = await graph.run(null, initialState);
298
-
299
- // Artifacts are already sent per-node by the middleware (NODE_ARTIFACT_MAP).
300
- // Here we only determine the final status and send it.
301
- const finalState = result.state;
302
- const validation = finalState.analyze_ticket_output?.validation
303
- || finalState.analyze_ticket_output?.analysis?.structured?.validation;
304
- let finalStatus = 'completed';
305
- if (validation && !validation.canProceed) {
306
- finalStatus = validation.status === 'insufficient_context'
307
- ? 'insufficient_context'
308
- : 'blocked';
309
- }
310
- console.log(`\nšŸ“‹ Validation: canProceed=${validation?.canProceed}, status=${validation?.status}, finalStatus=${finalStatus}`);
311
-
312
- console.log(`\nšŸ“Š Sending final status: ${finalStatus}`);
313
- await reportFinalStatus(initialState, { status: finalStatus });
314
-
315
- console.log('\nāœ… Analysis completed successfully');
316
- process.exit(0);
317
- } catch (error) {
318
- console.error('\nāŒ Analysis failed:', error.message);
319
-
320
- if (EXECUTION_ID) {
321
- try {
322
- console.log(`šŸ“” Reporting failure...`);
323
- await reportFinalStatus(initialState, { status: 'failed', error: error.message });
324
- } catch (_apiError) {
325
- console.error('āš ļø Failed to report error');
326
- }
327
- }
328
-
329
- process.exit(1);
330
- }
331
- }
332
-
333
- // Execute if run directly
334
- if (import.meta.url === `file://${process.argv[1]}`) {
335
- analyzeCommand();
336
- }
@@ -1,65 +0,0 @@
1
- import { patchCursorAgentForCI, checkCursorAgentPatched, getApprovalKeys, saveApprovalKeys } from '@zibby/core';
2
- import { resolve } from 'path';
3
- import chalk from 'chalk';
4
- import ora from 'ora';
5
-
6
- export async function ciSetupCommand(options) {
7
- console.log(chalk.bold.cyan('\nšŸ”§ Setting up CI/CD for Cursor Agent\n'));
8
- console.log(chalk.gray('━'.repeat(50)));
9
-
10
- const check = checkCursorAgentPatched();
11
-
12
- if (!check.installed) {
13
- console.log(chalk.red('\nāŒ cursor-agent is not installed!\n'));
14
- console.log(chalk.white('To install:'));
15
- console.log(chalk.gray(' curl https://cursor.com/install -fsS | bash\n'));
16
- process.exit(1);
17
- }
18
-
19
- if (check.patched) {
20
- console.log(chalk.green('āœ… cursor-agent is already patched for CI/CD\n'));
21
- } else {
22
- const spinner = ora('Patching cursor-agent...').start();
23
-
24
- try {
25
- await patchCursorAgentForCI();
26
- spinner.succeed('cursor-agent patched successfully');
27
- } catch (error) {
28
- spinner.fail('Failed to patch cursor-agent');
29
- console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
30
- process.exit(1);
31
- }
32
- }
33
-
34
- if (options.getKeys) {
35
- const spinner = ora('Getting approval keys...').start();
36
-
37
- try {
38
- const result = await getApprovalKeys(resolve(process.cwd()));
39
- spinner.succeed('Approval keys retrieved');
40
-
41
- console.log(chalk.cyan('\nšŸ“‹ Approval Keys:\n'));
42
- Object.entries(result.keys).forEach(([name, key]) => {
43
- console.log(chalk.white(` ${name}: ${chalk.gray(key)}`));
44
- });
45
-
46
- if (options.save) {
47
- saveApprovalKeys(resolve(process.cwd()), result.keys);
48
- } else {
49
- console.log(chalk.gray('\nTo save these keys, run:'));
50
- console.log(chalk.white(' zibby ci-setup --get-keys --save\n'));
51
- }
52
- } catch (error) {
53
- spinner.fail('Failed to get approval keys');
54
- console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
55
- process.exit(1);
56
- }
57
- }
58
-
59
- console.log(chalk.green('\nāœ… CI/CD setup complete!\n'));
60
- console.log(chalk.cyan('Next steps:'));
61
- console.log(chalk.white(' 1. Get approval keys: zibby ci-setup --get-keys'));
62
- console.log(chalk.white(' 2. Save to project: zibby ci-setup --get-keys --save'));
63
- console.log(chalk.white(' 3. Use in CI: zibby run <spec> --agent=cursor --auto-approve\n'));
64
- }
65
-