@skyforgeai/skyforge 2.0.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.
- package/README.md +246 -0
- package/bin/sky-code +40 -0
- package/package.json +150 -0
- package/scripts/postinstall.cjs +106 -0
- package/src/skill/bundled-snapshot.d.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/tryskyforge/skyforge/main/skyforge-tui.png" alt="SkyForge" width="600" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h3 align="center">SkyForge</h3>
|
|
6
|
+
|
|
7
|
+
<p align="center">The autonomous ServiceNow development agent.</p>
|
|
8
|
+
<p align="center"><em>AI-powered ServiceNow development, forged for you.</em></p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/@skyforgeai/skyforge"><img alt="npm" src="https://img.shields.io/npm/v/%40skyforgeai%2Fskyforge?style=for-the-badge&logo=npm&logoColor=white&color=CB3837" /></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i -g @skyforgeai/skyforge@latest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
<details>
|
|
23
|
+
<summary><b>More installation methods</b></summary>
|
|
24
|
+
<br>
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun add -g @skyforgeai/skyforge@latest # Bun
|
|
28
|
+
pnpm i -g @skyforgeai/skyforge@latest # pnpm
|
|
29
|
+
yarn global add @skyforgeai/skyforge@latest # Yarn
|
|
30
|
+
curl -fsSL https://raw.githubusercontent.com/tryskyforge/skyforge/main/install | bash # Install script
|
|
31
|
+
brew install tryskyforge/tap/skyforge # macOS / Linux
|
|
32
|
+
scoop install skyforge # Windows
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
</details>
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
skyforge
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That's it. SkyForge will prompt you to configure an AI provider on first launch.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
## Why SkyForge?
|
|
48
|
+
|
|
49
|
+
<table>
|
|
50
|
+
<tr>
|
|
51
|
+
<td width="50%" valign="top">
|
|
52
|
+
|
|
53
|
+
**ServiceNow-Native**<br>
|
|
54
|
+
<sub>200+ MCP tools and 54 domain skills built for ServiceNow development, deployment, and automation.</sub>
|
|
55
|
+
|
|
56
|
+
</td>
|
|
57
|
+
<td width="50%" valign="top">
|
|
58
|
+
|
|
59
|
+
**Any AI Provider**<br>
|
|
60
|
+
<sub>20+ providers: Anthropic, OpenAI, Google, AWS Bedrock, Azure, Groq, xAI, OpenRouter, and more.</sub>
|
|
61
|
+
|
|
62
|
+
</td>
|
|
63
|
+
</tr>
|
|
64
|
+
<tr>
|
|
65
|
+
<td width="50%" valign="top">
|
|
66
|
+
|
|
67
|
+
**Multi-Agent**<br>
|
|
68
|
+
<sub>Built-in build & plan agents. Custom agents with per-agent models, permissions, and temperature.</sub>
|
|
69
|
+
|
|
70
|
+
</td>
|
|
71
|
+
<td width="50%" valign="top">
|
|
72
|
+
|
|
73
|
+
**Extensible**<br>
|
|
74
|
+
<sub>MCP ecosystem support (stdio, SSE, HTTP). Plugin system via npm or local packages.</sub>
|
|
75
|
+
|
|
76
|
+
</td>
|
|
77
|
+
</tr>
|
|
78
|
+
</table>
|
|
79
|
+
|
|
80
|
+
## Supported Providers
|
|
81
|
+
|
|
82
|
+
<table>
|
|
83
|
+
<tr>
|
|
84
|
+
<td><b>Anthropic</b></td>
|
|
85
|
+
<td><b>OpenAI</b></td>
|
|
86
|
+
<td><b>Google</b></td>
|
|
87
|
+
<td><b>AWS Bedrock</b></td>
|
|
88
|
+
</tr>
|
|
89
|
+
<tr>
|
|
90
|
+
<td><sub>Claude 4.5/4.6</sub></td>
|
|
91
|
+
<td><sub>GPT-5, GPT-4, o-series</sub></td>
|
|
92
|
+
<td><sub>Gemini 2.5 + Vertex AI</sub></td>
|
|
93
|
+
<td><sub>All models, cross-region</sub></td>
|
|
94
|
+
</tr>
|
|
95
|
+
<tr><td colspan="4"> </td></tr>
|
|
96
|
+
<tr>
|
|
97
|
+
<td><b>Azure</b></td>
|
|
98
|
+
<td><b>Mistral</b></td>
|
|
99
|
+
<td><b>Groq</b></td>
|
|
100
|
+
<td><b>+ 13 more</b></td>
|
|
101
|
+
</tr>
|
|
102
|
+
<tr>
|
|
103
|
+
<td><sub>OpenAI + Cognitive Services</sub></td>
|
|
104
|
+
<td><sub>Large, Medium, Small</sub></td>
|
|
105
|
+
<td><sub>Ultra-fast inference</sub></td>
|
|
106
|
+
<td><sub>xAI, OpenRouter, Copilot, Cohere, Perplexity, ...</sub></td>
|
|
107
|
+
</tr>
|
|
108
|
+
</table>
|
|
109
|
+
|
|
110
|
+
## Built-in Tools
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
File Operations Shell Web Dev
|
|
114
|
+
─────────────── ───── ─── ───
|
|
115
|
+
read bash (streaming, webfetch plan (enter/exit)
|
|
116
|
+
write pty support) websearch task management
|
|
117
|
+
edit codesearch LSP (experimental)
|
|
118
|
+
glob skill invocation
|
|
119
|
+
grep, ls
|
|
120
|
+
apply_patch
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## ServiceNow MCP Tools
|
|
124
|
+
|
|
125
|
+
Connect to your ServiceNow instance and access **200+ tools**:
|
|
126
|
+
|
|
127
|
+
<table>
|
|
128
|
+
<tr>
|
|
129
|
+
<td valign="top"><sub><b>Operations</b> — Query tables, CMDB, users, metrics</sub></td>
|
|
130
|
+
<td valign="top"><sub><b>Development</b> — Script Includes, Business Rules, Client Scripts, UI Policies</sub></td>
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<td valign="top"><sub><b>Deployment</b> — Widgets, Update Sets, validation, rollback</sub></td>
|
|
134
|
+
<td valign="top"><sub><b>Automation</b> — Flow Designer, Scheduled Jobs, Approvals, Events</sub></td>
|
|
135
|
+
</tr>
|
|
136
|
+
<tr>
|
|
137
|
+
<td valign="top"><sub><b>Security</b> — ACLs, Domain Separation, compliance, scanning</sub></td>
|
|
138
|
+
<td valign="top"><sub><b>Analysis</b> — Reporting, Dashboards, KPIs, Performance Analytics</sub></td>
|
|
139
|
+
</tr>
|
|
140
|
+
</table>
|
|
141
|
+
|
|
142
|
+
```jsonc
|
|
143
|
+
{
|
|
144
|
+
"mcp": {
|
|
145
|
+
"servicenow": {
|
|
146
|
+
"type": "local",
|
|
147
|
+
"command": ["skyforge", "mcp", "start"],
|
|
148
|
+
"environment": {
|
|
149
|
+
"SERVICENOW_INSTANCE_URL": "https://your-instance.service-now.com",
|
|
150
|
+
"SERVICENOW_CLIENT_ID": "...",
|
|
151
|
+
"SERVICENOW_CLIENT_SECRET": "...",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Agents
|
|
159
|
+
|
|
160
|
+
| Agent | Description |
|
|
161
|
+
| :---------- | :------------------------------------------------------------ |
|
|
162
|
+
| **build** | Full access agent for development work |
|
|
163
|
+
| **plan** | Read-only agent for analysis — denies edits, asks before bash |
|
|
164
|
+
| **general** | Subagent for complex multi-step tasks (`@general`) |
|
|
165
|
+
|
|
166
|
+
## CLI
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
skyforge # Start TUI
|
|
170
|
+
skyforge serve # Headless API server (port 4096)
|
|
171
|
+
skyforge web # Server + web interface
|
|
172
|
+
skyforge attach <url> # Attach to remote server
|
|
173
|
+
skyforge auth # Configure authentication
|
|
174
|
+
skyforge models # List available models
|
|
175
|
+
skyforge stats # Usage statistics
|
|
176
|
+
skyforge export # Export session data
|
|
177
|
+
skyforge pr # Pull request automation
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Configuration
|
|
181
|
+
|
|
182
|
+
Config is loaded from (in priority order):
|
|
183
|
+
|
|
184
|
+
| Priority | Source |
|
|
185
|
+
| :------- | :------------------------------------- |
|
|
186
|
+
| 1 | Remote/well-known organization configs |
|
|
187
|
+
| 2 | Global config (`~/.skyforge/`) |
|
|
188
|
+
| 3 | `SKY_FORGE_CONFIG` env variable |
|
|
189
|
+
| 4 | Project config (`skyforge.jsonc`) |
|
|
190
|
+
| 5 | `SKY_FORGE_CONFIG_CONTENT` inline |
|
|
191
|
+
|
|
192
|
+
<details>
|
|
193
|
+
<summary><b>MCP servers</b></summary>
|
|
194
|
+
<br>
|
|
195
|
+
|
|
196
|
+
```jsonc
|
|
197
|
+
{
|
|
198
|
+
"mcp": {
|
|
199
|
+
"my-server": { "type": "local", "command": ["node", "./server.js"] },
|
|
200
|
+
"remote": { "type": "remote", "url": "https://example.com/mcp" },
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Supports stdio, SSE, and streamable HTTP with OAuth.
|
|
206
|
+
|
|
207
|
+
</details>
|
|
208
|
+
|
|
209
|
+
<details>
|
|
210
|
+
<summary><b>Plugins</b></summary>
|
|
211
|
+
<br>
|
|
212
|
+
|
|
213
|
+
```jsonc
|
|
214
|
+
{
|
|
215
|
+
"plugin": ["my-skyforge-plugin", "file://./local-plugin"],
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary><b>Permissions</b></summary>
|
|
223
|
+
<br>
|
|
224
|
+
|
|
225
|
+
```jsonc
|
|
226
|
+
{
|
|
227
|
+
"permission": {
|
|
228
|
+
"bash": "ask",
|
|
229
|
+
"write": "allow",
|
|
230
|
+
"read": "allow",
|
|
231
|
+
"external_directory": "deny",
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Glob patterns, per-agent rulesets, and env file protection included.
|
|
237
|
+
|
|
238
|
+
</details>
|
|
239
|
+
|
|
240
|
+
## Links
|
|
241
|
+
|
|
242
|
+
- [Getting Started](https://skyforgeai.gitbook.io/internal-docs/getting-started)
|
|
243
|
+
- [Configuration](https://skyforgeai.gitbook.io/internal-docs/configuration)
|
|
244
|
+
- [Bug Reports & Feature Requests](https://skyforge.canny.io)
|
|
245
|
+
|
|
246
|
+
|
package/bin/sky-code
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process")
|
|
4
|
+
const fs = require("fs")
|
|
5
|
+
const path = require("path")
|
|
6
|
+
const os = require("os")
|
|
7
|
+
|
|
8
|
+
const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
|
|
9
|
+
const archMap = { x64: "x64", arm64: "arm64" }
|
|
10
|
+
|
|
11
|
+
const platform = platformMap[os.platform()] || os.platform()
|
|
12
|
+
const arch = archMap[os.arch()] || os.arch()
|
|
13
|
+
const pkgName = `@skyforgeai/skyforge-${platform}-${arch}`
|
|
14
|
+
const binaryName = platform === "windows" ? "sky-code.exe" : "sky-code"
|
|
15
|
+
|
|
16
|
+
// Search for the platform binary in node_modules
|
|
17
|
+
function findBinary(startDir) {
|
|
18
|
+
let current = startDir
|
|
19
|
+
while (true) {
|
|
20
|
+
const candidate = path.join(current, "node_modules", pkgName, "bin", binaryName)
|
|
21
|
+
if (fs.existsSync(candidate)) return candidate
|
|
22
|
+
const parent = path.dirname(current)
|
|
23
|
+
if (parent === current) break
|
|
24
|
+
current = parent
|
|
25
|
+
}
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const scriptDir = path.dirname(fs.realpathSync(__filename))
|
|
30
|
+
const binary = findBinary(scriptDir)
|
|
31
|
+
|
|
32
|
+
if (!binary) {
|
|
33
|
+
console.error(`sky-code: Binary not found for ${platform}-${arch}`)
|
|
34
|
+
console.error(`Expected package: ${pkgName}`)
|
|
35
|
+
console.error(`Try: npm install -g @skyforgeai/skyforge`)
|
|
36
|
+
process.exit(1)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" })
|
|
40
|
+
process.exit(typeof result.status === "number" ? result.status : 0)
|
package/package.json
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"name": "@skyforgeai/skyforge",
|
|
5
|
+
"description": "SkyForge - ServiceNow Multi-Agent Development Framework powered by AI",
|
|
6
|
+
"license": "Elastic-2.0",
|
|
7
|
+
"private": false,
|
|
8
|
+
"scripts": {
|
|
9
|
+
"typecheck": "tsgo --noEmit",
|
|
10
|
+
"test": "bun test",
|
|
11
|
+
"build": "bun run script/build.ts",
|
|
12
|
+
"dev": "bun run --conditions=browser ./src/index.ts",
|
|
13
|
+
"clean": "echo 'Cleaning up...' && rm -rf node_modules dist",
|
|
14
|
+
"lint": "bun test --coverage",
|
|
15
|
+
"format": "bun run --prettier --write src/**/*.ts",
|
|
16
|
+
"build:mcp": "bun run script/build-mcp.ts"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"scripts",
|
|
21
|
+
"src/skill/bundled-snapshot.d.ts",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"skyforge": "./bin/sky-code",
|
|
26
|
+
"sky-code": "./bin/sky-code"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
"./*": "./src/*.ts"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@babel/core": "7.28.4",
|
|
33
|
+
"@octokit/webhooks-types": "7.6.1",
|
|
34
|
+
"@parcel/watcher-darwin-arm64": "2.5.1",
|
|
35
|
+
"@parcel/watcher-darwin-x64": "2.5.1",
|
|
36
|
+
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
|
37
|
+
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
|
38
|
+
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
|
39
|
+
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
|
40
|
+
"@parcel/watcher-win32-x64": "2.5.1",
|
|
41
|
+
"@standard-schema/spec": "1.0.0",
|
|
42
|
+
"@tsconfig/bun": "1.0.9",
|
|
43
|
+
"@types/babel__core": "7.20.5",
|
|
44
|
+
"@types/bun": "1.3.7",
|
|
45
|
+
"@types/turndown": "5.0.5",
|
|
46
|
+
"@types/yargs": "17.0.33",
|
|
47
|
+
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
48
|
+
"typescript": "5.8.2",
|
|
49
|
+
"vscode-languageserver-types": "3.17.5",
|
|
50
|
+
"why-is-node-running": "3.2.2",
|
|
51
|
+
"zod-to-json-schema": "3.25.1"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@actions/core": "1.11.1",
|
|
55
|
+
"@actions/github": "6.0.1",
|
|
56
|
+
"@agentclientprotocol/sdk": "0.12.0",
|
|
57
|
+
"@ai-sdk/amazon-bedrock": "3.0.73",
|
|
58
|
+
"@ai-sdk/anthropic": "2.0.57",
|
|
59
|
+
"@ai-sdk/azure": "2.0.91",
|
|
60
|
+
"@ai-sdk/cerebras": "1.0.34",
|
|
61
|
+
"@ai-sdk/cohere": "2.0.22",
|
|
62
|
+
"@ai-sdk/deepinfra": "1.0.31",
|
|
63
|
+
"@ai-sdk/gateway": "2.0.25",
|
|
64
|
+
"@ai-sdk/google": "2.0.52",
|
|
65
|
+
"@ai-sdk/google-vertex": "3.0.97",
|
|
66
|
+
"@ai-sdk/groq": "2.0.34",
|
|
67
|
+
"@ai-sdk/mistral": "2.0.27",
|
|
68
|
+
"@ai-sdk/openai": "2.0.89",
|
|
69
|
+
"@ai-sdk/openai-compatible": "1.0.30",
|
|
70
|
+
"@ai-sdk/perplexity": "2.0.23",
|
|
71
|
+
"@ai-sdk/provider": "2.0.1",
|
|
72
|
+
"@ai-sdk/provider-utils": "3.0.20",
|
|
73
|
+
"@ai-sdk/togetherai": "1.0.31",
|
|
74
|
+
"@ai-sdk/vercel": "1.0.31",
|
|
75
|
+
"@ai-sdk/xai": "2.0.51",
|
|
76
|
+
"@clack/prompts": "1.0.0-alpha.1",
|
|
77
|
+
"@gitlab/gitlab-ai-provider": "3.3.1",
|
|
78
|
+
"@hono/standard-validator": "0.2.2",
|
|
79
|
+
"@hono/zod-validator": "0.7.6",
|
|
80
|
+
"@modelcontextprotocol/sdk": "1.26.0",
|
|
81
|
+
"@octokit/graphql": "9.0.2",
|
|
82
|
+
"@octokit/rest": "22.0.0",
|
|
83
|
+
"@openauthjs/openauth": "0.0.0-20250322224806",
|
|
84
|
+
"@openrouter/ai-sdk-provider": "1.5.2",
|
|
85
|
+
"@opentui/core": "0.1.77",
|
|
86
|
+
"@opentui/solid": "0.1.77",
|
|
87
|
+
"@parcel/watcher": "2.5.1",
|
|
88
|
+
"@pierre/diffs": "1.0.2",
|
|
89
|
+
"@solid-primitives/event-bus": "1.1.2",
|
|
90
|
+
"@solid-primitives/scheduled": "1.5.2",
|
|
91
|
+
"@standard-schema/spec": "1.0.0",
|
|
92
|
+
"@zip.js/zip.js": "2.7.62",
|
|
93
|
+
"ai": "5.0.124",
|
|
94
|
+
"axios": "1.13.5",
|
|
95
|
+
"bonjour-service": "1.3.0",
|
|
96
|
+
"bun-pty": "0.4.4",
|
|
97
|
+
"chokidar": "4.0.3",
|
|
98
|
+
"clipboardy": "4.0.0",
|
|
99
|
+
"decimal.js": "10.5.0",
|
|
100
|
+
"diff": "8.0.3",
|
|
101
|
+
"dotenv": "17.2.3",
|
|
102
|
+
"fuzzysort": "3.1.0",
|
|
103
|
+
"gray-matter": "4.0.3",
|
|
104
|
+
"hono": "4.11.10",
|
|
105
|
+
"hono-openapi": "1.2.0",
|
|
106
|
+
"ignore": "7.0.5",
|
|
107
|
+
"jsonc-parser": "3.3.1",
|
|
108
|
+
"minimatch": "10.2.1",
|
|
109
|
+
"node-machine-id": "1.1.12",
|
|
110
|
+
"open": "10.1.2",
|
|
111
|
+
"opentui-spinner": "0.0.6",
|
|
112
|
+
"partial-json": "0.1.7",
|
|
113
|
+
"remeda": "2.26.0",
|
|
114
|
+
"solid-js": "1.9.10",
|
|
115
|
+
"strip-ansi": "7.1.2",
|
|
116
|
+
"tree-sitter-bash": "0.25.0",
|
|
117
|
+
"turndown": "7.2.0",
|
|
118
|
+
"ulid": "3.0.1",
|
|
119
|
+
"vscode-jsonrpc": "8.2.1",
|
|
120
|
+
"web-tree-sitter": "0.25.10",
|
|
121
|
+
"winston": "3.19.0",
|
|
122
|
+
"xdg-basedir": "5.1.0",
|
|
123
|
+
"yargs": "18.0.0",
|
|
124
|
+
"zod": "4.1.8",
|
|
125
|
+
"zod-to-json-schema": "3.25.1"
|
|
126
|
+
},
|
|
127
|
+
"repository": {
|
|
128
|
+
"type": "git",
|
|
129
|
+
"url": "https://github.com/tryskyforge/skyforge"
|
|
130
|
+
},
|
|
131
|
+
"homepage": "https://github.com/tryskyforge/skyforge#readme",
|
|
132
|
+
"bugs": {
|
|
133
|
+
"url": "https://skyforge.canny.io"
|
|
134
|
+
},
|
|
135
|
+
"keywords": [
|
|
136
|
+
"servicenow",
|
|
137
|
+
"ai",
|
|
138
|
+
"agent",
|
|
139
|
+
"mcp",
|
|
140
|
+
"cli",
|
|
141
|
+
"development"
|
|
142
|
+
],
|
|
143
|
+
"optionalDependencies": {
|
|
144
|
+
"@skyforgeai/skyforge-darwin-arm64": "2.0.0",
|
|
145
|
+
"@skyforgeai/skyforge-darwin-x64": "2.0.0",
|
|
146
|
+
"@skyforgeai/skyforge-linux-arm64": "2.0.0",
|
|
147
|
+
"@skyforgeai/skyforge-linux-x64": "2.0.0",
|
|
148
|
+
"@skyforgeai/skyforge-windows-x64": "2.0.0"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const https = require("https")
|
|
3
|
+
const fs = require("fs")
|
|
4
|
+
const path = require("path")
|
|
5
|
+
const os = require("os")
|
|
6
|
+
const { execSync } = require("child_process")
|
|
7
|
+
|
|
8
|
+
const pkg = require("../package.json")
|
|
9
|
+
const VERSION = pkg.version
|
|
10
|
+
const REPO = "tryskyforge/skyforge"
|
|
11
|
+
|
|
12
|
+
const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
|
|
13
|
+
const archMap = { x64: "x64", arm64: "arm64" }
|
|
14
|
+
|
|
15
|
+
const platform = platformMap[os.platform()] || os.platform()
|
|
16
|
+
const arch = archMap[os.arch()] || os.arch()
|
|
17
|
+
const archiveExt = ".tar.gz"
|
|
18
|
+
const tarballName = "skyforge-" + platform + "-" + arch + archiveExt
|
|
19
|
+
|
|
20
|
+
const pkgDir = path.join(__dirname, "..")
|
|
21
|
+
const binaryName = platform === "windows" ? "sky-code.exe" : "sky-code"
|
|
22
|
+
const binaryPath = path.join(pkgDir, "bin", binaryName)
|
|
23
|
+
|
|
24
|
+
// Verify the binary matches the current platform by checking magic bytes
|
|
25
|
+
function binaryMatchesPlatform(filePath) {
|
|
26
|
+
try {
|
|
27
|
+
var fd = fs.openSync(filePath, "r")
|
|
28
|
+
var buf = Buffer.alloc(4)
|
|
29
|
+
fs.readSync(fd, buf, 0, 4, 0)
|
|
30
|
+
fs.closeSync(fd)
|
|
31
|
+
var magic = buf.toString("hex")
|
|
32
|
+
|
|
33
|
+
if (platform === "darwin") {
|
|
34
|
+
// Mach-O: cffaedfe (64-bit LE), feedfacf (64-bit BE), cafebabe (universal/fat)
|
|
35
|
+
return magic === "cffaedfe" || magic === "feedfacf" || magic === "cafebabe"
|
|
36
|
+
}
|
|
37
|
+
if (platform === "linux") {
|
|
38
|
+
// ELF: 7f454c46
|
|
39
|
+
return magic === "7f454c46"
|
|
40
|
+
}
|
|
41
|
+
if (platform === "windows") {
|
|
42
|
+
// PE/MZ: 4d5a
|
|
43
|
+
return magic.startsWith("4d5a")
|
|
44
|
+
}
|
|
45
|
+
return false
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if file exists AND is a real binary (not just a launcher script)
|
|
52
|
+
// Launcher scripts are small (~2KB), actual binaries are 20MB+
|
|
53
|
+
// Also verify the binary is for the current platform (not a leftover from CI)
|
|
54
|
+
if (fs.existsSync(binaryPath)) {
|
|
55
|
+
var stats = fs.statSync(binaryPath)
|
|
56
|
+
if (stats.size > 100000 && binaryMatchesPlatform(binaryPath)) {
|
|
57
|
+
console.log("sky-code: Binary already exists")
|
|
58
|
+
process.exit(0)
|
|
59
|
+
}
|
|
60
|
+
if (stats.size > 100000) {
|
|
61
|
+
console.log("sky-code: Binary exists but is for wrong platform, re-downloading...")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const releaseUrl = "https://github.com/" + REPO + "/releases/download/v" + VERSION + "/" + tarballName
|
|
66
|
+
console.log("sky-code: Downloading binary for " + platform + "-" + arch + "...")
|
|
67
|
+
|
|
68
|
+
function followRedirects(url, callback) {
|
|
69
|
+
https.get(url, { headers: { "User-Agent": "sky-code" } }, function (res) {
|
|
70
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
71
|
+
followRedirects(res.headers.location, callback)
|
|
72
|
+
} else {
|
|
73
|
+
callback(res)
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "skyforge-"))
|
|
79
|
+
var tarPath = path.join(tmpDir, tarballName)
|
|
80
|
+
var file = fs.createWriteStream(tarPath)
|
|
81
|
+
|
|
82
|
+
followRedirects(releaseUrl, function (res) {
|
|
83
|
+
if (res.statusCode !== 200) {
|
|
84
|
+
console.warn("sky-code: Could not download binary (HTTP " + res.statusCode + ")")
|
|
85
|
+
console.warn("sky-code: Download manually from: https://github.com/" + REPO + "/releases")
|
|
86
|
+
process.exit(0)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
res.pipe(file)
|
|
90
|
+
file.on("finish", function () {
|
|
91
|
+
file.close()
|
|
92
|
+
try {
|
|
93
|
+
// All platforms use tar.gz — tar is available on Windows 10+ (build 17063+)
|
|
94
|
+
execSync('tar -xzf "' + tarPath + '" -C "' + pkgDir + '"', { stdio: "pipe" })
|
|
95
|
+
if (fs.existsSync(binaryPath)) {
|
|
96
|
+
fs.chmodSync(binaryPath, 493)
|
|
97
|
+
}
|
|
98
|
+
console.log("sky-code: Binary installed successfully!")
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.warn("sky-code: Could not extract binary")
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
fs.rmSync(tmpDir, { recursive: true })
|
|
104
|
+
} catch (e) {}
|
|
105
|
+
})
|
|
106
|
+
})
|