jfl 0.9.0 → 0.9.2
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 +35 -4
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +118 -2
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/digest.d.ts +6 -0
- package/dist/commands/digest.d.ts.map +1 -1
- package/dist/commands/digest.js +70 -69
- package/dist/commands/digest.js.map +1 -1
- package/dist/commands/eval.d.ts +40 -0
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +8 -8
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/findings.d.ts +7 -0
- package/dist/commands/findings.d.ts.map +1 -1
- package/dist/commands/findings.js +4 -4
- package/dist/commands/findings.js.map +1 -1
- package/dist/commands/ide.d.ts.map +1 -1
- package/dist/commands/ide.js +25 -2
- package/dist/commands/ide.js.map +1 -1
- package/dist/commands/kanban.js +6 -6
- package/dist/commands/kanban.js.map +1 -1
- package/dist/commands/linear.d.ts.map +1 -1
- package/dist/commands/linear.js +24 -0
- package/dist/commands/linear.js.map +1 -1
- package/dist/commands/pi.d.ts +3 -0
- package/dist/commands/pi.d.ts.map +1 -1
- package/dist/commands/pi.js +19 -0
- package/dist/commands/pi.js.map +1 -1
- package/dist/commands/portfolio.d.ts +5 -0
- package/dist/commands/portfolio.d.ts.map +1 -1
- package/dist/commands/portfolio.js +193 -203
- package/dist/commands/portfolio.js.map +1 -1
- package/dist/commands/predict.d.ts +19 -0
- package/dist/commands/predict.d.ts.map +1 -1
- package/dist/commands/predict.js +4 -4
- package/dist/commands/predict.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +106 -7
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts +25 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +191 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/tenet-agents.js +2 -2
- package/dist/commands/tenet-agents.js.map +1 -1
- package/dist/commands/tenet-setup.d.ts +2 -1
- package/dist/commands/tenet-setup.d.ts.map +1 -1
- package/dist/commands/tenet-setup.js +22 -18
- package/dist/commands/tenet-setup.js.map +1 -1
- package/dist/commands/viz.d.ts +33 -0
- package/dist/commands/viz.d.ts.map +1 -1
- package/dist/commands/viz.js +9 -9
- package/dist/commands/viz.js.map +1 -1
- package/dist/index.js +97 -43
- package/dist/index.js.map +1 -1
- package/dist/lib/advanced-setup.d.ts +1 -1
- package/dist/lib/advanced-setup.d.ts.map +1 -1
- package/dist/lib/advanced-setup.js +22 -22
- package/dist/lib/advanced-setup.js.map +1 -1
- package/dist/lib/discovery-agent.js +4 -4
- package/dist/lib/discovery-agent.js.map +1 -1
- package/dist/lib/linear-id-map.d.ts.map +1 -1
- package/dist/lib/linear-id-map.js +2 -0
- package/dist/lib/linear-id-map.js.map +1 -1
- package/dist/lib/linear-webhook.d.ts +50 -0
- package/dist/lib/linear-webhook.d.ts.map +1 -0
- package/dist/lib/linear-webhook.js +92 -0
- package/dist/lib/linear-webhook.js.map +1 -0
- package/dist/lib/onboarding.d.ts +1 -1
- package/dist/lib/onboarding.js +14 -14
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/rl-manager.d.ts +1 -1
- package/dist/lib/rl-manager.d.ts.map +1 -1
- package/dist/lib/rl-manager.js +5 -4
- package/dist/lib/rl-manager.js.map +1 -1
- package/dist/lib/setup/starter-intelligence.d.ts +25 -0
- package/dist/lib/setup/starter-intelligence.d.ts.map +1 -0
- package/dist/lib/setup/starter-intelligence.js +309 -0
- package/dist/lib/setup/starter-intelligence.js.map +1 -0
- package/dist/lib/tool-schemas.d.ts +35 -0
- package/dist/lib/tool-schemas.d.ts.map +1 -0
- package/dist/lib/tool-schemas.js +246 -0
- package/dist/lib/tool-schemas.js.map +1 -0
- package/dist/lib/workspace/data-pipeline.d.ts.map +1 -1
- package/dist/lib/workspace/data-pipeline.js +29 -20
- package/dist/lib/workspace/data-pipeline.js.map +1 -1
- package/dist/lib/workspace/engine.d.ts +1 -0
- package/dist/lib/workspace/engine.d.ts.map +1 -1
- package/dist/lib/workspace/engine.js +10 -0
- package/dist/lib/workspace/engine.js.map +1 -1
- package/dist/lib/workspace/surface-registry.d.ts.map +1 -1
- package/dist/lib/workspace/surface-registry.js +5 -0
- package/dist/lib/workspace/surface-registry.js.map +1 -1
- package/dist/lib/workspace/surfaces/sidebar.d.ts.map +1 -1
- package/dist/lib/workspace/surfaces/sidebar.js +5 -1
- package/dist/lib/workspace/surfaces/sidebar.js.map +1 -1
- package/dist/lib/workspace/tmux-adapter.d.ts +8 -5
- package/dist/lib/workspace/tmux-adapter.d.ts.map +1 -1
- package/dist/lib/workspace/tmux-adapter.js +38 -7
- package/dist/lib/workspace/tmux-adapter.js.map +1 -1
- package/dist/lib/workspace/tmux-sidebar.d.ts +14 -0
- package/dist/lib/workspace/tmux-sidebar.d.ts.map +1 -0
- package/dist/lib/workspace/tmux-sidebar.js +230 -0
- package/dist/lib/workspace/tmux-sidebar.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +7 -1
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/types/telemetry.d.ts +1 -0
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/utils/jfl-config.d.ts +7 -2
- package/dist/utils/jfl-config.d.ts.map +1 -1
- package/dist/utils/jfl-config.js +14 -4
- package/dist/utils/jfl-config.js.map +1 -1
- package/package.json +1 -1
- package/packages/pi/assets/boot.mp3 +0 -0
- package/packages/pi/extensions/autoresearch.ts +3 -2
- package/packages/pi/extensions/context.ts +29 -66
- package/packages/pi/extensions/eval.ts +2 -1
- package/packages/pi/extensions/hub-tools.ts +267 -0
- package/packages/pi/extensions/hud-tool.ts +230 -69
- package/packages/pi/extensions/index.ts +43 -63
- package/packages/pi/extensions/jfl-resolve.ts +98 -0
- package/packages/pi/extensions/journal.ts +91 -6
- package/packages/pi/extensions/map-bridge.ts +31 -0
- package/packages/pi/extensions/memory-tool.ts +84 -4
- package/packages/pi/extensions/onboarding-v2.ts +367 -399
- package/packages/pi/extensions/peter-parker.ts +2 -1
- package/packages/pi/extensions/policy-head-tool.ts +3 -2
- package/packages/pi/extensions/portfolio-bridge.ts +3 -4
- package/packages/pi/extensions/service-skills.ts +214 -0
- package/packages/pi/extensions/session.ts +91 -15
- package/packages/pi/extensions/stratus-bridge.ts +2 -1
- package/packages/pi/extensions/synopsis-tool.ts +6 -1
- package/packages/pi/extensions/training-buffer-tool.ts +3 -2
- package/packages/pi/extensions/types.ts +2 -0
- package/packages/pi/package.json +3 -1
- package/packages/pi/skills/viz/SKILL.md +204 -0
|
@@ -12,7 +12,7 @@ import { existsSync, readFileSync, appendFileSync, mkdirSync } from "fs"
|
|
|
12
12
|
import { join } from "path"
|
|
13
13
|
import { execSync } from "child_process"
|
|
14
14
|
import type { PiContext, PiTheme, JflConfig, AgentEndEvent, ToolExecutionEvent } from "./types.js"
|
|
15
|
-
import { getCurrentBranch } from "./session.js"
|
|
15
|
+
import { getCurrentBranch, getSessionBranch } from "./session.js"
|
|
16
16
|
import { emitCustomEvent } from "./map-bridge.js"
|
|
17
17
|
|
|
18
18
|
let projectRoot = ""
|
|
@@ -33,7 +33,9 @@ interface JournalEntry {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function getJournalPath(root: string): string {
|
|
36
|
-
|
|
36
|
+
// Prefer the session branch tracked by session.ts — git HEAD may differ
|
|
37
|
+
// if checkout failed due to dirty working tree
|
|
38
|
+
const branch = getSessionBranch() || getCurrentBranch(root)
|
|
37
39
|
return join(root, ".jfl", "journal", `${branch}.jsonl`)
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -57,7 +59,7 @@ function readRecentEntries(root: string, count = 5): JournalEntry[] {
|
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
function hasJournalEntryForSession(root: string, sessionBranch: string): boolean {
|
|
62
|
+
export function hasJournalEntryForSession(root: string, sessionBranch: string): boolean {
|
|
61
63
|
const journalPath = join(root, ".jfl", "journal", `${sessionBranch}.jsonl`)
|
|
62
64
|
if (!existsSync(journalPath)) return false
|
|
63
65
|
const content = readFileSync(journalPath, "utf-8").trim()
|
|
@@ -117,7 +119,7 @@ export async function setupJournal(ctx: PiContext, _config: JflConfig): Promise<
|
|
|
117
119
|
const entry: JournalEntry = {
|
|
118
120
|
v: 1,
|
|
119
121
|
ts: new Date().toISOString(),
|
|
120
|
-
session: getCurrentBranch(projectRoot),
|
|
122
|
+
session: getSessionBranch() || getCurrentBranch(projectRoot),
|
|
121
123
|
type,
|
|
122
124
|
status: "complete",
|
|
123
125
|
title: title.trim(),
|
|
@@ -134,7 +136,7 @@ export async function setupJournal(ctx: PiContext, _config: JflConfig): Promise<
|
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
// Fallback: raw JSON input for non-interactive mode
|
|
137
|
-
const branch = getCurrentBranch(projectRoot)
|
|
139
|
+
const branch = getSessionBranch() || getCurrentBranch(projectRoot)
|
|
138
140
|
const template = JSON.stringify({
|
|
139
141
|
v: 1,
|
|
140
142
|
ts: new Date().toISOString(),
|
|
@@ -172,6 +174,21 @@ export async function onToolExecutionEnd(
|
|
|
172
174
|
event: ToolExecutionEvent
|
|
173
175
|
): Promise<void> {
|
|
174
176
|
const toolName = event.toolName ?? event.tool ?? ""
|
|
177
|
+
|
|
178
|
+
// TaskUpdate completed → journal nudge (parity with CC PostToolUse hook)
|
|
179
|
+
if (toolName === "TaskUpdate") {
|
|
180
|
+
const input = event.input ?? event.args ?? {}
|
|
181
|
+
const inputStr = typeof input === "string" ? input : JSON.stringify(input)
|
|
182
|
+
if (/"status"\s*:\s*"completed"/.test(inputStr)) {
|
|
183
|
+
const branch = getCurrentBranch(projectRoot)
|
|
184
|
+
ctx.ui.notify(
|
|
185
|
+
`Task completed — write journal entry\nFile: .jfl/journal/${branch}.jsonl`,
|
|
186
|
+
{ level: "info" }
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
175
192
|
if (toolName.toLowerCase() !== "bash") return
|
|
176
193
|
|
|
177
194
|
const result = String(event.result ?? "")
|
|
@@ -202,10 +219,78 @@ export async function onJournalAgentEnd(
|
|
|
202
219
|
// Removed: "Journal entry recommended" nudge (noisy)
|
|
203
220
|
}
|
|
204
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Check @purpose header on Write/Edit to code files.
|
|
224
|
+
* Equivalent to Claude Code's PostToolUse(Write|Edit) hook.
|
|
225
|
+
*/
|
|
226
|
+
export function checkPurposeHeader(
|
|
227
|
+
ctx: PiContext,
|
|
228
|
+
event: ToolExecutionEvent
|
|
229
|
+
): void {
|
|
230
|
+
const toolName = (event.toolName ?? event.tool ?? "").toLowerCase()
|
|
231
|
+
if (toolName !== "write" && toolName !== "edit") return
|
|
232
|
+
|
|
233
|
+
// Extract file path from tool input
|
|
234
|
+
const input = event.input ?? event.args ?? {}
|
|
235
|
+
const filePath = typeof input === "string"
|
|
236
|
+
? input
|
|
237
|
+
: (input as any).path ?? (input as any).file_path ?? ""
|
|
238
|
+
|
|
239
|
+
if (!filePath) return
|
|
240
|
+
if (!/\.(ts|tsx|js|jsx)$/.test(filePath)) return
|
|
241
|
+
|
|
242
|
+
const fullPath = filePath.startsWith("/") ? filePath : join(projectRoot, filePath)
|
|
243
|
+
if (!existsSync(fullPath)) return
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
const head = readFileSync(fullPath, "utf-8").slice(0, 800)
|
|
247
|
+
if (!head.includes("@purpose")) {
|
|
248
|
+
ctx.ui.notify(
|
|
249
|
+
`⚠️ Missing @purpose header in ${filePath}\n Add: /** @purpose One-line description */`,
|
|
250
|
+
{ level: "warn" }
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
} catch {}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Auto-commit changes before context compaction.
|
|
258
|
+
* Equivalent to Claude Code's PreCompact hook that runs:
|
|
259
|
+
* git add knowledge/ previews/ content/ suggestions/ .jfl/ && git commit
|
|
260
|
+
*/
|
|
261
|
+
function autoCommitBeforeCompact(ctx: PiContext): void {
|
|
262
|
+
const trackedDirs = ["knowledge", "previews", "content", "suggestions", ".jfl", "CLAUDE.md"]
|
|
263
|
+
const addPaths = trackedDirs
|
|
264
|
+
.filter((d) => existsSync(join(projectRoot, d)))
|
|
265
|
+
.join(" ")
|
|
266
|
+
|
|
267
|
+
if (!addPaths) return
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const status = execSync(`git status --porcelain -- ${addPaths}`, {
|
|
271
|
+
cwd: projectRoot,
|
|
272
|
+
encoding: "utf-8",
|
|
273
|
+
}).trim()
|
|
274
|
+
|
|
275
|
+
if (!status) return // nothing to commit
|
|
276
|
+
|
|
277
|
+
execSync(`git add ${addPaths} && git commit -m "auto-commit: pre-compact save"`, {
|
|
278
|
+
cwd: projectRoot,
|
|
279
|
+
stdio: "pipe",
|
|
280
|
+
})
|
|
281
|
+
ctx.log("Pre-compact auto-commit saved changes", "debug")
|
|
282
|
+
} catch {
|
|
283
|
+
// Not critical — auto-commit daemon is the primary safety net
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
205
287
|
export async function checkJournalBeforeCompact(
|
|
206
288
|
ctx: PiContext
|
|
207
289
|
): Promise<{ cancel: true } | void> {
|
|
208
|
-
|
|
290
|
+
// Auto-commit changes before compaction (safety net)
|
|
291
|
+
autoCommitBeforeCompact(ctx)
|
|
292
|
+
|
|
293
|
+
const branch = getSessionBranch() || getCurrentBranch(projectRoot)
|
|
209
294
|
if (!hasJournalEntryForSession(projectRoot, branch)) {
|
|
210
295
|
if (ctx.ui.hasUI) {
|
|
211
296
|
const ok = await ctx.ui.confirm(
|
|
@@ -143,6 +143,37 @@ export async function setupMapBridge(ctx: PiContext, config: JflConfig): Promise
|
|
|
143
143
|
if (port) hubUrl = `http://localhost:${port}`
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// Verify the hub is actually reachable on this port.
|
|
147
|
+
// If not, try discovering the real port from the running process.
|
|
148
|
+
try {
|
|
149
|
+
const healthResp = await fetch(`${hubUrl}/health`, { signal: AbortSignal.timeout(3000) })
|
|
150
|
+
if (!healthResp.ok) throw new Error("unhealthy")
|
|
151
|
+
} catch {
|
|
152
|
+
ctx.log(`Hub unreachable at ${hubUrl}, attempting port discovery...`, "warn")
|
|
153
|
+
// Try to find the actual port from the running hub process
|
|
154
|
+
try {
|
|
155
|
+
const { execSync } = await import("child_process")
|
|
156
|
+
const psOut = execSync(
|
|
157
|
+
`ps aux | grep "context-hub serve.*--project-root ${root.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}" | grep -v grep`,
|
|
158
|
+
{ encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }
|
|
159
|
+
).trim()
|
|
160
|
+
const portMatch = psOut.match(/--port\s+(\d+)/)
|
|
161
|
+
if (portMatch) {
|
|
162
|
+
const discoveredPort = portMatch[1]
|
|
163
|
+
const testResp = await fetch(`http://localhost:${discoveredPort}/health`, { signal: AbortSignal.timeout(3000) })
|
|
164
|
+
if (testResp.ok) {
|
|
165
|
+
hubUrl = `http://localhost:${discoveredPort}`
|
|
166
|
+
// Fix the stale port file
|
|
167
|
+
const { writeFileSync } = await import("fs")
|
|
168
|
+
writeFileSync(join(root, ".jfl", "context-hub.port"), discoveredPort)
|
|
169
|
+
ctx.log(`Hub discovered on port ${discoveredPort} — fixed stale port file`, "warn")
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
ctx.log("Hub port discovery failed — hub tools will be unavailable", "warn")
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
146
177
|
ctx.on("hook:session-start", (data) => postToHub({ type: "hook:session-start", source: "pi-session", data, ts: new Date().toISOString() }))
|
|
147
178
|
ctx.on("hook:session-end", (data) => postToHub({ type: "hook:session-end", source: "pi-session", data, ts: new Date().toISOString() }))
|
|
148
179
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Memory Tool Extension
|
|
3
3
|
*
|
|
4
|
-
* Registers jfl_memory_search
|
|
5
|
-
*
|
|
6
|
-
* type-colored headers and collapsible sections.
|
|
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.
|
|
7
6
|
*
|
|
8
|
-
* @purpose
|
|
7
|
+
* @purpose Memory tools — search, add, and status for project memory
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
import type { PiContext } from "./types.js"
|
|
@@ -13,6 +12,7 @@ import { hubUrl, authToken } from "./map-bridge.js"
|
|
|
13
12
|
import { memoryRenderCall, memoryRenderResult } from "./tool-renderers.js"
|
|
14
13
|
|
|
15
14
|
export function setupMemoryTool(ctx: PiContext): void {
|
|
15
|
+
// ─── jfl_memory_search ───────────────────────────────────────────────────
|
|
16
16
|
ctx.registerTool({
|
|
17
17
|
name: "jfl_memory_search",
|
|
18
18
|
description: "Search JFL project memory — find past decisions, learnings, and patterns across all sessions",
|
|
@@ -70,4 +70,84 @@ export function setupMemoryTool(ctx: PiContext): void {
|
|
|
70
70
|
renderCall: memoryRenderCall,
|
|
71
71
|
renderResult: memoryRenderResult,
|
|
72
72
|
})
|
|
73
|
+
|
|
74
|
+
// ─── jfl_memory_add ──────────────────────────────────────────────────────
|
|
75
|
+
ctx.registerTool({
|
|
76
|
+
name: "jfl_memory_add",
|
|
77
|
+
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.",
|
|
78
|
+
promptSnippet: "Add a memory/note to project memory",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
title: {
|
|
83
|
+
type: "string",
|
|
84
|
+
description: "Title for the memory entry",
|
|
85
|
+
},
|
|
86
|
+
content: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "Content of the memory — the insight, decision, or note",
|
|
89
|
+
},
|
|
90
|
+
type: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "Type of memory entry",
|
|
93
|
+
enum: ["decision", "discovery", "insight", "note"],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: ["title", "content"],
|
|
97
|
+
},
|
|
98
|
+
async handler(input) {
|
|
99
|
+
const { title, content, type } = input as { title: string; content: string; type?: string }
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const resp = await fetch(`${hubUrl}/api/memory/add`, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
"Content-Type": "application/json",
|
|
106
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify({ title, content, type: type ?? "note" }),
|
|
109
|
+
signal: AbortSignal.timeout(5000),
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
if (!resp.ok) return "Failed to add memory — hub returned error."
|
|
113
|
+
const data = await resp.json() as { ok?: boolean; id?: string }
|
|
114
|
+
return data.ok
|
|
115
|
+
? `Memory added: "${title}" (${type ?? "note"})`
|
|
116
|
+
: "Memory add returned unexpected response."
|
|
117
|
+
} catch {
|
|
118
|
+
return "Memory add unavailable — Context Hub may not be running."
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// ─── jfl_memory_status ───────────────────────────────────────────────────
|
|
124
|
+
ctx.registerTool({
|
|
125
|
+
name: "jfl_memory_status",
|
|
126
|
+
description: "Get memory system statistics and health — total entries, indexed count, embedding status.",
|
|
127
|
+
promptSnippet: "Check memory system health and stats",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {},
|
|
131
|
+
},
|
|
132
|
+
async handler() {
|
|
133
|
+
try {
|
|
134
|
+
const resp = await fetch(`${hubUrl}/api/memory/status`, {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: {
|
|
137
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
138
|
+
},
|
|
139
|
+
signal: AbortSignal.timeout(5000),
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
if (!resp.ok) return "Memory status unavailable."
|
|
143
|
+
const data = await resp.json() as Record<string, unknown>
|
|
144
|
+
|
|
145
|
+
return Object.entries(data)
|
|
146
|
+
.map(([k, v]) => `${k}: ${typeof v === "object" ? JSON.stringify(v) : v}`)
|
|
147
|
+
.join("\n")
|
|
148
|
+
} catch {
|
|
149
|
+
return "Memory status unavailable — Context Hub may not be running."
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
})
|
|
73
153
|
}
|