Skip to content

Commit 10f1061

Browse files
committed
fix: restore npm entrypoints for cli and mcp
1 parent f116d97 commit 10f1061

34 files changed

Lines changed: 504 additions & 110 deletions

File tree

.githooks/sync-versions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ export function runSyncVersions(options: SyncVersionsOptions = {}): SyncVersions
411411

412412
validateVersion(currentRootVersion, 'root package.json')
413413

414+
const target = resolveTargetVersion(rootDir, currentRootVersion, options.requestedVersion)
415+
const changedPaths = new Set<string>()
416+
417+
syncJsonVersion(rootPackagePath, target.version, changedPaths)
418+
414419
const packageJsonPaths = discoverFilesByName(rootDir, 'package.json')
415420
.filter(filePath => resolve(filePath) !== rootPackagePath)
416421
.sort()

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ jobs:
7676
- name: Rust unit tests
7777
run: cargo test --workspace --exclude tnmsg --exclude tnmsc-integrate-tests --exclude tnmsc-local-tests --exclude tnmsm-integrate-tests --lib --bins
7878

79+
packaging-smoke:
80+
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
81+
runs-on: ubuntu-24.04
82+
timeout-minutes: 45
83+
steps:
84+
- uses: actions/checkout@v6
85+
86+
- uses: ./.github/actions/setup-node-pnpm
87+
88+
- uses: ./.github/actions/setup-rust
89+
with:
90+
cache-key: ci-packaging-smoke
91+
92+
- name: CLI packaging smoke
93+
run: cargo test -p tnmsc-integrate-tests packaging_smoke_covers_release_binary_and_global_install -- --exact --nocapture
94+
95+
- name: MCP packaging smoke
96+
run: cargo test -p tnmsm-integrate-tests packaging_smoke_covers_release_binary_and_global_install -- --exact --nocapture
97+
7998
gui-smoke:
8099
needs: changes
81100
if: |

.github/workflows/release.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,15 @@ jobs:
306306
- name: Build CLI package
307307
run: cargo build --release -p tnmsc
308308

309+
- name: Smoke test CLI main package
310+
shell: bash
311+
run: |
312+
set -euo pipefail
313+
npm install -g ./cli
314+
command -v tnmsc
315+
tnmsc help >/tmp/tnmsc-help.txt
316+
grep -q 'install' /tmp/tnmsc-help.txt
317+
309318
- name: Publish CLI package
310319
uses: ./.github/actions/npm-publish-package
311320
with:
@@ -382,6 +391,15 @@ jobs:
382391
- name: Build MCP package
383392
run: cargo build --release -p tnmsm
384393

394+
- name: Smoke test MCP main package
395+
shell: bash
396+
run: |
397+
set -euo pipefail
398+
npm install -g ./mcp
399+
command -v tnmsm
400+
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | tnmsm >/tmp/tnmsm-initialize.json
401+
grep -q '"jsonrpc":"2.0"' /tmp/tnmsm-initialize.json
402+
385403
- name: Publish MCP package
386404
uses: ./.github/actions/npm-publish-package
387405
with:

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ members = [
2929
]
3030

3131
[workspace.package]
32-
version = "2026.10422.10749"
32+
version = "2026.10422.11816"
3333
edition = "2024"
3434
rust-version = "1.88"
3535
license = "AGPL-3.0-only"

cli/.npmignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
*
2+
!bin
3+
!bin/
4+
!bin/tnmsc.js
25
!schema
36
!schema/
47
!schema/tnmsc.schema.json

cli/bin/tnmsc.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
4+
const {spawnSync} = require('node:child_process');
5+
const fs = require('node:fs');
6+
const path = require('node:path');
7+
8+
const PACKAGE_NAME = '@truenine/memory-sync-cli';
9+
const BINARY_NAME = 'tnmsc';
10+
const SUPPORTED_TARGETS = [
11+
'linux-x64-gnu',
12+
'linux-arm64-gnu',
13+
'darwin-x64',
14+
'darwin-arm64',
15+
'win32-x64-msvc',
16+
].join(', ');
17+
18+
const PLATFORM_PACKAGES = {
19+
darwin: {
20+
arm64: '@truenine/memory-sync-cli-darwin-arm64',
21+
x64: '@truenine/memory-sync-cli-darwin-x64',
22+
},
23+
linux: {
24+
arm64: '@truenine/memory-sync-cli-linux-arm64-gnu',
25+
x64: '@truenine/memory-sync-cli-linux-x64-gnu',
26+
},
27+
win32: {
28+
x64: '@truenine/memory-sync-cli-win32-x64-msvc',
29+
},
30+
};
31+
32+
function fail(message) {
33+
console.error(`${PACKAGE_NAME}: ${message}`);
34+
process.exit(1);
35+
}
36+
37+
function detectLinuxLibc() {
38+
const report = process.report;
39+
if (report == null || typeof report.getReport !== 'function') {
40+
return 'unknown';
41+
}
42+
43+
const header = report.getReport()?.header;
44+
if (header == null || typeof header !== 'object') {
45+
return 'unknown';
46+
}
47+
48+
if (header.glibcVersionRuntime || header.glibcVersionCompiler) {
49+
return 'glibc';
50+
}
51+
52+
return 'unknown';
53+
}
54+
55+
function resolvePlatformPackageName() {
56+
const archMap = PLATFORM_PACKAGES[process.platform];
57+
if (archMap == null) {
58+
fail(
59+
`Unsupported platform ${process.platform}/${process.arch}. Supported npm targets: ${SUPPORTED_TARGETS}.`,
60+
);
61+
}
62+
63+
const packageName = archMap[process.arch];
64+
if (packageName == null) {
65+
fail(
66+
`Unsupported architecture ${process.platform}/${process.arch}. Supported npm targets: ${SUPPORTED_TARGETS}.`,
67+
);
68+
}
69+
70+
if (process.platform === 'linux' && detectLinuxLibc() !== 'glibc') {
71+
fail(
72+
'Linux npm binaries currently require glibc. musl/Alpine environments are not supported by the published packages.',
73+
);
74+
}
75+
76+
return packageName;
77+
}
78+
79+
function readJson(filePath) {
80+
try {
81+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
82+
} catch (error) {
83+
fail(`Failed to read ${filePath}: ${error.message}`);
84+
}
85+
}
86+
87+
function resolveBinaryPath(packageName) {
88+
let manifestPath;
89+
try {
90+
manifestPath = require.resolve(`${packageName}/package.json`);
91+
} catch (error) {
92+
fail(
93+
`Missing optional native package ${packageName}. Reinstall ${PACKAGE_NAME} on a supported platform so npm can fetch the matching binary package. Original error: ${error.message}`,
94+
);
95+
}
96+
97+
const manifest = readJson(manifestPath);
98+
const packageDir = path.dirname(manifestPath);
99+
const binField = manifest.bin;
100+
let relativeBinaryPath;
101+
102+
if (typeof binField === 'string') {
103+
relativeBinaryPath = binField;
104+
} else if (binField != null && typeof binField === 'object') {
105+
if (typeof binField[BINARY_NAME] === 'string') {
106+
relativeBinaryPath = binField[BINARY_NAME];
107+
} else {
108+
relativeBinaryPath = Object.values(binField).find(value => typeof value === 'string');
109+
}
110+
}
111+
112+
if (typeof relativeBinaryPath !== 'string' || relativeBinaryPath.length === 0) {
113+
fail(`Package ${packageName} does not declare a ${BINARY_NAME} binary entry.`);
114+
}
115+
116+
const binaryPath = path.resolve(packageDir, relativeBinaryPath);
117+
if (!fs.existsSync(binaryPath)) {
118+
fail(
119+
`Native binary ${binaryPath} is missing from ${packageName}. Reinstall ${PACKAGE_NAME} and try again.`,
120+
);
121+
}
122+
123+
return binaryPath;
124+
}
125+
126+
function runNativeBinary(binaryPath) {
127+
const result = spawnSync(binaryPath, process.argv.slice(2), {
128+
env: process.env,
129+
stdio: 'inherit',
130+
});
131+
132+
if (result.error != null) {
133+
fail(`Failed to launch ${binaryPath}: ${result.error.message}`);
134+
}
135+
136+
if (typeof result.status === 'number') {
137+
process.exit(result.status);
138+
}
139+
140+
if (result.signal != null) {
141+
process.kill(process.pid, result.signal);
142+
return;
143+
}
144+
145+
process.exit(1);
146+
}
147+
148+
runNativeBinary(resolveBinaryPath(resolvePlatformPackageName()));

0 commit comments

Comments
 (0)