@zibby/cli 0.1.26 → 0.1.27
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 +44 -44
- package/dist/auth/cli-login.js +18 -0
- package/dist/bin/zibby.js +2 -0
- package/dist/commands/agent-reliability.js +8 -0
- package/dist/commands/analyze-graph.js +18 -0
- package/dist/commands/chat-session-store.js +1 -0
- package/dist/commands/chat.js +79 -0
- package/dist/commands/ci-setup.js +18 -0
- package/dist/commands/generate.js +69 -0
- package/dist/commands/implement.js +65 -0
- package/dist/commands/init.js +344 -0
- package/dist/commands/list-projects.js +11 -0
- package/dist/commands/memory.js +39 -0
- package/dist/commands/run-capacity-queue-cli.js +4 -0
- package/dist/commands/run.js +112 -0
- package/dist/commands/setup-scripts.js +15 -0
- package/dist/commands/studio.js +33 -0
- package/dist/commands/upload.js +22 -0
- package/dist/commands/video.js +6 -0
- package/dist/commands/workflow.js +45 -0
- package/dist/config/config.js +1 -0
- package/dist/config/environments.js +1 -0
- package/dist/utils/chat-run-lifecycle.js +3 -0
- package/dist/utils/execution-context.js +1 -0
- package/dist/utils/progress-reporter.js +1 -0
- package/dist/utils/studio-cli-log-mirror.js +1 -0
- package/dist/utils/studio-installer.js +7 -0
- package/dist/utils/studio-launcher.js +1 -0
- package/package.json +19 -16
- package/bin/zibby.js +0 -273
- package/src/auth/cli-login.js +0 -404
- package/src/commands/analyze-graph.js +0 -336
- package/src/commands/ci-setup.js +0 -65
- package/src/commands/implement.js +0 -664
- package/src/commands/init.js +0 -770
- package/src/commands/list-projects.js +0 -77
- package/src/commands/memory.js +0 -171
- package/src/commands/run.js +0 -919
- package/src/commands/setup-scripts.js +0 -114
- package/src/commands/upload.js +0 -162
- package/src/commands/video.js +0 -30
- package/src/commands/workflow.js +0 -368
- package/src/config/config.js +0 -117
- package/src/config/environments.js +0 -145
- package/src/utils/execution-context.js +0 -25
- package/src/utils/progress-reporter.js +0 -155
package/README.md
CHANGED
|
@@ -39,17 +39,17 @@ export ZIBBY_USER_TOKEN=zby_pat_xxxxx
|
|
|
39
39
|
export ZIBBY_PROJECT_ID=zby_xxxxx
|
|
40
40
|
|
|
41
41
|
# Step 3: Run tests
|
|
42
|
-
zibby
|
|
42
|
+
zibby test tests/**/*.spec.js
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### Running Tests with Cloud Sync
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
48
|
# Both project token + user token are required
|
|
49
|
-
zibby
|
|
49
|
+
zibby test test.spec.js --sync
|
|
50
50
|
|
|
51
51
|
# Or with explicit project override
|
|
52
|
-
zibby
|
|
52
|
+
zibby test test.spec.js --project zby_xxx --sync
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
**Backend validates:**
|
|
@@ -85,7 +85,7 @@ For automated pipelines, use Personal Access Tokens:
|
|
|
85
85
|
3. **Run tests:**
|
|
86
86
|
```bash
|
|
87
87
|
npm install -g @zibby/cli
|
|
88
|
-
zibby
|
|
88
|
+
zibby test tests/**/*.spec.js
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
**Token features:**
|
|
@@ -132,22 +132,22 @@ zibby init my-tests --agent=cursor --no-cloud --skip-install
|
|
|
132
132
|
- ✅ Installs Playwright browsers
|
|
133
133
|
- ✅ Generates README
|
|
134
134
|
|
|
135
|
-
### `zibby
|
|
135
|
+
### `zibby test` - Run Test Specification
|
|
136
136
|
|
|
137
137
|
Execute a test specification:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
140
|
# Basic usage
|
|
141
|
-
zibby
|
|
141
|
+
zibby test test-specs/auth/login.txt
|
|
142
142
|
|
|
143
143
|
# With options
|
|
144
|
-
zibby
|
|
144
|
+
zibby test test-specs/auth/login.txt --agent=cursor --headless
|
|
145
145
|
|
|
146
146
|
# Open results in browser after completion
|
|
147
|
-
zibby
|
|
147
|
+
zibby test test-specs/auth/login.txt --project zby_xxx --collection "My Tests" --open
|
|
148
148
|
|
|
149
149
|
# For CI/CD
|
|
150
|
-
zibby
|
|
150
|
+
zibby test test-specs/auth/login.txt --agent=cursor --auto-approve --headless
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
**Options:**
|
|
@@ -272,10 +272,10 @@ cp .env.example .env
|
|
|
272
272
|
# Edit .env: ANTHROPIC_API_KEY=sk-ant-...
|
|
273
273
|
|
|
274
274
|
# Run example test
|
|
275
|
-
zibby
|
|
275
|
+
zibby test test-specs/examples/google-search.txt
|
|
276
276
|
|
|
277
277
|
# Run with cloud sync and open results
|
|
278
|
-
zibby
|
|
278
|
+
zibby test test-specs/examples/google-search.txt \
|
|
279
279
|
--project zby_xxx \
|
|
280
280
|
--collection "My Tests" \
|
|
281
281
|
--open
|
|
@@ -296,7 +296,7 @@ npx playwright test tests/examples/google-search.spec.js
|
|
|
296
296
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
297
297
|
|
|
298
298
|
# Run tests
|
|
299
|
-
zibby
|
|
299
|
+
zibby test test-specs/auth/login.txt --agent=claude --headless
|
|
300
300
|
```
|
|
301
301
|
|
|
302
302
|
#### With Cursor Agent (Requires Setup)
|
|
@@ -315,13 +315,13 @@ zibby ci-setup
|
|
|
315
315
|
zibby ci-setup --get-keys --save
|
|
316
316
|
|
|
317
317
|
# 5. Run tests
|
|
318
|
-
zibby
|
|
318
|
+
zibby test test-specs/auth/login.txt \
|
|
319
319
|
--agent=cursor \
|
|
320
320
|
--auto-approve \
|
|
321
321
|
--headless
|
|
322
322
|
|
|
323
323
|
# 6. Upload results to cloud (optional)
|
|
324
|
-
zibby
|
|
324
|
+
zibby test test-specs/auth/login.txt \
|
|
325
325
|
--agent=cursor \
|
|
326
326
|
--auto-approve \
|
|
327
327
|
--headless \
|
|
@@ -360,7 +360,7 @@ jobs:
|
|
|
360
360
|
|
|
361
361
|
- name: Run tests
|
|
362
362
|
run: |
|
|
363
|
-
npx zibby
|
|
363
|
+
npx zibby test test-specs/auth/login.txt \
|
|
364
364
|
--agent=cursor \
|
|
365
365
|
--auto-approve \
|
|
366
366
|
--headless \
|
|
@@ -386,7 +386,7 @@ zibby init my-tests --agent=cursor
|
|
|
386
386
|
|
|
387
387
|
# 2. Run tests
|
|
388
388
|
cd my-tests
|
|
389
|
-
zibby
|
|
389
|
+
zibby test test-specs/examples/google-search.txt --agent=cursor
|
|
390
390
|
```
|
|
391
391
|
|
|
392
392
|
#### CI/CD Setup
|
|
@@ -422,17 +422,17 @@ This patches the cursor-agent binary to automatically approve MCP tool calls, wh
|
|
|
422
422
|
|
|
423
423
|
```bash
|
|
424
424
|
# Generate test using Cursor Agent
|
|
425
|
-
zibby
|
|
425
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
426
426
|
|
|
427
427
|
# With options and auto-open results
|
|
428
|
-
zibby
|
|
428
|
+
zibby test test-specs/auth/login.txt \
|
|
429
429
|
--agent=cursor \
|
|
430
430
|
--headless \
|
|
431
431
|
--collection="Auth Tests" \
|
|
432
432
|
--open
|
|
433
433
|
|
|
434
434
|
# Upload to specific project
|
|
435
|
-
zibby
|
|
435
|
+
zibby test test-specs/auth/login.txt \
|
|
436
436
|
--agent=cursor \
|
|
437
437
|
--project zby_your_project_id \
|
|
438
438
|
--collection="My Tests" \
|
|
@@ -443,7 +443,7 @@ zibby run test-specs/auth/login.txt \
|
|
|
443
443
|
|
|
444
444
|
```bash
|
|
445
445
|
# Complete CI/CD workflow
|
|
446
|
-
zibby
|
|
446
|
+
zibby test test-specs/auth/login.txt \
|
|
447
447
|
--agent=cursor \
|
|
448
448
|
--auto-approve \
|
|
449
449
|
--headless \
|
|
@@ -454,12 +454,12 @@ zibby run test-specs/auth/login.txt \
|
|
|
454
454
|
|
|
455
455
|
```bash
|
|
456
456
|
# Run only live execution (useful for debugging)
|
|
457
|
-
zibby
|
|
457
|
+
zibby test test-specs/auth/login.txt \
|
|
458
458
|
--agent=cursor \
|
|
459
459
|
--node=execute_live
|
|
460
460
|
|
|
461
461
|
# Resume from last session and run script generation
|
|
462
|
-
zibby
|
|
462
|
+
zibby test test-specs/auth/login.txt \
|
|
463
463
|
--agent=cursor \
|
|
464
464
|
--node=generate_script \
|
|
465
465
|
--session=last
|
|
@@ -474,7 +474,7 @@ zibby workflow download --type=run_test --include-default
|
|
|
474
474
|
# Modify .zibby/workflow-run_test.json as needed
|
|
475
475
|
|
|
476
476
|
# Run with custom workflow
|
|
477
|
-
zibby
|
|
477
|
+
zibby test test-specs/auth/login.txt \
|
|
478
478
|
--agent=cursor \
|
|
479
479
|
--workflow=CustomWorkflow
|
|
480
480
|
```
|
|
@@ -539,7 +539,7 @@ zibby ci-setup --get-keys
|
|
|
539
539
|
|
|
540
540
|
```bash
|
|
541
541
|
# Run in headed mode to see what's happening
|
|
542
|
-
zibby
|
|
542
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
543
543
|
|
|
544
544
|
# Check session logs
|
|
545
545
|
ls -la test-results/sessions/
|
|
@@ -638,13 +638,13 @@ ANTHROPIC_API_KEY=sk-ant-your-key-here
|
|
|
638
638
|
```bash
|
|
639
639
|
# Run all tests in a folder
|
|
640
640
|
for spec in test-specs/auth/*.txt; do
|
|
641
|
-
|
|
641
|
+
zibby test "$spec" --agent=cursor --headless --sync
|
|
642
642
|
done
|
|
643
643
|
|
|
644
644
|
# Or use a workflow system
|
|
645
645
|
zibby workflow download --type=run_test
|
|
646
646
|
# Edit workflow to run multiple specs
|
|
647
|
-
zibby
|
|
647
|
+
zibby test test-specs/auth/login.txt --workflow=BatchRunner
|
|
648
648
|
```
|
|
649
649
|
|
|
650
650
|
### Custom Approval Keys
|
|
@@ -669,7 +669,7 @@ cat > .mcp/approval-keys.json << 'EOF'
|
|
|
669
669
|
EOF
|
|
670
670
|
|
|
671
671
|
# 3. Use in CI
|
|
672
|
-
zibby
|
|
672
|
+
zibby test test-specs/auth/login.txt --agent=cursor --auto-approve
|
|
673
673
|
```
|
|
674
674
|
|
|
675
675
|
### Session Management
|
|
@@ -678,7 +678,7 @@ Cursor Agent creates session folders for each run. You can reuse sessions for de
|
|
|
678
678
|
|
|
679
679
|
```bash
|
|
680
680
|
# 1. Run test (creates session folder)
|
|
681
|
-
zibby
|
|
681
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
682
682
|
|
|
683
683
|
# Session saved to: test-results/sessions/1709567890/
|
|
684
684
|
|
|
@@ -689,13 +689,13 @@ ls test-results/sessions/1709567890/execute_live/
|
|
|
689
689
|
# title.txt - Generated test name
|
|
690
690
|
|
|
691
691
|
# 3. Resume from specific session
|
|
692
|
-
zibby
|
|
692
|
+
zibby test test-specs/auth/login.txt \
|
|
693
693
|
--agent=cursor \
|
|
694
694
|
--node=generate_script \
|
|
695
695
|
--session=1709567890
|
|
696
696
|
|
|
697
697
|
# 4. Or use "last" to resume from most recent
|
|
698
|
-
zibby
|
|
698
|
+
zibby test test-specs/auth/login.txt \
|
|
699
699
|
--agent=cursor \
|
|
700
700
|
--node=generate_script \
|
|
701
701
|
--session=last
|
|
@@ -705,7 +705,7 @@ zibby run test-specs/auth/login.txt \
|
|
|
705
705
|
|
|
706
706
|
```bash
|
|
707
707
|
# 1. Run in headed mode (see browser)
|
|
708
|
-
zibby
|
|
708
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
709
709
|
|
|
710
710
|
# 2. Check cursor-agent logs
|
|
711
711
|
tail -f ~/.cursor-agent/logs/agent.log
|
|
@@ -724,19 +724,19 @@ cursor-agent --test-mcp
|
|
|
724
724
|
|
|
725
725
|
```bash
|
|
726
726
|
# Use headless mode (faster)
|
|
727
|
-
zibby
|
|
727
|
+
zibby test test-specs/auth/login.txt --agent=cursor --headless
|
|
728
728
|
|
|
729
729
|
# Skip video recording
|
|
730
730
|
# Edit .zibby.config.js:
|
|
731
731
|
# video: 'off'
|
|
732
732
|
|
|
733
733
|
# Run specific nodes only
|
|
734
|
-
zibby
|
|
734
|
+
zibby test test-specs/auth/login.txt \
|
|
735
735
|
--agent=cursor \
|
|
736
736
|
--node=execute_live # Skip script generation & verification
|
|
737
737
|
|
|
738
738
|
# Reuse existing session
|
|
739
|
-
zibby
|
|
739
|
+
zibby test test-specs/auth/login.txt \
|
|
740
740
|
--agent=cursor \
|
|
741
741
|
--node=generate_script \
|
|
742
742
|
--session=last # No need to execute live again
|
|
@@ -774,13 +774,13 @@ The `--open` (or `-o`) flag automatically opens test results in your browser aft
|
|
|
774
774
|
|
|
775
775
|
```bash
|
|
776
776
|
# Opens browser to test results page
|
|
777
|
-
zibby
|
|
777
|
+
zibby test test-specs/auth/login.txt \
|
|
778
778
|
--project zby_xxx \
|
|
779
779
|
--collection "My Tests" \
|
|
780
780
|
--open
|
|
781
781
|
|
|
782
782
|
# Short form
|
|
783
|
-
zibby
|
|
783
|
+
zibby test test-specs/auth/login.txt --project zby_xxx -o
|
|
784
784
|
```
|
|
785
785
|
|
|
786
786
|
**Environment-aware URLs:**
|
|
@@ -829,22 +829,22 @@ zibby setup-playwright --headed
|
|
|
829
829
|
# ============================================
|
|
830
830
|
|
|
831
831
|
# Basic run (local)
|
|
832
|
-
zibby
|
|
832
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
833
833
|
|
|
834
834
|
# With options and open results
|
|
835
|
-
zibby
|
|
835
|
+
zibby test test-specs/auth/login.txt \
|
|
836
836
|
--agent=cursor \
|
|
837
837
|
--headless \
|
|
838
838
|
--collection="Auth Tests" \
|
|
839
839
|
--open
|
|
840
840
|
|
|
841
841
|
# Quick open with short flag
|
|
842
|
-
zibby
|
|
842
|
+
zibby test test-specs/auth/login.txt \
|
|
843
843
|
--project zby_xxx \
|
|
844
844
|
-o
|
|
845
845
|
|
|
846
846
|
# CI/CD run
|
|
847
|
-
zibby
|
|
847
|
+
zibby test test-specs/auth/login.txt \
|
|
848
848
|
--agent=cursor \
|
|
849
849
|
--auto-approve \
|
|
850
850
|
--headless \
|
|
@@ -856,15 +856,15 @@ zibby run test-specs/auth/login.txt \
|
|
|
856
856
|
# ============================================
|
|
857
857
|
|
|
858
858
|
# Run in headed mode (see browser)
|
|
859
|
-
zibby
|
|
859
|
+
zibby test test-specs/auth/login.txt --agent=cursor
|
|
860
860
|
|
|
861
861
|
# Run specific node
|
|
862
|
-
zibby
|
|
862
|
+
zibby test test-specs/auth/login.txt \
|
|
863
863
|
--agent=cursor \
|
|
864
864
|
--node=execute_live
|
|
865
865
|
|
|
866
866
|
# Resume from last session
|
|
867
|
-
zibby
|
|
867
|
+
zibby test test-specs/auth/login.txt \
|
|
868
868
|
--agent=cursor \
|
|
869
869
|
--node=generate_script \
|
|
870
870
|
--session=last
|
|
@@ -882,7 +882,7 @@ cat test-results/sessions/*/execute_live/events.json
|
|
|
882
882
|
zibby workflow download --type=run_test
|
|
883
883
|
|
|
884
884
|
# Run with custom workflow
|
|
885
|
-
zibby
|
|
885
|
+
zibby test test-specs/auth/login.txt \
|
|
886
886
|
--agent=cursor \
|
|
887
887
|
--workflow=CustomWorkflow
|
|
888
888
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import e from"chalk";import y from"ora";import{spawn as U}from"child_process";import{getApiUrl as p}from"../config/environments.js";import{saveSessionToken as $,saveUserInfo as x,saveProxyUrl as P,saveMem0ProxyUrl as C,getSessionToken as T,getUserInfo as z,clearSession as S,saveProjects as A}from"../config/config.js";function L(n){const o=process.platform;try{let t,r;return o==="darwin"?(t="open",r=[n]):o==="win32"?(t="cmd",r=["/c","start","",n]):(t="xdg-open",r=[n]),U(t,r,{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}function h(){const n=T(),o=z();return n&&o?{loggedIn:!0,user:o,token:n}:{loggedIn:!1}}async function Y(){try{console.log(e.cyan(`
|
|
2
|
+
\u{1F510} Initiating login...
|
|
3
|
+
`));const n=h();if(n.loggedIn){console.log(e.green("\u2705 Already logged in!")),console.log(e.gray(`User: ${n.user.email}`)),console.log(e.gray(`Name: ${n.user.name}
|
|
4
|
+
`));const{createInterface:o}=await import("readline"),t=o({input:process.stdin,output:process.stdout});return new Promise((r,c)=>{const s=()=>{t.close(),process.stdin.isTTY&&process.stdin.setRawMode(!1)},i=()=>{console.log(e.yellow(`
|
|
5
|
+
|
|
6
|
+
\u26A0\uFE0F Login cancelled
|
|
7
|
+
`)),s(),process.exit(0)};process.on("SIGINT",i),t.question(e.yellow("Continue with this session? (Y/n): "),async a=>{process.removeListener("SIGINT",i),s();try{if(a.toLowerCase()==="n"||a.toLowerCase()==="no"){console.log(e.gray(`Starting new login...
|
|
8
|
+
`));const d=await I();r(d)}else console.log(e.green(`Using existing session.
|
|
9
|
+
`)),r({success:!0,...n})}catch(d){c(d)}})})}return await I()}catch(n){return console.error(e.red(`
|
|
10
|
+
\u274C Login failed:`,n.message)),{success:!1,error:n.message}}}async function N(n){const o=p();try{const t=await fetch(`${o}/projects`,{headers:{Authorization:`Bearer ${n}`}});if(t.ok){const c=((await t.json()).projects||[]).map(s=>({name:s.name,projectId:s.projectId,apiToken:s.apiToken}));return A(c),c}}catch(t){console.log(e.gray(`\u26A0\uFE0F Could not fetch projects: ${t.message}`))}return[]}async function I(){const n=p(),o=y("Requesting login code...").start(),t=await fetch(`${n}/cli/login/initiate`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!t.ok){o.fail("Failed to request login code");const u=await t.json();throw new Error(u.error||"Failed to initiate login")}const{deviceCode:r,userCode:c,verificationUrl:s,expiresIn:i,interval:a}=await t.json();o.succeed("Login code generated"),console.log(""),console.log(e.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")),console.log(e.cyan("\u2551")+e.white.bold(" Complete login in your browser ")+e.cyan("\u2551")),console.log(e.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")),console.log(""),console.log(e.white("Opening browser to login page...")),console.log(e.gray(`Code expires in ${Math.floor(i/60)} minutes`)),console.log(""),await L(s)||(console.log(e.yellow("\u26A0\uFE0F Could not open browser automatically.")),console.log(e.white("Please open this URL manually: ")+e.blue(s)),console.log(""));const g=y("Waiting for authorization...").start(),v=(a||3)*1e3,b=Math.floor(i/(a||3));let w=0,m=!1;const k=()=>{m=!0,g.stop(),console.log(e.yellow(`
|
|
11
|
+
|
|
12
|
+
\u26A0\uFE0F Login cancelled
|
|
13
|
+
`)),process.exit(0)};process.on("SIGINT",k);try{for(;w<b&&!m;){await E(v),w++;const u=await fetch(`${n}/cli/login/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:r})});if(u.status===202)continue;if(!u.ok){g.fail("Authorization failed");const f=await u.json();throw new Error(f.error||"Authorization failed")}const l=await u.json();if(l.status==="authorized"){g.succeed(e.white("Authorization successful!")),$(l.token),x(l.user),l.proxyUrl&&P(l.proxyUrl),l.mem0ProxyUrl&&C(l.mem0ProxyUrl),console.log(""),console.log(e.gray(`User: ${l.user.email}`));const f=y("Fetching projects...").start(),j=await N(l.token);return f.succeed(`Fetched ${j.length} project${j.length!==1?"s":""}`),console.log(e.gray(`Session saved to: ~/.zibby/config.json
|
|
14
|
+
`)),{success:!0,loggedIn:!0,user:l.user,token:l.token}}if(l.status==="denied")throw g.fail("Authorization denied"),new Error("User denied authorization")}throw g.fail("Login timeout"),new Error("Login timed out - please try again")}finally{process.removeListener("SIGINT",k)}}function F(){if(!h().loggedIn){console.log(e.yellow(`
|
|
15
|
+
\u26A0\uFE0F Not logged in.
|
|
16
|
+
`));return}S(),console.log(e.green("\u2714")+e.white(" Logged out successfully!")),console.log(e.gray(`Session cleared from ~/.zibby/config.json
|
|
17
|
+
`))}async function G(n={}){const o=h(),t=process.env.ZIBBY_USER_TOKEN,r=p(),c=t||o.token;if(n.json){const s={authenticated:!!(o.loggedIn||t),user:o.user||null,tokenSource:t?"environment":o.token?"session":null,tokenType:t?"PAT":o.token?"JWT":null,apiUrl:r,configPath:o.loggedIn?"~/.zibby/config.json":null};if(c)try{const i=await fetch(`${r}/projects`,{headers:{Authorization:`Bearer ${c}`}});if(s.tokenValid=i.ok,i.ok){const a=await i.json();s.projectCount=(a.projects||[]).length}}catch(i){s.tokenValid=!1,s.error=i.message}else s.tokenValid=!1;console.log(JSON.stringify(s,null,2));return}if(console.log(""),!o.loggedIn&&!t){console.log(e.yellow("\u26A0\uFE0F Not authenticated")),console.log(""),console.log(e.white("To authenticate:")),console.log(e.gray(" Local: zibby login")),console.log(e.gray(` CI/CD: Set ZIBBY_USER_TOKEN env variable
|
|
18
|
+
`));return}if(console.log(e.green("\u2705 Authenticated")),console.log(""),console.log(e.bold.white("User Details:")),o.user?(console.log(e.gray(` Email: ${o.user.email}`)),o.user.userId&&console.log(e.gray(` User ID: ${o.user.userId}`)),o.user.name&&console.log(e.gray(` Name: ${o.user.name}`))):t&&console.log(e.gray(" (User details not available with PAT token)")),console.log(""),console.log(e.bold.white("Token Source:")),t?(console.log(e.gray(" Type: Personal Access Token (PAT)")),console.log(e.gray(" Location: ZIBBY_USER_TOKEN environment variable")),console.log(e.gray(` Preview: ${t.substring(0,8)}\u2022\u2022\u2022\u2022`))):(console.log(e.gray(" Type: Session Token (JWT)")),console.log(e.gray(" Location: ~/.zibby/config.json")),o.token&&console.log(e.gray(` Preview: ${o.token.substring(0,8)}\u2022\u2022\u2022\u2022`))),console.log(""),c)try{const s=(await import("ora")).default,i=s("Verifying authentication...").start(),a=await fetch(`${r}/projects`,{headers:{Authorization:`Bearer ${c}`}});if(a.ok){const g=((await a.json()).projects||[]).length;i.succeed(e.white("Token verified")),console.log(e.gray(` Projects: ${g} accessible`))}else i.fail(e.white("Token verification failed")),console.log(e.yellow(` Status: Invalid or expired (HTTP ${a.status})`))}catch(s){console.log(e.yellow(` Status: Could not verify (${s.message})`))}console.log(""),console.log(e.gray("\u{1F4A1} Run 'zibby list' to see your projects")),console.log("")}async function J(){const n=T();if(!n)return{valid:!1};const o=p();try{return(await fetch(`${o}/projects`,{headers:{Authorization:`Bearer ${n}`}})).ok?{valid:!0}:(S(),{valid:!1})}catch{return{valid:!1}}}function E(n){return new Promise(o=>setTimeout(o,n))}export{h as checkExistingSession,Y as loginCli,F as logoutCli,G as showLoginStatus,J as validateSession};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
process.stdout.on("error",o=>{o.code}),process.stderr.on("error",o=>{o.code}),process.env.DOTENV_CONFIG_QUIET="true";import"@zibby/skills";import{Command as s}from"commander";import{initCommand as c}from"../src/commands/init.js";import{runCommand as p}from"../src/commands/run.js";import{videoCommand as d}from"../src/commands/video.js";import{uploadCommand as m}from"../src/commands/upload.js";import{ciSetupCommand as l}from"../src/commands/ci-setup.js";import{setupPlaywrightMcpCommand as u,setupCiCommand as f,testWithVideoCommand as y}from"../src/commands/setup-scripts.js";import{readFileSync as w}from"fs";import{fileURLToPath as g}from"url";import{dirname as h,join as b}from"path";const k=g(import.meta.url),C=h(k),v=JSON.parse(w(b(C,"../package.json"),"utf-8")),i=process.argv.slice(2),I=i.includes("-h")||i.includes("--help"),P=i.includes("-V")||i.includes("--version"),S=i[0]==="chat",_=["--verbose","-v","--agent","--stream","-s"],j=i.length>0&&i.every(o=>_.includes(o)||i[i.indexOf(o)-1]==="--agent"),D=i.length===0||S||j;if(D&&!I&&!P){const o={},t=i.indexOf("--agent");t!==-1&&i[t+1]&&(o.agent=i[t+1]),(i.includes("--verbose")||i.includes("-v"))&&(o.verbose=!0),(i.includes("--stream")||i.includes("-s"))&&(o.stream=!0);const{chatCommand:r}=await import("../src/commands/chat.js");await r(o),process.exit(0)}const e=new s;e.name("zibby").description("Zibby Test Automation - AI-powered test generation").version(v.version),e.command("init").description("Initialize a new Zibby test project (like rails new)").argument("[project-name]","Project name (optional, uses current directory if not provided)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini)").option("--memory-backend <backend>","Memory backend to configure (dolt, mem0)","dolt").option("--skip-install","Skip npm install").option("--skip-memory","Skip test memory setup during initialization").option("-f, --force","Force reinitialize (overwrite existing config)").option("--headed","Run MCP browser in headed mode (visible browser)").option("--headless","Run MCP browser in headless mode (hidden browser)").option("--api-key <key>","Zibby API key for cloud sync").option("--cloud-sync","Enable cloud sync and install Zibby MCP").action(c),e.command("test").description("Run a test specification").argument("[spec-path]","Path to test spec file or inline test description in quotes").option("--sources <ids>","Comma-separated test case IDs to fetch from cloud").option("--execution <id>","Execution ID containing the test cases (required with --sources)").option("--agent <type>","Agent to use (claude, cursor, codex, gemini) - overrides config").option("--workflow <name>","Workflow to use (e.g., QuickSmokeWorkflow, quick-smoke)").option("--headless","Run browser in headless mode").option("--node <name>","Run only a specific node (e.g., execute_live, generate_script)").option("--session <id>",'Use existing session (e.g., 1768974629717 or "last") - requires --node').option("--session-path <dir>","Use this session folder (absolute or relative to cwd); Studio pins artifacts here").option("--project <id>","Project ID (optional, auto-detected from ZIBBY_API_KEY)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional, requires --collection)").option("--sync","Force upload to cloud (overrides cloudSync: false)").option("--no-sync","Skip upload to cloud (overrides cloudSync: true)").option("--config <path>","Path to config file",".zibby.config.mjs").option("--auto-approve","Auto-approve MCP tools (for CI/CD)").option("-o, --open","Open test results in browser after completion").option("--verbose","Show info level logs").option("--debug","Show debug level logs (most verbose)").option("-m, --mem","Enable test memory (Dolt-backed knowledge from previous runs)").action((o,t)=>(t.debug?process.env.ZIBBY_DEBUG="true":t.verbose&&(process.env.ZIBBY_VERBOSE="true"),p(o,t))),e.command("implement").description("Implement a Jira ticket using AI agent (runs in ECS container)").action(async(...o)=>{const{implementCommand:t}=await import("../src/commands/implement.js");return t(...o)}),e.command("analyze").description("Analyze a Jira ticket against the codebase (runs in ECS container)").option("--workflow <path>","Path to a local workflow JSON file (e.g., .zibby/workflow-analysis.json)").action(async(...o)=>{const{analyzeCommand:t}=await import("../src/commands/analyze-graph.js");return t(...o)}),e.command("video").description("Organize test videos next to test files").action(d),e.command("upload <spec-path>").description("Upload existing test artifacts to Zibby Cloud").option("--project <id>","Project ID (REQUIRED - use flag or ZIBBY_PROJECT_ID env)").option("--collection <id-or-name>","Collection ID or name (creates new if name doesn't exist)").option("--folder <path>","Folder path within collection (optional)").option("--agent <type>","Agent used (for metadata)").action(m),e.command("login").description("Log in to Zibby (opens browser for authentication)").action(async()=>{const{loginCli:o}=await import("../src/auth/cli-login.js");await o(),process.exit(0)}),e.command("logout").description("Log out from Zibby (clears saved session)").action(async()=>{const{logoutCli:o}=await import("../src/auth/cli-login.js");o(),process.exit(0)}),e.command("status").description("Show current authentication status and token details").option("--json","Output in JSON format (for scripts)").action(async o=>{const{showLoginStatus:t}=await import("../src/auth/cli-login.js");await t(o),process.exit(0)}),e.command("list").description("List your projects and API tokens").action(async()=>{const{listProjectsCommand:o}=await import("../src/commands/list-projects.js");await o()}),e.command("ci-setup").description("Setup Cursor Agent for CI/CD (patch and configure)").option("--get-keys","Get MCP approval keys").option("--save","Save approval keys to project").action(l),e.command("setup-playwright").description("Setup official Playwright MCP (from cursor-agent-package)").option("--headed","Configure MCP in headed mode (visible browser)").option("--viewport-width <width>","Viewport width (default: 1280)","1280").option("--viewport-height <height>","Viewport height (default: 720)","720").action(o=>{const t={width:parseInt(o.viewportWidth,10)||1280,height:parseInt(o.viewportHeight,10)||720};return u({...o,viewport:t})}),e.command("setup-ci-full").description("Complete CI/CD setup from scratch").action(f),e.command("test-video").description("Run Playwright tests with video recording").argument("[test-file]","Test file to run (default: tests/)").option("--headed","Run in headed mode (visible browser)").action(y),e.command("generate").description("Generate test specs from a ticket + codebase (local analysis using real AI agent)").option("-t, --ticket <key>","Jira ticket key (fetches automatically)").option("-i, --input <file>","Input file with ticket description/requirements").option("-d, --description <text>","Inline ticket description").option("--repo <path>","Path to the codebase (default: current directory)").option("--agent <type>","Agent to use (codex, claude, cursor, gemini)").option("--model <model>","Model override").option("-o, --output <dir>","Output directory for spec files (default: test-specs)").action(async o=>{const{generateCommand:t}=await import("../src/commands/generate.js");return t(o)}),e.command("studio").description("Launch Zibby Studio desktop (installs from CDN if needed). Uses this folder as the Zibby project.").option("-p, --port <port>","Port for the Studio API bridge (default: 3847)").option("--web","Open Studio in the browser instead of the desktop app").option("--no-open","Start the API only; do not open desktop or browser").action(async o=>{const{studioCommand:t}=await import("../src/commands/studio.js");return t(o)});const n=e.command("memory").description("Test memory database \u2014 version-controlled knowledge from runs");n.command("stats").description("Show memory database statistics").action(async()=>{const{memoryStatsCommand:o}=await import("../src/commands/memory.js");return o()}),n.command("init").description("Initialize the memory database (Dolt)").action(async()=>{const{memoryInitCommand:o}=await import("../src/commands/memory.js");return o()}),n.command("compact").description("Prune old data and run Dolt GC to reclaim storage").option("--max-runs <n>","Keep last N runs per spec (default: 50)",parseInt).option("--max-age <days>","Remove data older than N days (default: 90)",parseInt).action(async o=>{const{memoryCompactCommand:t}=await import("../src/commands/memory.js");return t(o)}),n.command("reset").description("Wipe the memory database").option("-f, --force","Confirm reset").action(async o=>{const{memoryResetCommand:t}=await import("../src/commands/memory.js");return t(o)});const a=e.command("workflow").description("Manage workflow graphs (download, upload, list)");a.command("download").description("Download a workflow graph from Zibby Cloud to .zibby/").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--type <type>","Workflow type: analysis, implementation, run_test").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").option("--output <dir>","Output directory (default: .zibby/)").option("--include-default","Download the built-in default graph if no custom one exists").action(async o=>{const{workflowDownloadCommand:t}=await import("../src/commands/workflow.js");return t(o)}),a.command("upload").description("Upload a local workflow graph to Zibby Cloud (validates before upload)").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--type <type>","Workflow type: analysis, implementation, run_test").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").option("--file <path>","Path to workflow JSON (default: .zibby/workflow-<type>.json)").action(async o=>{const{workflowUploadCommand:t}=await import("../src/commands/workflow.js");return t(o)}),a.command("list").description("List all workflows for a project").option("--project <id>","Project ID (or ZIBBY_PROJECT_ID env)").option("--api-key <key>","API key (or ZIBBY_API_KEY env)").action(async o=>{const{workflowListCommand:t}=await import("../src/commands/workflow.js");return t(o)});const x=e.command("run-queue").description("Parallel capacity \u2014 on-disk wait queue (see parallel.waitWhenAtCapacity in .zibby.config.mjs)");x.command("list").description("List CLI processes waiting for a run slot").option("--config <path>","Path to config file",".zibby.config.mjs").action(async o=>{const{runCapacityQueueListCommand:t}=await import("../src/commands/run-capacity-queue-cli.js");await t(o),process.exit(0)}),e.parse();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const f={cli_reliable_v1:{title:"General intelligence reliability contract",operatingRules:["Evidence-first reasoning: ground conclusions in observed outputs or tool evidence, not guesses.","No false completion: never claim success for a state-changing action until verification confirms it.","Execution integrity: do not claim any external action unless the matching tool call actually happened.","Bounded recovery: for transient failures, retry with adjusted parameters up to 2 times, then escalate with blocker + next step.",'Binary-answer discipline: for yes/no questions, verify the exact asked condition before answering; do not answer "yes" from a broader or approximate match.'],executionSafety:["Prefer low-blast-radius, reversible actions first.","Before irreversible or high-impact actions, confirm explicit user intent unless already authorized.","If verification cannot be run, state that limitation explicitly."],investigationLoop:["For unclear failures, follow this loop: detect -> gather evidence -> form hypothesis -> test hypothesis -> conclude.","If evidence is insufficient, explicitly collect more before proposing a root cause.","Prefer smallest validating action first before broad or costly retries."],responseQuality:["State assumptions explicitly when certainty is low.","Differentiate facts, hypotheses, and next actions.","Keep reports concise but decision-useful.","If related-but-not-identical matches exist, report them separately as context, not as the direct yes/no answer."],incidentTemplate:["ONLY when diagnosing failures or errors (never for successful actions), structure your response as: Root cause, Evidence, Attempted fixes, Current status, Next action."],skillRunbooks:{}}},p=2e3,y=12e3;function c(t=[]){if(!Array.isArray(t))return[];const r=new Set,i=[];for(const n of t){const e=String(n||"").replace(/\s+/g," ").trim();e&&(r.has(e)||(r.add(e),i.push(e)))}return i}function m(t,r=p){const i=String(t||"");return i.length<=r?i:`${i.slice(0,Math.max(0,r-14)).trimEnd()}
|
|
2
|
+
|
|
3
|
+
[truncated]`}function s(t,r=[],i=p){const n=c(r);if(n.length===0)return"";const e=[`## ${t}`,...n.map(o=>`- ${o}`)].join(`
|
|
4
|
+
`);return m(e,i)}function b(t){return!t||typeof t!="object"||Array.isArray(t)?null:t}function g(t,r){const i={...t,...r},n=["operatingRules","rules","executionSafety","investigationLoop","responseQuality","incidentTemplate"];for(const e of n)Array.isArray(r?.[e])?i[e]=[...c(t?.[e]||[]),...c(r[e])]:Array.isArray(t?.[e])&&(i[e]=[...c(t[e])]);return i.skillRunbooks={...t?.skillRunbooks||{},...r?.skillRunbooks||{}},i}function h(t={},r={}){const i=Array.isArray(t?.reliabilityAppendSections)?t.reliabilityAppendSections:[],n=Array.isArray(r?.reliabilityAppendSections)?r.reliabilityAppendSections:[];return[...i,...n].map(e=>{if(typeof e=="string")return{title:"Additional reliability guidance",lines:[e]};if(!e||typeof e!="object")return null;const o=String(e.title||"Additional reliability guidance").trim(),l=Array.isArray(e.lines)?e.lines:[];return{title:o,lines:l}}).filter(Boolean)}function A(t={},r={}){const i=String(r.reliabilityProfile||process.env.ZIBBY_RELIABILITY_PROFILE||t.reliabilityProfile||"cli_reliable_v1").trim(),n=t?.reliabilityProfiles?.[i];if(typeof n=="string"&&n.trim())return{name:i,text:n.trim()};if(n&&typeof n.instruction=="string"&&n.instruction.trim())return{name:i,text:n.instruction.trim()};const e=f[i]||f.cli_reliable_v1,o=b(n),l=o?g(e,o):e;return{name:i,defaults:l}}function x({activeSkills:t=[],chatConfig:r={},options:i={}}={}){const n=A(r,i);if(n.text)return n.text;const e=n.defaults||f.cli_reliable_v1,o=[s(e.title||"Reliability contract",e.operatingRules||e.rules||[]),s("Execution safety",e.executionSafety||[]),s("Investigation loop",e.investigationLoop||[]),s("Response quality",e.responseQuality||[]),s("Failure reporting format",e.incidentTemplate||[])],l=e.skillRunbooks||{};for(const a of t)l[a]&&o.push(s(`Runbook: ${a}`,l[a]));const d=h(r,i);for(const a of d)o.push(s(a.title,a.lines));const u=o.filter(Boolean).join(`
|
|
5
|
+
|
|
6
|
+
`).trim();return u.length<=y?u:`${u.slice(0,Math.max(0,y-14)).trimEnd()}
|
|
7
|
+
|
|
8
|
+
[truncated]`}export{x as buildReliabilityInstruction};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{dirname as k,join as x,resolve as j}from"path";import{fileURLToPath as P}from"url";import{readFileSync as O,existsSync as L}from"fs";import{compileGraph as A,validateGraphConfig as G}from"@zibby/core/framework/graph-compiler.js";import{WorkflowGraph as J}from"@zibby/core/framework/graph.js";import{buildAnalysisGraph as U}from"@zibby/core/templates/code-analysis/graph.js";import{analysisStateSchema as D}from"@zibby/core/templates/code-analysis/state.js";import"@zibby/core/templates/register-nodes.js";import{fetchExecutionContext as W}from"../utils/execution-context.js";import{reportProgress as z,reportArtifact as K,reportFinalStatus as R}from"../utils/progress-reporter.js";import{writeMcpConfig as N}from"@zibby/core/utils/mcp-config-writer.js";const F=P(import.meta.url),M=k(F),B=JSON.parse(O(x(M,"../../package.json"),"utf-8")),q={analyze_ticket:s=>({key:"analysis",value:{raw:s.raw,structured:s.output}}),generate_code:s=>({key:"codeImplementation",value:s.output?.codeImplementation}),generate_test_cases:s=>({key:"tests",value:s.output?.tests}),finalize:s=>({key:"report",value:s.output?.report})};function H(s,w){return async function(a,v,u){const T=Date.now(),d=[];let E="";const h=console.log,_=process.stdout.write.bind(process.stdout),f=process.stderr.write.bind(process.stderr);let S=!1;console.log=(...e)=>{const c=e.map(o=>typeof o=="string"?o:JSON.stringify(o)).join(" ");d.push(c),S=!0,h(...e),S=!1};let n="";process.stdout.write=(e,c,o)=>{if(!S){const l=typeof e=="string"?e:e.toString();n+=l;const p=n.split(`
|
|
3
|
+
`);n=p.pop()||"";for(const g of p){const y=g.trim();y&&d.push(y)}}return _(e,c,o)},h(`[Middleware] Started capturing logs for ${a}`);let $=!1;const C=setInterval(()=>{if($)return;const e=d.join(`
|
|
4
|
+
`);e!==E&&e.length>0&&(E=e,f(`\u{1F4E1} [Middleware] Sending live update for ${a}: ${e.length} chars, ${d.length} lines
|
|
5
|
+
`),s(a,"in_progress",e,u).catch(c=>{f(`\u26A0\uFE0F [Middleware] Failed to send live update: ${c.message}
|
|
6
|
+
`)}))},500);try{await s(a,"in_progress","",u);const e=await v(),c=((Date.now()-T)/1e3).toFixed(1);$=!0,clearInterval(C),await new Promise(l=>setImmediate(l)),console.log=h,process.stdout.write=_,n.trim()&&(d.push(n.trim()),n="");const o=d.join(`
|
|
7
|
+
`);if(f(`\u{1F4E1} [Middleware] Sending final update for ${a}: ${o.length} chars, ${d.length} total lines captured
|
|
8
|
+
`),e.success){await s(a,"success",o||`Completed in ${c}s`,u);const l=q[a];if(l){const{key:p,value:g}=l(e);g&&await w(u,p,g)}}else await s(a,"failed",`${o}
|
|
9
|
+
|
|
10
|
+
Error: ${e.error}`,u);return e}catch(e){$=!0,clearInterval(C),await new Promise(o=>setImmediate(o)),console.log=h,process.stdout.write=_;const c=`${d.join(`
|
|
11
|
+
`)}
|
|
12
|
+
|
|
13
|
+
Error: ${e.message}`;throw await s(a,"failed",c,u),e}}}async function Q(s){const{EXECUTION_ID:w,TICKET_KEY:I,PROJECT_ID:a,REPOS:v,PROGRESS_QUEUE_URL:u,PROGRESS_API_URL:T,SQS_AUTH_TOKEN:d,PROJECT_API_TOKEN:E,GITHUB_TOKEN:h,MODEL:_}=process.env;(!w||!I||!a)&&(console.error("\u274C Missing required environment variables"),console.error(" Required: EXECUTION_ID, TICKET_KEY, PROJECT_ID"),process.exit(1));const f=await W(w,a),S=f.ticketContext;let n=f.nodeConfigs||{};const $=v?JSON.parse(v):f.repos,C=process.env.WORKSPACE||"/workspace",e=x(k(k(k(M))),"core","templates","code-analysis","prompts");console.log(`
|
|
14
|
+
\u{1F680} Zibby Analysis (Graph Mode)`),console.log(`@zibby/cli v${B.version} | Node.js ${process.version}`),console.log("\u2500".repeat(60)),console.log(`Ticket: ${I}`),console.log(`Repositories: ${$.length}`),console.log(`Workspace: ${C}`),console.log(`AI Model: ${_||"auto"}`),console.log("\u2500".repeat(60));const c=H(z,K);let o,l,p=null;if(s?.workflow){const t=j(process.cwd(),s.workflow);if(L(t)||(console.error(`\u274C Workflow file not found: ${t}`),process.exit(1)),t.endsWith(".js")||t.endsWith(".mjs"))try{const{pathToFileURL:r}=await import("url");p=await import(r(t).href),l=`local JS module (${t})`}catch(r){console.error(`\u274C Failed to load workflow JS module: ${r.message}`),process.exit(1)}else{try{const i=JSON.parse(O(t,"utf-8")),{_meta:m,...b}=i;o=b,l=`local file (${t})`}catch(i){console.error(`\u274C Failed to parse workflow file: ${i.message}`),process.exit(1)}const r=G(o);r.valid||(console.error("\u274C Invalid workflow file:"),r.errors.forEach(i=>console.error(` - ${i}`)),process.exit(1))}}else if(f.graphConfig)o=f.graphConfig,l="custom (from project workflow)";else{const t=new J;U(t),o=t.serialize(),l="default"}let g;if(p){const r={...p.nodeConfigs||{},...n};g=p.buildGraph({nodeMiddleware:c}),console.log(`\u{1F4D0} Graph source: ${l}`),console.log(` Nodes: ${g.nodes.size}`),n=r}else{if(n&&Object.keys(n).length>0){const t=o.nodeConfigs||{},r={...t};for(const[i,m]of Object.entries(n))r[i]={...t[i],...m};o.nodeConfigs=r}console.log(`\u{1F4D0} Graph source: ${l}`),console.log(` Nodes: ${o.nodes?.length||0}`),console.log(` Edges: ${o.edges?.length||0}`),g=A(o,{nodeMiddleware:c,stateSchema:D})}N(n);const y={EXECUTION_ID:w,PROGRESS_QUEUE_URL:u,PROGRESS_API_URL:T,SQS_AUTH_TOKEN:d,PROJECT_API_TOKEN:E,workspace:C,repos:$,ticketContext:S,promptsDir:e,githubToken:h,model:_,nodeConfigs:n};try{const r=(await g.run(null,y)).state,i=r.analyze_ticket_output?.validation||r.analyze_ticket_output?.analysis?.structured?.validation;let m="completed";i&&!i.canProceed&&(m=i.status==="insufficient_context"?"insufficient_context":"blocked"),console.log(`
|
|
15
|
+
\u{1F4CB} Validation: canProceed=${i?.canProceed}, status=${i?.status}, finalStatus=${m}`),console.log(`
|
|
16
|
+
\u{1F4CA} Sending final status: ${m}`),await R(y,{status:m}),console.log(`
|
|
17
|
+
\u2705 Analysis completed successfully`),process.exit(0)}catch(t){if(console.error(`
|
|
18
|
+
\u274C Analysis failed:`,t.message),w)try{console.log("\u{1F4E1} Reporting failure..."),await R(y,{status:"failed",error:t.message})}catch{console.error("\u26A0\uFE0F Failed to report error")}process.exit(1)}}import.meta.url===`file://${process.argv[1]}`&&Q();export{Q as analyzeCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as o,mkdirSync as a,readFileSync as u,writeFileSync as c}from"fs";import{resolve as s}from"path";const y=30;function e(r){const t=s(r,".zibby","output");return o(t)||a(t,{recursive:!0}),t}function f(r){const t=s(r,".zibby","output","chat-history.json");if(!o(t))return[];try{const i=JSON.parse(u(t,"utf-8"));return Array.isArray(i)?i:[]}catch{return[]}}function h(r,t){const i=e(r),n=s(i,"chat-history.json");try{c(n,JSON.stringify((t||[]).slice(-y*2),null,2),"utf-8")}catch{}}function S(r){const t=s(r,".zibby","output","active-skills.json");if(!o(t))return null;try{const i=JSON.parse(u(t,"utf-8"));return Array.isArray(i)?i:null}catch{return null}}function A(r,t){const i=e(r),n=s(i,"active-skills.json");try{c(n,JSON.stringify(Array.isArray(t)?t:[]),"utf-8")}catch{}}export{S as loadActiveSkills,f as loadChatHistory,A as saveActiveSkills,h as saveChatHistory};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import{invokeAgent as xe,getAgentStrategy as _e,getSkill as $t}from"@zibby/core";import{existsSync as kt,readFileSync as oe,readdirSync as ve}from"fs";import{resolve as ft,join as Ft,dirname as Te,basename as Pe}from"path";import{createInterface as Ce,moveCursor as L,cursorTo as O,clearLine as q,emitKeypressEvents as Ie}from"readline";import{fileURLToPath as Ae}from"url";import e from"chalk";import Ee from"dotenv";import{getSessionToken as Yt,getUserInfo as Le,getProjects as Me,saveSessionToken as Be,saveUserInfo as Ne,clearSession as Oe,saveProxyUrl as Re,getProxyUrl as Ue,getMem0ProxyUrl as je,saveMem0ProxyUrl as De}from"../config/config.js";import{getApiUrl as ne}from"../config/environments.js";import{loadActiveSkills as Fe,loadChatHistory as Ye,saveActiveSkills as Ct,saveChatHistory as It}from"./chat-session-store.js";import{buildReliabilityInstruction as We}from"./agent-reliability.js";const He=Ae(import.meta.url),ze=Te(He),Je=JSON.parse(oe(Ft(ze,"../../package.json"),"utf-8")),re=30,qe=54,Ze=18e3,ie=12e3,ce=42e3;function Ge(o){return new Promise(t=>setTimeout(t,o))}const At=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Wt=[{cmd:"/help",desc:"Show this help"},{cmd:"/skills",desc:"List active & available skills"},{cmd:"/history",desc:"Show conversation history (--all or -n 50)"},{cmd:"/clear",desc:"Clear conversation history"},{cmd:"/memory",desc:"View stored memories, tasks, sessions"},{cmd:"/exit",desc:"Exit the chat"},{cmd:"/quit",desc:"Exit the chat"}];function ae(){let o=0,t="thinking...";const s=setInterval(()=>{const b=e.cyan(At[o%At.length]),_=o%3,T=_===0?e.white(".")+e.gray(".")+e.dim("."):_===1?e.dim(".")+e.white(".")+e.gray("."):e.gray(".")+e.dim(".")+e.white("."),E=t.replace(/\.+$/,""),A=` ${b} ${e.gray(E)}${T}`;process.stdout.write(`\r${" ".repeat(80)}\r${A}`),o++},300),r=()=>{clearInterval(s),process.stdout.write(`\r${" ".repeat(80)}\r`)};return r.setLabel=b=>{t=b},r}function Ms(o){const t=o?.agent;return t?t.provider?t.provider:t.gemini?"gemini":t.codex?"codex":t.claude?"claude":t.cursor?"cursor":process.env.AGENT_TYPE||"cursor":process.env.AGENT_TYPE||"cursor"}function Ke(o){return o.slice(-re).map(t=>`${t.role==="human"?"H":"AI"}: ${t.content}`).join(`
|
|
2
|
+
`)}function Bs(o,t,s){let r=o;return t.length>0&&(r+=`
|
|
3
|
+
|
|
4
|
+
${Ke(t)}`),r+=`
|
|
5
|
+
H: ${s}
|
|
6
|
+
AI:`,r}function Ve(o){const t=o.filter(s=>!process.env[s]);return{ok:t.length===0,missing:t}}function Xe(o){const t=ft(o,".zibby.config.mjs");if(!kt(t))return{};try{return import(t).then(s=>s.default||{})}catch{return{}}}async function Qe(o){const t=ft(o,".zibby","chat.mjs");if(kt(t)){const s=await import(t);return s.CHAT_CONFIG||s.default||{}}try{const s=await import("@zibby/core/templates/browser-test-automation/chat.mjs");return s.CHAT_CONFIG||s.default||{}}catch{return{systemPrompt:"You are Zibby, a friendly AI assistant for test automation.",skills:[]}}}function le(o){try{const t=ft(o,".zibby","commands");return kt(t)?ve(t).filter(s=>s.toLowerCase().endsWith(".md")).sort((s,r)=>s.localeCompare(r)):[]}catch{return[]}}function ts(o,t){const s=String(t||"").trim();if(!s.startsWith("/"))return s;const[r,...b]=s.split(/\s+/),_=b.join(" ").trim(),T=r.slice(1);if(!T)return s;const E=T.toLowerCase().endsWith(".md")?[T]:[T,`${T}.md`],A=ft(o,".zibby","commands"),U=E.find(R=>kt(Ft(A,R)));if(!U)return s;try{const R=oe(Ft(A,U),"utf-8").trim();return _?`${R}
|
|
7
|
+
|
|
8
|
+
${_}`:R}catch{return s}}function es(o){const t=o.slice(-re),s=[];let r=0;for(let b=t.length-1;b>=0;b--){const _=t[b],T=String(_?.content||""),E=_?.role==="human"?"user":"assistant",A=T.length;if(s.length>=6&&r+A>Ze)break;s.push({role:E,content:T}),r+=A}return s.reverse()}function xt(o,t){const s=String(o||"");return s.length<=t?s:`${s.slice(0,Math.max(0,t-24))}
|
|
9
|
+
|
|
10
|
+
[truncated for proxy size]`}function Ht(o){return o.reduce((t,s)=>t+String(s?.content||"").length+64,0)}function ss(o){let t=[...o];if(t.length===0||(t[0]?.role==="system"&&(t[0]={...t[0],content:xt(t[0].content,ie)}),Ht(t)<=ce))return t;const s=t[0],r=t[t.length-1],b=t.slice(1,-1).slice(-4).map(_=>({..._,content:xt(_.content,2500)}));return t=[s,...b,r],Ht(t)<=ce||(t=[{...s,content:xt(s?.content,6e3)},{...r,content:xt(r?.content,8e3)}]),t}function os(o){const t=[];for(const s of o){const r=$t(s),b=String(r?.description||"").trim();if(!b){t.push(`- ${s}`);continue}t.push(`- ${s}: ${Et(b,80)}`)}return t.length===0?"":`## Active skills (call get_skill_context before first use)
|
|
11
|
+
${t.join(`
|
|
12
|
+
`)}`}const ue={cli_plain:["## Response format for this channel","- Output plain terminal text only.","- Do NOT use Markdown syntax (no **bold**, __underline__, headings, code fences, inline backticks, or markdown tables).","- Keep responses concise and readable in a terminal.","- Write in natural, conversational English. Avoid dumping raw JSON, run IDs, or technical jargon.",'- When reporting test results: summarize in plain language (e.g. "Both tests finished \u2014 the checkbox test passed but the login test failed because..."). Include ticket keys but skip internal run IDs unless the user asks.',"- When something fails, explain the root cause simply and suggest a fix."].join(`
|
|
13
|
+
`)};function ns(o={},t={}){const s=String(t.outputProfile||process.env.ZIBBY_OUTPUT_PROFILE||o.outputProfile||"cli_plain").trim(),r=o?.outputProfiles?.[s];return typeof r=="string"&&r.trim()?r.trim():r&&typeof r.instruction=="string"&&r.instruction.trim()?r.instruction.trim():ue[s]||ue.cli_plain}function Et(o,t){const s=String(o??"");return s.length<=t?s:t<=1?s.slice(0,t):`${s.slice(0,t-1)}\u2026`}function rs(){return!1}function Ns(o){return o}function zt(){const o=Number(process.stdout?.columns)||0,t=o>8?Math.max(30,o-4):qe;return` ${"\u2500".repeat(t)}`}function pe(o=[]){const t=Wt.map(r=>({cmd:r.cmd,source:"builtin",name:r.cmd.slice(1),desc:r.desc})),s=o.map(r=>({cmd:`/${r}`,source:"template",name:r,desc:"Command template"}));return[...t,...s]}function is(o,t){const s=String(o||""),r=Number.isFinite(t)?t:s.length;return!(!s.startsWith("/")||r!==s.length||s.includes(" "))}function cs({userName:o,cwd:t,projectName:s,restoredCount:r,skillsLine:b}){const _=Number(process.stdout?.columns)||0,T=Math.max(40,Math.min(_-8,100)),E=Math.max(20,Math.floor((T-3)*.55)),A=T-E-3,U=o||"there",R=s||"No project linked",gt=Pe(t||process.cwd()),Y=[`Restored ${r} messages from previous session.`,"",b],rt=["Workspace details","",`v${Je.version} | Hi, ${U}`,`Company: ${R}`,`Directory: ~/${gt}`,`Path: ${t}`,"","Use /help for commands"],I=Math.max(Y.length,rt.length),K=(()=>{if(Y.length>=I)return Y;const j=Math.floor((I-Y.length)/2),st=I-Y.length-j;return[...Array(j).fill(""),...Y,...Array(st).fill("")]})(),H="\u2500",M=` \u250C${H.repeat(E+2)}\u252C${H.repeat(A+2)}\u2510`,et=` \u2514${H.repeat(E+2)}\u2534${H.repeat(A+2)}\u2518`;console.log(e.gray(M));for(let j=0;j<I;j++){const st=Et(K[j]||"",E),it=Et(rt[j]||"",A),ht=" ".repeat(Math.max(0,E-st.length)),l=" ".repeat(Math.max(0,A-it.length)),y=` \u2502 ${st}${ht} \u2502 ${it}${l} \u2502`;console.log(e.gray(y))}console.log(e.gray(et)),console.log("")}function as(){process.stdout?.isTTY&&(L(process.stdout,0,-2),O(process.stdout,4))}function ls(o){const t=!!(process.stdout?.isTTY&&process.stdin?.isTTY);let s=!1,r=!1,b=!1,_=null,T=0,E=0,A=0;function U(){return e.gray(zt())}function R(){_&&(clearInterval(_),_=null)}function gt(l){!t||!s||!r||!b||(process.stdout.write("\x1B7"),L(process.stdout,0,-2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(` ${l}`),process.stdout.write("\x1B8"))}function Y(){if(!(!t||!s)&&E!==0){process.stdout.write("\x1B7"),L(process.stdout,0,2);for(let l=0;l<E;l++)O(process.stdout,0),q(process.stdout,0),l<E-1&&L(process.stdout,0,1);process.stdout.write("\x1B8"),E=0,r&&rt()}}function rt(){!t||!s||!r||(process.stdout.write("\x1B7"),L(process.stdout,0,1),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),process.stdout.write("\x1B8"))}function I(l,y){if(!t||!s||!r)return;Y();const c=l.slice(0,6);if(c.length!==0){L(process.stdout,0,1);for(let h=0;h<c.length;h++)process.stdout.write(`
|
|
14
|
+
`);L(process.stdout,0,-(1+c.length)),process.stdout.write("\x1B7"),L(process.stdout,0,2);for(let h=0;h<c.length;h++){O(process.stdout,0),q(process.stdout,0);const Z=h===y?e.cyan("\u203A"):" ",d=h===y?e.white(c[h]):e.gray(c[h]);process.stdout.write(` ${Z} /${d}`),h<c.length-1&&L(process.stdout,0,1)}process.stdout.write("\x1B8"),E=c.length,rt()}}function K(){if(!t||!s||!r)return;Y();const l=process.stdout.columns||80,y=A>0?Math.ceil(A/l):1;O(process.stdout,0),L(process.stdout,0,-y),b&&L(process.stdout,0,-2),process.stdout.write("\x1B[J"),r=!1}function H(l={}){const y=l.preserveInput===!0;if(!t){o.prompt();return}y||(o.line="",o.cursor=0),A=zt().length;const c=U();process.stdout.write(`${c}
|
|
15
|
+
`),o.prompt(),process.stdout.write(`
|
|
16
|
+
${c}
|
|
17
|
+
`),as(),r=!0}function M(){if(!t||!s||!r)return;const l=process.stdout.columns||80,y=A>0?Math.ceil(A/l):1,c=U();process.stdout.write("\x1B7"),L(process.stdout,0,-y);for(let h=0;h<y;h++)O(process.stdout,0),q(process.stdout,0),h<y-1&&L(process.stdout,0,1);O(process.stdout,0),process.stdout.write(c),L(process.stdout,0,2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(c);for(let h=1;h<y;h++)L(process.stdout,0,1),O(process.stdout,0),q(process.stdout,0);process.stdout.write("\x1B8"),A=zt().length}function et(){if(!t||!s||!r)return;const l=(()=>{if(typeof o.getCursorPos!="function")return 0;try{return Math.max(0,Number(o.getCursorPos()?.rows||0))}catch{return 0}})();process.stdout.write("\x1B7"),L(process.stdout,0,-(l+1)),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),L(process.stdout,0,l+2),O(process.stdout,0),q(process.stdout,0),process.stdout.write(U()),process.stdout.write("\x1B8")}function j(l){R(),K(),console.log();const y=String(l??"").replace(/\r/g,"").split(`
|
|
18
|
+
`);for(;y.length>0&&y[y.length-1]==="";)y.pop();for(const c of y)console.log(c?` ${c}`:"");b=!1}function st(l){const y=String(l??"").replace(/\r/g,"").split(`
|
|
19
|
+
`);y.length===0&&y.push("");const c=[];for(const h of y)c.push(e.bgGray.white(` ${h||" "} `));return c.join(`
|
|
20
|
+
`)}function it(){R();const l=()=>e.gray(`${At[T%At.length]} thinking`);if(!t){console.log(` ${l()}`),b=!0;return}Y(),K(),console.log(),console.log(` ${l()}`),H({preserveInput:!0}),b=!0,T+=1,_=setInterval(()=>{b&&(gt(l()),T+=1)},120)}function ht(l){R();const y=String(l??"").replace(/\r/g,"").replace(/⎿/g,"");if(!b){j(y);return}K(),console.log();const c=y.split(`
|
|
21
|
+
`);for(;c.length>0&&c[c.length-1]==="";)c.pop();for(const h of c)console.log(h?` ${h}`:"");console.log(),b=!1}return{enabled:t,mount(){if(!s){if(!t){o.prompt(),s=!0;return}s=!0,H()}},refreshPrompt(l={}){if(t&&s){r&&K(),H(l);return}o.prompt()},pushSystem(l){j(l)},pushUser(l){j(st(l))},pushAssistant(l){ht(l)},showAssistantLoading:it,dismissTransientLoading(){R(),b&&t&&s&&r&&(process.stdout.write("\x1B7"),L(process.stdout,0,-2),O(process.stdout,0),q(process.stdout,0),L(process.stdout,0,-1),O(process.stdout,0),q(process.stdout,0),process.stdout.write("\x1B8")),b=!1},touchInputFrame:et,handleResize:M,showCommandDropdown:I,clearCommandDropdown:Y}}function us(){console.log(""),console.log(e.cyan(" Available commands:"));for(const o of Wt)console.log(e.white(` ${o.cmd.padEnd(10)} `)+e.gray(o.desc));console.log(""),console.log(e.cyan(" Chat options:")),console.log(e.white(" --stream, -s ")+e.gray("Enable typewriter effect (default: instant)")),console.log(""),console.log(e.gray(" To install/uninstall skills, just ask naturally:")),console.log(e.gray(' "connect to Jira" \u2022 "add GitHub" \u2022 "remove Slack"')),console.log("")}const ps=Ve;async function Os(o={}){const t=process.cwd();o.verbose&&(process.env.ZIBBY_VERBOSE="true");const s=o.stream||!1;[ft(t,".env.local"),ft(t,".env")].forEach(c=>{kt(c)&&Ee.config({path:c,override:!1})});try{await import("@zibby/skills")}catch{}function b(){const c=Yt();if(!c)return!1;try{const h=JSON.parse(atob(c.split(".")[1]));return h.exp&&h.exp*1e3>Date.now()}catch{return!1}}if(!b()){Oe();const c=ne(),{spawn:h}=await import("child_process"),Z=await fetch(`${c}/cli/login/initiate`,{method:"POST",headers:{"Content-Type":"application/json"}});Z.ok||(console.log(e.red("\n Could not start login. Try `zibby login`.\n")),process.exit(1));const{deviceCode:d,verificationUrl:n,expiresIn:N,interval:at}=await Z.json(),ot=process.platform;h(ot==="darwin"?"open":ot==="win32"?"cmd":"xdg-open",ot==="win32"?["/c","start","",n]:[n],{detached:!0,stdio:"ignore"}).unref();const lt=ae(),ut=(at||3)*1e3,pt=Math.floor(N/(at||3));let V=!1;for(let nt=0;nt<pt;nt++){await Ge(ut);try{const X=await fetch(`${c}/cli/login/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:d})});if(X.status===202)continue;if(!X.ok)break;const z=await X.json();if(z.status==="authorized"){Be(z.token),Ne(z.user),z.proxyUrl&&Re(z.proxyUrl),z.mem0ProxyUrl&&De(z.mem0ProxyUrl),V=!0;break}if(z.status==="denied")break}catch{break}}lt(),V||(console.log(e.red("\n Login failed or timed out. Run `zibby login` to try again.\n")),process.exit(1))}const _=await Xe(t),T=await Qe(t),E=o.agent||"assistant",A=Yt();A&&!process.env.ZIBBY_USER_TOKEN&&(process.env.ZIBBY_USER_TOKEN=A);const U=je()||Ue();U&&!process.env.ZIBBY_MEM0_OPENAI_BASE_URL&&(process.env.ZIBBY_MEM0_OPENAI_BASE_URL=U),process.env.AGENT_TYPE=E,process.env.ZIBBY_CHAT_OWNER_PID=String(process.pid);try{const{cleanupStalePidFiles:c}=await import("../utils/chat-run-lifecycle.js");c(t,_)}catch{}let R;try{R=_e({state:{agentType:E}})}catch(c){console.log(e.red(`
|
|
22
|
+
${c.message}
|
|
23
|
+
`)),process.exit(1)}const gt=Le(),rt=Me()?.[0]?.name,I=Ye(t),K=T.skills||[],H=Fe(t),M=H?[...new Set([...K,...H])]:[...K];let et={data:null,timestamp:0};const j=300*1e3,st={jira:"jira",github:"github",slack:"slack",sentry:"sentry"};try{const c=Yt();if(c){const h=ne(),Z=await fetch(`${h}/integrations/status`,{method:"GET",headers:{Authorization:`Bearer ${c}`}});if(Z.ok){const d=await Z.json();for(const[n,N]of Object.entries(st))d[n]?.connected&&!M.includes(N)&&$t(N)&&M.push(N);Ct(t,M)}}}catch{}const it=M.filter(c=>c!=="skill-installer"&&c!=="core-tools"),ht=it.length>0?`Skills: ${it.join(", ")}`:"Skills: (none)";cs({userName:gt?.name?.split(" ")[0],cwd:t,projectName:rt,restoredCount:I.length,skillsLine:ht});let l=le(t),y=pe(l);return new Promise(c=>{const h=process.env.ZIBBY_CHAT_TAB_COMPLETION==="1",Z={input:process.stdin,output:process.stdout,prompt:e.green(" > "),terminal:!0};h&&(Z.completer=u=>{const i=String(u||"");if(!i.startsWith("/"))return[[],i];const f=y.map(P=>P.cmd),$=f.filter(P=>P.startsWith(i));return[$.length>0?$:f,i]});const d=Ce(Z),n=ls(d);let N=null,at=!1;const ot=[],me=0,de=1200;let lt=!1,ut=!1,pt=!1,V=!1,nt="",X=0;const z=typeof d._ttyWrite=="function"?d._ttyWrite.bind(d):null;z&&(d._ttyWrite=(...u)=>{if(!(V||Date.now()<X))return z(...u)});function fe(){pt||!process.stdout?.isTTY||typeof process.stdout.write!="function"||(process.stdout.write("\x1B[?2004h"),pt=!0)}function Jt(){pt&&(!process.stdout?.isTTY||typeof process.stdout.write!="function"||(process.stdout.write("\x1B[?2004l"),pt=!1))}function ge(u){const i="\x1B[200~",f="\x1B[201~";if(!V&&!u.includes(i))return!1;let $=u,P=!1;for(;$.length>0;){if(!V){const C=$.indexOf(i);if(C===-1)break;P=!0,Kt(),V=!0,nt="",$=$.slice(C+i.length);continue}const J=$.indexOf(f);if(J===-1){P=!0,nt+=$;break}P=!0,nt+=$.slice(0,J);const Q=String(nt||"").replace(/\r\n/g,`
|
|
24
|
+
`).replace(/\r/g,`
|
|
25
|
+
`);if(Q.length>0){const C=Q.split(`
|
|
26
|
+
`);for(const G of C)Rt(G)}vt(),nt="",V=!1,$=$.slice(J+f.length)}return P}function qt(){if(!lt){lt=!0;try{It(t,I),Ct(t,M)}catch{}try{Jt()}catch{}try{d.close()}catch{}process.exit(0)}}async function Lt(){if(!lt){lt=!0,typeof R?.cleanup=="function"&&await R.cleanup().catch(()=>{});try{const{killAllChatOrchestratedRuns:u}=await import("../utils/chat-run-lifecycle.js"),{postCliInterruptedRunIndex:i}=await import("@zibby/core/utils/run-index-post-cli.js");u(t,process.pid,_),i({cwd:t,config:_})}catch{}It(t,I),Ct(t,M),n.pushSystem(e.gray("Session saved. Goodbye!")),Jt(),d.close(),process.exit(0)}}if(n.mount(),fe(),process.stdout?.isTTY){let u;process.stdout.on("resize",()=>{clearTimeout(u),u=setTimeout(()=>{n.handleResize()},80)})}let Mt=0;const _t=u=>{if(typeof u=="string"?u==="\x1B":u&&typeof u.length=="number"?u.length===1&&u[0]===27:!1){N&&N.abort(),qt();return}const f=typeof u=="string"?u:u&&typeof u.length=="number"?Buffer.from(u).toString("utf8"):"";if(!f)return;if(ge(f)){Mt=Date.now()+1200,X=Date.now()+1200,Ot();return}const $=(f.includes(`
|
|
27
|
+
`)||f.includes("\r"))&&f!=="\r"&&f!==`
|
|
28
|
+
`&&f!==`\r
|
|
29
|
+
`,P=f.includes("\x1B[200~")||f.includes("\x1B[201~"),J=f.length>=16&&/\s/.test(f)&&!f.startsWith("\x1B");($||P||J)&&(Mt=Date.now()+1200,X=Date.now()+1200,Kt(),Ot())},B={query:"",matches:[],selected:0},W={prefix:"",matches:[],nextIndex:0},x={active:!1,prefix:"",lines:[],timer:null},Bt=[];let Zt=0,Nt="";const he=new Set(Wt.map(u=>u.cmd));function mt(u,{preserveFrame:i=!1}={}){const f=String(u||"");d.line=f,d.cursor=f.length,Nt=f,typeof d._refreshLine=="function"?d._refreshLine():d.prompt(),i&&n.touchInputFrame()}function Gt(){W.prefix="",W.matches=[],W.nextIndex=0}function vt(){if(x.timer&&(clearTimeout(x.timer),x.timer=null),x.active&&x.lines.length>0){Zt+=1;const u=x.lines.length,i=`[Pasted text #${Zt} +${u} lines]`,f=x.lines.join(`
|
|
30
|
+
`);Bt.push({placeholder:i,text:f});const $=String(x.prefix||"").trimEnd(),P=$?`${$} ${i}`:i;mt(P,{preserveFrame:!0}),dt(d.line)}x.active=!1,x.prefix="",x.lines=[],X=0}function Ot(){x.timer&&clearTimeout(x.timer),x.timer=setTimeout(()=>{vt()},180)}function Kt(){x.active||(x.active=!0,x.prefix=String(Nt||d.line||""),x.lines=[],mt(x.prefix,{preserveFrame:!0}))}function Rt(u){return x.active?(x.lines.push(String(u||"")),mt(x.prefix,{preserveFrame:!0}),Ot(),!0):!1}function ye(u){let i=String(u||"");for(const f of Bt)i=i.split(f.placeholder).join(f.text);return i}function dt(u){const i=String(u||"");if(!i.startsWith("/")||i.includes(" ")||i.length===0){B.query="",B.matches=[],B.selected=0,n.clearCommandDropdown();return}l=le(t),y=pe(l);const f=i.slice(1).toLowerCase(),$=l.filter(P=>P.toLowerCase().startsWith(f));B.query=f,B.matches=$,B.selected=Math.min(B.selected,Math.max(0,$.length-1)),n.showCommandDropdown($,B.selected)}const Ut=(u,i)=>{if(i?.name==="escape"||i?.sequence==="\x1B"){N&&N.abort(),qt();return}if((i?.name==="return"||i?.name==="enter")&&(ut=!0),(i?.name==="backspace"||i?.name==="delete")&&n.touchInputFrame(),i?.name==="tab"&&!i?.shift){const P=String(d.line||""),J=Number(d.cursor||P.length);if(!is(P,J)){Gt(),dt(d.line);return}const Q=P.slice(1).toLowerCase();if(W.prefix!==Q&&(W.prefix=Q,W.matches=y.map(G=>G.cmd).filter(G=>G.toLowerCase().startsWith(`/${Q}`)),W.nextIndex=0),W.matches.length===0)return;const C=W.nextIndex%W.matches.length;W.nextIndex+=1,mt(W.matches[C]),dt(d.line);return}const f=String(d.line||""),$=f.startsWith("/")&&!f.includes(" ")&&B.matches.length>0;if(i?.name==="up"||i?.name==="down"){if(!$){dt(d.line);return}const P=i.name==="up"?-1:1,J=B.matches.length;B.selected=(B.selected+P+J)%J;const Q=B.matches[B.selected];mt(`/${Q}`,{preserveFrame:!0}),n.showCommandDropdown(B.matches,B.selected);return}i?.name!=="tab"&&Gt(),setTimeout(()=>{dt(d.line),x.active||(Nt=String(d.line||""))},50)};process.stdin?.on&&(Ie(process.stdin,d),process.stdin.on("keypress",Ut)),n.enabled&&process.stdin?.on&&(typeof process.stdin.prependListener=="function"?process.stdin.prependListener("data",_t):process.stdin.on("data",_t)),d.on("line",async u=>{try{let i=String(u||"");const f=ut;if(ut=!1,!f&&(x.active||V||Date.now()<Mt||Date.now()<X)){if(x.active&&i.length>0){Rt(i);return}x.active&&(vt(),n.refreshPrompt());return}if(x.active&&(vt(),i=String(d.line||i||"")),Rt(i))return;const $=i.trim(),P=B.matches[B.selected];if($.startsWith("/")&&!$.includes(" ")&&B.matches.length>0&&!he.has($)&&$!==`/${P}`){n.clearCommandDropdown(),n.refreshPrompt(),mt(`/${P}`),dt(`/${P}`);return}n.clearCommandDropdown();const C=String(i||"").replace(/[\u0000-\u001F\u007F-\u009F]/g,"").trim();if(!C){n.enabled&&process.stdout?.isTTY&&(L(process.stdout,0,-1),O(process.stdout,4));return}if(at&&C!=="/exit"&&C!=="/quit"){N&&N.abort(),ot.push(C),n.pushSystem(e.gray("Processing your message...")),n.refreshPrompt({preserveInput:!0});return}const G=1e4;if(C.length>G){n.pushSystem(e.red(`\u26A0 Input too long (${C.length} chars). Maximum: ${G} characters.`)),n.pushSystem(e.gray("Tip: If you need to share logs, use a file instead:")),n.pushSystem(e.gray(" 1. Save to file: pbpaste > debug.log")),n.pushSystem(e.gray(' 2. Ask: "analyze debug.log in current directory"')),n.refreshPrompt();return}if(C==="/exit"||C==="/quit"){Lt();return}if(C==="/help"){us(),n.refreshPrompt();return}if(C==="/skills"){const k=$t("skill-installer")?.catalog||{},g=M.filter(w=>w!=="skill-installer");console.log(e.cyan(`
|
|
31
|
+
Active skills:`)),g.length===0&&console.log(e.gray(" (none)"));for(const w of g){const S=k[w]||{};console.log(e.green(` \u2713 ${w}`)+e.gray(S.description?` \u2014 ${S.description}`:""))}const v=Object.keys(k).filter(w=>!M.includes(w));if(v.length>0){console.log(e.cyan(`
|
|
32
|
+
Available:`));for(const w of v){const S=k[w],m=S.envKeys?.length>0?ps(S.envKeys).ok?e.green(" \u2713 configured"):e.yellow(` \u26A0 needs: ${S.envKeys.join(", ")}`):"";console.log(e.white(` - ${w}`)+e.gray(` \u2014 ${S.description}`)+m)}}console.log(e.gray(`
|
|
33
|
+
Just ask to install: "connect to Jira", "add GitHub", etc.
|
|
34
|
+
`)),n.refreshPrompt();return}if(C.startsWith("/history")){if(I.length===0)console.log(e.gray(`
|
|
35
|
+
No conversation history.
|
|
36
|
+
`));else{const a=C.split(/\s+/).slice(1),k=a.includes("--all"),g=a.indexOf("-n"),v=g>=0&&a[g+1]?parseInt(a[g+1],10):NaN,w=k?I.length:isNaN(v)?10:v,S=I.slice(-w);console.log(e.gray(`
|
|
37
|
+
Showing ${S.length} of ${I.length} messages${k?" (all)":""}:
|
|
38
|
+
`));for(const m of S){const p=m.role==="human"?e.green(" You"):e.cyan(" Zibby"),D=k||v>10?500:100,F=m.content.length>D?`${m.content.substring(0,D)}...`:m.content;console.log(`${p}: ${e.white(F)}`)}console.log("")}n.refreshPrompt();return}if(C==="/clear"){I.length=0,It(t,I),console.log(e.gray(`
|
|
39
|
+
History cleared.
|
|
40
|
+
`)),n.refreshPrompt();return}if(C.startsWith("/memory")){const a=M.includes("chat-memory")?$t("chat-memory"):null;if(!a?.handleToolCall){console.log(e.yellow(`
|
|
41
|
+
Chat memory not active. Install with: "add chat memory"
|
|
42
|
+
`)),n.refreshPrompt();return}const k=C.split(/\s+/).slice(1),g=k[0]||"brief",v={options:{workspace:t}};try{if(g==="facts"||g==="all"){const w=parseInt(k[1],10)||30,S=await a.handleToolCall("memory_recall",{limit:w},v),m=JSON.parse(S);if(console.log(e.cyan(`
|
|
43
|
+
Stored memories (${m.total}):
|
|
44
|
+
`)),m.total===0)console.log(e.gray(` (empty \u2014 memories are saved as the agent learns things)
|
|
45
|
+
`));else{for(const p of m.memories){const D=e.yellow(`[${p.category}]`),F=Number(p.relevance)<1?e.gray(` (${(Number(p.relevance)*100).toFixed(0)}%)`):"",St=p.ticket_key?e.magenta(` ${p.ticket_key}`):"",bt=p.source?e.gray(` via ${p.source}`):"";console.log(` ${D}${St} ${e.white(p.content)}${F}${bt}`)}console.log("")}}else if(g==="tasks"){const w=parseInt(k[1],10)||20,S=await a.handleToolCall("task_history",{limit:w},v),m=JSON.parse(S);if(console.log(e.cyan(`
|
|
46
|
+
Task history (${m.total}):
|
|
47
|
+
`)),m.total===0)console.log(e.gray(` (no tasks logged yet)
|
|
48
|
+
`));else{for(const p of m.tasks){const D=p.status==="passed"?e.green("\u2713"):p.status==="failed"?e.red("\u2717"):e.yellow("\u25CB"),F=p.ticket_key?e.magenta(` ${p.ticket_key}`):"",St=e.gray(`[${p.type}]`),bt=p.result_summary?e.gray(` \u2014 ${p.result_summary.slice(0,80)}`):"";console.log(` ${D} ${St}${F} ${e.white(p.title)}${bt}`)}console.log("")}}else if(g==="sessions"){const w=await a.handleToolCall("memory_brief",{},v),S=JSON.parse(w);if(console.log(e.cyan(`
|
|
49
|
+
Recent sessions (${S.recentSessions?.length||0}):
|
|
50
|
+
`)),!S.recentSessions?.length)console.log(e.gray(` (no sessions saved yet)
|
|
51
|
+
`));else{for(const m of S.recentSessions){const p=m.tickets?e.magenta(` [${m.tickets}]`):"",D=m.tasks_run>0?e.gray(` \u2014 ${m.tasks_run} tasks (${m.tasks_passed} passed, ${m.tasks_failed} failed)`):"",F=m.created_at?e.gray(` ${m.created_at.split("T")[0]}`):"";if(console.log(` ${e.white(m.summary)}${p}${D}${F}`),m.key_facts)for(const St of m.key_facts.split(";").map(bt=>bt.trim()).filter(Boolean))console.log(e.gray(` \u2192 ${St}`))}console.log("")}}else if(g==="search"){const w=k.slice(1).join(" ");if(!w)console.log(e.yellow(`
|
|
52
|
+
Usage: /memory search <keyword>
|
|
53
|
+
`));else{const S=await a.handleToolCall("memory_recall",{query:w,limit:20},v),m=JSON.parse(S);console.log(e.cyan(`
|
|
54
|
+
Search "${w}" \u2014 ${m.total} results:
|
|
55
|
+
`));for(const p of m.memories){const D=e.yellow(`[${p.category}]`),F=p.ticket_key?e.magenta(` ${p.ticket_key}`):"";console.log(` ${D}${F} ${e.white(p.content)}`)}m.total===0&&console.log(e.gray(" (no matches)")),console.log("")}}else{const w=await a.handleToolCall("memory_brief",{},v),S=JSON.parse(w),m=S.topMemories?.length||0,p=S.recentSessions?.length||0,D=(S.taskStats||[]).map(F=>`${F.type}:${F.status}=${F.cnt}`).join(", ");console.log(e.cyan(`
|
|
56
|
+
Memory overview:
|
|
57
|
+
`)),console.log(e.white(` Facts stored: ${m>0?e.cyan(m):e.gray("0")}`)),console.log(e.white(` Sessions saved: ${p>0?e.cyan(p):e.gray("0")}`)),D&&console.log(e.white(` Task history: ${e.gray(D)}`)),console.log(e.gray(`
|
|
58
|
+
Subcommands:`)),console.log(e.gray(" /memory facts [n] \u2014 List all stored memories")),console.log(e.gray(" /memory tasks [n] \u2014 List task history")),console.log(e.gray(" /memory sessions \u2014 List session summaries")),console.log(e.gray(" /memory search <keyword> \u2014 Search memories")),console.log("")}}catch(w){console.log(e.red(`
|
|
59
|
+
Memory error: ${w.message}
|
|
60
|
+
`))}n.refreshPrompt();return}n.enabled&&process.stdout?.isTTY&&(L(process.stdout,0,-1),O(process.stdout,0)),n.pushUser(C),n.refreshPrompt(),n.showAssistantLoading();const Vt=ye(C),Tt=ts(t,Vt);if(Bt.length=0,!String(Tt||"").trim()){n.dismissTransientLoading(),n.refreshPrompt();return}if(Tt.length>G){n.pushAssistant(e.red(`Input too long after command expansion (${Tt.length} chars).`)),n.pushSystem(e.gray(`Try shortening the command template or user text. Limit: ${G} chars.`)),n.refreshPrompt();return}at=!0;let tt=T.systemPrompt||"You are Zibby, a helpful AI assistant.";const Xt=ns(T,o);Xt&&(tt+=`
|
|
61
|
+
|
|
62
|
+
${Xt}`);const Qt=We({activeSkills:M,chatConfig:T,options:o});Qt&&(tt+=`
|
|
63
|
+
|
|
64
|
+
${Qt}`);const te=os(M);if(te&&(tt+=`
|
|
65
|
+
|
|
66
|
+
${te}`),tt+=`
|
|
67
|
+
|
|
68
|
+
Use provided tools when external data/actions are required. Do not claim actions without tool calls. Before using a skill's tools for the first time in a conversation, call get_skill_context(skillId) to load its full guidance.`,M.includes("chat-memory")&&(tt+=`
|
|
69
|
+
|
|
70
|
+
### Memory Tool Usage (chat-memory)
|
|
71
|
+
- At conversation start: call memory_brief to load recent context.
|
|
72
|
+
- Before answering memory-dependent questions: call memory_recall with focused query terms.
|
|
73
|
+
- When learning durable user/project facts or decisions: call memory_store.
|
|
74
|
+
- Avoid storing transient chatter, filler text, or duplicate facts.
|
|
75
|
+
- Prefer updating strong existing facts over creating near-duplicates when possible.`),M.includes("chat-memory"))try{const a=$t("chat-memory");if(typeof a?.buildPromptContext=="function"){const k=Date.now();let g;et.data&&k-et.timestamp<j?(g=et.data,process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray("Using cached memory context"))):(g=await a.buildPromptContext({options:{workspace:t}},{}),et={data:g,timestamp:k},process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray("Refreshed memory context cache")));const v=String(g?.backend||"dolt");process.env.ZIBBY_VERBOSE==="true"&&(n.pushSystem(e.gray(`memory backend: ${v}`)),n.pushSystem(e.gray(`memory retrieval output: ${Et(JSON.stringify(g?.debugPreview||{}),1400)}`)),g?.error&&n.pushSystem(e.yellow(`memory backend warning: ${g.error}`))),g?.promptContext&&(tt+=`
|
|
76
|
+
|
|
77
|
+
${g.promptContext}`)}}catch(a){process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.yellow(`memory backend warning: ${String(a?.message||a)}`))}tt=xt(tt,ie);const Se=es(I),jt=ss([{role:"system",content:tt},...Se,{role:"user",content:Tt}]),ee=Ht(jt),be=Buffer.byteLength(JSON.stringify(jt),"utf8");process.env.ZIBBY_VERBOSE==="true"&&n.pushSystem(e.gray(`payload estimate: ${ee} chars, ${be} bytes (~${Math.round(ee/4)} tokens)`)),I.push({role:"human",content:Vt});const yt=n.enabled?(()=>{const a=()=>{};return a.setLabel=()=>{},a})():ae();let ct=!0;const Pt=[];let se="",wt="";const ds=50,fs=500,gs=3,hs=60,ys=500,ws=15,Ss=25,bs=4,$s=new Set([".","!","?",",",";",":"]),$e=a=>{ct&&(yt(),ct=!1),wt+=a},ke=(a,k)=>{if(!a){ct&&yt.setLabel("thinking...");return}Pt.push(a);const g=70;let v=a;if(k&&typeof k=="object"){const S=Object.values(k).map(p=>typeof p=="string"?p:JSON.stringify(p)).join(", "),m=`${a}(${S})`;m.length<=g?v=m:v=`${a}(${S.slice(0,g-a.length-4)}...)`}v!==se&&(se=v,n.pushSystem(e.gray(`\u23BF ${v}`)),n.refreshPrompt({preserveInput:!0}),ct&&n.showAssistantLoading()),ct&&yt.setLabel(v)},Dt=new AbortController;N=Dt;try{const a=await xe("",{state:{agentType:E,config:_,cwd:t,workspace:t}},{model:_?.agent?.assistant?.model||T.model||"auto",workspace:t,skills:M,activeSkills:M,config:_,timeout:T.timeout||3e5,messages:jt,skipPromptFragments:!0,stream:!0,onToken:$e,onToolCall:ke,signal:Dt.signal});ct&&yt();const k=typeof a=="string"?a:a?.structured?JSON.stringify(a.structured,null,2):a?.raw||String(a),g=wt&&wt.trim().length>0?wt.trim():k.trim(),v=rs(g,Pt)?g:g;n.pushAssistant(v);const w=Pt.length>0?`[tools used: ${Pt.join(", ")}]
|
|
78
|
+
${g}`:g;I.push({role:"ai",content:w}),It(t,I),Ct(t,M)}catch(a){if(ct&&yt(),n.dismissTransientLoading(),Dt.signal.aborted){ot.length===0&&n.pushAssistant(e.gray("[cancelled]"));let k="";try{const{testRunnerSkill:v}=await import("../../skills/index.js"),w=await v.handleToolCall("run_status",{runId:"all"},{options:{workspace:t}}),S=JSON.parse(w);S.runs?.length>0&&(k=`
|
|
79
|
+
[Active test runs: ${S.runs.map(p=>`${p.runId}: ${p.ticketKey||p.spec} (${p.status})`).join(", ")}. Use run_status("all") to check progress.]`)}catch{}const g=wt.trim();g?I.push({role:"ai",content:g+k}):I.push({role:"ai",content:`[interrupted \u2014 new message]${k}`})}else{const k=String(a?.message||a||"Unknown error");/413|payload too large|request payload too large/i.test(k)?(n.pushAssistant(e.yellow("Request became too large for the proxy (413).")),n.pushSystem(e.gray("Try: /clear, then retry your command; or shorten command/context."))):n.pushAssistant(e.red(`Error: ${k}`)),I.push({role:"ai",content:`[Error: ${a.message}]`})}}finally{N=null,at=!1}if(n.refreshPrompt(),ot.length>0){const a=ot.shift();ut=!0,setImmediate(()=>d.emit("line",a))}}catch(i){n.pushSystem(e.red(`Input handling error: ${i?.message||String(i)}`)),n.refreshPrompt()}}),d.on("SIGINT",()=>{if(N){N.abort();return}Lt()}),d.on("close",Lt);const we=()=>{process.stdin?.off?(process.stdin.off("data",_t),process.stdin.off("keypress",Ut)):process.stdin?.removeListener&&(process.stdin.removeListener("data",_t),process.stdin.removeListener("keypress",Ut))};d.on("close",we)})}export{Bs as _buildPrompt,Ve as _checkEnvKeys,Ke as _formatHistory,Ms as _inferAgentType,Os as chatCommand};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{patchCursorAgentForCI as i,checkCursorAgentPatched as p,getApprovalKeys as g,saveApprovalKeys as y}from"@zibby/core";import{resolve as c}from"path";import e from"chalk";import n from"ora";async function v(r){console.log(e.bold.cyan(`
|
|
2
|
+
\u{1F527} Setting up CI/CD for Cursor Agent
|
|
3
|
+
`)),console.log(e.gray("\u2501".repeat(50)));const t=p();if(t.installed||(console.log(e.red(`
|
|
4
|
+
\u274C cursor-agent is not installed!
|
|
5
|
+
`)),console.log(e.white("To install:")),console.log(e.gray(` curl https://cursor.com/install -fsS | bash
|
|
6
|
+
`)),process.exit(1)),t.patched)console.log(e.green(`\u2705 cursor-agent is already patched for CI/CD
|
|
7
|
+
`));else{const s=n("Patching cursor-agent...").start();try{await i(),s.succeed("cursor-agent patched successfully")}catch(o){s.fail("Failed to patch cursor-agent"),console.log(e.red(`
|
|
8
|
+
\u274C Error: ${o.message}
|
|
9
|
+
`)),process.exit(1)}}if(r.getKeys){const s=n("Getting approval keys...").start();try{const o=await g(c(process.cwd()));s.succeed("Approval keys retrieved"),console.log(e.cyan(`
|
|
10
|
+
\u{1F4CB} Approval Keys:
|
|
11
|
+
`)),Object.entries(o.keys).forEach(([a,l])=>{console.log(e.white(` ${a}: ${e.gray(l)}`))}),r.save?y(c(process.cwd()),o.keys):(console.log(e.gray(`
|
|
12
|
+
To save these keys, run:`)),console.log(e.white(` zibby ci-setup --get-keys --save
|
|
13
|
+
`)))}catch(o){s.fail("Failed to get approval keys"),console.log(e.red(`
|
|
14
|
+
\u274C Error: ${o.message}
|
|
15
|
+
`)),process.exit(1)}}console.log(e.green(`
|
|
16
|
+
\u2705 CI/CD setup complete!
|
|
17
|
+
`)),console.log(e.cyan("Next steps:")),console.log(e.white(" 1. Get approval keys: zibby ci-setup --get-keys")),console.log(e.white(" 2. Save to project: zibby ci-setup --get-keys --save")),console.log(e.white(` 3. Use in CI: zibby run <spec> --agent=cursor --auto-approve
|
|
18
|
+
`))}export{v as ciSetupCommand};
|