primo-cli 0.1.11 → 0.1.12
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/dist/commands/deploy.js +4 -4
- package/dist/commands/dev.js +19 -19
- package/dist/commands/new.js +5 -1
- package/dist/commands/pull-library.js +2 -2
- package/dist/commands/pull.js +2 -2
- package/dist/commands/push-library.js +2 -2
- package/dist/commands/push.js +5 -5
- package/dist/commands/validate.js +2 -2
- package/dist/utils/binary.js +31 -14
- package/package.json +1 -1
package/dist/commands/deploy.js
CHANGED
|
@@ -230,10 +230,10 @@ async function check_provider_auth(provider) {
|
|
|
230
230
|
// Bump to a release tag (:v3.0.0) when primocms cuts a stable release.
|
|
231
231
|
const PRIMO_SERVER_IMAGE = 'ghcr.io/primocms/primo:main';
|
|
232
232
|
async function generate_dockerfile(inventory) {
|
|
233
|
-
// One-line Dockerfile: pull the published
|
|
233
|
+
// One-line Dockerfile: pull the published primo image and run it
|
|
234
234
|
// unchanged. Workspace data (server.yaml, sites/, library/) is uploaded
|
|
235
|
-
// after deploy via `primo push`, which calls /api/
|
|
236
|
-
// first push (server with no sites) and /api/
|
|
235
|
+
// after deploy via `primo push`, which calls /api/primo/bootstrap on
|
|
236
|
+
// first push (server with no sites) and /api/primo/import/<id> on
|
|
237
237
|
// subsequent pushes. The volume mounted at /app/pb_data persists the
|
|
238
238
|
// SQLite database between restarts.
|
|
239
239
|
void inventory;
|
|
@@ -255,7 +255,7 @@ EXPOSE 8080
|
|
|
255
255
|
}
|
|
256
256
|
async function generate_fly_toml(inventory) {
|
|
257
257
|
const app_name = workspace_app_name(inventory.root_dir);
|
|
258
|
-
//
|
|
258
|
+
// primo binds 0.0.0.0:8080 in its CMD; mount /app/pb_data on a persistent
|
|
259
259
|
// volume so the SQLite db + uploads survive restarts. Auto-start/stop keeps
|
|
260
260
|
// the small instance free-tier-friendly.
|
|
261
261
|
const fly_toml = `app = "${app_name}"
|
package/dist/commands/dev.js
CHANGED
|
@@ -33,7 +33,7 @@ let is_importing_library = false;
|
|
|
33
33
|
let has_pending_library_local_changes = false;
|
|
34
34
|
let site_sync_baselines = new Map();
|
|
35
35
|
// Tracks the last set of conflict paths logged per site so we don't reprint
|
|
36
|
-
// the same conflict block every pull cycle when
|
|
36
|
+
// the same conflict block every pull cycle when primo's serialization
|
|
37
37
|
// keeps producing the same divergence (e.g. data-key mangling, key reorder).
|
|
38
38
|
const last_logged_conflicts = new Map();
|
|
39
39
|
// Track files written by sync to prevent watcher from re-pushing them.
|
|
@@ -254,7 +254,7 @@ function hash_snapshot_content(contents) {
|
|
|
254
254
|
function snapshot_value(snapshot, file_path) {
|
|
255
255
|
return snapshot.has(file_path) ? snapshot.get(file_path) : null;
|
|
256
256
|
}
|
|
257
|
-
// Reads a file but treats ENOENT as a soft miss —
|
|
257
|
+
// Reads a file but treats ENOENT as a soft miss — primo' export step can
|
|
258
258
|
// reshape the on-disk layout (e.g. promoting pages/foo.yaml to
|
|
259
259
|
// pages/foo/index.yaml when a child route is added) between when a directory
|
|
260
260
|
// listing is captured and when each file is read. The vanished file isn't an
|
|
@@ -273,7 +273,7 @@ async function read_file_or_vanish(full_path, label) {
|
|
|
273
273
|
}
|
|
274
274
|
// A path is "in conflict" when local has content that differs from CMS AND
|
|
275
275
|
// the local content represents a real user change — not just CMS-side
|
|
276
|
-
// serialization noise (
|
|
276
|
+
// serialization noise (primo re-emits YAML with normalized key order,
|
|
277
277
|
// ISO-coerced dates, etc., so the CMS export legitimately differs from a
|
|
278
278
|
// freshly-scaffolded file forever, and we don't want to scream about that
|
|
279
279
|
// every pull cycle).
|
|
@@ -369,7 +369,7 @@ async function collect_directory_snapshot(current_dir, relative_dir, snapshot, o
|
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
async function fetch_cms_site_snapshot(site_dir, api_url, config, server_config, workspace_dir, temp_name) {
|
|
372
|
-
const response = await fetch_with_timeout(`${api_url}/api/
|
|
372
|
+
const response = await fetch_with_timeout(`${api_url}/api/primo/export/${config.site_id}`, {}, 15000);
|
|
373
373
|
if (!response.ok)
|
|
374
374
|
return null;
|
|
375
375
|
const temp_dir = path.join(site_dir, '.primo', temp_name);
|
|
@@ -572,19 +572,19 @@ export async function dev_server(options) {
|
|
|
572
572
|
}
|
|
573
573
|
}
|
|
574
574
|
// Ensure binary is installed
|
|
575
|
-
spinner.text = 'Checking
|
|
575
|
+
spinner.text = 'Checking primo...';
|
|
576
576
|
const binary_path = await ensure_binary();
|
|
577
577
|
// Create data directory in project folder
|
|
578
578
|
const data_dir = await ensure_data_dir(base_dir);
|
|
579
579
|
spinner.text = 'Starting CMS...';
|
|
580
580
|
// Start the CMS binary with dev mode enabled. PRIMO_AUTHOR_MODE
|
|
581
|
-
// tells
|
|
581
|
+
// tells primo which sync mode the CLI is running in so the CMS
|
|
582
582
|
// UI can gate its editable surfaces accordingly (read-only when
|
|
583
583
|
// the CLI is in --author files, since CMS edits would be discarded
|
|
584
584
|
// before they ever round-trip to disk).
|
|
585
585
|
cms_process = spawn(binary_path, ['serve', '--http', `127.0.0.1:${port}`, '--dir', data_dir], {
|
|
586
586
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
587
|
-
env: { ...process.env,
|
|
587
|
+
env: { ...process.env, PRIMO_DEV_MODE: '1', PRIMO_AUTHOR_MODE: sync_policy.mode }
|
|
588
588
|
});
|
|
589
589
|
// Capture stderr for errors
|
|
590
590
|
let stderr_output = '';
|
|
@@ -1119,11 +1119,11 @@ async function register_primo_mcp_server(base_dir) {
|
|
|
1119
1119
|
if (mcp_servers.primo !== undefined) {
|
|
1120
1120
|
return null;
|
|
1121
1121
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1122
|
+
// Default to the published package; PRIMO_MCP_LOCAL opts into a local dist build.
|
|
1123
|
+
const local_mcp = process.env.PRIMO_MCP_LOCAL;
|
|
1124
1124
|
mcp_servers.primo = local_mcp
|
|
1125
1125
|
? { command: 'node', args: [local_mcp] }
|
|
1126
|
-
: { command: 'npx', args: ['-y', '
|
|
1126
|
+
: { command: 'npx', args: ['-y', 'primo-mcp'] };
|
|
1127
1127
|
config.mcpServers = mcp_servers;
|
|
1128
1128
|
// Claude Code reads project-root .mcp.json. .primo/ is gitignored local
|
|
1129
1129
|
// state, so the discoverable root file is the right registration target.
|
|
@@ -1251,7 +1251,7 @@ function change_requires_reload(_dir, _filename) {
|
|
|
1251
1251
|
return true;
|
|
1252
1252
|
}
|
|
1253
1253
|
async function request_browser_reload(api_url) {
|
|
1254
|
-
await fetch_with_timeout(`${api_url}/api/
|
|
1254
|
+
await fetch_with_timeout(`${api_url}/api/primo/dev/reload`, {
|
|
1255
1255
|
method: 'POST'
|
|
1256
1256
|
}, 5000);
|
|
1257
1257
|
}
|
|
@@ -1870,7 +1870,7 @@ async function import_site_files(site_dir, api_url, config, port, server_config,
|
|
|
1870
1870
|
const import_form = new FormData();
|
|
1871
1871
|
import_form.append('file', new Blob([zip_buffer]), 'site.zip');
|
|
1872
1872
|
const request_started = Date.now();
|
|
1873
|
-
const import_response = await fetch_with_timeout(`${api_url}/api/
|
|
1873
|
+
const import_response = await fetch_with_timeout(`${api_url}/api/primo/import/${site_id}`, {
|
|
1874
1874
|
method: 'POST',
|
|
1875
1875
|
body: import_form
|
|
1876
1876
|
}, 300000);
|
|
@@ -1912,7 +1912,7 @@ async function import_site_files(site_dir, api_url, config, port, server_config,
|
|
|
1912
1912
|
form_data.append('file', new Blob([zip_buffer]), 'site.zip');
|
|
1913
1913
|
try {
|
|
1914
1914
|
const bootstrap_started = Date.now();
|
|
1915
|
-
const bootstrap_response = await fetch_with_timeout(`${api_url}/api/
|
|
1915
|
+
const bootstrap_response = await fetch_with_timeout(`${api_url}/api/primo/bootstrap`, {
|
|
1916
1916
|
method: 'POST',
|
|
1917
1917
|
body: form_data
|
|
1918
1918
|
}, 300000); // 300s timeout for imports
|
|
@@ -1944,7 +1944,7 @@ async function import_site_files(site_dir, api_url, config, port, server_config,
|
|
|
1944
1944
|
const import_form = new FormData();
|
|
1945
1945
|
import_form.append('file', new Blob([zip_buffer]), 'site.zip');
|
|
1946
1946
|
const import_started = Date.now();
|
|
1947
|
-
const import_response = await fetch_with_timeout(`${api_url}/api/
|
|
1947
|
+
const import_response = await fetch_with_timeout(`${api_url}/api/primo/import/${site_id}`, {
|
|
1948
1948
|
method: 'POST',
|
|
1949
1949
|
body: import_form
|
|
1950
1950
|
}, 300000); // 300s timeout for imports
|
|
@@ -2016,13 +2016,13 @@ async function import_library_files(base_dir, api_url, delete_group_ids = [], de
|
|
|
2016
2016
|
}));
|
|
2017
2017
|
}
|
|
2018
2018
|
const request_started = Date.now();
|
|
2019
|
-
const response = await fetch_with_timeout(`${api_url}/api/
|
|
2019
|
+
const response = await fetch_with_timeout(`${api_url}/api/primo/import-library`, {
|
|
2020
2020
|
method: 'POST',
|
|
2021
2021
|
body: form_data
|
|
2022
2022
|
}, 120000);
|
|
2023
2023
|
const request_ms = Date.now() - request_started;
|
|
2024
2024
|
if (response.status === 404) {
|
|
2025
|
-
throw new Error('Shared library sync is not supported by the current
|
|
2025
|
+
throw new Error('Shared library sync is not supported by the current primo binary/server. Rebuild or update primo to use library sync.');
|
|
2026
2026
|
}
|
|
2027
2027
|
if (!response.ok) {
|
|
2028
2028
|
const error_text = await response.text();
|
|
@@ -2146,7 +2146,7 @@ async function create_site_zip(dir, excluded_paths = new Set()) {
|
|
|
2146
2146
|
});
|
|
2147
2147
|
}
|
|
2148
2148
|
async function sync_from_cms(site_dir, api_url, config, server_config, workspace_dir, sync_policy = { mode: 'both' }) {
|
|
2149
|
-
const response = await fetch_with_timeout(`${api_url}/api/
|
|
2149
|
+
const response = await fetch_with_timeout(`${api_url}/api/primo/export/${config.site_id}`, {}, 15000);
|
|
2150
2150
|
if (!response.ok)
|
|
2151
2151
|
return;
|
|
2152
2152
|
const zip_data = await response.arrayBuffer();
|
|
@@ -2240,9 +2240,9 @@ async function sync_from_cms(site_dir, api_url, config, server_config, workspace
|
|
|
2240
2240
|
}
|
|
2241
2241
|
}
|
|
2242
2242
|
async function sync_library_from_cms(base_dir, api_url) {
|
|
2243
|
-
const response = await fetch_with_timeout(`${api_url}/api/
|
|
2243
|
+
const response = await fetch_with_timeout(`${api_url}/api/primo/export-library`, {}, 15000);
|
|
2244
2244
|
if (response.status === 404) {
|
|
2245
|
-
throw new Error('Shared library sync is not supported by the current
|
|
2245
|
+
throw new Error('Shared library sync is not supported by the current primo binary/server. Rebuild or update primo to use library sync.');
|
|
2246
2246
|
}
|
|
2247
2247
|
if (!response.ok)
|
|
2248
2248
|
return;
|
package/dist/commands/new.js
CHANGED
|
@@ -107,10 +107,14 @@ allowed_blocks:
|
|
|
107
107
|
`);
|
|
108
108
|
await fs.writeFile(path.join(site_dir, 'page-types', 'default', 'fields.yaml'), '[]\n');
|
|
109
109
|
await fs.writeFile(path.join(site_dir, 'page-types', 'default', 'layout.yaml'), `# Sections shared by every page of this type. Add blocks here to render
|
|
110
|
-
# the same header/footer across all pages of this type.
|
|
110
|
+
# the same header/footer across all pages of this type. Body sections are
|
|
111
|
+
# seeded onto each newly created page of this type (and locked when the type
|
|
112
|
+
# has no allowed_blocks).
|
|
111
113
|
#
|
|
112
114
|
# header:
|
|
113
115
|
# - block: site-header
|
|
116
|
+
# body:
|
|
117
|
+
# - block: hero
|
|
114
118
|
# footer:
|
|
115
119
|
# - block: site-footer
|
|
116
120
|
`);
|
|
@@ -43,11 +43,11 @@ export async function pull_library(options) {
|
|
|
43
43
|
const output_dir = path.resolve(options.output || '.');
|
|
44
44
|
await fs.mkdir(output_dir, { recursive: true });
|
|
45
45
|
spinner.text = 'Exporting library...';
|
|
46
|
-
const response = await fetch(`${server}/api/
|
|
46
|
+
const response = await fetch(`${server}/api/primo/export-library`, {
|
|
47
47
|
headers
|
|
48
48
|
});
|
|
49
49
|
if (response.status === 404) {
|
|
50
|
-
spinner.fail('Shared library sync is not supported by this
|
|
50
|
+
spinner.fail('Shared library sync is not supported by this primo server. Update the server before using `primo library pull`.');
|
|
51
51
|
process.exit(1);
|
|
52
52
|
}
|
|
53
53
|
if (!response.ok) {
|
package/dist/commands/pull.js
CHANGED
|
@@ -183,7 +183,7 @@ export async function pull_site(options) {
|
|
|
183
183
|
async function pull_one_site(server, headers, site, site_dir, spinner) {
|
|
184
184
|
await fs.mkdir(site_dir, { recursive: true });
|
|
185
185
|
spinner.text = `Exporting ${site.name}...`;
|
|
186
|
-
const response = await fetch(`${server}/api/
|
|
186
|
+
const response = await fetch(`${server}/api/primo/export/${site.id}`, { headers });
|
|
187
187
|
if (!response.ok) {
|
|
188
188
|
const error = await response.text();
|
|
189
189
|
throw new Error(`Export failed for ${site.name}: ${error}`);
|
|
@@ -205,7 +205,7 @@ async function pull_one_site(server, headers, site, site_dir, spinner) {
|
|
|
205
205
|
}
|
|
206
206
|
async function pull_library_into(server, headers, root_dir, spinner) {
|
|
207
207
|
spinner.start('Pulling library...');
|
|
208
|
-
const response = await fetch(`${server}/api/
|
|
208
|
+
const response = await fetch(`${server}/api/primo/export-library`, { headers });
|
|
209
209
|
if (response.status === 404) {
|
|
210
210
|
spinner.warn('Library export not supported by this server — skipping');
|
|
211
211
|
return false;
|
|
@@ -47,13 +47,13 @@ export async function push_library(options) {
|
|
|
47
47
|
if (token) {
|
|
48
48
|
headers.Authorization = `Bearer ${token}`;
|
|
49
49
|
}
|
|
50
|
-
const response = await fetch(`${server}/api/
|
|
50
|
+
const response = await fetch(`${server}/api/primo/import-library`, {
|
|
51
51
|
method: 'POST',
|
|
52
52
|
headers,
|
|
53
53
|
body: form_data
|
|
54
54
|
});
|
|
55
55
|
if (response.status === 404) {
|
|
56
|
-
spinner.fail('Shared library sync is not supported by this
|
|
56
|
+
spinner.fail('Shared library sync is not supported by this primo server. Update the server before using `primo library push`.');
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
59
59
|
if (!response.ok) {
|
package/dist/commands/push.js
CHANGED
|
@@ -275,8 +275,8 @@ async function push_single_site(site_dir, options, spinner) {
|
|
|
275
275
|
throw new Error(bootstrap_result.error);
|
|
276
276
|
}
|
|
277
277
|
const endpoint = options.preview
|
|
278
|
-
? `${server}/api/
|
|
279
|
-
: `${server}/api/
|
|
278
|
+
? `${server}/api/primo/import/${site_id}/preview`
|
|
279
|
+
: `${server}/api/primo/import/${site_id}`;
|
|
280
280
|
spinner.text = options.preview ? 'Previewing changes...' : 'Pushing changes...';
|
|
281
281
|
const form_data = new FormData();
|
|
282
282
|
form_data.append('file', new Blob([zip_buffer]), 'site.zip');
|
|
@@ -288,7 +288,7 @@ async function push_single_site(site_dir, options, spinner) {
|
|
|
288
288
|
body: form_data
|
|
289
289
|
});
|
|
290
290
|
// 404 from import means the site doesn't exist on the server yet. On a
|
|
291
|
-
// freshly-deployed server we can fall back to /api/
|
|
291
|
+
// freshly-deployed server we can fall back to /api/primo/bootstrap,
|
|
292
292
|
// which creates the site and ingests the zip in one shot. Bootstrap is
|
|
293
293
|
// only available when the server has zero sites — past the first site,
|
|
294
294
|
// new sites must be created via the dashboard UI.
|
|
@@ -343,7 +343,7 @@ async function try_bootstrap_site(server, token, zip_buffer, config, site_id, gr
|
|
|
343
343
|
const headers = {};
|
|
344
344
|
if (token)
|
|
345
345
|
headers['Authorization'] = `Bearer ${token}`;
|
|
346
|
-
const response = await fetch(`${server}/api/
|
|
346
|
+
const response = await fetch(`${server}/api/primo/bootstrap`, {
|
|
347
347
|
method: 'POST',
|
|
348
348
|
headers,
|
|
349
349
|
body: form
|
|
@@ -399,7 +399,7 @@ async function push_library_dir(root_dir, options, spinner) {
|
|
|
399
399
|
spinner.text = 'Pushing library...';
|
|
400
400
|
const form_data = new FormData();
|
|
401
401
|
form_data.append('file', new Blob([zip_buffer]), 'library.zip');
|
|
402
|
-
const response = await fetch(`${server}/api/
|
|
402
|
+
const response = await fetch(`${server}/api/primo/import-library`, {
|
|
403
403
|
method: 'POST',
|
|
404
404
|
headers: { 'Authorization': `Bearer ${token}` },
|
|
405
405
|
body: form_data
|
|
@@ -456,7 +456,7 @@ async function validate_page_types(site_dir) {
|
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
// layout.yaml is required — comment-only stub is fine, but the file
|
|
459
|
-
// must exist so the page type's
|
|
459
|
+
// must exist so the page type's header/body/footer slots are
|
|
460
460
|
// discoverable.
|
|
461
461
|
try {
|
|
462
462
|
await fs.access(layout_path);
|
|
@@ -464,7 +464,7 @@ async function validate_page_types(site_dir) {
|
|
|
464
464
|
catch {
|
|
465
465
|
errors.push({
|
|
466
466
|
file: `page-types/${page_type_name}/layout.yaml`,
|
|
467
|
-
message: 'Missing layout.yaml. Each page type needs one (use the comment-only stub if there are no shared header/footer sections yet).',
|
|
467
|
+
message: 'Missing layout.yaml. Each page type needs one (use the comment-only stub if there are no shared header/body/footer sections yet).',
|
|
468
468
|
severity: 'error'
|
|
469
469
|
});
|
|
470
470
|
}
|
package/dist/utils/binary.js
CHANGED
|
@@ -9,11 +9,10 @@ import ora from 'ora';
|
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const PRIMO_HOME = path.join(os.homedir(), '.primo');
|
|
11
11
|
const BIN_DIR = path.join(PRIMO_HOME, 'bin');
|
|
12
|
-
const
|
|
13
|
-
const VERSION = '3.2.0'; // matches palacms releases
|
|
12
|
+
const VERSION = '3.2.0'; // matches primo releases
|
|
14
13
|
// Path to locally built binary (for development)
|
|
15
|
-
// The binary is at
|
|
16
|
-
const LOCAL_BINARY = path.resolve(__dirname, '..', '..', '..', '
|
|
14
|
+
// The binary is at primo/primo (inside the primo repo directory)
|
|
15
|
+
const LOCAL_BINARY = path.resolve(__dirname, '..', '..', '..', 'primo', 'primo');
|
|
17
16
|
function get_platform() {
|
|
18
17
|
const platform = os.platform();
|
|
19
18
|
const arch = os.arch();
|
|
@@ -48,11 +47,24 @@ function get_platform() {
|
|
|
48
47
|
}
|
|
49
48
|
function get_download_url(platform) {
|
|
50
49
|
const base = 'https://github.com/primocms/primo/releases/download';
|
|
51
|
-
const filename = `
|
|
50
|
+
const filename = `primo_${platform.os}_${platform.arch}${platform.ext}`;
|
|
52
51
|
return `${base}/v${VERSION}/${filename}`;
|
|
53
52
|
}
|
|
54
53
|
export async function get_binary_path() {
|
|
55
|
-
//
|
|
54
|
+
// Explicit override wins — layout-independent, the way to point at a
|
|
55
|
+
// local server build regardless of where this CLI lives on disk.
|
|
56
|
+
const override = process.env.PRIMO_BINARY;
|
|
57
|
+
if (override) {
|
|
58
|
+
try {
|
|
59
|
+
await fs.access(override, fs.constants.X_OK);
|
|
60
|
+
return override;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error(`PRIMO_BINARY is set to "${override}" but it is not an executable file`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Otherwise prefer a sibling dev build (only resolves when running from
|
|
67
|
+
// source next to a `primo` checkout), then fall back to the download.
|
|
56
68
|
try {
|
|
57
69
|
await fs.access(LOCAL_BINARY, fs.constants.X_OK);
|
|
58
70
|
return LOCAL_BINARY;
|
|
@@ -60,7 +72,7 @@ export async function get_binary_path() {
|
|
|
60
72
|
catch { }
|
|
61
73
|
// Fall back to downloaded binary
|
|
62
74
|
const platform = get_platform();
|
|
63
|
-
return path.join(BIN_DIR, `
|
|
75
|
+
return path.join(BIN_DIR, `primo${platform.ext}`);
|
|
64
76
|
}
|
|
65
77
|
export async function ensure_data_dir(base_dir) {
|
|
66
78
|
const data_dir = path.join(base_dir, '.primo');
|
|
@@ -78,18 +90,23 @@ export async function is_binary_installed() {
|
|
|
78
90
|
}
|
|
79
91
|
}
|
|
80
92
|
export async function ensure_binary() {
|
|
93
|
+
// If PRIMO_BINARY is set, honor it exclusively — surface a bad override
|
|
94
|
+
// rather than silently downloading a release binary behind the user's back.
|
|
95
|
+
if (process.env.PRIMO_BINARY) {
|
|
96
|
+
return await get_binary_path();
|
|
97
|
+
}
|
|
81
98
|
if (await is_binary_installed()) {
|
|
82
99
|
return await get_binary_path();
|
|
83
100
|
}
|
|
84
101
|
// Need to download - get the target path
|
|
85
102
|
const platform = get_platform();
|
|
86
|
-
const binary_path = path.join(BIN_DIR, `
|
|
87
|
-
const spinner = ora('Setting up
|
|
103
|
+
const binary_path = path.join(BIN_DIR, `primo${platform.ext}`);
|
|
104
|
+
const spinner = ora('Setting up Primo...').start();
|
|
88
105
|
try {
|
|
89
106
|
// Create directories
|
|
90
107
|
await fs.mkdir(BIN_DIR, { recursive: true });
|
|
91
108
|
const url = get_download_url(platform);
|
|
92
|
-
spinner.text = `Downloading
|
|
109
|
+
spinner.text = `Downloading primo for ${platform.os}/${platform.arch}...`;
|
|
93
110
|
// Download binary
|
|
94
111
|
const response = await fetch(url);
|
|
95
112
|
if (!response.ok) {
|
|
@@ -100,7 +117,7 @@ export async function ensure_binary() {
|
|
|
100
117
|
await pipeline(response.body, file_stream);
|
|
101
118
|
// Make executable
|
|
102
119
|
await fs.chmod(binary_path, 0o755);
|
|
103
|
-
spinner.succeed('
|
|
120
|
+
spinner.succeed('Primo setup complete');
|
|
104
121
|
return binary_path;
|
|
105
122
|
}
|
|
106
123
|
catch (error) {
|
|
@@ -108,16 +125,16 @@ export async function ensure_binary() {
|
|
|
108
125
|
// Provide manual instructions
|
|
109
126
|
console.log('');
|
|
110
127
|
console.log(chalk.yellow('To install manually:'));
|
|
111
|
-
console.log(chalk.dim(' 1. Download
|
|
128
|
+
console.log(chalk.dim(' 1. Download primo from https://github.com/primocms/primo/releases'));
|
|
112
129
|
console.log(chalk.dim(` 2. Place it in ${BIN_DIR}`));
|
|
113
|
-
console.log(chalk.dim(' 3. Make it executable: chmod +x
|
|
130
|
+
console.log(chalk.dim(' 3. Make it executable: chmod +x primo'));
|
|
114
131
|
console.log('');
|
|
115
132
|
throw error;
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
135
|
export async function get_binary_version() {
|
|
119
136
|
try {
|
|
120
|
-
const binary_path = get_binary_path();
|
|
137
|
+
const binary_path = await get_binary_path();
|
|
121
138
|
const { execSync } = await import('child_process');
|
|
122
139
|
const output = execSync(`"${binary_path}" --version`, { encoding: 'utf-8' });
|
|
123
140
|
return output.trim();
|