neotoma 0.9.1 → 0.10.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Your agents forget. Neotoma makes them remember.
4
4
 
5
- Versioned records — contacts, tasks, decisions, finances — that persist across Claude, Cursor, ChatGPT, OpenClaw, and every agent you run. Open-source. Local-first. Deterministic. MIT licensed.
5
+ Versioned records — contacts, tasks, decisions, finances — that persist across Claude, Cursor, ChatGPT, OpenClaw, IronClaw, and every agent you run. Open-source. Local-first. Deterministic. MIT licensed.
6
6
 
7
7
  **[neotoma.io](https://neotoma.io)** · **[Evaluate](https://neotoma.io/evaluate)** · **[Install](https://neotoma.io/install)** · **[Documentation](https://neotoma.io/docs)**
8
8
 
@@ -38,6 +38,7 @@ graph LR
38
38
  MCP --> ChatGPT
39
39
  MCP --> Cursor
40
40
  MCP --> OpenClaw
41
+ MCP --> IronClaw
41
42
  ```
42
43
 
43
44
  - **Deterministic.** Same observations always produce the same versioned entity snapshots. No ordering sensitivity.
@@ -51,7 +52,7 @@ graph LR
51
52
  | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
52
53
  | **Privacy-first** | Your data stays local. Never used for training. User-controlled storage, optional encryption at rest. Full export and deletion control. |
53
54
  | **Deterministic** | Same input always produces same output. Schema-first extraction, hash-based entity IDs, full provenance. No silent mutation. |
54
- | **Cross-platform** | One memory graph across Claude, ChatGPT, Cursor, OpenClaw, Codex, and CLI. MCP-based access. No platform lock-in. Works alongside native memory. |
55
+ | **Cross-platform** | One memory graph across Claude, ChatGPT, Cursor, OpenClaw, IronClaw, Codex, and CLI. MCP-based access. No platform lock-in. Works alongside native memory. |
55
56
 
56
57
  ## State guarantees
57
58
 
@@ -121,14 +122,14 @@ Three interfaces. One state invariant. Every interface provides the same determi
121
122
  | Interface | Description |
122
123
  | -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
123
124
  | **REST API** | Full HTTP interface for application integration. Entities, relationships, observations, schema, timeline, and version history. |
124
- | **MCP Server** | Model Context Protocol for Claude, ChatGPT, Cursor, OpenClaw, Codex, and more. Agents store and retrieve state through structured tool calls. |
125
+ | **MCP Server** | Model Context Protocol for Claude, ChatGPT, Cursor, OpenClaw, IronClaw, Codex, and more. Agents store and retrieve state through structured tool calls. |
125
126
  | **CLI** | Command-line for scripting and direct access. Inspect entities, replay timelines, and manage state from the terminal. |
126
127
 
127
128
  All three map to the same OpenAPI-backed operations. MCP tool calls log the equivalent CLI invocation.
128
129
 
129
130
  ## Who this is for
130
131
 
131
- People building a personal operating system with AI agents across their life — wiring together tools like Claude, Cursor, ChatGPT, OpenClaw, and custom scripts to manage contacts, tasks, finances, code, content, and other domains. The same person operates their agents, builds new pipelines, and debugs state drift. These are three operational modes, not separate personas:
132
+ People building a personal operating system with AI agents across their life — wiring together tools like Claude, Cursor, ChatGPT, OpenClaw, IronClaw, and custom scripts to manage contacts, tasks, finances, code, content, and other domains. The same person operates their agents, builds new pipelines, and debugs state drift. These are three operational modes, not separate personas:
132
133
 
133
134
  | Mode | What you're doing | The tax you pay without Neotoma | What you get back |
134
135
  | ---- | ----------------- | ------------------------------- | ----------------- |
@@ -155,7 +156,7 @@ Schema is flexible — store any entity type with whatever fields the message im
155
156
 
156
157
  ## Current status
157
158
 
158
- **Version:** v0.4.2 · **Releases:** 13 · **License:** MIT
159
+ **Version:** v0.9.1 · **Releases:** 26 · **License:** MIT
159
160
 
160
161
  ### What is guaranteed (even in preview)
161
162
 
@@ -217,7 +218,7 @@ npm test
217
218
 
218
219
  Neotoma exposes state via MCP. Local storage only in preview. Local built-in auth.
219
220
 
220
- **Setup guides:** [Cursor](https://neotoma.io/neotoma-with-cursor) · [Claude Code](https://neotoma.io/neotoma-with-claude-code) · [Claude](https://neotoma.io/neotoma-with-claude) · [ChatGPT](https://neotoma.io/neotoma-with-chatgpt) · [Codex](https://neotoma.io/neotoma-with-codex) · [OpenClaw](https://neotoma.io/neotoma-with-openclaw)
221
+ **Setup guides:** [Cursor](https://neotoma.io/neotoma-with-cursor) · [Claude Code](https://neotoma.io/neotoma-with-claude-code) · [Claude](https://neotoma.io/neotoma-with-claude) · [ChatGPT](https://neotoma.io/neotoma-with-chatgpt) · [Codex](https://neotoma.io/neotoma-with-codex) · [OpenCode](docs/integrations/hooks/opencode.md) · [OpenClaw](https://neotoma.io/neotoma-with-openclaw) · [IronClaw](https://neotoma.io/neotoma-with-ironclaw)
221
222
 
222
223
  For local source iteration, use the stable dev shim (`scripts/run_neotoma_mcp_stdio_dev_shim.sh` or `npm run dev:mcp:dev-shim`) instead of pointing installed MCP clients at a `tsx watch` stdio process. The shim keeps the client-facing JSON-RPC stream stable and asks clients to refresh or reconnect when the tool interface changes.
223
224
 
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAmK9B,eAAO,MAAM,GAAG,6CAAY,CAAC;AAif7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAU5D;AA4PD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAmBhD;AAyrHD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,4BAA4B,EAAE,iBAAiB,CAAC;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;;;;;;;;;;;;;cA+fS,MAAM;gBACJ,MAAM;2BACK,MAAM;qBACZ,MAAM;mBACR,MAAM;wBACD,MAAM;uBACP,MAAM;;;;;;;;;mBA3JV,MAAM;qBACJ,MAAM;wBACH,MAAM,GAAG,IAAI;2BACV,MAAM;;wBAET,MAAM;uBACP,MAAM,EAAE;wBACP,MAAM;uBACP,MAAM;;kBA9NX,MAAM;oBACJ,MAAM;yBACD,MAAM;4BACH,MAAM;2BACP,MAAM;;+BA4NF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;;;2BAkFlC,MAAM;0BACP,MAAM;0BACN,MAAM;;GA2F3B;AAuhED,wBAAsB,eAAe;;;eA2FpC"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAmK9B,eAAO,MAAM,GAAG,6CAAY,CAAC;AAif7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAU5D;AA4PD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAmBhD;AA4sHD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,4BAA4B,EAAE,iBAAiB,CAAC;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;;;;;;;;;;;;;cA+fS,MAAM;gBACJ,MAAM;2BACK,MAAM;qBACZ,MAAM;mBACR,MAAM;wBACD,MAAM;uBACP,MAAM;;;;;;;;;mBA3JV,MAAM;qBACJ,MAAM;wBACH,MAAM,GAAG,IAAI;2BACV,MAAM;;wBAET,MAAM;uBACP,MAAM,EAAE;wBACP,MAAM;uBACP,MAAM;;kBA9NX,MAAM;oBACJ,MAAM;yBACD,MAAM;4BACH,MAAM;2BACP,MAAM;;+BA4NF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;;;2BAkFlC,MAAM;0BACP,MAAM;0BACN,MAAM;;GA2F3B;AAuhED,wBAAsB,eAAe;;;eA2FpC"}
package/dist/actions.js CHANGED
@@ -1689,21 +1689,38 @@ app.post("/mcp/oauth/token", oauthTokenLimit, express.urlencoded({ extended: tru
1689
1689
  try {
1690
1690
  const grant_type = req.body?.grant_type;
1691
1691
  const code = req.body?.code;
1692
+ const refresh_token = req.body?.refresh_token;
1692
1693
  logger.info("[MCP OAuth] Token request received", {
1693
1694
  grant_type: grant_type ?? null,
1694
1695
  has_code: typeof code === "string" && code.length > 0,
1695
1696
  code_hint: typeof code === "string" ? code.slice(0, 8) : null,
1697
+ has_refresh_token: typeof refresh_token === "string" && refresh_token.length > 0,
1696
1698
  host: req.header("host") ?? null,
1697
1699
  });
1698
- if (grant_type !== "authorization_code") {
1700
+ if (grant_type !== "authorization_code" && grant_type !== "refresh_token") {
1699
1701
  logger.warn("[MCP OAuth] Token rejected: unsupported grant_type", {
1700
1702
  grant_type: grant_type ?? null,
1701
1703
  });
1702
1704
  return res.status(400).json({
1703
1705
  error: "unsupported_grant_type",
1704
- error_description: "Only authorization_code is supported",
1706
+ error_description: "Only authorization_code and refresh_token are supported",
1705
1707
  });
1706
1708
  }
1709
+ if (grant_type === "refresh_token") {
1710
+ if (!refresh_token || typeof refresh_token !== "string") {
1711
+ logger.warn("[MCP OAuth] Token refresh rejected: missing refresh_token");
1712
+ return res
1713
+ .status(400)
1714
+ .json({ error: "invalid_request", error_description: "refresh_token is required" });
1715
+ }
1716
+ const { refreshAccessToken } = await import("./services/mcp_oauth.js");
1717
+ const token = await refreshAccessToken(refresh_token);
1718
+ logger.info("[MCP OAuth] Token refreshed", {
1719
+ has_refresh_token: Boolean(token.refresh_token),
1720
+ });
1721
+ res.setHeader("Content-Type", "application/json");
1722
+ return res.json(token);
1723
+ }
1707
1724
  if (!code || typeof code !== "string") {
1708
1725
  logger.warn("[MCP OAuth] Token rejected: missing code");
1709
1726
  return res