@bytespell/shella 0.1.2 → 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 +19 -6
- package/bin/cli.js +73 -53
- 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/index.html +1 -1
- package/package.json +2 -1
- 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,29 +6,39 @@ 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
|
-
# From your project directory
|
|
13
12
|
cd ~/myproject
|
|
14
13
|
npx @bytespell/shella
|
|
15
14
|
```
|
|
16
15
|
|
|
17
16
|
Opens at `http://localhost:3067`. Access from your phone using the LAN IP shown.
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
### Permanent Install
|
|
20
19
|
|
|
21
20
|
```bash
|
|
22
|
-
|
|
21
|
+
npm install -g @bytespell/shella
|
|
22
|
+
shella
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
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
|
|
26
36
|
|
|
27
37
|
```yaml
|
|
28
38
|
# docker-compose.yml
|
|
29
39
|
services:
|
|
30
40
|
shella:
|
|
31
|
-
image: ghcr.io/bytespell/shella
|
|
41
|
+
image: ghcr.io/bytespell-oss/shella
|
|
32
42
|
ports:
|
|
33
43
|
- '3067:3067'
|
|
34
44
|
volumes:
|
|
@@ -70,6 +80,9 @@ shella --help # Show help
|
|
|
70
80
|
# Install dependencies
|
|
71
81
|
npm install
|
|
72
82
|
|
|
83
|
+
# Create .env.local with your projects directory
|
|
84
|
+
echo "SHELLA_PROJECTS_DIR=/path/to/your/projects" > .env.local
|
|
85
|
+
|
|
73
86
|
# Start dev servers (Vite + Express + OpenCode)
|
|
74
87
|
npm run start:dev
|
|
75
88
|
|
package/bin/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { existsSync, readdirSync } from 'fs';
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
const VERSION = '0.1.
|
|
11
|
+
const VERSION = '0.1.3';
|
|
12
12
|
/**
|
|
13
13
|
* Check if running inside Docker container
|
|
14
14
|
*/
|
|
@@ -55,27 +55,35 @@ function getLanIp() {
|
|
|
55
55
|
/**
|
|
56
56
|
* Print a nice boxed message with the access URL
|
|
57
57
|
*/
|
|
58
|
-
function printAccessBox(lanIp, port) {
|
|
58
|
+
function printAccessBox(lanIp, port, projectName) {
|
|
59
59
|
const url = `http://${lanIp}:${port}`;
|
|
60
60
|
const urlLine = ` ${url}`;
|
|
61
61
|
const width = Math.max(44, urlLine.length + 4);
|
|
62
62
|
const border = '-'.repeat(width);
|
|
63
63
|
const pad = (s) => s + ' '.repeat(width - s.length);
|
|
64
|
-
console.log(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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('');
|
|
73
79
|
}
|
|
74
80
|
/**
|
|
75
|
-
* Register projects with OpenCode
|
|
81
|
+
* Register projects with OpenCode by creating a session in each directory.
|
|
82
|
+
* This triggers OpenCode to discover and register the project.
|
|
76
83
|
*/
|
|
77
84
|
async function registerProjects(opencodePort, projectsDir) {
|
|
78
85
|
const baseUrl = `http://localhost:${opencodePort}`;
|
|
86
|
+
const registered = [];
|
|
79
87
|
if (projectsDir) {
|
|
80
88
|
// Resolve to absolute path
|
|
81
89
|
const absDir = path.resolve(projectsDir);
|
|
@@ -83,21 +91,29 @@ async function registerProjects(opencodePort, projectsDir) {
|
|
|
83
91
|
console.error(`Error: Projects directory not found: ${absDir}`);
|
|
84
92
|
process.exit(1);
|
|
85
93
|
}
|
|
86
|
-
// Register each subdirectory
|
|
94
|
+
// Register each subdirectory (OpenCode will determine if it's a git repo)
|
|
87
95
|
const entries = readdirSync(absDir, { withFileTypes: true });
|
|
88
96
|
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith('.'));
|
|
89
97
|
if (dirs.length === 0) {
|
|
90
|
-
console.error(`Error: No
|
|
98
|
+
console.error(`Error: No subdirectories found in ${absDir}`);
|
|
91
99
|
process.exit(1);
|
|
92
100
|
}
|
|
93
101
|
for (const entry of dirs) {
|
|
94
102
|
const dir = path.join(absDir, entry.name);
|
|
95
103
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
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);
|
|
98
114
|
}
|
|
99
|
-
catch
|
|
100
|
-
|
|
115
|
+
catch {
|
|
116
|
+
// Silently skip failed registrations
|
|
101
117
|
}
|
|
102
118
|
}
|
|
103
119
|
}
|
|
@@ -105,20 +121,28 @@ async function registerProjects(opencodePort, projectsDir) {
|
|
|
105
121
|
// Register cwd
|
|
106
122
|
const dir = process.cwd();
|
|
107
123
|
try {
|
|
108
|
-
await fetch(`${baseUrl}/
|
|
109
|
-
|
|
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));
|
|
110
133
|
}
|
|
111
|
-
catch
|
|
112
|
-
|
|
134
|
+
catch {
|
|
135
|
+
// Silently skip
|
|
113
136
|
}
|
|
114
137
|
}
|
|
138
|
+
return { count: registered.length, names: registered };
|
|
115
139
|
}
|
|
116
140
|
let opencodeServer = null;
|
|
117
141
|
let expressProcess = null;
|
|
118
142
|
async function startCommand(options) {
|
|
119
143
|
const port = parseInt(options.port);
|
|
120
144
|
const opencodePort = parseInt(options.opencodePort);
|
|
121
|
-
|
|
145
|
+
const cwd = process.cwd();
|
|
122
146
|
// Docker requires --projects-dir
|
|
123
147
|
if (isDocker() && !options.projectsDir) {
|
|
124
148
|
console.error('Error: --projects-dir is required when running in Docker.\n');
|
|
@@ -128,49 +152,48 @@ async function startCommand(options) {
|
|
|
128
152
|
console.error(' command: ["--projects-dir", "/project"]');
|
|
129
153
|
process.exit(1);
|
|
130
154
|
}
|
|
155
|
+
// Determine the projects directory to pass to the server
|
|
156
|
+
const projectsDir = options.projectsDir ? path.resolve(options.projectsDir) : cwd;
|
|
131
157
|
// Check if ports are available
|
|
132
158
|
const webPortAvailable = await isPortAvailable(port);
|
|
133
159
|
const ocPortAvailable = await isPortAvailable(opencodePort);
|
|
134
160
|
if (!webPortAvailable) {
|
|
135
161
|
console.error(`Error: Port ${port} is already in use.`);
|
|
136
|
-
console.error(`\nTry
|
|
137
|
-
console.error(` - Stop the process using port ${port}`);
|
|
138
|
-
console.error(` - Use a different port: shella --port 3070`);
|
|
162
|
+
console.error(`\nTry: shella --port 3070`);
|
|
139
163
|
process.exit(1);
|
|
140
164
|
}
|
|
141
165
|
if (!ocPortAvailable) {
|
|
142
|
-
console.error(`Error: Port ${opencodePort} is already in use (OpenCode
|
|
143
|
-
console.error(`\
|
|
144
|
-
console.error(`\nTry one of these:`);
|
|
145
|
-
console.error(` - Kill the existing OpenCode: pkill -f "opencode serve"`);
|
|
146
|
-
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`);
|
|
147
168
|
process.exit(1);
|
|
148
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...');
|
|
149
179
|
// Start OpenCode server using the bundled binary
|
|
150
|
-
console.log('Starting OpenCode...');
|
|
151
180
|
try {
|
|
152
181
|
opencodeServer = await createOpencodeServer({
|
|
153
182
|
port: opencodePort,
|
|
154
183
|
timeout: 30000,
|
|
155
184
|
});
|
|
156
|
-
console.log(` OpenCode ready (port ${opencodePort})`);
|
|
157
185
|
}
|
|
158
186
|
catch (err) {
|
|
159
187
|
const message = err instanceof Error ? err.message : String(err);
|
|
160
|
-
console.error(
|
|
161
|
-
if (message.includes('port')) {
|
|
162
|
-
console.error(`\nThe port ${opencodePort} may be in use. Try:`);
|
|
163
|
-
console.error(` shella --opencode-port 4097`);
|
|
164
|
-
}
|
|
188
|
+
console.error(`Failed to start OpenCode: ${message}`);
|
|
165
189
|
process.exit(1);
|
|
166
190
|
}
|
|
167
191
|
// Register projects with OpenCode
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// Start Express server in production mode
|
|
171
|
-
console.log('Starting Shella server...');
|
|
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
|
|
172
195
|
const serverPath = path.join(__dirname, '..', 'dist', 'server', 'index.js');
|
|
173
|
-
expressProcess = spawn('node', [serverPath], {
|
|
196
|
+
expressProcess = spawn('node', [serverPath, '--projects-dir', projectsDir], {
|
|
174
197
|
env: {
|
|
175
198
|
...process.env,
|
|
176
199
|
NODE_ENV: 'production',
|
|
@@ -181,7 +204,7 @@ async function startCommand(options) {
|
|
|
181
204
|
// Wait for server to be ready
|
|
182
205
|
await new Promise((resolve, reject) => {
|
|
183
206
|
const timeout = setTimeout(() => {
|
|
184
|
-
reject(new Error('Server startup timeout
|
|
207
|
+
reject(new Error('Server startup timeout'));
|
|
185
208
|
}, 10000);
|
|
186
209
|
expressProcess.stdout?.on('data', (data) => {
|
|
187
210
|
const output = data.toString();
|
|
@@ -189,11 +212,10 @@ async function startCommand(options) {
|
|
|
189
212
|
clearTimeout(timeout);
|
|
190
213
|
resolve();
|
|
191
214
|
}
|
|
192
|
-
//
|
|
193
|
-
process.stdout.write(output.replace(/\[shella-server\] /g, ' '));
|
|
215
|
+
// Suppress all server output
|
|
194
216
|
});
|
|
195
|
-
expressProcess.stderr?.on('data', (
|
|
196
|
-
|
|
217
|
+
expressProcess.stderr?.on('data', () => {
|
|
218
|
+
// Suppress stderr too
|
|
197
219
|
});
|
|
198
220
|
expressProcess.on('error', (err) => {
|
|
199
221
|
clearTimeout(timeout);
|
|
@@ -206,11 +228,10 @@ async function startCommand(options) {
|
|
|
206
228
|
}
|
|
207
229
|
});
|
|
208
230
|
});
|
|
209
|
-
console.log(` Shella ready (port ${port})`);
|
|
210
231
|
// Print access box
|
|
211
232
|
const lanIp = getLanIp();
|
|
212
|
-
printAccessBox(lanIp, port);
|
|
213
|
-
console.log('Press Ctrl+C to stop
|
|
233
|
+
printAccessBox(lanIp, port, projectName);
|
|
234
|
+
console.log('Press Ctrl+C to stop');
|
|
214
235
|
// Open browser if requested
|
|
215
236
|
if (options.open) {
|
|
216
237
|
const url = `http://localhost:${port}`;
|
|
@@ -222,7 +243,7 @@ async function startCommand(options) {
|
|
|
222
243
|
* Graceful shutdown handler
|
|
223
244
|
*/
|
|
224
245
|
function shutdown() {
|
|
225
|
-
console.log('\
|
|
246
|
+
console.log('\nStopping...');
|
|
226
247
|
if (expressProcess) {
|
|
227
248
|
expressProcess.kill('SIGTERM');
|
|
228
249
|
expressProcess = null;
|
|
@@ -231,7 +252,6 @@ function shutdown() {
|
|
|
231
252
|
opencodeServer.close();
|
|
232
253
|
opencodeServer = null;
|
|
233
254
|
}
|
|
234
|
-
console.log('Goodbye!');
|
|
235
255
|
process.exit(0);
|
|
236
256
|
}
|
|
237
257
|
// Handle shutdown signals
|
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};
|