opencode-graphiti 0.2.0 → 0.2.1-canary.4a80c5d.20260327091326

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -365,7 +365,8 @@ regardless of how aggressively the conversation was summarized.
365
365
  > work as summarized tool events. This plugin promotes child sessions to
366
366
  > first-class participants in the root session's state so that decisions, file
367
367
  > edits, and errors from delegated work are fully visible to the parent session.
368
- > See `docs/ContextOverhaul.md` §11.1 for the design rationale.
368
+ > See `docs/superpowers/plans/2026-03-20-context-mode-mcp-first.md` for the
369
+ > MCP-first rationale and canonical root-session participation model.
369
370
 
370
371
  When OpenCode spawns a child session (e.g. a subagent or delegated task), the
371
372
  plugin resolves the child's `sessionID` to the root/parent session by walking
@@ -1,3 +1,4 @@
1
+ import { notifyPluginWarning } from "./services/opencode-warning.js";
1
2
  import type { GraphitiConfig } from "./types/index.js";
2
3
  type ConfigLoadResult = {
3
4
  config: unknown;
@@ -17,6 +18,8 @@ export interface ConfigExplorerAdapter {
17
18
  type ConfigExplorerFactory = () => ConfigExplorerAdapter;
18
19
  export declare const setConfigExplorerAdapterForTesting: (factory: ConfigExplorerFactory) => void;
19
20
  export declare const resetConfigExplorerAdapterForTesting: () => void;
21
+ export declare const setConfigWarningNotifierForTesting: (notifier: typeof notifyPluginWarning) => void;
22
+ export declare const resetConfigWarningNotifierForTesting: () => void;
20
23
  export declare function loadConfig(directory?: string): GraphitiConfig;
21
24
  export {};
22
25
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AAkB1E,KAAK,gBAAgB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AAEnD,KAAK,mBAAmB,GACpB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,mBAAmB,CAAA;KAAE;CAiB1D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC1C;AAED,KAAK,qBAAqB,GAAG,MAAM,qBAAqB,CAAC;AAuPzD,eAAO,MAAM,kCAAkC,GAC7C,SAAS,qBAAqB,KAC7B,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AA6EF,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAgB7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AAkB1E,KAAK,gBAAgB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AAEnD,KAAK,mBAAmB,GACpB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,mBAAmB,CAAA;KAAE;CAiB1D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC1C;AAED,KAAK,qBAAqB,GAAG,MAAM,qBAAqB,CAAC;AAkSzD,eAAO,MAAM,kCAAkC,GAC7C,SAAS,qBAAqB,KAC7B,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AAEF,eAAO,MAAM,kCAAkC,GAC7C,UAAU,OAAO,mBAAmB,KACnC,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AA4FF,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAoD7D"}
package/esm/src/config.js CHANGED
@@ -2,7 +2,7 @@ import os from "node:os";
2
2
  import { createRequire } from "node:module";
3
3
  import { join } from "node:path";
4
4
  import { redactEndpointUserInfo } from "./services/endpoint-redaction.js";
5
- import { logger } from "./services/logger.js";
5
+ import { notifyPluginWarning } from "./services/opencode-warning.js";
6
6
  const DEFAULT_CONFIG = {
7
7
  redis: {
8
8
  endpoint: "redis://localhost:6379",
@@ -144,6 +144,37 @@ const normalizeConfiguredEndpoints = (value) => {
144
144
  : value.redis,
145
145
  };
146
146
  };
147
+ const getCanonicalGraphitiEndpoint = (value) => value?.graphiti?.endpoint ?? value?.endpoint;
148
+ const formatHostForUrl = (hostname) => hostname.includes(":") && !hostname.startsWith("[")
149
+ ? `[${hostname}]`
150
+ : hostname;
151
+ const inferSiblingEndpoints = (value) => {
152
+ if (!value)
153
+ return value;
154
+ const graphitiEndpoint = getCanonicalGraphitiEndpoint(value);
155
+ const redisEndpoint = value.redis?.endpoint;
156
+ if (graphitiEndpoint && !redisEndpoint) {
157
+ const host = formatHostForUrl(new URL(graphitiEndpoint).hostname);
158
+ return {
159
+ ...value,
160
+ redis: {
161
+ ...value.redis,
162
+ endpoint: `redis://${host}:6379`,
163
+ },
164
+ };
165
+ }
166
+ if (redisEndpoint && !graphitiEndpoint) {
167
+ const host = formatHostForUrl(new URL(redisEndpoint).hostname);
168
+ return {
169
+ ...value,
170
+ graphiti: {
171
+ ...value.graphiti,
172
+ endpoint: `http://${host}:8000/mcp`,
173
+ },
174
+ };
175
+ }
176
+ return value;
177
+ };
147
178
  const resolveNumber = (...candidates) => candidates.find((value) => value !== undefined);
148
179
  const resolveConfig = (value) => {
149
180
  const raw = value ?? {};
@@ -154,7 +185,7 @@ const resolveConfig = (value) => {
154
185
  const resolvedSessionTtlSeconds = resolveNumber(raw.redis?.sessionTtlSeconds);
155
186
  const resolvedCacheTtlSeconds = resolveNumber(raw.redis?.cacheTtlSeconds);
156
187
  const resolvedDrainRetryMax = resolveNumber(raw.redis?.drainRetryMax);
157
- const requestedGraphitiEndpoint = raw.graphiti?.endpoint ?? raw.endpoint;
188
+ const requestedGraphitiEndpoint = getCanonicalGraphitiEndpoint(raw);
158
189
  const resolvedGraphitiEndpoint = requestedGraphitiEndpoint ??
159
190
  DEFAULT_CONFIG.graphiti.endpoint;
160
191
  const resolvedGroupIdPrefix = raw.graphiti?.groupIdPrefix ??
@@ -207,12 +238,19 @@ const createCosmiconfigAdapter = () => {
207
238
  };
208
239
  };
209
240
  let configExplorerFactory = createCosmiconfigAdapter;
241
+ let notifyConfigWarning = notifyPluginWarning;
210
242
  export const setConfigExplorerAdapterForTesting = (factory) => {
211
243
  configExplorerFactory = factory;
212
244
  };
213
245
  export const resetConfigExplorerAdapterForTesting = () => {
214
246
  configExplorerFactory = createCosmiconfigAdapter;
215
247
  };
248
+ export const setConfigWarningNotifierForTesting = (notifier) => {
249
+ notifyConfigWarning = notifier;
250
+ };
251
+ export const resetConfigWarningNotifierForTesting = () => {
252
+ notifyConfigWarning = notifyPluginWarning;
253
+ };
216
254
  const getConfigExplorerAdapter = () => {
217
255
  try {
218
256
  return configExplorerFactory();
@@ -225,7 +263,7 @@ const loadConfigFile = (adapter, filePath) => {
225
263
  try {
226
264
  const loaded = adapter?.load(filePath);
227
265
  const normalized = loaded
228
- ? normalizeConfiguredEndpoints(normalizeConfig(loaded.config))
266
+ ? inferSiblingEndpoints(normalizeConfiguredEndpoints(normalizeConfig(loaded.config)))
229
267
  : null;
230
268
  return normalized;
231
269
  }
@@ -247,7 +285,7 @@ const searchConfig = (adapter, directory) => {
247
285
  try {
248
286
  const loaded = adapter.search(directory);
249
287
  const normalized = loaded
250
- ? normalizeConfiguredEndpoints(normalizeConfig(loaded.config))
288
+ ? inferSiblingEndpoints(normalizeConfiguredEndpoints(normalizeConfig(loaded.config)))
251
289
  : null;
252
290
  return normalized;
253
291
  }
@@ -266,23 +304,55 @@ const loadLegacyConfig = (adapter) => {
266
304
  return null;
267
305
  return loadConfigFile(adapter, join(homeDir, ".config", "opencode", ".graphitirc"));
268
306
  };
307
+ const warnIgnoredConfigSource = (source, error) => {
308
+ notifyConfigWarning(`Ignoring ${source} and using defaults: ${error.message}`, { source, code: error.code });
309
+ };
269
310
  const isRecoverableConfigLoadFailure = (error) => error instanceof ConfigLoadError &&
270
311
  (error.code === "config-discovery-init" ||
271
312
  error.code === "config-discovery-search" ||
272
- error.code === "config-file-load");
313
+ error.code === "config-file-load" ||
314
+ error.code === "config-invalid");
273
315
  export function loadConfig(directory) {
316
+ let adapter;
317
+ try {
318
+ adapter = getConfigExplorerAdapter();
319
+ }
320
+ catch (error) {
321
+ if (!(error instanceof ConfigLoadError) ||
322
+ !isRecoverableConfigLoadFailure(error)) {
323
+ throw error;
324
+ }
325
+ if (error.code === "config-discovery-init") {
326
+ return resolveConfig(null);
327
+ }
328
+ throw error;
329
+ }
330
+ try {
331
+ const discovered = searchConfig(adapter, directory);
332
+ if (discovered) {
333
+ return resolveConfig(discovered);
334
+ }
335
+ }
336
+ catch (error) {
337
+ if (!(error instanceof ConfigLoadError) ||
338
+ !isRecoverableConfigLoadFailure(error)) {
339
+ throw error;
340
+ }
341
+ if (error.code === "config-discovery-search") {
342
+ return resolveConfig(null);
343
+ }
344
+ warnIgnoredConfigSource("discovered config", error);
345
+ return resolveConfig(null);
346
+ }
274
347
  try {
275
- const adapter = getConfigExplorerAdapter();
276
- const loaded = searchConfig(adapter, directory);
277
- const resolved = loaded ?? loadLegacyConfig(adapter);
278
- return resolveConfig(resolved);
348
+ return resolveConfig(loadLegacyConfig(adapter));
279
349
  }
280
350
  catch (error) {
281
351
  if (!(error instanceof ConfigLoadError) ||
282
352
  !isRecoverableConfigLoadFailure(error)) {
283
353
  throw error;
284
354
  }
285
- logger.warn(error.message, error);
355
+ warnIgnoredConfigSource("legacy config", error);
286
356
  return resolveConfig(null);
287
357
  }
288
358
  }
@@ -4,5 +4,6 @@ export declare const setWarningTaskScheduler: (scheduler: ((callback: () => void
4
4
  export declare const setSuppressConsoleWarningsDuringTestsOverride: (value: boolean | undefined) => void;
5
5
  export declare const logStructuredWarning: (message: string, extra?: unknown) => boolean;
6
6
  export declare const showWarningToast: (message: string, extra?: unknown) => boolean;
7
+ export declare const notifyPluginWarning: (message: string, extra?: unknown) => void;
7
8
  export declare const notifyGraphitiAvailabilityIssue: (message: string, extra?: unknown) => void;
8
9
  //# sourceMappingURL=opencode-warning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-warning.d.ts","sourceRoot":"","sources":["../../../src/src/services/opencode-warning.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,wCAAwC,QAAO,OAM3D,CAAC;AA6FF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,OAAO,KACd,IAEF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,KACtD,IAIF,CAAC;AAEF,eAAO,MAAM,6CAA6C,GACxD,OAAO,OAAO,GAAG,SAAS,KACzB,IAEF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,OAEF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,KAAG,OAEnE,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAMF,CAAC"}
1
+ {"version":3,"file":"opencode-warning.d.ts","sourceRoot":"","sources":["../../../src/src/services/opencode-warning.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,wCAAwC,QAAO,OAM3D,CAAC;AA6FF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,OAAO,KACd,IAEF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,KACtD,IAIF,CAAC;AAEF,eAAO,MAAM,6CAA6C,GACxD,OAAO,OAAO,GAAG,SAAS,KACzB,IAEF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,OAEF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,KAAG,OAEnE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAMF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAEF,CAAC"}
@@ -95,10 +95,13 @@ export const logStructuredWarning = (message, extra) => {
95
95
  export const showWarningToast = (message, extra) => {
96
96
  return scheduleWarningToast(message, extra);
97
97
  };
98
- export const notifyGraphitiAvailabilityIssue = (message, extra) => {
98
+ export const notifyPluginWarning = (message, extra) => {
99
99
  const logged = scheduleStructuredWarning(message, extra);
100
100
  const toasted = scheduleWarningToast(message, extra);
101
101
  if (!logged && !toasted) {
102
102
  warnToConsole(message, extra);
103
103
  }
104
104
  };
105
+ export const notifyGraphitiAvailabilityIssue = (message, extra) => {
106
+ notifyPluginWarning(message, extra);
107
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-graphiti",
3
- "version": "0.2.0",
3
+ "version": "0.2.1-canary.4a80c5d.20260327091326",
4
4
  "description": "OpenCode plugin for persistent memory via Graphiti knowledge graph",
5
5
  "keywords": [
6
6
  "opencode",
@@ -1,3 +1,4 @@
1
+ import { notifyPluginWarning } from "./services/opencode-warning.js";
1
2
  import type { GraphitiConfig } from "./types/index.js";
2
3
  type ConfigLoadResult = {
3
4
  config: unknown;
@@ -17,6 +18,8 @@ export interface ConfigExplorerAdapter {
17
18
  type ConfigExplorerFactory = () => ConfigExplorerAdapter;
18
19
  export declare const setConfigExplorerAdapterForTesting: (factory: ConfigExplorerFactory) => void;
19
20
  export declare const resetConfigExplorerAdapterForTesting: () => void;
21
+ export declare const setConfigWarningNotifierForTesting: (notifier: typeof notifyPluginWarning) => void;
22
+ export declare const resetConfigWarningNotifierForTesting: () => void;
20
23
  export declare function loadConfig(directory?: string): GraphitiConfig;
21
24
  export {};
22
25
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AAkB1E,KAAK,gBAAgB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AAEnD,KAAK,mBAAmB,GACpB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,mBAAmB,CAAA;KAAE;CAiB1D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC1C;AAED,KAAK,qBAAqB,GAAG,MAAM,qBAAqB,CAAC;AAuPzD,eAAO,MAAM,kCAAkC,GAC7C,SAAS,qBAAqB,KAC7B,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AA6EF,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAgB7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AAkB1E,KAAK,gBAAgB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AAEnD,KAAK,mBAAmB,GACpB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAGjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,mBAAmB,CAAA;KAAE;CAiB1D;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC1C;AAED,KAAK,qBAAqB,GAAG,MAAM,qBAAqB,CAAC;AAkSzD,eAAO,MAAM,kCAAkC,GAC7C,SAAS,qBAAqB,KAC7B,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AAEF,eAAO,MAAM,kCAAkC,GAC7C,UAAU,OAAO,mBAAmB,KACnC,IAEF,CAAC;AAEF,eAAO,MAAM,oCAAoC,QAAO,IAEvD,CAAC;AA4FF,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAoD7D"}
@@ -3,13 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resetConfigExplorerAdapterForTesting = exports.setConfigExplorerAdapterForTesting = exports.ConfigLoadError = void 0;
6
+ exports.resetConfigWarningNotifierForTesting = exports.setConfigWarningNotifierForTesting = exports.resetConfigExplorerAdapterForTesting = exports.setConfigExplorerAdapterForTesting = exports.ConfigLoadError = void 0;
7
7
  exports.loadConfig = loadConfig;
8
8
  const node_os_1 = __importDefault(require("node:os"));
9
9
  const node_module_1 = require("node:module");
10
10
  const node_path_1 = require("node:path");
11
11
  const endpoint_redaction_js_1 = require("./services/endpoint-redaction.js");
12
- const logger_js_1 = require("./services/logger.js");
12
+ const opencode_warning_js_1 = require("./services/opencode-warning.js");
13
13
  const DEFAULT_CONFIG = {
14
14
  redis: {
15
15
  endpoint: "redis://localhost:6379",
@@ -152,6 +152,37 @@ const normalizeConfiguredEndpoints = (value) => {
152
152
  : value.redis,
153
153
  };
154
154
  };
155
+ const getCanonicalGraphitiEndpoint = (value) => value?.graphiti?.endpoint ?? value?.endpoint;
156
+ const formatHostForUrl = (hostname) => hostname.includes(":") && !hostname.startsWith("[")
157
+ ? `[${hostname}]`
158
+ : hostname;
159
+ const inferSiblingEndpoints = (value) => {
160
+ if (!value)
161
+ return value;
162
+ const graphitiEndpoint = getCanonicalGraphitiEndpoint(value);
163
+ const redisEndpoint = value.redis?.endpoint;
164
+ if (graphitiEndpoint && !redisEndpoint) {
165
+ const host = formatHostForUrl(new URL(graphitiEndpoint).hostname);
166
+ return {
167
+ ...value,
168
+ redis: {
169
+ ...value.redis,
170
+ endpoint: `redis://${host}:6379`,
171
+ },
172
+ };
173
+ }
174
+ if (redisEndpoint && !graphitiEndpoint) {
175
+ const host = formatHostForUrl(new URL(redisEndpoint).hostname);
176
+ return {
177
+ ...value,
178
+ graphiti: {
179
+ ...value.graphiti,
180
+ endpoint: `http://${host}:8000/mcp`,
181
+ },
182
+ };
183
+ }
184
+ return value;
185
+ };
155
186
  const resolveNumber = (...candidates) => candidates.find((value) => value !== undefined);
156
187
  const resolveConfig = (value) => {
157
188
  const raw = value ?? {};
@@ -162,7 +193,7 @@ const resolveConfig = (value) => {
162
193
  const resolvedSessionTtlSeconds = resolveNumber(raw.redis?.sessionTtlSeconds);
163
194
  const resolvedCacheTtlSeconds = resolveNumber(raw.redis?.cacheTtlSeconds);
164
195
  const resolvedDrainRetryMax = resolveNumber(raw.redis?.drainRetryMax);
165
- const requestedGraphitiEndpoint = raw.graphiti?.endpoint ?? raw.endpoint;
196
+ const requestedGraphitiEndpoint = getCanonicalGraphitiEndpoint(raw);
166
197
  const resolvedGraphitiEndpoint = requestedGraphitiEndpoint ??
167
198
  DEFAULT_CONFIG.graphiti.endpoint;
168
199
  const resolvedGroupIdPrefix = raw.graphiti?.groupIdPrefix ??
@@ -215,6 +246,7 @@ const createCosmiconfigAdapter = () => {
215
246
  };
216
247
  };
217
248
  let configExplorerFactory = createCosmiconfigAdapter;
249
+ let notifyConfigWarning = opencode_warning_js_1.notifyPluginWarning;
218
250
  const setConfigExplorerAdapterForTesting = (factory) => {
219
251
  configExplorerFactory = factory;
220
252
  };
@@ -223,6 +255,14 @@ const resetConfigExplorerAdapterForTesting = () => {
223
255
  configExplorerFactory = createCosmiconfigAdapter;
224
256
  };
225
257
  exports.resetConfigExplorerAdapterForTesting = resetConfigExplorerAdapterForTesting;
258
+ const setConfigWarningNotifierForTesting = (notifier) => {
259
+ notifyConfigWarning = notifier;
260
+ };
261
+ exports.setConfigWarningNotifierForTesting = setConfigWarningNotifierForTesting;
262
+ const resetConfigWarningNotifierForTesting = () => {
263
+ notifyConfigWarning = opencode_warning_js_1.notifyPluginWarning;
264
+ };
265
+ exports.resetConfigWarningNotifierForTesting = resetConfigWarningNotifierForTesting;
226
266
  const getConfigExplorerAdapter = () => {
227
267
  try {
228
268
  return configExplorerFactory();
@@ -235,7 +275,7 @@ const loadConfigFile = (adapter, filePath) => {
235
275
  try {
236
276
  const loaded = adapter?.load(filePath);
237
277
  const normalized = loaded
238
- ? normalizeConfiguredEndpoints(normalizeConfig(loaded.config))
278
+ ? inferSiblingEndpoints(normalizeConfiguredEndpoints(normalizeConfig(loaded.config)))
239
279
  : null;
240
280
  return normalized;
241
281
  }
@@ -257,7 +297,7 @@ const searchConfig = (adapter, directory) => {
257
297
  try {
258
298
  const loaded = adapter.search(directory);
259
299
  const normalized = loaded
260
- ? normalizeConfiguredEndpoints(normalizeConfig(loaded.config))
300
+ ? inferSiblingEndpoints(normalizeConfiguredEndpoints(normalizeConfig(loaded.config)))
261
301
  : null;
262
302
  return normalized;
263
303
  }
@@ -276,23 +316,55 @@ const loadLegacyConfig = (adapter) => {
276
316
  return null;
277
317
  return loadConfigFile(adapter, (0, node_path_1.join)(homeDir, ".config", "opencode", ".graphitirc"));
278
318
  };
319
+ const warnIgnoredConfigSource = (source, error) => {
320
+ notifyConfigWarning(`Ignoring ${source} and using defaults: ${error.message}`, { source, code: error.code });
321
+ };
279
322
  const isRecoverableConfigLoadFailure = (error) => error instanceof ConfigLoadError &&
280
323
  (error.code === "config-discovery-init" ||
281
324
  error.code === "config-discovery-search" ||
282
- error.code === "config-file-load");
325
+ error.code === "config-file-load" ||
326
+ error.code === "config-invalid");
283
327
  function loadConfig(directory) {
328
+ let adapter;
329
+ try {
330
+ adapter = getConfigExplorerAdapter();
331
+ }
332
+ catch (error) {
333
+ if (!(error instanceof ConfigLoadError) ||
334
+ !isRecoverableConfigLoadFailure(error)) {
335
+ throw error;
336
+ }
337
+ if (error.code === "config-discovery-init") {
338
+ return resolveConfig(null);
339
+ }
340
+ throw error;
341
+ }
342
+ try {
343
+ const discovered = searchConfig(adapter, directory);
344
+ if (discovered) {
345
+ return resolveConfig(discovered);
346
+ }
347
+ }
348
+ catch (error) {
349
+ if (!(error instanceof ConfigLoadError) ||
350
+ !isRecoverableConfigLoadFailure(error)) {
351
+ throw error;
352
+ }
353
+ if (error.code === "config-discovery-search") {
354
+ return resolveConfig(null);
355
+ }
356
+ warnIgnoredConfigSource("discovered config", error);
357
+ return resolveConfig(null);
358
+ }
284
359
  try {
285
- const adapter = getConfigExplorerAdapter();
286
- const loaded = searchConfig(adapter, directory);
287
- const resolved = loaded ?? loadLegacyConfig(adapter);
288
- return resolveConfig(resolved);
360
+ return resolveConfig(loadLegacyConfig(adapter));
289
361
  }
290
362
  catch (error) {
291
363
  if (!(error instanceof ConfigLoadError) ||
292
364
  !isRecoverableConfigLoadFailure(error)) {
293
365
  throw error;
294
366
  }
295
- logger_js_1.logger.warn(error.message, error);
367
+ warnIgnoredConfigSource("legacy config", error);
296
368
  return resolveConfig(null);
297
369
  }
298
370
  }
@@ -4,5 +4,6 @@ export declare const setWarningTaskScheduler: (scheduler: ((callback: () => void
4
4
  export declare const setSuppressConsoleWarningsDuringTestsOverride: (value: boolean | undefined) => void;
5
5
  export declare const logStructuredWarning: (message: string, extra?: unknown) => boolean;
6
6
  export declare const showWarningToast: (message: string, extra?: unknown) => boolean;
7
+ export declare const notifyPluginWarning: (message: string, extra?: unknown) => void;
7
8
  export declare const notifyGraphitiAvailabilityIssue: (message: string, extra?: unknown) => void;
8
9
  //# sourceMappingURL=opencode-warning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opencode-warning.d.ts","sourceRoot":"","sources":["../../../src/src/services/opencode-warning.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,wCAAwC,QAAO,OAM3D,CAAC;AA6FF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,OAAO,KACd,IAEF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,KACtD,IAIF,CAAC;AAEF,eAAO,MAAM,6CAA6C,GACxD,OAAO,OAAO,GAAG,SAAS,KACzB,IAEF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,OAEF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,KAAG,OAEnE,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAMF,CAAC"}
1
+ {"version":3,"file":"opencode-warning.d.ts","sourceRoot":"","sources":["../../../src/src/services/opencode-warning.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,wCAAwC,QAAO,OAM3D,CAAC;AA6FF,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,OAAO,KACd,IAEF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,KACtD,IAIF,CAAC;AAEF,eAAO,MAAM,6CAA6C,GACxD,OAAO,OAAO,GAAG,SAAS,KACzB,IAEF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,OAEF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,KAAG,OAEnE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAMF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,IAEF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.notifyGraphitiAvailabilityIssue = exports.showWarningToast = exports.logStructuredWarning = exports.setSuppressConsoleWarningsDuringTestsOverride = exports.setWarningTaskScheduler = exports.setOpenCodeClient = exports.shouldSuppressConsoleWarningsDuringTests = void 0;
3
+ exports.notifyGraphitiAvailabilityIssue = exports.notifyPluginWarning = exports.showWarningToast = exports.logStructuredWarning = exports.setSuppressConsoleWarningsDuringTestsOverride = exports.setWarningTaskScheduler = exports.setOpenCodeClient = exports.shouldSuppressConsoleWarningsDuringTests = void 0;
4
4
  const console = globalThis.console;
5
5
  const PREFIX = "[graphiti]";
6
6
  let openCodeClient;
@@ -104,11 +104,15 @@ const showWarningToast = (message, extra) => {
104
104
  return scheduleWarningToast(message, extra);
105
105
  };
106
106
  exports.showWarningToast = showWarningToast;
107
- const notifyGraphitiAvailabilityIssue = (message, extra) => {
107
+ const notifyPluginWarning = (message, extra) => {
108
108
  const logged = scheduleStructuredWarning(message, extra);
109
109
  const toasted = scheduleWarningToast(message, extra);
110
110
  if (!logged && !toasted) {
111
111
  warnToConsole(message, extra);
112
112
  }
113
113
  };
114
+ exports.notifyPluginWarning = notifyPluginWarning;
115
+ const notifyGraphitiAvailabilityIssue = (message, extra) => {
116
+ (0, exports.notifyPluginWarning)(message, extra);
117
+ };
114
118
  exports.notifyGraphitiAvailabilityIssue = notifyGraphitiAvailabilityIssue;