@bytespell/shella 0.1.0 → 0.1.3
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/README.md +32 -9
- package/bin/cli.js +122 -40
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +27 -0
- package/dist/server/routes/init.d.ts +15 -0
- package/dist/server/routes/init.js +25 -0
- package/dist/web/assets/{_baseUniq-Dj1Rdun9.js → _baseUniq-BXqY9Mam.js} +1 -1
- package/dist/web/assets/{arc-BcAe_L9C.js → arc-Bn6tUpO_.js} +1 -1
- package/dist/web/assets/{architectureDiagram-VXUJARFQ-CUydP-HB.js → architectureDiagram-VXUJARFQ-C7FAApUY.js} +1 -1
- package/dist/web/assets/{blockDiagram-VD42YOAC-D7ENTm-e.js → blockDiagram-VD42YOAC-C2fdaEWa.js} +1 -1
- package/dist/web/assets/{c4Diagram-YG6GDRKO-DE6z4ano.js → c4Diagram-YG6GDRKO-FEVzhARQ.js} +1 -1
- package/dist/web/assets/channel-CxjnQtV7.js +1 -0
- package/dist/web/assets/{chunk-4BX2VUAB-f1AgJ5-4.js → chunk-4BX2VUAB-DLekcSAU.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-CRc_DE4C.js → chunk-55IACEB6-8hFRjyTP.js} +1 -1
- package/dist/web/assets/{chunk-B4BG7PRW-BeFQ_8yC.js → chunk-B4BG7PRW-DULC9-MQ.js} +1 -1
- package/dist/web/assets/{chunk-DI55MBZ5-_SEo9TtQ.js → chunk-DI55MBZ5-DuOE5RH1.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-6M3K7zkj.js → chunk-FMBD7UC4-DaDNiCk7.js} +1 -1
- package/dist/web/assets/{chunk-QN33PNHL-BGGg7fLk.js → chunk-QN33PNHL-CKshfIHj.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-Q6HkNG6r.js → chunk-QZHKN3VN-D2Qy0tdi.js} +1 -1
- package/dist/web/assets/{chunk-TZMSLE5B-D3UMAT7-.js → chunk-TZMSLE5B-SPxkj-lp.js} +1 -1
- package/dist/web/assets/classDiagram-2ON5EDUG-CVG91-fs.js +1 -0
- package/dist/web/assets/classDiagram-v2-WZHVMYZB-CVG91-fs.js +1 -0
- package/dist/web/assets/clone-C7jxvixc.js +1 -0
- package/dist/web/assets/{code-block-QI2IAROF-BzpuLcBt.js → code-block-QI2IAROF-BZdAQmZ2.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-BIcssrhL.js → cose-bilkent-S5V4N54A-DbasixUk.js} +1 -1
- package/dist/web/assets/{dagre-6UL2VRFP-YaA_gyjx.js → dagre-6UL2VRFP-CStyjTc9.js} +1 -1
- package/dist/web/assets/{diagram-PSM6KHXK-r6WVaeIu.js → diagram-PSM6KHXK-Crk93U8d.js} +1 -1
- package/dist/web/assets/{diagram-QEK2KX5R-DtTKn621.js → diagram-QEK2KX5R-DiW6RNbg.js} +1 -1
- package/dist/web/assets/{diagram-S2PKOQOG-BINNPg42.js → diagram-S2PKOQOG-CKksz_qL.js} +1 -1
- package/dist/web/assets/{erDiagram-Q2GNP2WA-DXIwYH9k.js → erDiagram-Q2GNP2WA-CisACqqq.js} +1 -1
- package/dist/web/assets/{flowDiagram-NV44I4VS-D8Bad7wU.js → flowDiagram-NV44I4VS-BBp_5zAe.js} +1 -1
- package/dist/web/assets/{ganttDiagram-JELNMOA3-DSiZGBoG.js → ganttDiagram-JELNMOA3-BKZ30gLA.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-NY62KEGX-CCxrAUDj.js → gitGraphDiagram-NY62KEGX-ClizxUXq.js} +1 -1
- package/dist/web/assets/{graph-CcI3NtJu.js → graph-DqhaNOTU.js} +1 -1
- package/dist/web/assets/{index-BCTWtQQB.js → index-Dnmavb3d.js} +94 -94
- package/dist/web/assets/{infoDiagram-WHAUD3N6-C3OGZjzs.js → infoDiagram-WHAUD3N6-BQwNR0md.js} +1 -1
- package/dist/web/assets/{journeyDiagram-XKPGCS4Q-aT-Wsw7y.js → journeyDiagram-XKPGCS4Q-YOqPPID4.js} +1 -1
- package/dist/web/assets/{kanban-definition-3W4ZIXB7-DpUj9tx6.js → kanban-definition-3W4ZIXB7-Dtu8bvBx.js} +1 -1
- package/dist/web/assets/{layout-Ujef10t5.js → layout-Cc1ESzTe.js} +1 -1
- package/dist/web/assets/{linear-CLfbwX-c.js → linear-BwI2ANFG.js} +1 -1
- package/dist/web/assets/{mermaid.core-BAK_ixpL.js → mermaid.core-npIGP8NS.js} +5 -5
- package/dist/web/assets/{min-D8VL4G-w.js → min--MKscDc6.js} +1 -1
- package/dist/web/assets/{mindmap-definition-VGOIOE7T-ChCIxiAQ.js → mindmap-definition-VGOIOE7T-Cr39Vhym.js} +1 -1
- package/dist/web/assets/{pieDiagram-ADFJNKIX-jlQ1USe2.js → pieDiagram-ADFJNKIX-Cv8ke00t.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-AYHSOK5B-Dj2wmV1N.js → quadrantDiagram-AYHSOK5B-BPhHaTg8.js} +1 -1
- package/dist/web/assets/{requirementDiagram-UZGBJVZJ-Umq3-C8j.js → requirementDiagram-UZGBJVZJ-Cc42SoK0.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-TZEHDZUN-Ce6gdeOT.js → sankeyDiagram-TZEHDZUN-CtgBuq8T.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-WL72ISMW-DJGrGFRW.js → sequenceDiagram-WL72ISMW-B9lNGN6V.js} +1 -1
- package/dist/web/assets/{stateDiagram-FKZM4ZOC-D-zz3TRT.js → stateDiagram-FKZM4ZOC-C3dRTOMb.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-4FDKWEC3-oHTO1yj_.js +1 -0
- package/dist/web/assets/{timeline-definition-IT6M3QCI-C8M7N84Y.js → timeline-definition-IT6M3QCI-CXhSuTlt.js} +1 -1
- package/dist/web/assets/{treemap-KMMF4GRG-B_8-FlJu.js → treemap-KMMF4GRG-Csy25Uov.js} +1 -1
- package/dist/web/assets/{xychartDiagram-PRI3JC2R-DDPGTO3C.js → xychartDiagram-PRI3JC2R-CxEERqse.js} +1 -1
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +2 -2
- package/package.json +7 -2
- package/dist/web/assets/channel-C1Y873om.js +0 -1
- package/dist/web/assets/classDiagram-2ON5EDUG-DLBhGros.js +0 -1
- package/dist/web/assets/classDiagram-v2-WZHVMYZB-DLBhGros.js +0 -1
- package/dist/web/assets/clone-DVBZ10mH.js +0 -1
- package/dist/web/assets/stateDiagram-v2-4FDKWEC3-CARvDj2s.js +0 -1
package/README.md
CHANGED
|
@@ -6,26 +6,45 @@ Run multiple AI agents in parallel, persist sessions across devices, and manage
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
###
|
|
9
|
+
### Quick Start (npx)
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
+
cd ~/myproject
|
|
12
13
|
npx @bytespell/shella
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
Opens at `http://localhost:3067`. Access from your phone using the LAN IP shown.
|
|
16
17
|
|
|
17
|
-
###
|
|
18
|
+
### Permanent Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @bytespell/shella
|
|
22
|
+
shella
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Now you can run `shella` from any directory.
|
|
26
|
+
|
|
27
|
+
### Multiple Projects
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
shella --projects-dir ~/code
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Registers all subdirectories of `~/code` as available projects.
|
|
34
|
+
|
|
35
|
+
### Docker
|
|
18
36
|
|
|
19
37
|
```yaml
|
|
20
38
|
# docker-compose.yml
|
|
21
39
|
services:
|
|
22
40
|
shella:
|
|
23
|
-
image: ghcr.io/bytespell/shella
|
|
41
|
+
image: ghcr.io/bytespell-oss/shella
|
|
24
42
|
ports:
|
|
25
43
|
- '3067:3067'
|
|
26
44
|
volumes:
|
|
27
|
-
-
|
|
45
|
+
- ~/code:/project
|
|
28
46
|
- shella-data:/root/.config/shella
|
|
47
|
+
command: ['--projects-dir', '/project']
|
|
29
48
|
restart: unless-stopped
|
|
30
49
|
|
|
31
50
|
volumes:
|
|
@@ -47,11 +66,12 @@ docker compose up -d
|
|
|
47
66
|
## CLI Options
|
|
48
67
|
|
|
49
68
|
```bash
|
|
50
|
-
shella
|
|
51
|
-
shella --
|
|
52
|
-
shella --
|
|
53
|
-
shella --
|
|
54
|
-
shella --
|
|
69
|
+
shella # Start (registers current directory)
|
|
70
|
+
shella --projects-dir ~/code # Register all subdirs of ~/code
|
|
71
|
+
shella --port 3000 # Custom web port
|
|
72
|
+
shella --opencode-port 5000 # Custom OpenCode port
|
|
73
|
+
shella --no-open # Don't open browser
|
|
74
|
+
shella --help # Show help
|
|
55
75
|
```
|
|
56
76
|
|
|
57
77
|
## Development
|
|
@@ -60,6 +80,9 @@ shella --help # Show help
|
|
|
60
80
|
# Install dependencies
|
|
61
81
|
npm install
|
|
62
82
|
|
|
83
|
+
# Create .env.local with your projects directory
|
|
84
|
+
echo "SHELLA_PROJECTS_DIR=/path/to/your/projects" > .env.local
|
|
85
|
+
|
|
63
86
|
# Start dev servers (Vite + Express + OpenCode)
|
|
64
87
|
npm run start:dev
|
|
65
88
|
|
package/bin/cli.js
CHANGED
|
@@ -4,10 +4,17 @@ import { createOpencodeServer } from '@opencode-ai/sdk';
|
|
|
4
4
|
import { networkInterfaces } from 'os';
|
|
5
5
|
import { spawn } from 'child_process';
|
|
6
6
|
import { createConnection } from 'net';
|
|
7
|
+
import { existsSync, readdirSync } from 'fs';
|
|
7
8
|
import path from 'path';
|
|
8
9
|
import { fileURLToPath } from 'url';
|
|
9
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
const VERSION = '0.1.
|
|
11
|
+
const VERSION = '0.1.3';
|
|
12
|
+
/**
|
|
13
|
+
* Check if running inside Docker container
|
|
14
|
+
*/
|
|
15
|
+
function isDocker() {
|
|
16
|
+
return existsSync('/.dockerenv');
|
|
17
|
+
}
|
|
11
18
|
/**
|
|
12
19
|
* Check if a port is available
|
|
13
20
|
*/
|
|
@@ -48,68 +55,145 @@ function getLanIp() {
|
|
|
48
55
|
/**
|
|
49
56
|
* Print a nice boxed message with the access URL
|
|
50
57
|
*/
|
|
51
|
-
function printAccessBox(lanIp, port) {
|
|
58
|
+
function printAccessBox(lanIp, port, projectName) {
|
|
52
59
|
const url = `http://${lanIp}:${port}`;
|
|
53
60
|
const urlLine = ` ${url}`;
|
|
54
61
|
const width = Math.max(44, urlLine.length + 4);
|
|
55
62
|
const border = '-'.repeat(width);
|
|
56
63
|
const pad = (s) => s + ' '.repeat(width - s.length);
|
|
57
|
-
console.log(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
console.log('');
|
|
65
|
+
console.log(`+${border}+`);
|
|
66
|
+
console.log(`|${pad('')}|`);
|
|
67
|
+
if (projectName) {
|
|
68
|
+
console.log(`|${pad(` Shella v${VERSION} - ${projectName}`)}|`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.log(`|${pad(` Shella v${VERSION}`)}|`);
|
|
72
|
+
}
|
|
73
|
+
console.log(`|${pad('')}|`);
|
|
74
|
+
console.log(`|${pad(' Access from any device:')}|`);
|
|
75
|
+
console.log(`|${pad(urlLine)}|`);
|
|
76
|
+
console.log(`|${pad('')}|`);
|
|
77
|
+
console.log(`+${border}+`);
|
|
78
|
+
console.log('');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Register projects with OpenCode by creating a session in each directory.
|
|
82
|
+
* This triggers OpenCode to discover and register the project.
|
|
83
|
+
*/
|
|
84
|
+
async function registerProjects(opencodePort, projectsDir) {
|
|
85
|
+
const baseUrl = `http://localhost:${opencodePort}`;
|
|
86
|
+
const registered = [];
|
|
87
|
+
if (projectsDir) {
|
|
88
|
+
// Resolve to absolute path
|
|
89
|
+
const absDir = path.resolve(projectsDir);
|
|
90
|
+
if (!existsSync(absDir)) {
|
|
91
|
+
console.error(`Error: Projects directory not found: ${absDir}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// Register each subdirectory (OpenCode will determine if it's a git repo)
|
|
95
|
+
const entries = readdirSync(absDir, { withFileTypes: true });
|
|
96
|
+
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith('.'));
|
|
97
|
+
if (dirs.length === 0) {
|
|
98
|
+
console.error(`Error: No subdirectories found in ${absDir}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
for (const entry of dirs) {
|
|
102
|
+
const dir = path.join(absDir, entry.name);
|
|
103
|
+
try {
|
|
104
|
+
// Create a session to trigger project registration
|
|
105
|
+
await fetch(`${baseUrl}/session`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
'X-OpenCode-Directory': dir,
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({}),
|
|
112
|
+
});
|
|
113
|
+
registered.push(entry.name);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Silently skip failed registrations
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Register cwd
|
|
122
|
+
const dir = process.cwd();
|
|
123
|
+
try {
|
|
124
|
+
await fetch(`${baseUrl}/session`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': 'application/json',
|
|
128
|
+
'X-OpenCode-Directory': dir,
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify({}),
|
|
131
|
+
});
|
|
132
|
+
registered.push(path.basename(dir));
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Silently skip
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { count: registered.length, names: registered };
|
|
66
139
|
}
|
|
67
140
|
let opencodeServer = null;
|
|
68
141
|
let expressProcess = null;
|
|
69
142
|
async function startCommand(options) {
|
|
70
143
|
const port = parseInt(options.port);
|
|
71
144
|
const opencodePort = parseInt(options.opencodePort);
|
|
72
|
-
|
|
145
|
+
const cwd = process.cwd();
|
|
146
|
+
// Docker requires --projects-dir
|
|
147
|
+
if (isDocker() && !options.projectsDir) {
|
|
148
|
+
console.error('Error: --projects-dir is required when running in Docker.\n');
|
|
149
|
+
console.error('Example:');
|
|
150
|
+
console.error(' docker run -v ~/code:/project shella --projects-dir /project\n');
|
|
151
|
+
console.error('Or in docker-compose.yml:');
|
|
152
|
+
console.error(' command: ["--projects-dir", "/project"]');
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
// Determine the projects directory to pass to the server
|
|
156
|
+
const projectsDir = options.projectsDir ? path.resolve(options.projectsDir) : cwd;
|
|
73
157
|
// Check if ports are available
|
|
74
158
|
const webPortAvailable = await isPortAvailable(port);
|
|
75
159
|
const ocPortAvailable = await isPortAvailable(opencodePort);
|
|
76
160
|
if (!webPortAvailable) {
|
|
77
161
|
console.error(`Error: Port ${port} is already in use.`);
|
|
78
|
-
console.error(`\nTry
|
|
79
|
-
console.error(` - Stop the process using port ${port}`);
|
|
80
|
-
console.error(` - Use a different port: shella --port 3070`);
|
|
162
|
+
console.error(`\nTry: shella --port 3070`);
|
|
81
163
|
process.exit(1);
|
|
82
164
|
}
|
|
83
165
|
if (!ocPortAvailable) {
|
|
84
|
-
console.error(`Error: Port ${opencodePort} is already in use (OpenCode
|
|
85
|
-
console.error(`\
|
|
86
|
-
console.error(`\nTry one of these:`);
|
|
87
|
-
console.error(` - Kill the existing OpenCode: pkill -f "opencode serve"`);
|
|
88
|
-
console.error(` - Use a different port: shella --opencode-port 4097`);
|
|
166
|
+
console.error(`Error: Port ${opencodePort} is already in use (OpenCode).`);
|
|
167
|
+
console.error(`\nTry: pkill -f "opencode serve" or shella --opencode-port 4097`);
|
|
89
168
|
process.exit(1);
|
|
90
169
|
}
|
|
170
|
+
// Ensure opencode binary from node_modules/.bin is in PATH
|
|
171
|
+
// Required for: npm install -g @bytespell/shella
|
|
172
|
+
// No-op for: npx (already in PATH)
|
|
173
|
+
// Helps with: Direct execution (node bin/cli.js)
|
|
174
|
+
const binPath = path.join(__dirname, '..', 'node_modules', '.bin');
|
|
175
|
+
const pathSep = process.platform === 'win32' ? ';' : ':';
|
|
176
|
+
process.env.PATH = process.env.PATH ? `${binPath}${pathSep}${process.env.PATH}` : binPath;
|
|
177
|
+
// Show minimal startup message
|
|
178
|
+
console.log('Starting Shella...');
|
|
91
179
|
// Start OpenCode server using the bundled binary
|
|
92
|
-
console.log('Starting OpenCode...');
|
|
93
180
|
try {
|
|
94
181
|
opencodeServer = await createOpencodeServer({
|
|
95
182
|
port: opencodePort,
|
|
96
183
|
timeout: 30000,
|
|
97
184
|
});
|
|
98
|
-
console.log(` OpenCode ready (port ${opencodePort})`);
|
|
99
185
|
}
|
|
100
186
|
catch (err) {
|
|
101
187
|
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
-
console.error(
|
|
103
|
-
if (message.includes('port')) {
|
|
104
|
-
console.error(`\nThe port ${opencodePort} may be in use. Try:`);
|
|
105
|
-
console.error(` shella --opencode-port 4097`);
|
|
106
|
-
}
|
|
188
|
+
console.error(`Failed to start OpenCode: ${message}`);
|
|
107
189
|
process.exit(1);
|
|
108
190
|
}
|
|
109
|
-
//
|
|
110
|
-
|
|
191
|
+
// Register projects with OpenCode
|
|
192
|
+
const { names } = await registerProjects(opencodePort, options.projectsDir);
|
|
193
|
+
const projectName = names.length === 1 ? names[0] : names.length > 1 ? `${names.length} projects` : undefined;
|
|
194
|
+
// Start Express server in production mode, passing projectsDir
|
|
111
195
|
const serverPath = path.join(__dirname, '..', 'dist', 'server', 'index.js');
|
|
112
|
-
expressProcess = spawn('node', [serverPath], {
|
|
196
|
+
expressProcess = spawn('node', [serverPath, '--projects-dir', projectsDir], {
|
|
113
197
|
env: {
|
|
114
198
|
...process.env,
|
|
115
199
|
NODE_ENV: 'production',
|
|
@@ -120,7 +204,7 @@ async function startCommand(options) {
|
|
|
120
204
|
// Wait for server to be ready
|
|
121
205
|
await new Promise((resolve, reject) => {
|
|
122
206
|
const timeout = setTimeout(() => {
|
|
123
|
-
reject(new Error('Server startup timeout
|
|
207
|
+
reject(new Error('Server startup timeout'));
|
|
124
208
|
}, 10000);
|
|
125
209
|
expressProcess.stdout?.on('data', (data) => {
|
|
126
210
|
const output = data.toString();
|
|
@@ -128,11 +212,10 @@ async function startCommand(options) {
|
|
|
128
212
|
clearTimeout(timeout);
|
|
129
213
|
resolve();
|
|
130
214
|
}
|
|
131
|
-
//
|
|
132
|
-
process.stdout.write(output.replace(/\[shella-server\] /g, ' '));
|
|
215
|
+
// Suppress all server output
|
|
133
216
|
});
|
|
134
|
-
expressProcess.stderr?.on('data', (
|
|
135
|
-
|
|
217
|
+
expressProcess.stderr?.on('data', () => {
|
|
218
|
+
// Suppress stderr too
|
|
136
219
|
});
|
|
137
220
|
expressProcess.on('error', (err) => {
|
|
138
221
|
clearTimeout(timeout);
|
|
@@ -145,11 +228,10 @@ async function startCommand(options) {
|
|
|
145
228
|
}
|
|
146
229
|
});
|
|
147
230
|
});
|
|
148
|
-
console.log(` Shella ready (port ${port})`);
|
|
149
231
|
// Print access box
|
|
150
232
|
const lanIp = getLanIp();
|
|
151
|
-
printAccessBox(lanIp, port);
|
|
152
|
-
console.log('Press Ctrl+C to stop
|
|
233
|
+
printAccessBox(lanIp, port, projectName);
|
|
234
|
+
console.log('Press Ctrl+C to stop');
|
|
153
235
|
// Open browser if requested
|
|
154
236
|
if (options.open) {
|
|
155
237
|
const url = `http://localhost:${port}`;
|
|
@@ -161,7 +243,7 @@ async function startCommand(options) {
|
|
|
161
243
|
* Graceful shutdown handler
|
|
162
244
|
*/
|
|
163
245
|
function shutdown() {
|
|
164
|
-
console.log('\
|
|
246
|
+
console.log('\nStopping...');
|
|
165
247
|
if (expressProcess) {
|
|
166
248
|
expressProcess.kill('SIGTERM');
|
|
167
249
|
expressProcess = null;
|
|
@@ -170,7 +252,6 @@ function shutdown() {
|
|
|
170
252
|
opencodeServer.close();
|
|
171
253
|
opencodeServer = null;
|
|
172
254
|
}
|
|
173
|
-
console.log('Goodbye!');
|
|
174
255
|
process.exit(0);
|
|
175
256
|
}
|
|
176
257
|
// Handle shutdown signals
|
|
@@ -186,6 +267,7 @@ program
|
|
|
186
267
|
.description('Start Shella')
|
|
187
268
|
.option('-p, --port <port>', 'Web server port', '3067')
|
|
188
269
|
.option('--opencode-port <port>', 'OpenCode server port', '4096')
|
|
270
|
+
.option('--projects-dir <path>', 'Directory containing projects (each subdirectory becomes a project)')
|
|
189
271
|
.option('--no-open', "Don't open browser automatically")
|
|
190
272
|
.action(startCommand);
|
|
191
273
|
program.parse();
|
package/dist/server/index.d.ts
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -3,15 +3,21 @@ import fs from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { config as dotenvConfig } from 'dotenv';
|
|
6
7
|
import { corsMiddleware } from './middleware/cors.js';
|
|
7
8
|
import windowsRoutes from './routes/windows.js';
|
|
8
9
|
import modelStateRoutes from './routes/model-state.js';
|
|
9
10
|
import logsRoutes from './routes/logs.js';
|
|
10
11
|
import proxyRoutes from './routes/proxy.js';
|
|
12
|
+
import initRoutes from './routes/init.js';
|
|
11
13
|
import { getDatabase } from './services/database.js';
|
|
12
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
15
|
// Runtime mode detection
|
|
14
16
|
const isProd = process.env.NODE_ENV === 'production';
|
|
17
|
+
// Load .env.local in dev mode (for SHELLA_PROJECTS_DIR)
|
|
18
|
+
if (!isProd) {
|
|
19
|
+
dotenvConfig({ path: path.resolve(process.cwd(), '.env.local') });
|
|
20
|
+
}
|
|
15
21
|
// Port: 3067 in prod, 3068 in dev (Vite uses 3067 in dev)
|
|
16
22
|
const PORT = process.env.PORT || (isProd ? 3067 : 3068);
|
|
17
23
|
// Config directory: ~/.config/shella/
|
|
@@ -20,6 +26,26 @@ const CONFIG_DIR = path.join(os.homedir(), '.config', 'shella');
|
|
|
20
26
|
const LOG_FILE = isProd
|
|
21
27
|
? path.join(CONFIG_DIR, 'shella.log')
|
|
22
28
|
: path.resolve(process.cwd(), 'dev.log');
|
|
29
|
+
/**
|
|
30
|
+
* Parse --projects-dir from CLI args
|
|
31
|
+
*/
|
|
32
|
+
function parseProjectsDir() {
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
const idx = args.indexOf('--projects-dir');
|
|
35
|
+
if (idx !== -1 && args[idx + 1]) {
|
|
36
|
+
return path.resolve(args[idx + 1]);
|
|
37
|
+
}
|
|
38
|
+
// Fall back to env var (for dev mode via .env.local)
|
|
39
|
+
if (process.env.SHELLA_PROJECTS_DIR) {
|
|
40
|
+
return path.resolve(process.env.SHELLA_PROJECTS_DIR);
|
|
41
|
+
}
|
|
42
|
+
// Default to cwd
|
|
43
|
+
return process.cwd();
|
|
44
|
+
}
|
|
45
|
+
// Projects directory - passed from CLI or .env.local
|
|
46
|
+
export const PROJECTS_DIR = parseProjectsDir();
|
|
47
|
+
// Version - keep in sync with package.json
|
|
48
|
+
export const VERSION = '0.1.3';
|
|
23
49
|
/**
|
|
24
50
|
* Ensure config directory exists
|
|
25
51
|
*/
|
|
@@ -38,6 +64,7 @@ app.use(express.json());
|
|
|
38
64
|
app.get('/health', (_req, res) => res.json({ status: 'ok' }));
|
|
39
65
|
// Mount API routes
|
|
40
66
|
app.use('/__shella', windowsRoutes);
|
|
67
|
+
app.use('/__shella/init', initRoutes);
|
|
41
68
|
app.use('/__model-state', modelStateRoutes);
|
|
42
69
|
app.use('/__logs', logsRoutes);
|
|
43
70
|
app.use('/api', proxyRoutes);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shella initialization endpoint
|
|
3
|
+
*
|
|
4
|
+
* TODO: Consolidate more startup data here to reduce round-trips:
|
|
5
|
+
* - windows (currently /__shella/windows)
|
|
6
|
+
* - modelState (currently /__model-state)
|
|
7
|
+
* - projects (currently /api/project via OpenCode proxy)
|
|
8
|
+
* - agents, config, providers (currently /api/* via OpenCode proxy)
|
|
9
|
+
* - permissions (currently /api/permission via OpenCode proxy)
|
|
10
|
+
*
|
|
11
|
+
* For now, this just provides the projects directory info that the CLI
|
|
12
|
+
* passes to the server, so the frontend knows where Shella was started.
|
|
13
|
+
*/
|
|
14
|
+
declare const router: import("express-serve-static-core").Router;
|
|
15
|
+
export default router;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shella initialization endpoint
|
|
3
|
+
*
|
|
4
|
+
* TODO: Consolidate more startup data here to reduce round-trips:
|
|
5
|
+
* - windows (currently /__shella/windows)
|
|
6
|
+
* - modelState (currently /__model-state)
|
|
7
|
+
* - projects (currently /api/project via OpenCode proxy)
|
|
8
|
+
* - agents, config, providers (currently /api/* via OpenCode proxy)
|
|
9
|
+
* - permissions (currently /api/permission via OpenCode proxy)
|
|
10
|
+
*
|
|
11
|
+
* For now, this just provides the projects directory info that the CLI
|
|
12
|
+
* passes to the server, so the frontend knows where Shella was started.
|
|
13
|
+
*/
|
|
14
|
+
import { Router } from 'express';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { PROJECTS_DIR, VERSION } from '../index.js';
|
|
17
|
+
const router = Router();
|
|
18
|
+
router.get('/', (_req, res) => {
|
|
19
|
+
res.json({
|
|
20
|
+
projectsDir: PROJECTS_DIR,
|
|
21
|
+
projectsDirName: path.basename(PROJECTS_DIR),
|
|
22
|
+
version: VERSION,
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
export default router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{aU as L,bi as ln,aE as A,aS as v,bj as gn,bk as dn,aD as W,bl as hn,bm as z,bn as pn,bo as An,bp as m,aV as N,a_ as U,b1 as T,bq as _n,aY as on,br as wn,bs as On,aF as V,bt as Pn,bu as I}from"./mermaid.core-
|
|
1
|
+
import{aU as L,bi as ln,aE as A,aS as v,bj as gn,bk as dn,aD as W,bl as hn,bm as z,bn as pn,bo as An,bp as m,aV as N,a_ as U,b1 as T,bq as _n,aY as on,br as wn,bs as On,aF as V,bt as Pn,bu as I}from"./mermaid.core-npIGP8NS.js";var vn="[object Symbol]";function x(n){return typeof n=="symbol"||L(n)&&ln(n)==vn}function yn(n,r){for(var e=-1,i=n==null?0:n.length,f=Array(i);++e<i;)f[e]=r(n[e],e,n);return f}var B=v?v.prototype:void 0,K=B?B.toString:void 0;function k(n){if(typeof n=="string")return n;if(A(n))return yn(n,k)+"";if(x(n))return K?K.call(n):"";var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function En(){}function bn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i&&r(n[e],e,n)!==!1;);return n}function cn(n,r,e,i){for(var f=n.length,t=e+-1;++t<f;)if(r(n[t],t,n))return t;return-1}function Tn(n){return n!==n}function Rn(n,r,e){for(var i=e-1,f=n.length;++i<f;)if(n[i]===r)return i;return-1}function In(n,r,e){return r===r?Rn(n,r,e):cn(n,Tn,e)}function Sn(n,r){var e=n==null?0:n.length;return!!e&&In(n,r,0)>-1}function M(n){return W(n)?gn(n):dn(n)}var Ln=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,xn=/^\w*$/;function $(n,r){if(A(n))return!1;var e=typeof n;return e=="number"||e=="symbol"||e=="boolean"||n==null||x(n)?!0:xn.test(n)||!Ln.test(n)||r!=null&&n in Object(r)}var Mn=500;function $n(n){var r=hn(n,function(i){return e.size===Mn&&e.clear(),i}),e=r.cache;return r}var Cn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Dn=/\\(\\)?/g,Fn=$n(function(n){var r=[];return n.charCodeAt(0)===46&&r.push(""),n.replace(Cn,function(e,i,f,t){r.push(f?t.replace(Dn,"$1"):i||e)}),r});function Gn(n){return n==null?"":k(n)}function j(n,r){return A(n)?n:$(n,r)?[n]:Fn(Gn(n))}function R(n){if(typeof n=="string"||x(n))return n;var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function nn(n,r){r=j(r,n);for(var e=0,i=r.length;n!=null&&e<i;)n=n[R(r[e++])];return e&&e==i?n:void 0}function mn(n,r,e){var i=n==null?void 0:nn(n,r);return i===void 0?e:i}function rn(n,r){for(var e=-1,i=r.length,f=n.length;++e<i;)n[f+e]=r[e];return n}var H=v?v.isConcatSpreadable:void 0;function Nn(n){return A(n)||z(n)||!!(H&&n&&n[H])}function Hr(n,r,e,i,f){var t=-1,s=n.length;for(e||(e=Nn),f||(f=[]);++t<s;){var u=n[t];e(u)?rn(f,u):i||(f[f.length]=u)}return f}function Un(n,r,e,i){var f=-1,t=n==null?0:n.length;for(i&&t&&(e=n[++f]);++f<t;)e=r(e,n[f],f,n);return e}function en(n,r){for(var e=-1,i=n==null?0:n.length,f=0,t=[];++e<i;){var s=n[e];r(s,e,n)&&(t[f++]=s)}return t}function Bn(){return[]}var Kn=Object.prototype,Hn=Kn.propertyIsEnumerable,q=Object.getOwnPropertySymbols,qn=q?function(n){return n==null?[]:(n=Object(n),en(q(n),function(r){return Hn.call(n,r)}))}:Bn;function Yn(n,r,e){var i=r(n);return A(n)?i:rn(i,e(n))}function Y(n){return Yn(n,M,qn)}var Zn="__lodash_hash_undefined__";function Xn(n){return this.__data__.set(n,Zn),this}function Jn(n){return this.__data__.has(n)}function y(n){var r=-1,e=n==null?0:n.length;for(this.__data__=new pn;++r<e;)this.add(n[r])}y.prototype.add=y.prototype.push=Xn;y.prototype.has=Jn;function Qn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i;)if(r(n[e],e,n))return!0;return!1}function tn(n,r){return n.has(r)}var Wn=1,zn=2;function fn(n,r,e,i,f,t){var s=e&Wn,u=n.length,a=r.length;if(u!=a&&!(s&&a>u))return!1;var h=t.get(n),g=t.get(r);if(h&&g)return h==r&&g==n;var l=-1,d=!0,o=e&zn?new y:void 0;for(t.set(n,r),t.set(r,n);++l<u;){var p=n[l],_=r[l];if(i)var w=s?i(_,p,l,r,n,t):i(p,_,l,n,r,t);if(w!==void 0){if(w)continue;d=!1;break}if(o){if(!Qn(r,function(O,P){if(!tn(o,P)&&(p===O||f(p,O,e,i,t)))return o.push(P)})){d=!1;break}}else if(!(p===_||f(p,_,e,i,t))){d=!1;break}}return t.delete(n),t.delete(r),d}function Vn(n){var r=-1,e=Array(n.size);return n.forEach(function(i,f){e[++r]=[f,i]}),e}function C(n){var r=-1,e=Array(n.size);return n.forEach(function(i){e[++r]=i}),e}var kn=1,jn=2,nr="[object Boolean]",rr="[object Date]",er="[object Error]",ir="[object Map]",tr="[object Number]",fr="[object RegExp]",sr="[object Set]",ur="[object String]",ar="[object Symbol]",lr="[object ArrayBuffer]",gr="[object DataView]",Z=v?v.prototype:void 0,S=Z?Z.valueOf:void 0;function dr(n,r,e,i,f,t,s){switch(e){case gr:if(n.byteLength!=r.byteLength||n.byteOffset!=r.byteOffset)return!1;n=n.buffer,r=r.buffer;case lr:return!(n.byteLength!=r.byteLength||!t(new m(n),new m(r)));case nr:case rr:case tr:return An(+n,+r);case er:return n.name==r.name&&n.message==r.message;case fr:case ur:return n==r+"";case ir:var u=Vn;case sr:var a=i&kn;if(u||(u=C),n.size!=r.size&&!a)return!1;var h=s.get(n);if(h)return h==r;i|=jn,s.set(n,r);var g=fn(u(n),u(r),i,f,t,s);return s.delete(n),g;case ar:if(S)return S.call(n)==S.call(r)}return!1}var hr=1,pr=Object.prototype,Ar=pr.hasOwnProperty;function _r(n,r,e,i,f,t){var s=e&hr,u=Y(n),a=u.length,h=Y(r),g=h.length;if(a!=g&&!s)return!1;for(var l=a;l--;){var d=u[l];if(!(s?d in r:Ar.call(r,d)))return!1}var o=t.get(n),p=t.get(r);if(o&&p)return o==r&&p==n;var _=!0;t.set(n,r),t.set(r,n);for(var w=s;++l<a;){d=u[l];var O=n[d],P=r[d];if(i)var G=s?i(P,O,d,r,n,t):i(O,P,d,n,r,t);if(!(G===void 0?O===P||f(O,P,e,i,t):G)){_=!1;break}w||(w=d=="constructor")}if(_&&!w){var E=n.constructor,b=r.constructor;E!=b&&"constructor"in n&&"constructor"in r&&!(typeof E=="function"&&E instanceof E&&typeof b=="function"&&b instanceof b)&&(_=!1)}return t.delete(n),t.delete(r),_}var or=1,X="[object Arguments]",J="[object Array]",c="[object Object]",wr=Object.prototype,Q=wr.hasOwnProperty;function Or(n,r,e,i,f,t){var s=A(n),u=A(r),a=s?J:N(n),h=u?J:N(r);a=a==X?c:a,h=h==X?c:h;var g=a==c,l=h==c,d=a==h;if(d&&U(n)){if(!U(r))return!1;s=!0,g=!1}if(d&&!g)return t||(t=new T),s||_n(n)?fn(n,r,e,i,f,t):dr(n,r,a,e,i,f,t);if(!(e&or)){var o=g&&Q.call(n,"__wrapped__"),p=l&&Q.call(r,"__wrapped__");if(o||p){var _=o?n.value():n,w=p?r.value():r;return t||(t=new T),f(_,w,e,i,t)}}return d?(t||(t=new T),_r(n,r,e,i,f,t)):!1}function D(n,r,e,i,f){return n===r?!0:n==null||r==null||!L(n)&&!L(r)?n!==n&&r!==r:Or(n,r,e,i,D,f)}var Pr=1,vr=2;function yr(n,r,e,i){var f=e.length,t=f;if(n==null)return!t;for(n=Object(n);f--;){var s=e[f];if(s[2]?s[1]!==n[s[0]]:!(s[0]in n))return!1}for(;++f<t;){s=e[f];var u=s[0],a=n[u],h=s[1];if(s[2]){if(a===void 0&&!(u in n))return!1}else{var g=new T,l;if(!(l===void 0?D(h,a,Pr|vr,i,g):l))return!1}}return!0}function sn(n){return n===n&&!on(n)}function Er(n){for(var r=M(n),e=r.length;e--;){var i=r[e],f=n[i];r[e]=[i,f,sn(f)]}return r}function un(n,r){return function(e){return e==null?!1:e[n]===r&&(r!==void 0||n in Object(e))}}function br(n){var r=Er(n);return r.length==1&&r[0][2]?un(r[0][0],r[0][1]):function(e){return e===n||yr(e,n,r)}}function cr(n,r){return n!=null&&r in Object(n)}function Tr(n,r,e){r=j(r,n);for(var i=-1,f=r.length,t=!1;++i<f;){var s=R(r[i]);if(!(t=n!=null&&e(n,s)))break;n=n[s]}return t||++i!=f?t:(f=n==null?0:n.length,!!f&&wn(f)&&On(s,f)&&(A(n)||z(n)))}function Rr(n,r){return n!=null&&Tr(n,r,cr)}var Ir=1,Sr=2;function Lr(n,r){return $(n)&&sn(r)?un(R(n),r):function(e){var i=mn(e,n);return i===void 0&&i===r?Rr(e,n):D(r,i,Ir|Sr)}}function xr(n){return function(r){return r?.[n]}}function Mr(n){return function(r){return nn(r,n)}}function $r(n){return $(n)?xr(R(n)):Mr(n)}function an(n){return typeof n=="function"?n:n==null?V:typeof n=="object"?A(n)?Lr(n[0],n[1]):br(n):$r(n)}function Cr(n,r){return n&&Pn(n,r,M)}function Dr(n,r){return function(e,i){if(e==null)return e;if(!W(e))return n(e,i);for(var f=e.length,t=-1,s=Object(e);++t<f&&i(s[t],t,s)!==!1;);return e}}var F=Dr(Cr);function Fr(n){return typeof n=="function"?n:V}function qr(n,r){var e=A(n)?bn:F;return e(n,Fr(r))}function Gr(n,r){var e=[];return F(n,function(i,f,t){r(i,f,t)&&e.push(i)}),e}function Yr(n,r){var e=A(n)?en:Gr;return e(n,an(r))}function mr(n,r,e,i,f){return f(n,function(t,s,u){e=i?(i=!1,t):r(e,t,s,u)}),e}function Zr(n,r,e){var i=A(n)?Un:mr,f=arguments.length<3;return i(n,an(r),e,f,F)}var Nr=1/0,Ur=I&&1/C(new I([,-0]))[1]==Nr?function(n){return new I(n)}:En,Br=200;function Xr(n,r,e){var i=-1,f=Sn,t=n.length,s=!0,u=[],a=u;if(t>=Br){var h=r?null:Ur(n);if(h)return C(h);s=!1,f=tn,a=new y}else a=r?[]:u;n:for(;++i<t;){var g=n[i],l=r?r(g):g;if(g=g!==0?g:0,s&&l===l){for(var d=a.length;d--;)if(a[d]===l)continue n;r&&a.push(l),u.push(g)}else f(a,l,e)||(a!==u&&a.push(l),u.push(g))}return u}export{F as a,Hr as b,yn as c,an as d,rn as e,Yn as f,qn as g,Y as h,x as i,bn as j,M as k,Xr as l,Yr as m,qr as n,cn as o,Fr as p,Cr as q,Zr as r,Bn as s,Tr as t,j as u,R as v,nn as w,Rr as x,Gn as y};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{M as ln,N as an,O as Y,P as O,Q,R as un,S as y,T as tn,V as j,W as _,X as rn,Y as o,Z as sn,$ as on,a0 as fn}from"./mermaid.core-
|
|
1
|
+
import{M as ln,N as an,O as Y,P as O,Q,R as un,S as y,T as tn,V as j,W as _,X as rn,Y as o,Z as sn,$ as on,a0 as fn}from"./mermaid.core-npIGP8NS.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,D,S,v,R,V,a){var E=D-l,i=S-h,n=V-v,d=a-R,u=d*E-n*i;if(!(u*u<y))return u=(n*(h-R)-d*(l-v))/u,[l+u*E,h+u*i]}function H(l,h,D,S,v,R,V){var a=l-D,E=h-S,i=(V?R:-R)/j(a*a+E*E),n=i*E,d=-i*a,u=l+n,s=h+d,f=D+n,c=S+d,W=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,A=m*m+g*g,T=v-R,P=u*c-f*s,I=(g<0?-1:1)*j(on(0,T*T*A-P*P)),M=(P*g-m*I)/A,N=(-P*m-g*I)/A,w=(P*g+m*I)/A,p=(-P*m+g*I)/A,x=M-W,e=N-t,r=w-W,X=p-t;return x*x+e*e>r*r+X*X&&(M=w,N=p),{cx:M,cy:N,x01:-n,y01:-d,x11:M*(v/T-1),y11:N*(v/T-1)}}function hn(){var l=cn,h=yn,D=Q(0),S=null,v=gn,R=dn,V=mn,a=null,E=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=R.apply(this,arguments)-un,W=rn(c-f),t=c>f;if(a||(a=n=E()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(W>tn-y)a.moveTo(s*Y(f),s*O(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*Y(c),u*O(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,A=f,T=c,P=W,I=W,M=V.apply(this,arguments)/2,N=M>y&&(S?+S.apply(this,arguments):j(u*u+s*s)),w=_(rn(s-u)/2,+D.apply(this,arguments)),p=w,x=w,e,r;if(N>y){var X=sn(N/u*O(M)),z=sn(N/s*O(M));(P-=X*2)>y?(X*=t?1:-1,A+=X,T-=X):(P=0,A=T=(f+c)/2),(I-=z*2)>y?(z*=t?1:-1,m+=z,g-=z):(I=0,m=g=(f+c)/2)}var Z=s*Y(m),$=s*O(m),B=u*Y(T),C=u*O(T);if(w>y){var F=s*Y(g),G=s*O(g),J=u*Y(A),K=u*O(A),q;if(W<an)if(q=pn(Z,$,J,K,F,G,B,C)){var L=Z-q[0],U=$-q[1],k=F-q[0],b=G-q[1],nn=1/O(fn((L*k+U*b)/(j(L*L+U*U)*j(k*k+b*b)))/2),en=j(q[0]*q[0]+q[1]*q[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}I>y?x>y?(e=H(J,K,Z,$,s,x,t),r=H(F,G,B,C,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(Z,$),a.arc(0,0,s,m,g,!t)):a.moveTo(Z,$),!(u>y)||!(P>y)?a.lineTo(B,C):p>y?(e=H(B,C,F,G,u,-p,t),r=H(Z,$,J,K,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,A,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +R.apply(this,arguments))/2-an/2;return[Y(d)*n,O(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:Q(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:Q(+n),i):h},i.cornerRadius=function(n){return arguments.length?(D=typeof n=="function"?n:Q(+n),i):D},i.padRadius=function(n){return arguments.length?(S=n==null?null:typeof n=="function"?n:Q(+n),i):S},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:Q(+n),i):v},i.endAngle=function(n){return arguments.length?(R=typeof n=="function"?n:Q(+n),i):R},i.padAngle=function(n){return arguments.length?(V=typeof n=="function"?n:Q(+n),i):V},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|