@gamaze/hicortex 0.19.0 → 0.19.1
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 +16 -2
- package/dist/index.d.ts +25 -1
- package/dist/index.js +108 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,7 +54,21 @@ openclaw plugins install @gamaze/hicortex
|
|
|
54
54
|
openclaw gateway restart
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
The plugin connects to `http://127.0.0.1:8787` by default. For a remote server, add `serverUrl` and `authToken` (find the token via `hicortex status` on the server) to the plugin config in `~/.openclaw/openclaw.json
|
|
57
|
+
The plugin connects to `http://127.0.0.1:8787` by default. For a remote server, add `serverUrl` and `authToken` (find the token via `hicortex status` on the server) to the plugin's config section in `~/.openclaw/openclaw.json`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"plugins": {
|
|
62
|
+
"entries": {
|
|
63
|
+
"hicortex": {
|
|
64
|
+
"config": { "serverUrl": "http://your-server:8787", "authToken": "hctx-…" }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Bare top-level keys (`"serverUrl": …` at the root of `openclaw.json`) still work — legacy compat — but the nested form above is canonical. An empty nested `config` object is ignored rather than shadowing top-level keys.
|
|
58
72
|
|
|
59
73
|
## Requirements
|
|
60
74
|
|
|
@@ -399,7 +413,7 @@ The nightly and the server behave differently on purpose: a malformed config mak
|
|
|
399
413
|
|
|
400
414
|
**Tools not visible to agent (OC):** The plugin auto-adds tools to `tools.allow` on startup. Restart the gateway after install.
|
|
401
415
|
|
|
402
|
-
**OC plugin: "Server unreachable":** The plugin requires a running Hicortex server. Run `npx @gamaze/hicortex init` on the same machine, or set `serverUrl` in the plugin config to point at a remote server.
|
|
416
|
+
**OC plugin: "Server unreachable":** The plugin requires a running Hicortex server. Run `npx @gamaze/hicortex init` on the same machine, or set `serverUrl` in the plugin config (`plugins.entries.hicortex.config` in `~/.openclaw/openclaw.json`; bare top-level keys also work) to point at a remote server.
|
|
403
417
|
|
|
404
418
|
**LLM auto-config failed:** Check logs for `[hicortex] WARNING`. Add `llmBaseUrl` to plugin config or set `HICORTEX_LLM_BASE_URL` env var (applies to server setup, not the OC plugin itself).
|
|
405
419
|
|
package/dist/index.d.ts
CHANGED
|
@@ -23,13 +23,37 @@
|
|
|
23
23
|
* machine's Hicortex nightly reads them via oc-transcript-reader.ts —
|
|
24
24
|
* canonical nightly-from-logs, same as CC JSONL and Hermes state.db.
|
|
25
25
|
*/
|
|
26
|
-
import type { MemorySearchResult } from "./types.js";
|
|
26
|
+
import type { HicortexConfig, MemorySearchResult } from "./types.js";
|
|
27
27
|
export declare function formatToolResults(results: MemorySearchResult[]): {
|
|
28
28
|
content: Array<{
|
|
29
29
|
type: string;
|
|
30
30
|
text: string;
|
|
31
31
|
}>;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the plugin's config from the raw `ctx.config` OC hands the service
|
|
35
|
+
* (the ENTIRE openclaw.json — verified against gateway-cli createServiceContext:
|
|
36
|
+
* config = params.cfg — not a per-plugin section). Stateless: touches no module
|
|
37
|
+
* state, never mutates the input, never throws (console.warn is its only side
|
|
38
|
+
* effect). Three branches, first match wins:
|
|
39
|
+
*
|
|
40
|
+
* 1. `plugins.entries.hicortex.config` — the canonical OC per-plugin
|
|
41
|
+
* section. Only eligible when it is a non-null object with ≥1 OWN key:
|
|
42
|
+
* OC scaffolds `config: {}` for an installed-but-unconfigured plugin,
|
|
43
|
+
* and that empty object must not shadow real config further down.
|
|
44
|
+
* 2. `hicortex` at the top level — but only when `typeof === "object"`:
|
|
45
|
+
* a string/bool/number there (e.g. `"hicortex": true` as a feature
|
|
46
|
+
* toggle) is not a config and is skipped, not cast.
|
|
47
|
+
* 3. the top level itself — bare keys (`serverUrl`, `authToken`, …) at the
|
|
48
|
+
* root of openclaw.json; the pre-0.19 shape, kept for backcompat.
|
|
49
|
+
*
|
|
50
|
+
* `serverUrl` and `authToken` are validated at this boundary: a present but
|
|
51
|
+
* non-string (or empty-string) value warns naming the key and degrades —
|
|
52
|
+
* serverUrl falls back to DEFAULT_SERVER_URL, authToken to undefined. No
|
|
53
|
+
* throw paths: a malformed config degrades to defaults instead of leaving
|
|
54
|
+
* the plugin half-initialized.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveOcPluginConfig(raw: unknown): HicortexConfig;
|
|
33
57
|
declare const _default: {
|
|
34
58
|
id: string;
|
|
35
59
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
28
|
exports.formatToolResults = formatToolResults;
|
|
29
|
+
exports.resolveOcPluginConfig = resolveOcPluginConfig;
|
|
29
30
|
const paths_js_1 = require("./paths.js");
|
|
30
31
|
const features_js_1 = require("./features.js");
|
|
31
32
|
const extensions_js_1 = require("./extensions.js");
|
|
@@ -256,6 +257,104 @@ function formatToolResults(results) {
|
|
|
256
257
|
return { content: [{ type: "text", text }] };
|
|
257
258
|
}
|
|
258
259
|
// ---------------------------------------------------------------------------
|
|
260
|
+
// Config resolution
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
/** Object (not null, not array) → itself as a record; anything else → undefined. */
|
|
263
|
+
function isRecord(v) {
|
|
264
|
+
return typeof v === "object" && v !== null && !Array.isArray(v)
|
|
265
|
+
? v
|
|
266
|
+
: undefined;
|
|
267
|
+
}
|
|
268
|
+
function isNonEmptyString(v) {
|
|
269
|
+
return typeof v === "string" && v.length > 0;
|
|
270
|
+
}
|
|
271
|
+
/** Human name for a config value that failed validation. Only ever called
|
|
272
|
+
* with INVALID values (non-strings and empty strings), so the string branch
|
|
273
|
+
* means "empty string". */
|
|
274
|
+
function describeInvalid(v) {
|
|
275
|
+
if (v === null)
|
|
276
|
+
return "null";
|
|
277
|
+
if (Array.isArray(v))
|
|
278
|
+
return "an array";
|
|
279
|
+
if (typeof v === "string")
|
|
280
|
+
return "an empty string";
|
|
281
|
+
return typeof v === "object" ? "an object" : `a ${typeof v}`;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Resolve the plugin's config from the raw `ctx.config` OC hands the service
|
|
285
|
+
* (the ENTIRE openclaw.json — verified against gateway-cli createServiceContext:
|
|
286
|
+
* config = params.cfg — not a per-plugin section). Stateless: touches no module
|
|
287
|
+
* state, never mutates the input, never throws (console.warn is its only side
|
|
288
|
+
* effect). Three branches, first match wins:
|
|
289
|
+
*
|
|
290
|
+
* 1. `plugins.entries.hicortex.config` — the canonical OC per-plugin
|
|
291
|
+
* section. Only eligible when it is a non-null object with ≥1 OWN key:
|
|
292
|
+
* OC scaffolds `config: {}` for an installed-but-unconfigured plugin,
|
|
293
|
+
* and that empty object must not shadow real config further down.
|
|
294
|
+
* 2. `hicortex` at the top level — but only when `typeof === "object"`:
|
|
295
|
+
* a string/bool/number there (e.g. `"hicortex": true` as a feature
|
|
296
|
+
* toggle) is not a config and is skipped, not cast.
|
|
297
|
+
* 3. the top level itself — bare keys (`serverUrl`, `authToken`, …) at the
|
|
298
|
+
* root of openclaw.json; the pre-0.19 shape, kept for backcompat.
|
|
299
|
+
*
|
|
300
|
+
* `serverUrl` and `authToken` are validated at this boundary: a present but
|
|
301
|
+
* non-string (or empty-string) value warns naming the key and degrades —
|
|
302
|
+
* serverUrl falls back to DEFAULT_SERVER_URL, authToken to undefined. No
|
|
303
|
+
* throw paths: a malformed config degrades to defaults instead of leaving
|
|
304
|
+
* the plugin half-initialized.
|
|
305
|
+
*/
|
|
306
|
+
function resolveOcPluginConfig(raw) {
|
|
307
|
+
const warn = (msg) => console.warn(`[hicortex] WARNING: ${msg}`);
|
|
308
|
+
const full = isRecord(raw) ?? {};
|
|
309
|
+
// Branch 1 — isRecord at every level: a missing key, string, array, or
|
|
310
|
+
// null anywhere in the chain just falls through to the next branch.
|
|
311
|
+
const plugins = isRecord(full.plugins);
|
|
312
|
+
const entries = isRecord(plugins?.entries);
|
|
313
|
+
const entry = isRecord(entries?.hicortex);
|
|
314
|
+
const entryConfig = isRecord(entry?.config);
|
|
315
|
+
const nested = entryConfig !== undefined && Object.keys(entryConfig).length > 0
|
|
316
|
+
? entryConfig
|
|
317
|
+
: undefined;
|
|
318
|
+
// Branch 2 — top-level `hicortex`, object-guarded (see doc block).
|
|
319
|
+
const hicortexObj = isRecord(full.hicortex);
|
|
320
|
+
const winner = nested ?? hicortexObj ?? full;
|
|
321
|
+
const winnerPath = nested !== undefined
|
|
322
|
+
? "plugins.entries.hicortex.config"
|
|
323
|
+
: hicortexObj !== undefined ? "hicortex" : "the top level of openclaw.json";
|
|
324
|
+
// Copy, never the caller's object: sanitizing below must not mutate
|
|
325
|
+
// ctx.config, and pluginConfig must not alias OC's config state.
|
|
326
|
+
const resolved = { ...winner };
|
|
327
|
+
const rawUrl = winner.serverUrl;
|
|
328
|
+
if (rawUrl !== undefined && !isNonEmptyString(rawUrl)) {
|
|
329
|
+
warn(`plugin config key "serverUrl" must be a non-empty string (got ${describeInvalid(rawUrl)}) ` +
|
|
330
|
+
`— falling back to ${DEFAULT_SERVER_URL}`);
|
|
331
|
+
resolved.serverUrl = DEFAULT_SERVER_URL;
|
|
332
|
+
}
|
|
333
|
+
const rawToken = winner.authToken;
|
|
334
|
+
if (rawToken !== undefined && !isNonEmptyString(rawToken)) {
|
|
335
|
+
warn(`plugin config key "authToken" must be a non-empty string (got ${describeInvalid(rawToken)}) — ignoring it`);
|
|
336
|
+
resolved.authToken = undefined;
|
|
337
|
+
}
|
|
338
|
+
// Shadow detection (F2) — two configs disagreeing, surfaced instead of
|
|
339
|
+
// silently honoring one of them. Case 1: an OC-scaffolded EMPTY
|
|
340
|
+
// plugins.entries.hicortex.config was skipped while a bare top-level
|
|
341
|
+
// serverUrl exists (the exact shape the ≥1-own-key rule exists for).
|
|
342
|
+
// Gate on the ACTUAL winner (re-CR F1): in the compound shape (empty
|
|
343
|
+
// nested config + a top-level hicortex object + bare serverUrl) the hicortex
|
|
344
|
+
// object wins — the warn must not claim the bare key is being used.
|
|
345
|
+
if (nested === undefined && entryConfig !== undefined && winner === full && isNonEmptyString(full.serverUrl)) {
|
|
346
|
+
warn(`plugins.entries.hicortex.config is empty, so the top-level serverUrl is used instead — ` +
|
|
347
|
+
`remove the empty config section or move serverUrl into it`);
|
|
348
|
+
}
|
|
349
|
+
// Case 2: a real nested/hicortex section won the chain but carries no valid
|
|
350
|
+
// serverUrl, while a bare top-level serverUrl is set and will NOT be read.
|
|
351
|
+
if (winner !== full && !isNonEmptyString(rawUrl) && isNonEmptyString(full.serverUrl)) {
|
|
352
|
+
warn(`top-level serverUrl is set but ${winnerPath} takes precedence and has no valid serverUrl — ` +
|
|
353
|
+
`the plugin will NOT use the top-level value; move serverUrl into ${winnerPath}`);
|
|
354
|
+
}
|
|
355
|
+
return resolved;
|
|
356
|
+
}
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
259
358
|
// Plugin export
|
|
260
359
|
// ---------------------------------------------------------------------------
|
|
261
360
|
exports.default = {
|
|
@@ -269,12 +368,19 @@ exports.default = {
|
|
|
269
368
|
api.registerService({
|
|
270
369
|
id: "hicortex-service",
|
|
271
370
|
async start(ctx) {
|
|
272
|
-
|
|
371
|
+
// OC passes the ENTIRE openclaw.json as ctx.config (verified against
|
|
372
|
+
// gateway-cli createServiceContext: config = params.cfg), not a
|
|
373
|
+
// per-plugin section. resolveOcPluginConfig picks our section out of
|
|
374
|
+
// it (branch order documented on the function) and validates the
|
|
375
|
+
// scalar keys at the boundary. It never throws, so a malformed config
|
|
376
|
+
// can only degrade (warn + default), never half-initialize the plugin.
|
|
377
|
+
const config = resolveOcPluginConfig(ctx.config);
|
|
273
378
|
pluginConfig = config;
|
|
274
379
|
const log = ctx.logger
|
|
275
380
|
? (msg) => ctx.logger.info(msg)
|
|
276
381
|
: console.log;
|
|
277
|
-
// Resolve server URL and auth token from plugin config
|
|
382
|
+
// Resolve server URL and auth token from plugin config (both already
|
|
383
|
+
// validated strings — or absent, hence the ?? default)
|
|
278
384
|
serverUrl = (config.serverUrl ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
|
|
279
385
|
authToken = config.authToken;
|
|
280
386
|
// Use stateDir from context so tests can redirect state writes
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "hicortex",
|
|
3
3
|
"name": "Hicortex — Long-term Memory That Learns",
|
|
4
4
|
"description": "Your agents remember past decisions, avoid repeated mistakes, and get smarter every day. Nightly reflection generates actionable lessons that automatically update agent behavior.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.19.1",
|
|
6
6
|
"kind": "lifecycle",
|
|
7
7
|
"skills": ["./skills/hicortex-memory"],
|
|
8
8
|
"configSchema": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Persistent agent identity for AI agents \u2014 a hand-edited identity layer, nightly-distilled experience, and lessons injected every session, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|