69 Commits
Author SHA1 Message Date
Khushboo Mehta e477befff1 feat: bump flake.lock 2026-08-27 13:25:32 +02:00
Dario Gabriel LipicarandClaude Opus 5 82a17ba13d feat: bundle and auto-load modules_state
The observer and the feed merged in #189, but nothing shipped or loaded the
module, so in a normal run the whole thing was inert -- correctly, since the
feed arms only when modules_state itself loads.

BUNDLE. nix/modules.nix took one hardcoded capability_module; it now takes a
list of { name; pkg; version; }. Same generated manifest, same three traps its
comments encode (the required "type" field, the explicit extension list that
Windows needs, target-vs-build platform keys).

AUTO-LOAD. initializeModulesState() runs from logos_core_start() after
initializeCapabilityModule(). Optional by construction: absent, it returns
false, nothing changes, and the observer keeps early-outing with no sink.

LOADING LAST IS FINE, and this is the part that is easy to get wrong. The
membership edges from discoverInstalledModules and capability_module's own load
happen BEFORE any sink exists, so they are dropped. The snapshot back-fills
them. modules_state cannot be first, so it must not need to be -- which is
exactly what apply_snapshot is for.

MEASURED, stock daemon, no -m flag, no test door, no load-module:

  module list  capability_module state:loaded seq:2
               modules_state     state:ready  seq:4 pid:2515
  partial      false
  REFUSED      0
  snapshot     249 ms after "Module loaded: modules_state", exactly once

capability_module appearing at all is the proof the snapshot ran: it loaded
before the feed existed, so only apply_snapshot could have put it there.
`state:ready` rather than `loaded` exercises the loaded->ready publish
transition end to end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:32:50 -03:00
Dario Gabriel LipicarandClaude Opus 5 959d11d933 chore(deps): protocol 303ab08 across all three carriers
Level 3 of the propagation of logos-protocol#74 to logos-logoscore-cli, after
logos-plugin-qt#30 and logos-qt-sdk#46. Lock-only.

THREE inputs are bumped, not one, and that is the point of this level:
logos-protocol, logos-qt-sdk and logos-plugin-qt. Those are exactly the inputs
that CARRY a runtime liblogos_protocol.dylib into this closure. Measured across
all eight non-nix inputs -- cpp-sdk, module-loader, capability-module, module
and package-manager carry none.

This repo declares `inputs.logos-protocol.follows` on logos-cpp-sdk, which is
the one input that does NOT carry a protocol lib, and omits it on qt-sdk and
plugin-qt, which do. So their protocol rev is whatever their own locks say, and
each has to be bumped by hand. Today that is invisible because every rev
coincided; the moment one moves alone this closure holds two protocol libs,
which is the duplicate-runtime condition the one-runtime symbol gate exists to
catch. Worth a follow-up (two `follows` lines) rather than repeating this by
hand next time -- deliberately NOT folded in here, so a red artifact could not
be ambiguous between the bump and a topology change.

THE LOCK STILL SHOWS FOUR PROTOCOL REVS AFTERWARDS AND THAT IS CORRECT. 7 nodes,
4 revs: 303ab08 x3 (the carriers), 42460e5 x2 under default-module-loader and
logos-capability-module, plus two deeper. Lock-node count and closure
composition are different questions, and only the second one ships:

    protocol paths in the built logos-liblogos closure: exactly ONE
    n7yilrs2...-logos-protocol-lib-0.8.0        (the build of 303ab08)

which is the same store path verified in the two levels below to carry the
change (UTF-16 "(any)" x1, old warning x0) where the lib it replaces does not.

`nix flake check`: exit 0, 2 checks, no failures. Status read from nix rather
than from a pipeline -- `nix flake check | tail` reports tail's exit code, which
is always 0, and that misreported a check earlier in this chain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 17:40:22 -03:00
Dario Gabriel Lipicar 7234c26845 chore(deps): relock module loader stack 2026-08-25 11:54:17 -03:00
Dario Gabriel LipicarandClaude Opus 5 6be8eb0c01 chore(deps): move onto logos-protocol 0.8 and logos-plugin-qt master
logos-plugin-qt#26 makes protocol 0.8 a HARD FLOOR for every consumer of
logos-qt-host: cpp/logos_provider_object.cpp and cpp/qt_provider_object.cpp call
TokenManager::saveInboundToken unguarded, so the two inputs move together or not
at all. liblogos links logos-qt-host directly, and it is upstream of both apps
(each nix/app.nix copies liblogos's lib/* over the app), so it goes first.

  logos-protocol   2e3344ac -> 42460e5b  (0.7 -> 0.8, protocol#73)
  logos-plugin-qt  1aa3e31c -> 048152f2  (plugin-qt#26)

NO CODE CHANGES, and that was checked rather than assumed. 0.8 changes which
store ModuleProxy::authorize reads, so every token site here was classified:

  module_manager.cpp:336  saveToken(name, authToken)   OUTBOUND, still correct
  module_manager.cpp:132  getToken("capability_module") outbound read
  module_manager.cpp:219  getToken("capability_module") outbound read
  logos_core.cpp:82       getToken(key)                 outbound read
  module_manager.cpp:223  client->informModuleToken(...) inbound grant, over the
                          wire -- 0.8 routes it through saveInboundToken on the
                          RECEIVING side, which is a different process here

:336 is the host caching a module's OWN host-issued credential under that
module's name; protocol pins that meaning in
TokenDirection.TheOwnCredentialStillAuthorizesAndStillGatesPushes. liblogos is
therefore NOT an instance of the "seeded a peer's token through the outbound
door, then expected to authorize an inbound call against it" defect -- it
authorizes no inbound call at all: it registers no provider anywhere in src/,
and its default loader puts every target in another process.

Verified by BUILDING all ten outputs individually with --print-out-paths, on a
24-core x86_64-linux box:

  x86_64-linux    lib bin include modules tests default portable  all OK
  checks.tests    185 tests, 0 failures, 0 errors
  x86_64-windows  default portable                                all OK

Closure audit (nix-store -qR on packages.<sys>.default), which is the thing this
whole layer exists to keep at one:

  x86_64-linux    1 logos-qt-host (ka5vgzb8…)
                  1 logos-protocol derivation at 0.8, 3 outputs
                    (…-lib-0.8.0, …-headers-0.8.0, and the symlinkJoin)
  x86_64-windows  1 logos-qt-host (cksg9kw6…-x86_64-w64-mingw32)
                  1 logos-protocol-lib-x86_64-w64-mingw32-0.8.0

liblogos-bin's lib/liblogos_qt_host.so is a re-export COPY of the input's and
compares byte-identical to it, so the two paths are one image. logos-qt-sdk no
longer ships a qt-host of its own; it only propagates that one.

Not fixed here, and now documented at the logos-capability-module input with the
measurement: the capability_module this repo SHIPS is built by its own
logos-module-builder chain against logos-protocol 0.4.0 and a pre-#26
logos-qt-host, so the repo really does emit two logos-qt-host images -- invisible
to nix-store -qR because the plugin's references are scrubbed. The five-line
`follows` that closes it was written and measured (lock 211 -> 174, symbols
58 -> 71, Linux fully green) and then REJECTED: it makes capability_module the
first module on plugin-qt master's >=0.8 glue, which emits a direct call to
logos_module_accept_inbound_token that no backend defines yet -- neither
logos-cpp-sdk's pinned rev nor its master. On ELF that links cleanly with an
undefined symbol; the Windows cross-build is what turns it into an error. Add
those follows in the same wave as the logos-cpp-sdk emitter, not before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 10:41:44 -03:00
Dario LipicarandClaude Opus 5 bfbb1998f9 chore(deps): bump logos-qt-sdk past the header dedup, and follow its plugin-qt (#185)
logos-qt-sdk#42 handed logos_ui_plugin_context.h to logos-view-module, which
owns it beside the view glue emitter it is a matched pair with. Three comments
here listed it among the headers this repo re-exports; they are corrected.

The bump is not a one-input change, for two reasons found by doing it:

  * logos-qt-sdk at this rev requires include/cpp/logos_host_core.h from the
    cpp-sdk headers export, and the logos-cpp-sdk pinned here (e3744fb) predates
    it -- CMakeLists.txt:122 fails the configure outright. So logos-cpp-sdk goes
    to acea0d2 in the same commit (and logos-lidl follows it).

  * logos-qt-sdk GAINED a logos-plugin-qt input after c6be61d0 -- the rev whose
    ABSENCE of one is what the comment here cited to argue there was "no second
    logos-qt-host to collide with". Without a follows the lock resolved qt-sdk's
    own logos-plugin-qt (9b2c64e5) alongside this repo's (1aa3e31c): two
    resolutions of the repo that owns logos-qt-host, which is a second
    TokenManager and every cross-module call refused at runtime with no build
    diagnostic. The follows is added beside the url, matching the ones already
    there for logos-protocol and logos-cpp-sdk. Lock stays at 211 nodes.

Measured effect on the header set this repo re-exports -- exactly one removal:

  removed  logos_ui_plugin_context.h
  added    logos_caller.h, logos_host_core.h, logos_host_services.h,
           logos_qt_host_core.h (+ their cpp/ copies)

logos_api.h, logos_api_provider.h, logos_provider_object.h,
logos_qt_arg_decode.h and qt_provider_object.h all SURVIVE despite leaving
qt-sdk's own cpp/: logos-qt-host supplies them, through the `cp -rf` that runs
after the qt-sdk one precisely so its copies win.

Verified: nix build .#checks.aarch64-darwin.tests and .#default both pass.

NOT addressed, and pre-existing: the lock holds SIX logos-plugin-qt nodes, five
at 9b2c64e5 and this repo's root input at 1aa3e31c. That split is byte-identical
before and after this change.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:56:40 -03:00
Dario LipicarandClaude Opus 5 b2a9a0ba9d feat(shared-runtime): import the runtime instead of providing it (#182)
* feat(shared-runtime): import the runtime instead of providing it

PR-4 of the shared-runtime migration. liblogos_core stops being the single
provider of types it does not own, and becomes a consumer of the libraries that
do: logos-protocol#65 and logos-plugin-qt#22.

WHAT GOES AWAY. The whole if(WIN32) block that absorbed liblogos_protocol.a and
liblogos_qt_host.a with --whole-archive and re-published their symbols through a
generated .def, plus cmake/gen-shared-exports.sh itself. That scheme existed
because PE exports nothing it is not told to export and the definitions lived in
archives that every other image also linked; now they live in shared libraries
that export their own tables, so there is nothing for this repo to re-publish.

WHAT REPLACES IT is one line: logos_sdk carries logos_qt_host_shared rather than
the static archive. logos_qt_host_shared PUBLIC-links logos_protocol_shared, so
the protocol half arrives transitively and correctly layered.

THE INVARIANT IS UNCHANGED. The runtime must still exist exactly once per
process; it is now enforced by there being one shared library per type rather
than by one image absorbing everything. Measured, aarch64-darwin:

    liblogos_core.dylib       defines 0   (was 32 TokenManager symbols)
                              imports 8
    liblogos_protocol.dylib   defines 78  (TokenManager, LogosAPIClient, ...)
    liblogos_qt_host.dylib    defines 23  (LogosAPI)

OUT-OF-PROCESS CONSUMERS ARE DELIBERATELY UNAFFECTED. Module plugins and ui_qml
backends keep linking the STATIC archive: each runs in its own process where its
own copy is the CORRECT per-process singleton, and a .lgx records an empty nix
closure so it could not carry a shared library anyway.

TWO DEPLOYMENT FAILURES THIS ALSO FIXES, both of which built green.

nix/lib.nix now STAGES liblogos_protocol and liblogos_qt_host beside
liblogos_core, and asserts it did. liblogos_core records
@rpath/liblogos_qt_host.dylib with @loader_path as its only rpath, so the loader
looks for them in that directory and nowhere else. Before this:

    nix build .#default        OK
    logos_host --help          exit 0
    dlopen liblogos_core.dylib Library not loaded: @rpath/liblogos_qt_host.dylib

A help-text smoke test never touches the library, so nothing in the build or in
a boot check would have caught it. Hence the assertion rather than trust in the
copy loop.

CMakeLists.txt adds both to CMAKE_BUILD_RPATH, mirroring what
LOGOS_PACKAGE_MANAGER_ROOT already does. Without it logos_core_tests aborted at
dyld time, before main(), while .#default had already succeeded.

VERIFIED, aarch64-darwin: .#default OK, dlopen OK, checks.tests PASS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(shared-runtime): install RPATH too, or the installed test binary cannot load

BUILD_RPATH covers binaries run from the build tree; the test derivation runs the
INSTALLED one, which uses INSTALL_RPATH. Only Linux said so -- on macOS the
installed test binary resolved the libraries anyway and checks.tests passed,
while the same commit on Linux died before main() with

    error while loading shared libraries: liblogos_qt_host.so

A macOS-green run is not evidence for this class of failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(tests): put the shared runtime on the hand-set Linux RPATH

nix/tests.nix applies its RPATH with `patchelf --set-rpath`, which REPLACES
whatever CMake wrote. So CMAKE_BUILD_RPATH and CMAKE_INSTALL_RPATH have no
effect on the installed test binaries on Linux, and that list is the entire
search path: anything absent from it is absent at runtime.

Measured: adding both libraries to CMAKE_*_RPATH changed nothing and the suite
still died before main() with

    error while loading shared libraries: liblogos_qt_host.so

while the same commit passed on macOS, which does not go through this code path
at all. Two platforms, two independent rpath mechanisms, and only one of them
was wired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 09:51:26 -03:00
Dario Lipicar 3893c833ec chore(deps): relock logos-capability-module onto the cycle cut (#183)
logos-capability-module#25 dropped the builder's logos-standalone-app input,
which broke the dependency cycle

  logos-capability-module -> logos-module-builder -> logos-standalone-app
    -> logos-liblogos -> logos-capability-module -> ...

flake.lock cannot express a cycle, so Nix was unrolling it 5 times across 23
levels and duplicating the whole subtree at every level. Picking up the fix
collapses this lock:

  3,472 -> 211 nodes   (2.52 MB -> 0.12 MB, -88,855 lines)

Exactly one root input moves: logos-capability-module c670f7f -> 973f71b.
Every other root input resolves to the byte-identical rev it did before -- the
24 other flakes whose rev SETS shrank were duplicate copies pinned at historical
revs inside the unrolled cycle, never the ones this repo builds against.

Level 1 of 3 (ws update-order): logos-liblogos -> logos-standalone-app ->
logos-module-builder.
2026-08-20 23:52:34 -03:00
Dario LipicarandClaude Opus 5 cb9f27a017 chore(deps): relock default-module-loader onto the teardown wait (#181)
logos-module-loader-qt#9 (dece0c8) landed the host-side half of the module
teardown contract: between exec() returning and `delete logos_api`, logos_host
now asks the module to finish and waits a bounded 3s of the container's 5s
grace before proceeding.

Everything downstream of liblogos runs modules through that host, so until this
relock a module's aboutToUnload() override is simply never called -- the hook
exists, compiles, and does nothing. That failure is silent in the worst way:
teardown looks normal and the module's cleanup just does not happen.

Additive by construction. The host invokes the hook BY NAME through the
meta-object rather than the vtable, so a plugin that does not declare it has no
such meta-method, invokeMethod returns false, and teardown proceeds exactly as
before. Every module built today is in that case.

185/185 tests pass and the library builds against the new pin.

Unblocks logos-test-modules#46, the fixture that asserts the contract end to
end; it cannot go green until a logoscore built through here carries the wait.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 20:17:05 -03:00
Dario LipicarandClaude Opus 5 6a16bfffd6 chore(deps): relock capability_module onto the universal port (#179)
The url here is unpinned — github:logos-co/logos-capability-module — so it reads
as current, while the lock sat at 0cb33fb: the pre-#24 hand-written Qt plugin,
from 2026-08-11.

capability_module master is c670f7f, the `interface: "universal"` port from its
#24: a Qt-free impl over a host-granted trust root, declaring
metadata.json#host_services and failing CLOSED until the host grants them.

Safe here because this flake's own closure carries the granting side — the
loader resolves at acd07cf (logos-module-loader-qt#8, brought in by #178), which
stamps the hostServices property and calls logos_module_grant_host_services.
Verified in the lock rather than assumed.

This matters beyond one input: liblogos is what SHIPS capability_module —
nix/bin.nix copies its modules/ into the package and logos_core loads it through
initializeCapabilityModule(). So this lock is what consumers actually get,
whatever their own flake says. Both logos-basecamp and logos-logoscore-cli were
running the old Qt module through exactly this path, behind unpinned urls that
looked current.

`nix build .#default` and checks.tests both pass.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:13:53 -03:00
Dario LipicarandClaude Opus 5 b949212d6c chore(deps): relock default-module-loader onto the host-services grant (#178)
logos-module-loader-qt#8 merged (acd07cf), adding the half of the host-services
grant that lives in the loader: module_initializer.cpp stamps the `hostServices`
property, fed by qt_plugin_format_loader's hostServicesFor(), which supplies
[token_registry, token_delivery] for capability_module.

This flake's url for that input is UNPINNED — github:logos-co/logos-module-loader-qt
with no rev — so it reads as current in review. Its LOCK, however, had been on
e648735c since 2026-08-11, so every consumer built through liblogos kept getting
the pre-grant loader hours after #8 landed.

The symptom is silent. capability_module comes up ungranted, logos::host::
tokenKeys() returns ungranted, requestModule refuses to mint, and the caller's
outbound call returns a DEFAULT with no error surfaced:

    call orchestrator_module greetThrough World
    -> {"result":"","status":"ok"}

which is how it presents in logos-capability-module's doctests (25 passed,
3 failed) while that repo's own build-and-test passes on both platforms — the
unit tests drive the impl directly, the doctest drives the whole runtime.

Only the lock changes; flake.nix is untouched. `nix build .#default` passes.

Consumers pinning liblogos need their own relock to see this — logos-logoscore-cli
in particular, whose master lock is what logos-capability-module's doctests build
logoscore from.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 09:22:48 -03:00
Dario LipicarandClaude Opus 5 93207e4141 chore(deps): track protocol and plugin-qt master (#177)
* fix(windows): point the shared-runtime .def at logos-qt-host, and fail loudly

The Windows single-provider scheme makes liblogos_core.dll the one provider of
the shared C++ runtime, and it names its inputs by CMake TARGET. logos-qt-sdk no
longer carries an archive — the Qt host runtime moved to logos-qt-host — so
$<TARGET_FILE:logos-qt-sdk::logos_qt_sdk> no longer resolves and the whole
mechanism had to be repointed.

More importantly, the old shape failed OPEN. The guard was

  if(WIN32 AND TARGET logos-protocol::... AND TARGET logos-qt-sdk::logos_qt_sdk)

so a missing target did not error — the condition simply went false and the
--whole-archive link, the nm scan and the generated .def were all skipped
SILENTLY. The result is the split-brain this file exists to prevent: main_ui and
ui-host each end up with their own TokenManager and every cross-module call is
refused. The code already fails loudly when `nm` is missing, for exactly this
reason; it had no equivalent guard for the target being absent.

Now the target tests are a foreach + FATAL_ERROR inside if(WIN32), so a missing
provider stops the configure instead of quietly restoring the split-brain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(access-policy): say ON/OFF out loud, and pin the flag both directions

Deny-by-default enforcement already existed here: `mode: "enforce"` is the
switch, and under it computeDerivedAllowedCallersLocked derives each target's
allowed callers from the declared dependency graph. Nothing about that
changes — this makes the switch legible and pins its contract.

setAccessPolicy now states which side it landed on for every input (no
policy / unparseable / non-enforce mode / enforce). Enforcement that silently
failed to arm is the dangerous outcome: it looks identical to enforcement
that is working and simply has nothing to deny, so an operator who mistyped
`"mode":"enforced"` previously got a wide-open runtime and a clean log.

DenyByDefaultFlagTest drives one scenario through the flip: `declared`
declares `target`, `undeclared` declares nothing. Flag off, the target has no
restriction at all (today's behaviour). Flag on, `declared` is on the list and
`undeclared` is not. The declared half carries the weight — an implementation
that refused everything would pass the denial half on its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(b4): link the Qt host runtime from logos-qt-host, not logos-qt-sdk

B1 moved LogosAPI / LogosAPIProvider / LogosProviderBase / PluginInterface
out of logos-qt-sdk into logos-plugin-qt, published as the CMake target
logos-qt-host::logos_qt_host. This repoints liblogos at that target so B2b
can delete logos-qt-sdk's forwarders.

The host runtime is found DIRECTLY: add logos-plugin-qt as an input (pinned
to the B1 rev, since logos-qt-host is not on its master yet) with
logos-protocol / logos-nix / nixpkgs following, and find_package it against
a new LOGOS_QT_HOST_ROOT. It is deliberately not inherited through
find_package(logos-qt-sdk) -- qt-sdk does not carry a dependency on the host
runtime today, and will carry even less of one after B2b.

That also repairs the Windows single-provider block. It already named
logos-qt-host::logos_qt_host, but its comment claimed the target arrived via
find_package(logos-qt-sdk), which was false -- so its FATAL_ERROR guard would
have fired on the first real Windows build. The guard is unchanged (still a
hard error, never a silent skip); its premise is now true.

logos-qt-sdk stays an input, for the developer headers nix/include.nix
re-exports (logos_ui_plugin_context.h and friends) -- not for the host
runtime. Its now-unused -DLOGOS_QT_SDK_ROOT flag is dropped so CMake does not
warn about an unused variable; the env entry stays.

Two silent skips converted to hard errors along the way:

  - tests/CMakeLists.txt guarded its SDK include dirs with `if(EXISTS ...)`,
    so a bad root compiled the tests against a different copy of LogosAPI
    than they link. Now FATAL.
  - nix/include.nix copies the host headers over the qt-sdk ones so consumers
    of this prefix see the declaration liblogos_core actually links (qt-host's
    carries LOGOS_SHARED_API, the dllimport that keeps Windows on one
    TokenManager). Everything copied before it is mode 0444 out of the store,
    so a plain `cp -r` fails with EACCES and the existing `|| true` would have
    swallowed it -- hence chmod + `cp -rf`, plus an assertion that the
    installed logos_api.h really is qt-host's.

Verified on aarch64-darwin with local overrides for cpp-sdk, qt-sdk, protocol
and plugin-qt: logos-liblogos-lib, -include, -tests, default and portable all
build; the `tests` check runs 185 tests, 0 failures. Pointing
LOGOS_QT_HOST_ROOT at a nonexistent path fails the build with the intended
FATAL_ERROR rather than falling back. The header prefix is a strict superset
of the previous one (58 -> 63 files, none removed).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(deps): raise logos-protocol to the rev logos-qt-host actually needs

b3b2e50 repointed this repo from logos-qt-sdk's archive to logos-plugin-qt's
logos-qt-host, but left logos-protocol on master (03842db). That made the
repoint INERT: the tree did not build at all.

    cpp/logos_api.cpp:38:52: error: no member named 'forIdentity' in 'TokenManager'
    cpp/logos_api.cpp:48:24: error: no member named 'isolateIdentity' in 'TokenManager'
    cpp/logos_api.cpp:57:50: error: no member named 'forIdentity' in 'TokenManager'

logos-qt-host's LogosAPI is built on the per-identity token store, and protocol
master has none of it -- 03842db's TokenManager carries only instance(),
m_tokens and m_mutex. The identity API arrives in c8bab12
(feat/per-client-token-store), so that is the floor for consuming qt-host at
all. The rev is pinned in the url, not just the lock, for the same reason
logos-plugin-qt already is: it is not on master, so a bare url would let
`nix flake update` silently walk this back to three compile errors.

The rev is also not merely "new enough". It is the SAME rev logos-basecamp and
logos-standalone-app pin, and that identity is the point. liblogos_core, the
app image and every in-process UI plugin share one TokenManager; two protocol
generations across that boundary give two token stores, which is the
"ModuleProxy: rejecting unauthorized call ... auth token not recognized"
failure the Windows .def block in src/CMakeLists.txt exists to prevent. On PE
that shows up as duplicate definitions; on Mach-O the second store is simply
linked into whichever image referenced a symbol liblogos_core failed to export.
Which is exactly what was happening here: with no forIdentity to import, a
consumer drags logos_api.cpp.o out of the static archive and token_manager.cpp.o
comes with it.

Only logos-protocol moves. logos-cpp-sdk, logos-qt-sdk, logos-plugin-qt and
default-module-loader already `follows` it, so all four now compile against
c8bab12 and the lock diff is one node.

Verified on aarch64-darwin, every package and check built by name, all EXIT=0:
default, logos-liblogos, -bin, -include, -lib, -modules, -tests, portable, and
the `tests` check -- 185 tests, 0 failures. The acceptance measurement on the
built library:

    nm -gU lib/liblogos_core.dylib | grep -c LogosAPI11forIdentity   -> 1  (was: no build)
    nm -gU lib/liblogos_core.dylib | grep -c TokenManager8instanceEv -> 1  (still the provider)

liblogos_core now exports the whole identity surface -- LogosAPI::forIdentity,
TokenManager::forIdentity / isolateIdentity / isIsolated / seedBootstrapTokens
-- so consumers import them instead of re-linking a second copy.

NOT fixed here, and blocking on other repos:

  - packages.x86_64-windows does not evaluate on this branch:
    `attribute 'x86_64-windows' missing` at logos-plugin-qt.packages.<system>.
    logos-qt-host. logos-qt-sdk exposes a windows pseudo-system via
    forAllTargets/mkWindowsPkgs; logos-plugin-qt has only forAllSystems over the
    four real systems. So b3b2e50 traded a Windows-capable provider for one that
    is not, and the Windows single-provider machinery this repo owns cannot be
    evaluated, let alone measured, until logos-plugin-qt grows that target.
    liblogos master (5035877) still evaluates it.

  - the consumer half of the single-provider scheme still fails open:
    logos-basecamp/cmake/LogosSharedFromDll.cmake's
    logos_use_shared_runtime_from_dll() skips names that are not targets with no
    else, so a rename there is a silent no-op rather than an error. Its callers
    pass the right names today, so the hazard is latent rather than active.
    logos-qt-sdk's comment claims that file is duplicated into
    logos-logoscore-cli; at that repo's current HEAD (df31c82) it is not --
    there are no .cmake files there at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(deps): raise logos-plugin-qt to the pushed qt-host branch tip

8ccb1fc -> cc24fa1c, the tip of logos-plugin-qt's
feat/b4-qt-host-windows-target, which is now on origin.

This is not a routine refresh. 8ccb1fc keyed `packages` off forAllSystems and
so had no x86_64-windows attribute at all, while this flake reads
logos-plugin-qt.packages.${system}.logos-qt-host from forAllTargets. Against
the old rev, packages.x86_64-windows.default did not merely fail to build, it
failed to EVALUATE:

    error: attribute 'x86_64-windows' missing
    at flake.nix:145:25
        logosQtHost = logos-plugin-qt.packages.${system}.logos-qt-host;

Against cc24fa1c it evaluates to a derivation. Both directions were confirmed
with --override-input rather than assumed.

cc24fa1c rather than the sibling feat/b4-qt-host-windows-target-8ccb1fc
(989f6ae): the two branches carry the same work and their nix/qt-host.nix is
byte-identical, so they build the same runtime. The tiebreak is that
logos-qt-sdk pins cc24fa1c. This flake deliberately does not make
logos-qt-sdk's logos-plugin-qt follow this one, so pinning the other tip would
put two logos-qt-host builds in a single closure -- two LogosAPI/TokenManager
copies in one process, which is exactly the split-brain the .def block in
src/CMakeLists.txt exists to prevent.

Nothing else in the lock moved, deliberately. logos-protocol was already at
c8bab12; logos-cpp-sdk, logos-qt-sdk and logos-capability-module stay on
master, which is what this branch was written against -- include.nix already
copies qt-host's headers OVER qt-sdk's forwarders and asserts on
LOGOS_SHARED_API, so the surviving forwarders are handled rather than merely
tolerated. That assertion passes.

Verified on aarch64-darwin: all 8 packages plus checks.tests build, exit 0
each; the test suite reports 185 tests, 0 failures, 0 errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(windows): export the lp_* C ABI from liblogos_core.dll

The generated .def kept Itanium-mangled C++ only:

    if (name !~ /^_Z/) next

Every lp_* symbol is `extern "C"`, hence unmangled, so the filter dropped the
entire logos-protocol C ABI from the export table by construction. Measured on
the built PE before this change: 3050 exports, of which lp_* = 0 — not
exported, and not even defined in the image.

It stayed invisible because until B5 only C++ callers reached the shared
runtime. B5 re-emits every Qt-typed dependency wrapper as a VENEER over the lp
path, so a consumer that compiles such a wrapper into its own image now calls
lp_invoke / lp_client_create / lp_token_save directly. logos-basecamp compiles
package_manager_api.cpp into LogosBasecamp.exe, and the link failed with plain
`undefined reference to 'lp_invoke'` — no diagnostic pointing at the .def.

Exporting is the correct fix rather than letting the consumer link
liblogos_protocol.a itself: lp_token_save and friends operate on the
TokenManager singleton, so a static copy in the exe would reinstate exactly the
split-brain token store this whole .def scheme exists to prevent. Module plugins
are separate processes and keep their own per-image copy by design.

The prefix is deliberately tight — `lp_` only, not "anything unmangled" — so the
toolchain bookkeeping the ^_Z test was there to exclude (qt_version_tag_*, which
every image legitimately defines) stays excluded.

Delta is fully attributed: 3050 -> 3080 exports, exactly the 30 lp_* symbols,
with TokenManager (45) and LogosAPI (123) unchanged. LogosBasecamp.exe then
links, and still defines 0 TokenManager::instance while importing it from
liblogos_core.dll.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(deps): track protocol and plugin-qt master

logos-protocol#59 and logos-plugin-qt#19 merged, so both rev pins are retired and
their rationales rewritten to name the PRs that closed the gaps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:56:37 -03:00
503587797d feat(windows): cross-compile liblogos, and make liblogos_core the single provider (#176)
* feat(windows): cross-compile logos-liblogos for x86_64-w64-mingw32

Adds the x86_64-windows pseudo-system to `packages` (checks and devShells stay
native). liblogos's own src/ needed NO portability work at all -- verified
exhaustively, not assumed: 17 files, 2304 lines, zero POSIX headers and zero
POSIX APIs. All process, plugin and socket work already lives in
logos-container-subprocess and logos-module-loader-qt, which were ported first.

Two real blockers, one of them silent:

* install(TARGETS logos_core ...) named only LIBRARY and ARCHIVE destinations.
  A DLL is a RUNTIME artifact, so CMake SKIPPED IT WITHOUT COMMENT: the build
  succeeded and shipped a lib/ containing liblogos_core.dll.a and no DLL at
  all -- a link-only package that would have handed logosctl.exe an import
  library with nothing behind it. Proven by reverting the fix: rc=0, no DLL.
  lib.nix now refuses to produce an output with no loadable logos_core.

* The test suite is genuinely POSIX-only (spawn.h, sys/wait.h, mkdtemp, kill),
  and CMake put it in the default `all` target, so it broke the cross build
  before anything else could. Tests are now gated behind LOGOS_BUILD_TESTS,
  with the gate wrapping the gtest FetchContent fallback too -- otherwise
  dropping gtest sends CMake to the network inside the sandbox and it dies on
  a misleading "downloading ... failed".

Also: package_manager_lib needed IMPORTED_IMPLIB (mingw links against the
import library, not the DLL), and Qt's host tools come in via
logosQtCrossCmakeFlags.

Verified: liblogos_core.dll is a PE32+ DLL whose export table carries the C
ABI (logos_core_init / _start / _load_module / _get_loaded_modules). The
output also ships logos_host_qt.exe with its 15 runtime DLLs and
capability_module_plugin.dll. Native unchanged: 181 tests, 174 passed, 7
skipped -- the same 7 ProcessManagerTest cases skipped before this change.

* fix(windows): carry the package-manager DLL closure, and type the manifest

lib.nix (Windows only): copy every *.dll / *.dll.a from the package-manager
root rather than just libpackage_manager_lib*, with a loud guard if liblgx.dll
is missing -- an absent runtime DLL otherwise shows up as an executable that
exits with no output at all.

modules.nix: emit "type": "core" in the generated manifest. Native-visible
but strictly additive.

* fix(windows): export only the C API from liblogos_core

liblogos_core.dll exported 13,252 symbols. Eighteen of them were the
logos_core_* C API; the rest were the entire internal C++ surface,
LogosAPI's included. Any consumer linking both liblogos_core and the
qt-sdk static library therefore failed with

    multiple definition of `LogosAPI::LogosAPI(QString const&, QObject*)'
      ...liblogos_qt_sdk.a(logos_api.cpp.obj)
      first defined here: ...liblogos_core.dll.a(...)

which is what blocked main_ui from linking.

Root cause: LOGOS_CORE_EXPORT expanded to
__attribute__((visibility("default"))), an ELF concept that mingw-gcc
accepts and silently ignores on PE. Nothing was explicitly exported, so
an earlier fix reached for -Wl,--export-all-symbols to get the C API out
-- correct as far as it went, and the reason the whole C++ surface
leaked with it.

Using __declspec(dllexport)/dllimport on Windows fixes it at the root and
does so twice over: GNU ld disables PE auto-export image-wide as soon as
any symbol is dllexported, so the internal surface stops leaking as a
side effect. Measured: logos_core_* exports unchanged at 18, mangled C++
exports 13,673 -> 452, LogosAPI no longer exported at all.

Two copies of LogosAPI (host and plugin) is the DESIGNED arrangement, not
a regression -- see logos_qt_lp_bridge.h, which notes a Qt plugin links
its own copy of the protocol library so TokenManager::instance() inside
it is deliberately not the host's, and syncTokens is the bridge. That
holds on Unix too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(windows): export the shared runtime from liblogos_core.dll

Makes liblogos_core the single provider of TokenManager, LogosAPI,
LogosAPIClient and the LogosResult stream operators, so the Basecamp
process has ONE of each instead of nine.

The export set comes from a GENERATED .def rather than dllexport in the
headers, because the definitions live in liblogos_protocol.a /
liblogos_qt_sdk.a -- archives also linked by logos_host.exe, ui-host.exe,
every module plugin and every native platform. Annotating them for export
would mean a second, Windows-only, export-annotated build of both
archives kept in sync forever, to solve a Windows-only problem. Exporting
at this link instead leaves those archives compiled byte-identically.

Two details in gen-shared-exports.sh that look like they could be
simplified and cannot:

  * It exports the WHOLE archive, not a curated class list. ld picks
    archive members by object file for reasons unrelated to our symbols
    -- measured here, main_ui referenced std::string's move constructor
    and ld satisfied it from logos_api.cpp.obj, dragging LogosAPI,
    LogosAPIClient and TokenManager in behind it. Consumers link an empty
    archive and take everything from the DLL, which only works if the DLL
    really provides everything; a partial export set surfaces as an
    undefined reference in a downstream repo, far from the cause.
  * It filters COMDAT symbols out. Those come from inline functions and
    templates in headers, so every consumer TU emits its own copy
    regardless; exporting them makes the import library a strong
    definition that collides with that copy.

Measured after: liblogos_core.dll goes from 18 exports to 376, of which
132 are the shared runtime; LogosBasecamp.exe drops 14.3 MB -> 1.08 MB
and main_ui.dll 23.2 MB -> 10.1 MB as the duplicated statics stop being
linked in. Native aarch64-darwin is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Merge origin/master into feat/windows-cross, and re-pin the L1-L7 inputs

master landed 56aa8bb (bump logos package manager); merged clean, no conflicts.

Then the whole chain moves to its merged revs: logos-nix (L1); logos-protocol,
logos-module, logos-container, process-stats (L2); logos-cpp-sdk,
logos-module-loader, default-container=logos-container-subprocess,
logos-package-manager (L3); logos-qt-sdk (L4);
default-module-loader=logos-module-loader-qt (L5); logos-capability-module (L7).

Verified packages.x86_64-windows.default evaluates to a .drv against the merged
set. The native aarch64-darwin build was NOT verified locally: this machine is
currently failing unrelated derivations two different ways -- clang killed with
signal 9 during CMake's trivial compiler probe, and macOS refusing a Nix-store
gtest dylib with "library load denied by system policy" during
gtest_discover_tests. The first was proven environmental rather than
input-related by building the IDENTICAL derivation hash standalone, where it
passed. CI is the authority for the native side.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 10:54:58 -03:00
Khushboo Mehta 56aa8bb45c chore: bump logos package manager 2026-08-11 19:26:54 +00:00
Dario LipicarandClaude Opus 5 2f4162a97f chore: pin logos-protocol 0f26ffd, and move CI off Nix 2.22 (#174)
liblogos pinned logos-protocol at 3a31c91 (Jul 31). Bring the root pin to
master, 0f26ffd (Aug 6) — the span is exactly two commits, protocol #40
(lp_invoke_async can report a failure) and #41 (report failures that happen
after acquire, without moving the ABI).

Why per-repo pins rather than `follows` overrides: logos-protocol is
statically linked (`nix path-info -r` on the tests output shows zero
protocol store paths), and liblogos_core.dylib alone carries 299 weak
external definitions. On macOS, when two images built against different
protocol revisions land in one process, dyld coalesces those weak
definitions and one image's protocol code silently binds to the other's —
across a real ABI change, since #41 moved
PlainLogosObject::awaitCompletion from (QString const&, int) to
(QString const&, int, QString const&, logos::CallError*). Every repo in
the chain pinning the same protocol is what makes that a non-issue; no
override is needed anywhere.

The CI installer bump is hygiene bundled in, not a requirement for the
pin: cachix/install-nix-action@v27 installs Nix 2.22.1, which mis-handles
several flake locking features. @v31 installs 2.35.1, matching what
logos-standalone-app's CI already uses (and its inline comment already
explains why v27 was not good enough there either).

Verified on aarch64-darwin: `.#logos-liblogos-tests` builds and
logos_core_tests reports 181 run / 176 passed / 5 skipped — byte-identical
to the pre-bump baseline at f63cda3, and the 5 skips are the pre-existing
"set TEST_PLUGIN" environment skips. A from-scratch re-lock (flake.lock
deleted) succeeds and lands back on 0f26ffd under Nix 2.22.1, 2.32.4 and
2.35.1, and all three evaluate the tests package to the same derivation.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:46:09 -03:00
Dario LipicarandClaude Opus 5 f63cda3891 chore: bump the module loader for the host logging fix (#173)
logos-module-loader-qt#5 makes logos_host install its own Qt message
handler, so a module's diagnostics reach the daemon that spawned it
instead of being diverted to journald by Qt's default backend.

liblogos is the carrier: nothing downstream sees that fix until this pin
moves. Measured end to end on Linux with the two halves in place (this
loader plus logos-logoscore-cli#83, which fixes a -v that never reached
the daemon and raises spdlog's level so the forwarded records survive):
module lines in a session log went from 1 to 46, and the 59 lines per
install that were escaping to journald went to 0.

Single-input bump; nothing else in the lock moved. `nix flake check`
green.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 20:44:39 -03:00
Dario LipicarandClaude Opus 5 ee5c553497 chore: bump logos-protocol to the off-strand socket close fixes (#172)
4ee85b26 -> 3a31c91d. liblogos_core statically links logos_protocol, so the
plain-transport code in this library is a copy of whatever this pin says —
which is why the pin matters here and not just downstream.

The two fixes this carries are the same race on two different asio objects:

  #38 RpcConnection::fail() closed the socket on the caller's thread while
      every other access to m_stream was serialized on m_strand. Teardown
      (~RpcClient -> ~PlainTransportConnection -> stop() -> fail()) ran
      close() -> cleanup_descriptor_data(), nulling impl.reactor_data_, while
      the io worker was inside reactive_socket_service_base::start_op() for a
      just-posted write. SIGSEGV at +0x98 on the IoContextPool thread.

  #39 The acceptor half: RpcServerTcp/Ssl::stop() closed m_acceptor on the
      host thread (via ~PlainTransportHost) while doAccept() re-armed
      async_accept from its own completion handler on the io worker.

Both now hand the close to a strand with dispatch(). Measured upstream at
~0.45% of calls over tcp and tcp_ssl, 0 over local/QtRO.

It is a false negative, not a lost result: the RPC completes and prints the
right answer, then teardown crashes, so anything that checks the exit code
before parsing stdout reports a healthy call as failed.

Also swept up between the two pins: #35 jsonToLogosResult and
#37 Codec<std::optional<T>>. Both additive.

Verification on aarch64-darwin:
  - nix build .#checks.<sys>.tests: 181 tests, 16 suites, 0 failures —
    identical to origin/master (181/16/0), so no regression and no new
    coverage; protocol's own regression tests live in logos-protocol.
  - the fix is present in the artifact, not just the lock: the new private
    methods appear in the built liblogos_core.dylib —
    closeStreamOnStrand x16 (#38), RpcServerTcp/Ssl::closeAcceptorOnStrand
    (#39) — and are absent from the same symbol table built at origin/master.

Every logos-protocol edge on the strand that feeds liblogos_core now agrees
at 3a31c91d: root, logos-cpp-sdk, logos-qt-sdk and default-module-loader
(logos-module-loader-qt). One sibling still carries its own older protocol —
see the PR description for logos-capability-module.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 16:15:23 -03:00
osmaczko 4ef9736a1e chore: bump logos-module to the object-form dependency fix (#171)
logos-module 9fb81c5 (#22): a dependency entry written in the manifest's object form ({name, version?, signer?}) was read with toString(), which yields an empty string for anything but a JSON string, so the entry was dropped and the module it names never became a dependency.

ModuleRegistry reads a module's declared dependencies through this library, so this pin is what decides whether such an entry resolves.
2026-07-30 17:39:43 -03:00
Dario LipicarandClaude Opus 5 330f1cc496 chore: bump logos-protocol to the whole-valued-float fix (#170)
logos-protocol -> 4ee85b2  (#32 whole-valued floats, #33 path threading,
                              #34 adopted byte coverage)
  logos-cpp-sdk  -> 5f63af6

liblogos was pinning c0df466, which is #31's signedness check WITHOUT #32's
follow-up — the version that rejected 3.0 as well as 3.7. That matters more here
than in a leaf consumer: the daemon embeds liblogos, so its protocol pin is what
a `logoscore call` actually runs, no matter what logoscore-cli pins directly.
liblogos does not declare a follows for protocol, so bumping the consumer alone
leaves this copy behind.

logos-logoscore-cli master has been red on doc-tests since it picked up c0df466
(`call test_basic_module addInts 40 2` fails); this is the upstream half of
that fix.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 17:26:23 -03:00
Dario LipicarandClaude Opus 5 6f0ca4b9b0 chore: bump logos-protocol to the signedness + sentinel fixes (#169)
logos-protocol c0df466 (#31):
  * Codec<T> checks integer signedness and range, so a negative can no longer
    wrap into an unsigned and a wide value can no longer truncate.
  * the pending-call sentinel is matched by shape rather than key presence. All
    four detection sites used a bare contains(), so any user map carrying that
    key was taken for a deferred call and hung for the full timeout.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:44:50 -03:00
Dario LipicarandClaude Opus 5 7202ea19f1 chore: bump logos-protocol to the uint64 fixes (#168)
logos-protocol 8b8a358 (#30) — two places where a uint64 above int64max stopped
being itself:

  * the universal -> Qt EVENT bridge converted with QJsonDocument::fromJson +
    QJsonValue::toVariant instead of the canonical helper the method path uses,
    so uintEvent(2^64-1) arrived as 1.8446744073709552e+19 while the equivalent
    method return was exact. The same bridge also failed to decode canonical
    tagged bytes into a QByteArray.

  * the plain (tcp/tcp_ssl) wire had no unsigned alternative in RpcValue, so the
    same value wrapped to -1 — silently, and independently in each direction.

Retires M6 from the LIDL conformance matrix.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 07:35:33 -03:00
Dario LipicarandClaude Opus 5 5c8b9f06f4 chore: actually pin logos-protocol to 362b03f (#167)
#166 merged a lock whose node numbering differed from master's, so the textual
merge left the ROOT logos-protocol input on 6401e30 while 362b03f landed in a
transitive slot. Re-running the update on master still moves the pin, which is
the proof it never landed.

liblogos is the module host and consumers deliberately do not follows its
protocol, so this pin drives the host path for everything that links it.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 20:18:34 -03:00
Dario LipicarandClaude Opus 5 3e548c7582 chore: bump logos-protocol and logos-cpp-sdk (#166)
logos-protocol  ae2f7e1 -> 362b03f  one canonical LIDL <-> JSON codec (#29)
  logos-cpp-sdk   350a289 -> 3d322bd  64-bit int/uint, records, cdylib
                                       composites (#111, #113)

The protocol bump is the substantive one: it folds the Qt and plain-wire copies
into the shared codec, which fixes a bstr nested in a container being UTF-8
mangled, an empty nested bstr arriving as null, and a uint64 above int64max
degrading to a double once nested.

192 tests pass.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 18:05:28 -03:00
Dario LipicarandClaude Opus 4.8 be221c5749 chore: bump protocol + qt-sdk + capability-module + module-loader-qt (multi-user + token validator) (#165)
Pulls the whole multi-user runtime together with a consistent protocol:
- logos-protocol -> 6401e30 (#20: group-shareable sockets, reaper, bind-failure +
  ModuleProxy transport-aware token validator)
- logos-qt-sdk -> 2ec5945 (#11: LogosAPIProvider::setTokenValidator)
- logos-capability-module -> 390486e (#21: rebuilt against the new protocol,
  so core_service and capability_module no longer skew)
- default-module-loader (logos-module-loader-qt) -> bc46dbf (#4: logos_host quits
  cleanly on SIGTERM/SIGINT so module local sockets are unlinked, not leaked)

logos-liblogos + logos-liblogos-lib build green.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 07:21:36 -03:00
Dario Lipicar 64de644ec6 chore: re-pin logos-protocol to master (LogosAPIConsumer handle cache) (#163)
Picks up logos-co/logos-protocol#24 (664b43f): LogosAPIConsumer caches the
remote-object handle per name across sync + async calls (no per-call QtRO replica
acquire). qt-sdk/cpp-sdk follow logos-protocol, so this one bump threads the fix
through logos_host/ui-host. Consumer-side, ABI-compatible.
2026-07-20 09:09:34 -03:00
Dario Lipicar 8ebb808dfb chore: bump logos-protocol to master (nested-bytes qvariantToNlohmann fix #23) (#162) 2026-07-17 20:54:27 -03:00
Dario LipicarandClaude Opus 4.8 819faac420 feat: add logos_core_get_modules_info() for generic module introspection (#159)
* feat: add logos_core_get_modules_info() for generic module introspection

New C API returning a JSON array describing every known module — one
object each with name, path, loaded flag, direct dependencies, direct
dependents, and the full embedded metadata (parsed from the plugin's
declarative metadata.json; null when unreadable).

ModuleInfo now caches the raw metadata JSON at discovery (via
ModuleLib::LogosModule::getRawMetadataJson, no plugin instantiation),
ModuleRegistry::allModulesInfo() assembles the array under the registry
lock, and ModuleManager exposes it as getModulesInfoJson()/CStr.

Methods/events are intentionally excluded: they require instantiating the
plugin in-process, which would defeat the subprocess-isolation model for
a bulk "all known modules" query.

Tests: ModuleManagerTest.GetModulesInfo_* (shape, empty) and
RealModuleRegistryTest.GetModulesInfo_PopulatesEmbeddedMetadata (real
plugin metadata via TEST_PLUGIN).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: bump logos-module to merged getRawMetadataJson (#21)

Re-pin logos-module a3e288a → 2ec64c4 (master, includes #21) so the
modules-info API builds against the merged getRawMetadataJson without an
override. Full test suite green on this lock (181/181).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: record module load timestamp (loaded_at) in modules-info

Add ModuleInfo::loadedAt — a unix-seconds timestamp stamped by markLoaded
(both overloads) and cleared to 0 by markUnloaded, so loaded_at is 0 ⟺ not
loaded (reload re-stamps it). Surfaced as "loaded_at" in
logos_core_get_modules_info(), letting callers derive a module's uptime as
now - loaded_at (valid only while loaded).

Tests: GetModulesInfo_ReturnsRichEntryPerModule now asserts loaded_at is 0
for an unloaded module and > 0 for a loaded one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 18:36:09 -03:00
Khushboo-dev-cpp 87ae7ce5db chore: bump logos-protocol (#158) 2026-06-26 19:31:38 +02:00
Dario LipicarandClaude Opus 4.8 a86ca28971 chore: bump logos-protocol to concurrent-dispatch + pin host transport (#157)
The bundled QtRO host (logos_host_qt, from default-module-loader =
logos-module-loader-qt) was built against the pre-concurrent-dispatch protocol
(9de4165a) while liblogos_core moved with logos-protocol — and default-module-loader
was a bare input with no follows, so it stayed stale. A c6234940 plugin's
capability-token handshake was therefore rejected ('auth token not recognized')
inside the host (wallet-ui/basecamp UI never reached Ready).

Add default-module-loader.inputs.{logos-protocol,logos-cpp-sdk,logos-qt-sdk}.follows
so the host transport is always built against the same protocol as liblogos_core,
and bump logos-protocol to current master (c6234940). No C++ source changes — every
host call site uses signature-stable API.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 09:47:17 -03:00
Khushboo-dev-cpp bcccf2db65 chore: update logos-package in flake.lock (#156) 2026-06-23 14:14:19 +02:00
Dario LipicarandClaude Opus 4.8 0c0a23db48 deps: bump logos-module-loader-qt to the process-group isolation fix (#155)
The host was extracted from liblogos into logos-module-loader-qt (#149/#151/#152),
which left liblogos pinned at module-loader-qt 08213eb — a host WITHOUT the
subprocess process-group isolation + parent-death cleanup (the setsid() +
PR_SET_PDEATHSIG + getppid-watchdog that lived on the pre-refactor 272c6b5 lineage).

module-loader-qt #3 (331760d) forward-ports that exact fix into the extracted host
(src/host/logos_host.cpp, +50 lines, no interface change). Bump default-module-loader
08213eb → 331760d so liblogos master once again ships a host that isolates each module
subprocess into its own process group and reaps it on daemon death.

This lets downstream consumers (logoscore-cli, basecamp) track liblogos master and keep
the isolation behavior, instead of pinning the pre-refactor 272c6b5 commit.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 18:59:37 -03:00
Iuri Matias dbcafea05c extract subprocess container and container abstraction, module loader abstraction and qt module loader p2 (#152)
* update flake

* make default container and default module loader something configurable on build

* update flake

* ci fix

* update flake
2026-06-17 20:24:04 -04:00
Iuri Matias f36485ba86 extract subprocess container and container abstraction, module loader abstraction and qt module loader (WIP) (#151)
* extract subprocess container and container abstraction

* decouple receiving token on a module loader from the container

* move shim subprocess_manager to tests/

* add notes about potentially moving container registration and module_loader registration to the frontends

* extract module loader abstraction and qt module loader

* remove module_name_validation.h; overkill for just one function
2026-06-17 13:38:12 -04:00
Dario LipicarandClaude Opus 4.8 050f2d3628 Qt-split retarget + logos_protocol_version load gate (#142)
* Qt-split retarget + protocol-version load gate

- Link the split SDK stack: logos-qt-sdk (LogosAPI/provider glue; the
  logos_sdk alias now points at logos-qt-sdk::logos_qt_sdk, chaining
  logos-protocol) + Qt-free logos-cpp-sdk headers.
- Protocol-version load gate (the first real consumer of module
  metadata pre-load): ModuleManager reads the module's embedded
  logos_protocol_version before runtime.load() and applies the one
  compatibility rule — equal protocol MAJOR loads, different MAJOR is
  refused with a diagnostic naming both versions, missing/unparseable
  stamp (pre-protocol modules) loads permissively with a warning. The
  decision logic is std-only (logos_core/protocol_gate.h) and unit
  tested (refuse bumped major / warn-load legacy / silent minor skew).
- ModuleDescriptor.rawMetadata is now actually populated for runtimes.

* lock: pin extraction-chain branch revs for standalone CI

Temporary — drop when the chain PRs merge (re-lock against masters).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* doctest: pin logoscore-cli to its qt-split branch head

The doc-test builds logoscore-cli at latest master with only liblogos
overridden to the commit under test; master logoscore-cli cannot build
against qt-split liblogos. Pin the runtime to the chain branch
(logos-co/logos-logoscore-cli#43) so the doc-test exercises the
coherent stack. Temporary — revert to the unpinned URL when the chain
merges.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* host: surface the spawn auth token as a LogosAPI property

cdylib-authored modules run their own statically-linked protocol stack
whose TokenManager is a separate copy of the singleton; the generated Qt
glue reads this property (cross-image-safe, like modulePath) and seeds
the cdylib's stack via logos_module_accept_token so the module's
outbound calls authenticate.

* host: set the authToken property before registerObject

registerObject runs the provider object's init() — where the cdylib glue
reads the property. Setting it afterwards meant cdylib modules always saw
an empty token.

* lock: protocol+cpp-sdk merged to master — pins advance (protocol 9de4165, cpp-sdk f0fe8cb, qt-sdk 722e590)

* lock: qt-sdk#1 merged — pin advances to qt-sdk master

* gate: drop QJson from the Qt-free core — parse rawMetadataJson with nlohmann

The protocol-version load gate had pulled QJsonDocument/QJsonObject into
src/logos_core (Qt-free territory). logos-module now exposes the embedded
metadata as a compact JSON string, so the gate reads it via nlohmann and
the std::string extractMetadata overload.

* lock: logos-module b42805d (result-lm untracked)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 21:45:49 -03:00
Iuri Matias 66256b54ef update logos-capability-module and logos-cpp-sdk (#147) 2026-06-11 16:53:59 -04:00
Iuri Matias 098fed4527 support setting access policy (#145) 2026-06-10 18:17:54 -04:00
Igor Sirotin be7c8fd8e8 chore: bump logos-cpp-sdk (provider event threading fix) (#133)
Picks up logos-co/logos-cpp-sdk#68 — marshals provider event emission onto the
remoting source thread. Host-runtime step toward fixing the start hang.
2026-05-25 11:53:24 -04:00
Dario Lipicar 54abc701fd bump capability module (#127) 2026-05-07 16:44:09 -03:00
Dario Lipicar 94af58c819 support non-local remote transports (#123)
* support non-local remote transports

* fix tests

* avoid masking crashes

* allow transport set configuration on any module

* pr comments

* add docs

* pr comments

* fixes

* fix flake.nix
2026-05-07 12:41:12 -03:00
Dario Lipicar 87b5c2e337 sendTokenToProcess: deadline-driven retry + sun_path length check (#124)
Two related fixes to the parent-side token handoff to a child module
process, both motivated by races / silent failures observed in the
docker smoke matrix.

1. Replace the hard-coded 10×100ms retry loop with a deadline-driven
   loop, default budget 5000ms (configurable via a new max_wait_ms
   parameter). The previous 900ms cap was tight enough that on a cold
   child — dynamic loader + Qt platform bring-up + CLI11 parse +
   plugin loadFromPath — the parent would give up before the child
   bound its QtTokenReceiver socket, leaving a half-loaded module
   with a misleading "Failed to connect to token socket" error. New
   tests pin both ends of the contract:
       SendToken_FailsFast_WhenSocketNeverAppears  — bails within budget
       SendToken_SucceedsAfterDelay                — accepts late binders

   test_token_exchange's WrongName_FailsCleanlyWithinTimeout bound
   loosened from <5000ms to <5500ms because the deadline check can
   overshoot by ~one poll interval (50ms) plus syscall slack.

2. Validate the computed Unix socket path against
   sockaddr_un::sun_path (~104 bytes on macOS, ~108 on Linux) before
   strncpy. Long TMPDIR + module name + LOGOS_INSTANCE_ID combos
   would otherwise silently truncate, leaving the parent connecting
   to the wrong socket while the child binds the full path. Fail
   loudly instead.
2026-05-01 17:05:17 -03:00
Dario Lipicar a392301701 bump logos-package-manager (#116) 2026-04-16 18:26:08 -03:00
Iuri Matias ed5924ef1c use logos-cpp-sdk apis without qt types (#114) 2026-04-16 13:22:41 -04:00
Dario Lipicar 522c56b4fa introduce instance persistence path for modules (#106) 2026-04-09 16:59:03 -03:00
Iuri Matias 608a11394f Replace process stats + fix existing issue with process stats + add regression test (#105)
* update process stats

* fix issue with module state disapearing on discovery refresh

* update flake
2026-04-09 10:30:33 -04:00
Khushboo-dev-cpp da6ba7210e chore: bump logos-cpp-sdk to latest master (#95) 2026-03-31 16:27:01 +02:00
Dario Lipicar 4af6ae839b fix support for more than 2 module dirs (#91) 2026-03-27 15:28:47 -03:00
Iuri Matias 0d1e47f123 use new logos module methods to simplify getting name and dependencies (#90) 2026-03-27 14:22:00 -04:00
Dario Lipicar 0ed7848d11 use package manager lib (#86) 2026-03-26 18:53:05 -03:00
Iuri MatiasandLogos Workspace a3d52477c0 remove proxy api (#84)
* remove proxy api (moved to logos-module-client)

* remove logos module client (shouldn't be needed here)

* update flake

---------

Co-authored-by: Logos Workspace <logos@workspace.local>
2026-03-25 15:38:26 -04:00
Iuri MatiasandLogos Workspace 9a17418613 Abstract proxy api (#83)
* abstract/move some of proxy api logic to cpp-sdk

* use qFatal

* remove jsonParamToQVariant

* simplify using qFatal

* remove old interface.h use logos-module

* remove local code for now (will be re-added later)

* remove unnecessary methods and qDebugs

* update flake

---------

Co-authored-by: Logos Workspace <logos@workspace.local>
2026-03-25 09:31:06 -04:00