@owdproject/cli 0.0.3 → 0.1.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.
@@ -0,0 +1,222 @@
1
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs'
2
+ import { dirname, join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+ import {
5
+ resolveDesktopConfigPath,
6
+ desktopConfigWritePath,
7
+ } from './desktopConfig.js'
8
+
9
+ export const SCOPE = '@owdproject/'
10
+
11
+ /** Not loadable via desktop.config `modules` (core is the shell). */
12
+ export const DESKTOP_NON_INSTALLABLE = new Set([
13
+ '@owdproject/core',
14
+ '@owdproject/cli',
15
+ '@owdproject/nx',
16
+ ])
17
+
18
+ /** Installed documentation modules (current + deprecated package name). */
19
+ export const DOCS_MODULE_PACKAGES = [
20
+ '@owdproject/module-docs',
21
+ '@owdproject/docs',
22
+ ]
23
+
24
+ export function hasDocsModuleInstalled(config, deps = {}) {
25
+ return DOCS_MODULE_PACKAGES.some(
26
+ (name) => config?.modules?.includes(name) || deps[name],
27
+ )
28
+ }
29
+
30
+ export function docsBasePathFromConfig(config) {
31
+ const base = config?.docs?.basePath
32
+ if (typeof base === 'string' && base.startsWith('/')) return base
33
+ return '/docs'
34
+ }
35
+
36
+ /** Theme-internal UI kits — pulled in by themes, not listed as desktop modules. */
37
+ export function isDesktopKitPackage(pkgName) {
38
+ const isScoped = pkgName.startsWith(SCOPE)
39
+ const short = isScoped ? pkgName.slice(SCOPE.length) : pkgName
40
+ if (!isScoped && !pkgName.startsWith('kit-')) return false
41
+ return short.startsWith('kit-')
42
+ }
43
+
44
+ /** Scaffold / blueprint packages — not loadable desktop modules. */
45
+ export function isDesktopTemplatePackage(pkgName) {
46
+ const isScoped = pkgName.startsWith(SCOPE)
47
+ const short = isScoped ? pkgName.slice(SCOPE.length) : pkgName
48
+ if (!isScoped && !pkgName.endsWith('-template')) return false
49
+ return short.endsWith('-template')
50
+ }
51
+
52
+ export function isInstallableDesktopModule(pkgName) {
53
+ const isScoped = pkgName.startsWith(SCOPE)
54
+ if (!isScoped && !pkgName.startsWith('module-')) return false
55
+ return (
56
+ !DESKTOP_NON_INSTALLABLE.has(pkgName) &&
57
+ !isDesktopKitPackage(pkgName) &&
58
+ !isDesktopTemplatePackage(pkgName)
59
+ )
60
+ }
61
+
62
+ export const KINDS = {
63
+ app: {
64
+ label: 'Apps',
65
+ topic: 'owd-apps',
66
+ workspaceDir: 'apps',
67
+ configKey: 'apps',
68
+ nx: 'desktop:install-app',
69
+ },
70
+ module: {
71
+ label: 'Modules',
72
+ topic: 'owd-modules',
73
+ workspaceDir: 'packages',
74
+ configKey: 'modules',
75
+ nx: 'desktop:install-module',
76
+ },
77
+ theme: {
78
+ label: 'Themes',
79
+ topic: 'owd-themes',
80
+ workspaceDir: 'themes',
81
+ configKey: 'theme',
82
+ nx: 'desktop:install-theme',
83
+ },
84
+ }
85
+
86
+ export function findWorkspaceRoot(startDir = process.cwd()) {
87
+ let dir = startDir
88
+ for (;;) {
89
+ if (
90
+ existsSync(join(dir, 'pnpm-workspace.yaml')) &&
91
+ existsSync(join(dir, 'nx.json'))
92
+ ) {
93
+ return dir
94
+ }
95
+ const parent = dirname(dir)
96
+ if (parent === dir) return null
97
+ dir = parent
98
+ }
99
+ }
100
+
101
+ export function desktopMetaDir(workspaceRoot) {
102
+ return join(workspaceRoot, '.desktop')
103
+ }
104
+
105
+ export function settingsPath(workspaceRoot) {
106
+ return join(desktopMetaDir(workspaceRoot), 'settings.json')
107
+ }
108
+
109
+ /** @typedef {'npm' | 'workspace'} InstallMode */
110
+
111
+ export function normalizeInstallMode(value) {
112
+ if (value === 'workspace' || value === 'dev') return 'workspace'
113
+ return 'npm'
114
+ }
115
+
116
+ export function isWorkspaceInstallMode(settings) {
117
+ return normalizeInstallMode(settings?.installMode) === 'workspace'
118
+ }
119
+
120
+ /** @typedef {'updated' | 'name' | 'stars' | 'installed'} CatalogSortMode */
121
+
122
+ export function normalizeCatalogSort(value) {
123
+ const modes = ['updated', 'name', 'stars', 'installed']
124
+ return modes.includes(value) ? /** @type {CatalogSortMode} */ (value) : 'updated'
125
+ }
126
+
127
+ export function loadSettings(workspaceRoot, metaDir = null) {
128
+ const defaults = {
129
+ devPort: 3000,
130
+ githubUser: null,
131
+ githubOrgs: ['owdproject'],
132
+ installMode: /** @type {InstallMode} */ ('npm'),
133
+ catalogSort: /** @type {CatalogSortMode} */ ('updated'),
134
+ catalogNewDays: 14,
135
+ }
136
+
137
+ try {
138
+ const path = metaDir ? join(metaDir, 'settings.json') : settingsPath(workspaceRoot)
139
+ if (!existsSync(path)) {
140
+ return { ...defaults, ...detectGithubUser(), installMode: 'npm' }
141
+ }
142
+ const merged = { ...defaults, ...detectGithubUser(), ...JSON.parse(readFileSync(path, 'utf8')) }
143
+ merged.installMode = normalizeInstallMode(merged.installMode)
144
+ merged.catalogSort = normalizeCatalogSort(merged.catalogSort)
145
+ merged.catalogNewDays =
146
+ typeof merged.catalogNewDays === 'number' && merged.catalogNewDays > 0
147
+ ? merged.catalogNewDays
148
+ : 14
149
+ return merged
150
+ } catch {
151
+ return { ...defaults, ...detectGithubUser(), installMode: 'npm' }
152
+ }
153
+ }
154
+
155
+ function detectGithubUser() {
156
+ const fromEnv = process.env.OWD_GITHUB_USER?.trim()
157
+ if (fromEnv) return { githubUser: fromEnv }
158
+
159
+ try {
160
+ const user = execSync('git config --get github.user || git config --get user.username', {
161
+ encoding: 'utf8',
162
+ stdio: ['ignore', 'pipe', 'ignore'],
163
+ }).trim()
164
+ if (user) return { githubUser: user }
165
+ } catch {
166
+ /* ignore */
167
+ }
168
+
169
+ return {}
170
+ }
171
+
172
+ export function saveSettings(workspaceRoot, settings, metaDir = null) {
173
+ const dir = metaDir || desktopMetaDir(workspaceRoot)
174
+ mkdirSync(dir, { recursive: true })
175
+ const path = metaDir ? join(metaDir, 'settings.json') : settingsPath(workspaceRoot)
176
+ writeFileSync(path, JSON.stringify(settings, null, 2) + '\n')
177
+ }
178
+
179
+ export function desktopPaths(workspaceRoot) {
180
+ const desktop = join(workspaceRoot, 'desktop')
181
+ const resolved = resolveDesktopConfigPath(desktop)
182
+ const configWrite = desktopConfigWritePath(desktop)
183
+
184
+ return {
185
+ desktop,
186
+ config: resolved?.path ?? configWrite,
187
+ configWrite,
188
+ configLegacy: resolved?.legacy ?? false,
189
+ packageJson: join(desktop, 'package.json'),
190
+ }
191
+ }
192
+
193
+ export function shortName(pkgName) {
194
+ return pkgName.startsWith(SCOPE) ? pkgName.slice(SCOPE.length) : pkgName
195
+ }
196
+
197
+ export function fullName(short) {
198
+ return short.startsWith(SCOPE) ? short : `${SCOPE}${short}`
199
+ }
200
+
201
+ export function inferKind(shortName) {
202
+ if (shortName.startsWith('app-')) return 'app'
203
+ if (shortName.startsWith('theme-')) return 'theme'
204
+ return 'module'
205
+ }
206
+
207
+ export function getPackagesRequiredByTheme(workspaceRoot, themeName) {
208
+ if (!themeName) return []
209
+ const themeShort = shortName(themeName)
210
+ const pkgJsonPath = join(workspaceRoot, 'themes', themeShort, 'package.json')
211
+ if (!existsSync(pkgJsonPath)) return []
212
+ try {
213
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
214
+ const themeDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies }
215
+ return Object.keys(themeDeps).filter(
216
+ (dep) => isDesktopKitPackage(dep) || isInstallableDesktopModule(dep)
217
+ )
218
+ } catch {
219
+ return []
220
+ }
221
+ }
222
+
package/bin/owd.js CHANGED
@@ -1,121 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { Command } from 'commander'
4
- import chalk from 'chalk'
5
- import gradient from 'gradient-string'
6
- import inquirer from 'inquirer'
7
- import { execSync } from 'child_process'
8
- import fs from 'fs'
9
- import path from 'path'
3
+ import { runCli } from './cli.js'
10
4
 
11
- import {cloneRepo} from '../src/utils/cloneRepo.js'
12
-
13
- const program = new Command()
14
- const owdGradient = gradient('#0080ff', '#53bdf3', '#0080ff')
15
-
16
- const logTitle = () => {
17
- console.log(owdGradient(`\n
18
- ___ __ __ _ ___ _ _
19
- /___\\_ __ ___ _ __ / / /\\ \\ \\___| |__ / \\___ ___| | _| |_ ___ _ __
20
- // // '_ \\ / _ \\ '_ \\ \\ \\/ \\/ / _ \\ '_ \\ / /\\ / _ \\/ __| |/ / __/ _ \\| '_ \\
21
- / \\_//| |_) | __/ | | | \\ /\\ / __/ |_) | / /_// __/\\__ \\ <| || (_) | |_) |
22
- \\___/ | .__/ \\___|_| |_| \\/ \\/ \\___|_.__/ /___,' \\___||___/_|\\_\\\\__\\___/| .__/
23
- |_| |_|
24
- \n`))
25
- console.log(chalk.white(summonInspiration()))
26
- console.log(chalk.white('\n──────────────────────────────────────────────────────────────────────────────\n'))
27
- console.log(chalk.white(' ➜ ') + chalk.whiteBright('npx @owdproject/cli create') + chalk.gray(' Create a new project from the template'))
28
- console.log(chalk.white(' ➜ ') + chalk.whiteBright('npx @owdproject/cli start') + chalk.gray(' Start the dev server for local development'))
29
- console.log(chalk.white(' ➜ ') + chalk.whiteBright('npx @owdproject/cli generate') + chalk.gray(' Generate project for static deployment'))
30
- console.log(chalk.white('\n──────────────────────────────────────────────────────────────────────────────\n'))
31
- }
32
-
33
- const logServerInfo = () => {
34
- console.log(`\n ${chalk.red.bold('➜ Local:')} ${chalk.white('http://localhost:3000/')}`)
35
- console.log(` ${chalk.red.bold('➜ Network:')} ${chalk.white('http://localhost:3000/')} \n`)
36
- }
37
-
38
- program.command('create')
39
- .description('Create a new project')
40
- .action(async () => {
41
- logTitle()
42
- console.log(chalk.green('✨ Creating new project\n'))
43
-
44
- const { projectDir } = await inquirer.prompt([
45
- {
46
- type: 'input',
47
- name: 'projectDir',
48
- message: 'Enter the directory name for your new project:',
49
- default: 'owd-client'
50
- }
51
- ])
52
-
53
- const targetDir = path.join(process.cwd(), projectDir)
54
-
55
- if (fs.existsSync(targetDir)) {
56
- console.log(chalk.red(`Directory ${projectDir} already exists!`))
57
- return
58
- }
59
-
60
- fs.mkdirSync(targetDir, { recursive: true })
61
-
62
- try {
63
- await cloneRepo(targetDir)
64
-
65
- process.chdir(targetDir)
66
-
67
- console.log(chalk.green('Installing dependencies...'))
68
- execSync('npm install', { stdio: 'inherit' })
69
-
70
- console.log(chalk.blue('Starting development server...'))
71
- execSync('npm run dev', { stdio: 'inherit' })
72
- } catch (error) {
73
- console.error(error)
74
- console.log(chalk.red('✖ Error during project setup'))
75
- }
76
- })
77
-
78
- program.command('start')
79
- .description('Start the project in development mode')
80
- .action(() => {
81
- logTitle()
82
-
83
- try {
84
- execSync('npx nuxi dev --host --qr=false', { stdio: 'inherit' })
85
- console.log(chalk.blue('🚀 Starting development server'))
86
- logServerInfo()
87
- } catch (error) {
88
- console.log(chalk.red('✖ Error starting Nuxt server'))
89
- console.log(chalk.yellow(error.message))
90
- } finally {
91
- console.log(chalk.white('👨‍💻 If you need help, check the logs or visit our docs'))
92
- }
93
- })
94
-
95
- program.command('generate')
96
- .description('Generate deployment files')
97
- .action(() => {
98
- logTitle()
99
-
100
- try {
101
- execSync('npx nuxi generate', { stdio: 'inherit' })
102
- console.log(chalk.green('✅ Static site generated successfully!'))
103
- } catch (error) {
104
- console.log(chalk.red('✖ Error generating static site'))
105
- }
106
- })
107
-
108
- function summonInspiration() {
109
- const phrases = [
110
- "Launching your digital workspace with Open Web Desktop",
111
- "Unleashing the potential of your browser with Open Web Desktop",
112
- "Crafting a better web experience with Open Web Desktop",
113
- "Transforming how you showcase your portfolio on a browser",
114
- "Bringing your digital garden to life, right in the browser",
115
- "Opening up new possibilities with Open Web Desktop",
116
- ];
117
- const randomIndex = Math.floor(Math.random() * phrases.length);
118
- return phrases[randomIndex];
119
- }
120
-
121
- program.parse()
5
+ await runCli('owd', process.argv.slice(2), { deprecated: true })
@@ -0,0 +1,200 @@
1
+ package bridge
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "fmt"
7
+ "os"
8
+ "os/exec"
9
+ "path/filepath"
10
+ )
11
+
12
+ type Config struct {
13
+ Theme *string `json:"theme"`
14
+ Apps []string `json:"apps"`
15
+ Modules []string `json:"modules"`
16
+ }
17
+
18
+ type Settings struct {
19
+ DevPort int `json:"devPort"`
20
+ GithubUser *string `json:"githubUser"`
21
+ GithubOrgs []string `json:"githubOrgs"`
22
+ InstallMode string `json:"installMode"`
23
+ CatalogSort string `json:"catalogSort"`
24
+ CatalogNewDays int `json:"catalogNewDays"`
25
+ LastInstallChoices map[string]interface{} `json:"lastInstallChoices"`
26
+ }
27
+
28
+ type WorkspacePaths struct {
29
+ Desktop string `json:"desktop"`
30
+ Config string `json:"config"`
31
+ ConfigWrite string `json:"configWrite"`
32
+ ConfigLegacy bool `json:"configLegacy"`
33
+ PackageJson string `json:"packageJson"`
34
+ IsPlayground bool `json:"isPlayground"`
35
+ PackageName string `json:"packageName,omitempty"`
36
+ PackageDir string `json:"packageDir,omitempty"`
37
+ MetaDir string `json:"metaDir"`
38
+ }
39
+
40
+ type WorkspaceContext struct {
41
+ WorkspaceRoot string `json:"workspaceRoot"`
42
+ Settings Settings `json:"settings"`
43
+ Config Config `json:"config"`
44
+ Deps []string `json:"deps"`
45
+ Paths WorkspacePaths `json:"paths"`
46
+ }
47
+
48
+ type GithubForkInfo struct {
49
+ Owner string `json:"owner"`
50
+ Exists bool `json:"exists"`
51
+ IsFork bool `json:"isFork"`
52
+ }
53
+
54
+ type GithubSources struct {
55
+ Official struct {
56
+ Owner string `json:"owner"`
57
+ HtmlUrl string `json:"htmlUrl"`
58
+ } `json:"official"`
59
+ Fork *GithubForkInfo `json:"fork"`
60
+ }
61
+
62
+ type NpmSourceInfo struct {
63
+ Version string `json:"version"`
64
+ }
65
+
66
+ type SourcesMetadata struct {
67
+ Npm *NpmSourceInfo `json:"npm"`
68
+ Github GithubSources `json:"github"`
69
+ }
70
+
71
+ type CatalogEntry struct {
72
+ ShortName string `json:"shortName"`
73
+ Description string `json:"description"`
74
+ Stars int `json:"stars"`
75
+ HtmlUrl *string `json:"htmlUrl"`
76
+ Org string `json:"org"`
77
+ Kind string `json:"kind"`
78
+ LocalPath *string `json:"localPath"`
79
+ Remote *string `json:"remote"`
80
+ Version *string `json:"version"`
81
+ Name string `json:"name"`
82
+ Trusted bool `json:"trusted"`
83
+ Installed bool `json:"installed"`
84
+ LocalSource bool `json:"localSource"`
85
+ InPackageJson bool `json:"inPackageJson"`
86
+ ActiveTheme bool `json:"activeTheme"`
87
+ SourcesMeta *SourcesMetadata `json:"sourcesMeta"`
88
+ UpdatedAt *string `json:"updatedAt"`
89
+ PushedAt *string `json:"pushedAt"`
90
+ }
91
+
92
+ type CatalogResponse struct {
93
+ Entries []CatalogEntry `json:"entries"`
94
+ CacheAge string `json:"cacheAge"`
95
+ }
96
+
97
+ type WritePayload struct {
98
+ Config *Config `json:"config,omitempty"`
99
+ DepsToAdd map[string]string `json:"depsToAdd,omitempty"`
100
+ DepsToRemove []string `json:"depsToRemove,omitempty"`
101
+ Settings *Settings `json:"settings,omitempty"`
102
+ }
103
+
104
+ // FindWorkspaceRoot searches upwards from the current directory for pnpm-workspace.yaml
105
+ func FindWorkspaceRoot() (string, error) {
106
+ dir, err := os.Getwd()
107
+ if err != nil {
108
+ return "", err
109
+ }
110
+ for {
111
+ if _, err := os.Stat(filepath.Join(dir, "pnpm-workspace.yaml")); err == nil {
112
+ return dir, nil
113
+ }
114
+ parent := filepath.Dir(dir)
115
+ if parent == dir {
116
+ break
117
+ }
118
+ dir = parent
119
+ }
120
+ return "", fmt.Errorf("not inside an OWD workspace")
121
+ }
122
+
123
+ func getBridgePath(root string) string {
124
+ return filepath.Join(root, "packages", "cli", "bin", "bridge.js")
125
+ }
126
+
127
+ // ReadWorkspaceContext runs the node bridge with --read
128
+ func ReadWorkspaceContext(root string) (*WorkspaceContext, error) {
129
+ cmd := exec.Command("node", getBridgePath(root), "--read")
130
+ var stdout, stderr bytes.Buffer
131
+ cmd.Stdout = &stdout
132
+ cmd.Stderr = &stderr
133
+
134
+ if err := cmd.Run(); err != nil {
135
+ return nil, fmt.Errorf("bridge --read failed: %w (stderr: %s)", err, stderr.String())
136
+ }
137
+
138
+ var ctx WorkspaceContext
139
+ if err := json.Unmarshal(stdout.Bytes(), &ctx); err != nil {
140
+ return nil, fmt.Errorf("failed to unmarshal context JSON: %w", err)
141
+ }
142
+
143
+ return &ctx, nil
144
+ }
145
+
146
+ // ReadCatalog runs the node bridge with --catalog
147
+ func ReadCatalog(root string, force bool) (*CatalogResponse, error) {
148
+ args := []string{getBridgePath(root), "--catalog"}
149
+ if force {
150
+ args = append(args, "--force")
151
+ }
152
+ cmd := exec.Command("node", args...)
153
+ var stdout, stderr bytes.Buffer
154
+ cmd.Stdout = &stdout
155
+ cmd.Stderr = &stderr
156
+
157
+ if err := cmd.Run(); err != nil {
158
+ return nil, fmt.Errorf("bridge --catalog failed: %w (stderr: %s)", err, stderr.String())
159
+ }
160
+
161
+ var cat CatalogResponse
162
+ if err := json.Unmarshal(stdout.Bytes(), &cat); err != nil {
163
+ return nil, fmt.Errorf("failed to unmarshal catalog JSON: %w", err)
164
+ }
165
+
166
+ return &cat, nil
167
+ }
168
+
169
+ // WriteChanges feeds the write payload to the node bridge via stdin
170
+ func WriteChanges(root string, payload *WritePayload) error {
171
+ cmd := exec.Command("node", getBridgePath(root), "--write")
172
+ var stdout, stderr bytes.Buffer
173
+ cmd.Stdout = &stdout
174
+ cmd.Stderr = &stderr
175
+
176
+ stdinPipe, err := cmd.StdinPipe()
177
+ if err != nil {
178
+ return err
179
+ }
180
+
181
+ if err := cmd.Start(); err != nil {
182
+ return err
183
+ }
184
+
185
+ payloadBytes, err := json.Marshal(payload)
186
+ if err != nil {
187
+ return err
188
+ }
189
+
190
+ if _, err := stdinPipe.Write(payloadBytes); err != nil {
191
+ return err
192
+ }
193
+ stdinPipe.Close()
194
+
195
+ if err := cmd.Wait(); err != nil {
196
+ return fmt.Errorf("bridge --write failed: %w (stderr: %s)", err, stderr.String())
197
+ }
198
+
199
+ return nil
200
+ }
package/go/desktop-go ADDED
Binary file
package/go/go.mod ADDED
@@ -0,0 +1,26 @@
1
+ module owd-cli
2
+
3
+ go 1.21
4
+
5
+ require (
6
+ github.com/charmbracelet/bubbletea v1.1.1
7
+ github.com/charmbracelet/lipgloss v0.13.0
8
+ )
9
+
10
+ require (
11
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
12
+ github.com/charmbracelet/x/ansi v0.2.3 // indirect
13
+ github.com/charmbracelet/x/term v0.2.0 // indirect
14
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
15
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
16
+ github.com/mattn/go-isatty v0.0.20 // indirect
17
+ github.com/mattn/go-localereader v0.0.1 // indirect
18
+ github.com/mattn/go-runewidth v0.0.15 // indirect
19
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
20
+ github.com/muesli/cancelreader v0.2.2 // indirect
21
+ github.com/muesli/termenv v0.15.2 // indirect
22
+ github.com/rivo/uniseg v0.4.7 // indirect
23
+ golang.org/x/sync v0.8.0 // indirect
24
+ golang.org/x/sys v0.24.0 // indirect
25
+ golang.org/x/text v0.3.8 // indirect
26
+ )
package/go/go.sum ADDED
@@ -0,0 +1,37 @@
1
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
2
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3
+ github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY=
4
+ github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4=
5
+ github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
6
+ github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
7
+ github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
8
+ github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
9
+ github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
10
+ github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
11
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
12
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
13
+ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
14
+ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
15
+ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
16
+ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
17
+ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
18
+ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
19
+ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
20
+ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
21
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
22
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
23
+ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
24
+ github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
25
+ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
26
+ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
27
+ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
28
+ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
29
+ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
30
+ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
31
+ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
32
+ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
33
+ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34
+ golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
35
+ golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
36
+ golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
37
+ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
package/go/main.go ADDED
@@ -0,0 +1,30 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "os"
6
+
7
+ "owd-cli/bridge"
8
+ "owd-cli/tui"
9
+
10
+ tea "github.com/charmbracelet/bubbletea"
11
+ )
12
+
13
+ var p *tea.Program
14
+
15
+ func main() {
16
+ root, err := bridge.FindWorkspaceRoot()
17
+ if err != nil {
18
+ fmt.Printf("Error: %v\n", err)
19
+ os.Exit(1)
20
+ }
21
+
22
+ model := tui.NewModel(root)
23
+ p = tea.NewProgram(model, tea.WithAltScreen())
24
+ tui.Program = p
25
+
26
+ if _, err := p.Run(); err != nil {
27
+ fmt.Printf("Alas, there's been an error: %v", err)
28
+ os.Exit(1)
29
+ }
30
+ }