Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mvn/jvm.config
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
-Ddevelocity.scan.disabled=true
--enable-preview
86 changes: 86 additions & 0 deletions application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@
<groupId>dev.ikm.tinkar</groupId>
<artifactId>changeset-writer-provider</artifactId>
</dependency>
<dependency>
<groupId>dev.ikm.ike</groupId>
<artifactId>rocks-kb-engine</artifactId>
</dependency>
<dependency>
<groupId>network.ike.komet</groupId>
<artifactId>komet-claude-plugin</artifactId>
<version>1-SNAPSHOT</version>
</dependency>
<!-- RocksDB platform-specific natives; classifier set by OS profile below -->
<dependency>
<groupId>dev.ikm.jpms</groupId>
<artifactId>rocksdbjni</artifactId>
<classifier>${rocksdbjni.classifier}</classifier>
</dependency>

<!-- Start JPro related dependencies -->
<dependency>
Expand Down Expand Up @@ -185,6 +200,13 @@
<groupId>dev.ikm.tinkar</groupId>
<artifactId>events</artifactId>
</dependency>
<!-- gRPC datastore/search plugin — lives outside the komet repo, mirroring
komet-claude-plugin. Owns all gRPC-specific deps (grpc-stub, grpc-protobuf,
perfmark-api, etc); application only needs this one artifact + module requires. -->
<dependency>
<groupId>network.ike.komet</groupId>
<artifactId>komet-grpc-plugin</artifactId>
</dependency>
</dependencies>
<build>
<resources>
Expand Down Expand Up @@ -225,6 +247,15 @@
<ignoreSigningInformation>true</ignoreSigningInformation>
<options>
<option>-Xmx10g</option>
<!-- Required: tinkar-core uses preview features -->
<option>--enable-preview</option>
<option>--add-opens</option>
<option>javafx.graphics/javafx.scene=org.controlsfx.controls</option>
<option>--add-exports</option>
<option>javafx.controls/com.sun.javafx.scene.control.behavior=dev.ikm.komet.navigator</option>
<option>--add-exports</option>
<option>javafx.base/com.sun.javafx.event=one.jpro.platform.file</option>
<option>-Djava.util.concurrent.ForkJoinPool.common.exceptionHandler=dev.ikm.tinkar.common.alert.UncaughtExceptionAlertStreamer</option>
</options>
</configuration>
</plugin>
Expand All @@ -238,6 +269,21 @@
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<configuration>
<mainClass>dev.ikm.komet.application/dev.ikm.komet.app.App</mainClass>
<options>
<!-- tinkar-core uses preview features; must be enabled at runtime -->
<option>--enable-preview</option>
<option>-Xmx8g</option>
<option>--add-opens</option>
<option>javafx.graphics/javafx.scene=org.controlsfx.controls</option>
<option>--add-exports</option>
<option>javafx.controls/com.sun.javafx.scene.control.behavior=dev.ikm.komet.navigator</option>
<option>--add-exports</option>
<option>javafx.base/com.sun.javafx.event=one.jpro.platform.file</option>
<option>-Djava.util.concurrent.ForkJoinPool.common.exceptionHandler=dev.ikm.tinkar.common.alert.UncaughtExceptionAlertStreamer</option>
</options>
</configuration>
<executions>
<execution>
<!-- Default configuration for running -->
Expand All @@ -253,6 +299,8 @@
<jlinkVerbose>true</jlinkVerbose>
<jlinkZipName>kometJlink</jlinkZipName>
<options>
<!-- tinkar-core uses preview features; must be enabled at runtime -->
<option>--enable-preview</option>
<option>-Xmx8g</option>
<option>--add-opens</option>
<option>javafx.graphics/javafx.scene=org.controlsfx.controls</option>
Expand All @@ -261,6 +309,42 @@
<option>--add-exports</option>
<option>javafx.base/com.sun.javafx.event=one.jpro.platform.file</option>
<option>-Djava.util.concurrent.ForkJoinPool.common.exceptionHandler=dev.ikm.tinkar.common.alert.UncaughtExceptionAlertStreamer</option>
<!-- Forward datastore auto-select + gRPC connection properties from Maven -D flags to the app JVM -->
<option>-Dkomet.datastore.controller=${komet.datastore.controller}</option>
<option>-Dkomet.grpc.port=${komet.grpc.port}</option>
<option>-Dkomet.grpc.host=${komet.grpc.host}</option>
<!--
Allow the gRPC plugin (named module) to access grpc-api classes
from the unnamed module (classpath). grpc-netty-shaded transitively
pulls grpc-api onto the classpath; add-reads grants access.
-->
<option>--add-reads</option>
<option>dev.ikm.tinkar.provider.grpc=ALL-UNNAMED</option>
<!--
Reverse direction: grpc-netty-shaded/grpc-core/grpc-util (on the
classpath, unnamed module) reference classes shaded into
dev.ikm.tinkar.provider.grpc from grpc-api/guava — extend, in
NettyChannelProvider's case. A named module's packages are invisible
to the unnamed module unless explicitly exported to it. List
confirmed exhaustively via `jdeps -verbose:package` against every
classpath-resident gRPC jar.
-->
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/io.grpc=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.base=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.collect=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.io=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.math=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.util.concurrent=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.hash=ALL-UNNAMED</option>
<option>--add-exports</option>
<option>dev.ikm.tinkar.provider.grpc/com.google.common.primitives=ALL-UNNAMED</option>
</options>
</configuration>
</execution>
Expand Down Expand Up @@ -447,6 +531,7 @@
<jpackage.type>PKG</jpackage.type>
<jpackage.icon>src/main/resources/icons/KOMET.icns</jpackage.icon>
<jpackage.resourceDir>installer_resources/resourceDir_unix</jpackage.resourceDir>
<rocksdbjni.classifier>osx</rocksdbjni.classifier>
</properties>
</profile>
<profile>
Expand All @@ -461,6 +546,7 @@
<jpackage.type>RPM</jpackage.type>
<jpackage.icon>src/main/resources/icons/Komet.png</jpackage.icon>
<jpackage.resourceDir>installer_resources/resourceDir_unix</jpackage.resourceDir>
<rocksdbjni.classifier>linux64</rocksdbjni.classifier>
</properties>
</profile>
<profile>
Expand Down
51 changes: 49 additions & 2 deletions application/src/main/java/dev/ikm/komet/app/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static dev.ikm.komet.app.AppState.LOADING_DATA_SOURCE;
import static dev.ikm.komet.app.AppState.LOGIN;
import static dev.ikm.komet.app.AppState.RUNNING;
import static dev.ikm.komet.app.AppState.SELECTED_DATA_SOURCE;
import static dev.ikm.komet.app.AppState.SELECT_DATA_SOURCE;
import static dev.ikm.komet.app.AppState.SHUTDOWN;
import static dev.ikm.komet.app.AppState.STARTING;
Expand Down Expand Up @@ -49,6 +50,7 @@
import dev.ikm.komet.preferences.Preferences;
import dev.ikm.tinkar.common.alert.AlertObject;
import dev.ikm.tinkar.common.alert.AlertStreams;
import dev.ikm.tinkar.common.service.NoLocalUserStore;
import dev.ikm.tinkar.common.service.PrimitiveData;
import dev.ikm.tinkar.common.service.TinkExecutor;
import dev.ikm.tinkar.events.Evt;
Expand Down Expand Up @@ -193,7 +195,6 @@ private static void addShutdownHook() {
LOG.info("Starting shutdown hook");

try {
// Save and stop primitive data services gracefully
PrimitiveData.save();
PrimitiveData.stop();
} catch (Exception e) {
Expand Down Expand Up @@ -333,11 +334,23 @@ public void start(Stage stage) {

/**
* Handles the login feature based on the provided {@link LoginFeatureFlag} and platform.
* <p>
* When the system property {@code komet.datastore.controller} is set, the application
* auto-selects the named {@link dev.ikm.tinkar.common.service.DataServiceController}
* (matched by exact name, then by case-insensitive substring) instead of showing the
* datasource-selection screen. Author login is still skipped or shown afterward based on
* whether the selected provider implements {@link NoLocalUserStore} — see
* {@link #appStateChangeListener}.
*
* @param loginFeatureFlag the current state of the login feature
* @param stage the current application stage
*/
public void handleLoginFeature(LoginFeatureFlag loginFeatureFlag, Stage stage) {
String datastoreControllerProp = System.getProperty("komet.datastore.controller");
if (datastoreControllerProp != null && !datastoreControllerProp.isBlank()) {
startWithNamedDataSource(stage, datastoreControllerProp);
return;
}
switch (loginFeatureFlag) {
case ENABLED_WEB_ONLY -> {
if (IS_BROWSER) {
Expand All @@ -358,6 +371,34 @@ public void handleLoginFeature(LoginFeatureFlag loginFeatureFlag, Stage stage) {
}
}

/**
* Auto-selects a named data store controller and feeds it through the same
* {@link AppState#SELECTED_DATA_SOURCE} → {@link LoadDataSourceTask} → {@link AppState#SELECT_USER}
* pipeline that manual datasource selection uses, instead of showing the selection screen.
*
* @param stage the primary stage
* @param controllerName value of the {@code komet.datastore.controller} system property
*/
private void startWithNamedDataSource(Stage stage, String controllerName) {
var controllers = PrimitiveData.getControllerOptions();
var match = controllers.stream()
.filter(c -> c.controllerName().equalsIgnoreCase(controllerName))
.findFirst()
.or(() -> controllers.stream()
.filter(c -> c.controllerName().toLowerCase().contains(controllerName.toLowerCase()))
.findFirst());
if (match.isEmpty()) {
LOG.error("No data store controller matching '{}'; available: {}", controllerName,
controllers.stream().map(c -> c.controllerName()).toList());
startSelectDataSource(stage);
return;
}
PrimitiveData.selectControllerByName(match.get().controllerName());
LOG.info("Auto-selected data store controller: {}", match.get().controllerName());
state.addListener(this::appStateChangeListener);
state.set(SELECTED_DATA_SOURCE);
}

/**
* Initiates the login process by setting the application state to {@link AppState#LOGIN}
* and launching the login page.
Expand Down Expand Up @@ -499,7 +540,13 @@ private void appStateChangeListener(ObservableValue<? extends AppState> observab
TinkExecutor.threadPool().submit(new LoadDataSourceTask(state));
}
case SELECT_USER -> {
appPages.launchLoginAuthor(primaryStage);
// Providers with no local author/STAMP store (e.g. a remote-backed provider)
// skip login and go straight to RUNNING.
if (PrimitiveData.get() instanceof NoLocalUserStore) {
Platform.runLater(() -> state.set(RUNNING));
} else {
appPages.launchLoginAuthor(primaryStage);
}
}
case RUNNING -> {
if (userProperty.get() == null) {
Expand Down
35 changes: 26 additions & 9 deletions application/src/main/java/dev/ikm/komet/app/AppPages.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,13 @@ public void launchLandingPage(Stage stage, ConceptFacade loggedInUser) {
String username = windowSettings.getView().calculator().getPreferredDescriptionTextWithFallbackOrNid(loggedInUser.nid());
app.landingPageController = landingPageLoader.getController();

// Set the logged-in user as author on the controller's single edit coordinate
app.landingPageController.editCoordinate().authorForChangesProperty().setValue(loggedInUser);
// Set the logged-in user as author on the controller's single edit coordinate.
// In gRPC mode the ephemeral store has no entities, so nid resolution may fail; suppress.
try {
app.landingPageController.editCoordinate().authorForChangesProperty().setValue(loggedInUser);
} catch (Exception e) {
LOG.warn("Could not set author concept (expected in gRPC mode with empty data store): {}", e.getMessage());
}
app.landingPageController.getWelcomeTitleLabel().setText("Welcome " + username);
app.landingPageController.setSelectedDatasetTitle(PrimitiveData.get().name());
app.landingPageController.getGithubStatusHyperlink().setOnAction(_ -> app.appGithub.connectToGithub());
Expand Down Expand Up @@ -342,13 +347,25 @@ void launchJournalViewPage(PrefX journalWindowSettings, ConceptFacade loggedInUs
KometNodeFactory navigatorNodeFactory = new GraphNavigatorNodeFactory();
KometNodeFactory searchNodeFactory = new SearchNodeFactory();

journalController.launchKometFactoryNodes(
journalWindowSettings.getValue(JOURNAL_TITLE),
navigatorNodeFactory,
searchNodeFactory);
// load additional panels
journalController.loadNextGenReasonerPanel();
journalController.loadNextGenSearchPanel();
try {
journalController.launchKometFactoryNodes(
journalWindowSettings.getValue(JOURNAL_TITLE),
navigatorNodeFactory,
searchNodeFactory);
} catch (Exception e) {
LOG.error("Failed to launch navigator/search factory nodes (non-fatal in gRPC mode)", e);
}
// load additional panels — run independently so a nav failure doesn't block search
try {
journalController.loadNextGenReasonerPanel();
} catch (Exception e) {
LOG.error("Failed to load NextGen Reasoner panel", e);
}
try {
journalController.loadNextGenSearchPanel();
} catch (Exception e) {
LOG.error("Failed to load NextGen Search panel", e);
}
});
// disable the delete menu option for a Journal Card.
journalWindowSettings.setValue(CAN_DELETE, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,15 @@ void dataSourceChanged(ObservableValue<? extends DataServiceController<?>> obser
fileListView.getItems().sort(NaturalOrder.getObjectComparator());
fileListView.getSelectionModel().selectFirst();
fileListView.getSelectionModel().selectFirst();
fileListView.requestFocus();
boolean hasOptions = !fileListView.getItems().isEmpty();
fileListView.setVisible(hasOptions);
fileListView.setManaged(hasOptions);
// When there is no file list, move the property sheet up and let it span both rows
GridPane.setRowIndex(propertySheet, hasOptions ? 1 : 0);
GridPane.setRowSpan(propertySheet, hasOptions ? 1 : 2);
if (hasOptions) {
fileListView.requestFocus();
}

propertySheet.getItems().clear();
validationSupport = new ValidationSupport();
Expand Down
8 changes: 8 additions & 0 deletions application/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@
requires dev.ikm.tinkar.provider.ephemeral;
// End not happy...

// Plugin modules — must be explicit so the JVM includes them in the module graph
// (service binding via transitively-required modules' `uses` is not sufficient).
// komet-grpc-plugin's jar retains the module name dev.ikm.tinkar.provider.grpc
// (its original name from tinkar-core, before the implementation moved into the
// external plugin repo) rather than a komet.* name — no wrapper module needed.
requires komet.claude;
requires dev.ikm.tinkar.provider.grpc;

// JPro related modules
requires jpro.webapi;
requires one.jpro.platform.auth.core;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import dev.ikm.tinkar.common.id.PublicIdStringKey;
import dev.ikm.tinkar.common.service.PrimitiveData;
import dev.ikm.tinkar.entity.*;
import dev.ikm.tinkar.entity.EntityStringUtil;
import dev.ikm.tinkar.terms.EntityFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -118,7 +117,7 @@ public void addToContextMenu(Control control, ContextMenu contextMenu, ViewPrope
if (entityFacade != null) {
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
content.putString(EntityStringUtil.recursiveEntityToString(entityFacade));
content.putString(PrimitiveData.text(entityFacade.nid()));
clipboard.setContent(content);
}
});
Expand Down
Loading
Loading