Skip to content

[ffi] Evaluate shellout or child_process and isolate command-tooling FFI #20

Closed

Description

@GG-O-BP

Context

cmd_ffi.mjs runs external processes and CLI tooling through Node child_process.

Current boundary:

  • src/glendix/cmd_ffi.mjs
    • execSync / spawnSync usage behind exec, bridge runners, experimental-native runners, and npm/node shims
    • warning filters and process-output handling
  • src/glendix/cmd.gleam
    • externals exec, run_with_bridge, run_dev_with_bridge, run_experimental_native*, command_error_message, fail_process, etc.

Much of this is Glendix-specific build orchestration, but the generic "run a command" primitive may have an ecosystem equivalent.

Proposed package/API (spike)

  • Evaluate shellout (or plinth's child_process bindings) for the generic command-execution primitive (exec).
  • Isolate genuinely Glendix-specific tooling (bridge generation, experimental-native environment setup, Rollup/WASM, shim writing) from the generic execution primitive.
  • Decide which parts can use a package and which remain intentionally custom, and document the split.

Compatibility and public API impact

  • Preserve exit-code and failure semantics currently surfaced through command_error_message / fail_process and process stdio behavior (inherited stdio, filtered warnings).
  • Any replacement must preserve synchronous-vs-async behavior relied on by the CLI.
  • Confirm the chosen package supports the required stdio and error reporting on the Node target.

Non-goals

  • Rewriting bridge generation, experimental-native setup, or Rollup/WASM handling.
  • Changing CLI command semantics or output.

Acceptance criteria

  • Spike records whether shellout/child_process bindings can back the generic exec primitive and the delta in stdio/error handling.
  • The generic execution primitive is isolated from Glendix-specific tooling; if a package is adopted it backs that primitive.
  • Retained custom command tooling is documented as intentional.
  • Tests/contract checks cover success and failure exit paths and error-message surfacing.
  • FFI contract checks report no stale external declarations or exports.
  • glendix -> mendraw retains its currently declared dependency source form.

Verification

  • Local implementation loop: ./scripts/verify.sh inner glendix
  • If public signatures change: ./scripts/verify.sh shared glendix
  • Before a release or family-wide compatibility claim: ./scripts/verify.sh final

Activity

  1. added
    ffiForeign-function interface boundaries and interop
    refactorInternal restructuring without an intended feature change
    spikeTime-boxed investigation needed before implementation
    on Sep 7, 2026
  2. GG-O-BP commented on Sep 7, 2026

    @GG-O-BP
    CollaboratorAuthor

    분석 결과, generic exec에는 shellout을 채택하고 Glendix 전용 프로세스 코드는 유지하는 하이브리드 분리가 적합합니다.

    • shellout.command는 JavaScript/Node에서 동기식 spawnSync 기반이며, exit status를 Result로 돌려주고 LetBeStdout/LetBeStderr로 현재의 inherited stdio 동작을 보존할 수 있습니다.
    • 다만 현재 cmd.exec 공개 API는 인수 배열이 아니라 shell command string을 받으므로, Unix의 /bin/sh -c와 Windows의 ComSpec /d /s /c로 변환하는 얇은 플랫폼 경계가 필요합니다.
    • plinth/node/child_process의 현재 API는 exec/spawn handle과 stdin/kill만 제공하며, 동기 완료 결과, exit code, stdout/stderr 정책을 typed Result로 제공하지 않아 이 primitive의 대체재로는 부족합니다.
    • gleam ... 실행 시 Erlang backend의 알려진 불필요 warning만 제거하는 기존 동작은 shellout이 stdout/stderr를 분리해 필터링하는 API를 제공하지 않으므로 작은 custom boundary로 남겨야 합니다. 이는 generic execution이 아니라 Glendix의 Gleam build-output 정책입니다.
    • bridge 생성/정리, dev watcher, experimental-native 환경 및 Node/npm shim, Rollup/WASM 처리는 이 이슈의 non-goal이며 기존 custom tooling으로 유지합니다.

    구현 시 다음 계약을 보존하겠습니다.

    1. cmd.exec(command:) -> Result(Nil, CommandError) 공개 signature와 동기 동작
    2. 성공 시 Ok(Nil), 실패 시 CommandFailed("execute command", reason)
    3. stdin/stdout/stderr inherited 동작과 shell string 해석
    4. Gleam warning filtering 및 실패 메시지(Command failed: <command>) surfacing
    5. bridge/native tooling의 기존 semantics와 cleanup
    6. glendix -> mendraw의 현재 Hex dependency source

    테스트는 generic command 성공/실패, shell-string 처리, 실패 reason surfacing, Gleam filtered-runner 성공/실패를 contract 수준에서 추가하고 FFI declaration/export gate까지 실행하겠습니다.

  3. added a commit that references this issue on Sep 7, 2026
    0bf413d
  4. GG-O-BP commented on Sep 7, 2026

    @GG-O-BP
    CollaboratorAuthor

    ✅ Resolved via #34, merged into main (merge commit 0bf413d, implementation commit 0b1aa55).

    What shipped

    • Generic cmd.exec now delegates to the maintained shellout ~> 1.8.0 synchronous command, replacing the bespoke shell FFI wrapper while keeping the public contract stable (cmd.exec(command:) -> Result(Nil, CommandError), CommandFailed("execute command", reason)).
    • Cross-platform shell semantics preserved (Unix /bin/sh -c, Windows ComSpec /d /s /c).
    • New focused glendix/command module (+ FFI) with a contract test asserting the shellout.LetBeStdout SIGINT listener is cleaned up after execution.
    • plinth/node/child_process was evaluated and rejected (no synchronous completion / typed exit status / typed stdio). The remaining small custom FFI (Gleam warning filtering) is retained and documented in the READMEs.

    Verification

    • Family-wide ./scripts/verify.sh final passed: source/style/FFI/boundary gates, all standalone consumers, all package tests (gleam test 142 passed), Glendam browser checks, widget .mpk build, and Mendix full E2E (BUILD SUCCEEDED + post-boot browser smoke).
    • package-gates CI on the PR passed.
    • Dependency contract preserved: glendix -> mendraw remains a Hex requirement; pushed-tip dependency check passed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ffiForeign-function interface boundaries and interoprefactorInternal restructuring without an intended feature changespikeTime-boxed investigation needed before implementation

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions