@nookplot/mcp 0.4.109 → 0.4.111
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 +293 -293
- package/SKILL.md +145 -145
- package/dist/auth.d.ts +5 -112
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +53 -294
- package/dist/auth.js.map +1 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +1 -5
- package/dist/gateway.js.map +1 -1
- package/dist/index.d.ts +1 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -613
- package/dist/index.js.map +1 -1
- package/dist/server.js +81 -81
- package/dist/setup.js +7 -7
- package/dist/tools/cognitiveWorkspace.d.ts.map +1 -1
- package/dist/tools/cognitiveWorkspace.js +0 -30
- package/dist/tools/cognitiveWorkspace.js.map +1 -1
- package/dist/tools/ecosystem.d.ts.map +1 -1
- package/dist/tools/ecosystem.js +5 -1
- package/dist/tools/ecosystem.js.map +1 -1
- package/dist/tools/forgePresets.d.ts +2 -7
- package/dist/tools/forgePresets.d.ts.map +1 -1
- package/dist/tools/forgePresets.js +3 -133
- package/dist/tools/forgePresets.js.map +1 -1
- package/dist/tools/knowledgeGraph.js +1 -1
- package/dist/tools/knowledgeGraph.js.map +1 -1
- package/dist/tools/memory.d.ts.map +1 -1
- package/dist/tools/memory.js +33 -0
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/miningPipeline.d.ts +2 -6
- package/dist/tools/miningPipeline.d.ts.map +1 -1
- package/dist/tools/miningPipeline.js +3 -392
- package/dist/tools/miningPipeline.js.map +1 -1
- package/dist/tools/onchain.js +2 -2
- package/dist/tools/onchain.js.map +1 -1
- package/dist/tools/papers.d.ts.map +1 -1
- package/dist/tools/papers.js +0 -16
- package/dist/tools/papers.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +6 -27
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/reasoningWork.js +60 -60
- package/dist/tools/swarms.d.ts.map +1 -1
- package/dist/tools/swarms.js +1 -21
- package/dist/tools/swarms.js.map +1 -1
- package/package.json +1 -1
- package/skills/learn/SKILL.md +70 -70
- package/skills/mine/SKILL.md +85 -85
- package/skills/nookplot/SKILL.md +222 -222
- package/skills/social/SKILL.md +84 -84
- package/dist/profileName.d.ts +0 -65
- package/dist/profileName.d.ts.map +0 -1
- package/dist/profileName.js +0 -114
- package/dist/profileName.js.map +0 -1
- package/dist/syncSessions.d.ts +0 -84
- package/dist/syncSessions.d.ts.map +0 -1
- package/dist/syncSessions.js +0 -260
- package/dist/syncSessions.js.map +0 -1
- package/dist/syncSessionsExtractor.d.ts +0 -123
- package/dist/syncSessionsExtractor.d.ts.map +0 -1
- package/dist/syncSessionsExtractor.js +0 -362
- package/dist/syncSessionsExtractor.js.map +0 -1
- package/dist/syncSessionsState.d.ts +0 -89
- package/dist/syncSessionsState.d.ts.map +0 -1
- package/dist/syncSessionsState.js +0 -145
- package/dist/syncSessionsState.js.map +0 -1
- package/skills/hermes/nookplot/DESCRIPTION.md +0 -59
- package/skills/hermes/nookplot/daemon/SKILL.md +0 -103
- package/skills/hermes/nookplot/learn/SKILL.md +0 -131
- package/skills/hermes/nookplot/mine/SKILL.md +0 -111
- package/skills/hermes/nookplot/social/SKILL.md +0 -104
- package/skills/hermes/nookplot/sync/SKILL.md +0 -110
package/dist/profileName.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profile-name derivation for Hermes's `hermes profile create <name>`.
|
|
3
|
-
*
|
|
4
|
-
* Every forged agent on Nookplot maps to its own Hermes profile — a fully
|
|
5
|
-
* isolated directory tree at `~/.hermes/profiles/<name>/` with its own
|
|
6
|
-
* config.yaml, .env, sessions, and (optionally) Telegram bot token. The
|
|
7
|
-
* profile name is the user-facing handle: they run `<name> chat` (via the
|
|
8
|
-
* alias wrapper at `~/.local/bin/<name>`), and it shows up in
|
|
9
|
-
* `hermes profile list`.
|
|
10
|
-
*
|
|
11
|
-
* Hermes's validation rule (from `hermes profile create --help`):
|
|
12
|
-
* "Profile name (lowercase, alphanumeric)"
|
|
13
|
-
*
|
|
14
|
-
* Empirically, it also accepts hyphens. The pattern we target is
|
|
15
|
-
* `/^[a-z][a-z0-9-]{0,30}[a-z0-9]$/` — 2..32 chars, letter-prefix,
|
|
16
|
-
* alnum-or-hyphen middle, alnum suffix.
|
|
17
|
-
*
|
|
18
|
-
* Input sources, in preference order:
|
|
19
|
-
* 1. `display_name` from `agents.display_name` (slugged)
|
|
20
|
-
* 2. `agent-<last6-hex>` fallback derived from the agent address
|
|
21
|
-
*
|
|
22
|
-
* Collision handling is the caller's job — we just produce the candidate
|
|
23
|
-
* from inputs. The bash installer does a `hermes profile show $NAME ||
|
|
24
|
-
* hermes profile create $NAME` pattern, so a name that already exists
|
|
25
|
-
* with a DIFFERENT agent is the user's problem (rare, and giving them a
|
|
26
|
-
* clear error beats silently shadowing).
|
|
27
|
-
*
|
|
28
|
-
* @module profileName
|
|
29
|
-
*/
|
|
30
|
-
/** Validate against Hermes's profile-name rule. Exported for tests. */
|
|
31
|
-
export declare function isValidProfileName(name: string): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Slugify a free-form string (display name, title, etc.) into a safe
|
|
34
|
-
* profile name. Rules:
|
|
35
|
-
* - lowercase
|
|
36
|
-
* - unicode → ASCII approximation (NFKD strips diacritics)
|
|
37
|
-
* - non-alnum runs become single hyphens
|
|
38
|
-
* - leading/trailing hyphens trimmed
|
|
39
|
-
* - leading digits replaced with "a-" so the name starts with a letter
|
|
40
|
-
* - length capped at MAX_PROFILE_NAME_LEN, trimmed at a hyphen if possible
|
|
41
|
-
*
|
|
42
|
-
* Returns empty string if the input has no usable alphanumeric chars
|
|
43
|
-
* (e.g. pure emoji). Callers should treat that as "fall back to the
|
|
44
|
-
* address-based default."
|
|
45
|
-
*/
|
|
46
|
-
export declare function slugifyDisplayName(input: string): string;
|
|
47
|
-
/**
|
|
48
|
-
* Fallback name from an agent's on-chain address: `agent-<last6-hex>`.
|
|
49
|
-
* Always valid (short, letter-prefix, alnum).
|
|
50
|
-
*/
|
|
51
|
-
export declare function profileNameFromAddress(address: string): string;
|
|
52
|
-
/**
|
|
53
|
-
* Top-level derivation: try display_name first, fall back to address.
|
|
54
|
-
*
|
|
55
|
-
* Takes optional collision-check hook — if provided, we'll try `<name>-2`,
|
|
56
|
-
* `<name>-3`, ... up to `-9` before giving up. That's enough headroom for
|
|
57
|
-
* normal users; power users who hit it can rename via `hermes profile
|
|
58
|
-
* rename` after the fact.
|
|
59
|
-
*/
|
|
60
|
-
export declare function deriveProfileName(opts: {
|
|
61
|
-
displayName?: string | null;
|
|
62
|
-
agentAddress: string;
|
|
63
|
-
isTaken?: (candidate: string) => boolean;
|
|
64
|
-
}): string;
|
|
65
|
-
//# sourceMappingURL=profileName.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"profileName.d.ts","sourceRoot":"","sources":["../src/profileName.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA2BxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE;IACJ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C,GACA,MAAM,CAmBR"}
|
package/dist/profileName.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profile-name derivation for Hermes's `hermes profile create <name>`.
|
|
3
|
-
*
|
|
4
|
-
* Every forged agent on Nookplot maps to its own Hermes profile — a fully
|
|
5
|
-
* isolated directory tree at `~/.hermes/profiles/<name>/` with its own
|
|
6
|
-
* config.yaml, .env, sessions, and (optionally) Telegram bot token. The
|
|
7
|
-
* profile name is the user-facing handle: they run `<name> chat` (via the
|
|
8
|
-
* alias wrapper at `~/.local/bin/<name>`), and it shows up in
|
|
9
|
-
* `hermes profile list`.
|
|
10
|
-
*
|
|
11
|
-
* Hermes's validation rule (from `hermes profile create --help`):
|
|
12
|
-
* "Profile name (lowercase, alphanumeric)"
|
|
13
|
-
*
|
|
14
|
-
* Empirically, it also accepts hyphens. The pattern we target is
|
|
15
|
-
* `/^[a-z][a-z0-9-]{0,30}[a-z0-9]$/` — 2..32 chars, letter-prefix,
|
|
16
|
-
* alnum-or-hyphen middle, alnum suffix.
|
|
17
|
-
*
|
|
18
|
-
* Input sources, in preference order:
|
|
19
|
-
* 1. `display_name` from `agents.display_name` (slugged)
|
|
20
|
-
* 2. `agent-<last6-hex>` fallback derived from the agent address
|
|
21
|
-
*
|
|
22
|
-
* Collision handling is the caller's job — we just produce the candidate
|
|
23
|
-
* from inputs. The bash installer does a `hermes profile show $NAME ||
|
|
24
|
-
* hermes profile create $NAME` pattern, so a name that already exists
|
|
25
|
-
* with a DIFFERENT agent is the user's problem (rare, and giving them a
|
|
26
|
-
* clear error beats silently shadowing).
|
|
27
|
-
*
|
|
28
|
-
* @module profileName
|
|
29
|
-
*/
|
|
30
|
-
const MAX_PROFILE_NAME_LEN = 32;
|
|
31
|
-
const MIN_PROFILE_NAME_LEN = 2;
|
|
32
|
-
/** Validate against Hermes's profile-name rule. Exported for tests. */
|
|
33
|
-
export function isValidProfileName(name) {
|
|
34
|
-
return /^[a-z][a-z0-9-]{0,30}[a-z0-9]$/.test(name);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Slugify a free-form string (display name, title, etc.) into a safe
|
|
38
|
-
* profile name. Rules:
|
|
39
|
-
* - lowercase
|
|
40
|
-
* - unicode → ASCII approximation (NFKD strips diacritics)
|
|
41
|
-
* - non-alnum runs become single hyphens
|
|
42
|
-
* - leading/trailing hyphens trimmed
|
|
43
|
-
* - leading digits replaced with "a-" so the name starts with a letter
|
|
44
|
-
* - length capped at MAX_PROFILE_NAME_LEN, trimmed at a hyphen if possible
|
|
45
|
-
*
|
|
46
|
-
* Returns empty string if the input has no usable alphanumeric chars
|
|
47
|
-
* (e.g. pure emoji). Callers should treat that as "fall back to the
|
|
48
|
-
* address-based default."
|
|
49
|
-
*/
|
|
50
|
-
export function slugifyDisplayName(input) {
|
|
51
|
-
if (typeof input !== "string" || input.length === 0)
|
|
52
|
-
return "";
|
|
53
|
-
let s = input
|
|
54
|
-
.normalize("NFKD")
|
|
55
|
-
.replace(/[\u0300-\u036f]/g, "") // strip combining accents
|
|
56
|
-
.toLowerCase()
|
|
57
|
-
.replace(/[^a-z0-9]+/g, "-") // non-alnum runs → hyphen
|
|
58
|
-
.replace(/^-+|-+$/g, ""); // trim leading/trailing hyphens
|
|
59
|
-
if (s.length === 0)
|
|
60
|
-
return "";
|
|
61
|
-
// Hermes requires a letter prefix.
|
|
62
|
-
if (/^[0-9]/.test(s))
|
|
63
|
-
s = "a-" + s;
|
|
64
|
-
// Cap length. If we have to cut, prefer cutting at a hyphen so we don't
|
|
65
|
-
// leave a mid-word stump.
|
|
66
|
-
if (s.length > MAX_PROFILE_NAME_LEN) {
|
|
67
|
-
const cut = s.slice(0, MAX_PROFILE_NAME_LEN);
|
|
68
|
-
const lastHyphen = cut.lastIndexOf("-");
|
|
69
|
-
s = lastHyphen > MIN_PROFILE_NAME_LEN ? cut.slice(0, lastHyphen) : cut;
|
|
70
|
-
}
|
|
71
|
-
// Trim trailing hyphen that could remain after length cut.
|
|
72
|
-
s = s.replace(/-+$/, "");
|
|
73
|
-
// After all of that, still must pass the Hermes rule. If not, give up.
|
|
74
|
-
return isValidProfileName(s) ? s : "";
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Fallback name from an agent's on-chain address: `agent-<last6-hex>`.
|
|
78
|
-
* Always valid (short, letter-prefix, alnum).
|
|
79
|
-
*/
|
|
80
|
-
export function profileNameFromAddress(address) {
|
|
81
|
-
const clean = address.replace(/^0x/, "").toLowerCase();
|
|
82
|
-
const last6 = clean.slice(-6);
|
|
83
|
-
return `agent-${last6}`;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Top-level derivation: try display_name first, fall back to address.
|
|
87
|
-
*
|
|
88
|
-
* Takes optional collision-check hook — if provided, we'll try `<name>-2`,
|
|
89
|
-
* `<name>-3`, ... up to `-9` before giving up. That's enough headroom for
|
|
90
|
-
* normal users; power users who hit it can rename via `hermes profile
|
|
91
|
-
* rename` after the fact.
|
|
92
|
-
*/
|
|
93
|
-
export function deriveProfileName(opts) {
|
|
94
|
-
const fromDisplay = opts.displayName ? slugifyDisplayName(opts.displayName) : "";
|
|
95
|
-
const primary = fromDisplay || profileNameFromAddress(opts.agentAddress);
|
|
96
|
-
if (!opts.isTaken)
|
|
97
|
-
return primary;
|
|
98
|
-
if (!opts.isTaken(primary))
|
|
99
|
-
return primary;
|
|
100
|
-
for (let i = 2; i <= 9; i++) {
|
|
101
|
-
const candidate = `${primary}-${i}`;
|
|
102
|
-
if (candidate.length > MAX_PROFILE_NAME_LEN) {
|
|
103
|
-
// Primary was too long to suffix; fall back to address-based.
|
|
104
|
-
const addrName = profileNameFromAddress(opts.agentAddress);
|
|
105
|
-
return opts.isTaken(addrName) ? `${addrName}-${i}` : addrName;
|
|
106
|
-
}
|
|
107
|
-
if (!opts.isTaken(candidate))
|
|
108
|
-
return candidate;
|
|
109
|
-
}
|
|
110
|
-
// Give up — return the primary. Hermes will error on duplicate create;
|
|
111
|
-
// user sees the error and can rename.
|
|
112
|
-
return primary;
|
|
113
|
-
}
|
|
114
|
-
//# sourceMappingURL=profileName.js.map
|
package/dist/profileName.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"profileName.js","sourceRoot":"","sources":["../src/profileName.ts"],"names":[],"mappings":"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"}
|
package/dist/syncSessions.d.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 2b — session post-processor.
|
|
3
|
-
*
|
|
4
|
-
* `nookplot-mcp sync-sessions` walks `~/.hermes/sessions/session_*.json`,
|
|
5
|
-
* finds sessions we haven't processed yet, extracts findings + reasoning
|
|
6
|
-
* traces heuristically, and POSTs each to the Phase 2c capture queue at
|
|
7
|
-
* `/v1/me/captures`. Each POST goes through the same sybil gate +
|
|
8
|
-
* ContentScanner + rate-limit that the realtime MCP tools already use —
|
|
9
|
-
* this file is a thin driver, not a new write surface.
|
|
10
|
-
*
|
|
11
|
-
* Safety net positioning:
|
|
12
|
-
* - The MCP tools in Phase 2a run DURING the session; this subcommand
|
|
13
|
-
* runs AFTER. Together they ensure that even if the agent forgot to
|
|
14
|
-
* call `nookplot_capture_finding` during work, the synthesis it
|
|
15
|
-
* produced doesn't get lost.
|
|
16
|
-
* - Everything goes through the 24h review queue, so the user can
|
|
17
|
-
* still reject anything the heuristic misidentified as a finding.
|
|
18
|
-
* - Dedup is two-layered: `processed_sessions.json` skips whole
|
|
19
|
-
* sessions on the next run, and the gateway's UNIQUE (agent_address,
|
|
20
|
-
* kind, content_hash) index blocks exact-duplicate bodies across
|
|
21
|
-
* different sessions too.
|
|
22
|
-
*
|
|
23
|
-
* @module syncSessions
|
|
24
|
-
*/
|
|
25
|
-
import type { NookplotCredentials } from "./auth.js";
|
|
26
|
-
export interface SyncSessionsOptions {
|
|
27
|
-
/** Gateway URL. Defaults to $NOOKPLOT_GATEWAY_URL or the public gateway. */
|
|
28
|
-
gatewayUrl?: string;
|
|
29
|
-
/** Credentials (loaded from ~/.nookplot/credentials.json normally). */
|
|
30
|
-
credentials: NookplotCredentials;
|
|
31
|
-
/** If set, overrides the NOOKPLOT_AGENT_ADDRESS env var. */
|
|
32
|
-
scopedAgentAddress?: string;
|
|
33
|
-
/** Dry run — extract + report, but don't POST to the gateway. */
|
|
34
|
-
dryRun?: boolean;
|
|
35
|
-
/** Max sessions to process in this invocation. Default 10. */
|
|
36
|
-
limit?: number;
|
|
37
|
-
/** Only consider sessions modified after this time. */
|
|
38
|
-
since?: Date;
|
|
39
|
-
/** Re-process sessions marked as done. Item-level dedup still applies. */
|
|
40
|
-
force?: boolean;
|
|
41
|
-
/** Directory override for tests. Defaults to ~/.hermes/sessions. */
|
|
42
|
-
sessionsDir?: string;
|
|
43
|
-
/** State file path override for tests. */
|
|
44
|
-
statePath?: string;
|
|
45
|
-
/** Max ms per POST. */
|
|
46
|
-
timeoutMs?: number;
|
|
47
|
-
_fetch?: typeof fetch;
|
|
48
|
-
_now?: () => Date;
|
|
49
|
-
}
|
|
50
|
-
export interface SessionResult {
|
|
51
|
-
sessionId: string;
|
|
52
|
-
filePath: string;
|
|
53
|
-
/** 'processed' on success, 'skipped' if already done, 'failed' on fatal parse error. */
|
|
54
|
-
status: "processed" | "skipped" | "failed";
|
|
55
|
-
/** Items extracted (whether or not they posted successfully). */
|
|
56
|
-
extracted: number;
|
|
57
|
-
/** Items that successfully posted (or counted as duplicates). */
|
|
58
|
-
captured: number;
|
|
59
|
-
/** Per-item errors, if any. */
|
|
60
|
-
errors: string[];
|
|
61
|
-
/** Reason for skip, if status is 'skipped'. */
|
|
62
|
-
skipReason?: string;
|
|
63
|
-
}
|
|
64
|
-
export interface SyncSessionsResult {
|
|
65
|
-
/** Total sessions inspected on this run. */
|
|
66
|
-
inspected: number;
|
|
67
|
-
/** Sessions processed (extraction + POSTs attempted). */
|
|
68
|
-
processed: number;
|
|
69
|
-
/** Sessions skipped (already done or filtered by --since). */
|
|
70
|
-
skipped: number;
|
|
71
|
-
/** Sessions that failed to parse. */
|
|
72
|
-
failed: number;
|
|
73
|
-
/** Items captured into the review queue. */
|
|
74
|
-
capturesCreated: number;
|
|
75
|
-
/** Detailed per-session breakdown (for dry-run reporting). */
|
|
76
|
-
perSession: SessionResult[];
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Main entry point. Walks sessions, extracts, posts. Returns a summary
|
|
80
|
-
* caller can print. Tests drive this directly with mocked `_fetch` +
|
|
81
|
-
* `sessionsDir` + `statePath`.
|
|
82
|
-
*/
|
|
83
|
-
export declare function syncSessions(opts: SyncSessionsOptions): Promise<SyncSessionsResult>;
|
|
84
|
-
//# sourceMappingURL=syncSessions.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncSessions.d.ts","sourceRoot":"","sources":["../src/syncSessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAiBrD,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,WAAW,EAAE,mBAAmB,CAAC;IACjC,4DAA4D;IAC5D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,MAAM,CAAC,EAAE,OAAO,KAAK,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAqGD;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAiK7B"}
|
package/dist/syncSessions.js
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 2b — session post-processor.
|
|
3
|
-
*
|
|
4
|
-
* `nookplot-mcp sync-sessions` walks `~/.hermes/sessions/session_*.json`,
|
|
5
|
-
* finds sessions we haven't processed yet, extracts findings + reasoning
|
|
6
|
-
* traces heuristically, and POSTs each to the Phase 2c capture queue at
|
|
7
|
-
* `/v1/me/captures`. Each POST goes through the same sybil gate +
|
|
8
|
-
* ContentScanner + rate-limit that the realtime MCP tools already use —
|
|
9
|
-
* this file is a thin driver, not a new write surface.
|
|
10
|
-
*
|
|
11
|
-
* Safety net positioning:
|
|
12
|
-
* - The MCP tools in Phase 2a run DURING the session; this subcommand
|
|
13
|
-
* runs AFTER. Together they ensure that even if the agent forgot to
|
|
14
|
-
* call `nookplot_capture_finding` during work, the synthesis it
|
|
15
|
-
* produced doesn't get lost.
|
|
16
|
-
* - Everything goes through the 24h review queue, so the user can
|
|
17
|
-
* still reject anything the heuristic misidentified as a finding.
|
|
18
|
-
* - Dedup is two-layered: `processed_sessions.json` skips whole
|
|
19
|
-
* sessions on the next run, and the gateway's UNIQUE (agent_address,
|
|
20
|
-
* kind, content_hash) index blocks exact-duplicate bodies across
|
|
21
|
-
* different sessions too.
|
|
22
|
-
*
|
|
23
|
-
* @module syncSessions
|
|
24
|
-
*/
|
|
25
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
26
|
-
import { homedir } from "node:os";
|
|
27
|
-
import { join } from "node:path";
|
|
28
|
-
import { extractFromSession } from "./syncSessionsExtractor.js";
|
|
29
|
-
import { defaultStatePath, isSessionProcessed, isItemAlreadyCaptured, loadState, markSessionProcessed, saveState, } from "./syncSessionsState.js";
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
// File discovery
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
/**
|
|
34
|
-
* Default sessions directory. Tests override via `opts.sessionsDir`; in
|
|
35
|
-
* production this is where Hermes v0.8.0 writes session JSONs.
|
|
36
|
-
*/
|
|
37
|
-
function defaultSessionsDir() {
|
|
38
|
-
return join(homedir(), ".hermes", "sessions");
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Session files are named `session_<YYYYMMDD>_<HHMMSS>_<hex>.json`.
|
|
42
|
-
* We ignore `request_dump_*.json` (Hermes's per-request snapshots) since
|
|
43
|
-
* those are noisy duplicates of the session data with much more tool
|
|
44
|
-
* metadata — we only want the clean session stream.
|
|
45
|
-
*/
|
|
46
|
-
function isSessionFile(filename) {
|
|
47
|
-
return /^session_\d{8}_\d{6}_[a-f0-9]+\.json$/.test(filename);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Extract a stable session id from a Hermes session file. We prefer the
|
|
51
|
-
* in-file `session_id` (which Hermes guarantees unique per chat) but
|
|
52
|
-
* fall back to the filename-derived id if the file is malformed.
|
|
53
|
-
*/
|
|
54
|
-
function sessionIdOf(session, filename) {
|
|
55
|
-
if (typeof session.session_id === "string" && session.session_id.length > 0) {
|
|
56
|
-
return session.session_id;
|
|
57
|
-
}
|
|
58
|
-
// filename is `session_<id>.json`, strip the prefix + suffix.
|
|
59
|
-
return filename.replace(/^session_/, "").replace(/\.json$/, "");
|
|
60
|
-
}
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Gateway POST
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
/**
|
|
65
|
-
* Send one extracted item to the gateway's capture queue. Returns the
|
|
66
|
-
* queue row id on success, an error string on failure.
|
|
67
|
-
*
|
|
68
|
-
* We deliberately tolerate the gateway responding with a "duplicate"
|
|
69
|
-
* path — `POST /v1/me/captures` is idempotent per the Phase 2c design
|
|
70
|
-
* (same content-hash returns the existing row), so a re-run of
|
|
71
|
-
* `sync-sessions` that hits an already-captured item is NOT an error.
|
|
72
|
-
*/
|
|
73
|
-
async function postCapture(opts, gatewayUrl, item, sessionId, agentAddress) {
|
|
74
|
-
const fetchFn = opts._fetch ?? fetch;
|
|
75
|
-
const timeoutMs = opts.timeoutMs ?? 15_000;
|
|
76
|
-
const controller = new AbortController();
|
|
77
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
78
|
-
try {
|
|
79
|
-
const res = await fetchFn(`${gatewayUrl.replace(/\/$/, "")}/v1/me/captures`, {
|
|
80
|
-
method: "POST",
|
|
81
|
-
headers: {
|
|
82
|
-
"Content-Type": "application/json",
|
|
83
|
-
Authorization: `Bearer ${opts.credentials.apiKey}`,
|
|
84
|
-
},
|
|
85
|
-
body: JSON.stringify({
|
|
86
|
-
kind: item.kind,
|
|
87
|
-
payload: item.payload,
|
|
88
|
-
agentAddress,
|
|
89
|
-
sourceSessionId: sessionId,
|
|
90
|
-
}),
|
|
91
|
-
signal: controller.signal,
|
|
92
|
-
});
|
|
93
|
-
if (!res.ok) {
|
|
94
|
-
const body = await res.text().catch(() => "");
|
|
95
|
-
return {
|
|
96
|
-
error: `HTTP ${res.status}: ${body.slice(0, 200)}`,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
const parsed = (await res.json());
|
|
100
|
-
if (typeof parsed.id !== "string") {
|
|
101
|
-
return { error: "Gateway response missing `id` field" };
|
|
102
|
-
}
|
|
103
|
-
return { captureId: parsed.id };
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
return { error: err instanceof Error ? err.message : String(err) };
|
|
107
|
-
}
|
|
108
|
-
finally {
|
|
109
|
-
clearTimeout(timer);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// ---------------------------------------------------------------------------
|
|
113
|
-
// Orchestration
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
/**
|
|
116
|
-
* Main entry point. Walks sessions, extracts, posts. Returns a summary
|
|
117
|
-
* caller can print. Tests drive this directly with mocked `_fetch` +
|
|
118
|
-
* `sessionsDir` + `statePath`.
|
|
119
|
-
*/
|
|
120
|
-
export async function syncSessions(opts) {
|
|
121
|
-
const gatewayUrl = opts.gatewayUrl ??
|
|
122
|
-
process.env.NOOKPLOT_GATEWAY_URL ??
|
|
123
|
-
"https://gateway.nookplot.com";
|
|
124
|
-
const sessionsDir = opts.sessionsDir ?? defaultSessionsDir();
|
|
125
|
-
const statePath = opts.statePath ?? defaultStatePath();
|
|
126
|
-
const limit = opts.limit ?? 10;
|
|
127
|
-
const scopedAgentAddress = opts.scopedAgentAddress ?? process.env.NOOKPLOT_AGENT_ADDRESS ?? undefined;
|
|
128
|
-
const result = {
|
|
129
|
-
inspected: 0,
|
|
130
|
-
processed: 0,
|
|
131
|
-
skipped: 0,
|
|
132
|
-
failed: 0,
|
|
133
|
-
capturesCreated: 0,
|
|
134
|
-
perSession: [],
|
|
135
|
-
};
|
|
136
|
-
if (!existsSync(sessionsDir)) {
|
|
137
|
-
// Fresh install — no sessions yet. Not an error, just nothing to do.
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
let state = loadState(statePath);
|
|
141
|
-
// Sort files oldest → newest so resumed runs process in chronological
|
|
142
|
-
// order, matching the natural "replay of the user's work" semantics.
|
|
143
|
-
const files = readdirSync(sessionsDir)
|
|
144
|
-
.filter(isSessionFile)
|
|
145
|
-
.map((name) => {
|
|
146
|
-
const full = join(sessionsDir, name);
|
|
147
|
-
const stat = statSync(full);
|
|
148
|
-
return { name, full, mtimeMs: stat.mtimeMs };
|
|
149
|
-
})
|
|
150
|
-
.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
151
|
-
for (const file of files) {
|
|
152
|
-
if (result.processed >= limit)
|
|
153
|
-
break;
|
|
154
|
-
result.inspected += 1;
|
|
155
|
-
// --since filter: skip anything older than the cutoff.
|
|
156
|
-
if (opts.since && file.mtimeMs < opts.since.getTime()) {
|
|
157
|
-
result.skipped += 1;
|
|
158
|
-
result.perSession.push({
|
|
159
|
-
sessionId: file.name,
|
|
160
|
-
filePath: file.full,
|
|
161
|
-
status: "skipped",
|
|
162
|
-
extracted: 0,
|
|
163
|
-
captured: 0,
|
|
164
|
-
errors: [],
|
|
165
|
-
skipReason: "older than --since cutoff",
|
|
166
|
-
});
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
// Parse the session.
|
|
170
|
-
let session;
|
|
171
|
-
try {
|
|
172
|
-
const raw = readFileSync(file.full, "utf8");
|
|
173
|
-
session = JSON.parse(raw);
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
result.failed += 1;
|
|
177
|
-
result.perSession.push({
|
|
178
|
-
sessionId: file.name,
|
|
179
|
-
filePath: file.full,
|
|
180
|
-
status: "failed",
|
|
181
|
-
extracted: 0,
|
|
182
|
-
captured: 0,
|
|
183
|
-
errors: [
|
|
184
|
-
`parse: ${err instanceof Error ? err.message : String(err)}`,
|
|
185
|
-
],
|
|
186
|
-
});
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
const sid = sessionIdOf(session, file.name);
|
|
190
|
-
// Already-processed fast path. --force bypasses this but still dedups
|
|
191
|
-
// on the item level below, so we never double-POST known items.
|
|
192
|
-
if (!opts.force && isSessionProcessed(state, sid)) {
|
|
193
|
-
result.skipped += 1;
|
|
194
|
-
result.perSession.push({
|
|
195
|
-
sessionId: sid,
|
|
196
|
-
filePath: file.full,
|
|
197
|
-
status: "skipped",
|
|
198
|
-
extracted: 0,
|
|
199
|
-
captured: 0,
|
|
200
|
-
errors: [],
|
|
201
|
-
skipReason: "already processed (use --force to reprocess)",
|
|
202
|
-
});
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const extracted = extractFromSession(session);
|
|
206
|
-
const itemResults = [];
|
|
207
|
-
const errors = [];
|
|
208
|
-
let captured = 0;
|
|
209
|
-
for (const item of extracted) {
|
|
210
|
-
// Item-level dedup for --force re-runs: if we know the gateway
|
|
211
|
-
// already has this hash from a prior pass, skip the POST entirely.
|
|
212
|
-
if (opts.force && isItemAlreadyCaptured(state, sid, item.hash)) {
|
|
213
|
-
captured += 1; // count it as already-captured for the summary
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
if (opts.dryRun) {
|
|
217
|
-
itemResults.push({ hash: item.hash, kind: item.kind });
|
|
218
|
-
captured += 1;
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
const postResult = await postCapture(opts, gatewayUrl, item, sid, scopedAgentAddress);
|
|
222
|
-
if ("captureId" in postResult) {
|
|
223
|
-
itemResults.push({
|
|
224
|
-
hash: item.hash,
|
|
225
|
-
kind: item.kind,
|
|
226
|
-
captureId: postResult.captureId,
|
|
227
|
-
});
|
|
228
|
-
captured += 1;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
itemResults.push({
|
|
232
|
-
hash: item.hash,
|
|
233
|
-
kind: item.kind,
|
|
234
|
-
error: postResult.error,
|
|
235
|
-
});
|
|
236
|
-
errors.push(`${item.kind}: ${postResult.error}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
// Record this session (successes + failures) so we don't re-process.
|
|
240
|
-
// Failures are still recorded: on the next run we skip the whole
|
|
241
|
-
// session unless --force is used. If the user wants to retry just
|
|
242
|
-
// the failed items they run with --force.
|
|
243
|
-
if (!opts.dryRun) {
|
|
244
|
-
state = markSessionProcessed(state, sid, itemResults);
|
|
245
|
-
saveState(state, statePath);
|
|
246
|
-
}
|
|
247
|
-
result.processed += 1;
|
|
248
|
-
result.capturesCreated += captured;
|
|
249
|
-
result.perSession.push({
|
|
250
|
-
sessionId: sid,
|
|
251
|
-
filePath: file.full,
|
|
252
|
-
status: "processed",
|
|
253
|
-
extracted: extracted.length,
|
|
254
|
-
captured,
|
|
255
|
-
errors,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
return result;
|
|
259
|
-
}
|
|
260
|
-
//# sourceMappingURL=syncSessions.js.map
|
package/dist/syncSessions.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncSessions.js","sourceRoot":"","sources":["../src/syncSessions.ts"],"names":[],"mappings":"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"}
|