@obinexusltd/curl-polycall 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OBINexus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/Makefile ADDED
@@ -0,0 +1,122 @@
1
+ ifneq ($(OS),Windows_NT)
2
+ ifeq ($(origin CC),default)
3
+ CC := cc
4
+ endif
5
+ endif
6
+ CFLAGS ?= -O2 -Wall -Wextra
7
+ PIC_FLAGS ?= -fPIC
8
+
9
+ SRC := src/polycall_ffi.c
10
+ OBJ_DIR := build/obj
11
+ BIN_DIR := build/bin
12
+ OBJ := $(OBJ_DIR)/polycall_ffi.o
13
+
14
+ DESTDIR ?=
15
+ PREFIX ?= /usr/local
16
+ SYSCONFDIR ?= /etc
17
+ BINDIR ?= $(PREFIX)/bin
18
+ LIBEXECDIR ?= $(PREFIX)/lib/curl-polycall
19
+ DOCDIR ?= $(PREFIX)/share/doc/curl-polycall
20
+ EXAMPLESDIR ?= $(PREFIX)/share/curl-polycall/examples
21
+
22
+ ifeq ($(OS),Windows_NT)
23
+ PIC_FLAGS :=
24
+ PYTHON ?= python
25
+ LIB := $(BIN_DIR)/polycall_ffi.dll
26
+ TMP_LIB := $(BIN_DIR)/polycall_ffi.tmp.dll
27
+ SHARED_FLAGS := -shared
28
+ else
29
+ PYTHON ?= python3
30
+ UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)
31
+ ifeq ($(UNAME_S),Darwin)
32
+ LIB := $(BIN_DIR)/libpolycall_ffi.dylib
33
+ SHARED_FLAGS := -dynamiclib
34
+ else
35
+ LIB := $(BIN_DIR)/libpolycall_ffi.so
36
+ SHARED_FLAGS := -shared
37
+ endif
38
+ endif
39
+
40
+ .PHONY: all clean dirs install uninstall run windows-build FORCE
41
+
42
+ ifeq ($(OS),Windows_NT)
43
+ all: windows-build
44
+ else
45
+ all: dirs $(LIB)
46
+ endif
47
+
48
+ FORCE:
49
+
50
+ ifeq ($(OS),Windows_NT)
51
+ dirs:
52
+ @if not exist "build" mkdir "build"
53
+ @if not exist "build\bin" mkdir "build\bin"
54
+ @if not exist "build\obj" mkdir "build\obj"
55
+ else
56
+ dirs:
57
+ mkdir -p $(BIN_DIR) $(OBJ_DIR)
58
+ endif
59
+
60
+ $(OBJ): FORCE $(SRC) src/polycall_ffi.h | dirs
61
+ $(CC) $(CFLAGS) $(PIC_FLAGS) -c $(SRC) -o $(OBJ)
62
+
63
+ ifeq ($(OS),Windows_NT)
64
+ windows-build: dirs
65
+ powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-windows.ps1
66
+ else
67
+ $(LIB): $(OBJ) | dirs
68
+ $(CC) $(SHARED_FLAGS) $(OBJ) -o $(LIB)
69
+ endif
70
+
71
+ run: all
72
+ $(PYTHON) server.py
73
+
74
+ ifeq ($(OS),Windows_NT)
75
+ install:
76
+ @echo "make install is only supported on Unix-like systems"
77
+ @exit 1
78
+
79
+ uninstall:
80
+ @echo "make uninstall is only supported on Unix-like systems"
81
+ @exit 1
82
+ else
83
+ install: all
84
+ install -d "$(DESTDIR)$(BINDIR)"
85
+ install -d "$(DESTDIR)$(LIBEXECDIR)"
86
+ install -d "$(DESTDIR)$(LIBEXECDIR)/build/bin"
87
+ install -d "$(DESTDIR)$(SYSCONFDIR)/curl-polycall"
88
+ install -d "$(DESTDIR)$(DOCDIR)"
89
+ install -d "$(DESTDIR)$(EXAMPLESDIR)"
90
+ install -m 0644 ffi.py server.py "$(DESTDIR)$(LIBEXECDIR)/"
91
+ install -m 0644 "$(LIB)" "$(DESTDIR)$(LIBEXECDIR)/build/bin/"
92
+ install -m 0644 config/curl-polycall.env "$(DESTDIR)$(SYSCONFDIR)/curl-polycall/curl-polycall.env"
93
+ install -m 0644 README.md LICENSE "$(DESTDIR)$(DOCDIR)/"
94
+ install -m 0644 docs/FAULT_TOLERANT_FFI_PROOF.md "$(DESTDIR)$(DOCDIR)/"
95
+ install -m 0755 examples/curl.sh "$(DESTDIR)$(EXAMPLESDIR)/curl.sh"
96
+ sed -e 's|@LIBEXECDIR@|$(LIBEXECDIR)|g' \
97
+ -e 's|@SYSCONFDIR@|$(SYSCONFDIR)|g' \
98
+ scripts/curl-polycall-server.in > "$(DESTDIR)$(BINDIR)/curl-polycall-server"
99
+ chmod 0755 "$(DESTDIR)$(BINDIR)/curl-polycall-server"
100
+ sed -e 's|@BINDIR@|$(BINDIR)|g' \
101
+ -e 's|@EXAMPLESDIR@|$(EXAMPLESDIR)|g' \
102
+ scripts/curl-polycall.in > "$(DESTDIR)$(BINDIR)/curl-polycall"
103
+ chmod 0755 "$(DESTDIR)$(BINDIR)/curl-polycall"
104
+
105
+ uninstall:
106
+ rm -f "$(DESTDIR)$(BINDIR)/curl-polycall" "$(DESTDIR)$(BINDIR)/curl-polycall-server"
107
+ rm -rf "$(DESTDIR)$(LIBEXECDIR)"
108
+ rm -rf "$(DESTDIR)$(DOCDIR)"
109
+ rm -rf "$(DESTDIR)$(EXAMPLESDIR)"
110
+ rm -f "$(DESTDIR)$(SYSCONFDIR)/curl-polycall/curl-polycall.env"
111
+ rmdir "$(DESTDIR)$(SYSCONFDIR)/curl-polycall" 2>/dev/null || true
112
+ endif
113
+
114
+ ifeq ($(OS),Windows_NT)
115
+ clean:
116
+ @if exist "build\bin\polycall_ffi.dll" del /q "build\bin\polycall_ffi.dll"
117
+ @if exist "build\bin\polycall_ffi.tmp.dll" del /q "build\bin\polycall_ffi.tmp.dll"
118
+ @if exist "build\obj\polycall_ffi.o" del /q "build\obj\polycall_ffi.o"
119
+ else
120
+ clean:
121
+ rm -rf $(BIN_DIR)/* $(OBJ_DIR)/*
122
+ endif
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # curl-polycall
2
+
3
+ Minimal direct FFI demonstration for libpolycall-style command interpolation through `curl` or `wget`.
4
+
5
+ The point of this example is narrow:
6
+
7
+ - expose a tiny native C ABI;
8
+ - load it from Python 3 with `import ffi`;
9
+ - serve HTTP endpoints that call the native ABI directly;
10
+ - keep NSIGII as an external attachable artifact, not C code inside libpolycall;
11
+ - keep `micro attach` and `micro detach` as runtime dependency registration only.
12
+
13
+ ## Layout
14
+
15
+ ```text
16
+ curl-polycall/
17
+ |-- build/
18
+ | |-- bin/
19
+ | `-- obj/
20
+ |-- config/
21
+ | `-- curl-polycall.env
22
+ |-- debian/
23
+ | |-- control
24
+ | |-- rules
25
+ | `-- source/
26
+ |-- docs/
27
+ | |-- FAULT_TOLERANT_FFI_PROOF.md
28
+ | `-- UNIX_PACKAGING.md
29
+ |-- examples/
30
+ | |-- curl.ps1
31
+ | `-- curl.sh
32
+ |-- scripts/
33
+ | `-- build-windows.ps1
34
+ |-- src/
35
+ | |-- polycall_ffi.c
36
+ | `-- polycall_ffi.h
37
+ |-- ffi.py
38
+ |-- server.py
39
+ |-- Makefile
40
+ |-- package.json
41
+ `-- README.md
42
+ ```
43
+
44
+ ## npm package metadata
45
+
46
+ The project root includes `package.json` for the npm package
47
+ `@obinexusltd/curl-polycall`. The package metadata lists every source folder in
48
+ `directories` and keeps generated native build outputs out of the source package
49
+ while preserving `build/bin` and `build/obj` with `.gitkeep` placeholders.
50
+
51
+ The package also exposes two CLI entry points via npm:
52
+
53
+ - `curl-polycall` → `scripts/curl-polycall.in`
54
+ - `curl-polycall-server` → `scripts/curl-polycall-server.in`
55
+
56
+ Install globally or run through `npx`:
57
+
58
+ ```sh
59
+ npm install -g @obinexusltd/curl-polycall
60
+ curl-polycall server
61
+ curl-polycall health
62
+ curl-polycall command ping
63
+ ```
64
+
65
+ Or run directly with `npx`:
66
+
67
+ ```sh
68
+ npx @obinexusltd/curl-polycall server
69
+ ```
70
+
71
+ Useful npm scripts:
72
+
73
+ ```sh
74
+ npm run build
75
+ npm run build:deb
76
+ npm run build:windows
77
+ npm start
78
+ npm run demo
79
+ npm run demo:windows
80
+ npm run test:ffi
81
+ ```
82
+
83
+ ## Native ABI
84
+
85
+ ```c
86
+ int polycall_verify_command(const char *command, char *out_buffer, int out_buffer_len);
87
+ int polycall_runtime_micro_attach(const char *dependency_path, char *out_buffer, int out_buffer_len);
88
+ int polycall_runtime_micro_detach(const char *dependency_path, char *out_buffer, int out_buffer_len);
89
+ ```
90
+
91
+ Platform outputs:
92
+
93
+ - Windows: `build/bin/polycall_ffi.dll`
94
+ - Linux: `build/bin/libpolycall_ffi.so`
95
+ - macOS: `build/bin/libpolycall_ffi.dylib`
96
+ - Objects: `build/obj`
97
+
98
+ ## Build
99
+
100
+ Linux/macOS:
101
+
102
+ ```sh
103
+ make
104
+ python3 server.py
105
+ ```
106
+
107
+ Windows PowerShell:
108
+
109
+ ```powershell
110
+ .\scripts\build-windows.ps1
111
+ python server.py
112
+ ```
113
+
114
+ If Windows reports `cannot open file 'build\bin\polycall_ffi.dll'` or
115
+ `Permission denied`, stop the running server with `Ctrl+C` before rebuilding.
116
+ Python keeps the DLL loaded while `server.py` is running.
117
+
118
+ ## Unix and apt install
119
+
120
+ For generic Unix installs:
121
+
122
+ ```sh
123
+ make
124
+ sudo make install PREFIX=/usr SYSCONFDIR=/etc
125
+ ```
126
+
127
+ For Debian/Ubuntu local apt installs:
128
+
129
+ ```sh
130
+ sudo apt update
131
+ sudo apt install build-essential debhelper devscripts
132
+ chmod +x debian/rules scripts/build-deb.sh
133
+ sh scripts/build-deb.sh
134
+ sudo apt install ../curl-polycall_0.1.0_$(dpkg --print-architecture).deb
135
+ ```
136
+
137
+ Then run:
138
+
139
+ ```sh
140
+ curl-polycall server
141
+ curl-polycall health
142
+ curl-polycall command ping
143
+ ```
144
+
145
+ Plain `sudo apt install curl-polycall` works only after the `.deb` is published
146
+ to an apt repository configured on the machine. See
147
+ [docs/UNIX_PACKAGING.md](docs/UNIX_PACKAGING.md).
148
+
149
+ ## Direct Python FFI
150
+
151
+ ```python
152
+ import ffi
153
+
154
+ runtime = ffi.load()
155
+ runtime.command("ping")
156
+ runtime.attach("build/bin/example.nsigii")
157
+ runtime.detach("build/bin/example.nsigii")
158
+ ```
159
+
160
+ ## Curl endpoints
161
+
162
+ Start the server first:
163
+
164
+ ```sh
165
+ python server.py
166
+ ```
167
+
168
+ Then call individual endpoints:
169
+
170
+ ```sh
171
+ curl "http://127.0.0.1:8084/"
172
+ curl "http://127.0.0.1:8084/command?cmd=ping"
173
+ curl "http://127.0.0.1:8084/command?cmd=health"
174
+ curl "http://127.0.0.1:8084/command?cmd=unknown"
175
+ curl "http://127.0.0.1:8084/micro/attach?path=build/bin/example.nsigii"
176
+ curl "http://127.0.0.1:8084/micro/detach?path=build/bin/example.nsigii"
177
+ ```
178
+
179
+ Or run the example script:
180
+
181
+ ```sh
182
+ bash examples/curl.sh
183
+ ```
184
+
185
+ From PowerShell:
186
+
187
+ ```powershell
188
+ .\examples\curl.ps1
189
+ ```
190
+
191
+ Both example scripts wait briefly for `http://127.0.0.1:8084/` before sending
192
+ the endpoint requests, so they can be launched while `server.py` is still
193
+ starting.
194
+
195
+ Do not run `curl.exe examples/curl.sh`; that asks curl to fetch a URL named
196
+ `examples/curl.sh`. Use `bash examples/curl.sh` or the PowerShell script above.
197
+
198
+ Each response is trinary JSON:
199
+
200
+ ```json
201
+ {"status":"YES","message":"..."}
202
+ {"status":"NO","message":"..."}
203
+ {"status":"MAYBE","message":"..."}
204
+ ```
205
+
206
+ Known commands return `YES`, invalid input returns `NO`, and unknown but syntactically valid commands return `MAYBE`.
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,7 @@
1
+ # curl-polycall Unix runtime config
2
+ #
3
+ # This file is installed to /etc/curl-polycall/curl-polycall.env by the
4
+ # Debian package and the POSIX Makefile install target.
5
+
6
+ CURL_POLYCALL_HOST=127.0.0.1
7
+ CURL_POLYCALL_PORT=8084
@@ -0,0 +1,6 @@
1
+ curl-polycall (0.1.0) unstable; urgency=medium
2
+
3
+ * Initial Debian package for the curl-polycall direct FFI demo.
4
+ * Install POSIX commands, FHS config, docs, examples, and native FFI library.
5
+
6
+ -- OBINexus LTD <support@obinexus.com> Wed, 24 Jun 2026 21:30:00 +0000
package/debian/control ADDED
@@ -0,0 +1,27 @@
1
+ Source: curl-polycall
2
+ Section: net
3
+ Priority: optional
4
+ Maintainer: OBINexus LTD <support@obinexus.com>
5
+ Build-Depends:
6
+ debhelper-compat (= 13),
7
+ gcc,
8
+ make,
9
+ python3
10
+ Standards-Version: 4.6.2
11
+ Rules-Requires-Root: no
12
+ Homepage: https://github.com/obinexusltd/curl-polycall
13
+
14
+ Package: curl-polycall
15
+ Architecture: any
16
+ Depends:
17
+ ${misc:Depends},
18
+ ${shlibs:Depends},
19
+ curl,
20
+ python3
21
+ Description: Direct FFI curl endpoint demonstration for libpolycall
22
+ curl-polycall is a minimal verification-first Foreign Function Interface
23
+ demonstration. It exposes a native C ABI, loads it from Python with ctypes,
24
+ and serves curl/wget-friendly HTTP endpoints that return YES, NO, or MAYBE.
25
+ .
26
+ NSIGII artifacts remain external runtime dependencies; they are not embedded
27
+ into the native libpolycall demonstration.
@@ -0,0 +1,26 @@
1
+ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2
+ Upstream-Name: curl-polycall
3
+ Source: https://github.com/obinexusltd/curl-polycall
4
+
5
+ Files: *
6
+ Copyright: 2026 OBINexus
7
+ License: MIT
8
+
9
+ License: MIT
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+ .
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+ .
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
package/debian/docs ADDED
@@ -0,0 +1,2 @@
1
+ README.md
2
+ docs/FAULT_TOLERANT_FFI_PROOF.md
package/debian/rules ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/make -f
2
+
3
+ %:
4
+ dh $@
5
+
6
+ override_dh_auto_build:
7
+ $(MAKE)
8
+
9
+ override_dh_auto_install:
10
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/curl-polycall PREFIX=/usr SYSCONFDIR=/etc
11
+
12
+ override_dh_auto_clean:
13
+ $(MAKE) clean
@@ -0,0 +1 @@
1
+ 3.0 (native)
@@ -0,0 +1,70 @@
1
+ # Fault-Tolerant Direct FFI Proof
2
+
3
+ ## Scope
4
+
5
+ `curl-polycall` proves only the direct Foreign Function Interface boundary.
6
+
7
+ It does not implement NSIGII as `nsigii.h` or `nsigii.c` inside libpolycall. It does not implement a DOP adapter. It does not copy microvm example code. NSIGII remains an external proof, artifact, or dependency that can be attached, detached, inspected, or loaded later by a runtime.
8
+
9
+ ## Direct FFI Call Chain
10
+
11
+ The call chain is:
12
+
13
+ ```text
14
+ curl/wget
15
+ -> Python 3 http.server endpoint
16
+ -> import ffi
17
+ -> ctypes.CDLL(...)
18
+ -> native C ABI function
19
+ -> bounded JSON response buffer
20
+ ```
21
+
22
+ The Python host performs a real foreign function call into the native shared library. The HTTP server is only a transport surface for command-line interoperability.
23
+
24
+ ## Native ABI Boundary
25
+
26
+ The exported ABI is exactly:
27
+
28
+ ```c
29
+ int polycall_verify_command(const char *command, char *out_buffer, int out_buffer_len);
30
+ int polycall_runtime_micro_attach(const char *dependency_path, char *out_buffer, int out_buffer_len);
31
+ int polycall_runtime_micro_detach(const char *dependency_path, char *out_buffer, int out_buffer_len);
32
+ ```
33
+
34
+ Each function accepts caller-owned input plus a bounded output buffer. The C implementation writes responses with `snprintf`, checks truncation, and returns an error code if the buffer is invalid or too small.
35
+
36
+ ## Why NSIGII Is Not Embedded
37
+
38
+ NSIGII is treated as an external artifact because libpolycall's responsibility here is native ABI interoperability, not NSIGII protocol logic. Embedding NSIGII directly as C headers or C source would collapse two separate concerns:
39
+
40
+ - libpolycall: command interpolation, ABI boundary, language interop, runtime dependency attachment;
41
+ - NSIGII: external proof/artifact/dependency semantics.
42
+
43
+ Keeping NSIGII outside the native demo preserves the ability to attach, detach, inspect, or replace artifacts without rebuilding libpolycall.
44
+
45
+ ## Attach/Detach Is Separate From Execution
46
+
47
+ `polycall_runtime_micro_attach` and `polycall_runtime_micro_detach` register dependency paths only. They do not load, invoke, fork, evaluate, or execute the dependency.
48
+
49
+ This preserves a linkable-then-executable model: attachment establishes that a runtime dependency may be known to the runtime; execution remains a later, explicit phase outside this minimal proof.
50
+
51
+ ## Trinary Verification Model
52
+
53
+ The response model is trinary:
54
+
55
+ - `YES`: the command or dependency operation is accepted.
56
+ - `NO`: the input is invalid, empty, or unsafe for registration.
57
+ - `MAYBE`: the command is syntactically valid but not registered.
58
+
59
+ This maps to verification-first command processing. The server never executes command strings. It asks the native ABI to verify the command, then returns the verification result.
60
+
61
+ ## Distributed Command-Line Interoperability
62
+
63
+ `curl` and `wget` provide distributed command-line entry points:
64
+
65
+ ```sh
66
+ curl "http://127.0.0.1:8084/command?cmd=ping"
67
+ wget -qO- "http://127.0.0.1:8084/command?cmd=health"
68
+ ```
69
+
70
+ The HTTP layer can be reached by ordinary command-line tools, while the actual decision boundary remains the native FFI call. That gives the demo a minimal decentralized shape: remote text request in, verification-first native ABI decision out.
@@ -0,0 +1,98 @@
1
+ # Unix Packaging And Apt Install
2
+
3
+ ## What apt can and cannot do
4
+
5
+ `sudo apt install curl-polycall` only works after `curl-polycall` has been
6
+ published into an apt repository that the machine knows about.
7
+
8
+ For local development, build a `.deb` first and install it with:
9
+
10
+ ```sh
11
+ sudo apt install ./curl-polycall_0.1.0_$(dpkg --print-architecture).deb
12
+ ```
13
+
14
+ ## Standard Unix Layout
15
+
16
+ The package follows the Filesystem Hierarchy Standard:
17
+
18
+ ```text
19
+ /usr/bin/curl-polycall
20
+ /usr/bin/curl-polycall-server
21
+ /usr/lib/curl-polycall/
22
+ /usr/lib/curl-polycall/build/bin/libpolycall_ffi.so
23
+ /etc/curl-polycall/curl-polycall.env
24
+ /usr/share/doc/curl-polycall/
25
+ /usr/share/curl-polycall/examples/
26
+ ```
27
+
28
+ Runtime config is read from `/etc/curl-polycall/curl-polycall.env`:
29
+
30
+ ```sh
31
+ CURL_POLYCALL_HOST=127.0.0.1
32
+ CURL_POLYCALL_PORT=8084
33
+ ```
34
+
35
+ ## Debian/Ubuntu Local Package
36
+
37
+ Install build tools:
38
+
39
+ ```sh
40
+ sudo apt update
41
+ sudo apt install build-essential debhelper devscripts
42
+ ```
43
+
44
+ Build the Debian package:
45
+
46
+ ```sh
47
+ chmod +x debian/rules scripts/build-deb.sh
48
+ sh scripts/build-deb.sh
49
+ ```
50
+
51
+ Install the local package:
52
+
53
+ ```sh
54
+ sudo apt install ../curl-polycall_0.1.0_$(dpkg --print-architecture).deb
55
+ ```
56
+
57
+ Use the installed commands:
58
+
59
+ ```sh
60
+ curl-polycall server
61
+ curl-polycall health
62
+ curl-polycall command ping
63
+ curl-polycall command unknown
64
+ curl-polycall attach build/bin/example.nsigii
65
+ curl-polycall detach build/bin/example.nsigii
66
+ ```
67
+
68
+ ## Generic Unix Install
69
+
70
+ For Unix-like systems without apt:
71
+
72
+ ```sh
73
+ make
74
+ sudo make install PREFIX=/usr SYSCONFDIR=/etc
75
+ ```
76
+
77
+ Remove:
78
+
79
+ ```sh
80
+ sudo make uninstall PREFIX=/usr SYSCONFDIR=/etc
81
+ ```
82
+
83
+ ## Local Apt Repository
84
+
85
+ After building the `.deb`, create a tiny local apt repository:
86
+
87
+ ```sh
88
+ mkdir -p ~/apt-repo
89
+ cp ../curl-polycall_0.1.0_$(dpkg --print-architecture).deb ~/apt-repo/
90
+ cd ~/apt-repo
91
+ dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
92
+ echo "deb [trusted=yes] file:$HOME/apt-repo ./" | sudo tee /etc/apt/sources.list.d/curl-polycall-local.list
93
+ sudo apt update
94
+ sudo apt install curl-polycall
95
+ ```
96
+
97
+ That is the step that makes plain `sudo apt install curl-polycall` work on a
98
+ machine.
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env pwsh
2
+ $ErrorActionPreference = "Stop"
3
+
4
+ $base = "http://127.0.0.1:8084"
5
+
6
+ Write-Host "Waiting for curl-polycall at $base ..."
7
+ $ready = $false
8
+ for ($i = 0; $i -lt 30; $i++) {
9
+ curl.exe --silent --fail "$base/" > $null 2>$null
10
+ if ($LASTEXITCODE -eq 0) {
11
+ $ready = $true
12
+ break
13
+ }
14
+ Start-Sleep -Milliseconds 500
15
+ }
16
+
17
+ if (-not $ready) {
18
+ throw "curl-polycall is not reachable at $base. Start it with: python .\server.py"
19
+ }
20
+
21
+ $paths = @(
22
+ "/",
23
+ "/command?cmd=ping",
24
+ "/command?cmd=health",
25
+ "/command?cmd=unknown",
26
+ "/micro/attach?path=build/bin/example.nsigii",
27
+ "/micro/detach?path=build/bin/example.nsigii"
28
+ )
29
+
30
+ foreach ($path in $paths) {
31
+ curl.exe --silent --show-error "$base$path"
32
+ Write-Host ""
33
+ }
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+ base="http://127.0.0.1:8084"
4
+
5
+ printf 'Waiting for curl-polycall at %s ...\n' "$base"
6
+ ready=0
7
+ i=0
8
+ while [ "$i" -lt 30 ]; do
9
+ if curl --silent --fail --output /dev/null "$base/"; then
10
+ ready=1
11
+ break
12
+ fi
13
+ i=$((i + 1))
14
+ sleep 0.5
15
+ done
16
+
17
+ if [ "$ready" -ne 1 ]; then
18
+ printf 'curl-polycall is not reachable at %s. Start it with: python server.py\n' "$base" >&2
19
+ exit 1
20
+ fi
21
+
22
+ curl --silent --show-error "$base/"
23
+ printf '\n'
24
+ curl --silent --show-error "$base/command?cmd=ping"
25
+ printf '\n'
26
+ curl --silent --show-error "$base/command?cmd=health"
27
+ printf '\n'
28
+ curl --silent --show-error "$base/command?cmd=unknown"
29
+ printf '\n'
30
+ curl --silent --show-error "$base/micro/attach?path=build/bin/example.nsigii"
31
+ printf '\n'
32
+ curl --silent --show-error "$base/micro/detach?path=build/bin/example.nsigii"
33
+ printf '\n'
package/ffi.py ADDED
@@ -0,0 +1,75 @@
1
+ """Direct FFI loader for curl-polycall.
2
+
3
+ This module intentionally gives the Python side an `import ffi` surface.
4
+ It uses ctypes from the Python standard library so no extra dependency is needed.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import ctypes
9
+ import os
10
+ import platform
11
+ from pathlib import Path
12
+
13
+ ROOT = Path(__file__).resolve().parent
14
+
15
+
16
+ def _default_library_name() -> str:
17
+ system = platform.system().lower()
18
+ if system == "windows":
19
+ return "polycall_ffi.dll"
20
+ if system == "darwin":
21
+ return "libpolycall_ffi.dylib"
22
+ return "libpolycall_ffi.so"
23
+
24
+
25
+ def _default_library_path() -> Path:
26
+ return ROOT / "build" / "bin" / _default_library_name()
27
+
28
+
29
+ class PolycallFFI:
30
+ def __init__(self, library_path: str | os.PathLike[str] | None = None) -> None:
31
+ self.library_path = Path(library_path) if library_path else _default_library_path()
32
+ if not self.library_path.exists():
33
+ raise FileNotFoundError(
34
+ f"FFI library not found: {self.library_path}. Build it first."
35
+ )
36
+ try:
37
+ self.lib = ctypes.CDLL(str(self.library_path))
38
+ except OSError as exc:
39
+ raise OSError(
40
+ f"Unable to load FFI library {self.library_path}: {exc}. "
41
+ "Rebuild it with a compiler target that matches this Python process."
42
+ ) from exc
43
+ self._bind()
44
+
45
+ def _bind(self) -> None:
46
+ for name in (
47
+ "polycall_verify_command",
48
+ "polycall_runtime_micro_attach",
49
+ "polycall_runtime_micro_detach",
50
+ ):
51
+ fn = getattr(self.lib, name)
52
+ fn.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
53
+ fn.restype = ctypes.c_int
54
+
55
+ def _call(self, fn_name: str, value: str) -> str:
56
+ output = ctypes.create_string_buffer(1024)
57
+ fn = getattr(self.lib, fn_name)
58
+ code = fn(value.encode("utf-8"), output, len(output))
59
+ text = output.value.decode("utf-8", errors="replace")
60
+ if code != 0:
61
+ raise RuntimeError(f"{fn_name} failed with code {code}: {text}")
62
+ return text
63
+
64
+ def command(self, command: str) -> str:
65
+ return self._call("polycall_verify_command", command)
66
+
67
+ def attach(self, dependency_path: str) -> str:
68
+ return self._call("polycall_runtime_micro_attach", dependency_path)
69
+
70
+ def detach(self, dependency_path: str) -> str:
71
+ return self._call("polycall_runtime_micro_detach", dependency_path)
72
+
73
+
74
+ def load(library_path: str | os.PathLike[str] | None = None) -> PolycallFFI:
75
+ return PolycallFFI(library_path)
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@obinexusltd/curl-polycall",
3
+ "version": "0.1.0",
4
+ "description": "Minimal curl-to-Python-to-native direct FFI demonstration for libpolycall.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/obinexus/curl-polycall#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/obinexusltd/curl-polycall.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/obinexusltd/curl-polycall/issues"
13
+ },
14
+ "keywords": [
15
+ "ffi",
16
+ "ctypes",
17
+ "curl",
18
+ "polycall",
19
+ "libpolycall",
20
+ "native-abi"
21
+ ],
22
+ "type": "commonjs",
23
+ "files": [
24
+ "build/bin/.gitkeep",
25
+ "build/obj/.gitkeep",
26
+ "config/",
27
+ "debian/",
28
+ "docs/",
29
+ "examples/",
30
+ "scripts/",
31
+ "src/",
32
+ "ffi.py",
33
+ "server.py",
34
+ "Makefile",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "bin": {
39
+ "curl-polycall": "scripts/curl-polycall.in",
40
+ "curl-polycall-server": "scripts/curl-polycall-server.in"
41
+ },
42
+ "directories": {
43
+ "build": "build",
44
+ "buildBin": "build/bin",
45
+ "buildObj": "build/obj",
46
+ "config": "config",
47
+ "debian": "debian",
48
+ "doc": "docs",
49
+ "example": "examples",
50
+ "lib": "src",
51
+ "scripts": "scripts",
52
+ "src": "src"
53
+ },
54
+ "scripts": {
55
+ "build": "make",
56
+ "build:deb": "sh scripts/build-deb.sh",
57
+ "build:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-windows.ps1",
58
+ "clean": "make clean",
59
+ "demo": "sh examples/curl.sh",
60
+ "demo:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File examples/curl.ps1",
61
+ "start": "python server.py",
62
+ "start:python3": "python3 server.py",
63
+ "test:ffi": "python -c \"import ffi; runtime = ffi.load(); print(runtime.command('ping'))\""
64
+ },
65
+ "publishConfig": {
66
+ "access": "public"
67
+ }
68
+ }
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ if ! command -v dpkg-buildpackage >/dev/null 2>&1; then
5
+ cat >&2 <<'MSG'
6
+ dpkg-buildpackage was not found.
7
+
8
+ Install the Debian packaging toolchain first:
9
+ sudo apt update
10
+ sudo apt install build-essential debhelper devscripts
11
+ MSG
12
+ exit 1
13
+ fi
14
+
15
+ dpkg-buildpackage -us -uc -b
16
+
17
+ cat <<'MSG'
18
+
19
+ Debian package build complete.
20
+
21
+ Install locally with:
22
+ sudo apt install ../curl-polycall_0.1.0_$(dpkg --print-architecture).deb
23
+
24
+ After install:
25
+ curl-polycall server
26
+ curl-polycall health
27
+ curl-polycall command ping
28
+ MSG
@@ -0,0 +1,69 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ New-Item -ItemType Directory -Force -Path build/bin | Out-Null
4
+ New-Item -ItemType Directory -Force -Path build/obj | Out-Null
5
+ Remove-Item -Force -ErrorAction SilentlyContinue `
6
+ build/bin/polycall_ffi.tmp.dll, `
7
+ build/obj/polycall_ffi.tmp.o
8
+
9
+ function Test-LastExitCode {
10
+ param([string]$Label)
11
+ if ($LASTEXITCODE -ne 0) {
12
+ throw "$Label failed with exit code $LASTEXITCODE"
13
+ }
14
+ }
15
+
16
+ function Move-BuiltDll {
17
+ try {
18
+ if (Test-Path build/bin/polycall_ffi.dll) {
19
+ Remove-Item -Force build/bin/polycall_ffi.dll
20
+ }
21
+ Move-Item -Force build/bin/polycall_ffi.tmp.dll build/bin/polycall_ffi.dll
22
+ } catch {
23
+ Remove-Item -Force -ErrorAction SilentlyContinue build/bin/polycall_ffi.tmp.dll
24
+ throw "Cannot replace build/bin/polycall_ffi.dll. Stop the running Python server first because Windows keeps loaded DLLs locked. Original error: $($_.Exception.Message)"
25
+ }
26
+ }
27
+
28
+ $clCommand = "cl /nologo /W4 /O2 /LD /Fe:build\bin\polycall_ffi.tmp.dll /Fo:build\obj\polycall_ffi.obj src\polycall_ffi.c /link /IMPLIB:build\obj\polycall_ffi.lib /PDB:build\obj\polycall_ffi.pdb"
29
+ $vcvarsCandidates = @(
30
+ "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat",
31
+ "C:\Program Files\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat",
32
+ "C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
33
+ )
34
+
35
+ foreach ($vcvars in $vcvarsCandidates) {
36
+ if (Test-Path $vcvars) {
37
+ $cmd = "`"$vcvars`" >nul && $clCommand"
38
+ cmd.exe /d /s /c $cmd
39
+ Test-LastExitCode "MSVC x64 build"
40
+ Move-BuiltDll
41
+ Write-Host "Built build/bin/polycall_ffi.dll with MSVC x64"
42
+ exit 0
43
+ }
44
+ }
45
+
46
+ if ($env:INCLUDE -and $env:LIB -and (Get-Command cl.exe -ErrorAction SilentlyContinue)) {
47
+ cl /nologo /W4 /O2 /LD /Fe:build\bin\polycall_ffi.tmp.dll /Fo:build\obj\polycall_ffi.obj src\polycall_ffi.c /link /IMPLIB:build\obj\polycall_ffi.lib /PDB:build\obj\polycall_ffi.pdb
48
+ Test-LastExitCode "MSVC build"
49
+ Move-BuiltDll
50
+ Write-Host "Built build/bin/polycall_ffi.dll with MSVC"
51
+ exit 0
52
+ }
53
+
54
+ if (Get-Command gcc.exe -ErrorAction SilentlyContinue) {
55
+ $target = (gcc -dumpmachine).Trim()
56
+ if ($target -match "mingw32") {
57
+ Write-Warning "GCC target '$target' is commonly 32-bit; the DLL may not load into 64-bit Python."
58
+ }
59
+ gcc -O2 -Wall -Wextra -c src/polycall_ffi.c -o build/obj/polycall_ffi.tmp.o
60
+ Test-LastExitCode "GCC compile"
61
+ gcc -shared build/obj/polycall_ffi.tmp.o -o build/bin/polycall_ffi.tmp.dll
62
+ Test-LastExitCode "GCC link"
63
+ Move-Item -Force build/obj/polycall_ffi.tmp.o build/obj/polycall_ffi.o
64
+ Move-BuiltDll
65
+ Write-Host "Built build/bin/polycall_ffi.dll with GCC"
66
+ exit 0
67
+ }
68
+
69
+ throw "No Windows C compiler found. Install Visual Studio Build Tools or MinGW GCC."
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ libexecdir="@LIBEXECDIR@"
5
+ envfile="${CURL_POLYCALL_ENV:-@SYSCONFDIR@/curl-polycall/curl-polycall.env}"
6
+
7
+ if [ -r "$envfile" ]; then
8
+ set -a
9
+ # shellcheck disable=SC1090
10
+ . "$envfile"
11
+ set +a
12
+ fi
13
+
14
+ exec "${PYTHON:-python3}" "$libexecdir/server.py" "$@"
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ base="${CURL_POLYCALL_URL:-http://127.0.0.1:8084}"
5
+
6
+ usage() {
7
+ cat <<'USAGE'
8
+ Usage:
9
+ curl-polycall server
10
+ curl-polycall health
11
+ curl-polycall command [ping|health|unknown]
12
+ curl-polycall attach PATH
13
+ curl-polycall detach PATH
14
+ curl-polycall demo
15
+
16
+ Environment:
17
+ CURL_POLYCALL_URL Base URL for client commands, default http://127.0.0.1:8084
18
+ USAGE
19
+ }
20
+
21
+ case "${1:-help}" in
22
+ server)
23
+ exec "@BINDIR@/curl-polycall-server"
24
+ ;;
25
+ health)
26
+ curl --silent --show-error --fail "$base/"
27
+ printf '\n'
28
+ ;;
29
+ command)
30
+ command_name="${2:-ping}"
31
+ curl --silent --show-error --fail "$base/command?cmd=$command_name"
32
+ printf '\n'
33
+ ;;
34
+ attach)
35
+ if [ "${2:-}" = "" ]; then
36
+ printf 'curl-polycall attach requires a dependency path\n' >&2
37
+ exit 2
38
+ fi
39
+ curl --silent --show-error --fail "$base/micro/attach?path=$2"
40
+ printf '\n'
41
+ ;;
42
+ detach)
43
+ if [ "${2:-}" = "" ]; then
44
+ printf 'curl-polycall detach requires a dependency path\n' >&2
45
+ exit 2
46
+ fi
47
+ curl --silent --show-error --fail "$base/micro/detach?path=$2"
48
+ printf '\n'
49
+ ;;
50
+ demo)
51
+ exec sh "@EXAMPLESDIR@/curl.sh"
52
+ ;;
53
+ help|--help|-h)
54
+ usage
55
+ ;;
56
+ *)
57
+ usage >&2
58
+ exit 2
59
+ ;;
60
+ esac
package/server.py ADDED
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import sys
6
+ from http.server import BaseHTTPRequestHandler, HTTPServer
7
+ from urllib.parse import parse_qs, urlparse
8
+
9
+ import ffi
10
+
11
+ runtime: ffi.PolycallFFI | None = None
12
+
13
+
14
+ class Handler(BaseHTTPRequestHandler):
15
+ def _send_json(self, payload: str, status: int = 200) -> None:
16
+ self.send_response(status)
17
+ self.send_header("Content-Type", "application/json")
18
+ self.end_headers()
19
+ self.wfile.write(payload.encode("utf-8"))
20
+
21
+ def do_GET(self) -> None:
22
+ if runtime is None:
23
+ self._send_json(json.dumps({"status": "NO", "message": "ffi runtime not loaded"}), 500)
24
+ return
25
+
26
+ parsed = urlparse(self.path)
27
+ query = parse_qs(parsed.query)
28
+
29
+ try:
30
+ if parsed.path == "/":
31
+ return self._send_json(json.dumps({
32
+ "status": "YES",
33
+ "message": "curl-polycall direct ffi server",
34
+ "endpoints": [
35
+ "/command?cmd=ping",
36
+ "/command?cmd=health",
37
+ "/command?cmd=unknown",
38
+ "/micro/attach?path=build/bin/example.nsigii",
39
+ "/micro/detach?path=build/bin/example.nsigii"
40
+ ]
41
+ }))
42
+
43
+ if parsed.path == "/command":
44
+ command = query.get("cmd", [""])[0]
45
+ return self._send_json(runtime.command(command))
46
+
47
+ if parsed.path == "/micro/attach":
48
+ dep = query.get("path", [""])[0]
49
+ return self._send_json(runtime.attach(dep))
50
+
51
+ if parsed.path == "/micro/detach":
52
+ dep = query.get("path", [""])[0]
53
+ return self._send_json(runtime.detach(dep))
54
+
55
+ self._send_json(json.dumps({"status": "NO", "message": "unknown endpoint"}), 404)
56
+ except Exception as exc:
57
+ self._send_json(json.dumps({"status": "NO", "message": str(exc)}), 500)
58
+
59
+
60
+ def main() -> None:
61
+ global runtime
62
+
63
+ host = os.environ.get("CURL_POLYCALL_HOST", "127.0.0.1")
64
+ port = int(os.environ.get("CURL_POLYCALL_PORT", "8084"))
65
+ try:
66
+ runtime = ffi.load()
67
+ except Exception as exc:
68
+ raise SystemExit(f"curl-polycall FFI load failed before serving: {exc}") from exc
69
+
70
+ print(f"curl-polycall serving http://{host}:{port}")
71
+ try:
72
+ HTTPServer((host, port), Handler).serve_forever()
73
+ except KeyboardInterrupt:
74
+ print("\ncurl-polycall stopped", file=sys.stderr)
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -0,0 +1,79 @@
1
+ #define POLYCALL_FFI_EXPORTS
2
+ #include "polycall_ffi.h"
3
+
4
+ #include <ctype.h>
5
+ #include <stdio.h>
6
+ #include <string.h>
7
+
8
+ static int has_non_space(const char *value) {
9
+ if (value == NULL) {
10
+ return 0;
11
+ }
12
+ while (*value != '\0') {
13
+ if (!isspace((unsigned char)*value)) {
14
+ return 1;
15
+ }
16
+ value++;
17
+ }
18
+ return 0;
19
+ }
20
+
21
+ static int dependency_path_is_valid(const char *dependency_path) {
22
+ if (!has_non_space(dependency_path)) {
23
+ return 0;
24
+ }
25
+ for (const unsigned char *cursor = (const unsigned char *)dependency_path;
26
+ *cursor != '\0';
27
+ cursor++) {
28
+ if (*cursor < 32U || *cursor == 127U) {
29
+ return 0;
30
+ }
31
+ }
32
+ return 1;
33
+ }
34
+
35
+ static int write_result(char *out_buffer, int out_buffer_len, const char *status, const char *message) {
36
+ if (out_buffer == NULL || out_buffer_len <= 0) {
37
+ return -1;
38
+ }
39
+ int written = snprintf(out_buffer, (size_t)out_buffer_len,
40
+ "{\"status\":\"%s\",\"message\":\"%s\"}",
41
+ status, message);
42
+ if (written < 0 || written >= out_buffer_len) {
43
+ return -2;
44
+ }
45
+ return 0;
46
+ }
47
+
48
+ int polycall_verify_command(const char *command, char *out_buffer, int out_buffer_len) {
49
+ if (!has_non_space(command)) {
50
+ return write_result(out_buffer, out_buffer_len, "NO", "empty command");
51
+ }
52
+
53
+ /* Verification-first example: accept only a small command vocabulary. */
54
+ if (strcmp(command, "ping") == 0) {
55
+ return write_result(out_buffer, out_buffer_len, "YES", "polycall pong via direct ffi");
56
+ }
57
+ if (strcmp(command, "health") == 0) {
58
+ return write_result(out_buffer, out_buffer_len, "YES", "ffi runtime healthy");
59
+ }
60
+
61
+ return write_result(out_buffer, out_buffer_len, "MAYBE", "command not registered");
62
+ }
63
+
64
+ int polycall_runtime_micro_attach(const char *dependency_path, char *out_buffer, int out_buffer_len) {
65
+ if (!dependency_path_is_valid(dependency_path)) {
66
+ return write_result(out_buffer, out_buffer_len, "NO", "invalid dependency path");
67
+ }
68
+
69
+ /* Attach means register/link dependency metadata at runtime; no execution here. */
70
+ return write_result(out_buffer, out_buffer_len, "YES", "micro dependency attached");
71
+ }
72
+
73
+ int polycall_runtime_micro_detach(const char *dependency_path, char *out_buffer, int out_buffer_len) {
74
+ if (!dependency_path_is_valid(dependency_path)) {
75
+ return write_result(out_buffer, out_buffer_len, "NO", "invalid dependency path");
76
+ }
77
+
78
+ return write_result(out_buffer, out_buffer_len, "YES", "micro dependency detached");
79
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef POLYCALL_FFI_H
2
+ #define POLYCALL_FFI_H
3
+
4
+ #ifdef _WIN32
5
+ #ifdef POLYCALL_FFI_EXPORTS
6
+ #define POLYCALL_API __declspec(dllexport)
7
+ #else
8
+ #define POLYCALL_API __declspec(dllimport)
9
+ #endif
10
+ #else
11
+ #define POLYCALL_API __attribute__((visibility("default")))
12
+ #endif
13
+
14
+ #ifdef __cplusplus
15
+ extern "C" {
16
+ #endif
17
+
18
+ /*
19
+ * Direct FFI boundary for libpolycall-style calls.
20
+ * This is intentionally NOT NSIGII logic and NOT a DOP adapter.
21
+ * It exposes stable C ABI functions that Python/Node/etc can load.
22
+ */
23
+ POLYCALL_API int polycall_verify_command(const char *command,
24
+ char *out_buffer,
25
+ int out_buffer_len);
26
+
27
+ POLYCALL_API int polycall_runtime_micro_attach(const char *dependency_path,
28
+ char *out_buffer,
29
+ int out_buffer_len);
30
+
31
+ POLYCALL_API int polycall_runtime_micro_detach(const char *dependency_path,
32
+ char *out_buffer,
33
+ int out_buffer_len);
34
+
35
+ #ifdef __cplusplus
36
+ }
37
+ #endif
38
+
39
+ #endif /* POLYCALL_FFI_H */