• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 29502124931

16 Jul 2026 01:25PM UTC coverage: 28.408% (-0.9%) from 29.306%
29502124931

Pull #557

github

web-flow
Merge e21decfba into 809bff55b
Pull Request #557: feat: chat with local Claude Code via MCP endpoint

2005 of 7820 branches covered (25.64%)

Branch coverage included in aggregate %.

4012 of 13361 relevant lines covered (30.03%)

4.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.29
src/main/java/com/knowledgepixels/nanodash/NanodashPreferences.java
1
package com.knowledgepixels.nanodash;
2

3
import org.slf4j.Logger;
4
import org.slf4j.LoggerFactory;
5
import tools.jackson.core.JacksonException;
6
import tools.jackson.databind.ObjectMapper;
7
import tools.jackson.dataformat.yaml.YAMLMapper;
8

9
import java.io.File;
10
import java.io.Serializable;
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.List;
14

15
/**
16
 * Class to manage Nanodash preferences.
17
 */
18
public class NanodashPreferences implements Serializable {
6✔
19

20
    private static NanodashPreferences obj;
21
    private static final Logger logger = LoggerFactory.getLogger(NanodashPreferences.class);
12✔
22

23
    /**
24
     * Get the singleton instance of NanodashPreferences.
25
     *
26
     * @return the NanodashPreferences instance
27
     */
28
    public static NanodashPreferences get() {
29
        if (obj == null) {
6✔
30
            File prefFile = new File(System.getProperty("user.home") + DEFAULT_SETTING_PATH);
21✔
31
            if (!prefFile.exists()) {
9✔
32
                return new NanodashPreferences();
12✔
33
            }
34
            ObjectMapper mapper = new YAMLMapper();
12✔
35
            try {
36
                obj = mapper.readValue(prefFile, NanodashPreferences.class);
18✔
37
            } catch (JacksonException ex) {
3✔
38
                obj = new NanodashPreferences();
12✔
39
                logger.error("Could not read preferences file at '{}' using defaults", DEFAULT_SETTING_PATH, ex);
15✔
40
            }
3✔
41
        }
42
        return obj;
6✔
43
    }
44

45
    private List<String> nanopubActions = new ArrayList<>();
15✔
46
    private boolean readOnlyMode = false;
9✔
47
    private String websiteUrl = "http://localhost:37373/";
9✔
48
    private boolean orcidLoginMode = false;
9✔
49
    private String orcidClientId;
50
    private String orcidClientSecret;
51
    private String settingUri;
52
    private String umamiScriptUrl;
53
    private String umamiWebsiteId;
54
    private String homeResource = "https://w3id.org/spaces/knowledgepixels/nanodash/r/home";
9✔
55
    private boolean claudeChatEnabled = false;
9✔
56
    private String claudeChatBinary = "claude";
9✔
57
    private String claudeChatModel;
58
    private boolean mcpRemoteEnabled = false;
12✔
59
    public static final String DEFAULT_SETTING_PATH = "/.nanopub/nanodash-preferences.yml";
60

61
    /**
62
     * Return the list of nanopub actions.
63
     *
64
     * @return list of nanopub actions
65
     */
66
    public List<String> getNanopubActions() {
67
        String s = System.getenv("NANODASH_NANOPUB_ACTIONS");
9✔
68
        if (s != null && !s.isBlank()) {
15✔
69
            return Arrays.asList(s.split(" "));
15✔
70
        }
71
        return nanopubActions;
9✔
72
    }
73

74
    /**
75
     * Set the list of nanopub actions.
76
     *
77
     * @param nanopubActions the list of nanopub actions
78
     */
79
    public void setNanopubActions(List<String> nanopubActions) {
80
        this.nanopubActions = nanopubActions;
9✔
81
    }
3✔
82

83
    /**
84
     * Check if the application is in read-only mode.
85
     *
86
     * @return true if in read-only mode, false otherwise
87
     */
88
    public boolean isReadOnlyMode() {
89
        if ("true".equals(System.getenv("NANODASH_READ_ONLY_MODE"))) {
15✔
90
            logger.debug("Found environment variable NANODASH_READ_ONLY_MODE with value: {}", true);
15✔
91
            return true;
6✔
92
        }
93
        logger.debug("Environment variable NANODASH_READ_ONLY_MODE not set, using default: {}", readOnlyMode);
18✔
94
        return readOnlyMode;
9✔
95
    }
96

97
    /**
98
     * Set the read-only mode.
99
     *
100
     * @param readOnlyMode true to enable read-only mode, false to disable
101
     */
102
    public void setReadOnlyMode(boolean readOnlyMode) {
103
        this.readOnlyMode = readOnlyMode;
9✔
104
    }
3✔
105

106
    /**
107
     * Get the website URL.
108
     *
109
     * @return the website URL
110
     */
111
    public String getWebsiteUrl() {
112
        String s = System.getenv("NANODASH_WEBSITE_URL");
9✔
113
        if (s != null && !s.isBlank()) {
15✔
114
            logger.debug("Found environment variable NANODASH_WEBSITE_URL with value: {}", s);
12✔
115
            return s;
6✔
116
        }
117
        logger.debug("Environment variable NANODASH_WEBSITE_URL not set, using default: {}", websiteUrl);
15✔
118
        return websiteUrl;
9✔
119
    }
120

121
    /**
122
     * Set the website URL.
123
     *
124
     * @param websiteUrl the website URL to set
125
     */
126
    public void setWebsiteUrl(String websiteUrl) {
127
        this.websiteUrl = websiteUrl;
9✔
128
    }
3✔
129

130
    /**
131
     * Check if the application is in ORCID login mode.
132
     *
133
     * @return true if in ORCID login mode, false otherwise
134
     */
135
    public boolean isOrcidLoginMode() {
136
        if ("true".equals(System.getenv("NANODASH_ORCID_LOGIN_MODE"))) {
15✔
137
            logger.debug("Found environment variable NANODASH_ORCID_LOGIN_MODE with value: {}", true);
15✔
138
            return true;
6✔
139
        }
140
        logger.debug("Environment variable NANODASH_ORCID_LOGIN_MODE not set, using default: {}", orcidLoginMode);
18✔
141
        return orcidLoginMode;
9✔
142
    }
143

144
    /**
145
     * Set the ORCID login mode.
146
     *
147
     * @param orcidLoginMode true to enable ORCID login mode, false to disable
148
     */
149
    public void setOrcidLoginMode(boolean orcidLoginMode) {
150
        this.orcidLoginMode = orcidLoginMode;
9✔
151
    }
3✔
152

153
    /**
154
     * Get the ORCID client ID.
155
     *
156
     * @return the ORCID client ID
157
     */
158
    public String getOrcidClientId() {
159
        String s = System.getenv("NANOPUB_ORCID_CLIENT_ID");
9✔
160
        if (s != null && !s.isBlank()) {
15✔
161
            logger.debug("Found environment variable NANOPUB_ORCID_CLIENT_ID with value: {}", s);
12✔
162
            return s;
6✔
163
        }
164
        logger.debug("Environment variable NANOPUB_ORCID_CLIENT_ID not set, using default: {}", orcidClientId);
15✔
165
        return orcidClientId;
9✔
166
    }
167

168
    /**
169
     * Set the ORCID client ID.
170
     *
171
     * @param orcidClientId the ORCID client ID to set
172
     */
173
    public void setOrcidClientId(String orcidClientId) {
174
        this.orcidClientId = orcidClientId;
9✔
175
    }
3✔
176

177
    /**
178
     * Get the ORCID client secret.
179
     * .
180
     *
181
     * @return the ORCID client secret
182
     */
183
    public String getOrcidClientSecret() {
184
        String s = System.getenv("NANOPUB_ORCID_CLIENT_SECRET");
9✔
185
        if (s != null && !s.isBlank()) {
15✔
186
            logger.debug("Found environment variable NANOPUB_ORCID_CLIENT_SECRET");
9✔
187
            return s;
6✔
188
        }
189
        logger.debug("Environment variable NANOPUB_ORCID_CLIENT_SECRET not set, using default");
9✔
190
        return orcidClientSecret;
9✔
191
    }
192

193
    /**
194
     * Set the ORCID client secret.
195
     *
196
     * @param orcidClientSecret the ORCID client secret to set
197
     */
198
    public void setOrcidClientSecret(String orcidClientSecret) {
199
        this.orcidClientSecret = orcidClientSecret;
9✔
200
    }
3✔
201

202
    /**
203
     * Get the setting URI.
204
     *
205
     * @return the setting URI
206
     */
207
    public String getSettingUri() {
208
        return settingUri;
9✔
209
    }
210

211
    /**
212
     * Set the setting URI.
213
     *
214
     * @param settingUri the setting URI to set
215
     */
216
    public void setSettingUri(String settingUri) {
217
        this.settingUri = settingUri;
9✔
218
    }
3✔
219

220
    /**
221
     * Get the Umami analytics script URL.
222
     *
223
     * @return the Umami script URL, or null if not configured
224
     */
225
    public String getUmamiScriptUrl() {
226
        String s = System.getenv("NANODASH_UMAMI_SCRIPT_URL");
9✔
227
        if (s != null && !s.isBlank()) return s;
6!
228
        return umamiScriptUrl;
9✔
229
    }
230

231
    /**
232
     * Set the Umami analytics script URL.
233
     *
234
     * @param umamiScriptUrl the Umami script URL to set
235
     */
236
    public void setUmamiScriptUrl(String umamiScriptUrl) {
237
        this.umamiScriptUrl = umamiScriptUrl;
×
238
    }
×
239

240
    /**
241
     * Get the Umami analytics website ID.
242
     *
243
     * @return the Umami website ID, or null if not configured
244
     */
245
    public String getUmamiWebsiteId() {
246
        String s = System.getenv("NANODASH_UMAMI_WEBSITE_ID");
×
247
        if (s != null && !s.isBlank()) return s;
×
248
        return umamiWebsiteId;
×
249
    }
250

251
    /**
252
     * Set the Umami analytics website ID.
253
     *
254
     * @param umamiWebsiteId the Umami website ID to set
255
     */
256
    public void setUmamiWebsiteId(String umamiWebsiteId) {
257
        this.umamiWebsiteId = umamiWebsiteId;
×
258
    }
×
259

260
    /**
261
     * Check whether the local Claude Code chat feature is enabled.
262
     *
263
     * Intended for locally running single-user instances only; see
264
     * docs/claude-code-chat.md.
265
     *
266
     * @return true if the Claude chat feature is enabled
267
     */
268
    public boolean isClaudeChatEnabled() {
269
        if ("true".equals(System.getenv("NANODASH_CLAUDE_CHAT_ENABLED"))) {
×
270
            return true;
×
271
        }
272
        return claudeChatEnabled;
×
273
    }
274

275
    /**
276
     * Set whether the local Claude Code chat feature is enabled.
277
     *
278
     * @param claudeChatEnabled true to enable
279
     */
280
    public void setClaudeChatEnabled(boolean claudeChatEnabled) {
281
        this.claudeChatEnabled = claudeChatEnabled;
×
282
    }
×
283

284
    /**
285
     * Get the command to run the Claude Code CLI.
286
     *
287
     * @return the binary name or path (default "claude")
288
     */
289
    public String getClaudeChatBinary() {
290
        String s = System.getenv("NANODASH_CLAUDE_CHAT_BINARY");
×
291
        if (s != null && !s.isBlank()) return s;
×
292
        return claudeChatBinary;
×
293
    }
294

295
    /**
296
     * Set the command to run the Claude Code CLI.
297
     *
298
     * @param claudeChatBinary the binary name or path
299
     */
300
    public void setClaudeChatBinary(String claudeChatBinary) {
301
        this.claudeChatBinary = claudeChatBinary;
×
302
    }
×
303

304
    /**
305
     * Get the model override for Claude Code chat sessions.
306
     *
307
     * @return the model name, or null to use the CLI's default
308
     */
309
    public String getClaudeChatModel() {
310
        String s = System.getenv("NANODASH_CLAUDE_CHAT_MODEL");
×
311
        if (s != null && !s.isBlank()) return s;
×
312
        return claudeChatModel;
×
313
    }
314

315
    /**
316
     * Set the model override for Claude Code chat sessions.
317
     *
318
     * @param claudeChatModel the model name
319
     */
320
    public void setClaudeChatModel(String claudeChatModel) {
321
        this.claudeChatModel = claudeChatModel;
×
322
    }
×
323

324
    /**
325
     * Check whether remote MCP access with per-user API tokens is enabled.
326
     *
327
     * Lets users point their own AI agents at this instance's /mcp endpoint;
328
     * independent of the local Claude chat feature (either can be enabled
329
     * without the other). See docs/remote-mcp.md.
330
     *
331
     * @return true if remote MCP access is enabled
332
     */
333
    public boolean isMcpRemoteEnabled() {
334
        if ("true".equals(System.getenv("NANODASH_MCP_REMOTE_ENABLED"))) {
15!
335
            return true;
×
336
        }
337
        return mcpRemoteEnabled;
9✔
338
    }
339

340
    /**
341
     * Set whether remote MCP access with per-user API tokens is enabled.
342
     *
343
     * @param mcpRemoteEnabled true to enable
344
     */
345
    public void setMcpRemoteEnabled(boolean mcpRemoteEnabled) {
346
        this.mcpRemoteEnabled = mcpRemoteEnabled;
×
347
    }
×
348

349
    public String getHomeResource() {
350
        String s = System.getenv("NANODASH_HOME_RESOURCE");
×
351
        if (s != null && !s.isBlank()) {
×
352
            logger.debug("Found environment variable NANODASH_HOME_RESOURCE with value: {}", s);
×
353
            return s;
×
354
        }
355
        logger.debug("Environment variable NANODASH_HOME_RESOURCE not set, using default: {}", homeResource);
×
356
        return homeResource;
×
357
    }
358

359
    public void setHomeResource(String homeResource) {
360
        this.homeResource = homeResource;
×
361
    }
×
362

363
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc