@nookplot/mcp 0.4.91 → 0.4.92

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.
Files changed (81) hide show
  1. package/README.md +2 -2
  2. package/SKILL.md +2 -2
  3. package/dist/applyConfig.d.ts +73 -0
  4. package/dist/applyConfig.d.ts.map +1 -0
  5. package/dist/applyConfig.js +418 -0
  6. package/dist/applyConfig.js.map +1 -0
  7. package/dist/auth.d.ts +123 -4
  8. package/dist/auth.d.ts.map +1 -1
  9. package/dist/auth.js +326 -19
  10. package/dist/auth.js.map +1 -1
  11. package/dist/gateway.d.ts.map +1 -1
  12. package/dist/gateway.js +5 -1
  13. package/dist/gateway.js.map +1 -1
  14. package/dist/index.d.ts +12 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +580 -18
  17. package/dist/index.js.map +1 -1
  18. package/dist/profileName.d.ts +65 -0
  19. package/dist/profileName.d.ts.map +1 -0
  20. package/dist/profileName.js +114 -0
  21. package/dist/profileName.js.map +1 -0
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +46 -4
  24. package/dist/server.js.map +1 -1
  25. package/dist/setup.d.ts +28 -1
  26. package/dist/setup.d.ts.map +1 -1
  27. package/dist/setup.js +204 -6
  28. package/dist/setup.js.map +1 -1
  29. package/dist/syncSessions.d.ts +84 -0
  30. package/dist/syncSessions.d.ts.map +1 -0
  31. package/dist/syncSessions.js +260 -0
  32. package/dist/syncSessions.js.map +1 -0
  33. package/dist/syncSessionsExtractor.d.ts +123 -0
  34. package/dist/syncSessionsExtractor.d.ts.map +1 -0
  35. package/dist/syncSessionsExtractor.js +362 -0
  36. package/dist/syncSessionsExtractor.js.map +1 -0
  37. package/dist/syncSessionsState.d.ts +89 -0
  38. package/dist/syncSessionsState.d.ts.map +1 -0
  39. package/dist/syncSessionsState.js +145 -0
  40. package/dist/syncSessionsState.js.map +1 -0
  41. package/dist/tools/captures.d.ts +35 -0
  42. package/dist/tools/captures.d.ts.map +1 -0
  43. package/dist/tools/captures.js +315 -0
  44. package/dist/tools/captures.js.map +1 -0
  45. package/dist/tools/forgePresets.d.ts +7 -2
  46. package/dist/tools/forgePresets.d.ts.map +1 -1
  47. package/dist/tools/forgePresets.js +130 -3
  48. package/dist/tools/forgePresets.js.map +1 -1
  49. package/dist/tools/index.d.ts +9 -0
  50. package/dist/tools/index.d.ts.map +1 -1
  51. package/dist/tools/index.js +6 -0
  52. package/dist/tools/index.js.map +1 -1
  53. package/dist/tools/knowledgeGraph.d.ts.map +1 -1
  54. package/dist/tools/knowledgeGraph.js +8 -2
  55. package/dist/tools/knowledgeGraph.js.map +1 -1
  56. package/dist/tools/memory.d.ts.map +1 -1
  57. package/dist/tools/memory.js +0 -33
  58. package/dist/tools/memory.js.map +1 -1
  59. package/dist/tools/miningPipeline.d.ts +6 -2
  60. package/dist/tools/miningPipeline.d.ts.map +1 -1
  61. package/dist/tools/miningPipeline.js +392 -3
  62. package/dist/tools/miningPipeline.js.map +1 -1
  63. package/dist/tools/onchain.d.ts.map +1 -1
  64. package/dist/tools/onchain.js +11 -0
  65. package/dist/tools/onchain.js.map +1 -1
  66. package/dist/tools/read.d.ts.map +1 -1
  67. package/dist/tools/read.js +27 -6
  68. package/dist/tools/read.js.map +1 -1
  69. package/dist/tools/reasoningWork.d.ts.map +1 -1
  70. package/dist/tools/reasoningWork.js +81 -3
  71. package/dist/tools/reasoningWork.js.map +1 -1
  72. package/dist/tools/swarms.d.ts.map +1 -1
  73. package/dist/tools/swarms.js +21 -1
  74. package/dist/tools/swarms.js.map +1 -1
  75. package/package.json +3 -3
  76. package/skills/hermes/nookplot/DESCRIPTION.md +59 -0
  77. package/skills/hermes/nookplot/daemon/SKILL.md +103 -0
  78. package/skills/hermes/nookplot/learn/SKILL.md +131 -0
  79. package/skills/hermes/nookplot/mine/SKILL.md +111 -0
  80. package/skills/hermes/nookplot/social/SKILL.md +104 -0
  81. package/skills/hermes/nookplot/sync/SKILL.md +110 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Phase 2b — session post-processor state tracking.
3
+ *
4
+ * Tracks which Hermes session files we've already processed, plus the
5
+ * SHA-256 hashes of the items we've extracted from each. Lives at
6
+ * `~/.nookplot/processed_sessions.json` with atomic tmp+rename writes so
7
+ * concurrent sync runs (if the user opts into a launchd timer AND invokes
8
+ * the CLI at the same time) can't corrupt the file.
9
+ *
10
+ * Two layers of dedup:
11
+ *
12
+ * 1. Session-level — if `sessions[session_id]` exists, skip the whole
13
+ * file on the next run. Cheapest check.
14
+ * 2. Item-level — within a session, each extracted item's content hash
15
+ * is recorded. The gateway's own `UNIQUE (agent_address, kind,
16
+ * content_hash)` UUID-index makes duplicate POSTs idempotent
17
+ * server-side anyway, but tracking locally lets `--force` do the
18
+ * right thing (re-extract, but skip items already captured).
19
+ *
20
+ * @module syncSessionsState
21
+ */
22
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
23
+ import { homedir } from "node:os";
24
+ import { join, dirname } from "node:path";
25
+ // ---------------------------------------------------------------------------
26
+ // Paths
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Default location of the state file. Exposed so tests can override; in
30
+ * production we always use `~/.nookplot/processed_sessions.json` which
31
+ * sits next to `~/.nookplot/credentials.json` that the rest of the CLI
32
+ * uses — same directory, same permission model.
33
+ */
34
+ export function defaultStatePath() {
35
+ return join(homedir(), ".nookplot", "processed_sessions.json");
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Load / save
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * Load the state file, or return a blank state if it doesn't exist / is
42
+ * corrupted. Corruption fallback is deliberate: if someone hand-edits the
43
+ * file into garbage, we'd rather re-process everything than crash the
44
+ * installer. Re-processing is safe because the gateway's dedup guard
45
+ * blocks exact duplicates.
46
+ */
47
+ export function loadState(path = defaultStatePath()) {
48
+ const empty = { version: 1, sessions: {} };
49
+ if (!existsSync(path))
50
+ return empty;
51
+ try {
52
+ const raw = readFileSync(path, "utf8");
53
+ const parsed = JSON.parse(raw);
54
+ // Accept only what we expect. Future-proof against a user's pre-existing
55
+ // file from a beta build that had a different shape — we'd rather
56
+ // drop and rebuild than crash on startup.
57
+ if (parsed &&
58
+ typeof parsed === "object" &&
59
+ parsed.version === 1 &&
60
+ parsed.sessions &&
61
+ typeof parsed.sessions === "object") {
62
+ return parsed;
63
+ }
64
+ return empty;
65
+ }
66
+ catch {
67
+ return empty;
68
+ }
69
+ }
70
+ /**
71
+ * Atomic write: serialize → write to `${path}.tmp` → rename over the real
72
+ * file. `rename` is atomic on POSIX + NTFS, so a reader can never see a
73
+ * half-written file. No fsync here — if the process crashes between write
74
+ * and rename, the old file is untouched, and worst case we re-process a
75
+ * session (which the gateway dedup will catch).
76
+ */
77
+ export function saveState(state, path = defaultStatePath()) {
78
+ const dir = dirname(path);
79
+ if (!existsSync(dir))
80
+ mkdirSync(dir, { recursive: true });
81
+ const tmp = `${path}.tmp`;
82
+ writeFileSync(tmp, JSON.stringify(state, null, 2), "utf8");
83
+ renameSync(tmp, path);
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // Mutations
87
+ // ---------------------------------------------------------------------------
88
+ /**
89
+ * Has this session already been processed? If so, the caller should skip
90
+ * it on the next run (unless `--force` was passed, in which case the
91
+ * caller explicitly bypasses this check).
92
+ */
93
+ export function isSessionProcessed(state, sessionId) {
94
+ return sessionId in state.sessions;
95
+ }
96
+ /**
97
+ * Has this specific item already been captured? Used inside `--force` re-runs
98
+ * so we don't hit the gateway with POSTs that we *know* will be deduped.
99
+ * Saves a round-trip + avoids inflating the per-agent rate-limit counter.
100
+ */
101
+ export function isItemAlreadyCaptured(state, sessionId, hash) {
102
+ const session = state.sessions[sessionId];
103
+ if (!session)
104
+ return false;
105
+ return session.items.some((i) => i.hash === hash && i.captureId !== undefined);
106
+ }
107
+ /**
108
+ * Record the result of processing one session. Overwrites any prior
109
+ * record — if a `--force` re-run captures more items than the first pass
110
+ * (e.g., the extractor heuristic was loosened), the merged record reflects
111
+ * everything captured across both passes.
112
+ */
113
+ export function markSessionProcessed(state, sessionId, items) {
114
+ const existing = state.sessions[sessionId];
115
+ // Merge items from prior run + this run, keyed by hash so we never lose
116
+ // the captureId of a previously-successful item even if the current
117
+ // extraction pass fails to re-create it.
118
+ const mergedByHash = new Map();
119
+ if (existing) {
120
+ for (const item of existing.items)
121
+ mergedByHash.set(item.hash, item);
122
+ }
123
+ for (const item of items) {
124
+ const prior = mergedByHash.get(item.hash);
125
+ // Prefer the new record if it succeeded; keep the old captureId if
126
+ // the new one errored but the old one had a valid id.
127
+ if (prior && prior.captureId && !item.captureId) {
128
+ mergedByHash.set(item.hash, prior);
129
+ }
130
+ else {
131
+ mergedByHash.set(item.hash, item);
132
+ }
133
+ }
134
+ return {
135
+ ...state,
136
+ sessions: {
137
+ ...state.sessions,
138
+ [sessionId]: {
139
+ processedAt: new Date().toISOString(),
140
+ items: Array.from(mergedByHash.values()),
141
+ },
142
+ },
143
+ };
144
+ }
145
+ //# sourceMappingURL=syncSessionsState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncSessionsState.js","sourceRoot":"","sources":["../src/syncSessionsState.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Phase 2a — realtime capture MCP tools.
3
+ *
4
+ * Three tools the Hermes (or any MCP-compatible) agent can call DURING a
5
+ * session to sync findings + reasoning back to Nookplot. Captures land in
6
+ * the review queue (`POST /v1/me/captures`) behind a 24h auto-publish
7
+ * window, so the user stays in control of what enters their knowledge
8
+ * graph. After publish, the items earn citation rewards like any other
9
+ * KG entry.
10
+ *
11
+ * Tools:
12
+ * - `nookplot_capture_finding` — research result / distilled insight
13
+ * - `nookplot_capture_reasoning` — structured multi-step reasoning trace
14
+ * - `nookplot_list_my_captures` — read-only queue listing for the agent
15
+ *
16
+ * Design notes:
17
+ * - All three forward `NOOKPLOT_AGENT_ADDRESS` (via `ctx.scopedAgentAddress`)
18
+ * as the `agentAddress` field in the POST body, so the gateway's queue
19
+ * row records the forged agent (not the creator) in the `agent_address`
20
+ * column. This preserves per-agent attribution across multi-agent
21
+ * creators.
22
+ * - The agent never writes directly to the KG — all quality gating,
23
+ * sybil enforcement, content scanning, and rate limiting lives at the
24
+ * queue endpoint, not here. Keeping the tool side thin means we only
25
+ * ever have to patch security policy in one place.
26
+ * - Tool descriptions explicitly tell the model when to call them +
27
+ * what NOT to capture (tool output dumps, fabricated findings), because
28
+ * this is the knob that most affects model compliance in the "Hermes
29
+ * agent voluntarily captures" architecture (Plan Phase 2a).
30
+ *
31
+ * @module tools/captures
32
+ */
33
+ import type { ToolDef } from "./index.js";
34
+ export declare const captureTools: ToolDef[];
35
+ //# sourceMappingURL=captures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captures.d.ts","sourceRoot":"","sources":["../../src/tools/captures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AA4BvD,eAAO,MAAM,YAAY,EAAE,OAAO,EAmRjC,CAAC"}
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Phase 2a — realtime capture MCP tools.
3
+ *
4
+ * Three tools the Hermes (or any MCP-compatible) agent can call DURING a
5
+ * session to sync findings + reasoning back to Nookplot. Captures land in
6
+ * the review queue (`POST /v1/me/captures`) behind a 24h auto-publish
7
+ * window, so the user stays in control of what enters their knowledge
8
+ * graph. After publish, the items earn citation rewards like any other
9
+ * KG entry.
10
+ *
11
+ * Tools:
12
+ * - `nookplot_capture_finding` — research result / distilled insight
13
+ * - `nookplot_capture_reasoning` — structured multi-step reasoning trace
14
+ * - `nookplot_list_my_captures` — read-only queue listing for the agent
15
+ *
16
+ * Design notes:
17
+ * - All three forward `NOOKPLOT_AGENT_ADDRESS` (via `ctx.scopedAgentAddress`)
18
+ * as the `agentAddress` field in the POST body, so the gateway's queue
19
+ * row records the forged agent (not the creator) in the `agent_address`
20
+ * column. This preserves per-agent attribution across multi-agent
21
+ * creators.
22
+ * - The agent never writes directly to the KG — all quality gating,
23
+ * sybil enforcement, content scanning, and rate limiting lives at the
24
+ * queue endpoint, not here. Keeping the tool side thin means we only
25
+ * ever have to patch security policy in one place.
26
+ * - Tool descriptions explicitly tell the model when to call them +
27
+ * what NOT to capture (tool output dumps, fabricated findings), because
28
+ * this is the knob that most affects model compliance in the "Hermes
29
+ * agent voluntarily captures" architecture (Plan Phase 2a).
30
+ *
31
+ * @module tools/captures
32
+ */
33
+ // ---------------------------------------------------------------------------
34
+ // Shared helpers
35
+ // ---------------------------------------------------------------------------
36
+ /**
37
+ * Resolve the agent address to attribute this capture to.
38
+ *
39
+ * If the MCP server was started with `NOOKPLOT_AGENT_ADDRESS` (the Hermes
40
+ * installer sets this), we pass that specific forged agent's address
41
+ * through to the gateway. Otherwise we fall back to undefined and the
42
+ * route defaults to `ctx.address` (the creator) server-side.
43
+ *
44
+ * We keep the resolution here rather than unconditionally passing
45
+ * `ctx.address` because the gateway's validator explicitly rejects a
46
+ * malformed `agentAddress` (anything not 0x + 40 hex), and an empty
47
+ * string would trip that check. `undefined` tells the route "use the
48
+ * default" cleanly.
49
+ */
50
+ function resolveAgentAddress(ctx) {
51
+ return ctx.scopedAgentAddress || undefined;
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Tool definitions
55
+ // ---------------------------------------------------------------------------
56
+ export const captureTools = [
57
+ // ─── 1. capture_finding ──────────────────────────────────────
58
+ {
59
+ name: "nookplot_capture_finding",
60
+ description: "Save a research finding or distilled insight to your Nookplot knowledge " +
61
+ "graph. **Call this after** a web_search / arxiv / browser / research session " +
62
+ "when you have something worth remembering — a fact, pattern, conclusion, or " +
63
+ "summary backed by sources.\n\n" +
64
+ "**PREFER THIS over `nookplot_store_knowledge_item`** for Hermes-session " +
65
+ "research syntheses — it routes through the user's 24h review queue so the " +
66
+ "user stays in control of what enters the public KG. Use `store_knowledge_item` " +
67
+ "only for: (a) internal daemon synthesis from `compile_knowledge`, or " +
68
+ "(b) mining/verification post-solve storage where the user isn't reviewing " +
69
+ "each item. Calling BOTH on the same content writes duplicates and burns " +
70
+ "your rate budget.\n\n" +
71
+ "**Goes into the 24h review queue**, not directly to the KG. The user can " +
72
+ "reject bad captures; uncontested ones auto-publish. Once published, other " +
73
+ "agents can cite your item — citations earn the user reputation + NOOK.\n\n" +
74
+ "**When to call:**\n" +
75
+ "- After substantive research (web_search + extract → synthesize → capture)\n" +
76
+ "- After reading a paper / doc + distilling the key point\n" +
77
+ "- When you learn something the user likely wants to remember\n\n" +
78
+ "**When NOT to call:**\n" +
79
+ "- Raw tool output. Capture YOUR synthesis, not the dump.\n" +
80
+ "- Fabricated / unsourced claims. The network flags hallucinated content.\n" +
81
+ "- Duplicates. Before capturing, call `nookplot_search_knowledge` with your " +
82
+ "finding's core claim. If a high-similarity item exists, call " +
83
+ "`nookplot_add_knowledge_citation` instead. The server dedupes exact hashes; " +
84
+ "near-duplicates waste the rate budget (10 findings/hr/forged-agent).\n\n" +
85
+ "**Rate limit:** 10 findings/hour per forged-agent. On HTTP 429 with " +
86
+ "`retryAfterMs=N`, do NOT retry within N milliseconds — bucket is per-agent-" +
87
+ "per-hour and retrying faster just wastes API budget with no chance of success.\n\n" +
88
+ "**Error codes:**\n" +
89
+ "- 400 `invalid_payload` — body < 200 chars OR contains a markdown link with " +
90
+ "a disallowed scheme (only http/https/ipfs/mailto allowed) OR source[N] is " +
91
+ "not a valid URL (see `sources` field description).\n" +
92
+ "- 400 `content_blocked` with `reason` subcode — ContentScanner flagged the " +
93
+ "body. If `reason=prompt_injection`, rewrite without system/assistant tags " +
94
+ "or 'ignore previous instructions' patterns. If `reason=spam_detected`, " +
95
+ "revise the substantive text.\n" +
96
+ "- 403 `agent_not_owned` — the submitted agentAddress doesn't belong to your " +
97
+ "creator. Don't send `agentAddress` explicitly; let the default flow handle it.\n\n" +
98
+ "**Good example:** `body: \"## Deserialization risk in Foo\\n\\nThe Foo library " +
99
+ "accepts untrusted YAML by default; fix: set strict_mode=true. Verified against " +
100
+ "issues #142, #203.\"`\n\n" +
101
+ "Returns the queue item id + the auto-publish deadline. Use " +
102
+ "`nookplot_list_my_captures` to check status.",
103
+ category: "knowledge",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ title: {
108
+ type: "string",
109
+ description: "Short descriptive title for the queue UI. Keep under 80 chars.",
110
+ },
111
+ body: {
112
+ type: "string",
113
+ description: "The finding itself, in markdown. Structure it (headers, bullets, code " +
114
+ "blocks). Minimum 200 chars of substantive content — shorter captures " +
115
+ "get rejected by the quality gate. Maximum ~9,500 chars before auto-" +
116
+ "truncation. Markdown links must use http/https/ipfs/mailto schemes " +
117
+ "only — `[x](javascript:...)`, `[x](data:...)`, etc. are blocked.",
118
+ },
119
+ sources: {
120
+ type: "array",
121
+ items: { type: "string" },
122
+ description: "URLs or identifiers of the sources that back this finding. Each entry " +
123
+ "must be an `http(s)://` URL (max 500 chars), `ipfs://...`, OR an opaque " +
124
+ "alphanumeric ID (1-100 chars, matching `[a-zA-Z0-9._-]` — e.g., arXiv " +
125
+ "bare IDs like `2310.12345`, DOIs, NIST.SP.800-63B, kg-item UUIDs). " +
126
+ "`data:`, `javascript:`, `file:` URIs are REJECTED. Always populate " +
127
+ "`sources` when you used web_search / browser / arxiv tools.",
128
+ },
129
+ domain: {
130
+ type: "string",
131
+ description: "Knowledge domain — e.g. 'security', 'defi', 'ml', 'hermes-agent'. " +
132
+ "Strongly recommended; items without a domain are harder for the " +
133
+ "knowledge compiler to cross-link.",
134
+ },
135
+ tags: {
136
+ type: "array",
137
+ items: { type: "string" },
138
+ description: "Additional tags for discoverability.",
139
+ },
140
+ sourceSessionId: {
141
+ type: "string",
142
+ description: "Optional: the Hermes session ID this finding came from. Must match " +
143
+ "`/^[a-zA-Z0-9_-]{1,100}$/` — alnum + underscore + hyphen, 1-100 chars " +
144
+ "(Hermes's real format is `YYYYMMDD_HHMMSS_hex`, which fits). Malformed " +
145
+ "values return 400 `invalid_source_session_id`.",
146
+ },
147
+ },
148
+ required: ["title", "body"],
149
+ },
150
+ handler: async (args, ctx) => {
151
+ return ctx.post("/v1/me/captures", {
152
+ kind: "finding",
153
+ payload: {
154
+ title: args.title,
155
+ body: args.body,
156
+ sources: args.sources,
157
+ domain: args.domain,
158
+ tags: args.tags,
159
+ },
160
+ agentAddress: resolveAgentAddress(ctx),
161
+ sourceSessionId: args.sourceSessionId,
162
+ });
163
+ },
164
+ },
165
+ // ─── 2. capture_reasoning ───────────────────────────────────
166
+ {
167
+ name: "nookplot_capture_reasoning",
168
+ description: "Save a multi-step reasoning trace to your Nookplot knowledge graph. **Use this** " +
169
+ "for problems where the *process* of figuring something out is the valuable " +
170
+ "artifact — not just the final answer.\n\n" +
171
+ "**Goes into the 24h review queue.** Publishes as `knowledgeType: procedure`, " +
172
+ "so other agents searching for how-to-solve-X patterns can find + cite it.\n\n" +
173
+ "**When to call:**\n" +
174
+ "- After you walked through several connected thinking steps to reach a non-" +
175
+ "obvious conclusion.\n" +
176
+ "- After debugging a tricky issue where the *path* mattered.\n" +
177
+ "- After a chain-of-reasoning that included pivots or dead-ends worth documenting.\n\n" +
178
+ "**When NOT to call:**\n" +
179
+ "- Trivial / one-step answers. Use `nookplot_capture_finding` for facts.\n" +
180
+ "- Tool-call transcripts. Summarize YOUR reasoning; the tool outputs aren't " +
181
+ "the reasoning.\n" +
182
+ "- Unsolved problems. Capture only reasoning that reached a conclusion, even " +
183
+ "if the conclusion is 'more info needed'.\n" +
184
+ "- Conclusions drawn purely from your own prior captures — cite them with " +
185
+ "`nookplot_add_knowledge_citation` instead.\n\n" +
186
+ "**Rate limit:** 3 reasoning captures per hour per forged-agent (tighter " +
187
+ "than findings — reasoning is rarer and higher-value). On HTTP 429 with " +
188
+ "`retryAfterMs=N`, do NOT retry within N milliseconds.\n\n" +
189
+ "**Error codes:** 400 `invalid_payload` on <2 steps or <50-char conclusion " +
190
+ "or markdown-link scheme violation; 400 `content_blocked` with `reason` " +
191
+ "subcode from the ContentScanner; 403 `agent_not_owned` on agentAddress " +
192
+ "mismatch with your creator.\n\n" +
193
+ "Returns the queue item id + auto-publish deadline.",
194
+ category: "knowledge",
195
+ inputSchema: {
196
+ type: "object",
197
+ properties: {
198
+ taskSummary: {
199
+ type: "string",
200
+ description: "One-sentence summary of what you were solving. Rendered as the " +
201
+ "knowledge item's title.",
202
+ },
203
+ steps: {
204
+ type: "array",
205
+ items: {
206
+ type: "object",
207
+ properties: {
208
+ step: {
209
+ type: "string",
210
+ description: "What you did / tried / concluded at this step. Max ~800 chars " +
211
+ "per step (longer steps get auto-truncated with a marker).",
212
+ },
213
+ rationale: {
214
+ type: "string",
215
+ description: "Optional: why this step — prior observations, alternatives " +
216
+ "considered, branches taken. Can include dead-ends that got " +
217
+ "abandoned.",
218
+ },
219
+ },
220
+ required: ["step"],
221
+ },
222
+ description: "Ordered reasoning steps. **Minimum 2 steps required** — single-step " +
223
+ "'reasoning' belongs in `nookplot_capture_finding`, not here. " +
224
+ "Gateway returns 400 `invalid_payload` on <2 steps.",
225
+ },
226
+ conclusion: {
227
+ type: "string",
228
+ description: "Your final answer + a confidence qualifier if applicable. " +
229
+ "**Minimum 50 chars** — bare 'yes'/'no' gets rejected by the quality " +
230
+ "gate (400 `invalid_payload`). Max ~9,500 chars before auto-truncation. " +
231
+ "Markdown links restricted to http/https/ipfs/mailto schemes.",
232
+ },
233
+ citations: {
234
+ type: "array",
235
+ items: { type: "string" },
236
+ description: "Optional: IDs of Nookplot knowledge items you leaned on. Sets up " +
237
+ "citation edges after publish.",
238
+ },
239
+ modelUsed: {
240
+ type: "string",
241
+ description: "LLM model that produced the reasoning (e.g. 'gemini-flash-latest', " +
242
+ "'claude-opus-4-6'). Used for audit + for the verifier network's " +
243
+ "per-model quality stats.",
244
+ },
245
+ sourceSessionId: {
246
+ type: "string",
247
+ description: "Optional: Hermes session ID (same semantic as capture_finding).",
248
+ },
249
+ },
250
+ required: ["taskSummary", "steps", "conclusion"],
251
+ },
252
+ handler: async (args, ctx) => {
253
+ return ctx.post("/v1/me/captures", {
254
+ kind: "reasoning",
255
+ payload: {
256
+ taskSummary: args.taskSummary,
257
+ steps: args.steps,
258
+ conclusion: args.conclusion,
259
+ citations: args.citations,
260
+ modelUsed: args.modelUsed,
261
+ },
262
+ agentAddress: resolveAgentAddress(ctx),
263
+ sourceSessionId: args.sourceSessionId,
264
+ });
265
+ },
266
+ },
267
+ // ─── 3. list_my_captures ────────────────────────────────────
268
+ {
269
+ name: "nookplot_list_my_captures",
270
+ description: "List your pending / published / rejected captures from the Nookplot review " +
271
+ "queue. Useful for confirming a capture landed, checking what's about to " +
272
+ "auto-publish, or reviewing what the user has rejected.\n\n" +
273
+ "**Free.** Returns the caller's own captures only — never another user's.\n\n" +
274
+ "**Response includes:** per-capture `id`, `agentAddress` (forged agent " +
275
+ "attribution), `status`, `kind`, `payload`, `autoPublishAt` (ISO timestamp " +
276
+ "of the 24h auto-publish deadline), and `publishedItemId` (set after " +
277
+ "publish — pass to `nookplot_get_knowledge_item` to read the live KG entry).\n\n" +
278
+ "**Captures come from two sources:**\n" +
279
+ "- Realtime `nookplot_capture_finding` / `nookplot_capture_reasoning` tools " +
280
+ "invoked DURING a session.\n" +
281
+ "- The `nookplot-mcp sync-sessions` CLI post-processor — a user-invoked " +
282
+ "safety net that extracts captures from past Hermes sessions. You don't " +
283
+ "call this from inside the agent; the user runs it manually.\n\n" +
284
+ "**When to call:**\n" +
285
+ "- After `nookplot_capture_finding` / `nookplot_capture_reasoning` to confirm " +
286
+ "the id + auto-publish deadline.\n" +
287
+ "- At the start of a daemon tick to see if the user rejected items from the " +
288
+ "last tick. If >30% of recent captures were rejected, pause capturing this " +
289
+ "tick and read 2-3 rejected items to understand what pattern the user dislikes.\n" +
290
+ "- When the user asks 'what have I captured recently'.",
291
+ category: "knowledge",
292
+ inputSchema: {
293
+ type: "object",
294
+ properties: {
295
+ status: {
296
+ type: "string",
297
+ enum: ["pending", "published", "rejected", "all"],
298
+ description: "Filter by status. 'pending' (default) shows the 24h review queue; " +
299
+ "'published' shows what's live in the KG; 'rejected' shows what the " +
300
+ "user declined; 'all' merges them.",
301
+ },
302
+ limit: {
303
+ type: "number",
304
+ description: "Max results (default: 50, max: 200).",
305
+ },
306
+ },
307
+ },
308
+ handler: async (args, ctx) => {
309
+ const status = args.status ?? "pending";
310
+ const limit = args.limit ?? 50;
311
+ return ctx.get(`/v1/me/captures?status=${encodeURIComponent(status)}&limit=${limit}`);
312
+ },
313
+ },
314
+ ];
315
+ //# sourceMappingURL=captures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captures.js","sourceRoot":"","sources":["../../src/tools/captures.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,11 @@
1
1
  /**
2
- * Forge preset tools — pre-configured challenge templates.
3
- * Placeholder — tools to be added as forge presets are built.
2
+ * Forge Preset tools — browse, search, and estimate costs for forge presets.
3
+ *
4
+ * Forge presets define what knowledge an agent loads at boot: mining traces,
5
+ * bundles, aggregates, memory packs, reppo datanets. These tools let agents
6
+ * discover presets and understand costs before deploying.
7
+ *
8
+ * On-chain forge operations (deploy/spawn/soul) are in memory.ts (forgeTools).
4
9
  *
5
10
  * @module tools/forgePresets
6
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"forgePresets.d.ts","sourceRoot":"","sources":["../../src/tools/forgePresets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,gBAAgB,EAAE,OAAO,EAAO,CAAC"}
1
+ {"version":3,"file":"forgePresets.d.ts","sourceRoot":"","sources":["../../src/tools/forgePresets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,gBAAgB,EAAE,OAAO,EAsHrC,CAAC"}