@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.
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 +19 -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
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 run tests/**/*.spec.js
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 run test.spec.js --sync
49
+ zibby test test.spec.js --sync
50
50
 
51
51
  # Or with explicit project override
52
- zibby run test.spec.js --project zby_xxx --sync
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 run tests/**/*.spec.js
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 run` - Run Test Specification
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 run test-specs/auth/login.txt
141
+ zibby test test-specs/auth/login.txt
142
142
 
143
143
  # With options
144
- zibby run test-specs/auth/login.txt --agent=cursor --headless
144
+ zibby test test-specs/auth/login.txt --agent=cursor --headless
145
145
 
146
146
  # Open results in browser after completion
147
- zibby run test-specs/auth/login.txt --project zby_xxx --collection "My Tests" --open
147
+ zibby test test-specs/auth/login.txt --project zby_xxx --collection "My Tests" --open
148
148
 
149
149
  # For CI/CD
150
- zibby run test-specs/auth/login.txt --agent=cursor --auto-approve --headless
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 run test-specs/examples/google-search.txt
275
+ zibby test test-specs/examples/google-search.txt
276
276
 
277
277
  # Run with cloud sync and open results
278
- zibby run test-specs/examples/google-search.txt \
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 run test-specs/auth/login.txt --agent=claude --headless
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/examples/google-search.txt --agent=cursor
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 run test-specs/auth/login.txt --agent=cursor
425
+ zibby test test-specs/auth/login.txt --agent=cursor
426
426
 
427
427
  # With options and auto-open results
428
- zibby run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt --agent=cursor
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
- zibby run "$spec" --agent=cursor --headless --sync
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 run test-specs/auth/login.txt --workflow=BatchRunner
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 run test-specs/auth/login.txt --agent=cursor --auto-approve
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 run test-specs/auth/login.txt --agent=cursor
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt --agent=cursor
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 run test-specs/auth/login.txt --agent=cursor --headless
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt --project zby_xxx -o
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 run test-specs/auth/login.txt --agent=cursor
832
+ zibby test test-specs/auth/login.txt --agent=cursor
833
833
 
834
834
  # With options and open results
835
- zibby run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt --agent=cursor
859
+ zibby test test-specs/auth/login.txt --agent=cursor
860
860
 
861
861
  # Run specific node
862
- zibby run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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 run test-specs/auth/login.txt \
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};