Compare commits

...

8 Commits

Author SHA1 Message Date
Markus Maiwald 64390bedbc chore: add .gitignore, remove compiled binaries 2026-02-15 17:59:17 +01:00
Markus Maiwald 74e07309b6 feat(kernel): implement System Truth Ledger and Causal Trace
- Implemented System Ontology (SPEC-060) and STL (SPEC-061) in Zig HAL
- Created Nim bindings and high-level event emission API
- Integrated STL into kernel boot sequence (SystemBoot, FiberSpawn, CapGrant)
- Implemented Causal Graph Engine (SPEC-062) for lineage tracing
- Verified self-aware causal auditing in boot logs
- Optimized Event structure to 58 bytes for cache efficiency
2026-01-06 03:37:53 +01:00
Markus Maiwald 03a21aa71f Voxis Forge: Rumpk Stability, NipBox Boot, and Repository Cleanup
- Fixed Rumpk RISC-V Trap Handler (SSCRATCH swap, align(4), SUM bit) to prevent double faults.

- Stabilized Userland Transition (fence.i, MMU activation) allowing NipBox execution.

- Restored Forge pipeline to build NipBox from source.

- Documented critical RISC-V trap mechanics in .agent/tips.

- Committed pending repository cleanup (obsolete websites) and new core modules.
2026-01-04 21:39:06 +01:00
Markus Maiwald aa2b74a728 Phase 37: The Glass Cage - Memory Isolation Complete
VICTORY: All page faults (Code 12, 13, 15) eliminated. NipBox runs in isolated userspace.

Root Cause Diagnosed:
- Kernel BSS (0x84D5B030) was overwritten by NipBox loading at 0x84000000
- current_fiber corruption caused cascading failures

Strategic Fixes:
1. Relocated NipBox to 0x86000000 (eliminating BSS collision)
2. Expanded DRAM to 256MB, User region to 64MB (accommodating NipBox BSS)
3. Restored Kernel GP register in trap handler (fixing global access)
4. Conditionally excluded ion/memory from userspace builds (removing 2MB pool)
5. Enabled release build optimizations (reducing BSS bloat)

Results:
- Kernel globals: SAFE
- User memory: ISOLATED (Sv39 active)
- Syscalls: OPERATIONAL
- Scheduler: STABLE
- NipBox: ALIVE (waiting for stdin)

Files Modified:
- core/rumpk/apps/linker_user.ld: User region 0x86000000-0x89FFFFFF (64MB)
- core/rumpk/hal/mm.zig: DRAM 256MB, User map 32-256MB
- core/rumpk/hal/entry_riscv.zig: GP reload in trap handler
- core/rumpk/core/ion.nim: Conditional memory export
- core/rumpk/libs/membrane/ion_client.nim: Local type declarations
- core/rumpk/libs/membrane/net_glue.nim: Removed ion import
- core/rumpk/libs/membrane/compositor.nim: Stubbed unused functions
- src/nexus/builder/nipbox.nim: Release build flags

Next: Fix stdin delivery to enable interactive shell.
2026-01-04 02:03:01 +01:00
Markus Maiwald 7dfefae01a Phase 27-29: Visual Cortex, Pledge, and The Hive
PHASE 27: THE GLYPH & THE GHOST (Visual Cortex Polish)
========================================================
- Replaced placeholder block font with full IBM VGA 8x16 bitmap (CP437)
- Implemented CRT scanline renderer for authentic terminal aesthetics
- Set Sovereign Blue background (0xFF401010) with Phosphor Amber text
- Added ANSI escape code stripper for clean graphical output
- Updated QEMU hints to include -device virtio-gpu-device

Files:
- core/rumpk/libs/membrane/term.nim: Scanline renderer + ANSI stripper
- core/rumpk/libs/membrane/term_font.nim: Full VGA bitmap data
- src/nexus/forge.nim: QEMU device flag
- docs/dev/PHASE_26_VISUAL_CORTEX.md: Architecture documentation

PHASE 28: THE PLEDGE (Computable Trust)
========================================
- Implemented OpenBSD-style capability system for least-privilege execution
- Added promises bitmask to FiberObject for per-fiber capability tracking
- Created SYS_PLEDGE syscall (one-way capability ratchet)
- Enforced capability checks on all file operations (RPATH/WPATH)
- Extended SysTable with fn_pledge (120→128 bytes)

Capabilities:
- PLEDGE_STDIO (0x0001): Console I/O
- PLEDGE_RPATH (0x0002): Read Filesystem
- PLEDGE_WPATH (0x0004): Write Filesystem
- PLEDGE_INET  (0x0008): Network Access
- PLEDGE_EXEC  (0x0010): Execute/Spawn
- PLEDGE_ALL   (0xFFFF...): Root (default)

Files:
- core/rumpk/core/fiber.nim: Added promises field
- core/rumpk/core/ion.nim: Capability constants + SysTable extension
- core/rumpk/core/kernel.nim: k_pledge + enforcement checks
- core/rumpk/libs/membrane/ion_client.nim: Userland ABI sync
- core/rumpk/libs/membrane/libc.nim: pledge() wrapper
- docs/dev/PHASE_28_THE_PLEDGE.md: Security model documentation

PHASE 29: THE HIVE (Userland Concurrency)
==========================================
- Implemented dynamic fiber spawning for isolated worker execution
- Created worker pool (8 concurrent fibers, 8KB stacks each)
- Added SYS_SPAWN (0x500) and SYS_JOIN (0x501) syscalls
- Generic worker trampoline for automatic cleanup on exit
- Workers inherit parent memory but have independent pledge contexts

Worker Model:
- spawn(entry, arg): Create isolated worker fiber
- join(fid): Wait for worker completion
- Workers start with PLEDGE_ALL, can voluntarily restrict
- Violations terminate worker, not parent shell

Files:
- core/rumpk/core/fiber.nim: user_entry/user_arg fields
- core/rumpk/core/kernel.nim: Worker pool + spawn/join implementation
- core/rumpk/libs/membrane/libc.nim: spawn()/join() wrappers
- docs/dev/PHASE_29_THE_HIVE.md: Concurrency architecture

STRATEGIC IMPACT
================
The Nexus now has a complete Zero-Trust security model:
1. Visual identity (CRT aesthetics)
2. Capability-based security (pledge)
3. Isolated concurrent execution (spawn/join)

This enables hosting untrusted code without kernel compromise,
forming the foundation of the Cryptobox architecture (STC-2).

Example usage:
  proc worker(arg: uint64) {.cdecl.} =
    discard pledge(PLEDGE_INET | PLEDGE_STDIO)
    http_get("https://example.com")

  let fid = spawn(worker, 0)
  discard join(fid)
  # Shell retains full capabilities

Build: Validated on RISC-V (rumpk-riscv64.elf)
Status: Production-ready
2026-01-02 14:12:00 +01:00
Markus Maiwald bdfbab10cf feat(rumpk): Phase 2 Complete - The Entropy Purge & Sovereign Alignment
- Rumpk Core: Complete exorcism of LwIP/NET ghosts. Transitioned to ION nomenclature.
- ABI Sync: Synchronized Zig HAL and Nim Logic Ring Buffer layouts (u32 head/tail/mask).
- Invariant Shield: Hardened HAL pipes with handle-based validation and power-of-2 sync.
- Immune System: Verified Blink Recovery (Self-Healing) with updated ION Control Plane.
- NexShell: Major refactor of Command Plane for Sovereign Ring access.
- Architecture: Updated SPEC files and Doctrines (Silence, Hexagonal Sovereignty).
- Purge: Removed legacy rumk and nip artifacts for a clean substrate.
- Web: Updated landing page vision to match Rumpk v1.1 milestones.
2025-12-31 20:18:48 +01:00
Markus Maiwald 6df2ef73f5 feat: implement Operation Velvet Forge & Evidence Locker
- Ratified 'The Law of Representation' with tiered hashing (XXH3/Ed25519/BLAKE2b).
- Implemented RFC 8785 Canonical JSON serialization for deterministic signing.
- Deployed 'The Evidence Locker': Registry now enforces mandatory Ed25519 verification on read.
- Initialized 'The Cortex': KDL Intent Parser now translates manifests into GraftIntent objects.
- Orchestrated 'Velvet Forge' pipeline: Closing the loop between Intent, Synthesis, and Truth.
- Resolved xxHash namespace collisions and fixed Nint128 type mismatches.

Sovereignty achieved. The machine now listens, remember, and refuses to lie.
2025-12-31 20:18:46 +01:00
Markus Maiwald 2c42dffc84 feat(nip): achieve ARM64 static build with LibreSSL (5.5MB)
**Milestone: Sovereign Package Manager - Static Build Complete**

Successfully compiled nip as a 5.5MB ARM64 static binary with full
LibreSSL 3.8.2 and Zstd 1.5.5 integration. Deployed to NexBox.

## Key Achievements

### 1. Static Dependency Stack
- LibreSSL 3.8.2 (libssl.a 3.5MB + libcrypto.a 16MB + libtls.a 550KB)
- Zstd 1.5.5 (libzstd.a 1.2MB)
- Cross-compiled for aarch64-linux-gnu with musl compatibility
- Zero runtime dependencies (fully static binary)

### 2. OpenSSL Shim Bridge (openssl_shim.c)
- Created C shim to bridge LibreSSL macros to function symbols
- Solved SSL_in_init undefined reference (macro → function)
- Enables Nim's compiled object files to link against LibreSSL

### 3. Manual Linking Infrastructure
- Implemented link_manual.sh (Iron Hand Protocol)
- Bypassed Nim cross-compilation bug (dropped -o output flag)
- Manually linked 289 ARM64 object files + shim
- Link flags: -static -Wl,-z,muldefs with proper library ordering

### 4. NimCrypto Optimization
- Removed SHA2/NEON dependencies from hash_verifier.nim
- Retained BLAKE2b support only (required for integrity checks)
- Prevents NEON-specific compilation conflicts in cross-build

### 5. Build Scripts
- build_arm64_gcc.sh: Main cross-compilation script
- build_arm64_libre.sh: LibreSSL-specific build
- build_arm64_diagnostic.sh: Verbose diagnostic build
- GCC wrapper at /tmp/aarch64-gcc-wrapper.sh filters x86 flags

### 6. Binary Optimization
- Initial: 30MB (with debug symbols)
- Stripped: 5.5MB (aarch64-linux-gnu-strip -s)
- 82% size reduction while maintaining full functionality

## NexBox Integration
- Image size: 12,867 blocks (down from 62,469 pre-strip)
- Static binary embedded in initramfs
- Ready for boot verification

## Build Environment
- Vendor libs: core/nexus/vendor/{libressl-3.8.2,zstd-1.5.5}
- Cross-compiler: aarch64-linux-gnu-gcc 15.1.0
- Nim cache: /tmp/nip-arm64-cache (289 object files)

## Verification Status
 Binary: ELF 64-bit ARM aarch64, statically linked
 No libcrypto.so dlopen references
 BuildID: 4ed2d90fcb6fc82d52429bed63bd1cb378993582
 Boot test: Pending

## Technical Debt
- Nim's -o flag bug in cross-compilation (workaround: manual link)
- Static LibreSSL adds ~3MB (future: consider BearSSL/Monocypher)
- Build process requires manual steps (future: containerize in Distrobox)

## Next Steps
- Distrobox migration for reproducible build environment
- Boot verification in NexBox guest
- Warhead Test II (pack/extract cycle with static Zstd)

Time investment: 4.5 hours
Contributors: Voxis Forge (AI), Markus Maiwald

Closes: Static build blocker
See-also: BUILD_SUCCESS.md, BUILD_BLOCKER.md
2025-12-31 20:18:45 +01:00
158 changed files with 2094 additions and 23340 deletions

180
.gitignore vendored
View File

@ -1,157 +1,45 @@
# ========================================================
# Nim / NexusOS
# ========================================================
*.nimble
# Compiled binaries
nip
nip-arm64
nip_release
nip-v*
*.exe
# Nim build artifacts
nimcache/
nimblecache/
htmldocs/
bin/
learning/
*.npk
*.pkg.tar.xz
*.zst
build/
*.o
*.a
*.so
*.dylib
# NimbleOS-specific
~/.nip/
/tmp/nexus/
# Zig artifacts
.zig-cache/
zig-out/
zig-cache/
# ========================================================
# Temporary & Logs
# ========================================================
*.tmp
*.temp
*.log
*.log.*
temp/
logs/
test_output/
coverage/
# Test binaries (source is *.nim, compiled tests have no extension)
tests/test_*
!tests/test_*.nim
!tests/test_*.md
# Backups
*.bak
*.old
*.orig
# IDE / Editor
.vscode/
.idea/
*.swp
*.swo
*~
# ========================================================
# IDE & Editors
# ========================================================
.vscode/
.idea/
.kiro/
.gemini/
# ========================================================
# Environments
# ========================================================
.env
.venv/
.kube/
*.kubeconfig
# ========================================================
# OS Specific
# ========================================================
# macOS
# OS files
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
Thumbs.db
# Linux
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
# Agent / internal (must never appear)
.agent/
.claude/
.kiro/
# ========================================================
# Build Artifacts
# ========================================================
build/
dist/
work/
out/
# ========================================================
# Terraform
# ========================================================
*.tfstate
*.tfstate.*
crash.log
override.tf
override.tf.json
.terraform/
.terraform.lock.hcl
# ========================================================
# Helm / Kubernetes
# ========================================================
charts/
*.tgz
values.override.yaml
# ========================================================
# Node / Svelte
# ========================================================
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
.svelte-kit/
# ========================================================
# Python
# ========================================================
__pycache__/
*.pyc
*.pyo
*.pyd
*.egg-info/
.eggs/
# ========================================================
# Docker
# ========================================================
.dockerignore
docker-compose.override.yml
# ========================================================
# Proxmox VM Backups
# ========================================================
*.vma.zst
*.vma.lzo
*.vma.gz
# Compiled executables
src/nip.out
*.out
# Debug and test executables (binaries, not source)
debug_*
demo_*
simple_*
compute_hashes
# Test binaries (but not test source files)
test_use_flags
test_blake2b
test_filesystem_integration
test_generation_filesystem
test_integrity_monitoring
test_lockfile_restoration
test_lockfile_system
# Cross-contamination guard
core/rumpk/
core/nexus/
competitors/

57
BUILD_BLOCKER.md Normal file
View File

@ -0,0 +1,57 @@
# Critical Blocker: ARM64 NIP Static Build
## Status: LINK PHASE FAILING
### Root Cause Analysis
The `nim c` command compiles all source files to ARM64 object files successfully, but the **final link step is silently failing**.
**Evidence:**
1. All `.c``.o` compilation succeeds (ARM64 object files created in `/tmp/nip-arm64-cache/`)
2. Linker command executes but **lacks `-o` flag specifying output path**
3. Build returns exit code 0 (success) but no binary produced
4. `-o:build/arm64/nip` argument to `nim c` is being ignored or not passed to linker
### Linker Command (from diagnostic output):
```bash
aarch64-linux-gnu-gcc [hundreds of .o files] \
-pthread -lm -lrt \
-L/path/to/zstd-1.5.5/lib \
-L/path/to/libressl-3.8.2/ssl/.libs \
-L/path/to/libressl-3.8.2/crypto/.libs \
-L/path/to/libressl-3.8.2/tls/.libs \
-static -lssl -lcrypto -ltls -lzstd -lpthread -ldl -lm -lresolv \
-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now -Wl,-z,pack-relative-relocs
```
**MISSING:** `-o /path/to/output/binary`
### Attempted Solutions
1. ✅ Built LibreSSL 3.8.2 static (16MB crypto + 3.5MB ssl + 550KB tls) for ARM64
2. ✅ Built Zstd 1.5.5 static (1.2MB) for ARM64
3. ✅ Created GCC wrapper to filter x86 flags (`-mpclmul`, etc.)
4. ✅ Used `--dynlibOverride:ssl --dynlibOverride:crypto` to prevent dlopen()
5. ❌ Multiple output path specifications (`-o:`, `--out:`) all ignored
6. ❌ Force rebuild with `-f` - still no output
7. ❌ Absolute paths - still no output
### Hypothesis
Nim's ARM64 cross-compilation may have a bug where the `-o` flag isn't being passed through to the final linker invocation when using `--gcc.linkerexe:aarch64-linux-gnu-gcc`.
### Recommended Next Steps
**Option A: Manual Link (Immediate)**
1. Use the object files already compiled in `/tmp/nip-arm64-cache/`
2. Manually invoke `aarch64-linux-gnu-gcc` with proper `-o` flag
3. Create binary directly
**Option B: Different Nim Output Strategy**
1. Try `--compileOnly` to generate C code
2. Use custom Makefile for linking phase
3. Bypass Nim's linker invocation entirely
**Option C: Investigate Nim Bug**
1. Check if this is a known Nim cross-compilation issue
2. Try older/newer Nim version
3. Report bug to Nim if not known
**Current Time Impact:** ~3 hours spent debugging LibreSSL/Zstd static linking - successfully resolved. ~1 hour on output path issue - unresolved.

53
BUILD_SUCCESS.md Normal file
View File

@ -0,0 +1,53 @@
# ARM64 Static NIP Build - Success Report
## Final Status: ✅ **COMPLETE**
### Binary Specifications
- **Path**: `/home/markus/zWork/_Git/Nexus/core/nip/build/arm64/nip`
- **Size**: 30MB
- **Architecture**: ARM aarch64, statically linked
- **Build Date**: 2025-12-28 23:27
### Integrated Components
1. **LibreSSL 3.8.2** (20MB total)
- `libssl.a` (3.5MB)
- `libcrypto.a` (16MB)
- `libtls.a` (550KB)
2. **Zstd 1.5.5** - `libzstd.a` (1.2MB)
3. **Custom OpenSSL Shim** - `openssl_shim.o` (1.4KB)
- Bridges LibreSSL macros (`SSL_in_init`) to function symbols
4. **NimCrypto** - BLAKE2b only (SHA2/NEON removed)
### Build Method: Manual Linking ("Iron Hand" Protocol)
**Root Cause**: Nim's cross-compilation dropped the `-o` output flag from linker invocation.
**Solution**:
1. Nim compiled 289 ARM64 `.o` files successfully
2. Created C shim to bridge LibreSSL macro→function gap
3. Manually invoked `aarch64-linux-gnu-gcc` with all objects + shim
4. Forced static linking with proper library order
### Verification Results
```
✅ Structure: STATIC (no dynamic dependencies)
✅ No libcrypto.so dlopen references
✅ BuildID: 4ed2d90fcb6fc82d52429bed63bd1cb378993582
```
### NexBox Integration
- **Image Size**: 62,469 blocks (30MB+ initramfs)
- **Status**: Built successfully
- **Next**: Boot test + Warhead Test II (pack/extract cycle)
### Time Investment
- **LibreSSL/Zstd Static Build**: ~2 hours
- **Nim `-o` Flag Investigation**: ~1.5 hours
- **Manual Linking + Shim**: ~1 hour
- **Total**: ~4.5 hours
### Key Files Created
1. `/home/markus/zWork/_Git/Nexus/core/nip/src/openssl_shim.c` - Macro bridge
2. `/home/markus/zWork/_Git/Nexus/core/nip/link_manual.sh` - Manual linker
3. `/home/markus/zWork/_Git/Nexus/core/nexus/vendor/libressl-3.8.2/` - ARM64 static libs
4. `/home/markus/zWork/_Git/Nexus/core/nexus/vendor/zstd-1.5.5/` - ARM64 static lib

77
build_arm64_diagnostic.sh Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash
# Voxis Diagnostic Build Protocol (ARM64 + LibreSSL)
set -e # Exit immediately if any command fails
# --- 1. PATH RECONNAISSANCE ---
# Resolve absolute paths to stop relative path madness
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$BASE_DIR" # Ensure we are in core/nip/
VENDOR="$(realpath ../../core/nexus/vendor)"
ZSTD_PATH="$VENDOR/zstd-1.5.5/lib"
LIBRE_PATH="$VENDOR/libressl-3.8.2"
LIBRE_SSL_LIB="$LIBRE_PATH/ssl/.libs"
LIBRE_CRYPTO_LIB="$LIBRE_PATH/crypto/.libs"
LIBRE_TLS_LIB="$LIBRE_PATH/tls/.libs"
OUTPUT_DIR="$BASE_DIR/build/arm64"
TARGET_BIN="$OUTPUT_DIR/nip"
echo "🔎 [DIAGNOSTIC] Path Verification:"
echo " Base: $BASE_DIR"
echo " Vendor: $VENDOR"
echo " Output: $OUTPUT_DIR"
# Check Critical Assets
for lib in "$ZSTD_PATH/libzstd.a" "$LIBRE_SSL_LIB/libssl.a" "$LIBRE_CRYPTO_LIB/libcrypto.a"; do
if [ ! -f "$lib" ]; then
echo "❌ CRITICAL FAILURE: Missing Asset -> $lib"
echo " Did you run 'make' inside the library directories?"
exit 1
fi
done
echo "✅ All Static Libraries Found."
mkdir -p "$OUTPUT_DIR"
# --- 2. THE COMPILATION (FORCE MODE) ---
echo "🔨 [FORGE] Starting Compilation..."
# Put wrapper in PATH to filter x86 flags
export PATH="/tmp/gcc-wrapper-bin:$PATH"
# -f : Force rebuild (ignore cache)
# --listCmd : SHOW ME THE LINKER COMMAND
nim c -f --listCmd \
--skipProjCfg \
--nimcache:/tmp/nip-arm64-cache \
-d:release -d:ssl -d:openssl \
-d:nimcrypto_disable_neon \
-d:nimcrypto_no_asm \
--cpu:arm64 --os:linux \
--cc:gcc \
--gcc.exe:aarch64-linux-gnu-gcc \
--gcc.linkerexe:aarch64-linux-gnu-gcc \
--dynlibOverride:ssl --dynlibOverride:crypto \
--passC:"-I$ZSTD_PATH -I$LIBRE_PATH/include" \
--passL:"-L$ZSTD_PATH -L$LIBRE_SSL_LIB -L$LIBRE_CRYPTO_LIB -L$LIBRE_TLS_LIB" \
--passL:"-static -lssl -lcrypto -ltls -lzstd -lpthread -ldl -lm -lresolv" \
--opt:size \
--mm:orc \
--threads:on \
-o:"$TARGET_BIN" \
src/nip.nim
# --- 3. POST-MORTEM ---
echo "---------------------------------------------------"
if [ -f "$TARGET_BIN" ]; then
echo "✅ SUCCESS: Binary located at:"
ls -l "$TARGET_BIN"
file "$TARGET_BIN"
else
echo "❌ FAILURE: Output file missing at $TARGET_BIN"
echo "🔎 Searching for 'nip' binaries in the tree..."
find . -type f -name nip -exec ls -l {} +
fi

107
build_arm64_gcc.sh Executable file
View File

@ -0,0 +1,107 @@
#!/bin/bash
# Voxis Static Build Protocol (GCC Edition)
# Cross-compile nip for ARM64 using GNU toolchain
set -e
echo "🛡️ [VOXIS] ARM64 Static Build (GCC Cross-Compile)"
echo "=========================================================="
echo ""
# 1. Define Paths
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ZSTD_LIB_PATH="$SCRIPT_DIR/../nexus/vendor/zstd-1.5.5/lib"
ZSTD_INC_PATH="$SCRIPT_DIR/../nexus/vendor/zstd-1.5.5/lib"
SSL_LIB_PATH="$SCRIPT_DIR/../nexus/vendor/libressl-3.8.2"
SSL_INC_PATH="$SCRIPT_DIR/../nexus/vendor/libressl-3.8.2/include"
OUTPUT_DIR="$SCRIPT_DIR/build/arm64"
mkdir -p "$OUTPUT_DIR"
echo "📦 Zstd Library: $ZSTD_LIB_PATH/libzstd.a"
echo "📦 LibreSSL Libraries: $SSL_LIB_PATH/{crypto,ssl,tls}/.libs/*.a"
echo "📂 Output: $OUTPUT_DIR/nip"
echo ""
# 2. Verify libzstd.a exists and is ARM64
if [ ! -f "$ZSTD_LIB_PATH/libzstd.a" ]; then
echo "❌ Error: libzstd.a not found at $ZSTD_LIB_PATH"
exit 1
fi
if [ ! -f "$SSL_LIB_PATH/crypto/.libs/libcrypto.a" ]; then
echo "❌ Error: libcrypto.a not found at $SSL_LIB_PATH/crypto/.libs/"
exit 1
fi
echo "✅ Static libraries verified"
echo ""
# 3. Clean previous build
rm -f "$OUTPUT_DIR/nip"
rm -rf ~/.cache/nim/nip_*
echo "🧹 Cleaned previous builds"
echo ""
# 4. Compile with GCC cross-compiler
echo "🔨 Compiling nip for ARM64..."
echo " This may take a few minutes..."
echo ""
# Put wrapper in PATH
export PATH="/tmp/gcc-wrapper-bin:$PATH"
nim c \
--skipProjCfg \
--nimcache:/tmp/nip-arm64-cache \
-d:release \
-d:danger \
-d:ssl \
-d:nimcrypto_disable_neon \
-d:nimcrypto_no_asm \
--dynlibOverride:ssl \
--dynlibOverride:crypto \
--cpu:arm64 \
--os:linux \
--cc:gcc \
--gcc.exe:aarch64-linux-gnu-gcc \
--gcc.linkerexe:aarch64-linux-gnu-gcc \
--passC:"-I$ZSTD_INC_PATH -I$SSL_INC_PATH" \
--passL:"-L$ZSTD_LIB_PATH -L$SSL_LIB_PATH/ssl/.libs -L$SSL_LIB_PATH/crypto/.libs -L$SSL_LIB_PATH/tls/.libs" \
--passL:"-static -lssl -lcrypto -ltls -lzstd -lpthread -lm -lresolv" \
--opt:size \
--mm:orc \
--threads:on \
--out:"$OUTPUT_DIR/nip" \
src/nip.nim
# 5. Verify output
if [ ! -f "$OUTPUT_DIR/nip" ]; then
echo ""
echo "❌ Build failed: binary not produced"
exit 1
fi
echo ""
echo "✅ Build successful!"
echo ""
echo "📊 Binary info:"
ls -lh "$OUTPUT_DIR/nip"
file "$OUTPUT_DIR/nip"
echo ""
# Check if it's actually ARM64 and static
if file "$OUTPUT_DIR/nip" | grep -q "ARM aarch64"; then
echo "✅ Architecture: ARM64 (aarch64)"
else
echo "⚠️ Warning: Binary may not be ARM64"
fi
if file "$OUTPUT_DIR/nip" | grep -q "statically linked"; then
echo "✅ Linking: Static"
else
echo "⚠️ Warning: Binary may not be statically linked"
fi
echo ""
echo "🎯 Output: $OUTPUT_DIR/nip"

105
build_arm64_libre.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
# Voxis Static Build Protocol (GCC + Zstd + LibreSSL Edition)
set -e
echo "🛡️ [VOXIS] Linking Sovereign Artifact (ARM64 + LibreSSL)..."
echo ""
# --- 1. CONFIGURATION ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENDOR="$SCRIPT_DIR/../nexus/vendor"
ZSTD_PATH="$VENDOR/zstd-1.5.5/lib"
LIBRE_PATH="$VENDOR/libressl-3.8.2"
# LibreSSL hides static libs in subdirectories
LIBRE_SSL_LIB="$LIBRE_PATH/ssl/.libs"
LIBRE_CRYPTO_LIB="$LIBRE_PATH/crypto/.libs"
LIBRE_TLS_LIB="$LIBRE_PATH/tls/.libs"
OUTPUT_DIR="$SCRIPT_DIR/build/arm64"
mkdir -p "$OUTPUT_DIR"
# Verify libraries exist
if [ ! -f "$LIBRE_CRYPTO_LIB/libcrypto.a" ]; then
echo "❌ Error: libcrypto.a not found at $LIBRE_CRYPTO_LIB"
exit 1
fi
if [ ! -f "$ZSTD_PATH/libzstd.a" ]; then
echo "❌ Error: libzstd.a not found at $ZSTD_PATH"
exit 1
fi
echo "✅ Static libraries verified"
echo " 📦 Zstd: $ZSTD_PATH/libzstd.a"
echo " 📦 LibreSSL crypto: $LIBRE_CRYPTO_LIB/libcrypto.a"
echo " 📦 LibreSSL ssl: $LIBRE_SSL_LIB/libssl.a"
echo " 📦 LibreSSL tls: $LIBRE_TLS_LIB/libtls.a"
echo ""
# Put wrapper in PATH to filter x86 flags
export PATH="/tmp/gcc-wrapper-bin:$PATH"
# --- 2. THE COMPILATION ---
# -d:ssl : Enable Nim SSL support
# -d:openssl : Use OpenSSL-compatible API
# --dynlibOverride : VITAL. Stops Nim from trying to load .so files at runtime.
# --passC : Include headers (Zstd + LibreSSL)
# --passL : Link static libs (Note the multiple -L paths)
echo "🔨 Compiling nip for ARM64..."
echo ""
nim c \
--skipProjCfg \
--nimcache:/tmp/nip-arm64-cache \
-d:release \
-d:ssl \
-d:openssl \
-d:nimcrypto_disable_neon \
-d:nimcrypto_no_asm \
--cpu:arm64 \
--os:linux \
--cc:gcc \
--gcc.exe:aarch64-linux-gnu-gcc \
--gcc.linkerexe:aarch64-linux-gnu-gcc \
--dynlibOverride:ssl \
--dynlibOverride:crypto \
--passC:"-I$ZSTD_PATH -I$LIBRE_PATH/include" \
--passL:"-L$ZSTD_PATH -L$LIBRE_SSL_LIB -L$LIBRE_CRYPTO_LIB -L$LIBRE_TLS_LIB" \
--passL:"-static -lssl -lcrypto -ltls -lzstd -lpthread -ldl -lm -lresolv" \
--opt:size \
--mm:orc \
--threads:on \
-o:"$OUTPUT_DIR/nip" \
src/nip.nim
# --- 3. VERIFICATION ---
if [ $? -eq 0 ] && [ -f "$OUTPUT_DIR/nip" ]; then
echo ""
echo "✅ Build Successful!"
echo ""
echo "📊 Binary info:"
ls -lh "$OUTPUT_DIR/nip"
file "$OUTPUT_DIR/nip"
echo ""
# Check if truly static
if file "$OUTPUT_DIR/nip" | grep -q "statically linked"; then
echo "✅ Linking: Static"
else
echo "⚠️ Warning: Binary may not be fully static"
fi
# Check for crypto strings (should NOT be present as dlopen targets)
if strings "$OUTPUT_DIR/nip" | grep -q "libcrypto.so"; then
echo "⚠️ Warning: Binary still contains libcrypto.so references"
else
echo "✅ No dynamic crypto references found"
fi
else
echo ""
echo "❌ Build Failed."
exit 1
fi

187
build_arm64_static.sh Executable file
View File

@ -0,0 +1,187 @@
#!/bin/bash
# NIP ARM64 Static Build Script using Zig
# Builds a fully static ARM64 binary using Zig as C compiler with musl
set -e
echo "🚀 Building NIP for ARM64 (aarch64-linux-musl) using Zig"
echo "========================================================="
echo ""
# Check dependencies
if ! command -v nim &> /dev/null; then
echo "❌ Error: Nim compiler not found"
exit 1
fi
if ! command -v zig &> /dev/null; then
echo "❌ Error: Zig compiler not found"
exit 1
fi
echo "📋 Nim version: $(nim --version | head -1)"
echo "📋 Zig version: $(zig version)"
echo ""
# Create Zig wrapper that shadows aarch64-linux-gnu-gcc
ZIG_WRAPPER_DIR="/tmp/nip-zig-wrappers-arm64"
rm -rf "$ZIG_WRAPPER_DIR"
mkdir -p "$ZIG_WRAPPER_DIR"
# Create a wrapper named exactly "aarch64-linux-gnu-gcc" that calls zig cc
# This shadows the system's aarch64-linux-gnu-gcc when prepended to PATH
# Filters out x86-specific compile flags AND problematic linker flags
cat > "$ZIG_WRAPPER_DIR/aarch64-linux-gnu-gcc" << 'WRAPPER'
#!/bin/bash
# Zig CC wrapper for ARM64 cross-compilation
# Shadows system's aarch64-linux-gnu-gcc and filters incompatible flags
FILTERED_ARGS=()
echo "Wrapper called with:" >> /tmp/wrapper.log
printf "'%s' " "$@" >> /tmp/wrapper.log
echo "" >> /tmp/wrapper.log
for arg in "$@"; do
case "$arg" in
# Skip x86-specific compile flags
-mpclmul|-maes|-msse*|-mavx*|-mno-80387|-fcf-protection|-fstack-clash-protection)
;;
-march=x86*|-march=native)
;;
-mtune=haswell|-mtune=skylake|-mtune=generic)
;;
-Wp,-D_FORTIFY_SOURCE=*)
;;
-flto)
# LTO can cause issues with zig cross-compile
;;
# Skip dynamic library flags that don't work with musl static
-ldl)
# musl's libc.a includes dl* functions, no separate libdl needed
;;
# Filter all march/mtune flags to avoid zig cc conflicts
-m64|-m32|-march=*|-mtune=*|-mcpu=*|-Xclang*|-target-feature*)
# skip host-specific flags
;;
*)
FILTERED_ARGS+=("$arg")
;;
esac
done
exec zig cc -target aarch64-linux-musl "${FILTERED_ARGS[@]}"
WRAPPER
chmod +x "$ZIG_WRAPPER_DIR/aarch64-linux-gnu-gcc"
echo "✅ Created Zig wrapper at $ZIG_WRAPPER_DIR/aarch64-linux-gnu-gcc"
echo ""
# Clean previous builds and cache
echo "🧹 Cleaning previous ARM64 builds and Nim cache..."
rm -f nip-arm64 nip_arm64 nip-arm64-musl
rm -rf ~/.cache/nim/nip_*
rm -rf /tmp/nip-arm64-cache
echo ""
# Prepend our wrapper to PATH
export PATH="$ZIG_WRAPPER_DIR:$PATH"
# Verify our wrapper is first in PATH
FOUND_GCC=$(which aarch64-linux-gnu-gcc)
echo "🔍 Using gcc wrapper: $FOUND_GCC"
echo ""
# Compile statically
echo "🔨 Building optimized ARM64 static binary..."
echo " Target: aarch64-linux-musl (static via Zig)"
echo " This may take a few minutes..."
nim c \
--cpu:arm64 \
--os:linux \
--cc:gcc \
--gcc.exe:"$ZIG_WRAPPER_DIR/aarch64-linux-gnu-gcc" \
--gcc.linkerexe:"$ZIG_WRAPPER_DIR/aarch64-linux-gnu-gcc" \
--passC:"-O2" \
--passC:"-w" \
--passL:-static \
--passL:-s \
-d:release \
-d:danger \
-d:nimcrypto_disable_neon \
-d:nimcrypto_no_asm \
-d:nimcrypto_sysrand \
--opt:size \
--mm:orc \
--threads:on \
--nimcache:/tmp/nip-arm64-cache \
--skipProjCfg \
--out:nip-arm64 \
src/nip.nim 2>&1 | tee /tmp/nip-arm64-build.log
if [ ! -f "nip-arm64" ]; then
echo ""
echo "❌ Build failed! Check /tmp/nip-arm64-build.log for details"
echo "Last 20 lines of error:"
tail -20 /tmp/nip-arm64-build.log
exit 1
fi
echo ""
echo "✅ Build successful!"
echo ""
# Show binary info
echo "📊 Binary Information:"
ls -lh nip-arm64
echo ""
echo "🔍 File details:"
file nip-arm64
echo ""
# Verify it's ARM64
if file nip-arm64 | grep -q "ARM aarch64"; then
echo "✅ Verified: Binary is ARM64 aarch64"
else
echo "⚠️ Binary may not be ARM64 - check file output above"
fi
echo ""
# Verify static linking with readelf
echo "🔍 Verifying static linking..."
if readelf -d nip-arm64 2>/dev/null | grep -q "NEEDED"; then
echo "⚠️ Binary has dynamic dependencies:"
readelf -d nip-arm64 2>/dev/null | grep NEEDED
else
echo "✅ No dynamic dependencies found (fully static)"
fi
echo ""
# Test with QEMU if available
echo "🧪 Testing binary with QEMU user-mode emulation..."
if command -v qemu-aarch64 &> /dev/null; then
if timeout 10 qemu-aarch64 ./nip-arm64 --version 2>&1; then
echo "✅ Binary works under QEMU aarch64 emulation"
else
echo "⚠️ Binary may need additional setup"
fi
else
echo " QEMU aarch64 user-mode not available"
fi
echo ""
# Create output directory
OUTPUT_DIR="build/arm64"
mkdir -p "$OUTPUT_DIR"
cp nip-arm64 "$OUTPUT_DIR/nip"
chmod +x "$OUTPUT_DIR/nip"
echo "🎉 ARM64 build complete!"
echo ""
echo "📋 Build Summary:"
echo " Binary: nip-arm64"
echo " Target: aarch64-linux-musl (static)"
echo " Size: $(ls -lh nip-arm64 | awk '{print $5}')"
echo " Output: $OUTPUT_DIR/nip"
echo ""
echo "📦 Ready for NexBox integration!"

0
examples/json-output-demo.nim Executable file → Normal file
View File

95
link_manual.sh Executable file
View File

@ -0,0 +1,95 @@
#!/bin/bash
# Voxis "Iron Hand" Protocol - Manual Linker Override
set -e
# --- 1. TARGET ACQUISITION ---
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$BASE_DIR"
CACHE_DIR="/tmp/nip-arm64-cache"
OUTPUT_DIR="build/arm64"
TARGET="$OUTPUT_DIR/nip"
VENDOR="$(realpath ../../core/nexus/vendor)"
ZSTD_PATH="$VENDOR/zstd-1.5.5/lib"
LIBRE_PATH="$VENDOR/libressl-3.8.2"
LIBRE_SSL_LIB="$LIBRE_PATH/ssl/.libs"
LIBRE_CRYPTO_LIB="$LIBRE_PATH/crypto/.libs"
LIBRE_TLS_LIB="$LIBRE_PATH/tls/.libs"
mkdir -p "$OUTPUT_DIR"
echo "🔨 [IRON HAND] Locating debris..."
# Gather all object files from the cache
# We filter out any potential garbage, ensuring only .o files
OBJECTS=$(find "$CACHE_DIR" -name "*.o" 2>/dev/null | tr '\n' ' ')
if [ -z "$OBJECTS" ]; then
echo "❌ ERROR: No object files found in $CACHE_DIR. Did you run the compile step?"
exit 1
fi
OBJ_COUNT=$(echo "$OBJECTS" | wc -w)
echo " Found $OBJ_COUNT object files"
echo "🔗 [IRON HAND] Linking Sovereign Artifact (with Shim)..."
# 2.1: Validate Shim exists
SHIM_OBJ="$BASE_DIR/src/openssl_shim.o"
if [ ! -f "$SHIM_OBJ" ]; then
echo "❌ Missing Shim: $SHIM_OBJ"
echo " Run: cd src && aarch64-linux-gnu-gcc -c openssl_shim.c -o openssl_shim.o -I../../nexus/vendor/libressl-3.8.2/include -O2"
exit 1
fi
# --- 2. THE WELD ---
# We invoke the cross-compiler directly as the linker.
# We feed it every single object file Nim created + our shim.
aarch64-linux-gnu-gcc \
$OBJECTS \
"$SHIM_OBJ" \
-o "$TARGET" \
-L"$ZSTD_PATH" \
-L"$LIBRE_SSL_LIB" \
-L"$LIBRE_CRYPTO_LIB" \
-L"$LIBRE_TLS_LIB" \
-static \
-lpthread \
-lssl -lcrypto -ltls \
-lzstd \
-ldl -lm -lrt -lresolv \
-Wl,-z,muldefs \
-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now
# --- 3. VERIFICATION ---
echo ""
if [ -f "$TARGET" ]; then
echo "✅ [SUCCESS] Binary forged at: $TARGET"
echo ""
ls -lh "$TARGET"
file "$TARGET"
echo ""
echo "🔎 Checking linkage type..."
# If static, 'ldd' should say "not a dynamic executable"
if ldd "$TARGET" 2>&1 | grep -q "not a dynamic executable"; then
echo " ✅ Structure: STATIC"
else
echo " ⚠️ Structure: DYNAMIC"
ldd "$TARGET" | head -n 5
fi
echo ""
echo "🔎 Checking for libcrypto.so references..."
if strings "$TARGET" | grep -q "libcrypto.so"; then
echo " ⚠️ Found dlopen references (may still work if --dynlibOverride worked)"
else
echo " ✅ No libcrypto.so dlopen references"
fi
else
echo "❌ [FAILURE] Linker command finished but no binary produced."
exit 1
fi

12
nim_arm64.cfg Normal file
View File

@ -0,0 +1,12 @@
# ARM64 Cross-Compile Configuration
# Override all system flags
# Clear all default flags
@if arm64:
passC = ""
passL = ""
@end
# Disable all x86 optimizations
--passC:"-O2"
--passC:"-w"

13
nip.nim
View File

@ -1,10 +1,15 @@
#!/usr/bin/env nim
## NIP MVP - Minimal Viable Product CLI
## Simple, focused package grafting from Nix, PKGSRC, and Pacman
# Copyright (c) 2026 Nexus Foundation
# Licensed under the Libertaria Sovereign License (LSL-1.0)
# See legal/LICENSE_SOVEREIGN.md for details.
# NIP MVP - Minimal Viable Product CLI
# Simple, focused package grafting from Nix, PKGSRC, and Pacman
import std/[os, strutils, strformat]
import src/nimpak/cli/graft_commands
import src/nimpak/cli/bootstrap_commands
import src/nimpak/cli/store_commands
const
Version = "0.1.0-mvp"
@ -30,6 +35,7 @@ COMMANDS:
doctor Check system health
setup Setup system integration (PATH, libraries)
bootstrap Build tool management (nix, pkgsrc, gentoo)
store Interact with Content-Addressable Storage (CAS)
config [show|init] Show or initialize configuration
logs [lines] Show recent log entries (default: 50)
search <query> Search for packages (coming soon)
@ -227,6 +233,9 @@ proc main() =
bootstrapHelpCommand()
exitCode = 1
of "store":
exitCode = dispatchStoreCommand(commandArgs, verbose)
else:
echo fmt"Error: Unknown command '{command}'"
echo "Run 'nip --help' for usage information"

View File

@ -4,7 +4,7 @@
import std/[strutils, json, os, times, osproc, tables, strformat, httpclient]
import ../grafting
from ../cas import Result, ok, err, isErr, get
import ../types
type
AURAdapter* = ref object of PackageAdapter
@ -240,10 +240,10 @@ proc downloadPKGBUILD(adapter: AURAdapter, packageName: string): Result[string,
writeFile(pkgbuildPath, content)
return Result[string, string](isOk: true, value: pkgbuildPath)
return Result[string, string](isOk: true, okValue: pkgbuildPath)
except Exception as e:
return Result[string, string](isOk: false, error: fmt"Failed to download PKGBUILD: {e.msg}")
return Result[string, string](isOk: false, errValue: fmt"Failed to download PKGBUILD: {e.msg}")
proc showPKGBUILDReview(pkgbuildPath: string): bool =
## Show PKGBUILD for user review
@ -316,26 +316,26 @@ proc calculateAURHash(pkgbuildPath: string): string =
"aur-hash-error"
method validatePackage*(adapter: AURAdapter, packageName: string): Result[bool, string] {.base.} =
method validatePackage*(adapter: AURAdapter, packageName: string): Result[bool, string] =
## Validate that a package exists in AUR
try:
let info = searchAURPackage(adapter, packageName)
if info.name == "":
return Result[bool, string](isOk: false, error: fmt"Package '{packageName}' not found in AUR")
return Result[bool, string](isOk: false, errValue: fmt"Package '{packageName}' not found in AUR")
return Result[bool, string](isOk: true, value: true)
return Result[bool, string](isOk: true, okValue: true)
except Exception as e:
return Result[bool, string](isOk: false, error: fmt"Validation error: {e.msg}")
return Result[bool, string](isOk: false, errValue: fmt"Validation error: {e.msg}")
method getPackageInfo*(adapter: AURAdapter, packageName: string): Result[JsonNode, string] {.base.} =
method getPackageInfo*(adapter: AURAdapter, packageName: string): Result[JsonNode, string] =
## Get detailed package information from AUR
try:
let info = searchAURPackage(adapter, packageName)
if info.name == "":
return Result[JsonNode, string](isOk: false, error: fmt"Package '{packageName}' not found in AUR")
return Result[JsonNode, string](isOk: false, errValue: fmt"Package '{packageName}' not found in AUR")
let jsonResult = %*{
"name": info.name,
@ -354,7 +354,7 @@ method getPackageInfo*(adapter: AURAdapter, packageName: string): Result[JsonNod
"build_method": "nippel"
}
return Result[JsonNode, string](isOk: true, value: jsonResult)
return Result[JsonNode, string](isOk: true, okValue: jsonResult)
except Exception as e:
return Result[JsonNode, string](isOk: false, error: fmt"Error getting package info: {e.msg}")
return Result[JsonNode, string](isOk: false, errValue: fmt"Error getting package info: {e.msg}")

View File

@ -1,17 +1,17 @@
## Git Source Adapter for NexusForge
## Implements "Obtainium-style" Git-based package resolution
##
## Features:
## - Parse git+https:// URLs with optional tag/branch specifiers
## - Poll GitHub/GitLab APIs for tags and releases
## - Semver matching and wildcard support
## - Shallow clone for efficient fetching
# Git Source Adapter for NexusForge
# Implements "Obtainium-style" Git-based package resolution
#
# Features:
# - Parse git+https:// URLs with optional tag/branch specifiers
# - Poll GitHub/GitLab APIs for tags and releases
# - Semver matching and wildcard support
# - Shallow clone for efficient fetching
import std/[strutils, options, json, httpclient, os, osproc, uri, times,
sequtils, algorithm]
import ../types/grafting_types
import ../cas
from ../cas import Result, VoidResult, ok, err, isErr, get
import ../types
type
GitSourceKind* = enum
@ -468,7 +468,7 @@ proc ingestDirToCas*(cas: var CasManager, sourceDir: string,
let storeResult = cas.storeObject(dataBytes)
if storeResult.isOk:
let obj = storeResult.value
let obj = storeResult.okValue
allHashes.add(file & ":" & obj.hash)
result.files.add(file)
totalSize += obj.size
@ -488,7 +488,7 @@ proc ingestDirToCas*(cas: var CasManager, sourceDir: string,
if manifestResult.isOk:
result.success = true
result.casHash = manifestResult.value.hash
result.casHash = manifestResult.okValue.hash
result.totalSize = totalSize
# =============================================================================
@ -577,7 +577,7 @@ proc downloadAndIngestAsset*(cas: var CasManager, asset: GitAsset,
# Download the asset
let downloadResult = downloadReleaseAsset(asset, tempPath, token)
if not downloadResult.isOk:
return err[string, string](downloadResult.error)
return err[string, string](downloadResult.errValue)
# Ingest into CAS
try:
@ -589,7 +589,7 @@ proc downloadAndIngestAsset*(cas: var CasManager, asset: GitAsset,
removeFile(tempPath)
if storeResult.isOk:
return ok[string, string](storeResult.value.hash)
return ok[string, string](storeResult.okValue.hash)
else:
return err[string, string]("CAS store failed")
except IOError as e:
@ -628,10 +628,10 @@ proc obtainPackage*(cas: var CasManager, source: GitSource, tagPattern: string =
# Step 1: Get available tags
let tagsResult = fetchTags(source)
if not tagsResult.isOk:
result.errors.add("Failed to fetch tags: " & tagsResult.error)
result.errors.add("Failed to fetch tags: " & tagsResult.errValue)
return
let matchedTags = filterTags(tagsResult.value, tagPattern)
let matchedTags = filterTags(tagsResult.okValue, tagPattern)
if matchedTags.len == 0:
result.errors.add("No tags match pattern: " & tagPattern)
return
@ -644,7 +644,7 @@ proc obtainPackage*(cas: var CasManager, source: GitSource, tagPattern: string =
if preferRelease and source.kind == GitHub:
let releasesResult = fetchGitHubReleases(source)
if releasesResult.isOk:
for release in releasesResult.value:
for release in releasesResult.okValue:
if release.tag == bestTag.name:
let asset = findAssetByPattern(release, assetPattern)
if asset.isSome:
@ -652,7 +652,7 @@ proc obtainPackage*(cas: var CasManager, source: GitSource, tagPattern: string =
actualCacheDir, source.token)
if ingestResult.isOk:
result.success = true
result.casHash = ingestResult.value
result.casHash = ingestResult.okValue
result.fetchMethod = "release"
result.files = @[asset.get().name]
return

View File

@ -3,7 +3,7 @@
import std/[strutils, json, os, times, osproc, tables, strformat]
import ../grafting
from ../cas import Result, ok, err, isErr, get
import ../types
type
NixAdapter* = ref object of PackageAdapter
@ -351,31 +351,31 @@ proc calculateNixStoreHash(storePath: string): string =
"nix-hash-error"
method validatePackage*(adapter: NixAdapter, packageName: string): Result[bool, string] {.base.} =
method validatePackage*(adapter: NixAdapter, packageName: string): Result[bool, string] =
## Validate that a package exists in nixpkgs
try:
if not isNixAvailable():
return Result[bool, string](isOk: false, error: "Nix is not installed. Install Nix from https://nixos.org/download.html")
return Result[bool, string](isOk: false, errValue: "Nix is not installed. Install Nix from https://nixos.org/download.html")
let info = getNixPackageInfo(adapter, packageName)
if info.name == "":
return Result[bool, string](isOk: false, error: fmt"Package '{packageName}' not found in nixpkgs")
return Result[bool, string](isOk: false, errValue: fmt"Package '{packageName}' not found in nixpkgs")
return Result[bool, string](isOk: true, value: true)
return Result[bool, string](isOk: true, okValue: true)
except JsonParsingError as e:
return Result[bool, string](isOk: false, error: fmt"Failed to parse Nix output: {e.msg}")
return Result[bool, string](isOk: false, errValue: fmt"Failed to parse Nix output: {e.msg}")
except Exception as e:
return Result[bool, string](isOk: false, error: fmt"Validation error: {e.msg}")
return Result[bool, string](isOk: false, errValue: fmt"Validation error: {e.msg}")
method getPackageInfo*(adapter: NixAdapter, packageName: string): Result[JsonNode, string] {.base.} =
method getPackageInfo*(adapter: NixAdapter, packageName: string): Result[JsonNode, string] =
## Get detailed package information from nixpkgs
try:
let info = getNixPackageInfo(adapter, packageName)
if info.name == "":
return Result[JsonNode, string](isOk: false, error: fmt"Package '{packageName}' not found in nixpkgs")
return Result[JsonNode, string](isOk: false, errValue: fmt"Package '{packageName}' not found in nixpkgs")
let jsonResult = %*{
"name": info.name,
@ -389,10 +389,10 @@ method getPackageInfo*(adapter: NixAdapter, packageName: string): Result[JsonNod
"adapter": adapter.name
}
return Result[JsonNode, string](isOk: true, value: jsonResult)
return Result[JsonNode, string](isOk: true, okValue: jsonResult)
except Exception as e:
return Result[JsonNode, string](isOk: false, error: fmt"Error getting package info: {e.msg}")
return Result[JsonNode, string](isOk: false, errValue: fmt"Error getting package info: {e.msg}")
# Utility functions for Nix integration
proc getNixSystemInfo*(): JsonNode =

View File

@ -1,11 +1,11 @@
## Pacman Database Adapter for NIP
##
## This module provides integration with the existing pacman package manager,
## allowing NIP to read, understand, and manage pacman-installed packages.
## This enables gradual migration from pacman to NIP on Arch Linux systems.
# Pacman Database Adapter for NIP
#
# This module provides integration with the existing pacman package manager,
# allowing NIP to read, understand, and manage pacman-installed packages.
# This enables gradual migration from pacman to NIP on Arch Linux systems.
import std/[os, strutils, tables, times, sequtils, options, strformat, hashes, osproc]
from ../cas import VoidResult, Result, ok, get, err
import ../types
import ../grafting
type
@ -319,10 +319,10 @@ proc syncWithNip*(adapter: var PacmanAdapter): Result[int, string] =
# This would integrate with the existing NIP database system
syncedCount.inc
return Result[int, string](isOk: true, value: syncedCount)
return Result[int, string](isOk: true, okValue: syncedCount)
except Exception as e:
return Result[int, string](isOk: false, error: "Failed to sync with NIP: " & e.msg)
return Result[int, string](isOk: false, errValue: "Failed to sync with NIP: " & e.msg)
proc getPackageInfo*(adapter: PacmanAdapter, name: string): string =
## Get detailed package information in human-readable format
@ -390,18 +390,18 @@ proc nipPacmanSync*(): Result[string, string] =
let loadResult = adapter.loadPacmanDatabase()
if not loadResult.isOk:
return Result[string, string](isOk: false, error: loadResult.errValue)
return Result[string, string](isOk: false, errValue: loadResult.errValue)
let syncResult = adapter.syncWithNip()
if not syncResult.isOk:
return Result[string, string](isOk: false, error: syncResult.error)
return Result[string, string](isOk: false, errValue: syncResult.errValue)
let stats = adapter.getSystemStats()
let message = "✅ Synchronized " & $syncResult.get() & " packages\n" &
"📊 Total: " & $stats.totalPackages & " packages, " &
$(stats.totalSize div (1024*1024)) & " MB"
return Result[string, string](isOk: true, value: message)
return Result[string, string](isOk: true, okValue: message)
proc nipPacmanList*(query: string = ""): Result[string, string] =
## NIP command: nip pacman-list [query]
@ -410,26 +410,26 @@ proc nipPacmanList*(query: string = ""): Result[string, string] =
let loadResult = adapter.loadPacmanDatabase()
if not loadResult.isOk:
return Result[string, string](isOk: false, error: loadResult.errValue)
return Result[string, string](isOk: false, errValue: loadResult.errValue)
let packages = if query == "":
adapter.listPackages()
else:
adapter.searchPackages(query)
var result = "📦 Pacman Packages"
var listOutput = "📦 Pacman Packages"
if query != "":
result.add(" (matching '" & query & "')")
result.add(":\n\n")
listOutput.add(" (matching '" & query & "')")
listOutput.add(":\n\n")
for pkg in packages:
result.add("" & pkg.name & " " & pkg.version)
listOutput.add("" & pkg.name & " " & pkg.version)
if pkg.description != "":
result.add(" - " & pkg.description)
result.add("\n")
listOutput.add(" - " & pkg.description)
listOutput.add("\n")
result.add("\nTotal: " & $packages.len & " packages")
return Result[string, string](isOk: true, value: result)
listOutput.add("\nTotal: " & $packages.len & " packages")
return Result[string, string](isOk: true, okValue: listOutput)
proc nipPacmanInfo*(packageName: string): Result[string, string] =
## NIP command: nip pacman-info <package>
@ -438,10 +438,10 @@ proc nipPacmanInfo*(packageName: string): Result[string, string] =
let loadResult = adapter.loadPacmanDatabase()
if not loadResult.isOk:
return Result[string, string](isOk: false, error: loadResult.errValue)
return Result[string, string](isOk: false, errValue: loadResult.errValue)
let info = adapter.getPackageInfo(packageName)
return Result[string, string](isOk: true, value: info)
return Result[string, string](isOk: true, okValue: info)
proc nipPacmanDeps*(packageName: string): Result[string, string] =
## NIP command: nip pacman-deps <package>
@ -450,38 +450,38 @@ proc nipPacmanDeps*(packageName: string): Result[string, string] =
let loadResult = adapter.loadPacmanDatabase()
if not loadResult.isOk:
return Result[string, string](isOk: false, error: loadResult.errValue)
return Result[string, string](isOk: false, errValue: loadResult.errValue)
var visited: seq[string] = @[]
let deps = adapter.getDependencyTree(packageName, visited)
var result = "🌳 Dependency tree for " & packageName & ":\n\n"
var outputStr = "🌳 Dependency tree for " & packageName & ":\n\n"
for i, dep in deps:
let prefix = if i == deps.len - 1: "└── " else: "├── "
result.add(prefix & dep & "\n")
outputStr.add(prefix & dep & "\n")
if deps.len == 0:
result.add("No dependencies found.\n")
outputStr.add("No dependencies found.\n")
else:
result.add("\nTotal dependencies: " & $deps.len)
outputStr.add("\nTotal dependencies: " & $deps.len)
return Result[string, string](isOk: true, value: result)
return Result[string, string](isOk: true, okValue: outputStr)
# Grafting adapter methods for coordinator integration
method validatePackage*(adapter: PacmanAdapter, packageName: string): Result[bool, string] =
proc validatePackage*(adapter: PacmanAdapter, packageName: string): Result[bool, string] =
## Validate if a package exists using pacman -Ss (checks repos)
try:
# Use pacman to search for package (checks both local and remote)
let (output, exitCode) = execCmdEx(fmt"pacman -Ss '^{packageName}$'")
if exitCode == 0 and output.len > 0:
return Result[bool, string](isOk: true, value: true)
return Result[bool, string](isOk: true, okValue: true)
else:
return Result[bool, string](isOk: true, value: false)
return Result[bool, string](isOk: true, okValue: false)
except Exception as e:
return Result[bool, string](isOk: false, error: "Failed to validate package: " & e.msg)
return Result[bool, string](isOk: false, errValue: "Failed to validate package: " & e.msg)
proc isPackageInstalled(adapter: PacmanAdapter, packageName: string): bool =
## Check if package is installed locally using pacman -Q
@ -491,7 +491,7 @@ proc isPackageInstalled(adapter: PacmanAdapter, packageName: string): bool =
except:
return false
method graftPackage*(adapter: var PacmanAdapter, packageName: string, cache: GraftingCache): GraftResult =
proc graftPackage*(adapter: var PacmanAdapter, packageName: string, cache: GraftingCache): GraftResult =
## Graft a package from Pacman (local or remote)
echo fmt"🌱 Grafting package from Pacman: {packageName}"

View File

@ -3,7 +3,7 @@
import std/[strutils, json, os, times, osproc, strformat]
import ../grafting
from ../cas import Result, ok, err, isErr, get
import ../types
type
PKGSRCAdapter* = ref object of PackageAdapter
@ -490,9 +490,9 @@ method validatePackage*(adapter: PKGSRCAdapter, packageName: string): Result[boo
## Validate that a package exists in PKGSRC
try:
let info = findPKGSRCPackage(adapter, packageName)
return Result[bool, string](isOk: true, value: info.name != "")
return Result[bool, string](isOk: true, okValue: info.name != "")
except Exception as e:
return Result[bool, string](isOk: false, error: fmt"Validation error: {e.msg}")
return Result[bool, string](isOk: false, errValue: fmt"Validation error: {e.msg}")
method getPackageInfo*(adapter: PKGSRCAdapter, packageName: string): Result[JsonNode, string] =
## Get detailed package information from PKGSRC
@ -500,7 +500,7 @@ method getPackageInfo*(adapter: PKGSRCAdapter, packageName: string): Result[Json
let info = findPKGSRCPackage(adapter, packageName)
if info.name == "":
return Result[JsonNode, string](isOk: false, error: fmt"Package '{packageName}' not found in PKGSRC")
return Result[JsonNode, string](isOk: false, errValue: fmt"Package '{packageName}' not found in PKGSRC")
let result = %*{
"name": info.name,
@ -517,10 +517,10 @@ method getPackageInfo*(adapter: PKGSRCAdapter, packageName: string): Result[Json
"adapter": adapter.name
}
return Result[JsonNode, string](isOk: true, value: result)
return Result[JsonNode, string](isOk: true, okValue: result)
except Exception as e:
return Result[JsonNode, string](isOk: false, error: fmt"Error getting package info: {e.msg}")
return Result[JsonNode, string](isOk: false, errValue: fmt"Error getting package info: {e.msg}")
# Utility functions
proc isPKGSRCAvailable*(adapter: PKGSRCAdapter): bool =

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NimPak Performance Benchmarking
##
## Comprehensive benchmarks for the NimPak package manager.

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/build_system.nim
## Nimplate Build System Integration
##

View File

@ -1,11 +1,18 @@
## Content-Addressable Storage (CAS) System
##
## This module implements the foundational content-addressable storage system
## that provides automatic deduplication and cryptographic verification using
## xxHash (xxh3_128) for maximum performance with BLAKE2b legacy fallback.
##
## Hash Algorithm: xxHash xxh3_128 (40-50 GiB/s, 128-bit collision-safe)
## Legacy Support: BLAKE2b-512 (for backward compatibility)
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# Content-Addressable Storage (CAS) System
#
# This module implements the foundational content-addressable storage system
# that provides automatic deduplication and cryptographic verification using
# xxHash (xxh3_128) for maximum performance with BLAKE2b legacy fallback.
#
# Hash Algorithm: xxHash xxh3_128 (40-50 GiB/s, 128-bit collision-safe)
# Legacy Support: BLAKE2b-512 (for backward compatibility)
import std/[os, tables, sets, strutils, json, sequtils, hashes, options, times, algorithm]
{.warning[Deprecated]:off.}
@ -13,37 +20,12 @@ import std/threadpool # For parallel operations
{.warning[Deprecated]:on.}
import xxhash # Modern high-performance hashing (2-3x faster than BLAKE2b)
import nimcrypto/blake2 # Legacy fallback
import ../nip/types
import ./types
import ./protection # Read-only protection manager
# Result type for error handling - using std/options for now
type
Result*[T, E] = object
case isOk*: bool
of true:
value*: T
of false:
error*: E
# Result types are imported from ./types
VoidResult*[E] = object
case isOk*: bool
of true:
discard
of false:
errValue*: E
proc ok*[T, E](val: T): Result[T, E] =
Result[T, E](isOk: true, value: val)
proc err*[T, E](error: E): Result[T, E] =
Result[T, E](isOk: false, error: error)
proc ok*[E](dummy: typedesc[E]): VoidResult[E] =
VoidResult[E](isOk: true)
proc isErr*[T, E](r: Result[T, E]): bool = not r.isOk
proc get*[T, E](r: Result[T, E]): T = r.value
proc getError*[T, E](r: Result[T, E]): E = r.error
type
FormatType* = enum

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NCA Content-Addressable Chunks Format Handler
##
## This module implements the NCA (Nexus Content-Addressable) chunk format for

View File

@ -12,6 +12,7 @@ import std/[os, strutils, times, json, tables, sequtils, algorithm, strformat]
# TODO: Re-enable when nipcells module is available
# import ../nipcells
import ../grafting, ../database, core
import ../build/[recipe_manager, recipe_parser]
import audit_commands, track_commands, verify_commands
import enhanced_search
@ -170,6 +171,37 @@ proc infoCommand*(packageName: string): CommandResult =
try:
core.showInfo(fmt"Getting information for package: {packageName}")
# Initialize RecipeManager to check Bazaar
let rm = newRecipeManager()
let recipeOpt = rm.loadRecipe(packageName)
if recipeOpt.isSome:
let recipe = recipeOpt.get()
let packageInfo = %*{
"name": recipe.name,
"version": recipe.version,
"description": recipe.description,
"homepage": recipe.metadata.homepage,
"license": recipe.metadata.license,
"stream": "bazaar", # It comes from the Bazaar
"architecture": "multi", # Recipe supports multiple
"installed": false, # We don't check installed status here yet
"source_type": recipe.toolType
}
if globalContext.options.outputFormat == OutputHuman:
echo bold("Package Information (Bazaar): " & highlight(packageName))
echo "=".repeat(30)
echo "Name: " & packageInfo["name"].getStr()
echo "Version: " & highlight(packageInfo["version"].getStr())
echo "Description: " & packageInfo["description"].getStr()
echo "License: " & packageInfo["license"].getStr()
echo "Source Type: " & packageInfo["source_type"].getStr()
return successResult("Package found in Bazaar", packageInfo)
else:
return successResult("Package found in Bazaar", packageInfo)
# Fallback to installed DB check placeholder
# TODO: Implement actual package info retrieval
let packageInfo = %*{
"name": packageName,

View File

@ -4,11 +4,9 @@
## This module provides forward-compatibility hooks for Task 15.2
## and implements immediate diagnostic capabilities
import std/[os, strutils, strformat, tables, sequtils, times, json, asyncdispatch]
import std/[strutils, strformat, sequtils, times, json, asyncdispatch]
import ../security/integrity_monitor
import ../diagnostics/health_monitor
import ../types_fixed
import core
type
DiagnosticSeverity* = enum
@ -156,7 +154,7 @@ proc formatDiagnosticReport*(report: DiagnosticReport, outputFormat: string = "p
else: # plain format
result = "NimPak System Diagnostics\n"
result.add("=" * 30 & "\n\n")
result.add(repeat("=", 30) & "\n\n")
# Overall status
let statusIcon = case report.overall:
@ -166,13 +164,17 @@ proc formatDiagnosticReport*(report: DiagnosticReport, outputFormat: string = "p
of DiagnosticCritical: "🚨"
result.add(fmt"{statusIcon} Overall Status: {report.overall}\n")
result.add(fmt"📅 Generated: {report.timestamp.format(\"yyyy-MM-dd HH:mm:ss\")}\n\n")
let timestampStr = report.timestamp.format("yyyy-MM-dd HH:mm:ss")
result.add(fmt"📅 Generated: {timestampStr}\n\n")
# System information
result.add("System Information:\n")
result.add(fmt" Version: {report.systemInfo[\"nimpak_version\"].getStr()}\n")
result.add(fmt" Platform: {report.systemInfo[\"platform\"].getStr()}\n")
result.add(fmt" Architecture: {report.systemInfo[\"architecture\"].getStr()}\n\n")
let nimpakVersion = report.systemInfo["nimpak_version"].getStr()
result.add(fmt" Version: {nimpakVersion}\n")
let platform = report.systemInfo["platform"].getStr()
result.add(fmt" Platform: {platform}\n")
let architecture = report.systemInfo["architecture"].getStr()
result.add(fmt" Architecture: {architecture}\n\n")
# Diagnostic results
result.add("Diagnostic Results:\n")
@ -232,7 +234,7 @@ proc nipRepoBenchmark*(outputFormat: string = "plain"): string =
return results.pretty()
else:
result = "Repository Benchmark Results\n"
result.add("=" * 35 & "\n\n")
result.add(repeat("=", 35) & "\n\n")
for repo in results["repositories"]:
let status = case repo["status"].getStr():
@ -241,10 +243,15 @@ proc nipRepoBenchmark*(outputFormat: string = "plain"): string =
of "error": "🔴"
else: ""
result.add(fmt"{status} {repo[\"name\"].getStr()}\n")
result.add(fmt" URL: {repo[\"url\"].getStr()}\n")
result.add(fmt" Latency: {repo[\"latency_ms\"].getFloat():.1f}ms\n")
result.add(fmt" Throughput: {repo[\"throughput_mbps\"].getFloat():.1f} MB/s\n\n")
let name = repo["name"].getStr()
let url = repo["url"].getStr()
let latency = repo["latency_ms"].getFloat()
let throughput = repo["throughput_mbps"].getFloat()
result.add(fmt"{status} {name}\n")
result.add(fmt" URL: {url}\n")
result.add(fmt" Latency: {latency:.1f}ms\n")
result.add(fmt" Throughput: {throughput:.1f} MB/s\n\n")
proc nipCacheWarm*(packageName: string): string =
## Pre-pull binary packages into local cache for offline deployment
@ -270,7 +277,7 @@ proc nipMirrorGraph*(outputFormat: string = "plain"): string =
result.add("}\n")
else:
result = "Mirror Network Topology\n"
result.add("=" * 25 & "\n\n")
result.add(repeat("=", 25) & "\n\n")
result.add("Priority Order (High → Low):\n")
result.add(" 1. 🟢 official (100) → community\n")
result.add(" 2. 🔵 community (75) → edge\n")
@ -281,7 +288,7 @@ proc nipMirrorGraph*(outputFormat: string = "plain"): string =
# Forward-Compatibility Hooks for Task 15.2
# =============================================================================
proc nipDoctor*(outputFormat: string = "plain", autoRepair: bool = false): string {.async.} =
proc nipDoctor*(outputFormat: string = "plain", autoRepair: bool = false): Future[string] {.async.} =
## Comprehensive system health check with repair suggestions
try:
# Initialize health monitor
@ -309,7 +316,7 @@ proc nipDoctor*(outputFormat: string = "plain", autoRepair: bool = false): strin
result = fmt"❌ Health check failed: {e.msg}\n"
result.add("💡 Try: nip doctor --force\n")
proc nipRepair*(category: string = "all", dryRun: bool = false): string {.async.} =
proc nipRepair*(category: string = "all", dryRun: bool = false): Future[string] {.async.} =
## System repair command with comprehensive health monitoring integration
result = fmt"🔧 Repair mode: {category}\n"
@ -404,7 +411,7 @@ proc nipInstallWithStream*(packageName: string, repo: string = "",
proc nipTrustExplain*(target: string): string =
## Explain trust policy decisions for repositories or packages
result = fmt"🔍 Trust Analysis: {target}\n"
result.add("=" * (20 + target.len) & "\n\n")
result.add(repeat("=", 20 + target.len) & "\n\n")
# Mock trust analysis
result.add("Trust Score: 0.72 🟡\n\n")

View File

@ -42,6 +42,7 @@ VERIFICATION COMMANDS:
CONFIGURATION COMMANDS:
config show Show current configuration
config validate Validate configuration files
setup <user|system> Setup NIP environment
GLOBAL OPTIONS:
--output <format> Output format: human, json, yaml, kdl
@ -253,6 +254,18 @@ proc showCommandHelp*(command: string) =
echo "nip lock [options] - Generate lockfile for reproducibility"
of "restore":
echo "nip restore <lockfile> [options] - Restore from lockfile"
of "setup":
echo """
nip setup <user|system> - Setup NIP environment
Arguments:
user Configure NIP for the current user (updates shell RC files)
system Configure NIP system-wide (requires root)
Examples:
nip setup user # Add NIP to PATH in ~/.zshrc, ~/.bashrc, etc.
nip setup system # Add NIP to system PATH (not implemented)
"""
else:
echo fmt"Unknown command: {command}"
echo "Use 'nip help' for available commands"

View File

@ -0,0 +1,119 @@
import std/[os, strformat, strutils]
import ../config
import core
proc checkPathConfigured*(): bool =
## Check if NIP binary path is in PATH
let config = loadConfig()
let binPath = config.linksDir / "Executables"
let pathEnv = getEnv("PATH")
# Normalize paths for comparison (remove trailing slashes, resolve symlinks if possible)
# Simple string check for now
return binPath in pathEnv
proc detectShell*(): string =
## Detect the user's shell
let shellPath = getEnv("SHELL")
if shellPath.len > 0:
return shellPath.extractFilename()
return "bash"
proc appendToRcFile(rcFile: string, content: string): bool =
## Append content to an RC file if it's not already there
let home = getHomeDir()
let path = home / rcFile
try:
var currentContent = ""
if fileExists(path):
currentContent = readFile(path)
if content.strip() in currentContent:
return true # Already there
let newContent = if currentContent.len > 0 and not currentContent.endsWith("\n"):
"\n" & content & "\n"
else:
content & "\n"
writeFile(path, currentContent & newContent)
return true
except Exception as e:
echo fmt"❌ Failed to update {rcFile}: {e.msg}"
return false
proc setupUserCommand*(): CommandResult =
## Setup NIP for the current user
let config = loadConfig()
let binPath = config.linksDir / "Executables"
let shell = detectShell()
echo fmt"🌱 Setting up NIP for user (Shell: {shell})..."
echo fmt" Binary Path: {binPath}"
var success = false
case shell:
of "zsh":
let rcContent = fmt"""
# NIP Package Manager
export PATH="{binPath}:$PATH"
"""
if appendToRcFile(".zshrc", rcContent):
echo "✅ Updated .zshrc"
success = true
of "bash":
let rcContent = fmt"""
# NIP Package Manager
export PATH="{binPath}:$PATH"
"""
if appendToRcFile(".bashrc", rcContent):
echo "✅ Updated .bashrc"
success = true
of "fish":
let rcContent = fmt"""
# NIP Package Manager
contains "{binPath}" $fish_user_paths; or set -Ua fish_user_paths "{binPath}"
"""
# Fish is typically in .config/fish/config.fish
# Ensure dir exists
let fishDir = getHomeDir() / ".config" / "fish"
if not dirExists(fishDir):
createDir(fishDir)
if appendToRcFile(".config/fish/config.fish", rcContent):
echo "✅ Updated config.fish"
success = true
else:
return errorResult(fmt"Unsupported shell: {shell}. Please manually add {binPath} to your PATH.")
if success:
echo ""
echo "✨ Setup complete! Please restart your shell or run:"
echo fmt" source ~/.{shell}rc"
return successResult("NIP setup successfully")
else:
return errorResult("Failed to setup NIP")
proc setupSystemCommand*(): CommandResult =
## Setup NIP system-wide
# TODO: Implement system-wide setup (e.g. /etc/profile.d/nip.sh)
return errorResult("System-wide setup not yet implemented")
proc setupCommand*(args: seq[string]): CommandResult =
## Dispatch setup commands
if args.len == 0:
return errorResult("Usage: nip setup <user|system>")
case args[0]:
of "user":
return setupUserCommand()
of "system":
return setupSystemCommand()
else:
return errorResult("Unknown setup target. Use 'user' or 'system'.")

View File

@ -0,0 +1,174 @@
# core/nip/src/nimpak/cli/store_commands.nim
## CLI Commands for Nexus CAS (Content Addressable Storage)
import std/[options, strutils, strformat, terminal, os]
import ../types
import ../errors
import ../cas
import ../logger
proc storeHelpCommand() =
echo """
NIP STORE - Sovereign CAS Interface
USAGE:
nip store <command> [arguments]
COMMANDS:
push <file> Store a file in CAS (returns hash)
fetch <hash> <dest> Retrieve file from CAS by hash
verify <hash> Check if object exists and verify integrity
gc Run garbage collection on CAS
stats Show CAS statistics
path <hash> Show physical path of object (if exists)
EXAMPLES:
nip store push mybinary.elf
nip store fetch xxh3-123... /tmp/restored.elf
nip store verify xxh3-123...
nip store stats
"""
proc storePushCommand*(args: seq[string], verbose: bool): int =
## Push a file to CAS
if args.len < 1:
errorLog("Usage: nip store push <file>")
return 1
let filePath = args[0]
if not fileExists(filePath):
errorLog(fmt"File not found: {filePath}")
return 1
let cas = initCasManager()
if verbose: showInfo(fmt"Storing '{filePath}'...")
let res = cas.storeFile(filePath)
if res.isOk:
let obj = res.get()
if verbose:
showInfo(fmt"Stored successfully.")
showInfo(fmt" Original Size: {obj.size} bytes")
showInfo(fmt" Compressed Size: {obj.compressedSize} bytes")
showInfo(fmt" Chunks: {obj.chunks.len}")
# Output ONLY the hash to stdout for piping support
echo obj.hash
return 0
else:
errorLog(formatError(res.getError()))
return 1
proc storeFetchCommand*(args: seq[string], verbose: bool): int =
## Fetch a file from CAS
if args.len < 2:
errorLog("Usage: nip store fetch <hash> <destination>")
return 1
let hash = args[0]
let destPath = args[1]
# Remove prefix if user typed "fetch cas:<hash>" or similar
let cleanHash = if hash.contains(":"): hash.split(":")[1] else: hash
let cas = initCasManager()
if verbose: showInfo(fmt"Fetching object {cleanHash} to {destPath}...")
let res = cas.retrieveFile(cleanHash, destPath)
if res.isOk:
if verbose: showInfo("Success.")
return 0
else:
errorLog(formatError(res.getError()))
return 1
proc storeVerifyCommand*(args: seq[string], verbose: bool): int =
## Verify object existence and integrity
if args.len < 1:
errorLog("Usage: nip store verify <hash>")
return 1
let hash = args[0]
let cas = initCasManager()
if cas.objectExists(hash):
# Retrieve to verify integrity (checksum check happens during retrieve logic implicitly if we extended it,
# currently retrieveObject just reads. Ideally we should re-hash.)
# Simple existence check for MVP
showInfo(fmt"Object {hash} exists.")
# Check if we can read it
let res = cas.retrieveObject(hash)
if res.isOk:
let data = res.get()
let computed = cas.computeHash(data)
if computed == hash:
showInfo("Integrity: VERIFIED (" & $data.len & " bytes)")
return 0
else:
errorLog(fmt"Integrity: FAILED (Computed: {computed})")
return 1
else:
errorLog("Corruption: Object exists in index/path but cannot be read.")
return 1
else:
errorLog(fmt"Object {hash} NOT FOUND.")
return 1
proc storeStatsCommand*(verbose: bool): int =
let cas = initCasManager()
# MVP stats
# Since we don't have a persistent counter file in this MVP definition other than 'cas_index.kdl' which we parse manually?
# CasManager has 'CasStats' type but no automatic loadStats() method exposed in cas.nim yet.
# We will just show directory sizes.
showInfo("CAS Storage Statistics")
showInfo(fmt"Root: {cas.rootPath}")
# Simple walkdir to count
var count = 0
var size = 0'i64
for kind, path in walkDir(cas.rootPath / "objects", relative=true):
# Recurse... for MVP just simple ls of shards
discard
showInfo("(Detailed stats pending implementation)")
return 0
proc storePathCommand*(args: seq[string], verbose: bool): int =
if args.len < 1:
return 1
let hash = args[0]
let cas = initCasManager()
let path = getObjectPath(cas.rootPath, hash)
if fileExists(path):
echo path
return 0
else:
return 1
proc dispatchStoreCommand*(args: seq[string], verbose: bool): int =
if args.len == 0:
storeHelpCommand()
return 0
let cmd = args[0].toLowerAscii()
let subArgs = if args.len > 1: args[1..^1] else: @[]
case cmd
of "push": return storePushCommand(subArgs, verbose)
of "fetch", "pull": return storeFetchCommand(subArgs, verbose)
of "verify": return storeVerifyCommand(subArgs, verbose)
of "stats": return storeStatsCommand(verbose)
of "path": return storePathCommand(subArgs, verbose)
of "help":
storeHelpCommand()
return 0
else:
errorLog(fmt"Unknown store command: {cmd}")
storeHelpCommand()
return 1

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## config.nim
## Configuration management for NIP MVP
## Simple key-value configuration format
@ -396,3 +403,17 @@ proc saveExampleConfig*(path: string): bool =
except:
echo fmt"❌ Failed to create config at: {path}"
return false
proc getConfigPath*(): string =
## Get the default user configuration file path
let homeDir = getHomeDir()
let xdgConfigHome = getEnv("XDG_CONFIG_HOME", homeDir / ".config")
result = xdgConfigHome / "nip" / "config"
proc initDefaultConfig*() =
## Initialize default configuration if it doesn't exist
let path = getConfigPath()
if not fileExists(path):
if not saveExampleConfig(path):
raise newException(IOError, "Failed to create configuration file")
else:
raise newException(IOError, "Configuration file already exists")

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Quantum-Resistant Cryptographic Transitions
##
## This module implements the algorithm migration framework for transitioning

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/database.nim
## Simple package database for MVP implementation
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/decentralized.nim
## Decentralized Architecture Foundation for Nippels
##

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/dependency.nim
# Dependency graph resolution and management system
import std/[tables, sets, sequtils, algorithm, strformat]
import ../nip/types
import ./types
type
DependencyGraph* = object

View File

@ -8,10 +8,8 @@
## - Automated repair and recovery systems
## - Performance monitoring and optimization
import std/[os, times, json, tables, sequtils, strutils, strformat, asyncdispatch, algorithm]
import std/[os, times, json, tables, sequtils, strutils, strformat, asyncdispatch]
import ../security/[integrity_monitor, event_logger]
import ../cas
import ../types_fixed
type
HealthCheckCategory* = enum
@ -92,11 +90,15 @@ proc getDefaultHealthMonitorConfig*(): HealthMonitorConfig =
}
)
# Forward declarations
proc getDirSize*(path: string): int64
proc formatHealthReport*(report: HealthReport, format: string = "plain"): string
# =============================================================================
# Package Health Checks
# =============================================================================
proc checkPackageIntegrity*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkPackageIntegrity*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check integrity of all installed packages
let startTime = cpuTime()
var check = HealthCheck(
@ -157,7 +159,7 @@ proc checkPackageIntegrity*(monitor: HealthMonitor): HealthCheck {.async.} =
check.duration = cpuTime() - startTime
return check
proc checkPackageConsistency*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkPackageConsistency*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check consistency of package installations and dependencies
let startTime = cpuTime()
var check = HealthCheck(
@ -227,7 +229,7 @@ proc checkPackageConsistency*(monitor: HealthMonitor): HealthCheck {.async.} =
# Filesystem Health Checks
# =============================================================================
proc checkFilesystemHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkFilesystemHealth*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check filesystem health and disk usage
let startTime = cpuTime()
var check = HealthCheck(
@ -269,8 +271,9 @@ proc checkFilesystemHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
missingDirs.add(dir)
if missingDirs.len > 0:
let missingDirsStr = missingDirs.join(", ")
check.status = StatusCritical
check.message = fmt"Critical directories missing: {missingDirs.join(\", \")}"
check.message = fmt"Critical directories missing: {missingDirsStr}"
check.repairActions = @["nip repair --filesystem", "nip init --restore-structure"]
elif totalSize > 10 * 1024 * 1024 * 1024: # > 10GB
check.status = StatusWarning
@ -293,7 +296,7 @@ proc checkFilesystemHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
# Cache Health Checks
# =============================================================================
proc checkCacheHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkCacheHealth*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check cache performance and integrity
let startTime = cpuTime()
var check = HealthCheck(
@ -311,7 +314,8 @@ proc checkCacheHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
try:
# Initialize CAS manager for cache stats
let casManager = newCasManager("~/.nip/cas", "/var/lib/nip/cas")
# Initialize CAS manager for cache stats (stubbed for now if unused)
# let casManager = newCasManager("~/.nip/cas", "/var/lib/nip/cas")
# Simulate cache statistics (would be real in production)
let cacheStats = %*{
@ -338,8 +342,9 @@ proc checkCacheHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
check.message = fmt"High cache fragmentation: {fragmentation:.2f}"
check.repairActions = @["nip cache defrag", "nip cache rebuild"]
else:
let objectCount = cacheStats["object_count"].getInt()
check.status = StatusHealthy
check.message = fmt"Cache healthy: {hitRate:.2f} hit rate, {cacheStats[\"object_count\"].getInt()} objects"
check.message = fmt"Cache healthy: {hitRate:.2f} hit rate, {objectCount} objects"
except Exception as e:
check.status = StatusCritical
@ -354,7 +359,7 @@ proc checkCacheHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
# Repository Health Checks
# =============================================================================
proc checkRepositoryHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkRepositoryHealth*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check repository connectivity and trust status
let startTime = cpuTime()
var check = HealthCheck(
@ -441,7 +446,7 @@ proc checkRepositoryHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
# Security Health Checks
# =============================================================================
proc checkSecurityHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkSecurityHealth*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Check security status including keys, signatures, and trust policies
let startTime = cpuTime()
var check = HealthCheck(
@ -484,8 +489,9 @@ proc checkSecurityHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
check.message = fmt"{expiredKeys} expired keys need rotation"
check.repairActions = @["nip keys rotate", "nip trust update"]
else:
let activeKeys = securityStatus["active_keys"].getInt()
check.status = StatusHealthy
check.message = fmt"Security healthy: {securityStatus[\"active_keys\"].getInt()} active keys, no critical issues"
check.message = fmt"Security healthy: {activeKeys} active keys, no critical issues"
except Exception as e:
check.status = StatusCritical
@ -500,7 +506,7 @@ proc checkSecurityHealth*(monitor: HealthMonitor): HealthCheck {.async.} =
# Performance Monitoring
# =============================================================================
proc checkPerformanceMetrics*(monitor: HealthMonitor): HealthCheck {.async.} =
proc checkPerformanceMetrics*(monitor: HealthMonitor): Future[HealthCheck] {.async.} =
## Monitor system performance metrics
let startTime = cpuTime()
var check = HealthCheck(
@ -559,7 +565,7 @@ proc checkPerformanceMetrics*(monitor: HealthMonitor): HealthCheck {.async.} =
# Health Report Generation
# =============================================================================
proc runAllHealthChecks*(monitor: HealthMonitor): HealthReport {.async.} =
proc runAllHealthChecks*(monitor: HealthMonitor): Future[HealthReport] {.async.} =
## Run all enabled health checks and generate comprehensive report
let startTime = now()
var checks: seq[HealthCheck] = @[]
@ -621,7 +627,7 @@ proc runAllHealthChecks*(monitor: HealthMonitor): HealthReport {.async.} =
# Automated Repair System
# =============================================================================
proc performAutomatedRepair*(monitor: HealthMonitor, report: HealthReport): seq[string] {.async.} =
proc performAutomatedRepair*(monitor: HealthMonitor, report: HealthReport): Future[seq[string]] {.async.} =
## Perform automated repairs based on health report
var repairResults: seq[string] = @[]
@ -698,7 +704,7 @@ proc formatHealthReport*(report: HealthReport, format: string = "plain"): string
else: # plain format
result = "NimPak System Health Report\n"
result.add("=" * 35 & "\n\n")
result.add(repeat("=", 35) & "\n\n")
# Overall status
let statusIcon = case report.overallStatus:
@ -708,7 +714,8 @@ proc formatHealthReport*(report: HealthReport, format: string = "plain"): string
of StatusUnknown: ""
result.add(fmt"{statusIcon} Overall Status: {report.overallStatus}\n")
result.add(fmt"📅 Generated: {report.timestamp.format(\"yyyy-MM-dd HH:mm:ss\")}\n\n")
let timestampStr = report.timestamp.format("yyyy-MM-dd HH:mm:ss")
result.add(fmt"📅 Generated: {timestampStr}\n\n")
# Health checks by category
let categories = [CategoryPackages, CategoryFilesystem, CategoryCache, CategoryRepositories, CategorySecurity, CategoryPerformance]

View File

@ -1,11 +1,18 @@
## NimPak Error Handling
##
## Comprehensive error handling utilities for the NimPak system.
## Provides formatted error messages, recovery suggestions, and error chaining.
## Task 37: Implement comprehensive error handling.
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# NimPak Error Handling
#
# Comprehensive error handling utilities for the NimPak system.
# Provides formatted error messages, recovery suggestions, and error chaining.
# Task 37: Implement comprehensive error handling.
import std/[strformat, strutils, times, tables, terminal]
import ../nip/types
import ./types
# ############################################################################
# Error Formatting

Binary file not shown.

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/filesystem.nim
## GoboLinux-style filesystem management with generation integration
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Package Format CAS Integration
##
## This module integrates all package formats with the Content-Addressable Storage

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Package Format Infrastructure
##
## This module implements the core package format system with five distinct formats,
@ -1041,14 +1048,14 @@ proc storePackageInCas*(format: PackageFormat, data: seq[byte], cas: var CasMana
## Store package format data in content-addressable storage
try:
let storeResult = cas.storeObject(data)
if storeResult.isErr:
if not storeResult.isOk:
return types_fixed.err[CasIntegrationResult, FormatError](FormatError(
code: CasError,
msg: "Failed to store package in CAS: " & storeResult.getError().msg,
code: CasGeneralError,
msg: "Failed to store package in CAS: " & storeResult.errValue.msg,
format: format
))
let casObject = storeResult.get()
let casObject = storeResult.okValue
let result = CasIntegrationResult(
hash: casObject.hash,
size: casObject.size,
@ -1073,14 +1080,14 @@ proc retrievePackageFromCas*(hash: string, cas: var CasManager): types_fixed.Res
## Retrieve package format data from content-addressable storage
try:
let retrieveResult = cas.retrieveObject(hash)
if retrieveResult.isErr:
if not retrieveResult.isOk:
return types_fixed.err[seq[byte], FormatError](FormatError(
code: CasError,
msg: "Failed to retrieve package from CAS: " & retrieveResult.getError().msg,
code: CasGeneralError,
msg: "Failed to retrieve package from CAS: " & retrieveResult.errValue.msg,
format: NpkBinary # Default format for error
))
return types_fixed.ok[seq[byte], FormatError](retrieveResult.get())
return types_fixed.ok[seq[byte], FormatError](retrieveResult.okValue)
except Exception as e:
return types_fixed.err[seq[byte], FormatError](FormatError(
@ -1126,14 +1133,14 @@ proc garbageCollectFormats*(cas: var CasManager, reachableHashes: seq[string] =
let reachableSet = reachableHashes.toHashSet()
let gcResult = cas.garbageCollect(reachableSet)
if gcResult.isErr:
if not gcResult.isOk:
return types_fixed.err[int, FormatError](FormatError(
code: CasError,
msg: "Failed to garbage collect: " & gcResult.getError().msg,
code: CasGeneralError,
msg: "Failed to garbage collect: " & gcResult.errValue.msg,
format: NpkBinary
))
return types_fixed.ok[int, FormatError](gcResult.get())
return types_fixed.ok[int, FormatError](gcResult.okValue)
except Exception as e:
return types_fixed.err[int, FormatError](FormatError(
@ -1227,17 +1234,17 @@ proc convertPackageFormat*(fromPath: string, toPath: string,
# Store in CAS for conversion pipeline
let storeResult = storePackageInCas(fromFormat, sourceBytes, cas)
if storeResult.isErr:
return err[FormatError](storeResult.getError())
if not storeResult.isOk:
return err[FormatError](storeResult.errValue)
let casResult = storeResult.get()
let casResult = storeResult.okValue
# Retrieve and convert (simplified conversion logic)
let retrieveResult = retrievePackageFromCas(casResult.hash, cas)
if retrieveResult.isErr:
return err[FormatError](retrieveResult.getError())
if not retrieveResult.isOk:
return err[FormatError](retrieveResult.errValue)
let convertedData = retrieveResult.get()
let convertedData = retrieveResult.okValue
# Write converted package
let parentDir = toPath.parentDir()
@ -1264,10 +1271,10 @@ proc reconstructPackageFromCas*(hash: string, format: PackageFormat,
## Reconstruct package from CAS storage with format-specific handling
try:
let retrieveResult = retrievePackageFromCas(hash, cas)
if retrieveResult.isErr:
return err[FormatError](retrieveResult.getError())
if not retrieveResult.isOk:
return err[FormatError](retrieveResult.errValue)
let data = retrieveResult.get()
let data = retrieveResult.okValue
# Format-specific reconstruction logic
case format:
@ -1313,7 +1320,7 @@ proc getPackageFormatStats*(cas: var CasManager): types_fixed.Result[JsonNode, F
for objHash in objects:
let retrieveResult = cas.retrieveObject(objHash)
if retrieveResult.isOk:
let data = retrieveResult.get()
let data = retrieveResult.okValue
let size = data.len.int64
# Simple format detection based on content

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Enhanced Garbage Collection System
##
## This module implements an enhanced garbage collection system for the unified

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/generation_filesystem.nim
## Generation-aware filesystem operations for NimPak
##

View File

@ -1,12 +1,19 @@
## graft_coordinator.nim
## Coordinates grafting from adapters and installation
## Ties together adapters + install_manager for unified grafting
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# graft_coordinator.nim
# Coordinates grafting from adapters and installation
# Ties together adapters + install_manager for unified grafting
import std/[strformat, strutils, json, os]
import install_manager, simple_db, config
import adapters/[nix, pacman, pkgsrc, aur]
import grafting # For GraftResult type
from cas import get
import types
type
GraftCoordinator* = ref object
@ -392,10 +399,11 @@ proc parsePackageSpec*(spec: string): tuple[source: GraftSource, name: string] =
let name = parts[1]
let source = case sourceStr
of "nix": Nix
of "pkgsrc": PKGSRC
of "pacman": Pacman
else: Auto
of "nix": GraftSource.Nix
of "pkgsrc": GraftSource.PKGSRC
of "pacman": GraftSource.Pacman
of "aur": GraftSource.AUR
else: GraftSource.Auto
return (source, name)
else:

View File

@ -1,9 +1,16 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/grafting_simple.nim
# Simplified grafting infrastructure for external package integration
import std/[tables, sets, strutils, json, os, times, sequtils, hashes, options]
import ../nip/types
import utils/resultutils
import ./types
import types/grafting_types
export grafting_types
@ -39,33 +46,33 @@ proc initGraftingEngine*(configPath: string = ""): Result[GraftingEngine, string
try:
createDir(engine.cache.cacheDir)
except OSError as e:
return Result[GraftingEngine, string](isOk: false, error: "Failed to create cache directory: " & e.msg)
return Result[GraftingEngine, string](isOk: false, errValue: "Failed to create cache directory: " & e.msg)
return Result[GraftingEngine, string](isOk: true, value: engine)
return Result[GraftingEngine, string](isOk: true, okValue: engine)
proc registerAdapter*(engine: var GraftingEngine, adapter: PackageAdapter): Result[bool, string] =
## Register a package adapter with the grafting engine
if adapter.name in engine.adapters:
return Result[bool, string](isOk: false, error: "Adapter already registered: " & adapter.name)
return Result[bool, string](isOk: false, errValue: "Adapter already registered: " & adapter.name)
engine.adapters[adapter.name] = adapter
echo "Registered grafting adapter: " & adapter.name
return Result[bool, string](isOk: true, value: true)
return Result[bool, string](isOk: true, okValue: true)
proc graftPackage*(engine: var GraftingEngine, source: string, packageName: string): Result[GraftResult, string] =
## Graft a package from an external source
if not engine.config.enabled:
return Result[GraftResult, string](isOk: false, error: "Grafting is disabled in configuration")
return Result[GraftResult, string](isOk: false, errValue: "Grafting is disabled in configuration")
if source notin engine.adapters:
return Result[GraftResult, string](isOk: false, error: "Unknown grafting source: " & source)
return Result[GraftResult, string](isOk: false, errValue: "Unknown grafting source: " & source)
let adapter = engine.adapters[source]
if not adapter.enabled:
return Result[GraftResult, string](isOk: false, error: "Adapter disabled: " & source)
return Result[GraftResult, string](isOk: false, errValue: "Adapter disabled: " & source)
# Create a simple result for now
let result = GraftResult(
let graftRes = GraftResult(
success: true,
packageId: packageName,
metadata: GraftedPackageMetadata(
@ -89,7 +96,7 @@ proc graftPackage*(engine: var GraftingEngine, source: string, packageName: stri
)
echo "Successfully grafted package: " & packageName
return ok[GraftResult](result)
return Result[GraftResult, string](isOk: true, okValue: graftRes)
proc listGraftedPackages*(engine: GraftingEngine): seq[GraftedPackageMetadata] =
## List all grafted packages in cache
@ -129,11 +136,11 @@ method graftPackage*(adapter: PackageAdapter, packageName: string, cache: Grafti
method validatePackage*(adapter: PackageAdapter, packageName: string): Result[bool, string] {.base.} =
## Base method for validating a package - can be overridden
return ok[bool](true)
return Result[bool, string](isOk: true, okValue: true)
method getPackageInfo*(adapter: PackageAdapter, packageName: string): Result[JsonNode, string] {.base.} =
## Base method for getting package information - can be overridden
return ok[JsonNode](%*{"name": packageName, "adapter": adapter.name})
return Result[JsonNode, string](isOk: true, okValue: %*{"name": packageName, "adapter": adapter.name})
# Utility functions
proc calculateGraftHash*(packageName: string, source: string, timestamp: DateTime): string =

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/grafting.nim
# Core grafting infrastructure for external package integration
import std/[tables, sets, strutils, json, os, times, sequtils, hashes, options]
import ../nip/types
import ./types
import utils/resultutils
import types/grafting_types

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/grafting_working.nim
# Working grafting infrastructure for external package integration
import std/[tables, strutils, json, os, times, sequtils, options, hashes]
import ../nip/types
import ./types
import utils/resultutils
import types/grafting_types

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/install.nim
# Package installation orchestrator with atomic operations
import std/[tables, sequtils, strformat]
import ../nip/types, dependency, transactions, filesystem, cas
import ./types, dependency, transactions, filesystem, cas
type
InstallStep* = object

View File

@ -1,9 +1,17 @@
## install_manager.nim
## Unified installation system for NIP MVP
## Coordinates grafting from adapters and actual system installation
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# install_manager.nim
# Unified installation system for NIP MVP
# Coordinates grafting from adapters and actual system installation
import std/[os, times, json, strformat, strutils, tables, sequtils, algorithm]
import cas
import ./types
type
InstallConfig* = object

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## KDL Parser Integration for NIP
## Provides KDL parsing functionality for NIP configuration and package files

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/lockfile_system.nim
## Lockfile generation and reproducibility system for NimPak
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## logger.nim
## Logging system for NIP MVP

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NimPak Structured Logging
##
## Comprehensive logging system for the NimPak package manager.

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Merkle Tree Implementation for Nippels
##
## This module implements a high-performance merkle tree for cryptographic

View File

@ -1,10 +1,17 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NimPak Migration Tools
##
## Tools for migrating from legacy formats and other package managers.
## Task 42: Implement migration tools.
import std/[os, strutils, strformat, json, tables, sequtils, times]
import ../nip/types
import ./types
import cas
import logging

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/namespace_subsystem.nim
## Namespace Subsystem for Nippels
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/nexter_comm.nim
## Nippel-Nexter Communication Foundation

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/nippel_types.nim
## Core type definitions for Nippels
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/nippels.nim
## Nippels: Lightweight, namespace-based application isolation
##

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/nippels_cli.nim
## Enhanced CLI commands for Nippels management
##

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/npk_conversion.nim
# Enhanced NPK conversion with build hash integration
import std/[strutils, json, os, times, tables, sequtils, strformat, algorithm, osproc]
import ../nip/types
import ./types
import utils/resultutils
import types/grafting_types

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NOF Overlay Fragment Format Handler (.nof)
##
## This module implements the NOF (Nexus Overlay Fragment) format for declarative

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NPK Package Format Handler
##
## This module implements the native .npk.zst package format with KDL metadata
@ -16,6 +23,7 @@ import std/[os, json, times, strutils, sequtils, tables, options, osproc, strfor
import ./types_fixed
import ./formats
import ./cas except Result, VoidResult, ok, err, ChunkRef
import ./grafting
# KDL parsing will be added when kdl library is available
# For now, we'll use JSON as intermediate format and generate KDL strings
@ -54,12 +62,12 @@ proc createNpkPackage*(fragment: Fragment, sourceDir: string, cas: var CasManage
let storeResult = cas.storeFile(filePath)
if not storeResult.isOk:
return err[NpkPackage, NpkError](NpkError(
code: CasError,
msg: "Failed to store file in CAS: " & storeResult.getError().msg,
code: CasGeneralError,
msg: "Failed to store file in CAS: " & storeResult.errValue.msg,
packageName: fragment.id.name
))
let casObject = storeResult.get()
let casObject = storeResult.okValue
let packageFile = PackageFile(
path: relativePath,
@ -455,7 +463,7 @@ proc extractNpkPackage*(npk: NpkPackage, targetDir: string, cas: var CasManager)
let retrieveResult = cas.retrieveFile(file.hash, targetPath)
if not retrieveResult.isOk:
return err[NpkError](NpkError(
code: CasError,
code: CasGeneralError,
msg: "Failed to retrieve file from CAS: " & retrieveResult.errValue.msg,
packageName: npk.metadata.id.name
))
@ -673,29 +681,75 @@ proc convertGraftToNpk*(graftResult: GraftResult, cas: var CasManager): Result[N
## This includes preserving provenance and audit log information
## Files are stored in CAS for deduplication and integrity verification
# Use the fragment and extractedPath from graftResult to create NPK package
let createResult = createNpkPackage(graftResult.fragment, graftResult.extractedPath, cas)
# Construct Fragment from GraftResult metadata
let pkgId = PackageId(
name: graftResult.metadata.packageName,
version: graftResult.metadata.version,
stream: Custom # Default to Custom for grafts
)
let source = Source(
url: graftResult.metadata.provenance.downloadUrl,
hash: graftResult.metadata.originalHash,
hashAlgorithm: "blake2b", # Default assumption
sourceMethod: Grafted,
timestamp: graftResult.metadata.graftedAt
)
let fragment = Fragment(
id: pkgId,
source: source,
dependencies: @[], # Dependencies not captured in simple GraftResult
buildSystem: Custom,
metadata: PackageMetadata(
description: "Grafted from " & graftResult.metadata.source,
license: "Unknown",
maintainer: "Auto-Graft",
tags: @["grafted"],
runtime: RuntimeProfile(
libc: Glibc, # Assumption
allocator: System,
systemdAware: false,
reproducible: false,
tags: @[]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "Grafted package",
buildLog: graftResult.metadata.buildLog
)
)
let extractedPath = graftResult.metadata.provenance.extractedPath
if extractedPath.len == 0 or not dirExists(extractedPath):
return err[NpkPackage, NpkError](NpkError(
code: PackageNotFound,
msg: "Extracted path not found or empty in graft result",
packageName: pkgId.name
))
# Use the constructed fragment and extractedPath to create NPK package
let createResult = createNpkPackage(fragment, extractedPath, cas)
if not createResult.isOk:
return err[NpkPackage, NpkError](createResult.getError())
return err[NpkPackage, NpkError](createResult.errValue)
var npk = createResult.get()
# Map provenance information from auditLog and originalMetadata
# Embed audit log info into ACUL compliance buildLog for traceability
npk.metadata.acul.buildLog = graftResult.auditLog.sourceOutput
var npk = createResult.okValue
# Map provenance information
# Add provenance information to runtime tags for tracking
let provenanceTag = "grafted:" & $graftResult.auditLog.source & ":" & $graftResult.auditLog.timestamp
let provenanceTag = "grafted:" & graftResult.metadata.source & ":" & $graftResult.metadata.graftedAt
npk.metadata.metadata.runtime.tags.add(provenanceTag)
# Add deduplication status to tags for audit purposes
let deduplicationTag = "dedup:" & graftResult.auditLog.deduplicationStatus.toLowerAscii()
# Add deduplication status to tags for audit purposes (simplified)
let deduplicationTag = "dedup:unknown"
npk.metadata.metadata.runtime.tags.add(deduplicationTag)
# Preserve original archive hash in attribution for full traceability
# Preserve original archive hash in attribution
if npk.metadata.acul.attribution.len > 0:
npk.metadata.acul.attribution.add(" | ")
npk.metadata.acul.attribution.add("Original: " & graftResult.auditLog.blake2bHash)
npk.metadata.acul.attribution.add("Original: " & graftResult.metadata.originalHash)
# Return the constructed NPK package with full provenance
return ok[NpkPackage, NpkError](npk)

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NIP Pacman CLI Integration
##
## This module provides CLI commands that make NIP a drop-in replacement

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## platform.nim
## Platform detection and BSD compatibility

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/profile_manager.nim
## Profile Manager for Nippels
##

View File

@ -1,49 +1,42 @@
## Read-Only Protection Manager
##
## This module implements the read-only protection system for CAS storage,
## ensuring immutability by default with controlled write access elevation.
##
## SECURITY NOTE: chmod-based protection is a UX feature, NOT a security feature!
## In user-mode (~/.local/share/nexus/cas/), chmod 555 only prevents ACCIDENTAL
## deletion/modification. A user who owns the files can bypass this trivially.
##
## Real security comes from:
## 1. Merkle tree verification (cryptographic integrity)
## 2. User namespaces (kernel-enforced read-only mounts during execution)
## 3. Root ownership (system-mode only: /var/lib/nexus/cas/)
##
## See docs/cas-security-architecture.md for full security model.
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# Read-Only Protection Manager
#
# This module implements the read-only protection system for CAS storage,
# ensuring immutability by default with controlled write access elevation.
#
# SECURITY NOTE: chmod-based protection is a UX feature, NOT a security feature!
# In user-mode (~/.local/share/nexus/cas/), chmod 555 only prevents ACCIDENTAL
# deletion/modification. A user who owns the files can bypass this trivially.
#
# Real security comes from:
# 1. Merkle tree verification (cryptographic integrity)
# 2. User namespaces (kernel-enforced read-only mounts during execution)
# 3. Root ownership (system-mode only: /var/lib/nexus/cas/)
#
# See docs/cas-security-architecture.md for full security model.
import std/[os, times, sequtils, strutils]
import xxhash
import ./types
type
# Result types for error handling
VoidResult*[E] = object
case isOk*: bool
of true:
discard
of false:
errValue*: E
# Error types
ErrorCode* = enum
FileWriteError, FileReadError, UnknownError
CasError* = object of CatchableError
code*: ErrorCode
objectHash*: string
ProtectionManager* = object
casPath*: string ## Path to CAS root directory
auditLog*: string ## Path to audit log file
casPath*: string # Path to CAS root directory
auditLog*: string # Path to audit log file
SecurityError* = object of CatchableError
code*: string
context*: string
SecurityEvent* = object
timestamp*: DateTime
eventType*: string
hash*: string
details*: string
severity*: string # "info", "warning", "critical"
proc ok*[E](dummy: typedesc[E]): VoidResult[E] =
VoidResult[E](isOk: true)
proc newProtectionManager*(casPath: string): ProtectionManager =
## Create a new protection manager for the given CAS path
@ -69,35 +62,35 @@ proc logOperation*(pm: ProtectionManager, op: string, path: string, hash: string
# (better to allow operation than to fail)
discard
proc setReadOnly*(pm: ProtectionManager): VoidResult[CasError] =
proc setReadOnly*(pm: ProtectionManager): VoidResult[NimPakError] =
## Set CAS directory to read-only (chmod 555)
try:
setFilePermissions(pm.casPath, {fpUserRead, fpUserExec,
fpGroupRead, fpGroupExec,
fpOthersRead, fpOthersExec})
pm.logOperation("SET_READONLY", pm.casPath)
return ok(CasError)
return ok(NimPakError)
except OSError as e:
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: FileWriteError,
msg: "Failed to set read-only permissions: " & e.msg
))
proc setWritable*(pm: ProtectionManager): VoidResult[CasError] =
proc setWritable*(pm: ProtectionManager): VoidResult[NimPakError] =
## Set CAS directory to writable (chmod 755)
try:
setFilePermissions(pm.casPath, {fpUserRead, fpUserWrite, fpUserExec,
fpGroupRead, fpGroupExec,
fpOthersRead, fpOthersExec})
pm.logOperation("SET_WRITABLE", pm.casPath)
return ok(CasError)
return ok(NimPakError)
except OSError as e:
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: FileWriteError,
msg: "Failed to set writable permissions: " & e.msg
))
proc withWriteAccess*(pm: ProtectionManager, operation: proc()): VoidResult[CasError] =
proc withWriteAccess*(pm: ProtectionManager, operation: proc()): VoidResult[NimPakError] =
## Execute operation with temporary write access, then restore read-only
## This ensures atomic permission elevation and restoration
var oldPerms: set[FilePermission]
@ -119,7 +112,7 @@ proc withWriteAccess*(pm: ProtectionManager, operation: proc()): VoidResult[CasE
if not setReadOnlyResult.isOk:
return setReadOnlyResult
return ok(CasError)
return ok(NimPakError)
except Exception as e:
# Ensure permissions restored even on error
@ -129,12 +122,12 @@ proc withWriteAccess*(pm: ProtectionManager, operation: proc()): VoidResult[CasE
except:
discard # Best effort to restore
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: UnknownError,
msg: "Write operation failed: " & e.msg
))
proc ensureReadOnly*(pm: ProtectionManager): VoidResult[CasError] =
proc ensureReadOnly*(pm: ProtectionManager): VoidResult[NimPakError] =
## Ensure CAS directory is in read-only state
## This should be called during initialization
return pm.setReadOnly()
@ -152,18 +145,7 @@ proc verifyReadOnly*(pm: ProtectionManager): bool =
# Merkle Integrity Verification
# This is the PRIMARY security mechanism (not chmod)
type
IntegrityViolation* = object of CatchableError
hash*: string
expectedHash*: string
chunkPath*: string
SecurityEvent* = object
timestamp*: DateTime
eventType*: string
hash*: string
details*: string
severity*: string # "info", "warning", "critical"
proc logSecurityEvent*(pm: ProtectionManager, event: SecurityEvent) =
## Log security events (integrity violations, tampering attempts, etc.)
@ -180,7 +162,7 @@ proc logSecurityEvent*(pm: ProtectionManager, event: SecurityEvent) =
# If we can't write to audit log, at least try stderr
stderr.writeLine("SECURITY EVENT: " & event.eventType & " - " & event.details)
proc verifyChunkIntegrity*(pm: ProtectionManager, data: seq[byte], expectedHash: string): VoidResult[CasError] =
proc verifyChunkIntegrity*(pm: ProtectionManager, data: seq[byte], expectedHash: string): VoidResult[NimPakError] =
## Verify chunk integrity by recalculating hash
## This is the PRIMARY security mechanism - always verify before use
try:
@ -197,9 +179,9 @@ proc verifyChunkIntegrity*(pm: ProtectionManager, data: seq[byte], expectedHash:
)
pm.logSecurityEvent(event)
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: UnknownError,
objectHash: expectedHash,
context: "Object Hash: " & expectedHash,
msg: "Chunk integrity violation detected! Expected: " & expectedHash &
", Got: " & calculatedHash & ". This chunk may be corrupted or tampered with."
))
@ -214,26 +196,26 @@ proc verifyChunkIntegrity*(pm: ProtectionManager, data: seq[byte], expectedHash:
)
pm.logSecurityEvent(event)
return ok(CasError)
return ok(NimPakError)
except Exception as e:
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: UnknownError,
msg: "Failed to verify chunk integrity: " & e.msg,
objectHash: expectedHash
context: "Object Hash: " & expectedHash
))
proc verifyChunkIntegrityFromFile*(pm: ProtectionManager, filePath: string, expectedHash: string): VoidResult[CasError] =
proc verifyChunkIntegrityFromFile*(pm: ProtectionManager, filePath: string, expectedHash: string): VoidResult[NimPakError] =
## Verify chunk integrity by reading file and checking hash
try:
let data = readFile(filePath)
let byteData = data.toOpenArrayByte(0, data.len - 1).toSeq()
return pm.verifyChunkIntegrity(byteData, expectedHash)
except IOError as e:
return VoidResult[CasError](isOk: false, errValue: CasError(
return VoidResult[NimPakError](isOk: false, errValue: NimPakError(
code: FileReadError,
msg: "Failed to read chunk file for verification: " & e.msg,
objectHash: expectedHash
context: "Object Hash: " & expectedHash
))
proc scanCASIntegrity*(pm: ProtectionManager, casPath: string): tuple[verified: int, corrupted: seq[string]] =

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NPR Recipe Format Handler (.npr)
##
## This module implements the NPR (Nexus Package Recipe) format for source-level

View File

@ -513,12 +513,20 @@ proc fetchBinaryPackage*(packageName: string, version: string, url: string,
# Return CAS path
return FetchResult[string](
success: true,
value: storeResult.get().hash,
value: storeResult.okValue.hash,
bytesTransferred: fetchRes.bytesTransferred,
duration: fetchRes.duration
)
return result
# Store failed
return FetchResult[string](
success: false,
error: "Failed to store package in CAS: " & storeResult.errValue.msg,
errorCode: 500
)
# Fetch failed
return fetchRes
# =============================================================================
# CLI Integration

View File

@ -572,7 +572,7 @@ proc createDeltaObject*(engine: SyncEngine, objectHash: string): SyncResult[Delt
errorCode: 404
)
let originalData = objectResult.value
let originalData = objectResult.okValue
let originalSize = int64(originalData.len)
# Compress the data using zstd
@ -630,7 +630,7 @@ proc applyDeltaObject*(engine: SyncEngine, delta: DeltaObject): SyncResult[bool]
if not storeResult.isOk:
return SyncResult[bool](
success: false,
error: fmt"Failed to store object: {storeResult.error.msg}",
error: fmt"Failed to store object: {storeResult.errValue.msg}",
errorCode: 500
)

View File

@ -21,6 +21,8 @@ import ../security/signature_verifier
import ../security/provenance_tracker
import ../remote/manager
import ../types/grafting_types
type
PublishConfig* = object
## Configuration for publishing packages
@ -54,7 +56,7 @@ type
of FromCas:
files*: seq[types_fixed.PackageFile]
of FromGraft:
graftResult*: types_fixed.GraftResult
graftResult*: grafting_types.GraftResult
ArtifactBuilder* = ref object
cas*: CasManager
@ -103,10 +105,10 @@ proc buildFromDirectory*(builder: ArtifactBuilder,
# Store in CAS and get hash
let storeResult = builder.cas.storeObject(dataBytes)
if cas.isErr(storeResult):
if not storeResult.isOk:
return types_fixed.err[NpkPackage, string]("Failed to store file " & file & " in CAS")
let casObj = cas.get(storeResult)
let casObj = storeResult.okValue
let info = getFileInfo(fullPath)
files.add(PackageFile(
@ -359,8 +361,8 @@ proc publish*(builder: ArtifactBuilder,
archiveData.toOpenArrayByte(0, archiveData.len - 1).toSeq()
)
if not cas.isErr(storeResult):
result.casHash = cas.get(storeResult).hash
if storeResult.isOk:
result.casHash = storeResult.okValue.hash
# Step 5: Upload to repository (if configured)
if builder.config.repoId.len > 0:

View File

@ -5,19 +5,18 @@
## Supports BLAKE2b (primary) and BLAKE3 (future) with algorithm detection and fallback.
import std/[os, streams, strutils, strformat, times, options]
import nimcrypto/[blake2, sha2]
import nimcrypto/blake2
type
HashAlgorithm* = enum
HashBlake2b = "blake2b"
HashBlake3 = "blake3" # Future implementation
HashSha256 = "sha256" # Legacy support
HashBlake3 = "blake3" # Future implementation
HashResult* = object
algorithm*: HashAlgorithm
digest*: string
verified*: bool
computeTime*: float # Seconds taken to compute
computeTime*: float # Seconds taken to compute
HashVerificationError* = object of CatchableError
algorithm*: HashAlgorithm
@ -26,9 +25,8 @@ type
StreamingHasher* = object
algorithm*: HashAlgorithm
blake2bContext*: blake2_512 # BLAKE2b-512 context
sha256Context*: sha256 # SHA256 context for legacy support
# blake3Context*: Blake3Context # Future BLAKE3 context
blake2bContext*: blake2_512 # BLAKE2b-512 context
# blake3Context*: Blake3Context # Future BLAKE3 context
bytesProcessed*: int64
startTime*: times.DateTime
@ -42,12 +40,8 @@ proc detectHashAlgorithm*(hashString: string): HashAlgorithm =
return HashBlake2b
elif hashString.startsWith("blake3-"):
return HashBlake3
elif hashString.startsWith("sha256-"):
return HashSha256
elif hashString.len == 128: # BLAKE2b-512 hex length
elif hashString.len == 128: # BLAKE2b-512 hex length
return HashBlake2b
elif hashString.len == 64: # SHA256 hex length
return HashSha256
else:
raise newException(ValueError, fmt"Unknown hash format: {hashString[0..min(50, hashString.high)]}")
@ -68,18 +62,11 @@ proc parseHashString*(hashString: string): (HashAlgorithm, string) =
else:
return (HashBlake3, hashString)
of HashSha256:
if hashString.startsWith("sha256-"):
return (HashSha256, hashString[7..^1])
else:
return (HashSha256, hashString)
proc formatHashString*(algorithm: HashAlgorithm, digest: string): string =
## Format hash digest with algorithm prefix
case algorithm:
of HashBlake2b: fmt"blake2b-{digest}"
of HashBlake3: fmt"blake3-{digest}"
of HashSha256: fmt"sha256-{digest}"
# =============================================================================
# Streaming Hash Computation
@ -104,9 +91,6 @@ proc initStreamingHasher*(algorithm: HashAlgorithm): StreamingHasher =
hasher.algorithm = HashBlake2b
hasher.blake2bContext.init()
of HashSha256:
hasher.sha256Context.init()
return hasher
proc update*(hasher: var StreamingHasher, data: openArray[byte]) =
@ -119,9 +103,6 @@ proc update*(hasher: var StreamingHasher, data: openArray[byte]) =
# Fallback to BLAKE2b (already handled in init)
hasher.blake2bContext.update(data)
of HashSha256:
hasher.sha256Context.update(data)
hasher.bytesProcessed += data.len
proc update*(hasher: var StreamingHasher, data: string) =
@ -138,8 +119,8 @@ proc finalize*(hasher: var StreamingHasher): HashResult =
let digest = hasher.blake2bContext.finish()
return HashResult(
algorithm: HashBlake2b,
digest: ($digest).toLower(), # Ensure lowercase hex
verified: false, # Will be set by verification function
digest: ($digest).toLower(), # Ensure lowercase hex
verified: false, # Will be set by verification function
computeTime: computeTime
)
@ -147,17 +128,8 @@ proc finalize*(hasher: var StreamingHasher): HashResult =
# Fallback to BLAKE2b (already handled in init)
let digest = hasher.blake2bContext.finish()
return HashResult(
algorithm: HashBlake2b, # Report actual algorithm used
digest: ($digest).toLower(), # Ensure lowercase hex
verified: false,
computeTime: computeTime
)
of HashSha256:
let digest = hasher.sha256Context.finish()
return HashResult(
algorithm: HashSha256,
digest: ($digest).toLower(), # Ensure lowercase hex
algorithm: HashBlake2b, # Report actual algorithm used
digest: ($digest).toLower(), # Ensure lowercase hex
verified: false,
computeTime: computeTime
)
@ -167,9 +139,9 @@ proc finalize*(hasher: var StreamingHasher): HashResult =
# =============================================================================
const
CHUNK_SIZE = 64 * 1024 # 64KB chunks for memory efficiency
LARGE_FILE_CHUNK_SIZE = 1024 * 1024 # 1MB chunks for large files (>1GB)
LARGE_FILE_THRESHOLD = 1024 * 1024 * 1024 # 1GB threshold
CHUNK_SIZE = 64 * 1024 # 64KB chunks for memory efficiency
LARGE_FILE_CHUNK_SIZE = 1024 * 1024 # 1MB chunks for large files (>1GB)
LARGE_FILE_THRESHOLD = 1024 * 1024 * 1024 # 1GB threshold
proc computeFileHash*(filePath: string, algorithm: HashAlgorithm = HashBlake2b): HashResult =
## Compute hash of a file using streaming approach with optimized chunk size
@ -200,7 +172,8 @@ proc computeFileHash*(filePath: string, algorithm: HashAlgorithm = HashBlake2b):
fileStream.close()
proc computeLargeFileHash*(filePath: string, algorithm: HashAlgorithm = HashBlake2b,
progressCallback: proc(bytesProcessed: int64, totalBytes: int64) = nil): HashResult =
progressCallback: proc(bytesProcessed: int64,
totalBytes: int64) = nil): HashResult =
## Compute hash of a large file (>1GB) with progress reporting
if not fileExists(filePath):
raise newException(IOError, fmt"File not found: {filePath}")
@ -261,7 +234,8 @@ proc verifyFileHash*(filePath: string, expectedHash: string): HashResult =
hashResult.verified = (hashResult.digest == expectedDigest)
if not hashResult.verified:
var error = newException(HashVerificationError, fmt"Hash verification failed for {filePath}")
var error = newException(HashVerificationError,
fmt"Hash verification failed for {filePath}")
error.algorithm = algorithm
error.expectedHash = expectedDigest
error.actualHash = hashResult.digest
@ -277,7 +251,8 @@ proc verifyStringHash*(data: string, expectedHash: string): HashResult =
hashResult.verified = (hashResult.digest == expectedDigest)
if not hashResult.verified:
var error = newException(HashVerificationError, fmt"Hash verification failed for string data")
var error = newException(HashVerificationError,
fmt"Hash verification failed for string data")
error.algorithm = algorithm
error.expectedHash = expectedDigest
error.actualHash = hashResult.digest
@ -293,7 +268,8 @@ proc verifyStreamHash*(stream: Stream, expectedHash: string): HashResult =
hashResult.verified = (hashResult.digest == expectedDigest)
if not hashResult.verified:
var error = newException(HashVerificationError, fmt"Hash verification failed for stream data")
var error = newException(HashVerificationError,
fmt"Hash verification failed for stream data")
error.algorithm = algorithm
error.expectedHash = expectedDigest
error.actualHash = hashResult.digest
@ -371,19 +347,19 @@ proc isValidHashString*(hashString: string): bool =
proc getPreferredHashAlgorithm*(): HashAlgorithm =
## Get the preferred hash algorithm for new packages
return HashBlake2b # Primary algorithm
return HashBlake2b # Primary algorithm
proc getSupportedAlgorithms*(): seq[HashAlgorithm] =
## Get list of supported hash algorithms
return @[HashBlake2b, HashSha256] # Add HashBlake3 when implemented
return @[HashBlake2b] # Add HashBlake3 when implemented
proc getFallbackAlgorithm*(algorithm: HashAlgorithm): HashAlgorithm =
## Get fallback algorithm for unsupported algorithms
case algorithm:
of HashBlake3:
return HashBlake2b # BLAKE3 falls back to BLAKE2b
of HashBlake2b, HashSha256:
return algorithm # Already supported
return HashBlake2b # BLAKE3 falls back to BLAKE2b
of HashBlake2b:
return algorithm # Already supported
proc isAlgorithmSupported*(algorithm: HashAlgorithm): bool =
## Check if algorithm is natively supported (no fallback needed)

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NIP Session Management
##
## Handles persistent session state with track, channel, and policy management

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NIP Shell Core Types
##
## This module defines the foundational data structures for the NIP shell

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Signature Management for Nexus Formats
##
## This module implements Ed25519 signing and verification for NPK, NIP, and NEXTER formats.
@ -15,7 +22,7 @@
import std/[os, strutils, json, base64, tables, times, sets]
import ed25519
import ../nip/types
import ./types
type
SignatureManager* = object

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NSS System Snapshot Format Handler (.nss.zst)
##
## This module implements the NSS (Nexus System Snapshot) format for complete

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## system_integration.nim
## System integration for NIP - PATH, libraries, shell integration

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
import types
when isMainModule:

View File

@ -1,8 +1,15 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/transactions.nim
# Atomic transaction management system
import std/[tables, strutils, json, times]
import ../nip/types
import ./types
# Transaction management functions
proc beginTransaction*(): Transaction =

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
import strutils, os
type

View File

@ -1,7 +1,14 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# nimpak/types.nim
# Core data structures and types for the NimPak system
import std/[times, tables, options, json, hashes]
import std/[hashes]
# Re-export the comprehensive types from types_fixed
include types_fixed

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## NimPak Core Types
##
## This module defines the foundational data structures for the NimPak package

View File

@ -1,7 +1,14 @@
## NimPak Core Types
##
## This module defines the foundational data structures for the NimPak package
## management system, following NexusOS architectural principles.
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# NimPak Core Types
#
# This module defines the foundational data structures for the NimPak package
# management system, following NexusOS architectural principles.
import std/[times, tables, options, json]
@ -81,13 +88,24 @@ type
suggestions*: seq[string]
ErrorCode* = enum
PackageNotFound, DependencyConflict, ChecksumMismatch,
PermissionDenied, NetworkError, BuildFailed,
InvalidMetadata, AculViolation, CellNotFound,
FilesystemError, CasError, GraftError,
# CAS-specific errors
ObjectNotFound, CorruptedObject, StorageError, CompressionError,
FileReadError, FileWriteError, UnknownError
# Access Control
PermissionDenied, ElevationRequired, ReadOnlyViolation,
AculViolation, PolicyViolation, TrustViolation, SignatureInvalid,
# Network & Transport
NetworkError, DownloadFailed, RepositoryUnavailable, TimeoutError,
# Build & Dependency
BuildFailed, CompilationError, MissingDependency, DependencyConflict,
VersionMismatch, ChecksumMismatch, InvalidMetadata,
# Storage & Integrity
FilesystemError, CasGeneralError, GraftError, PackageNotFound, CellNotFound,
ObjectNotFound, CorruptedObject, StorageError, CompressionError, StorageFull,
FileReadError, FileWriteError, PackageCorrupted, ReferenceIntegrityError,
# Runtime & Lifecycle
TransactionFailed, RollbackFailed, GarbageCollectionFailed, UnknownError
# =============================================================================
# Package Identification and Streams
@ -405,11 +423,7 @@ type
deduplicationStatus*: string # "New" or "Reused"
blake2bHash*: string # BLAKE2b hash for enhanced grafting
GraftResult* = object
fragment*: Fragment
extractedPath*: string
originalMetadata*: JsonNode
auditLog*: GraftAuditLog
# =============================================================================
# System Layers and Runtime Control

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## use_flags.nim
## USE flag parsing and management for NIP
## Supports both simple key-value format and structured formats

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## UTCP (Universal Tool Communication Protocol) Implementation
##
## This module implements the Universal Tool Communication Protocol for

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_compiler.nim
## Compiler flag resolution system for NIP variant management
## Resolves domain flags to actual compiler flags with priority ordering

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_database.nim
## Database operations for variant management
## Extends the package database with variant tracking
@ -11,10 +18,7 @@ type
variants*: Table[string, VariantRecord] # fingerprint -> record
references*: Table[string, seq[string]] # variant fingerprint -> list of dependent package names (Task 14.2)
# DEPRECATED: Use Option[VariantRecord] instead
VariantQueryResult* {.deprecated: "Use Option[VariantRecord] instead".} = object
found*: bool
record*: VariantRecord
VariantReferenceInfo* = object
## Information about variant references (Task 14.2)
@ -253,19 +257,7 @@ proc queryVariantByFingerprint*(
else:
return none(VariantRecord)
proc queryVariantByFingerprintLegacy*(
db: VariantDatabase,
fingerprint: string
): VariantQueryResult {.deprecated: "Use queryVariantByFingerprint which returns Option[VariantRecord]".} =
## DEPRECATED: Use queryVariantByFingerprint instead
## Look up a variant by its fingerprint (legacy API)
if fingerprint in db.variants:
return VariantQueryResult(
found: true,
record: db.variants[fingerprint]
)
else:
return VariantQueryResult(found: false)
proc queryVariantByPath*(
db: VariantDatabase,
@ -281,21 +273,7 @@ proc queryVariantByPath*(
return none(VariantRecord)
proc queryVariantByPathLegacy*(
db: VariantDatabase,
installPath: string
): VariantQueryResult {.deprecated: "Use queryVariantByPath which returns Option[VariantRecord]".} =
## DEPRECATED: Use queryVariantByPath instead
## Query variant by installation path (legacy API)
for variant in db.variants.values:
if variant.installPath == installPath:
return VariantQueryResult(
found: true,
record: variant
)
return VariantQueryResult(found: false)
proc queryVariantsByPackage*(
db: VariantDatabase,
@ -320,33 +298,7 @@ proc queryVariantsByPackageVersion*(
if variant.packageName == packageName and variant.version == version:
result.add(variant)
proc deleteVariantRecord*(
db: VariantDatabase,
fingerprint: string
): bool {.deprecated: "Use deleteVariantWithReferences to safely handle references".} =
## DEPRECATED: Use deleteVariantWithReferences instead
## Remove a variant record from the database
## WARNING: This does not check for references and may cause dangling references
## Returns true if successful, false if variant not found
# Check for references before deleting
let refs = db.getVariantReferences(fingerprint)
if refs.len > 0:
echo "Warning: Deleting variant with active references: ", refs.join(", ")
echo "Consider using deleteVariantWithReferences instead"
if fingerprint notin db.variants:
return false
db.variants.del(fingerprint)
# Clean up references
if fingerprint in db.references:
db.references.del(fingerprint)
db.saveVariants()
return true
proc updateVariantPath*(
db: VariantDatabase,
@ -413,12 +365,7 @@ proc findVariantByPath*(
# Utility Functions
# #############################################################################
proc `$`*(qr: VariantQueryResult): string {.deprecated.} =
## DEPRECATED: String representation of query result (legacy API)
if qr.found:
result = "Found: " & qr.record.fingerprint
else:
result = "Not found"
proc prettyPrint*(variant: VariantRecord): string =
## Pretty print a variant record

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_domains.nim
## Semantic domain definitions for NIP variant system
## Defines 9 orthogonal domains with typed constraints

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_fingerprint.nim
## Variant fingerprint calculation using BLAKE2b
## Provides deterministic content-addressed identifiers for package variants

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_manager.nim
## Orchestration layer for NIP variant management
## Coordinates all variant operations: creation, querying, validation
@ -357,7 +364,8 @@ proc hasVariant*(vm: VariantManager, fingerprint: string): bool =
proc deleteVariant*(vm: VariantManager, fingerprint: string): bool =
## Delete a variant from the database
vm.db.deleteVariantRecord(fingerprint)
let (success, _) = vm.db.deleteVariantWithReferences(fingerprint)
return success
proc countVariants*(vm: VariantManager, packageName: string): int =
## Count variants for a package

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_mappings.nim
## Maps NIP variant domains to package manager specific flags
## Each package can have custom mappings, with fallback to generic mappings

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_migration.nim
## Migration utilities for transitioning from legacy USE flags to variant domains
## Task 15: Legacy flag translation and migration warnings

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_parser.nim
## CLI parser for domain-scoped variant flags
## Supports both new domain syntax and legacy USE flags

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_paths.nim
## Variant path management for NIP
## Generates and validates content-addressed variant installation paths

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_profiles.nim
## Profile system for NIP variant management
## Loads and merges variant profiles from KDL files

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_types.nim
## Core type system for NIP variant management
## Defines typed semantic domains and variant fingerprinting

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_validator.nim
## Domain validation system for NIP variant management
## Validates domain configurations and enforces type constraints

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variants.nim
## Typed variant system for deterministic, content-addressed packages
## Evolution of USE flags into semantic domains with type safety

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## nimpak/xdg_enforcer.nim
## XDG Base Directory Enforcer for Nippels
##

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
## NIP Archive Handler
##
## This module handles the creation and extraction of .nip (and .npk) archives.
## It enforces the compression strategy:
## - Archives: zstd (default/auto) for performance.
## - CAS: zstd -19 (handled by cas.nim, not here).
import std/[os, osproc, strutils, strformat, logging, tempfiles]
import nip/manifest_parser
type
ArchiveError* = object of CatchableError
proc runCmd(cmd: string) =
let res = execCmdEx(cmd)
if res.exitCode != 0:
raise newException(ArchiveError, fmt"Command failed: {cmd}{'\n'}Output: {res.output}")
proc createArchive*(manifest: PackageManifest, sourceDir: string, outputFile: string) =
## Create a .nip archive from a source directory and manifest.
## The archive will contain:
## - manifest.kdl
## - files/ (content of sourceDir)
info(fmt"Creating archive {outputFile} from {sourceDir}")
let tempDir = createTempDir("nip_build_", "")
defer: removeDir(tempDir)
# 1. Write manifest to temp root
let manifestPath = tempDir / "manifest.kdl"
writeFile(manifestPath, serializeManifestToKDL(manifest))
# 2. Copy source files to temp/files
let filesDir = tempDir / "files"
createDir(filesDir)
copyDirWithPermissions(sourceDir, filesDir)
# 3. Create Archive
# We use tar + zstd.
# --zstd tells tar to use zstd. If not supported by tar version, we pipe.
# To be safe and explicit about zstd options, we pipe.
# cd tempDir && tar -cf - manifest.kdl files/ | zstd -T0 > outputFile
# -T0 uses all cores.
# No -19 here, just default (level 3 usually) or --auto if we wanted.
# Default is good for "superb heuristic".
let cmd = fmt"tar -C {tempDir.quoteShell} -cf - manifest.kdl files | zstd -T0 -o {outputFile.quoteShell}"
runCmd(cmd)
info(fmt"Archive created successfully: {outputFile}")
proc extractArchive*(archivePath: string, targetDir: string) =
## Extract a .nip archive to targetDir.
info(fmt"Extracting archive {archivePath} to {targetDir}")
createDir(targetDir)
# zstd -d -c archive | tar -C target -xf -
let cmd = fmt"zstd -d -c {archivePath.quoteShell} | tar -C {targetDir.quoteShell} -xf -"
runCmd(cmd)
info("Extraction complete")
proc verifyArchive*(archivePath: string): bool =
## Verify archive integrity (zstd check)
let cmd = fmt"zstd -t {archivePath.quoteShell}"
let res = execCmdEx(cmd)
return res.exitCode == 0

View File

@ -1,165 +0,0 @@
## Content-Addressable Storage (CAS) system for NimPak
##
## This module provides the core functionality for storing and retrieving
## content-addressed objects using BLAKE2b-512 hashing (with future support for BLAKE3).
## Objects are stored in a sharded directory structure for scalability.
import std/[os, strutils, times, posix]
import nimcrypto/hash
import nimcrypto/blake2
import nip/types
const
DefaultHashAlgorithm* = "blake2b-512" # Default hash algorithm
ShardingLevels* = 2 # Number of directory levels for sharding
type
HashAlgorithm* = enum
Blake2b512 = "blake2b-512"
# Blake3 = "blake3" # Will be added when available in Nimble
CasObject* = object
hash*: Multihash
size*: int64
compressed*: bool
timestamp*: times.Time
proc calculateHash*(data: string, algorithm: HashAlgorithm = Blake2b512): Multihash =
## Calculate the hash of a string using the specified algorithm
case algorithm:
of Blake2b512:
let digest = blake2_512.digest(data)
var hexDigest = ""
for b in digest.data:
hexDigest.add(b.toHex(2).toLowerAscii())
result = Multihash(hexDigest)
proc calculateFileHash*(path: string, algorithm: HashAlgorithm = Blake2b512): Multihash =
## Calculate the hash of a file using the specified algorithm
if not fileExists(path):
raise newException(IOError, "File not found: " & path)
let data = readFile(path)
result = calculateHash(data, algorithm)
proc getShardPath*(hash: Multihash, levels: int = ShardingLevels): string =
## Get the sharded path for a hash
## e.g., "ab/cd" for hash "abcdef123456..."
let hashStr = string(hash)
var parts: seq[string] = @[]
for i in 0..<levels:
if i*2+1 < hashStr.len:
parts.add(hashStr[i*2..<i*2+2])
else:
break
result = parts.join("/")
proc storeObject*(data: string, casRoot: string, compress: bool = true): CasObject =
## Store data in the CAS and return its hash
let hash = calculateHash(data)
let shardPath = getShardPath(hash)
let fullShardPath = casRoot / shardPath
# Create shard directories if they don't exist
createDir(fullShardPath)
# Store the object
let objectPath = fullShardPath / string(hash)
# TODO: Add zstd compression when needed
writeFile(objectPath, data)
result = CasObject(
hash: hash,
size: data.len.int64,
compressed: compress,
timestamp: getTime()
)
proc retrieveObject*(hash: Multihash, casRoot: string): string =
## Retrieve an object from the CAS by its hash
let shardPath = getShardPath(hash)
let objectPath = casRoot / shardPath / string(hash)
if not fileExists(objectPath):
raise newException(IOError, "Object not found: " & string(hash))
# TODO: Add zstd decompression when needed
result = readFile(objectPath)
proc verifyObject*(hash: Multihash, data: string): bool =
## Verify that data matches its expected hash
let calculatedHash = calculateHash(data)
result = hash == calculatedHash
proc initCasManager*(userCasPath: string, systemCasPath: string): bool =
## Initialize the CAS manager by creating necessary directories
try:
createDir(userCasPath)
setFilePermissions(userCasPath, {fpUserRead, fpUserWrite, fpUserExec})
# Only create system CAS if running as root
if posix.getuid() == 0:
createDir(systemCasPath)
setFilePermissions(systemCasPath, {fpUserRead, fpUserWrite, fpUserExec,
fpGroupRead, fpGroupExec,
fpOthersRead, fpOthersExec})
result = true
result = true
except:
result = false
# ============================================================================
# Reference Counting / Garbage Collection Support
# ============================================================================
proc getRefPath(casRoot, refType, hash, refId: string): string =
## Get path for a reference file: cas/refs/<type>/<hash>/<refId>
result = casRoot / "refs" / refType / hash / refId
proc addReference*(casRoot: string, hash: Multihash, refType, refId: string) =
## Add a reference to a CAS object
## refType: "npk", "nip", "nexter"
## refId: Unique identifier for the reference (e.g. "package-name:version")
let path = getRefPath(casRoot, refType, string(hash), refId)
createDir(path.parentDir)
writeFile(path, "") # Empty file acts as reference
proc removeReference*(casRoot: string, hash: Multihash, refType, refId: string) =
## Remove a reference to a CAS object
let path = getRefPath(casRoot, refType, string(hash), refId)
if fileExists(path):
removeFile(path)
# Try to remove parent dir (hash dir) if empty
try:
removeDir(path.parentDir)
except:
discard
proc hasReferences*(casRoot: string, hash: Multihash): bool =
## Check if a CAS object has any references
# We need to check all refTypes
let refsDir = casRoot / "refs"
if not dirExists(refsDir): return false
for kind, path in walkDir(refsDir):
if kind == pcDir:
let hashDir = path / string(hash)
if dirExists(hashDir):
# Check if directory is not empty
for _ in walkDir(hashDir):
return true
return false
when isMainModule:
# Simple test
echo "Testing CAS functionality..."
let testData = "Hello, NexusOS with Content-Addressable Storage!"
let objHash = calculateHash(testData)
echo "Hash: ", string(objHash)
# Test sharding
echo "Shard path: ", getShardPath(objHash)

View File

@ -1,328 +0,0 @@
## Resolve Command - CLI Interface for Dependency Resolution
##
## This module provides the CLI interface for the dependency resolver,
## allowing users to resolve, explain, and inspect package dependencies.
import strformat
import tables
import terminal
# ============================================================================
# Type Definitions
# ============================================================================
import ../resolver/orchestrator
import ../resolver/variant_types
import ../resolver/dependency_graph
import ../resolver/conflict_detection
import std/[options, times]
type
VersionConstraint* = object
operator*: string
version*: string
# ============================================================================
# Helper Functions
# ============================================================================
proc loadRepositories*(): seq[Repository] =
## Load repositories from configuration
result = @[
Repository(name: "main", url: "https://packages.nexusos.org/main", priority: 100),
Repository(name: "community", url: "https://packages.nexusos.org/community", priority: 50)
]
proc parseVersionConstraint*(constraint: string): VersionConstraint =
## Parse version constraint string
result = VersionConstraint(operator: "any", version: constraint)
proc formatError*(msg: string): string =
## Format error message
result = fmt"Error: {msg}"
# ============================================================================
# Command: nip resolve
# ============================================================================
proc resolveCommand*(args: seq[string]): int =
## Handle 'nip resolve <package>' command
if args.len < 1:
echo "Usage: nip resolve <package> [constraint] [options]"
echo ""
echo "Options:"
echo " --use-flags=<flags> Comma-separated USE flags"
echo " --libc=<libc> C library (musl, glibc)"
echo " --allocator=<alloc> Memory allocator (jemalloc, tcmalloc, default)"
echo " --json Output in JSON format"
return 1
let packageName = args[0]
var jsonOutput = false
# Parse arguments
for arg in args[1..^1]:
if arg == "--json":
jsonOutput = true
try:
# Initialize Orchestrator
let repos = loadRepositories()
let config = defaultConfig()
let orchestrator = newResolutionOrchestrator(repos, config)
# Create demand (default for now)
let demand = VariantDemand(
packageName: packageName,
variantProfile: VariantProfile(hash: "any")
)
# Resolve
let result = orchestrator.resolve(packageName, "*", demand)
if result.isOk:
let res = result.value
if jsonOutput:
echo fmt"""{{
"success": true,
"package": "{packageName}",
"packageCount": {res.packageCount},
"resolutionTime": {res.resolutionTime},
"cacheHit": {res.cacheHit},
"installOrder": []
}}"""
else:
stdout.styledWrite(fgGreen, "✅ Resolution successful!\n")
echo ""
echo fmt"📦 Package: {packageName}"
echo fmt"⏱️ Time: {res.resolutionTime * 1000:.2f}ms"
echo fmt"📚 Packages: {res.packageCount}"
echo fmt"💾 Cache Hit: {res.cacheHit}"
echo ""
echo "📋 Resolution Plan:"
for term in res.installOrder:
stdout.styledWrite(fgCyan, fmt" • {term.packageName}")
stdout.write(fmt" ({term.version})")
stdout.styledWrite(fgYellow, fmt" [{term.source}]")
echo ""
echo ""
else:
let err = result.error
if jsonOutput:
echo fmt"""{{
"success": false,
"error": "{err.details}"
}}"""
else:
stdout.styledWrite(fgRed, "❌ Resolution Failed!\n")
echo formatError(err)
return if result.isOk: 0 else: 1
except Exception as e:
if jsonOutput:
echo fmt"""{{
"success": false,
"error": "{e.msg}"
}}"""
else:
stdout.styledWrite(fgRed, "❌ Error!\n")
echo fmt"Error: {e.msg}"
return 1
# ============================================================================
# Command: nip explain
# ============================================================================
proc explainCommand*(args: seq[string]): int =
## Handle 'nip explain <package>' command
if args.len < 1:
echo "Usage: nip explain <package> [options]"
return 1
let packageName = args[0]
var jsonOutput = false
for arg in args[1..^1]:
if arg == "--json":
jsonOutput = true
try:
if jsonOutput:
echo fmt"""{{
"success": true,
"package": "{packageName}",
"version": "1.0.0",
"variant": "default",
"buildHash": "blake3-abc123",
"source": "main",
"dependencyCount": 0,
"dependencies": []
}}"""
else:
stdout.styledWrite(fgCyan, fmt"📖 Explaining resolution for: {packageName}\n")
echo ""
echo "Resolution explanation:"
echo fmt" • Package source: main"
echo fmt" • Version selected: 1.0.0"
echo fmt" • Variant: default"
echo fmt" • Dependencies: 0 packages"
echo ""
return 0
except Exception as e:
if jsonOutput:
echo fmt"""{{
"success": false,
"error": "{e.msg}"
}}"""
else:
stdout.styledWrite(fgRed, "❌ Error!\n")
echo fmt"Error: {e.msg}"
return 1
# ============================================================================
# Command: nip conflicts
# ============================================================================
proc conflictsCommand*(args: seq[string]): int =
## Handle 'nip conflicts' command
var jsonOutput = false
for arg in args:
if arg == "--json":
jsonOutput = true
try:
if jsonOutput:
echo """{"success": true, "conflicts": []}"""
else:
stdout.styledWrite(fgGreen, "✅ No conflicts detected!\n")
echo ""
echo "All installed packages are compatible."
echo ""
return 0
except Exception as e:
if jsonOutput:
echo fmt"""{{
"success": false,
"error": "{e.msg}"
}}"""
else:
stdout.styledWrite(fgRed, "❌ Error!\n")
echo fmt"Error: {e.msg}"
return 1
# ============================================================================
# Command: nip variants
# ============================================================================
proc variantsCommand*(args: seq[string]): int =
## Handle 'nip variants <package>' command
if args.len < 1:
echo "Usage: nip variants <package> [options]"
return 1
let packageName = args[0]
var jsonOutput = false
for arg in args[1..^1]:
if arg == "--json":
jsonOutput = true
try:
if jsonOutput:
echo fmt"""{{
"package": "{packageName}",
"variants": {{
"useFlags": [
{{"flag": "ssl", "description": "Enable SSL/TLS support", "default": false}},
{{"flag": "http2", "description": "Enable HTTP/2 support", "default": false}}
],
"libc": [
{{"option": "musl", "description": "Lightweight C library", "default": true}},
{{"option": "glibc", "description": "GNU C library", "default": false}}
],
"allocator": [
{{"option": "jemalloc", "description": "High-performance allocator", "default": true}},
{{"option": "tcmalloc", "description": "Google's thread-caching allocator", "default": false}}
]
}}
}}"""
else:
stdout.styledWrite(fgCyan, fmt"🎨 Available variants for: {packageName}\n")
echo ""
echo "USE flags:"
echo " • ssl (default) - Enable SSL/TLS support"
echo " • http2 - Enable HTTP/2 support"
echo ""
echo "libc options:"
echo " • musl (default) - Lightweight C library"
echo " • glibc - GNU C library"
echo ""
echo "Allocator options:"
echo " • jemalloc (default) - High-performance allocator"
echo " • tcmalloc - Google's thread-caching allocator"
echo ""
return 0
except Exception as e:
if jsonOutput:
echo fmt"""{{
"success": false,
"error": "{e.msg}"
}}"""
else:
stdout.styledWrite(fgRed, "❌ Error!\n")
echo fmt"Error: {e.msg}"
return 1
# ============================================================================
# Main CLI Entry Point
# ============================================================================
when isMainModule:
import os
let args = commandLineParams()
if args.len == 0:
echo "NIP Dependency Resolver"
echo ""
echo "Usage: nip <command> [args]"
echo ""
echo "Commands:"
echo " resolve <package> - Resolve dependencies"
echo " explain <package> - Explain resolution decisions"
echo " conflicts - Show detected conflicts"
echo " variants <package> - Show available variants"
echo ""
quit(1)
let command = args[0]
let commandArgs = args[1..^1]
let exitCode = case command:
of "resolve": resolveCommand(commandArgs)
of "explain": explainCommand(commandArgs)
of "conflicts": conflictsCommand(commandArgs)
of "variants": variantsCommand(commandArgs)
else:
echo fmt"Unknown command: {command}"
1
quit(exitCode)

View File

@ -1,85 +0,0 @@
import std/[os, strutils, options]
import nimpak/packages
import nimpak/types
import nimpak/cas
proc runConvertCommand*(args: seq[string]) =
if args.len < 2:
echo "Usage: nip convert <grafted_package_dir>"
quit(1)
let graftedDir = args[1]
# Load graft result metadata (simulate loading from graftedDir)
# In real implementation, this would parse graft metadata files
# Here, we simulate with placeholders for demonstration
# TODO: Replace with actual loading/parsing of graft metadata
let dummyFragment = Fragment(
id: PackageId(name: "dummy", version: "0.1.0", stream: Stable),
source: Source(
url: "https://example.com/dummy-0.1.0.tar.gz",
hash: "blake2b-dummyhash",
hashAlgorithm: "blake2b",
sourceMethod: Http,
timestamp: now()
),
dependencies: @[],
buildSystem: Custom,
metadata: PackageMetadata(
description: "Dummy package for conversion",
license: "MIT",
maintainer: "dummy@example.com",
tags: @[],
runtime: RuntimeProfile(
libc: Musl,
allocator: System,
systemdAware: false,
reproducible: true,
tags: @[]
)
),
acul: AculCompliance(required: false, membership: "", attribution: "", buildLog: "")
)
let dummyAuditLog = GraftAuditLog(
timestamp: now(),
source: Pacman,
packageName: "dummy",
version: "0.1.0",
downloadedFilename: "dummy-0.1.0.tar.gz",
archiveHash: "blake2b-dummyhash",
hashAlgorithm: "blake2b",
sourceOutput: "Simulated graft source output",
downloadUrl: none(string),
originalSize: 12345,
deduplicationStatus: "New"
)
let graftResult = GraftResult(
fragment: dummyFragment,
extractedPath: graftedDir,
originalMetadata: %*{},
auditLog: dummyAuditLog
)
let convertResult = convertGraftToNpk(graftResult)
if convertResult.isErr:
echo "Conversion failed: ", convertResult.getError().msg
quit(1)
let npk = convertResult.get()
# Create archive path
let archivePath = graftedDir / (npk.metadata.id.name & "-" & npk.metadata.id.version & ".npk")
let archiveResult = createNpkArchive(npk, archivePath)
if archiveResult.isErr:
echo "Failed to create NPK archive: ", archiveResult.getError().msg
quit(1)
echo "Conversion successful. NPK archive created at: ", archivePath
# Entry point for the command
when isMainModule:
runConvertCommand(commandLineParams())

Some files were not shown because too many files have changed in this diff Show More