Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: yusufcanb/tlm
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.0
Choose a base ref
...
head repository: yusufcanb/tlm
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1.1
Choose a head ref
Loading
27 changes: 27 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: Bug report
about: Create a report to help me improve
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
*A clear and concise description of what the bug is.*

**Console Output**
*If applicable, add console output.*

**tlm Version**
*Which tlm version are you running? Type `tlm version` to get the version*

e.g. `tlm 1.0 (windows/amd64)`


**Platform Information (please complete the following information):**
*Which operating system are you running on?*-


**Additional context**
*Add any other context about the problem here.*
10 changes: 10 additions & 0 deletions .github/ISSUE_TEMPLATE/custom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---


46 changes: 41 additions & 5 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
name: build
name: ci

on: [push]
on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -27,5 +26,42 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: dist
path: |
dist
path: dist/
retention-days: 1
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: dist

- name: Install tlm
run: |
mv $(cat VERSION)/tlm_$(cat VERSION)_linux_amd64 /usr/local/bin/tlm
chmod +x /usr/local/bin/tlm
tlm help
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: 3.11

- name: Install dependencies
run: pip install -r e2e/requirements.txt

- name: Run Tests wo/ Ollama
run: robot --outputdir dist --name tlm --exclude requires=ollama tlm.robot
working-directory: e2e/

- name: Archive e2e artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: e2e-report
path: e2e/dist/

needs:
- build
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -20,4 +20,5 @@
# Go workspace file
go.work
.idea
dist
dist
.venv/
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# tlm - Local CLI Copilot, powered by CodeLLaMa. 💻🦙

![Latest Build](https://img.shields.io/github/actions/workflow/status/yusufcanb/tlm/build.yaml?style=for-the-badge&logo=github)
![Latest Release](https://img.shields.io/github/v/release/yusufcanb/tlm?display_name=release&style=for-the-badge&logo=github&link=https%3A%2F%2Fgithub.com%2Fyusufcanb%2Ftlm%2Freleases)
[![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/yusufcanb_tlm?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonar)](https://sonarcloud.io/project/overview?id=yusufcanb_tlm)
[![Latest Release](https://img.shields.io/github/v/release/yusufcanb/tlm?display_name=release&style=for-the-badge&logo=github&link=https%3A%2F%2Fgithub.com%2Fyusufcanb%2Ftlm%2Freleases)](https://github.com/yusufcanb/tlm/releases)
![Downloads](https://img.shields.io/github/downloads/yusufcanb/tlm/total.svg?style=for-the-badge&logo=github&color=orange)



tlm is your CLI companion which requires nothing except your workstation. It uses most efficient and powerful [CodeLLaMa](https://ai.meta.com/blog/code-llama-large-language-model-coding/) in your local environment to provide you the best possible command line suggestions.

![Suggest](./assets/suggest.gif)
@@ -36,16 +39,16 @@ Installation can be done in two ways;
[Ollama](https://ollama.com/) is needed to download to necessary models.
It can be downloaded with the following methods on different platforms.

- On Linux and macOS;
- On macOs and Windows;

Download instructions can be followed at the following link: [https://ollama.com/download](https://ollama.com/download)

- On Linux;

```bash
curl -fsSL https://ollama.com/install.sh | sh
```

- On Windows;

Download instructions can be followed at the following link: [https://ollama.com/download](https://ollama.com/download)

- Or using official Docker images 🐳;

```bash
@@ -67,15 +70,15 @@ It will recognize the which platform and architecture to download and will execu
Download and execute the installation script by using the following command;

```bash
curl -fsSL https://raw.githubusercontent.com/yusufcanb/tlm/main/install.sh | sudo bash -E
curl -fsSL https://raw.githubusercontent.com/yusufcanb/tlm/release/1.1/install.sh | sudo bash -E
```

#### Windows (Powershell 5.1 or higher)

Download and execute the installation script by using the following command;

```powershell
Invoke-RestMethod -Uri https://raw.githubusercontent.com/yusufcanb/tlm/main/install.ps1 | Invoke-Expression
Invoke-RestMethod -Uri https://raw.githubusercontent.com/yusufcanb/tlm/release/1.1/install.ps1 | Invoke-Expression
```

### Go Install
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0
1.1
36 changes: 19 additions & 17 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -7,9 +7,8 @@ import (
"github.com/yusufcanb/tlm/config"
"github.com/yusufcanb/tlm/explain"
"github.com/yusufcanb/tlm/install"
"github.com/yusufcanb/tlm/shell"
"github.com/yusufcanb/tlm/suggest"
"os"
"io/fs"
"runtime"

"github.com/urfave/cli/v2"
@@ -22,51 +21,54 @@ var explainModelfile string
var suggestModelfile string

type TlmApp struct {
App *cli.App
writer *fs.File

explainModelfile string
suggestModelfile string

App *cli.App
}

func New(version string) *TlmApp {
func New(version, buildSha string) *TlmApp {
con := config.New()
con.LoadOrCreateConfig()

o, _ := ollama.ClientFromEnvironment()
sug := suggest.New(o, suggestModelfile)
exp := explain.New(o, explainModelfile)
sug := suggest.New(o)
exp := explain.New(o)
ins := install.New(o, suggestModelfile, explainModelfile)

cliApp := &cli.App{
Name: "tlm",
Usage: "terminal copilot, powered by CodeLLaMa.",
UsageText: "tlm explain <command>\ntlm suggest <prompt>",
Version: version,
CommandNotFound: func(context *cli.Context, s string) {
fmt.Println(shell.Err() + " command not found.")
os.Exit(-1)
},
Name: "tlm",
Usage: "terminal copilot, powered by CodeLLaMa.",
UsageText: "tlm explain <command>\ntlm suggest <prompt>",
Version: version,
CommandNotFound: notFound,
Before: beforeRun(),
After: afterRun(ins, version),
Action: func(c *cli.Context) error {
return cli.ShowAppHelp(c)
},
Commands: []*cli.Command{
sug.Command(),
exp.Command(),
ins.Command(),
ins.DeployCommand(),
con.Command(),
{
Name: "version",
Aliases: []string{"v"},
Usage: "Prints tlm version.",
Action: func(c *cli.Context) error {
fmt.Printf("tlm %s (%s/%s)", version, runtime.GOOS, runtime.GOARCH)
fmt.Printf("tlm %s (%s) on %s/%s", version, buildSha, runtime.GOOS, runtime.GOARCH)
return nil
},
},
},
}

return &TlmApp{
app := &TlmApp{
App: cliApp,
}

return app
}
52 changes: 52 additions & 0 deletions app/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package app_test

import (
"fmt"
"github.com/yusufcanb/tlm/app"
"io"
"os"
"testing"
)

func run(args []string) {
tlm := app.New("0.0", "test")

err := tlm.App.Run(args)
if err != nil {
os.Exit(1)
}
}

func Test_Version(t *testing.T) {

stdout := os.Stdout

args := os.Args[0:1]
args = append(args, " version")

capturedOutput := os.NewFile(0, "tlm.log")
os.Stdout = capturedOutput

run(args)

// Read all contents from the capturedOutput
contents, err := io.ReadAll(capturedOutput)
if err != nil {
fmt.Println("Error reading contents:", err)
t.Fail()
}

os.Stdout = stdout
_ = capturedOutput.Close()

// Print the captured output
t.Log("Captured Output:")
t.Log(string(contents))

}

func Test_Help(t *testing.T) {
args := os.Args[0:1]
args = append(args, "help")
run(args)
}
33 changes: 33 additions & 0 deletions app/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package app

import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/yusufcanb/tlm/install"
"github.com/yusufcanb/tlm/shell"
"os"
)

func notFound(_ *cli.Context, _ string) {
fmt.Println(shell.Err() + " command not found.")
os.Exit(-1)
}

func beforeRun() func(c *cli.Context) error {
return func(c *cli.Context) error {
return nil
}
}

func afterRun(ins *install.Install, version string) func(c *cli.Context) error {
return func(c *cli.Context) error {
switch c.Args().Get(0) {
case "suggest", "s", "explain", "e":
return nil

default:
return ins.ReleaseManager.CheckForUpdates(version)
}
}

}
3 changes: 2 additions & 1 deletion build.ps1
Original file line number Diff line number Diff line change
@@ -17,13 +17,14 @@ New-Item -ItemType Directory -Path "dist"
# Build Function (Helper)
Function Build-Target($os, $version, $arch) {
$outputName = "${appName}_${version}_${os}_${arch}"
$sha1 = (git rev-parse --short HEAD).Trim()
if ($os -eq "windows") {
$outputName += ".exe"
}

Write-Output "Building for $os/$arch (version: $version) -> $outputName"
# Invokes the Go toolchain (assumes it's in the PATH)
go build -o "dist/$version/$outputName" "main.go"
go build -o "dist/$version/$outputName" -ldflags "-X main.sha1ver=$sha1" "main.go"
}

# Build for each target OS
3 changes: 2 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ build() {
app_name=$2
version=$3
arch=$4
sha1=$(git rev-parse --short HEAD | tr -d '\n')

# Determine output filename with optional .exe extension
output_name="${app_name}_${version}_${os}_${arch}"
@@ -14,7 +15,7 @@ build() {
fi

echo "Building for $os/$arch (version: $version) -> $output_name"
CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -o "dist/${version}/${output_name}" main.go
CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -o "dist/${version}/${output_name}" -ldflags "-X main.sha1ver=$sha1" main.go
}

# Operating systems to target
13 changes: 8 additions & 5 deletions config/api.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@ import (
"path"
)

var defaultLLMHost = "http://localhost:11434"
var (
defaultSuggestionPolicy = "stable"
defaultExplainPolicy = "creative"
defaultShell = "auto"
)

func isExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
@@ -30,11 +34,10 @@ func (c *Config) LoadOrCreateConfig() {

configPath := path.Join(homeDir, ".tlm.yaml")
if !isExists(configPath) {
viper.Set("shell", shell.GetShell())

viper.Set("shell", defaultShell)
viper.Set("llm.host", defaultLLMHost)
viper.Set("llm.suggestion", "balanced")
viper.Set("llm.explain", "balanced")
viper.Set("llm.suggestion", defaultSuggestionPolicy)
viper.Set("llm.explain", defaultExplainPolicy)

err := os.Setenv("OLLAMA_HOST", defaultLLMHost)
if err != nil {
Loading