tabby-tabbyspaces 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/.github/workflows/ci.yml +26 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +81 -0
- package/.github/workflows/release.yml +30 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +33 -0
- package/CONTRIBUTING.md +3 -1
- package/README.md +21 -18
- package/TODO.md +5 -0
- package/dist/build-config.d.ts +3 -3
- package/dist/components/deleteConfirmModal.component.d.ts +7 -0
- package/dist/components/deleteConfirmModal.component.d.ts.map +1 -0
- package/dist/components/paneEditor.component.d.ts +9 -18
- package/dist/components/paneEditor.component.d.ts.map +1 -1
- package/dist/components/splitPreview.component.d.ts +50 -50
- package/dist/components/splitPreview.component.d.ts.map +1 -1
- package/dist/components/workspaceEditor.component.d.ts +61 -54
- package/dist/components/workspaceEditor.component.d.ts.map +1 -1
- package/dist/components/workspaceList.component.d.ts +56 -39
- package/dist/components/workspaceList.component.d.ts.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +1 -1
- package/dist/index.js.map +1 -1
- package/dist/models/workspace.model.d.ts +118 -78
- package/dist/models/workspace.model.d.ts.map +1 -1
- package/dist/package.json +1 -1
- package/dist/providers/config.provider.d.ts +8 -8
- package/dist/providers/settings.provider.d.ts +7 -7
- package/dist/providers/toolbar.provider.d.ts +23 -15
- package/dist/providers/toolbar.provider.d.ts.map +1 -1
- package/dist/services/startupCommand.service.d.ts +27 -19
- package/dist/services/startupCommand.service.d.ts.map +1 -1
- package/dist/services/workspaceBackground.service.d.ts +38 -0
- package/dist/services/workspaceBackground.service.d.ts.map +1 -0
- package/dist/services/workspaceEditor.service.d.ts +46 -32
- package/dist/services/workspaceEditor.service.d.ts.map +1 -1
- package/docs/DESIGN.md +57 -0
- package/docs/SESSION-2026-01-14-S1-DESIGN.md +134 -0
- package/mockups/index.html +162 -0
- package/mockups/s1-tight-sharp.html +522 -0
- package/mockups/shared/base.css +216 -0
- package/mockups/v06-tabbed.html +643 -0
- package/package.json +2 -1
- package/screenshots/editor.png +0 -0
- package/scripts/build-dev.js +2 -1
- package/scripts/build-prod.js +2 -1
- package/src/components/deleteConfirmModal.component.ts +23 -0
- package/src/components/paneEditor.component.pug +27 -43
- package/src/components/paneEditor.component.scss +37 -85
- package/src/components/paneEditor.component.ts +4 -32
- package/src/components/splitPreview.component.pug +0 -9
- package/src/components/splitPreview.component.scss +46 -70
- package/src/components/splitPreview.component.ts +15 -25
- package/src/components/workspaceEditor.component.pug +140 -112
- package/src/components/workspaceEditor.component.scss +270 -202
- package/src/components/workspaceEditor.component.ts +161 -85
- package/src/components/workspaceList.component.pug +31 -51
- package/src/components/workspaceList.component.scss +86 -77
- package/src/components/workspaceList.component.ts +89 -34
- package/src/index.ts +4 -0
- package/src/models/workspace.model.ts +80 -2
- package/src/providers/toolbar.provider.ts +78 -9
- package/src/services/startupCommand.service.ts +30 -32
- package/src/services/workspaceBackground.service.ts +167 -0
- package/src/services/workspaceEditor.service.ts +77 -40
- package/src/styles/_index.scss +3 -0
- package/src/styles/_mixins.scss +180 -0
- package/src/styles/_variables.scss +67 -0
- package/TEST_MCP.md +0 -176
- package/cdp-click.js +0 -22
- package/cdp-test.js +0 -28
- package/screenshots/pane-edit.png +0 -0
- package/test_cdp.py +0 -50
package/TEST_MCP.md
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
# MCP Testiranje TabbySpaces
|
|
2
|
-
|
|
3
|
-
Uputstvo za Claude da testira plugin kroz tabby-mcp.
|
|
4
|
-
|
|
5
|
-
## Pre-requisites
|
|
6
|
-
|
|
7
|
-
1. Build plugin: `npm run build:dev`
|
|
8
|
-
2. Pokreni NOVI Tabby instance sa debug portom:
|
|
9
|
-
```bash
|
|
10
|
-
cmd.exe /c start "" "C:\Program Files (x86)\Tabby\Tabby.exe" --remote-debugging-port=9222
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Test 1: Proveri da nema orphaned profila
|
|
14
|
-
|
|
15
|
-
```javascript
|
|
16
|
-
// Očekivano: Nema split-layout:tabbyspaces_dev: profila u config
|
|
17
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
18
|
-
const profiles = window.require('tabby-core').ConfigService.store.profiles || []
|
|
19
|
-
const orphaned = profiles.filter(p => p.id?.startsWith('split-layout:tabbyspaces'))
|
|
20
|
-
JSON.stringify({ total: profiles.length, orphaned: orphaned.length, ids: orphaned.map(p => p.id) })
|
|
21
|
-
`)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
**Očekivan rezultat:** `orphaned: 0`
|
|
25
|
-
|
|
26
|
-
## Test 2: Otvori Settings i proveri plugin
|
|
27
|
-
|
|
28
|
-
```javascript
|
|
29
|
-
// Klikni na Settings
|
|
30
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
31
|
-
document.querySelector('[title="Settings"]')?.click()
|
|
32
|
-
'Settings opened'
|
|
33
|
-
`)
|
|
34
|
-
|
|
35
|
-
// Sačekaj 500ms, pa klikni na TabbySpaces DEV tab
|
|
36
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
37
|
-
const tabs = Array.from(document.querySelectorAll('.nav-link'))
|
|
38
|
-
const devTab = tabs.find(t => t.textContent.includes('TabbySpaces DEV'))
|
|
39
|
-
devTab?.click()
|
|
40
|
-
devTab ? 'TabbySpaces DEV tab clicked' : 'Tab not found'
|
|
41
|
-
`)
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Test 3: Kreiraj test workspace
|
|
45
|
-
|
|
46
|
-
```javascript
|
|
47
|
-
// Klikni New Workspace
|
|
48
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
49
|
-
const btn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('New Workspace'))
|
|
50
|
-
btn?.click()
|
|
51
|
-
btn ? 'New Workspace clicked' : 'Button not found'
|
|
52
|
-
`)
|
|
53
|
-
|
|
54
|
-
// Unesi ime
|
|
55
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
56
|
-
const input = document.querySelector('.name-input')
|
|
57
|
-
if (input) {
|
|
58
|
-
input.value = 'MCP Test Workspace'
|
|
59
|
-
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
60
|
-
'Name set'
|
|
61
|
-
} else 'Input not found'
|
|
62
|
-
`)
|
|
63
|
-
|
|
64
|
-
// Sačuvaj
|
|
65
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
66
|
-
const saveBtn = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Save'))
|
|
67
|
-
saveBtn?.click()
|
|
68
|
-
saveBtn ? 'Saved' : 'Save button not found'
|
|
69
|
-
`)
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Test 4: Proveri da NIJE kreiran profil u config.store.profiles
|
|
73
|
-
|
|
74
|
-
```javascript
|
|
75
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
76
|
-
const profiles = window.require('tabby-core').ConfigService.store.profiles || []
|
|
77
|
-
const wsProfiles = profiles.filter(p => p.id?.includes('mcp-test-workspace'))
|
|
78
|
-
JSON.stringify({ found: wsProfiles.length, message: wsProfiles.length === 0 ? 'PASS - No profile created' : 'FAIL - Profile was created' })
|
|
79
|
-
`)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
**Očekivan rezultat:** `found: 0, message: "PASS - No profile created"`
|
|
83
|
-
|
|
84
|
-
## Test 5: Testiraj CWD injection (Shell Detection)
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
// Testiraj shell detection funkciju
|
|
88
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
89
|
-
// Simuliraj shell detection
|
|
90
|
-
function detectShellType(command) {
|
|
91
|
-
const cmd = command.toLowerCase()
|
|
92
|
-
if (cmd.includes('nu.exe') || cmd.includes('nushell') || cmd.endsWith('/nu')) return 'nushell'
|
|
93
|
-
if (cmd.includes('powershell') || cmd.includes('pwsh')) return 'powershell'
|
|
94
|
-
if (cmd.includes('cmd.exe') || cmd.endsWith('\\\\cmd')) return 'cmd'
|
|
95
|
-
if (cmd.includes('bash') || cmd.includes('zsh') || cmd.includes('fish') || cmd.includes('/sh')) return 'posix'
|
|
96
|
-
return 'unknown'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const tests = [
|
|
100
|
-
{ cmd: 'C:\\\\Programs\\\\nu\\\\bin\\\\nu.exe', expected: 'nushell' },
|
|
101
|
-
{ cmd: 'C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe', expected: 'powershell' },
|
|
102
|
-
{ cmd: 'pwsh.exe', expected: 'powershell' },
|
|
103
|
-
{ cmd: 'C:\\\\Windows\\\\System32\\\\cmd.exe', expected: 'cmd' },
|
|
104
|
-
{ cmd: '/usr/bin/bash', expected: 'posix' },
|
|
105
|
-
{ cmd: '/bin/zsh', expected: 'posix' },
|
|
106
|
-
]
|
|
107
|
-
|
|
108
|
-
const results = tests.map(t => ({
|
|
109
|
-
cmd: t.cmd,
|
|
110
|
-
expected: t.expected,
|
|
111
|
-
actual: detectShellType(t.cmd),
|
|
112
|
-
pass: detectShellType(t.cmd) === t.expected
|
|
113
|
-
}))
|
|
114
|
-
|
|
115
|
-
JSON.stringify({ passed: results.filter(r => r.pass).length, total: results.length, results }, null, 2)
|
|
116
|
-
`)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Očekivan rezultat:** `passed: 6, total: 6`
|
|
120
|
-
|
|
121
|
-
## Test 6: Otvori workspace iz toolbar-a
|
|
122
|
-
|
|
123
|
-
```javascript
|
|
124
|
-
// Klikni na TabbySpaces toolbar button (4 squares icon)
|
|
125
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
126
|
-
const toolbarBtns = document.querySelectorAll('toolbar-button')
|
|
127
|
-
const wsBtn = Array.from(toolbarBtns).find(b => b.querySelector('svg rect'))
|
|
128
|
-
wsBtn?.click()
|
|
129
|
-
wsBtn ? 'Toolbar button clicked' : 'Button not found'
|
|
130
|
-
`)
|
|
131
|
-
|
|
132
|
-
// Selektuj workspace iz liste
|
|
133
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
134
|
-
const options = document.querySelectorAll('.selector-option')
|
|
135
|
-
const testWs = Array.from(options).find(o => o.textContent.includes('MCP Test'))
|
|
136
|
-
testWs?.click()
|
|
137
|
-
testWs ? 'Workspace selected' : 'Workspace not found in selector'
|
|
138
|
-
`)
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Test 7: Proveri otvorene tabove
|
|
142
|
-
|
|
143
|
-
```javascript
|
|
144
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
145
|
-
const tabs = document.querySelectorAll('.tab')
|
|
146
|
-
const tabInfo = Array.from(tabs).map(t => ({
|
|
147
|
-
title: t.querySelector('.tab-title')?.textContent || 'unknown',
|
|
148
|
-
active: t.classList.contains('active')
|
|
149
|
-
}))
|
|
150
|
-
JSON.stringify(tabInfo)
|
|
151
|
-
`)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Cleanup
|
|
155
|
-
|
|
156
|
-
```javascript
|
|
157
|
-
// Zatvori test tab
|
|
158
|
-
mcp__tabby__execute_js(target: -1, code: `
|
|
159
|
-
const closeBtn = document.querySelector('.tab.active .btn-close')
|
|
160
|
-
closeBtn?.click()
|
|
161
|
-
'Tab closed'
|
|
162
|
-
`)
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## Quick Full Test Sequence
|
|
166
|
-
|
|
167
|
-
```
|
|
168
|
-
1. mcp__tabby__list_targets (uzmi poslednji target)
|
|
169
|
-
2. Test 1: Proveri orphaned profile
|
|
170
|
-
3. Test 5: Shell detection
|
|
171
|
-
4. Test 2: Otvori settings
|
|
172
|
-
5. Test 3: Kreiraj workspace
|
|
173
|
-
6. Test 4: Proveri da nema profila
|
|
174
|
-
7. Test 6: Otvori workspace
|
|
175
|
-
8. Test 7: Proveri tabove
|
|
176
|
-
```
|
package/cdp-click.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
const CDP = require('chrome-remote-interface');
|
|
2
|
-
|
|
3
|
-
(async () => {
|
|
4
|
-
const client = await CDP({port: 9222});
|
|
5
|
-
const {Runtime, DOM, Input} = client;
|
|
6
|
-
|
|
7
|
-
// Click on "TabbySpaces DEV" link
|
|
8
|
-
const result = await Runtime.evaluate({
|
|
9
|
-
expression: `
|
|
10
|
-
const link = Array.from(document.querySelectorAll('a')).find(a => a.innerText.includes('TabbySpaces DEV'));
|
|
11
|
-
if (link) {
|
|
12
|
-
link.click();
|
|
13
|
-
'Clicked TabbySpaces DEV';
|
|
14
|
-
} else {
|
|
15
|
-
'TabbySpaces DEV link not found';
|
|
16
|
-
}
|
|
17
|
-
`
|
|
18
|
-
});
|
|
19
|
-
console.log('Result:', result.result.value);
|
|
20
|
-
|
|
21
|
-
await client.close();
|
|
22
|
-
})().catch(e => console.error('Error:', e.message));
|
package/cdp-test.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const CDP = require('chrome-remote-interface');
|
|
2
|
-
|
|
3
|
-
(async () => {
|
|
4
|
-
const client = await CDP({port: 9222});
|
|
5
|
-
const {Runtime, DOM} = client;
|
|
6
|
-
|
|
7
|
-
// Get page title
|
|
8
|
-
const title = await Runtime.evaluate({expression: 'document.title'});
|
|
9
|
-
console.log('Title:', title.result.value);
|
|
10
|
-
|
|
11
|
-
// Get all clickable elements
|
|
12
|
-
const clickables = await Runtime.evaluate({
|
|
13
|
-
expression: `
|
|
14
|
-
Array.from(document.querySelectorAll('button, [role=button], .btn, a, [ng-click]'))
|
|
15
|
-
.map(el => ({
|
|
16
|
-
tag: el.tagName,
|
|
17
|
-
text: (el.innerText || el.textContent || '').trim().substring(0, 50),
|
|
18
|
-
class: (el.className || '').substring(0, 50)
|
|
19
|
-
}))
|
|
20
|
-
.slice(0, 30)
|
|
21
|
-
`,
|
|
22
|
-
returnByValue: true
|
|
23
|
-
});
|
|
24
|
-
console.log('Clickable elements:');
|
|
25
|
-
console.log(JSON.stringify(clickables.result.value, null, 2));
|
|
26
|
-
|
|
27
|
-
await client.close();
|
|
28
|
-
})().catch(e => console.error('Error:', e.message));
|
|
Binary file
|
package/test_cdp.py
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"""Test CDP connection to Tabby - click on TabbySpaces settings"""
|
|
2
|
-
import pychrome
|
|
3
|
-
import time
|
|
4
|
-
|
|
5
|
-
# Connect to Tabby
|
|
6
|
-
browser = pychrome.Browser(url="http://localhost:9222")
|
|
7
|
-
tabs = browser.list_tab()
|
|
8
|
-
print(f"Found {len(tabs)} tabs")
|
|
9
|
-
|
|
10
|
-
# Get the first tab (main Tabby window)
|
|
11
|
-
tab = tabs[0]
|
|
12
|
-
print(f"Using first tab")
|
|
13
|
-
tab.start()
|
|
14
|
-
|
|
15
|
-
# Click on TabbySpaces link
|
|
16
|
-
print("\nClicking on 'TabbySpaces' link...")
|
|
17
|
-
result = tab.Runtime.evaluate(expression="""
|
|
18
|
-
const link = Array.from(document.querySelectorAll('a.nav-link'))
|
|
19
|
-
.find(a => a.innerText.trim() === 'TabbySpaces');
|
|
20
|
-
if (link) {
|
|
21
|
-
link.click();
|
|
22
|
-
'Clicked TabbySpaces!';
|
|
23
|
-
} else {
|
|
24
|
-
'TabbySpaces link not found';
|
|
25
|
-
}
|
|
26
|
-
""")
|
|
27
|
-
print(f"Result: {result.get('result', {}).get('value')}")
|
|
28
|
-
|
|
29
|
-
time.sleep(0.3)
|
|
30
|
-
|
|
31
|
-
# Verify we're on TabbySpaces page - look for workspace elements
|
|
32
|
-
result = tab.Runtime.evaluate(expression="""
|
|
33
|
-
// Check for TabbySpaces specific content
|
|
34
|
-
const content = document.body.innerText;
|
|
35
|
-
const hasWorkspaces = content.includes('Workspace') || content.includes('workspace');
|
|
36
|
-
const activeLink = document.querySelector('a.nav-link.active');
|
|
37
|
-
({
|
|
38
|
-
activePage: activeLink ? activeLink.innerText.trim() : 'unknown',
|
|
39
|
-
hasWorkspaceContent: hasWorkspaces,
|
|
40
|
-
pageSnippet: content.substring(0, 500)
|
|
41
|
-
});
|
|
42
|
-
""", returnByValue=True)
|
|
43
|
-
|
|
44
|
-
data = result.get('result', {}).get('value', {})
|
|
45
|
-
print(f"\nActive page: {data.get('activePage')}")
|
|
46
|
-
print(f"Has workspace content: {data.get('hasWorkspaceContent')}")
|
|
47
|
-
print(f"\nPage snippet:\n{data.get('pageSnippet', '')[:300]}...")
|
|
48
|
-
|
|
49
|
-
tab.stop()
|
|
50
|
-
print("\nDone!")
|