refactor(cli,ffi): relocate file_watcher to libgossamer with C-ABI exports#24
Merged
Merged
Conversation
…ports
Move cli/src/file_watcher.zig → src/interface/ffi/src/file_watcher.zig so
any libgossamer consumer can use the hot-reload watcher — the native Zig
CLI (today), the planned Ephapax-wasm CLI behind a host launcher, or
third-party embedders.
Changes:
• git-mv the source file; update its header to reflect the new home.
• Add two C-ABI exports at the bottom of the relocated file:
- gossamer_watcher_start(handle, config_json, frontend_dist)
dupes both buffers into watcher-owned memory so callers may free
their inputs immediately on return.
- gossamer_watcher_stop(opaque_handle)
blocks on thread join, then frees the owned buffers + state.
• Extend WatcherState with owned_json / owned_frontend_dist fields so
the slices stored in WatchConfig outlive any caller-provided buffer
when started via the C boundary. Zig-native start() leaves both null
(back-compat — caller manages lifetime).
• Wire src/interface/ffi/src/main.zig to pick up the new module via
the existing comptime { _ = @import(...) } pattern.
• cli/src/main.zig: drop the local @import("file_watcher.zig"), add
extern decls for the two new exports, replace the call sites in
cmdDev() with the C-ABI calls.
Verified:
• zig ast-check on all 3 touched files — zero parse errors.
• Compile-link to GTK3/WebKitGTK requires those system dev libs which
aren't installed in this WSL env (pre-existing limitation, not a
regression); CI will run the full build.
Phase 14a.2 of the gossamer cli (cli/) port from native Zig to typed-wasm
Ephapax. Unblocks task #15 by ensuring the watcher API is reachable from
any future wasm-host launcher.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 41 issues detected
View findings[
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Action actions/upload-artifact@v4 needs attention",
"type": "unpinned_action",
"file": "release.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action actions/download-artifact@v4 needs attention",
"type": "unpinned_action",
"file": "release.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/gossamer/gossamer/tests/unit/result_code_test.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/gossamer/gossamer/tests/unit/guard_mode_test.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/gossamer/gossamer/tests/unit/ipc_test.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/gossamer/gossamer/tests/unit/capability_test.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/gossamer/gossamer/tests/unit/dialog_test.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This was referenced May 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cli/src/file_watcher.zig→src/interface/ffi/src/file_watcher.zigso any libgossamer consumer (today's native Zig CLI, the planned Ephapax-wasm CLI behind a host launcher, third-party embedders) shares the same hot-reload path.gossamer_watcher_start(handle, config_json, frontend_dist) -> opaque*andgossamer_watcher_stop(opaque*) -> void. The start path dupes both buffers into watcher-owned memory so callers may free their inputs on return.cli/src/main.zigto call the new exports viaextern fndecls instead of importing the moved file.Why
Phase 14a.2 of porting the gossamer CLI to typed-wasm Ephapax (umbrella issue forthcoming). The watcher is platform-coupled GTK-thread-marshalling code — it belongs in FFI/Zig per the architecture rule, not in the CLI's application code. Relocating it now means the future Ephapax port doesn't need to re-implement hot-reload from scratch.
Test plan
zig ast-checkon all three touched files — zero parse errors.gossamer devagainst a real project — edit a watched file, confirm reload still fires.Notes for reviewer
WatcherStategained two optional fields (owned_json,owned_frontend_dist) that store dupes of the caller's strings. The Zig-nativestart()path leaves bothnullfor back-compat; only the new C-ABIgossamer_watcher_startpopulates them.parseWatchConfigis unchanged. A real JSON parser belongs in libgossamer (planned in a follow-up:gossamer_conf_load).🤖 Generated with Claude Code