jfl 0.9.6 → 0.9.8
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/dist/commands/agents.js +1 -1
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +77 -18
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/deploy.js +1 -1
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/feedback.js +1 -1
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/hud.js +1 -1
- package/dist/commands/hud.js.map +1 -1
- package/dist/commands/init-from-service.js +1 -1
- package/dist/commands/init-from-service.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/kanban.js +6 -6
- package/dist/commands/kanban.js.map +1 -1
- package/dist/commands/login.d.ts +2 -13
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +6 -44
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/organize.d.ts +16 -0
- package/dist/commands/organize.d.ts.map +1 -0
- package/dist/commands/organize.js +334 -0
- package/dist/commands/organize.js.map +1 -0
- package/dist/commands/peter.d.ts.map +1 -1
- package/dist/commands/peter.js +273 -0
- package/dist/commands/peter.js.map +1 -1
- package/dist/commands/pi.d.ts.map +1 -1
- package/dist/commands/pi.js +11 -5
- package/dist/commands/pi.js.map +1 -1
- package/dist/commands/repair.js +1 -1
- package/dist/commands/repair.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +113 -45
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +4 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +66 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-config.d.ts.map +1 -1
- package/dist/lib/agent-config.js +24 -2
- package/dist/lib/agent-config.js.map +1 -1
- package/dist/lib/hub-health.d.ts.map +1 -1
- package/dist/lib/hub-health.js +14 -2
- package/dist/lib/hub-health.js.map +1 -1
- package/dist/lib/resource-optimizer-middleware.d.ts.map +1 -1
- package/dist/lib/resource-optimizer-middleware.js +8 -2
- package/dist/lib/resource-optimizer-middleware.js.map +1 -1
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +13 -12
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/utils/auth-status.d.ts +21 -0
- package/dist/utils/auth-status.d.ts.map +1 -0
- package/dist/utils/auth-status.js +53 -0
- package/dist/utils/auth-status.js.map +1 -0
- package/package.json +3 -2
- package/packages/pi/dist/agent-grid.d.ts +24 -0
- package/packages/pi/dist/agent-grid.d.ts.map +1 -0
- package/packages/pi/dist/agent-grid.js +162 -0
- package/packages/pi/dist/agent-grid.js.map +1 -0
- package/packages/pi/dist/agent-names.d.ts +43 -0
- package/packages/pi/dist/agent-names.d.ts.map +1 -0
- package/packages/pi/dist/agent-names.js +156 -0
- package/packages/pi/dist/agent-names.js.map +1 -0
- package/packages/pi/dist/autoresearch.d.ts +15 -0
- package/packages/pi/dist/autoresearch.d.ts.map +1 -0
- package/packages/pi/dist/autoresearch.js +372 -0
- package/packages/pi/dist/autoresearch.js.map +1 -0
- package/packages/pi/dist/bookmarks.d.ts +15 -0
- package/packages/pi/dist/bookmarks.d.ts.map +1 -0
- package/packages/pi/dist/bookmarks.js +77 -0
- package/packages/pi/dist/bookmarks.js.map +1 -0
- package/packages/pi/dist/context.d.ts +17 -0
- package/packages/pi/dist/context.d.ts.map +1 -0
- package/packages/pi/dist/context.js +152 -0
- package/packages/pi/dist/context.js.map +1 -0
- package/packages/pi/dist/crm-tool.d.ts +12 -0
- package/packages/pi/dist/crm-tool.d.ts.map +1 -0
- package/packages/pi/dist/crm-tool.js +58 -0
- package/packages/pi/dist/crm-tool.js.map +1 -0
- package/packages/pi/dist/eval-tool.d.ts +11 -0
- package/packages/pi/dist/eval-tool.d.ts.map +1 -0
- package/packages/pi/dist/eval-tool.js +188 -0
- package/packages/pi/dist/eval-tool.js.map +1 -0
- package/packages/pi/dist/eval.d.ts +12 -0
- package/packages/pi/dist/eval.d.ts.map +1 -0
- package/packages/pi/dist/eval.js +43 -0
- package/packages/pi/dist/eval.js.map +1 -0
- package/packages/pi/dist/footer.d.ts +20 -0
- package/packages/pi/dist/footer.d.ts.map +1 -0
- package/packages/pi/dist/footer.js +222 -0
- package/packages/pi/dist/footer.js.map +1 -0
- package/packages/pi/dist/header.d.ts +17 -0
- package/packages/pi/dist/header.d.ts.map +1 -0
- package/packages/pi/dist/header.js +156 -0
- package/packages/pi/dist/header.js.map +1 -0
- package/packages/pi/dist/hub-resolver.d.ts +11 -0
- package/packages/pi/dist/hub-resolver.d.ts.map +1 -0
- package/packages/pi/dist/hub-resolver.js +58 -0
- package/packages/pi/dist/hub-resolver.js.map +1 -0
- package/packages/pi/dist/hub-tools.d.ts +14 -0
- package/packages/pi/dist/hub-tools.d.ts.map +1 -0
- package/packages/pi/dist/hub-tools.js +266 -0
- package/packages/pi/dist/hub-tools.js.map +1 -0
- package/packages/pi/dist/hud-tool.d.ts +17 -0
- package/packages/pi/dist/hud-tool.d.ts.map +1 -0
- package/packages/pi/dist/hud-tool.js +297 -0
- package/packages/pi/dist/hud-tool.js.map +1 -0
- package/packages/pi/dist/index.d.ts +12 -0
- package/packages/pi/dist/index.d.ts.map +1 -0
- package/packages/pi/dist/index.js +436 -0
- package/packages/pi/dist/index.js.map +1 -0
- package/packages/pi/dist/jfl-resolve.d.ts +29 -0
- package/packages/pi/dist/jfl-resolve.d.ts.map +1 -0
- package/packages/pi/dist/jfl-resolve.js +89 -0
- package/packages/pi/dist/jfl-resolve.js.map +1 -0
- package/packages/pi/dist/journal.d.ts +23 -0
- package/packages/pi/dist/journal.d.ts.map +1 -0
- package/packages/pi/dist/journal.js +250 -0
- package/packages/pi/dist/journal.js.map +1 -0
- package/packages/pi/dist/map-bridge.d.ts +20 -0
- package/packages/pi/dist/map-bridge.d.ts.map +1 -0
- package/packages/pi/dist/map-bridge.js +181 -0
- package/packages/pi/dist/map-bridge.js.map +1 -0
- package/packages/pi/dist/memory-tool.d.ts +11 -0
- package/packages/pi/dist/memory-tool.d.ts.map +1 -0
- package/packages/pi/dist/memory-tool.js +148 -0
- package/packages/pi/dist/memory-tool.js.map +1 -0
- package/packages/pi/dist/notifications.d.ts +15 -0
- package/packages/pi/dist/notifications.d.ts.map +1 -0
- package/packages/pi/dist/notifications.js +65 -0
- package/packages/pi/dist/notifications.js.map +1 -0
- package/packages/pi/dist/onboarding-v1.d.ts +15 -0
- package/packages/pi/dist/onboarding-v1.d.ts.map +1 -0
- package/packages/pi/dist/onboarding-v1.js +417 -0
- package/packages/pi/dist/onboarding-v1.js.map +1 -0
- package/packages/pi/dist/onboarding-v2.d.ts +18 -0
- package/packages/pi/dist/onboarding-v2.d.ts.map +1 -0
- package/packages/pi/dist/onboarding-v2.js +402 -0
- package/packages/pi/dist/onboarding-v2.js.map +1 -0
- package/packages/pi/dist/onboarding-v3.d.ts +13 -0
- package/packages/pi/dist/onboarding-v3.d.ts.map +1 -0
- package/packages/pi/dist/onboarding-v3.js +581 -0
- package/packages/pi/dist/onboarding-v3.js.map +1 -0
- package/packages/pi/dist/peter-parker.d.ts +12 -0
- package/packages/pi/dist/peter-parker.d.ts.map +1 -0
- package/packages/pi/dist/peter-parker.js +162 -0
- package/packages/pi/dist/peter-parker.js.map +1 -0
- package/packages/pi/dist/pivot-tool.d.ts +11 -0
- package/packages/pi/dist/pivot-tool.d.ts.map +1 -0
- package/packages/pi/dist/pivot-tool.js +56 -0
- package/packages/pi/dist/pivot-tool.js.map +1 -0
- package/packages/pi/dist/policy-head-tool.d.ts +15 -0
- package/packages/pi/dist/policy-head-tool.d.ts.map +1 -0
- package/packages/pi/dist/policy-head-tool.js +220 -0
- package/packages/pi/dist/policy-head-tool.js.map +1 -0
- package/packages/pi/dist/portfolio-bridge.d.ts +12 -0
- package/packages/pi/dist/portfolio-bridge.d.ts.map +1 -0
- package/packages/pi/dist/portfolio-bridge.js +81 -0
- package/packages/pi/dist/portfolio-bridge.js.map +1 -0
- package/packages/pi/dist/service-skills.d.ts +15 -0
- package/packages/pi/dist/service-skills.d.ts.map +1 -0
- package/packages/pi/dist/service-skills.js +198 -0
- package/packages/pi/dist/service-skills.js.map +1 -0
- package/packages/pi/dist/session.d.ts +24 -0
- package/packages/pi/dist/session.d.ts.map +1 -0
- package/packages/pi/dist/session.js +394 -0
- package/packages/pi/dist/session.js.map +1 -0
- package/packages/pi/dist/shortcuts.d.ts +11 -0
- package/packages/pi/dist/shortcuts.d.ts.map +1 -0
- package/packages/pi/dist/shortcuts.js +231 -0
- package/packages/pi/dist/shortcuts.js.map +1 -0
- package/packages/pi/dist/startup-briefing.d.ts +13 -0
- package/packages/pi/dist/startup-briefing.d.ts.map +1 -0
- package/packages/pi/dist/startup-briefing.js +271 -0
- package/packages/pi/dist/startup-briefing.js.map +1 -0
- package/packages/pi/dist/stratus-bridge.d.ts +14 -0
- package/packages/pi/dist/stratus-bridge.d.ts.map +1 -0
- package/packages/pi/dist/stratus-bridge.js +104 -0
- package/packages/pi/dist/stratus-bridge.js.map +1 -0
- package/packages/pi/dist/subway-mesh.d.ts +88 -0
- package/packages/pi/dist/subway-mesh.d.ts.map +1 -0
- package/packages/pi/dist/subway-mesh.js +813 -0
- package/packages/pi/dist/subway-mesh.js.map +1 -0
- package/packages/pi/dist/synopsis-tool.d.ts +12 -0
- package/packages/pi/dist/synopsis-tool.d.ts.map +1 -0
- package/packages/pi/dist/synopsis-tool.js +84 -0
- package/packages/pi/dist/synopsis-tool.js.map +1 -0
- package/packages/pi/dist/tool-renderers.d.ts +55 -0
- package/packages/pi/dist/tool-renderers.d.ts.map +1 -0
- package/packages/pi/dist/tool-renderers.js +349 -0
- package/packages/pi/dist/tool-renderers.js.map +1 -0
- package/packages/pi/dist/training-buffer-tool.d.ts +16 -0
- package/packages/pi/dist/training-buffer-tool.d.ts.map +1 -0
- package/packages/pi/dist/training-buffer-tool.js +319 -0
- package/packages/pi/dist/training-buffer-tool.js.map +1 -0
- package/packages/pi/dist/types.d.ts +195 -0
- package/packages/pi/dist/types.d.ts.map +1 -0
- package/packages/pi/dist/types.js +11 -0
- package/packages/pi/dist/types.js.map +1 -0
- package/packages/pi/extensions/session.ts +115 -8
- package/packages/pi/extensions/training-buffer-tool.ts +15 -8
- package/packages/pi/extensions/types.ts +1 -0
- package/packages/pi/package.json +2 -3
- package/scripts/postinstall.js +52 -4
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journal Extension
|
|
3
|
+
*
|
|
4
|
+
* Detects git commits via tool_execution_end, prompts for journal entries,
|
|
5
|
+
* registers the /journal command with interactive type selection,
|
|
6
|
+
* shows themed journal stream in below-editor widget.
|
|
7
|
+
*
|
|
8
|
+
* @purpose Auto-journal detection + interactive /journal command + themed widget
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { execSync } from "child_process";
|
|
13
|
+
import { getCurrentBranch, getSessionBranch } from "./session.js";
|
|
14
|
+
import { emitCustomEvent } from "./map-bridge.js";
|
|
15
|
+
let projectRoot = "";
|
|
16
|
+
function getJournalPath(root) {
|
|
17
|
+
// Prefer the session branch tracked by session.ts — git HEAD may differ
|
|
18
|
+
// if checkout failed due to dirty working tree
|
|
19
|
+
const branch = getSessionBranch() || getCurrentBranch(root);
|
|
20
|
+
return join(root, ".jfl", "journal", `${branch}.jsonl`);
|
|
21
|
+
}
|
|
22
|
+
function appendJournalEntry(root, entry) {
|
|
23
|
+
const journalPath = getJournalPath(root);
|
|
24
|
+
mkdirSync(join(root, ".jfl", "journal"), { recursive: true });
|
|
25
|
+
appendFileSync(journalPath, JSON.stringify(entry) + "\n");
|
|
26
|
+
}
|
|
27
|
+
function readRecentEntries(root, count = 5) {
|
|
28
|
+
const journalPath = getJournalPath(root);
|
|
29
|
+
if (!existsSync(journalPath))
|
|
30
|
+
return [];
|
|
31
|
+
try {
|
|
32
|
+
const lines = readFileSync(journalPath, "utf-8")
|
|
33
|
+
.split("\n")
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.slice(-count);
|
|
36
|
+
return lines.map(l => JSON.parse(l));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function hasJournalEntryForSession(root, sessionBranch) {
|
|
43
|
+
const journalPath = join(root, ".jfl", "journal", `${sessionBranch}.jsonl`);
|
|
44
|
+
if (!existsSync(journalPath))
|
|
45
|
+
return false;
|
|
46
|
+
const content = readFileSync(journalPath, "utf-8").trim();
|
|
47
|
+
return content.length > 0;
|
|
48
|
+
}
|
|
49
|
+
const TYPE_ICONS = {
|
|
50
|
+
feature: "✦",
|
|
51
|
+
fix: "✧",
|
|
52
|
+
decision: "◆",
|
|
53
|
+
discovery: "◇",
|
|
54
|
+
milestone: "★",
|
|
55
|
+
"session-end": "●",
|
|
56
|
+
spec: "□",
|
|
57
|
+
};
|
|
58
|
+
const TYPE_COLORS = {
|
|
59
|
+
feature: "success",
|
|
60
|
+
fix: "error",
|
|
61
|
+
decision: "warning",
|
|
62
|
+
discovery: "accent",
|
|
63
|
+
milestone: "warning",
|
|
64
|
+
"session-end": "dim",
|
|
65
|
+
spec: "muted",
|
|
66
|
+
};
|
|
67
|
+
function showRecentJournal(_ctx) {
|
|
68
|
+
// Widget removed — journal entries visible via /journal or Ctrl+Shift+J
|
|
69
|
+
}
|
|
70
|
+
export async function setupJournal(ctx, _config) {
|
|
71
|
+
projectRoot = ctx.session.projectRoot;
|
|
72
|
+
showRecentJournal(ctx);
|
|
73
|
+
ctx.registerCommand({
|
|
74
|
+
name: "journal",
|
|
75
|
+
description: "Write a journal entry for the current session",
|
|
76
|
+
async handler(_args, ctx) {
|
|
77
|
+
if (ctx.ui.hasUI) {
|
|
78
|
+
const types = [
|
|
79
|
+
{ value: "feature", label: "✦ Feature", description: "Something built or completed" },
|
|
80
|
+
{ value: "fix", label: "✧ Fix", description: "Bug found and fixed" },
|
|
81
|
+
{ value: "decision", label: "◆ Decision", description: "Choice made between options" },
|
|
82
|
+
{ value: "discovery", label: "◇ Discovery", description: "Insight or learning" },
|
|
83
|
+
{ value: "milestone", label: "★ Milestone", description: "Major goal reached" },
|
|
84
|
+
];
|
|
85
|
+
const type = await ctx.ui.select("Journal Entry Type", types);
|
|
86
|
+
if (!type)
|
|
87
|
+
return;
|
|
88
|
+
const title = await ctx.ui.input("Title", "What happened?");
|
|
89
|
+
if (!title?.trim())
|
|
90
|
+
return;
|
|
91
|
+
const summary = await ctx.ui.input("Summary (2-3 sentences)", "Brief description");
|
|
92
|
+
const entry = {
|
|
93
|
+
v: 1,
|
|
94
|
+
ts: new Date().toISOString(),
|
|
95
|
+
session: getSessionBranch() || getCurrentBranch(projectRoot),
|
|
96
|
+
type,
|
|
97
|
+
status: "complete",
|
|
98
|
+
title: title.trim(),
|
|
99
|
+
summary: summary?.trim() ?? title.trim(),
|
|
100
|
+
};
|
|
101
|
+
appendJournalEntry(projectRoot, entry);
|
|
102
|
+
await emitCustomEvent(ctx, "journal:entry", entry);
|
|
103
|
+
ctx.emit("journal:written", entry);
|
|
104
|
+
showRecentJournal(ctx);
|
|
105
|
+
ctx.ui.notify(`${TYPE_ICONS[type] ?? "·"} Journal: ${title.trim()}`, { level: "success" });
|
|
106
|
+
ctx.ui.setStatus("journal", undefined);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Fallback: raw JSON input for non-interactive mode
|
|
110
|
+
const branch = getSessionBranch() || getCurrentBranch(projectRoot);
|
|
111
|
+
const template = JSON.stringify({
|
|
112
|
+
v: 1,
|
|
113
|
+
ts: new Date().toISOString(),
|
|
114
|
+
session: branch,
|
|
115
|
+
type: "feature",
|
|
116
|
+
status: "complete",
|
|
117
|
+
title: "",
|
|
118
|
+
summary: "",
|
|
119
|
+
detail: "",
|
|
120
|
+
files: [],
|
|
121
|
+
}, null, 2);
|
|
122
|
+
const content = await ctx.ui.input("Journal Entry (paste JSON)", template);
|
|
123
|
+
if (!content?.trim())
|
|
124
|
+
return;
|
|
125
|
+
try {
|
|
126
|
+
const entry = JSON.parse(content);
|
|
127
|
+
appendJournalEntry(projectRoot, entry);
|
|
128
|
+
await emitCustomEvent(ctx, "journal:entry", entry);
|
|
129
|
+
ctx.emit("journal:written", entry);
|
|
130
|
+
showRecentJournal(ctx);
|
|
131
|
+
ctx.ui.notify("Journal entry saved", { level: "success" });
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
ctx.ui.notify("Invalid JSON — entry not saved. Use /journal and paste valid JSON.", { level: "warn" });
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
ctx.on("map:journal:entry", () => showRecentJournal(ctx));
|
|
139
|
+
ctx.on("journal:written", () => showRecentJournal(ctx));
|
|
140
|
+
}
|
|
141
|
+
export async function onToolExecutionEnd(ctx, event) {
|
|
142
|
+
const toolName = event.toolName ?? event.tool ?? "";
|
|
143
|
+
// TaskUpdate completed → journal nudge (parity with CC PostToolUse hook)
|
|
144
|
+
if (toolName === "TaskUpdate") {
|
|
145
|
+
const input = event.input ?? event.args ?? {};
|
|
146
|
+
const inputStr = typeof input === "string" ? input : JSON.stringify(input);
|
|
147
|
+
if (/"status"\s*:\s*"completed"/.test(inputStr)) {
|
|
148
|
+
const branch = getCurrentBranch(projectRoot);
|
|
149
|
+
ctx.ui.notify(`Task completed — write journal entry\nFile: .jfl/journal/${branch}.jsonl`, { level: "info" });
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (toolName.toLowerCase() !== "bash")
|
|
154
|
+
return;
|
|
155
|
+
const result = String(event.result ?? "");
|
|
156
|
+
const isGitCommit = /\[[\w/.-]+\s+[0-9a-f]{7,}\]/.test(result);
|
|
157
|
+
if (!isGitCommit)
|
|
158
|
+
return;
|
|
159
|
+
let commitMsg = "";
|
|
160
|
+
let commitFiles = "";
|
|
161
|
+
try {
|
|
162
|
+
commitMsg = execSync("git log -1 --pretty=%B", { cwd: projectRoot }).toString().trim();
|
|
163
|
+
commitFiles = execSync("git diff-tree --no-commit-id --name-only -r HEAD", { cwd: projectRoot })
|
|
164
|
+
.toString().trim();
|
|
165
|
+
}
|
|
166
|
+
catch { }
|
|
167
|
+
ctx.emit("pi:git-commit-detected", { message: commitMsg, files: commitFiles });
|
|
168
|
+
ctx.ui.notify([
|
|
169
|
+
"Git commit detected — Ctrl+Shift+J for quick journal or /journal",
|
|
170
|
+
commitMsg ? `Commit: ${commitMsg.split("\n")[0]}` : "",
|
|
171
|
+
commitFiles ? `Files: ${commitFiles.split("\n").slice(0, 3).join(", ")}` : "",
|
|
172
|
+
].filter(Boolean).join("\n"), { level: "info" });
|
|
173
|
+
}
|
|
174
|
+
export async function onJournalAgentEnd(_ctx, _event) {
|
|
175
|
+
// Removed: "Journal entry recommended" nudge (noisy)
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Check @purpose header on Write/Edit to code files.
|
|
179
|
+
* Equivalent to Claude Code's PostToolUse(Write|Edit) hook.
|
|
180
|
+
*/
|
|
181
|
+
export function checkPurposeHeader(ctx, event) {
|
|
182
|
+
const toolName = (event.toolName ?? event.tool ?? "").toLowerCase();
|
|
183
|
+
if (toolName !== "write" && toolName !== "edit")
|
|
184
|
+
return;
|
|
185
|
+
// Extract file path from tool input
|
|
186
|
+
const input = event.input ?? event.args ?? {};
|
|
187
|
+
const filePath = typeof input === "string"
|
|
188
|
+
? input
|
|
189
|
+
: input.path ?? input.file_path ?? "";
|
|
190
|
+
if (!filePath)
|
|
191
|
+
return;
|
|
192
|
+
if (!/\.(ts|tsx|js|jsx)$/.test(filePath))
|
|
193
|
+
return;
|
|
194
|
+
const fullPath = filePath.startsWith("/") ? filePath : join(projectRoot, filePath);
|
|
195
|
+
if (!existsSync(fullPath))
|
|
196
|
+
return;
|
|
197
|
+
try {
|
|
198
|
+
const head = readFileSync(fullPath, "utf-8").slice(0, 800);
|
|
199
|
+
if (!head.includes("@purpose")) {
|
|
200
|
+
ctx.ui.notify(`⚠️ Missing @purpose header in ${filePath}\n Add: /** @purpose One-line description */`, { level: "warn" });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch { }
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Auto-commit changes before context compaction.
|
|
207
|
+
* Equivalent to Claude Code's PreCompact hook that runs:
|
|
208
|
+
* git add knowledge/ previews/ content/ suggestions/ .jfl/ && git commit
|
|
209
|
+
*/
|
|
210
|
+
function autoCommitBeforeCompact(ctx) {
|
|
211
|
+
const trackedDirs = ["knowledge", "previews", "content", "suggestions", ".jfl", "CLAUDE.md"];
|
|
212
|
+
const addPaths = trackedDirs
|
|
213
|
+
.filter((d) => existsSync(join(projectRoot, d)))
|
|
214
|
+
.join(" ");
|
|
215
|
+
if (!addPaths)
|
|
216
|
+
return;
|
|
217
|
+
try {
|
|
218
|
+
const status = execSync(`git status --porcelain -- ${addPaths}`, {
|
|
219
|
+
cwd: projectRoot,
|
|
220
|
+
encoding: "utf-8",
|
|
221
|
+
}).trim();
|
|
222
|
+
if (!status)
|
|
223
|
+
return; // nothing to commit
|
|
224
|
+
execSync(`git add ${addPaths} && git commit -m "auto-commit: pre-compact save"`, {
|
|
225
|
+
cwd: projectRoot,
|
|
226
|
+
stdio: "pipe",
|
|
227
|
+
});
|
|
228
|
+
ctx.log("Pre-compact auto-commit saved changes", "debug");
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Not critical — auto-commit daemon is the primary safety net
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export async function checkJournalBeforeCompact(ctx) {
|
|
235
|
+
// Auto-commit changes before compaction (safety net)
|
|
236
|
+
autoCommitBeforeCompact(ctx);
|
|
237
|
+
const branch = getSessionBranch() || getCurrentBranch(projectRoot);
|
|
238
|
+
if (!hasJournalEntryForSession(projectRoot, branch)) {
|
|
239
|
+
if (ctx.ui.hasUI) {
|
|
240
|
+
const ok = await ctx.ui.confirm("No Journal Entry", "No journal entry for this session. Compacting without one loses context.\n\nContinue anyway?");
|
|
241
|
+
if (!ok)
|
|
242
|
+
return ctx.cancel();
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
ctx.ui.notify("No journal entry for this session. Write one with /journal before compacting.", { level: "warn" });
|
|
246
|
+
return ctx.cancel();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../extensions/journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAP Event Bridge Extension
|
|
3
|
+
*
|
|
4
|
+
* Translates Pi lifecycle events → MAP event bus (Context Hub HTTP).
|
|
5
|
+
* Also subscribes to hub SSE stream and re-emits as Pi custom events.
|
|
6
|
+
* Enforces scope filtering from .jfl/config.json context_scope.
|
|
7
|
+
*
|
|
8
|
+
* @purpose Pi lifecycle → MAP bus bridge with scope enforcement
|
|
9
|
+
*/
|
|
10
|
+
import type { PiContext, JflConfig, AgentEndEvent, ToolExecutionEvent } from "./types.js";
|
|
11
|
+
declare let hubUrl: string;
|
|
12
|
+
declare let authToken: string | null;
|
|
13
|
+
export declare function setupMapBridge(ctx: PiContext, config: JflConfig): Promise<void>;
|
|
14
|
+
export declare function onMapBridgeShutdown(_ctx: PiContext): Promise<void>;
|
|
15
|
+
export declare function emitAgentStart(ctx: PiContext, event: unknown): Promise<void>;
|
|
16
|
+
export declare function emitAgentEnd(ctx: PiContext, event: AgentEndEvent): Promise<void>;
|
|
17
|
+
export declare function onMapToolEnd(ctx: PiContext, event: ToolExecutionEvent): Promise<void>;
|
|
18
|
+
export declare function emitCustomEvent(ctx: PiContext, type: string, data: unknown): Promise<void>;
|
|
19
|
+
export { hubUrl, authToken };
|
|
20
|
+
//# sourceMappingURL=map-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map-bridge.d.ts","sourceRoot":"","sources":["../extensions/map-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAezF,QAAA,IAAI,MAAM,QAA0B,CAAA;AACpC,QAAA,IAAI,SAAS,EAAE,MAAM,GAAG,IAAW,CAAA;AAyGnC,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CrF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3F;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhG;AAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MAP Event Bridge Extension
|
|
3
|
+
*
|
|
4
|
+
* Translates Pi lifecycle events → MAP event bus (Context Hub HTTP).
|
|
5
|
+
* Also subscribes to hub SSE stream and re-emits as Pi custom events.
|
|
6
|
+
* Enforces scope filtering from .jfl/config.json context_scope.
|
|
7
|
+
*
|
|
8
|
+
* @purpose Pi lifecycle → MAP bus bridge with scope enforcement
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync, existsSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
let hubUrl = "http://localhost:4242";
|
|
13
|
+
let authToken = null;
|
|
14
|
+
let scope = {};
|
|
15
|
+
let sseAbort = null;
|
|
16
|
+
const PI_TO_MAP = {
|
|
17
|
+
"hook:session-start": "hook:session-start",
|
|
18
|
+
"hook:session-end": "hook:session-end",
|
|
19
|
+
"task:started": "task:started",
|
|
20
|
+
"task:completed": "task:completed",
|
|
21
|
+
"hook:tool-use": "hook:tool-use",
|
|
22
|
+
"hook:tool-result": "hook:tool-result",
|
|
23
|
+
};
|
|
24
|
+
function readToken(root) {
|
|
25
|
+
const tokenPath = join(root, ".jfl", "context-hub.token");
|
|
26
|
+
if (existsSync(tokenPath)) {
|
|
27
|
+
return readFileSync(tokenPath, "utf-8").trim();
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function matchPattern(pattern, value) {
|
|
32
|
+
if (pattern === "*")
|
|
33
|
+
return true;
|
|
34
|
+
if (pattern === value)
|
|
35
|
+
return true;
|
|
36
|
+
if (pattern.includes("*")) {
|
|
37
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
38
|
+
return regex.test(value);
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
function isEventAllowedToEmit(eventType, src) {
|
|
43
|
+
if (!src.produces || src.produces.length === 0)
|
|
44
|
+
return true;
|
|
45
|
+
return src.produces.some(p => matchPattern(p, eventType));
|
|
46
|
+
}
|
|
47
|
+
function isEventDenied(eventType, src) {
|
|
48
|
+
if (!src.denied || src.denied.length === 0)
|
|
49
|
+
return false;
|
|
50
|
+
return src.denied.some(d => matchPattern(d, eventType));
|
|
51
|
+
}
|
|
52
|
+
async function postToHub(event) {
|
|
53
|
+
if (isEventDenied(event.type, scope))
|
|
54
|
+
return;
|
|
55
|
+
if (!isEventAllowedToEmit(event.type, scope))
|
|
56
|
+
return;
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch(`${hubUrl}/api/events`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify(event),
|
|
65
|
+
});
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
// Silently ignore hub connectivity issues — it may not be running
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Hub not available — non-fatal
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function subscribeToHubSSE(ctx) {
|
|
75
|
+
sseAbort = new AbortController();
|
|
76
|
+
const consumesPatterns = scope.consumes ?? ["*"];
|
|
77
|
+
try {
|
|
78
|
+
const patternsParam = consumesPatterns.join(",");
|
|
79
|
+
const url = `${hubUrl}/api/events/stream?pattern=${encodeURIComponent(patternsParam)}`;
|
|
80
|
+
const resp = await fetch(url, {
|
|
81
|
+
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},
|
|
82
|
+
signal: sseAbort.signal,
|
|
83
|
+
});
|
|
84
|
+
if (!resp.ok || !resp.body)
|
|
85
|
+
return;
|
|
86
|
+
const reader = resp.body.getReader();
|
|
87
|
+
const decoder = new TextDecoder();
|
|
88
|
+
let buffer = "";
|
|
89
|
+
while (true) {
|
|
90
|
+
const { done, value } = await reader.read();
|
|
91
|
+
if (done)
|
|
92
|
+
break;
|
|
93
|
+
buffer += decoder.decode(value, { stream: true });
|
|
94
|
+
const lines = buffer.split("\n");
|
|
95
|
+
buffer = lines.pop() ?? "";
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
if (!line.startsWith("data: "))
|
|
98
|
+
continue;
|
|
99
|
+
try {
|
|
100
|
+
const event = JSON.parse(line.slice(6));
|
|
101
|
+
if (isEventDenied(event.type, scope))
|
|
102
|
+
continue;
|
|
103
|
+
ctx.emit(`map:${event.type}`, event);
|
|
104
|
+
}
|
|
105
|
+
catch { }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
if (err.name === "AbortError")
|
|
111
|
+
return;
|
|
112
|
+
// Silently ignore — Context Hub may not be running
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function setupMapBridge(ctx, config) {
|
|
116
|
+
const root = ctx.session.projectRoot;
|
|
117
|
+
authToken = readToken(root);
|
|
118
|
+
scope = config.context_scope ?? {};
|
|
119
|
+
const portFile = join(root, ".jfl", "context-hub.port");
|
|
120
|
+
if (existsSync(portFile)) {
|
|
121
|
+
const port = readFileSync(portFile, "utf-8").trim();
|
|
122
|
+
if (port)
|
|
123
|
+
hubUrl = `http://localhost:${port}`;
|
|
124
|
+
}
|
|
125
|
+
// Verify the hub is actually reachable on this port.
|
|
126
|
+
// If not, try discovering the real port from the running process.
|
|
127
|
+
try {
|
|
128
|
+
const healthResp = await fetch(`${hubUrl}/health`, { signal: AbortSignal.timeout(3000) });
|
|
129
|
+
if (!healthResp.ok)
|
|
130
|
+
throw new Error("unhealthy");
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
ctx.log(`Hub unreachable at ${hubUrl}, attempting port discovery...`, "warn");
|
|
134
|
+
// Try to find the actual port from the running hub process
|
|
135
|
+
try {
|
|
136
|
+
const { execSync } = await import("child_process");
|
|
137
|
+
const psOut = execSync(`ps aux | grep "context-hub serve.*--project-root ${root.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}" | grep -v grep`, { encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
138
|
+
const portMatch = psOut.match(/--port\s+(\d+)/);
|
|
139
|
+
if (portMatch) {
|
|
140
|
+
const discoveredPort = portMatch[1];
|
|
141
|
+
const testResp = await fetch(`http://localhost:${discoveredPort}/health`, { signal: AbortSignal.timeout(3000) });
|
|
142
|
+
if (testResp.ok) {
|
|
143
|
+
hubUrl = `http://localhost:${discoveredPort}`;
|
|
144
|
+
// Fix the stale port file
|
|
145
|
+
const { writeFileSync } = await import("fs");
|
|
146
|
+
writeFileSync(join(root, ".jfl", "context-hub.port"), discoveredPort);
|
|
147
|
+
ctx.log(`Hub discovered on port ${discoveredPort} — fixed stale port file`, "warn");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
ctx.log("Hub port discovery failed — hub tools will be unavailable", "warn");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
ctx.on("hook:session-start", (data) => postToHub({ type: "hook:session-start", source: "pi-session", data, ts: new Date().toISOString() }));
|
|
156
|
+
ctx.on("hook:session-end", (data) => postToHub({ type: "hook:session-end", source: "pi-session", data, ts: new Date().toISOString() }));
|
|
157
|
+
subscribeToHubSSE(ctx).catch(() => { });
|
|
158
|
+
}
|
|
159
|
+
export async function onMapBridgeShutdown(_ctx) {
|
|
160
|
+
sseAbort?.abort();
|
|
161
|
+
sseAbort = null;
|
|
162
|
+
}
|
|
163
|
+
export async function emitAgentStart(ctx, event) {
|
|
164
|
+
await postToHub({ type: "task:started", source: `pi-agent:${ctx.session.id}`, data: event, ts: new Date().toISOString() });
|
|
165
|
+
}
|
|
166
|
+
export async function emitAgentEnd(ctx, event) {
|
|
167
|
+
await postToHub({ type: "task:completed", source: `pi-agent:${ctx.session.id}`, data: event, ts: new Date().toISOString() });
|
|
168
|
+
}
|
|
169
|
+
export async function onMapToolEnd(ctx, event) {
|
|
170
|
+
await postToHub({
|
|
171
|
+
type: "hook:tool-result",
|
|
172
|
+
source: `pi-agent:${ctx.session.id}`,
|
|
173
|
+
data: { tool: event.toolName ?? event.tool, duration: event.duration },
|
|
174
|
+
ts: new Date().toISOString(),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
export async function emitCustomEvent(ctx, type, data) {
|
|
178
|
+
await postToHub({ type, source: `pi:${ctx.session.id}`, data, ts: new Date().toISOString() });
|
|
179
|
+
}
|
|
180
|
+
export { hubUrl, authToken };
|
|
181
|
+
//# sourceMappingURL=map-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map-bridge.js","sourceRoot":"","sources":["../extensions/map-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Tool Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers jfl_memory_search, jfl_memory_add, and jfl_memory_status tools.
|
|
5
|
+
* Full parity with the Context Hub MCP server's memory tools.
|
|
6
|
+
*
|
|
7
|
+
* @purpose Memory tools — search, add, and status for project memory
|
|
8
|
+
*/
|
|
9
|
+
import type { PiContext } from "./types.js";
|
|
10
|
+
export declare function setupMemoryTool(ctx: PiContext): void;
|
|
11
|
+
//# sourceMappingURL=memory-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-tool.d.ts","sourceRoot":"","sources":["../extensions/memory-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAI3C,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CA2IpD"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Tool Extension
|
|
3
|
+
*
|
|
4
|
+
* Registers jfl_memory_search, jfl_memory_add, and jfl_memory_status tools.
|
|
5
|
+
* Full parity with the Context Hub MCP server's memory tools.
|
|
6
|
+
*
|
|
7
|
+
* @purpose Memory tools — search, add, and status for project memory
|
|
8
|
+
*/
|
|
9
|
+
import { hubUrl, authToken } from "./map-bridge.js";
|
|
10
|
+
import { memoryRenderCall, memoryRenderResult } from "./tool-renderers.js";
|
|
11
|
+
export function setupMemoryTool(ctx) {
|
|
12
|
+
// ─── jfl_memory_search ───────────────────────────────────────────────────
|
|
13
|
+
ctx.registerTool({
|
|
14
|
+
name: "jfl_memory_search",
|
|
15
|
+
description: "Search JFL project memory — find past decisions, learnings, and patterns across all sessions",
|
|
16
|
+
promptSnippet: "Search project memory for decisions, learnings, and session history",
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
query: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Search query to find relevant memories",
|
|
23
|
+
},
|
|
24
|
+
limit: {
|
|
25
|
+
type: "number",
|
|
26
|
+
description: "Maximum results (default: 10)",
|
|
27
|
+
},
|
|
28
|
+
type: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Filter by entry type: feature, fix, decision, discovery, milestone, all",
|
|
31
|
+
enum: ["feature", "fix", "decision", "discovery", "milestone", "all"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["query"],
|
|
35
|
+
},
|
|
36
|
+
async handler(input) {
|
|
37
|
+
const { query, limit, type } = input;
|
|
38
|
+
try {
|
|
39
|
+
const body = { query, maxItems: limit ?? 10 };
|
|
40
|
+
if (type && type !== "all")
|
|
41
|
+
body.type = type;
|
|
42
|
+
const resp = await fetch(`${hubUrl}/api/memory/search`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify(body),
|
|
49
|
+
});
|
|
50
|
+
if (!resp.ok)
|
|
51
|
+
return "Memory search unavailable.";
|
|
52
|
+
const data = await resp.json();
|
|
53
|
+
if (!data.results?.length)
|
|
54
|
+
return "No memories found.";
|
|
55
|
+
return data.results
|
|
56
|
+
.map(r => {
|
|
57
|
+
const header = [r.type && `[${r.type}]`, r.title].filter(Boolean).join(" ");
|
|
58
|
+
return [header, r.content].filter(Boolean).join("\n");
|
|
59
|
+
})
|
|
60
|
+
.join("\n\n---\n\n");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return "Memory search unavailable — Context Hub may not be running.";
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
renderCall: memoryRenderCall,
|
|
67
|
+
renderResult: memoryRenderResult,
|
|
68
|
+
});
|
|
69
|
+
// ─── jfl_memory_add ──────────────────────────────────────────────────────
|
|
70
|
+
ctx.registerTool({
|
|
71
|
+
name: "jfl_memory_add",
|
|
72
|
+
description: "Manually add a memory or note to the project memory system. Use to capture insights, decisions, or important context that should persist across sessions.",
|
|
73
|
+
promptSnippet: "Add a memory/note to project memory",
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
title: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Title for the memory entry",
|
|
80
|
+
},
|
|
81
|
+
content: {
|
|
82
|
+
type: "string",
|
|
83
|
+
description: "Content of the memory — the insight, decision, or note",
|
|
84
|
+
},
|
|
85
|
+
type: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Type of memory entry",
|
|
88
|
+
enum: ["decision", "discovery", "insight", "note"],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
required: ["title", "content"],
|
|
92
|
+
},
|
|
93
|
+
async handler(input) {
|
|
94
|
+
const { title, content, type } = input;
|
|
95
|
+
try {
|
|
96
|
+
const resp = await fetch(`${hubUrl}/api/memory/add`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({ title, content, type: type ?? "note" }),
|
|
103
|
+
signal: AbortSignal.timeout(5000),
|
|
104
|
+
});
|
|
105
|
+
if (!resp.ok)
|
|
106
|
+
return "Failed to add memory — hub returned error.";
|
|
107
|
+
const data = await resp.json();
|
|
108
|
+
return (data.ok || data.id)
|
|
109
|
+
? `Memory added: "${title}" (${type ?? "note"})${data.id ? ` [id: ${data.id}]` : ""}`
|
|
110
|
+
: "Memory add returned unexpected response.";
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return "Memory add unavailable — Context Hub may not be running.";
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
// ─── jfl_memory_status ───────────────────────────────────────────────────
|
|
118
|
+
ctx.registerTool({
|
|
119
|
+
name: "jfl_memory_status",
|
|
120
|
+
description: "Get memory system statistics and health — total entries, indexed count, embedding status.",
|
|
121
|
+
promptSnippet: "Check memory system health and stats",
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: "object",
|
|
124
|
+
properties: {},
|
|
125
|
+
},
|
|
126
|
+
async handler() {
|
|
127
|
+
try {
|
|
128
|
+
const resp = await fetch(`${hubUrl}/api/memory/status`, {
|
|
129
|
+
method: "GET",
|
|
130
|
+
headers: {
|
|
131
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
132
|
+
},
|
|
133
|
+
signal: AbortSignal.timeout(5000),
|
|
134
|
+
});
|
|
135
|
+
if (!resp.ok)
|
|
136
|
+
return "Memory status unavailable.";
|
|
137
|
+
const data = await resp.json();
|
|
138
|
+
return Object.entries(data)
|
|
139
|
+
.map(([k, v]) => `${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`)
|
|
140
|
+
.join("\n");
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return "Memory status unavailable — Context Hub may not be running.";
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=memory-tool.js.map
|