taskforceai-cli 0.6.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawn } from 'node:child_process';
4
+ import { existsSync } from 'node:fs';
4
5
  import { join } from 'node:path';
5
6
  import { fileURLToPath } from 'node:url';
6
- import { existsSync } from 'node:fs';
7
7
 
8
8
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
9
9
  const binPath = join(__dirname, 'taskforceai-bin');
package/go.mod CHANGED
@@ -1,17 +1,10 @@
1
1
  module github.com/TaskForceAI/cli
2
2
 
3
- go 1.25.5
3
+ go 1.25
4
4
 
5
- replace github.com/TaskForceAI/core => ../core
6
-
7
- replace github.com/TaskForceAI/infrastructure-llm => ../infrastructure-llm
8
-
9
- replace github.com/TaskForceAI/infrastructure-search => ../infrastructure-search
10
-
11
- replace github.com/TaskForceAI/shared => ../shared
5
+ toolchain go1.25.4
12
6
 
13
7
  require (
14
- github.com/TaskForceAI/core v0.0.0-00010101000000-000000000000
15
8
  github.com/blang/semver v3.5.1+incompatible
16
9
  github.com/charmbracelet/bubbles v0.21.0
17
10
  github.com/charmbracelet/bubbletea v1.3.10
@@ -19,47 +12,44 @@ require (
19
12
  github.com/getsentry/sentry-go v0.40.0
20
13
  github.com/rhysd/go-github-selfupdate v1.2.3
21
14
  github.com/sahilm/fuzzy v0.1.1
22
- github.com/stretchr/testify v1.11.1
23
15
  golang.org/x/oauth2 v0.34.0
24
16
  modernc.org/sqlite v1.42.2
25
17
  )
26
18
 
27
19
  require (
28
- github.com/TaskForceAI/shared v0.0.0 // indirect
29
20
  github.com/atotto/clipboard v0.1.4 // indirect
30
21
  github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
31
- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
32
- github.com/charmbracelet/x/ansi v0.10.1 // indirect
33
- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
34
- github.com/charmbracelet/x/term v0.2.1 // indirect
35
- github.com/davecgh/go-spew v1.1.1 // indirect
22
+ github.com/charmbracelet/colorprofile v0.4.1 // indirect
23
+ github.com/charmbracelet/x/ansi v0.11.3 // indirect
24
+ github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
25
+ github.com/charmbracelet/x/term v0.2.2 // indirect
26
+ github.com/clipperhouse/displaywidth v0.6.2 // indirect
27
+ github.com/clipperhouse/stringish v0.1.1 // indirect
28
+ github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
36
29
  github.com/dustin/go-humanize v1.0.1 // indirect
37
30
  github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
38
31
  github.com/google/go-github/v30 v30.1.0 // indirect
39
- github.com/google/go-querystring v1.0.0 // indirect
32
+ github.com/google/go-querystring v1.2.0 // indirect
40
33
  github.com/google/uuid v1.6.0 // indirect
41
34
  github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect
42
- github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
35
+ github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
43
36
  github.com/mattn/go-isatty v0.0.20 // indirect
44
37
  github.com/mattn/go-localereader v0.0.1 // indirect
45
- github.com/mattn/go-runewidth v0.0.16 // indirect
38
+ github.com/mattn/go-runewidth v0.0.19 // indirect
46
39
  github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
47
40
  github.com/muesli/cancelreader v0.2.2 // indirect
48
41
  github.com/muesli/termenv v0.16.0 // indirect
49
- github.com/ncruces/go-strftime v0.1.9 // indirect
50
- github.com/pmezard/go-difflib v1.0.0 // indirect
42
+ github.com/ncruces/go-strftime v1.0.0 // indirect
51
43
  github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
52
44
  github.com/rivo/uniseg v0.4.7 // indirect
53
- github.com/stretchr/objx v0.5.2 // indirect
54
45
  github.com/tcnksm/go-gitconfig v0.1.2 // indirect
55
- github.com/ulikunitz/xz v0.5.9 // indirect
46
+ github.com/ulikunitz/xz v0.5.15 // indirect
56
47
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
57
- golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
58
- golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
59
- golang.org/x/sys v0.36.0 // indirect
60
- golang.org/x/text v0.14.0 // indirect
61
- gopkg.in/yaml.v3 v3.0.1 // indirect
62
- modernc.org/libc v1.66.10 // indirect
48
+ golang.org/x/crypto v0.46.0 // indirect
49
+ golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
50
+ golang.org/x/sys v0.39.0 // indirect
51
+ golang.org/x/text v0.32.0 // indirect
52
+ modernc.org/libc v1.67.4 // indirect
63
53
  modernc.org/mathutil v1.7.1 // indirect
64
54
  modernc.org/memory v1.11.0 // indirect
65
55
  )
package/go.sum CHANGED
@@ -8,16 +8,22 @@ github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u
8
8
  github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
9
9
  github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
10
10
  github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
11
- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
12
- github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
11
+ github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
12
+ github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
13
13
  github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
14
14
  github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
15
- github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
16
- github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
17
- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
18
- github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
19
- github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
20
- github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
15
+ github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI=
16
+ github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI=
17
+ github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
18
+ github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
19
+ github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
20
+ github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
21
+ github.com/clipperhouse/displaywidth v0.6.2 h1:ZDpTkFfpHOKte4RG5O/BOyf3ysnvFswpyYrV7z2uAKo=
22
+ github.com/clipperhouse/displaywidth v0.6.2/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
23
+ github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
24
+ github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
25
+ github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
26
+ github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
21
27
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
28
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23
29
  github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -35,39 +41,39 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
35
41
  github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
36
42
  github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
37
43
  github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
38
- github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
39
44
  github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
45
+ github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
46
+ github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
40
47
  github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
41
48
  github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
42
49
  github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
43
50
  github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
51
+ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
52
+ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
44
53
  github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
45
54
  github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=
46
55
  github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
47
56
  github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
48
- github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
49
- github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
50
57
  github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
51
- github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
52
58
  github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
53
59
  github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
54
60
  github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
55
- github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
56
- github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
61
+ github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
62
+ github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
57
63
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
58
64
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
59
65
  github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
60
66
  github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
61
- github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
62
- github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
67
+ github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
68
+ github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
63
69
  github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
64
70
  github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
65
71
  github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
66
72
  github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
67
73
  github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
68
74
  github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
69
- github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
70
- github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
75
+ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
76
+ github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
71
77
  github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
72
78
  github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
73
79
  github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -81,83 +87,81 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
81
87
  github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
82
88
  github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
83
89
  github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg=
84
- github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
85
90
  github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
86
91
  github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
87
- github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
88
- github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
89
92
  github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
90
93
  github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
91
- github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
92
- github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
93
- github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
94
- github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
94
+ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
95
+ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
95
96
  github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw=
96
97
  github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE=
97
- github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
98
98
  github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
99
+ github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
100
+ github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
99
101
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
100
102
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
101
103
  go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
102
104
  go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
103
105
  golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
104
- golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
105
106
  golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
106
- golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
107
- golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
108
- golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
109
- golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
107
+ golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
108
+ golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
109
+ golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
110
+ golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
111
+ golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
112
+ golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
110
113
  golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
111
114
  golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
112
115
  golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
113
- golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
114
116
  golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
117
+ golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
118
+ golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
115
119
  golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
116
120
  golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
117
121
  golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
118
122
  golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
119
123
  golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
120
- golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
121
- golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
124
+ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
125
+ golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
122
126
  golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
123
127
  golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
124
128
  golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
125
129
  golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
126
130
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
127
- golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
128
- golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
131
+ golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
132
+ golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
129
133
  golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
130
134
  golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
131
135
  golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
132
- golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
133
- golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
136
+ golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
137
+ golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
134
138
  golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
135
- golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
136
- golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
139
+ golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
140
+ golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
137
141
  google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
138
142
  google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
139
143
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
140
144
  gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
141
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
142
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
143
145
  gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
144
146
  gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
145
147
  gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
146
148
  gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
147
149
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
148
150
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
149
- modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4=
150
- modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
151
- modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A=
152
- modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q=
151
+ modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
152
+ modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
153
+ modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
154
+ modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
153
155
  modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
154
156
  modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
155
157
  modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
156
158
  modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
159
+ modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
160
+ modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
157
161
  modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
158
162
  modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
159
- modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A=
160
- modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I=
163
+ modernc.org/libc v1.67.4 h1:zZGmCMUVPORtKv95c2ReQN5VDjvkoRm9GWPTEPuvlWg=
164
+ modernc.org/libc v1.67.4/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
161
165
  modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
162
166
  modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
163
167
  modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskforceai-cli",
3
- "version": "0.6.4",
3
+ "version": "0.10.0",
4
4
  "description": "TaskForceAI terminal client (Go-based) with SQLite support.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,4 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { existsSync } from 'node:fs';
3
2
  import { join } from 'node:path';
4
3
  import { fileURLToPath } from 'node:url';
5
4
 
@@ -1,37 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "time"
7
-
8
- "github.com/TaskForceAI/core/pkg/config"
9
- "github.com/TaskForceAI/core/pkg/platform"
10
- )
11
-
12
- // ConfigLoader is a function type for loading config (allows test injection)
13
- type ConfigLoader func(path string) (config.Config, error)
14
-
15
- // DefaultConfigLoader is the default config loader
16
- var DefaultConfigLoader ConfigLoader = config.LoadConfig
17
-
18
- func RunBenchmark(ctx context.Context) error {
19
- return RunBenchmarkWithLoader(ctx, DefaultConfigLoader)
20
- }
21
-
22
- // RunBenchmarkWithLoader allows injecting a custom config loader for testing
23
- func RunBenchmarkWithLoader(ctx context.Context, loader ConfigLoader) error {
24
- _, err := loader("")
25
- if err != nil {
26
- return err
27
- }
28
-
29
- logger := platform.GetLogger()
30
- logger.Info("Starting performance benchmark...")
31
-
32
- start := time.Now()
33
- // Mock implementation for benchmark
34
- logger.Info(fmt.Sprintf("Benchmark completed in %v", time.Since(start)))
35
-
36
- return nil
37
- }
@@ -1,47 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "context"
5
- "errors"
6
- "testing"
7
-
8
- "github.com/TaskForceAI/core/pkg/config"
9
- "github.com/stretchr/testify/assert"
10
- )
11
-
12
- func TestRunBenchmark(t *testing.T) {
13
- cleanup := setupTestConfig(t)
14
- defer cleanup()
15
-
16
- ctx := context.Background()
17
- err := RunBenchmark(ctx)
18
- assert.NoError(t, err)
19
- }
20
-
21
- func TestRunBenchmarkWithLoader(t *testing.T) {
22
- ctx := context.Background()
23
-
24
- // Test with successful loader
25
- successLoader := func(path string) (config.Config, error) {
26
- return config.Config{}, nil
27
- }
28
- err := RunBenchmarkWithLoader(ctx, successLoader)
29
- assert.NoError(t, err)
30
- }
31
-
32
- func TestRunBenchmarkWithLoader_ConfigError(t *testing.T) {
33
- ctx := context.Background()
34
-
35
- // Test with failing loader
36
- failLoader := func(path string) (config.Config, error) {
37
- return config.Config{}, errors.New("config load error")
38
- }
39
- err := RunBenchmarkWithLoader(ctx, failLoader)
40
- assert.Error(t, err)
41
- assert.Contains(t, err.Error(), "config load error")
42
- }
43
-
44
- func TestDefaultConfigLoader(t *testing.T) {
45
- // Test that DefaultConfigLoader is set
46
- assert.NotNil(t, DefaultConfigLoader)
47
- }
@@ -1,71 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "context"
5
- "time"
6
-
7
- "github.com/TaskForceAI/core/pkg/platform"
8
- )
9
-
10
- type PersistConversationInput struct {
11
- UserID *string
12
- UserInput string
13
- Result string
14
- ExecutionTime *float64
15
- Model string
16
- AgentCount int
17
- }
18
-
19
- type PersistConversation func(input PersistConversationInput) error
20
-
21
- // CLIFactory is a function that creates an OrchestratorCLI
22
- type CLIFactory func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error)
23
-
24
- // DefaultCLIFactory is the default factory using NewOrchestratorCLI
25
- var DefaultCLIFactory CLIFactory = NewOrchestratorCLI
26
-
27
- func MakeItHeavy(ctx context.Context, query string, modelID *string, userID *string, persist PersistConversation) (string, error) {
28
- return MakeItHeavyWithFactory(ctx, query, modelID, userID, persist, DefaultCLIFactory)
29
- }
30
-
31
- // MakeItHeavyWithFactory allows injecting a custom CLI factory for testing
32
- func MakeItHeavyWithFactory(ctx context.Context, query string, modelID *string, userID *string, persist PersistConversation, factory CLIFactory) (string, error) {
33
- opts := OrchestratorCLIOptions{
34
- Silent: true,
35
- }
36
- if modelID != nil {
37
- opts.ModelID = *modelID
38
- }
39
-
40
- cli, err := factory(opts)
41
- if err != nil {
42
- return "", err
43
- }
44
-
45
- result, err := cli.RunTask(ctx, query)
46
- if err != nil {
47
- return "", err
48
- }
49
-
50
- if persist != nil {
51
- var execTime *float64
52
- if !cli.startTime.IsZero() {
53
- t := time.Since(cli.startTime).Seconds()
54
- execTime = &t
55
- }
56
-
57
- err = persist(PersistConversationInput{
58
- UserID: userID,
59
- UserInput: query,
60
- Result: result,
61
- ExecutionTime: execTime,
62
- Model: cli.modelDisplay,
63
- AgentCount: cli.orchestrator.GetAgentCount(),
64
- })
65
- if err != nil {
66
- platform.GetLogger().Error("Failed to persist result", "error", err)
67
- }
68
- }
69
-
70
- return result, nil
71
- }
@@ -1,153 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "bytes"
5
- "context"
6
- "errors"
7
- "testing"
8
-
9
- "github.com/stretchr/testify/assert"
10
- "github.com/stretchr/testify/mock"
11
- )
12
-
13
- func TestMakeItHeavyWithFactory(t *testing.T) {
14
- mockOrch := new(MockOrchestrator)
15
- mockOrch.On("Orchestrate", mock.Anything, "test query").Return("test result", nil)
16
- mockOrch.On("GetAgentCount").Return(3)
17
-
18
- var buf bytes.Buffer
19
- factory := func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
20
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
21
- Orchestrator: mockOrch,
22
- ModelDisplay: "Test Model",
23
- Silent: true,
24
- Stdout: &buf,
25
- }), nil
26
- }
27
-
28
- modelID := "test-model"
29
- userID := "user-123"
30
- persistCalled := false
31
- persist := func(input PersistConversationInput) error {
32
- persistCalled = true
33
- assert.Equal(t, "test query", input.UserInput)
34
- assert.Equal(t, "test result", input.Result)
35
- assert.Equal(t, "user-123", *input.UserID)
36
- assert.Equal(t, "Test Model", input.Model)
37
- assert.Equal(t, 3, input.AgentCount)
38
- return nil
39
- }
40
-
41
- result, err := MakeItHeavyWithFactory(context.Background(), "test query", &modelID, &userID, persist, factory)
42
- assert.NoError(t, err)
43
- assert.Equal(t, "test result", result)
44
- assert.True(t, persistCalled)
45
- mockOrch.AssertExpectations(t)
46
- }
47
-
48
- func TestMakeItHeavyWithFactory_FactoryError(t *testing.T) {
49
- factory := func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
50
- return nil, errors.New("factory error")
51
- }
52
-
53
- result, err := MakeItHeavyWithFactory(context.Background(), "query", nil, nil, nil, factory)
54
- assert.Error(t, err)
55
- assert.Equal(t, "", result)
56
- assert.Contains(t, err.Error(), "factory error")
57
- }
58
-
59
- func TestMakeItHeavyWithFactory_OrchestrationError(t *testing.T) {
60
- mockOrch := new(MockOrchestrator)
61
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("", errors.New("orchestration error"))
62
-
63
- factory := func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
64
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
65
- Orchestrator: mockOrch,
66
- Silent: true,
67
- }), nil
68
- }
69
-
70
- result, err := MakeItHeavyWithFactory(context.Background(), "query", nil, nil, nil, factory)
71
- assert.Error(t, err)
72
- assert.Equal(t, "", result)
73
- assert.Contains(t, err.Error(), "orchestration error")
74
- }
75
-
76
- func TestMakeItHeavyWithFactory_PersistError(t *testing.T) {
77
- mockOrch := new(MockOrchestrator)
78
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("result", nil)
79
- mockOrch.On("GetAgentCount").Return(1)
80
-
81
- factory := func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
82
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
83
- Orchestrator: mockOrch,
84
- Silent: true,
85
- }), nil
86
- }
87
-
88
- persist := func(input PersistConversationInput) error {
89
- return errors.New("persist error")
90
- }
91
-
92
- // Should still return result even if persist fails
93
- result, err := MakeItHeavyWithFactory(context.Background(), "query", nil, nil, persist, factory)
94
- assert.NoError(t, err)
95
- assert.Equal(t, "result", result)
96
- }
97
-
98
- func TestMakeItHeavyWithFactory_NilPersist(t *testing.T) {
99
- mockOrch := new(MockOrchestrator)
100
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("result", nil)
101
-
102
- factory := func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
103
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
104
- Orchestrator: mockOrch,
105
- Silent: true,
106
- }), nil
107
- }
108
-
109
- result, err := MakeItHeavyWithFactory(context.Background(), "query", nil, nil, nil, factory)
110
- assert.NoError(t, err)
111
- assert.Equal(t, "result", result)
112
- }
113
-
114
- func TestMakeItHeavy_Types(t *testing.T) {
115
- // Test type definitions
116
- var persist PersistConversation = nil
117
- assert.Nil(t, persist)
118
-
119
- // Test PersistConversationInput
120
- input := PersistConversationInput{
121
- UserInput: "test",
122
- Result: "result",
123
- Model: "model",
124
- AgentCount: 1,
125
- }
126
- assert.Equal(t, "test", input.UserInput)
127
- }
128
-
129
- func TestCLIFactory(t *testing.T) {
130
- // Test that DefaultCLIFactory is set
131
- assert.NotNil(t, DefaultCLIFactory)
132
- }
133
-
134
- func TestMakeItHeavy(t *testing.T) {
135
- // Save and restore DefaultCLIFactory
136
- origFactory := DefaultCLIFactory
137
- defer func() { DefaultCLIFactory = origFactory }()
138
-
139
- mockOrch := new(MockOrchestrator)
140
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("result", nil)
141
- mockOrch.On("GetAgentCount").Return(1)
142
-
143
- DefaultCLIFactory = func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
144
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
145
- Orchestrator: mockOrch,
146
- Silent: true,
147
- }), nil
148
- }
149
-
150
- result, err := MakeItHeavy(context.Background(), "query", nil, nil, nil)
151
- assert.NoError(t, err)
152
- assert.Equal(t, "result", result)
153
- }
@@ -1,250 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "bufio"
5
- "context"
6
- "fmt"
7
- "io"
8
- "os"
9
- "strings"
10
- "time"
11
-
12
- "github.com/TaskForceAI/core/pkg/agent"
13
- "github.com/TaskForceAI/core/pkg/config"
14
- "github.com/TaskForceAI/core/pkg/orchestrator"
15
- "github.com/TaskForceAI/core/pkg/platform"
16
- )
17
-
18
- const (
19
- colorOrange = "\x1b[38;5;208m"
20
- colorRed = "\x1b[91m"
21
- colorEnd = "\x1b[0m"
22
- progressBarLen = 70
23
- )
24
-
25
- func buildProgressBar(status string) string {
26
- switch status {
27
- case "QUEUED":
28
- return "○ " + strings.Repeat("·", progressBarLen)
29
- case "INITIALIZING...":
30
- return fmt.Sprintf("%s◐%s ", colorOrange, colorEnd) + strings.Repeat("·", progressBarLen)
31
- case "PROCESSING...":
32
- return fmt.Sprintf("%s●%s ", colorOrange, colorEnd) + fmt.Sprintf("%s:%s", colorOrange, colorEnd) + strings.Repeat("·", 10) + strings.Repeat("·", progressBarLen-11)
33
- case "COMPLETED":
34
- return fmt.Sprintf("%s●%s ", colorOrange, colorEnd) + strings.Repeat(fmt.Sprintf("%s:%s", colorOrange, colorEnd), progressBarLen)
35
- default:
36
- if strings.HasPrefix(status, "FAILED") {
37
- return fmt.Sprintf("%s✗%s ", colorRed, colorEnd) + strings.Repeat(fmt.Sprintf("%s×%s", colorRed, colorEnd), progressBarLen)
38
- }
39
- return fmt.Sprintf("%s◐%s ", colorOrange, colorEnd) + strings.Repeat("·", progressBarLen)
40
- }
41
- }
42
-
43
- // IOrchestrator defines the interface for task orchestration
44
- type IOrchestrator interface {
45
- Orchestrate(ctx context.Context, input string) (string, error)
46
- GetAgentCount() int
47
- }
48
-
49
- // ModelSelector is a function type for resolving model selection (allows test injection)
50
- type ModelSelector func(cfg config.Config, modelID string) (*orchestrator.ResolvedModelSelection, error)
51
-
52
- // DefaultModelSelector is the default model selector
53
- var DefaultModelSelector ModelSelector = orchestrator.ResolveModelSelection
54
-
55
- type OrchestratorCLIOptions struct {
56
- Silent bool
57
- ModelID string
58
- Client agent.ILLMClient
59
- }
60
-
61
- type OrchestratorCLI struct {
62
- orchestrator IOrchestrator
63
- startTime time.Time
64
- running bool
65
- modelDisplay string
66
- modelID string
67
- modelLabel string
68
- silent bool
69
- stdin io.Reader
70
- stdout io.Writer
71
- }
72
-
73
- // OrchestratorCLIDeps allows injecting dependencies for testing
74
- type OrchestratorCLIDeps struct {
75
- Orchestrator IOrchestrator
76
- ModelDisplay string
77
- ModelID string
78
- ModelLabel string
79
- Silent bool
80
- Stdin io.Reader
81
- Stdout io.Writer
82
- }
83
-
84
- func NewOrchestratorCLI(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
85
- cfg, err := config.LoadConfig("")
86
- if err != nil {
87
- return nil, err
88
- }
89
-
90
- modelSelection, err := DefaultModelSelector(cfg, opts.ModelID)
91
- if err != nil {
92
- return nil, err
93
- }
94
-
95
- deps := orchestrator.OrchestratorDeps{
96
- Client: opts.Client,
97
- }
98
-
99
- orch := orchestrator.New(modelSelection.Config, deps, map[string]interface{}{
100
- "silent": opts.Silent,
101
- })
102
-
103
- return &OrchestratorCLI{
104
- orchestrator: orch,
105
- modelDisplay: modelSelection.SelectedModel.Badge,
106
- modelID: modelSelection.SelectedModel.ID,
107
- modelLabel: modelSelection.SelectedModel.Label,
108
- silent: opts.Silent,
109
- stdin: os.Stdin,
110
- stdout: os.Stdout,
111
- }, nil
112
- }
113
-
114
- // NewOrchestratorCLIWithDeps creates a CLI with injected dependencies for testing
115
- func NewOrchestratorCLIWithDeps(deps OrchestratorCLIDeps) *OrchestratorCLI {
116
- stdin := deps.Stdin
117
- if stdin == nil {
118
- stdin = os.Stdin
119
- }
120
- stdout := deps.Stdout
121
- if stdout == nil {
122
- stdout = os.Stdout
123
- }
124
- return &OrchestratorCLI{
125
- orchestrator: deps.Orchestrator,
126
- modelDisplay: deps.ModelDisplay,
127
- modelID: deps.ModelID,
128
- modelLabel: deps.ModelLabel,
129
- silent: deps.Silent,
130
- stdin: stdin,
131
- stdout: stdout,
132
- }
133
- }
134
-
135
- func (c *OrchestratorCLI) clearScreen() {
136
- fmt.Fprint(c.stdout, "\033[H\033[2J")
137
- }
138
-
139
- func (c *OrchestratorCLI) updateDisplay() {
140
- if !c.running {
141
- return
142
- }
143
-
144
- elapsed := time.Since(c.startTime).Seconds()
145
-
146
- c.clearScreen()
147
- logger := platform.GetLogger()
148
- logger.Info(c.modelDisplay)
149
- status := "COMPLETED"
150
- if c.running {
151
- status = "RUNNING"
152
- }
153
- logger.Info(fmt.Sprintf("● %s • %.2fs\n", status, elapsed))
154
- }
155
-
156
- func (c *OrchestratorCLI) RunTask(ctx context.Context, input string) (string, error) {
157
- c.startTime = time.Now()
158
- c.running = true
159
-
160
- if !c.silent {
161
- done := make(chan struct{})
162
- // Use a done channel to signal the ticker goroutine to exit immediately
163
- // preventing goroutine leaks/deadlocks in synctest
164
- defer close(done)
165
-
166
- go func() {
167
- ticker := time.NewTicker(1 * time.Second)
168
- defer ticker.Stop()
169
- for {
170
- select {
171
- case <-done:
172
- return
173
- case <-ticker.C:
174
- c.updateDisplay()
175
- }
176
- }
177
- }()
178
- }
179
-
180
- res, err := c.orchestrator.Orchestrate(ctx, input)
181
- c.running = false
182
-
183
- if c.silent {
184
- platform.GetLogger().Info(fmt.Sprintf("Orchestration completed in %.2fs", time.Since(c.startTime).Seconds()))
185
- } else {
186
- c.updateDisplay()
187
- fmt.Fprintf(c.stdout, "%s\nFINAL RESULTS\n%s\n\n%s\n\n%s\n", strings.Repeat("=", 80), strings.Repeat("=", 80), res, strings.Repeat("=", 80))
188
- }
189
-
190
- return res, err
191
- }
192
-
193
- func (c *OrchestratorCLI) InteractiveMode(ctx context.Context) error {
194
- logger := platform.GetLogger()
195
- logger.Info(fmt.Sprintf("Multi-Agent Orchestrator\nConfigured for %d parallel agents\nType 'quit', 'exit', or 'bye' to exit\n%s", c.orchestrator.GetAgentCount(), strings.Repeat("-", 50)))
196
- logger.Info(fmt.Sprintf("Using model: %s (%s)\nOrchestrator initialized successfully!\n%s", c.modelLabel, c.modelID, strings.Repeat("-", 50)))
197
-
198
- scanner := bufio.NewScanner(c.stdin)
199
- for {
200
- fmt.Fprint(c.stdout, "\nUser: ")
201
- if !scanner.Scan() {
202
- break
203
- }
204
- input := scanner.Text()
205
- lowerInput := strings.ToLower(strings.TrimSpace(input))
206
- if lowerInput == "quit" || lowerInput == "exit" || lowerInput == "bye" {
207
- break
208
- }
209
-
210
- logger.Info("\nOrchestrator: Starting multi-agent analysis...\n")
211
- _, err := c.RunTask(ctx, input)
212
- if err != nil {
213
- logger.Error("Orchestration failed", "error", err)
214
- }
215
- }
216
-
217
- return scanner.Err()
218
- }
219
-
220
- // GetOrchestrator returns the underlying orchestrator for testing
221
- func (c *OrchestratorCLI) GetOrchestrator() IOrchestrator {
222
- return c.orchestrator
223
- }
224
-
225
- // GetStartTime returns the start time for testing
226
- func (c *OrchestratorCLI) GetStartTime() time.Time {
227
- return c.startTime
228
- }
229
-
230
- // GetModelDisplay returns the model display string for testing
231
- func (c *OrchestratorCLI) GetModelDisplay() string {
232
- return c.modelDisplay
233
- }
234
-
235
- // Global functions for audit script (use DefaultCLIFactory for testability)
236
- func InteractiveMode(ctx context.Context) error {
237
- c, err := DefaultCLIFactory(OrchestratorCLIOptions{})
238
- if err != nil {
239
- return err
240
- }
241
- return c.InteractiveMode(ctx)
242
- }
243
-
244
- func RunTask(ctx context.Context, input string) (string, error) {
245
- c, err := DefaultCLIFactory(OrchestratorCLIOptions{})
246
- if err != nil {
247
- return "", err
248
- }
249
- return c.RunTask(ctx, input)
250
- }
@@ -1,400 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "bytes"
5
- "context"
6
- "errors"
7
- "strings"
8
- "testing"
9
- "testing/synctest"
10
- "time"
11
-
12
- "github.com/TaskForceAI/core/pkg/config"
13
- "github.com/TaskForceAI/core/pkg/orchestrator"
14
- "github.com/stretchr/testify/assert"
15
- "github.com/stretchr/testify/mock"
16
- )
17
-
18
- // MockOrchestrator implements IOrchestrator for testing
19
- type MockOrchestrator struct {
20
- mock.Mock
21
- }
22
-
23
- func (m *MockOrchestrator) Orchestrate(ctx context.Context, input string) (string, error) {
24
- args := m.Called(ctx, input)
25
- return args.String(0), args.Error(1)
26
- }
27
-
28
- func (m *MockOrchestrator) GetAgentCount() int {
29
- args := m.Called()
30
- return args.Int(0)
31
- }
32
-
33
- func TestBuildProgressBar(t *testing.T) {
34
- tests := []struct {
35
- name string
36
- status string
37
- contains string
38
- }{
39
- {"QUEUED", "QUEUED", "○"},
40
- {"INITIALIZING", "INITIALIZING...", "◐"},
41
- {"PROCESSING", "PROCESSING...", "●"},
42
- {"COMPLETED", "COMPLETED", "●"},
43
- {"FAILED", "FAILED 123", "✗"},
44
- {"UNKNOWN", "UNKNOWN", "◐"},
45
- }
46
-
47
- for _, tt := range tests {
48
- t.Run(tt.name, func(t *testing.T) {
49
- result := buildProgressBar(tt.status)
50
- assert.Contains(t, result, tt.contains)
51
- })
52
- }
53
- }
54
-
55
- func TestOrchestratorCLI_ClearScreen(t *testing.T) {
56
- var buf bytes.Buffer
57
- mockOrch := new(MockOrchestrator)
58
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
59
- Orchestrator: mockOrch,
60
- Stdout: &buf,
61
- })
62
-
63
- cli.clearScreen()
64
- assert.Contains(t, buf.String(), "\033[H\033[2J")
65
- }
66
-
67
- func TestOrchestratorCLI_UpdateDisplay(t *testing.T) {
68
- mockOrch := new(MockOrchestrator)
69
- var buf bytes.Buffer
70
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
71
- Orchestrator: mockOrch,
72
- Silent: false,
73
- Stdout: &buf,
74
- })
75
-
76
- // Not running - should return immediately
77
- cli.running = false
78
- cli.updateDisplay()
79
-
80
- // Running - should update display
81
- cli.running = true
82
- cli.startTime = time.Now()
83
- cli.updateDisplay()
84
- }
85
-
86
- func TestOrchestratorCLI_RunTask(t *testing.T) {
87
- mockOrch := new(MockOrchestrator)
88
- var buf bytes.Buffer
89
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
90
- Orchestrator: mockOrch,
91
- Silent: true,
92
- Stdout: &buf,
93
- })
94
-
95
- mockOrch.On("Orchestrate", mock.Anything, "test query").Return("test result", nil)
96
-
97
- result, err := cli.RunTask(context.Background(), "test query")
98
- assert.NoError(t, err)
99
- assert.Equal(t, "test result", result)
100
- mockOrch.AssertExpectations(t)
101
- }
102
-
103
- func TestOrchestratorCLI_RunTask_NotSilent(t *testing.T) {
104
- mockOrch := new(MockOrchestrator)
105
- var buf bytes.Buffer
106
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
107
- Orchestrator: mockOrch,
108
- Silent: false,
109
- Stdout: &buf,
110
- })
111
-
112
- mockOrch.On("Orchestrate", mock.Anything, "test query").Return("test result", nil)
113
-
114
- result, err := cli.RunTask(context.Background(), "test query")
115
- assert.NoError(t, err)
116
- assert.Equal(t, "test result", result)
117
- assert.Contains(t, buf.String(), "FINAL RESULTS")
118
- mockOrch.AssertExpectations(t)
119
- }
120
-
121
- func TestOrchestratorCLI_RunTask_OrchestrationError(t *testing.T) {
122
- mockOrch := new(MockOrchestrator)
123
- var buf bytes.Buffer
124
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
125
- Orchestrator: mockOrch,
126
- Silent: true,
127
- Stdout: &buf,
128
- })
129
-
130
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("", errors.New("orchestration error"))
131
-
132
- result, err := cli.RunTask(context.Background(), "query")
133
- assert.Error(t, err)
134
- assert.Equal(t, "", result)
135
- mockOrch.AssertExpectations(t)
136
- }
137
-
138
- func TestOrchestratorCLI_InteractiveMode(t *testing.T) {
139
- mockOrch := new(MockOrchestrator)
140
- mockOrch.On("GetAgentCount").Return(3)
141
- mockOrch.On("Orchestrate", mock.Anything, "hello").Return("response", nil)
142
-
143
- input := "hello\nexit\n"
144
- var buf bytes.Buffer
145
-
146
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
147
- Orchestrator: mockOrch,
148
- ModelLabel: "Test Model",
149
- ModelID: "test-model",
150
- Silent: true,
151
- Stdin: strings.NewReader(input),
152
- Stdout: &buf,
153
- })
154
-
155
- err := cli.InteractiveMode(context.Background())
156
- assert.NoError(t, err)
157
- mockOrch.AssertExpectations(t)
158
- }
159
-
160
- func TestOrchestratorCLI_InteractiveMode_ExitCommands(t *testing.T) {
161
- tests := []string{"quit", "exit", "bye"}
162
-
163
- for _, cmd := range tests {
164
- t.Run(cmd, func(t *testing.T) {
165
- mockOrch := new(MockOrchestrator)
166
- mockOrch.On("GetAgentCount").Return(1)
167
-
168
- var buf bytes.Buffer
169
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
170
- Orchestrator: mockOrch,
171
- Silent: true,
172
- Stdin: strings.NewReader(cmd + "\n"),
173
- Stdout: &buf,
174
- })
175
-
176
- err := cli.InteractiveMode(context.Background())
177
- assert.NoError(t, err)
178
- })
179
- }
180
- }
181
-
182
- func TestOrchestratorCLI_InteractiveMode_EOF(t *testing.T) {
183
- mockOrch := new(MockOrchestrator)
184
- mockOrch.On("GetAgentCount").Return(1)
185
-
186
- // Empty input will cause scanner to return false immediately
187
- var buf bytes.Buffer
188
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
189
- Orchestrator: mockOrch,
190
- Silent: true,
191
- Stdin: strings.NewReader(""),
192
- Stdout: &buf,
193
- })
194
-
195
- err := cli.InteractiveMode(context.Background())
196
- assert.NoError(t, err)
197
- }
198
-
199
- func TestOrchestratorCLI_Getters(t *testing.T) {
200
- mockOrch := new(MockOrchestrator)
201
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
202
- Orchestrator: mockOrch,
203
- ModelDisplay: "Test Display",
204
- })
205
-
206
- assert.Equal(t, mockOrch, cli.GetOrchestrator())
207
- assert.Equal(t, "Test Display", cli.GetModelDisplay())
208
- assert.True(t, cli.GetStartTime().IsZero())
209
- }
210
-
211
- func TestNewOrchestratorCLI(t *testing.T) {
212
- cleanup := setupTestConfig(t)
213
- defer cleanup()
214
-
215
- opts := OrchestratorCLIOptions{
216
- Silent: true,
217
- ModelID: "test-model",
218
- Client: nil,
219
- }
220
-
221
- cli, err := NewOrchestratorCLI(opts)
222
- assert.NoError(t, err)
223
- assert.NotNil(t, cli)
224
- assert.True(t, cli.silent)
225
- }
226
-
227
- func TestNewOrchestratorCLIWithDeps_Defaults(t *testing.T) {
228
- mockOrch := new(MockOrchestrator)
229
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
230
- Orchestrator: mockOrch,
231
- })
232
-
233
- assert.NotNil(t, cli.stdin)
234
- assert.NotNil(t, cli.stdout)
235
- }
236
-
237
- func TestOrchestratorCLI_InteractiveMode_OrchestrationError(t *testing.T) {
238
- mockOrch := new(MockOrchestrator)
239
- mockOrch.On("GetAgentCount").Return(1)
240
- mockOrch.On("Orchestrate", mock.Anything, "test").Return("", errors.New("orchestration error"))
241
-
242
- input := "test\nexit\n"
243
- var buf bytes.Buffer
244
-
245
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
246
- Orchestrator: mockOrch,
247
- Silent: true,
248
- Stdin: strings.NewReader(input),
249
- Stdout: &buf,
250
- })
251
-
252
- err := cli.InteractiveMode(context.Background())
253
- assert.NoError(t, err) // Should handle orchestration error gracefully
254
- }
255
-
256
- func TestPersistConversationInput(t *testing.T) {
257
- userID := "user-123"
258
- execTime := 1.5
259
-
260
- input := PersistConversationInput{
261
- UserID: &userID,
262
- UserInput: "test input",
263
- Result: "test result",
264
- ExecutionTime: &execTime,
265
- Model: "test-model",
266
- AgentCount: 3,
267
- }
268
-
269
- assert.Equal(t, "user-123", *input.UserID)
270
- assert.Equal(t, "test input", input.UserInput)
271
- assert.Equal(t, "test result", input.Result)
272
- assert.Equal(t, 1.5, *input.ExecutionTime)
273
- assert.Equal(t, "test-model", input.Model)
274
- assert.Equal(t, 3, input.AgentCount)
275
- }
276
-
277
- // Tests for global wrapper functions
278
- func TestGlobalInteractiveMode(t *testing.T) {
279
- // Save and restore DefaultCLIFactory
280
- origFactory := DefaultCLIFactory
281
- defer func() { DefaultCLIFactory = origFactory }()
282
-
283
- mockOrch := new(MockOrchestrator)
284
- mockOrch.On("GetAgentCount").Return(1)
285
-
286
- DefaultCLIFactory = func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
287
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
288
- Orchestrator: mockOrch,
289
- Silent: true,
290
- Stdin: strings.NewReader("exit\n"),
291
- Stdout: &bytes.Buffer{},
292
- }), nil
293
- }
294
-
295
- err := InteractiveMode(context.Background())
296
- assert.NoError(t, err)
297
- }
298
-
299
- func TestGlobalInteractiveMode_FactoryError(t *testing.T) {
300
- origFactory := DefaultCLIFactory
301
- defer func() { DefaultCLIFactory = origFactory }()
302
-
303
- DefaultCLIFactory = func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
304
- return nil, errors.New("factory error")
305
- }
306
-
307
- err := InteractiveMode(context.Background())
308
- assert.Error(t, err)
309
- assert.Contains(t, err.Error(), "factory error")
310
- }
311
-
312
- func TestGlobalRunTask(t *testing.T) {
313
- origFactory := DefaultCLIFactory
314
- defer func() { DefaultCLIFactory = origFactory }()
315
-
316
- mockOrch := new(MockOrchestrator)
317
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("result", nil)
318
-
319
- DefaultCLIFactory = func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
320
- return NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
321
- Orchestrator: mockOrch,
322
- Silent: true,
323
- }), nil
324
- }
325
-
326
- result, err := RunTask(context.Background(), "query")
327
- assert.NoError(t, err)
328
- assert.Equal(t, "result", result)
329
- }
330
-
331
- func TestGlobalRunTask_FactoryError(t *testing.T) {
332
- origFactory := DefaultCLIFactory
333
- defer func() { DefaultCLIFactory = origFactory }()
334
-
335
- DefaultCLIFactory = func(opts OrchestratorCLIOptions) (*OrchestratorCLI, error) {
336
- return nil, errors.New("factory error")
337
- }
338
-
339
- result, err := RunTask(context.Background(), "query")
340
- assert.Error(t, err)
341
- assert.Equal(t, "", result)
342
- assert.Contains(t, err.Error(), "factory error")
343
- }
344
-
345
- func TestNewOrchestratorCLI_ConfigError(t *testing.T) {
346
- // Don't setup config - should fail to load
347
- opts := OrchestratorCLIOptions{
348
- Silent: true,
349
- ModelID: "test-model",
350
- }
351
-
352
- _, err := NewOrchestratorCLI(opts)
353
- assert.Error(t, err) // Should fail because config doesn't exist
354
- }
355
-
356
- func TestNewOrchestratorCLI_ModelSelectionError(t *testing.T) {
357
- cleanup := setupTestConfig(t)
358
- defer cleanup()
359
-
360
- // Save and restore DefaultModelSelector
361
- origSelector := DefaultModelSelector
362
- defer func() { DefaultModelSelector = origSelector }()
363
-
364
- // Make model selection return an error
365
- DefaultModelSelector = func(cfg config.Config, modelID string) (*orchestrator.ResolvedModelSelection, error) {
366
- return nil, errors.New("model selection error")
367
- }
368
-
369
- opts := OrchestratorCLIOptions{
370
- Silent: true,
371
- ModelID: "test-model",
372
- }
373
-
374
- _, err := NewOrchestratorCLI(opts)
375
- assert.Error(t, err)
376
- assert.Contains(t, err.Error(), "model selection error")
377
- }
378
-
379
- func TestOrchestratorCLI_RunTask_NotSilent_WithTicker(t *testing.T) {
380
- synctest.Test(t, func(t *testing.T) {
381
- // Test the ticker goroutine branch by running without silent mode
382
- // and giving it a chance to tick (ticker fires every 1 second)
383
- mockOrch := new(MockOrchestrator)
384
- var buf bytes.Buffer
385
- cli := NewOrchestratorCLIWithDeps(OrchestratorCLIDeps{
386
- Orchestrator: mockOrch,
387
- Silent: false,
388
- Stdout: &buf,
389
- })
390
-
391
- // Make orchestration take longer than 1 second so ticker can fire
392
- mockOrch.On("Orchestrate", mock.Anything, "query").Return("result", nil).Run(func(args mock.Arguments) {
393
- time.Sleep(1100 * time.Millisecond) // Just over 1 second to let ticker fire
394
- })
395
-
396
- result, err := cli.RunTask(context.Background(), "query")
397
- assert.NoError(t, err)
398
- assert.Equal(t, "result", result)
399
- })
400
- }
@@ -1,28 +0,0 @@
1
- package cli
2
-
3
- import (
4
- "os"
5
- "testing"
6
-
7
- "github.com/stretchr/testify/require"
8
- )
9
-
10
- func setupTestConfig(t *testing.T) func() {
11
- // LoadConfig defaults to "config/config.yaml" relative to CWD
12
- // We need to create this file in the test directory
13
- yamlContent := `
14
- gateway:
15
- model: test-model
16
- orchestrator:
17
- parallel_agents: 1
18
- `
19
- err := os.MkdirAll("config", 0755)
20
- require.NoError(t, err)
21
-
22
- err = os.WriteFile("config/config.yaml", []byte(yamlContent), 0644)
23
- require.NoError(t, err)
24
-
25
- return func() {
26
- os.RemoveAll("config")
27
- }
28
- }