Skip to content
Merged

Dev #37

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1f3f427
chore: update sync-versions script path and add TypeScript configurat…
TrueNine Feb 22, 2026
26913ac
refactor: move init-bundle from packages/ to libraries/ (9 renamed, 1…
TrueNine Feb 22, 2026
5896426
chore: add Cargo build configuration and cleanup public files (3 adde…
TrueNine Feb 22, 2026
1f83ebb
chore: add Rust CLI bridge and commands (23 added, 2 modified)
TrueNine Feb 22, 2026
a1db197
refactor: move logger from packages/ to libraries/ with Rust lib (6 a…
TrueNine Feb 22, 2026
f662d9b
refactor: move md-compiler from packages/ to libraries/ with Rust lib…
TrueNine Feb 22, 2026
6d3ea68
refactor: add init-bundle library with Rust support (10 added)
TrueNine Feb 22, 2026
5c6b682
chore: add plugin-input-shared-ignore and update plugin versions (7 a…
TrueNine Feb 22, 2026
be85fe9
build: add scripts for native build and NAPI handling (4 added)
TrueNine Feb 22, 2026
42343bb
refactor: add libraries for config, input-plugins, and plugin-shared …
TrueNine Feb 22, 2026
2109530
ci: add release-cli-binary and release-cli-napi workflows (2 added, 4…
TrueNine Feb 22, 2026
5da32d7
chore: update root package.json
TrueNine Feb 22, 2026
751c761
chore: update lockfiles and workspace config (3 modified)
TrueNine Feb 22, 2026
f6c242d
chore: add IDE config files (6 added, 1 modified)
TrueNine Feb 22, 2026
0012abf
chore: update cli/src/config.ts (1 modified)
TrueNine Feb 22, 2026
a867ab4
chore: update package versions and configs across workspace (54 modif…
TrueNine Feb 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 79 additions & 16 deletions .git-hooks/sync-versions.ts → .githooks/sync-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Version Sync Script
* Auto-sync all sub-package versions before commit
*/
import { readFileSync, writeFileSync } from 'node:fs'
import { readFileSync, writeFileSync, readdirSync, existsSync, statSync } from 'node:fs'
import { execSync } from 'node:child_process'
import { resolve } from 'node:path'
import { resolve, join } from 'node:path'
import process from 'node:process'

interface PackageEntry {
Expand Down Expand Up @@ -47,21 +47,74 @@ const packages: readonly PackageEntry[] = [
{ path: 'doc/package.json', name: 'doc' },
]

let changed = false
// Discover all libraries and their npm sub-packages
function discoverLibraryPackages(): PackageEntry[] {
const entries: PackageEntry[] = []
const librariesDir = resolve('libraries')
if (!existsSync(librariesDir)) return entries
for (const lib of readdirSync(librariesDir)) {
const libDir = join(librariesDir, lib)
if (!statSync(libDir).isDirectory()) continue
const libPkg = join(libDir, 'package.json')
if (existsSync(libPkg)) {
entries.push({ path: `libraries/${lib}/package.json`, name: `lib:${lib}` })
}
}
return entries
}

for (const pkg of packages) {
const fullPath = resolve(pkg.path)
const content = readFileSync(fullPath, 'utf-8')
const pkgJson: PackageJson = JSON.parse(content)
// Discover npm platform sub-packages under a given directory (e.g. cli/npm/)
function discoverNpmSubPackages(baseDir: string, prefix: string): PackageEntry[] {
const entries: PackageEntry[] = []
const npmDir = resolve(baseDir, 'npm')
if (!existsSync(npmDir) || !statSync(npmDir).isDirectory()) return entries
for (const platform of readdirSync(npmDir)) {
const platformDir = join(npmDir, platform)
if (!statSync(platformDir).isDirectory()) continue
const platformPkg = join(platformDir, 'package.json')
if (existsSync(platformPkg)) {
entries.push({ path: `${baseDir}/npm/${platform}/package.json`, name: `${prefix}/${platform}` })
}
}
return entries
}

if (pkgJson.version !== rootVersion) {
console.log(` ✓ ${pkg.name}: version ${pkgJson.version} → ${rootVersion}`)
pkgJson.version = rootVersion
changed = true
// Discover all packages under packages/
function discoverPackagesDir(): PackageEntry[] {
const entries: PackageEntry[] = []
const packagesDir = resolve('packages')
if (!existsSync(packagesDir)) return entries
for (const pkg of readdirSync(packagesDir)) {
const pkgDir = join(packagesDir, pkg)
if (!statSync(pkgDir).isDirectory()) continue
const pkgFile = join(pkgDir, 'package.json')
if (existsSync(pkgFile)) {
entries.push({ path: `packages/${pkg}/package.json`, name: `pkg:${pkg}` })
}
}
return entries
}

const libraryPackages = discoverLibraryPackages()
const packagesPackages = discoverPackagesDir()
const cliNpmPackages = discoverNpmSubPackages('cli', 'cli-napi')

let changed = false

for (const pkg of [...packages, ...libraryPackages, ...packagesPackages, ...cliNpmPackages]) {
const fullPath = resolve(pkg.path)
try {
const content = readFileSync(fullPath, 'utf-8').replace(/^\uFEFF/, '')
const pkgJson: PackageJson = JSON.parse(content)

if (changed) {
writeFileSync(fullPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8')
if (pkgJson.version !== rootVersion) {
console.log(` ✓ ${pkg.name}: version ${pkgJson.version} → ${rootVersion}`)
pkgJson.version = rootVersion
writeFileSync(fullPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8')
changed = true
}
} catch {
console.log(`⚠️ ${pkg.path} not found or invalid, skipping`)
}
}

Expand Down Expand Up @@ -96,8 +149,7 @@ try {

// Sync version field in tnmsc.example.json files
const exampleConfigPaths = [
'cli/public/tnmsc.example.json',
'packages/init-bundle/public/public/tnmsc.example.json',
'libraries/init-bundle/public/public/tnmsc.example.json',
]

for (const examplePath of exampleConfigPaths) {
Expand All @@ -119,8 +171,19 @@ for (const examplePath of exampleConfigPaths) {
if (changed) {
console.log('\n📦 Versions synced, auto-staging changes...')
try {
const filesToStage = [
'cli/package.json',
'gui/package.json',
'doc/package.json',
'gui/src-tauri/Cargo.toml',
'gui/src-tauri/tauri.conf.json',
'libraries/init-bundle/public/public/tnmsc.example.json',
...libraryPackages.map(p => p.path),
...packagesPackages.map(p => p.path),
...cliNpmPackages.map(p => p.path),
]
execSync(
'git add cli/package.json gui/package.json doc/package.json gui/src-tauri/Cargo.toml gui/src-tauri/tauri.conf.json cli/public/tnmsc.example.json packages/init-bundle/public/public/tnmsc.example.json',
`git add ${filesToStage.join(' ')}`,
{ stdio: 'inherit' }
)
console.log('✅ Staged modified files')
Expand Down
File renamed without changes.
19 changes: 18 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4

- name: Install GTK development dependencies
run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libglib2.0-dev pkg-config
run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libglib2.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf pkg-config

- name: Setup pnpm
uses: pnpm/action-setup@v4
Expand Down Expand Up @@ -46,3 +46,20 @@ jobs:

- name: Typecheck
run: pnpm exec turbo run typecheck

- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-ci-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-ci-

- name: Rust tests (excluding GUI)
run: cargo test --workspace --exclude memory-sync-gui
140 changes: 140 additions & 0 deletions .github/workflows/release-cli-binary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Release CLI Binary

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || github.run_id }}
cancel-in-progress: true

on:
workflow_call:
inputs:
version:
required: true
type: string
workflow_dispatch:
inputs:
version:
description: 'Version to release (without v prefix, e.g. 2026.10222.0)'
required: true
type: string

permissions:
contents: read

jobs:
build-cli-binary:
strategy:
fail-fast: false
matrix:
include:
- platform: ubuntu-24.04
target: x86_64-unknown-linux-gnu
binary: tnmsc
archive: tnmsc-linux-x86_64.tar.gz
- platform: ubuntu-24.04
target: aarch64-unknown-linux-gnu
binary: tnmsc
archive: tnmsc-linux-aarch64.tar.gz
cross: true
- platform: macos-14
target: aarch64-apple-darwin
binary: tnmsc
archive: tnmsc-darwin-aarch64.tar.gz
- platform: macos-14
target: x86_64-apple-darwin
binary: tnmsc
archive: tnmsc-darwin-x86_64.tar.gz
- platform: windows-latest
target: x86_64-pc-windows-msvc
binary: tnmsc.exe
archive: tnmsc-windows-x86_64.zip

runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4

# 1. Build plugin-runtime.mjs first (needed for embedded-runtime feature)
- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 25

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install & bundle plugin-runtime
shell: bash
run: |
pnpm install --frozen-lockfile
pnpm exec turbo run build --filter=@truenine/memory-sync-cli...
ls -la cli/dist/plugin-runtime.mjs

# 2. Build Rust binary with embedded plugin-runtime.mjs
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Install cross-compilation tools (aarch64-linux)
if: matrix.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV

- name: Cache cargo registry & target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.target }}-cargo-cli-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-cargo-cli-

- name: Build tnmsc binary (release, with embedded runtime)
run: cargo build --release --target ${{ matrix.target }} -p tnmsc --features embedded-runtime

- name: Run tests (native only)
if: ${{ !matrix.cross }}
run: cargo test --release --target ${{ matrix.target }} -p tnmsc --features embedded-runtime

# 3. Package binary + plugin-runtime.mjs
- name: Package (unix)
if: runner.os != 'Windows'
shell: bash
run: |
mkdir -p staging
cp target/${{ matrix.target }}/release/${{ matrix.binary }} staging/
cp cli/dist/plugin-runtime.mjs staging/
cd staging
tar czf ../${{ matrix.archive }} *

- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item "target/${{ matrix.target }}/release/${{ matrix.binary }}" staging/
Copy-Item "cli/dist/plugin-runtime.mjs" staging/
Compress-Archive -Path staging/* -DestinationPath ${{ matrix.archive }}

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: cli-${{ matrix.target }}
path: ${{ matrix.archive }}
if-no-files-found: error
Loading
Loading