runwork 0.2.0 → 0.2.5
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/LICENSE +10 -16
- package/dist/api/client.d.ts +22 -0
- package/dist/api/client.js +9 -0
- package/dist/commands/dev.js +20 -70
- package/dist/commands/integrations.d.ts +2 -0
- package/dist/commands/integrations.js +86 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +165 -0
- package/dist/generated/bundled-types.js +32 -32
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/git/__tests__/auto-commit.test.d.ts +1 -0
- package/dist/git/__tests__/auto-commit.test.js +373 -0
- package/dist/git/__tests__/manifest.test.d.ts +1 -0
- package/dist/git/__tests__/manifest.test.js +377 -0
- package/dist/git/__tests__/sync.test.d.ts +1 -0
- package/dist/git/__tests__/sync.test.js +403 -0
- package/dist/git/auto-commit.d.ts +1 -0
- package/dist/git/auto-commit.js +15 -5
- package/dist/git/sync.d.ts +15 -0
- package/dist/git/sync.js +116 -0
- package/dist/index.js +4 -0
- package/dist/logs/tailer.js +5 -11
- package/dist/template/manifest.js +24 -4
- package/package.json +3 -3
- package/dist/auth/browser.d.ts +0 -2
- package/dist/auth/browser.js +0 -7
package/LICENSE
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
Copyright (c) 2025-2026 Runwork All rights reserved.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This software and associated documentation files (the "Software") are the
|
|
4
|
+
proprietary and confidential property of Runwork
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
6
|
+
No part of the Software may be copied, modified, distributed, sublicensed,
|
|
7
|
+
sold, or otherwise made available to any third party without the prior
|
|
8
|
+
written consent of Runwork
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
You may use the Software solely as a tool to interact with the Runwork
|
|
11
|
+
platform in accordance with the Runwork Terms of Service.
|
|
14
12
|
|
|
15
13
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
14
|
+
IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
|
package/dist/api/client.d.ts
CHANGED
|
@@ -63,6 +63,28 @@ export declare class ApiClient {
|
|
|
63
63
|
filePath: string;
|
|
64
64
|
fileContents: string;
|
|
65
65
|
}>, deletedFiles?: string[]): Promise<void>;
|
|
66
|
+
searchIntegrations(query: string, limit?: number): Promise<{
|
|
67
|
+
results: Array<{
|
|
68
|
+
id: string;
|
|
69
|
+
name: string;
|
|
70
|
+
provider: string;
|
|
71
|
+
docs?: {
|
|
72
|
+
name: string;
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
pathFormat: string;
|
|
75
|
+
examples: string[];
|
|
76
|
+
notes?: string[];
|
|
77
|
+
requiredSetup?: string;
|
|
78
|
+
};
|
|
79
|
+
}>;
|
|
80
|
+
}>;
|
|
81
|
+
listConnectedIntegrations(workspaceId: string): Promise<Array<{
|
|
82
|
+
integrationId: string;
|
|
83
|
+
canonicalId?: string;
|
|
84
|
+
provider: string;
|
|
85
|
+
status?: string;
|
|
86
|
+
createdAt?: string;
|
|
87
|
+
}>>;
|
|
66
88
|
/**
|
|
67
89
|
* Get git remote URL for an app.
|
|
68
90
|
* Both canonical ({baseUrl}/api/git/{workspaceId}/{appId}) and
|
package/dist/api/client.js
CHANGED
|
@@ -133,6 +133,15 @@ export class ApiClient {
|
|
|
133
133
|
body: JSON.stringify({ files, deletedFiles }),
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
|
+
async searchIntegrations(query, limit = 20) {
|
|
137
|
+
const params = new URLSearchParams({ q: query, limit: String(limit) });
|
|
138
|
+
const res = await this.request(`/api/integrations/search?${params}`);
|
|
139
|
+
return res.data;
|
|
140
|
+
}
|
|
141
|
+
async listConnectedIntegrations(workspaceId) {
|
|
142
|
+
const res = await this.request(`/api/workspaces/${workspaceId}/integrations`);
|
|
143
|
+
return res.data.integrations;
|
|
144
|
+
}
|
|
136
145
|
/**
|
|
137
146
|
* Get git remote URL for an app.
|
|
138
147
|
* Both canonical ({baseUrl}/api/git/{workspaceId}/{appId}) and
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { execFileSync } from 'child_process';
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { requireAuth } from '../auth/store.js';
|
|
6
6
|
import { ApiClient } from '../api/client.js';
|
|
7
7
|
import { watchAndAutoCommit, stopAutoCommit } from '../git/auto-commit.js';
|
|
8
|
+
import { syncWithRemote } from '../git/sync.js';
|
|
8
9
|
import { startLogTailer } from '../logs/tailer.js';
|
|
9
10
|
import { populateTypes } from '../types-manager.js';
|
|
10
11
|
import { loadManifest, generateManifest, saveManifest, detectUserEdits } from '../template/manifest.js';
|
|
@@ -28,25 +29,6 @@ function readConfig() {
|
|
|
28
29
|
}
|
|
29
30
|
return JSON.parse(readFileSync('.runwork.json', 'utf-8'));
|
|
30
31
|
}
|
|
31
|
-
function hasCommits() {
|
|
32
|
-
try {
|
|
33
|
-
execFileSync('git', ['rev-parse', 'HEAD'], { stdio: 'pipe' });
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function hasTrackedChanges() {
|
|
41
|
-
try {
|
|
42
|
-
// Only check tracked files (modified/deleted/staged) - not untracked (??) files
|
|
43
|
-
const output = execFileSync('git', ['status', '--porcelain'], { encoding: 'utf-8' });
|
|
44
|
-
return output.trim().split('\n').some(line => line.length > 0 && !line.startsWith('??'));
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
32
|
export const devCommand = new Command('dev')
|
|
51
33
|
.description('Start local development server with live sync')
|
|
52
34
|
.option('--no-logs', 'Disable automatic log tailing')
|
|
@@ -103,60 +85,28 @@ export const devCommand = new Command('dev')
|
|
|
103
85
|
// Fetch SKILL.md (best-effort, after session so DO registries are available)
|
|
104
86
|
await populateSkill(cwd, client, config.appId);
|
|
105
87
|
// Sync AFTER starting session so we pick up any commits the DO created
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const untrackedOutput = execFileSync('git', ['ls-files', '--others', '--exclude-standard'], { encoding: 'utf-8' }).trim();
|
|
121
|
-
const untracked = new Set(untrackedOutput.split('\n').filter(Boolean));
|
|
122
|
-
for (const file of remoteFiles) {
|
|
123
|
-
if (untracked.has(file)) {
|
|
124
|
-
try {
|
|
125
|
-
unlinkSync(join(cwd, file));
|
|
126
|
-
}
|
|
127
|
-
catch { /* already gone */ }
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch { /* best effort */ }
|
|
132
|
-
execFileSync('git', ['rebase', 'runwork/main'], { stdio: 'inherit' });
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
try {
|
|
136
|
-
execFileSync('git', ['rebase', '--abort'], { stdio: 'pipe' });
|
|
137
|
-
}
|
|
138
|
-
catch { /* no rebase in progress */ }
|
|
139
|
-
console.warn('Pull failed (remote may not have commits yet). Continuing...');
|
|
140
|
-
}
|
|
141
|
-
if (dirty) {
|
|
142
|
-
try {
|
|
143
|
-
execFileSync('git', ['stash', 'pop'], { stdio: 'inherit' });
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
88
|
+
console.log('Syncing with Runwork...');
|
|
89
|
+
const syncResult = syncWithRemote(cwd);
|
|
90
|
+
switch (syncResult.status) {
|
|
91
|
+
case 'skipped':
|
|
92
|
+
console.log('No commits yet. Skipping sync.');
|
|
93
|
+
break;
|
|
94
|
+
case 'synced':
|
|
95
|
+
console.log('Synced with Runwork.');
|
|
96
|
+
break;
|
|
97
|
+
case 'merged':
|
|
98
|
+
console.log('Merged with Runwork (histories diverged).');
|
|
99
|
+
break;
|
|
100
|
+
case 'sync-failed':
|
|
101
|
+
if (syncResult.error === 'stash-conflict') {
|
|
146
102
|
console.error('Merge conflicts detected after stash pop. Resolve conflicts and restart.');
|
|
147
103
|
process.exit(1);
|
|
148
104
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
execFileSync('git', ['push', 'runwork', 'main'], { stdio: 'inherit' });
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
console.warn('Push failed. Continuing with current state...');
|
|
156
|
-
}
|
|
105
|
+
console.warn('Pull failed (remote may not have commits yet). Continuing...');
|
|
106
|
+
break;
|
|
157
107
|
}
|
|
158
|
-
|
|
159
|
-
console.
|
|
108
|
+
if (!syncResult.pushed && syncResult.status !== 'skipped' && syncResult.status !== 'sync-failed') {
|
|
109
|
+
console.warn('Push failed. Continuing with current state...');
|
|
160
110
|
}
|
|
161
111
|
// Declare logTailer before cleanup so cleanup can reference it
|
|
162
112
|
let logTailer;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { requireAuth } from '../auth/store.js';
|
|
3
|
+
import { ApiClient } from '../api/client.js';
|
|
4
|
+
import { readFileSync, existsSync } from 'fs';
|
|
5
|
+
function readConfig() {
|
|
6
|
+
if (!existsSync('.runwork.json')) {
|
|
7
|
+
console.error('No .runwork.json found. Run `runwork init` first.');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
return JSON.parse(readFileSync('.runwork.json', 'utf-8'));
|
|
11
|
+
}
|
|
12
|
+
const searchCommand = new Command('search')
|
|
13
|
+
.description('Search available integrations from the platform catalog')
|
|
14
|
+
.argument('<query>', 'Search query (e.g., "google drive", "hubspot", "slack")')
|
|
15
|
+
.option('--limit <n>', 'Maximum results to show', '20')
|
|
16
|
+
.action(async (query, opts) => {
|
|
17
|
+
const credentials = requireAuth();
|
|
18
|
+
const client = new ApiClient(credentials);
|
|
19
|
+
const limit = parseInt(opts.limit, 10);
|
|
20
|
+
try {
|
|
21
|
+
const { results } = await client.searchIntegrations(query, limit);
|
|
22
|
+
if (results.length === 0) {
|
|
23
|
+
console.log(`No integrations found for "${query}".`);
|
|
24
|
+
console.log('Try broader terms (e.g., "calendar" instead of "google calendar").');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.log(`Found ${results.length} integration(s) for "${query}":\n`);
|
|
28
|
+
for (const r of results) {
|
|
29
|
+
console.log(` ${r.id} - ${r.name} (${r.provider})`);
|
|
30
|
+
if (r.docs) {
|
|
31
|
+
console.log(` Base URL: ${r.docs.baseUrl}`);
|
|
32
|
+
console.log(` Path format: ${r.docs.pathFormat}`);
|
|
33
|
+
if (r.docs.examples && r.docs.examples.length > 0) {
|
|
34
|
+
console.log(` Endpoints:`);
|
|
35
|
+
for (const example of r.docs.examples) {
|
|
36
|
+
console.log(` ${example}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (r.docs.notes && r.docs.notes.length > 0) {
|
|
40
|
+
for (const note of r.docs.notes) {
|
|
41
|
+
console.log(` Note: ${note}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (r.docs.requiredSetup) {
|
|
45
|
+
console.log(` Setup: ${r.docs.requiredSetup}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
50
|
+
console.log('\nUsage: Add the integration ID to APP_INTEGRATION_REQUIREMENTS in worker/integration-requirements.ts');
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
console.error('Failed to search integrations:', err instanceof Error ? err.message : err);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const listCommand = new Command('list')
|
|
58
|
+
.description('List connected workspace integrations')
|
|
59
|
+
.action(async () => {
|
|
60
|
+
const credentials = requireAuth();
|
|
61
|
+
const client = new ApiClient(credentials);
|
|
62
|
+
const config = readConfig();
|
|
63
|
+
try {
|
|
64
|
+
const integrations = await client.listConnectedIntegrations(config.workspaceId);
|
|
65
|
+
if (integrations.length === 0) {
|
|
66
|
+
console.log('No integrations connected in this workspace.');
|
|
67
|
+
console.log('Connect integrations at https://runwork.ai/workspace-settings');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log(`Connected integrations (${integrations.length}):\n`);
|
|
71
|
+
for (const i of integrations) {
|
|
72
|
+
const id = i.canonicalId || i.integrationId;
|
|
73
|
+
const status = i.status || 'connected';
|
|
74
|
+
const date = i.createdAt ? ` (since ${new Date(i.createdAt).toLocaleDateString()})` : '';
|
|
75
|
+
console.log(` ${id} - ${i.provider}${date} [${status}]`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.error('Failed to list integrations:', err instanceof Error ? err.message : err);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
export const integrationsCommand = new Command('integrations')
|
|
84
|
+
.description('Search and manage workspace integrations')
|
|
85
|
+
.addCommand(searchCommand)
|
|
86
|
+
.addCommand(listCommand);
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execFileSync } from 'child_process';
|
|
3
|
+
import { VERSION } from '../generated/version.js';
|
|
4
|
+
const GITHUB_REPO = 'runwork-ai/cli';
|
|
5
|
+
const INSTALL_SCRIPT_URL = 'https://runwork.ai/install.sh';
|
|
6
|
+
async function fetchLatestVersion() {
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/releases/latest`);
|
|
9
|
+
if (!response.ok)
|
|
10
|
+
return null;
|
|
11
|
+
const data = await response.json();
|
|
12
|
+
return data.tag_name?.replace(/^v/, '') || null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function detectInstallMethod() {
|
|
19
|
+
try {
|
|
20
|
+
const binaryPath = process.argv[1] || '';
|
|
21
|
+
// Homebrew: /opt/homebrew/Cellar/runwork/... or /usr/local/Cellar/runwork/...
|
|
22
|
+
if (binaryPath.includes('/Cellar/runwork/') || binaryPath.includes('/homebrew/')) {
|
|
23
|
+
return 'brew';
|
|
24
|
+
}
|
|
25
|
+
// Volta: ~/.volta/tools/image/packages/runwork/...
|
|
26
|
+
if (binaryPath.includes('/.volta/')) {
|
|
27
|
+
return 'volta';
|
|
28
|
+
}
|
|
29
|
+
// Bun global: ~/.bun/install/global/... or ~/.bun/bin/...
|
|
30
|
+
if (binaryPath.includes('/.bun/')) {
|
|
31
|
+
return 'bun';
|
|
32
|
+
}
|
|
33
|
+
// pnpm global: ~/.local/share/pnpm/... or pnpm/global/...
|
|
34
|
+
if (binaryPath.includes('/pnpm/') || binaryPath.includes('/.pnpm/')) {
|
|
35
|
+
return 'pnpm';
|
|
36
|
+
}
|
|
37
|
+
// Yarn global: ~/.yarn/bin/... or ~/.config/yarn/global/...
|
|
38
|
+
if (binaryPath.includes('/.yarn/') || binaryPath.includes('/yarn/global/')) {
|
|
39
|
+
return 'yarn';
|
|
40
|
+
}
|
|
41
|
+
// npm global: node_modules or /lib/node/ in path
|
|
42
|
+
if (binaryPath.includes('node_modules') || binaryPath.includes('/lib/node/')) {
|
|
43
|
+
return 'npm';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Fall through to binary
|
|
48
|
+
}
|
|
49
|
+
return 'binary';
|
|
50
|
+
}
|
|
51
|
+
export const upgradeCommand = new Command('upgrade')
|
|
52
|
+
.description('Upgrade Runwork CLI to the latest version')
|
|
53
|
+
.option('--check', 'Check for updates without installing')
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
console.log(`Current version: ${VERSION}`);
|
|
56
|
+
const latest = await fetchLatestVersion();
|
|
57
|
+
if (!latest) {
|
|
58
|
+
console.error('Could not fetch latest version. Check your internet connection.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
if (latest === VERSION) {
|
|
62
|
+
console.log(`Already on the latest version (${VERSION}).`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
console.log(`Latest version: ${latest}`);
|
|
66
|
+
if (options.check) {
|
|
67
|
+
console.log(`\nRun \`runwork upgrade\` to install the update.`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const method = detectInstallMethod();
|
|
71
|
+
if (method === 'brew') {
|
|
72
|
+
console.log('\nDetected installation method: brew');
|
|
73
|
+
console.log('Upgrading via Homebrew...\n');
|
|
74
|
+
try {
|
|
75
|
+
execFileSync('brew', ['update', '--quiet'], { stdio: 'inherit' });
|
|
76
|
+
execFileSync('brew', ['upgrade', 'runwork'], { stdio: 'inherit' });
|
|
77
|
+
console.log('\nUpgraded successfully via Homebrew.');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
console.error('\nHomebrew upgrade failed. Try manually: brew update && brew upgrade runwork');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (method === 'bun') {
|
|
86
|
+
console.log('\nDetected installation method: bun');
|
|
87
|
+
console.log('Upgrading via bun...\n');
|
|
88
|
+
try {
|
|
89
|
+
execFileSync('bun', ['install', '-g', 'runwork@latest'], { stdio: 'inherit' });
|
|
90
|
+
console.log('\nUpgraded successfully via bun.');
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
console.error('\nbun upgrade failed. Try manually: bun install -g runwork@latest');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (method === 'pnpm') {
|
|
99
|
+
console.log('\nDetected installation method: pnpm');
|
|
100
|
+
console.log('Upgrading via pnpm...\n');
|
|
101
|
+
try {
|
|
102
|
+
execFileSync('pnpm', ['update', '-g', 'runwork'], { stdio: 'inherit' });
|
|
103
|
+
console.log('\nUpgraded successfully via pnpm.');
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
console.error('\npnpm upgrade failed. Try manually: pnpm update -g runwork');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (method === 'yarn') {
|
|
112
|
+
console.log('\nDetected installation method: yarn');
|
|
113
|
+
console.log('Upgrading via yarn...\n');
|
|
114
|
+
try {
|
|
115
|
+
execFileSync('yarn', ['global', 'upgrade', 'runwork'], { stdio: 'inherit' });
|
|
116
|
+
console.log('\nUpgraded successfully via yarn.');
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
console.error('\nyarn upgrade failed. Try manually: yarn global upgrade runwork');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (method === 'volta') {
|
|
125
|
+
console.log('\nDetected installation method: volta');
|
|
126
|
+
console.log('Upgrading via Volta...\n');
|
|
127
|
+
try {
|
|
128
|
+
execFileSync('volta', ['install', 'runwork@latest'], { stdio: 'inherit' });
|
|
129
|
+
console.log('\nUpgraded successfully via Volta.');
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
console.error('\nVolta upgrade failed. Try manually: volta install runwork@latest');
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (method === 'npm') {
|
|
138
|
+
console.log('\nDetected installation method: npm');
|
|
139
|
+
console.log('Upgrading via npm...\n');
|
|
140
|
+
try {
|
|
141
|
+
execFileSync('npm', ['update', '-g', 'runwork'], { stdio: 'inherit' });
|
|
142
|
+
console.log('\nUpgraded successfully via npm.');
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
console.error('\nnpm upgrade failed. Try manually: npm update -g runwork');
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// Binary install: download install script and pipe to sh
|
|
151
|
+
console.log('\nUpgrading via install script...\n');
|
|
152
|
+
try {
|
|
153
|
+
const response = await fetch(INSTALL_SCRIPT_URL);
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
throw new Error(`Failed to download install script: ${response.status}`);
|
|
156
|
+
}
|
|
157
|
+
const script = await response.text();
|
|
158
|
+
execFileSync('sh', ['-c', script], { stdio: 'inherit' });
|
|
159
|
+
console.log('\nUpgraded successfully.');
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
console.error(`\nUpgrade failed. Try manually: curl -fsSL ${INSTALL_SCRIPT_URL} | sh`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
});
|