@phren/cli 0.0.56 → 0.0.57
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/shell/render-api.js +101 -0
- package/package.json +3 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { listProjectCards } from "../data/access.js";
|
|
2
|
+
import { renderShell } from "./view.js";
|
|
3
|
+
import { getListItems } from "./input.js";
|
|
4
|
+
// ── View cycling order (same as the shell tab bar) ──────────────────────────
|
|
5
|
+
const VIEW_ORDER = [
|
|
6
|
+
"Projects", "Tasks", "Findings", "Review Queue", "Skills", "Hooks",
|
|
7
|
+
];
|
|
8
|
+
// ── Render ──────────────────────────────────────────────────────────────────
|
|
9
|
+
/** Render a full shell frame for the given state. Read-only, no mutations. */
|
|
10
|
+
export async function renderMenuFrame(phrenPath, profile, state) {
|
|
11
|
+
const shellState = {
|
|
12
|
+
version: 3,
|
|
13
|
+
view: state.view,
|
|
14
|
+
project: state.project,
|
|
15
|
+
filter: state.filter,
|
|
16
|
+
};
|
|
17
|
+
const ctx = {
|
|
18
|
+
phrenPath,
|
|
19
|
+
profile,
|
|
20
|
+
state: shellState,
|
|
21
|
+
currentCursor: () => state.cursor,
|
|
22
|
+
currentScroll: () => state.scroll,
|
|
23
|
+
setScroll: () => { },
|
|
24
|
+
};
|
|
25
|
+
const stubDoctor = async () => ({
|
|
26
|
+
ok: true,
|
|
27
|
+
checks: [],
|
|
28
|
+
});
|
|
29
|
+
const output = await renderShell(ctx, "navigate", // always navigate mode (no input mode in agent menu)
|
|
30
|
+
"", // no inputCtx
|
|
31
|
+
"", // no inputBuf
|
|
32
|
+
false, // no help
|
|
33
|
+
"Tab: Chat ←→: Views ↑↓: Navigate Enter: Select /: Filter Esc: Back", stubDoctor, null, // subsectionsCache
|
|
34
|
+
() => { }, // setHealthLineCount
|
|
35
|
+
() => { });
|
|
36
|
+
const listCount = getListItems(phrenPath, profile, shellState, 0).length;
|
|
37
|
+
return { output, listCount };
|
|
38
|
+
}
|
|
39
|
+
// ── Navigation (pure function) ──────────────────────────────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* Apply a key to the menu state. Returns a new state, or null to signal
|
|
42
|
+
* "exit menu mode" (Tab or Escape at top level).
|
|
43
|
+
*/
|
|
44
|
+
export function handleMenuKey(state, keyName, listCount, phrenPath, profile) {
|
|
45
|
+
switch (keyName) {
|
|
46
|
+
// Exit menu
|
|
47
|
+
case "tab":
|
|
48
|
+
case "q":
|
|
49
|
+
return null;
|
|
50
|
+
// View cycling
|
|
51
|
+
case "left": {
|
|
52
|
+
const idx = VIEW_ORDER.indexOf(state.view);
|
|
53
|
+
const next = idx <= 0 ? VIEW_ORDER[VIEW_ORDER.length - 1] : VIEW_ORDER[idx - 1];
|
|
54
|
+
return { ...state, view: next, cursor: 0, scroll: 0, filter: undefined };
|
|
55
|
+
}
|
|
56
|
+
case "right": {
|
|
57
|
+
const idx = VIEW_ORDER.indexOf(state.view);
|
|
58
|
+
const next = idx >= VIEW_ORDER.length - 1 ? VIEW_ORDER[0] : VIEW_ORDER[idx + 1];
|
|
59
|
+
return { ...state, view: next, cursor: 0, scroll: 0, filter: undefined };
|
|
60
|
+
}
|
|
61
|
+
// Cursor movement
|
|
62
|
+
case "up":
|
|
63
|
+
return { ...state, cursor: Math.max(0, state.cursor - 1) };
|
|
64
|
+
case "down":
|
|
65
|
+
return { ...state, cursor: Math.min(Math.max(0, listCount - 1), state.cursor + 1) };
|
|
66
|
+
// Enter: drill into project (Projects view only)
|
|
67
|
+
case "return": {
|
|
68
|
+
if (state.view === "Projects" && phrenPath && profile) {
|
|
69
|
+
const cards = listProjectCards(phrenPath, profile);
|
|
70
|
+
const filtered = state.filter
|
|
71
|
+
? cards.filter((c) => `${c.name} ${c.summary} ${c.docs.join(" ")}`.toLowerCase().includes(state.filter.toLowerCase()))
|
|
72
|
+
: cards;
|
|
73
|
+
const selected = filtered[state.cursor];
|
|
74
|
+
if (selected) {
|
|
75
|
+
return { ...state, view: "Tasks", project: selected.name, cursor: 0, scroll: 0 };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Escape from sub-view back to Projects
|
|
79
|
+
if (state.view !== "Projects" && state.project) {
|
|
80
|
+
return state; // no-op for non-projects views on enter
|
|
81
|
+
}
|
|
82
|
+
return state;
|
|
83
|
+
}
|
|
84
|
+
// Escape: clear filter, or go back to projects, or exit
|
|
85
|
+
case "escape": {
|
|
86
|
+
if (state.filter)
|
|
87
|
+
return { ...state, filter: undefined, cursor: 0, scroll: 0 };
|
|
88
|
+
if (state.view !== "Projects" && state.project) {
|
|
89
|
+
return { ...state, view: "Projects", project: undefined, cursor: 0, scroll: 0 };
|
|
90
|
+
}
|
|
91
|
+
return null; // exit menu
|
|
92
|
+
}
|
|
93
|
+
// Health shortcut
|
|
94
|
+
case "h":
|
|
95
|
+
if (state.view === "Health")
|
|
96
|
+
return { ...state, view: "Projects", cursor: 0, scroll: 0 };
|
|
97
|
+
return { ...state, view: "Health", cursor: 0, scroll: 0 };
|
|
98
|
+
default:
|
|
99
|
+
return state;
|
|
100
|
+
}
|
|
101
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phren/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.57",
|
|
4
4
|
"description": "Knowledge layer for AI agents — CLI, MCP server, and data layer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"./data/access": "./dist/data/access.js",
|
|
16
16
|
"./data/tasks": "./dist/data/tasks.js",
|
|
17
17
|
"./core/finding": "./dist/core/finding.js",
|
|
18
|
-
"./session/utils": "./dist/session/utils.js"
|
|
18
|
+
"./session/utils": "./dist/session/utils.js",
|
|
19
|
+
"./shell/render-api": "./dist/shell/render-api.js"
|
|
19
20
|
},
|
|
20
21
|
"files": [
|
|
21
22
|
"dist",
|