@phren/cli 0.0.7 → 0.0.9
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/icon.svg +416 -0
- package/mcp/dist/capabilities/mcp.js +5 -5
- package/mcp/dist/capabilities/vscode.js +3 -3
- package/mcp/dist/cli-actions.js +113 -3
- package/mcp/dist/cli-namespaces.js +497 -4
- package/mcp/dist/cli.js +7 -1
- package/mcp/dist/data-tasks.js +16 -1
- package/mcp/dist/entrypoint.js +6 -0
- package/mcp/dist/init-config.js +6 -6
- package/mcp/dist/init.js +29 -7
- package/mcp/dist/mcp-finding.js +26 -1
- package/mcp/dist/mcp-tasks.js +2 -1
- package/mcp/dist/memory-ui-assets.js +37 -1
- package/mcp/dist/memory-ui-graph.js +19 -5
- package/mcp/dist/memory-ui-page.js +7 -30
- package/mcp/dist/memory-ui-scripts.js +1 -103
- package/mcp/dist/memory-ui-server.js +1 -82
- package/mcp/dist/phren-paths.js +3 -3
- package/mcp/dist/shell-input.js +4 -22
- package/mcp/dist/shell-render.js +2 -2
- package/mcp/dist/shell-view.js +1 -2
- package/mcp/dist/shell.js +0 -5
- package/mcp/dist/tool-registry.js +1 -0
- package/package.json +2 -1
- package/skills/docs.md +170 -0
|
@@ -579,96 +579,7 @@ export function renderProjectReferenceEnhancementScript(authToken) {
|
|
|
579
579
|
})();`;
|
|
580
580
|
}
|
|
581
581
|
export function renderReviewQueueEditSyncScript() {
|
|
582
|
-
return
|
|
583
|
-
function normalizeQueueText(raw) {
|
|
584
|
-
return String(raw == null ? '' : raw)
|
|
585
|
-
.replace(/\\r\\n?/g, '\\n')
|
|
586
|
-
.replace(/\\0/g, ' ')
|
|
587
|
-
.replace(/<!--[\\s\\S]*?-->/g, ' ')
|
|
588
|
-
.replace(/\\\\[nrt]/g, ' ')
|
|
589
|
-
.replace(/\\\\\"/g, '"')
|
|
590
|
-
.replace(/\\\\\\\\/g, '\\\\')
|
|
591
|
-
.replace(/\\n+/g, ' ')
|
|
592
|
-
.replace(/\\s+/g, ' ')
|
|
593
|
-
.trim();
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
function rebuildEditedQueueLine(line, newText) {
|
|
597
|
-
var dateMatch = String(line || '').match(/^- \\[(\\d{4}-\\d{2}-\\d{2})\\]/);
|
|
598
|
-
var confidenceMatch = String(line || '').match(/\\[confidence\\s+([01](?:\\.\\d+)?)\\]/i);
|
|
599
|
-
var normalizedText = normalizeQueueText(newText);
|
|
600
|
-
var date = dateMatch ? dateMatch[1] : new Date().toISOString().slice(0, 10);
|
|
601
|
-
var confidencePart = confidenceMatch
|
|
602
|
-
? ' [confidence ' + Number(confidenceMatch[1]).toFixed(2) + ']'
|
|
603
|
-
: '';
|
|
604
|
-
return {
|
|
605
|
-
text: normalizedText,
|
|
606
|
-
line: '- [' + date + '] ' + normalizedText + confidencePart
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function escapeHtml(text) {
|
|
611
|
-
return String(text)
|
|
612
|
-
.replace(/&/g, '&')
|
|
613
|
-
.replace(/</g, '<')
|
|
614
|
-
.replace(/>/g, '>')
|
|
615
|
-
.replace(/"/g, '"');
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
function syncEditedCard(card, project, nextLine, nextText) {
|
|
619
|
-
if (!card || !project || !nextLine) return;
|
|
620
|
-
card.setAttribute('data-key', project + '\\\\x00' + nextLine);
|
|
621
|
-
card.setAttribute('data-project', project);
|
|
622
|
-
var approveBtn = card.querySelector('.btn-approve');
|
|
623
|
-
if (approveBtn) {
|
|
624
|
-
approveBtn.setAttribute('data-project', project);
|
|
625
|
-
approveBtn.setAttribute('data-line', nextLine);
|
|
626
|
-
}
|
|
627
|
-
var rejectBtn = card.querySelector('.btn-reject');
|
|
628
|
-
if (rejectBtn) {
|
|
629
|
-
rejectBtn.setAttribute('data-project', project);
|
|
630
|
-
rejectBtn.setAttribute('data-line', nextLine);
|
|
631
|
-
}
|
|
632
|
-
var editForm = card.querySelector('.review-card-edit form');
|
|
633
|
-
if (editForm) {
|
|
634
|
-
editForm.setAttribute('data-project', project);
|
|
635
|
-
editForm.setAttribute('data-line', nextLine);
|
|
636
|
-
}
|
|
637
|
-
var editTextarea = card.querySelector('textarea[name="new_text"]');
|
|
638
|
-
if (editTextarea) editTextarea.value = nextText;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
function maybeSyncEditedCard(card, project, line, newText, attemptsLeft) {
|
|
642
|
-
if (!card || !project) return;
|
|
643
|
-
var rebuilt = rebuildEditedQueueLine(line, newText);
|
|
644
|
-
var textEl = card.querySelector('.review-card-text');
|
|
645
|
-
var editSection = card.querySelector('.review-card-edit');
|
|
646
|
-
if (editSection && editSection.style.display === 'none') {
|
|
647
|
-
if (textEl) textEl.innerHTML = escapeHtml(rebuilt.text);
|
|
648
|
-
syncEditedCard(card, project, rebuilt.line, rebuilt.text);
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
if (attemptsLeft > 0) {
|
|
652
|
-
setTimeout(function() {
|
|
653
|
-
maybeSyncEditedCard(card, project, line, newText, attemptsLeft - 1);
|
|
654
|
-
}, 150);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
document.addEventListener('submit', function(event) {
|
|
659
|
-
var form = event.target;
|
|
660
|
-
if (!form || typeof form.getAttribute !== 'function' || typeof form.querySelector !== 'function') return;
|
|
661
|
-
if (!form.closest || !form.closest('.review-card-edit')) return;
|
|
662
|
-
var project = form.getAttribute('data-project') || '';
|
|
663
|
-
var line = form.getAttribute('data-line') || '';
|
|
664
|
-
var textarea = form.querySelector('textarea[name="new_text"]');
|
|
665
|
-
var newText = textarea ? textarea.value : '';
|
|
666
|
-
var card = form.closest('.review-card');
|
|
667
|
-
setTimeout(function() {
|
|
668
|
-
maybeSyncEditedCard(card, project, line, newText, 20);
|
|
669
|
-
}, 0);
|
|
670
|
-
}, true);
|
|
671
|
-
})();`;
|
|
582
|
+
return "";
|
|
672
583
|
}
|
|
673
584
|
export function renderTasksAndSettingsScript(authToken) {
|
|
674
585
|
return `(function() {
|
|
@@ -1342,9 +1253,6 @@ export function renderEventWiringScript() {
|
|
|
1342
1253
|
var highlightBtn = document.getElementById('highlight-only-btn');
|
|
1343
1254
|
if (highlightBtn) highlightBtn.addEventListener('click', function() { toggleHighlightOnly(this); });
|
|
1344
1255
|
|
|
1345
|
-
var selectAllCheckbox = document.getElementById('review-select-all-checkbox');
|
|
1346
|
-
if (selectAllCheckbox) selectAllCheckbox.addEventListener('change', function() { toggleSelectAll(this.checked); });
|
|
1347
|
-
|
|
1348
1256
|
// --- Graph controls ---
|
|
1349
1257
|
var graphZoomIn = document.getElementById('graph-zoom-in');
|
|
1350
1258
|
if (graphZoomIn) graphZoomIn.addEventListener('click', function() { graphZoom(1.2); });
|
|
@@ -1363,16 +1271,6 @@ export function renderEventWiringScript() {
|
|
|
1363
1271
|
var sessionsFilterProject = document.getElementById('sessions-filter-project');
|
|
1364
1272
|
if (sessionsFilterProject) sessionsFilterProject.addEventListener('change', function() { loadSessions(); });
|
|
1365
1273
|
|
|
1366
|
-
// --- Batch bar ---
|
|
1367
|
-
var batchApproveBtn = document.getElementById('batch-approve-btn');
|
|
1368
|
-
if (batchApproveBtn) batchApproveBtn.addEventListener('click', function() { batchAction('approve'); });
|
|
1369
|
-
var batchRejectBtn = document.getElementById('batch-reject-btn');
|
|
1370
|
-
if (batchRejectBtn) batchRejectBtn.addEventListener('click', function() { batchAction('reject'); });
|
|
1371
|
-
var batchTagSelect = document.getElementById('batch-tag-select');
|
|
1372
|
-
if (batchTagSelect) batchTagSelect.addEventListener('change', function() { if(this.value){batchActionByTag(this.value,'approve');this.value='';} });
|
|
1373
|
-
var batchCancelBtn = document.getElementById('batch-cancel-btn');
|
|
1374
|
-
if (batchCancelBtn) batchCancelBtn.addEventListener('click', function() { clearBatchSelection(); });
|
|
1375
|
-
|
|
1376
1274
|
// --- Command palette ---
|
|
1377
1275
|
var cmdpal = document.getElementById('cmdpal');
|
|
1378
1276
|
if (cmdpal) cmdpal.addEventListener('click', function(e) { closeCmdPal(e); });
|
|
@@ -5,7 +5,7 @@ import * as fs from "fs";
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import * as querystring from "querystring";
|
|
7
7
|
import { spawn, execFileSync } from "child_process";
|
|
8
|
-
import {
|
|
8
|
+
import { computePhrenLiveStateToken, getProjectDirs, } from "./shared.js";
|
|
9
9
|
import { editFinding, readReviewQueue, removeFinding, readFindings, addFinding as addFindingStore, readTasksAcrossProjects, addTask as addTaskStore, completeTask as completeTaskStore, removeTask as removeTaskStore, TASKS_FILENAME, } from "./data-access.js";
|
|
10
10
|
import { isValidProjectName, errorMessage } from "./utils.js";
|
|
11
11
|
import { readInstallPreferences, writeInstallPreferences, writeGovernanceInstallPreferences } from "./init-preferences.js";
|
|
@@ -251,40 +251,6 @@ function readProjectQueue(phrenPath, profile) {
|
|
|
251
251
|
}
|
|
252
252
|
return items;
|
|
253
253
|
}
|
|
254
|
-
function runQueueAction(_phrenPath, pathname, _project, _line, _newText) {
|
|
255
|
-
if (pathname === "/api/approve" || pathname === "/approve")
|
|
256
|
-
return { ok: false, error: "Queue approval has been removed. Use the review queue as a read-only reference." };
|
|
257
|
-
if (pathname === "/api/reject" || pathname === "/reject")
|
|
258
|
-
return { ok: false, error: "Queue rejection has been removed. Use the review queue as a read-only reference." };
|
|
259
|
-
if (pathname === "/api/edit" || pathname === "/edit")
|
|
260
|
-
return { ok: false, error: "Queue editing has been removed. Use the review queue as a read-only reference." };
|
|
261
|
-
return { ok: false, error: "unknown action" };
|
|
262
|
-
}
|
|
263
|
-
function handleLegacyQueueActionResult(res, result) {
|
|
264
|
-
if (result.ok) {
|
|
265
|
-
res.writeHead(302, { location: "/" });
|
|
266
|
-
res.end();
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const code = result.code;
|
|
270
|
-
if (code === PhrenError.PERMISSION_DENIED || result.error.includes("requires maintainer/admin role")) {
|
|
271
|
-
res.writeHead(403, { "content-type": "text/plain; charset=utf-8" });
|
|
272
|
-
res.end(result.error);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
if (code === PhrenError.NOT_FOUND) {
|
|
276
|
-
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
277
|
-
res.end(result.error);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
if (code === PhrenError.INVALID_PROJECT_NAME || code === PhrenError.EMPTY_INPUT) {
|
|
281
|
-
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
282
|
-
res.end(result.error);
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
|
|
286
|
-
res.end(result.error);
|
|
287
|
-
}
|
|
288
254
|
function parseTopicsPayload(raw) {
|
|
289
255
|
try {
|
|
290
256
|
const parsed = JSON.parse(raw);
|
|
@@ -1024,53 +990,6 @@ export function createWebUiHttpServer(phrenPath, renderPage, profile, opts) {
|
|
|
1024
990
|
res.end(JSON.stringify({ ok: true, token }));
|
|
1025
991
|
return;
|
|
1026
992
|
}
|
|
1027
|
-
if (req.method === "POST" && ["/api/approve", "/api/reject", "/api/edit"].includes(pathname)) {
|
|
1028
|
-
void readFormBody(req, res).then((parsed) => {
|
|
1029
|
-
if (!parsed)
|
|
1030
|
-
return;
|
|
1031
|
-
if (!requirePostAuth(req, res, url, parsed, authToken, true))
|
|
1032
|
-
return;
|
|
1033
|
-
if (!requireCsrf(res, parsed, csrfTokens, true))
|
|
1034
|
-
return;
|
|
1035
|
-
const project = String(parsed.project || "");
|
|
1036
|
-
const line = String(parsed.line || "");
|
|
1037
|
-
const newText = String(parsed.new_text || "");
|
|
1038
|
-
if (!project || !line || !isValidProjectName(project)) {
|
|
1039
|
-
res.writeHead(400, { "content-type": "application/json" });
|
|
1040
|
-
res.end(JSON.stringify({ ok: false, error: "Missing or invalid project/line" }));
|
|
1041
|
-
return;
|
|
1042
|
-
}
|
|
1043
|
-
const result = runQueueAction(phrenPath, pathname, project, line, newText);
|
|
1044
|
-
res.writeHead(200, { "content-type": "application/json" });
|
|
1045
|
-
res.end(JSON.stringify({ ok: result.ok, error: result.ok ? undefined : result.error }));
|
|
1046
|
-
});
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
if (req.method === "POST" && ["/approve", "/reject", "/edit"].includes(pathname)) {
|
|
1050
|
-
void readFormBody(req, res).then((parsed) => {
|
|
1051
|
-
if (!parsed)
|
|
1052
|
-
return;
|
|
1053
|
-
if (!requirePostAuth(req, res, url, parsed, authToken))
|
|
1054
|
-
return;
|
|
1055
|
-
if (!requireCsrf(res, parsed, csrfTokens))
|
|
1056
|
-
return;
|
|
1057
|
-
const project = String(parsed.project || "");
|
|
1058
|
-
const line = String(parsed.line || "");
|
|
1059
|
-
const newText = String(parsed.new_text || "");
|
|
1060
|
-
if (!project || !line) {
|
|
1061
|
-
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
1062
|
-
res.end("Missing project/line");
|
|
1063
|
-
return;
|
|
1064
|
-
}
|
|
1065
|
-
if (!isValidProjectName(project)) {
|
|
1066
|
-
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
1067
|
-
res.end("Invalid project name");
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
handleLegacyQueueActionResult(res, runQueueAction(phrenPath, pathname, project, line, newText));
|
|
1071
|
-
});
|
|
1072
|
-
return;
|
|
1073
|
-
}
|
|
1074
993
|
// GET /api/findings/:project — list findings for a project
|
|
1075
994
|
if (req.method === "GET" && pathname.startsWith("/api/findings/")) {
|
|
1076
995
|
const project = decodeURIComponent(pathname.slice("/api/findings/".length));
|
package/mcp/dist/phren-paths.js
CHANGED
|
@@ -134,7 +134,7 @@ let cachedPhrenPath;
|
|
|
134
134
|
let cachedPhrenPathKey;
|
|
135
135
|
export function findPhrenPath() {
|
|
136
136
|
const cacheKey = [
|
|
137
|
-
((process.env.PHREN_PATH
|
|
137
|
+
((process.env.PHREN_PATH) ?? ""),
|
|
138
138
|
process.env.HOME ?? "",
|
|
139
139
|
process.env.USERPROFILE ?? "",
|
|
140
140
|
process.cwd(),
|
|
@@ -142,7 +142,7 @@ export function findPhrenPath() {
|
|
|
142
142
|
if (cachedPhrenPath !== undefined && cachedPhrenPathKey === cacheKey)
|
|
143
143
|
return cachedPhrenPath;
|
|
144
144
|
cachedPhrenPathKey = cacheKey;
|
|
145
|
-
const envVal = (process.env.PHREN_PATH
|
|
145
|
+
const envVal = (process.env.PHREN_PATH)?.trim();
|
|
146
146
|
if (envVal) {
|
|
147
147
|
const resolved = path.resolve(expandHomePath(envVal));
|
|
148
148
|
cachedPhrenPath = isPhrenRootCandidate(resolved) ? resolved : null;
|
|
@@ -170,7 +170,7 @@ export function ensurePhrenPath() {
|
|
|
170
170
|
});
|
|
171
171
|
cachedPhrenPath = defaultPath;
|
|
172
172
|
cachedPhrenPathKey = [
|
|
173
|
-
((process.env.PHREN_PATH
|
|
173
|
+
((process.env.PHREN_PATH) ?? ""),
|
|
174
174
|
process.env.HOME ?? "",
|
|
175
175
|
process.env.USERPROFILE ?? "",
|
|
176
176
|
process.cwd(),
|
package/mcp/dist/shell-input.js
CHANGED
|
@@ -274,14 +274,6 @@ export async function executePalette(host, input) {
|
|
|
274
274
|
host.setMessage(" Usage: :find add <text> | :find remove <id|match>");
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
|
-
if (command === "mq") {
|
|
278
|
-
const project = host.ensureProjectSelected();
|
|
279
|
-
if (!project)
|
|
280
|
-
return;
|
|
281
|
-
const action = (parts[1] || "").toLowerCase();
|
|
282
|
-
host.setMessage(" Queue approve/reject/edit have been removed. The review queue is now read-only.");
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
277
|
if (command === "machine" && parts[1]?.toLowerCase() === "map") {
|
|
286
278
|
if (parts.length < 4) {
|
|
287
279
|
host.setMessage(" Usage: :machine map <hostname> <profile>");
|
|
@@ -409,7 +401,7 @@ export async function executePalette(host, input) {
|
|
|
409
401
|
if (queueResult.ok) {
|
|
410
402
|
const conflictItems = queueResult.data.filter((q) => q.section === "Conflicts");
|
|
411
403
|
if (conflictItems.length) {
|
|
412
|
-
lines.push(` ${style.yellow(`${conflictItems.length} conflict(s) in Review Queue`)} (:
|
|
404
|
+
lines.push(` ${style.yellow(`${conflictItems.length} conflict(s) in Review Queue`)} (inspect in :review queue)`);
|
|
413
405
|
}
|
|
414
406
|
}
|
|
415
407
|
}
|
|
@@ -473,8 +465,7 @@ function suggestCommand(input) {
|
|
|
473
465
|
const known = [
|
|
474
466
|
"help", "projects", "tasks", "task", "findings", "review queue", "machines", "health",
|
|
475
467
|
"open", "search", "add", "complete", "move", "reprioritize", "pin", "unpin", "context",
|
|
476
|
-
"work next", "tidy", "find add", "find remove", "
|
|
477
|
-
"mq edit", "machine map", "profile add-project", "profile remove-project",
|
|
468
|
+
"work next", "tidy", "find add", "find remove", "machine map", "profile add-project", "profile remove-project",
|
|
478
469
|
"run fix", "relink", "rerun hooks", "update", "govern", "consolidate",
|
|
479
470
|
"undo", "diff", "conflicts", "reset",
|
|
480
471
|
];
|
|
@@ -494,7 +485,7 @@ export function completeInput(line, phrenPath, profile, state) {
|
|
|
494
485
|
":projects", ":tasks", ":task", ":findings", ":review queue", ":machines", ":health",
|
|
495
486
|
":open", ":search", ":add", ":complete", ":move", ":reprioritize", ":pin",
|
|
496
487
|
":unpin", ":context", ":work next", ":tidy", ":find add", ":find remove",
|
|
497
|
-
":
|
|
488
|
+
":machine map",
|
|
498
489
|
":profile add-project", ":profile remove-project",
|
|
499
490
|
":run fix", ":relink", ":rerun hooks", ":update", ":govern", ":consolidate",
|
|
500
491
|
":undo", ":diff", ":conflicts", ":reset", ":help",
|
|
@@ -528,15 +519,6 @@ export function completeInput(line, phrenPath, profile, state) {
|
|
|
528
519
|
...result.data.items.Done,
|
|
529
520
|
].map((item) => `:${cmd} ${item.id}`);
|
|
530
521
|
}
|
|
531
|
-
if (cmd === "mq" && ["approve", "reject", "edit"].includes((parts[1] || "").toLowerCase())) {
|
|
532
|
-
const project = state.project;
|
|
533
|
-
if (!project)
|
|
534
|
-
return [];
|
|
535
|
-
const result = readReviewQueue(phrenPath, project);
|
|
536
|
-
if (!result.ok)
|
|
537
|
-
return [];
|
|
538
|
-
return result.data.map((item) => `:mq ${parts[1].toLowerCase()} ${item.id}`);
|
|
539
|
-
}
|
|
540
522
|
if (cmd === "find" && (parts[1] || "").toLowerCase() === "remove") {
|
|
541
523
|
const project = state.project;
|
|
542
524
|
if (!project)
|
|
@@ -640,7 +622,7 @@ async function activateSelected(host) {
|
|
|
640
622
|
break;
|
|
641
623
|
case "Review Queue":
|
|
642
624
|
if (item.text) {
|
|
643
|
-
host.setMessage(` ${style.dim(item.id ?? "")} ${item.text} ${style.dim("[
|
|
625
|
+
host.setMessage(` ${style.dim(item.id ?? "")} ${item.text} ${style.dim("[ read-only ]")}`);
|
|
644
626
|
}
|
|
645
627
|
break;
|
|
646
628
|
case "Skills":
|
package/mcp/dist/shell-render.js
CHANGED
|
@@ -182,7 +182,7 @@ export function shellHelpText() {
|
|
|
182
182
|
` ${style.bold("Projects")} ${k("↵")} ${d("open project tasks")} ${k("i")} ${d("cycle intro mode")}`,
|
|
183
183
|
` ${style.bold("Tasks")} ${k("a")} ${d("add task")} ${k("d")} ${d("toggle active/queue")} ${k("↵")} ${d("mark complete")}`,
|
|
184
184
|
` ${style.bold("Fragments")} ${k("a")} ${d("tell phren")} ${k("d")} ${d("delete selected")}`,
|
|
185
|
-
` ${style.bold("Review Queue")} ${k("
|
|
185
|
+
` ${style.bold("Review Queue")} ${k("↵")} ${d("inspect selected item")} ${d("(read-only)")}`,
|
|
186
186
|
` ${style.bold("Skills")} ${k("t")} ${d("toggle enabled")} ${k("d")} ${d("remove")}`,
|
|
187
187
|
"",
|
|
188
188
|
hdr("Palette commands (:cmd)"),
|
|
@@ -195,7 +195,7 @@ export function shellHelpText() {
|
|
|
195
195
|
` ${cmd(":pin <id>")} ${cmd(":unpin <id>")} ${cmd(":work next")} ${cmd(":tidy [keep]")}`,
|
|
196
196
|
` ${cmd(":find add <text>")} ${cmd(":find remove <id|match>")}`,
|
|
197
197
|
` ${cmd(":intro always|once-per-version|off")}`,
|
|
198
|
-
` ${cmd(":
|
|
198
|
+
` ${cmd(":review queue")} ${d("inspect review queue (read-only)")}`,
|
|
199
199
|
` ${cmd(":govern")} ${cmd(":consolidate")} ${cmd(":search <query>")}`,
|
|
200
200
|
` ${cmd(":undo")} ${cmd(":diff")} ${cmd(":conflicts")} ${cmd(":reset")}`,
|
|
201
201
|
` ${cmd(":run fix")} ${cmd(":relink")} ${cmd(":rerun hooks")} ${cmd(":update")}`,
|
package/mcp/dist/shell-view.js
CHANGED
|
@@ -57,7 +57,6 @@ function renderBottomBar(state, navMode, inputCtx, inputBuf) {
|
|
|
57
57
|
add: "add task",
|
|
58
58
|
"learn-add": "add finding",
|
|
59
59
|
"skill-add": "new skill name",
|
|
60
|
-
"mq-edit": "edit Review Queue item",
|
|
61
60
|
};
|
|
62
61
|
const label = labels[inputCtx] || inputCtx;
|
|
63
62
|
return `${sep}\n ${style.boldCyan(label + " ›")} ${inputBuf}${style.cyan("█")}`;
|
|
@@ -66,7 +65,7 @@ function renderBottomBar(state, navMode, inputCtx, inputBuf) {
|
|
|
66
65
|
Projects: [`${k("↵")} ${d("open project")}`, `${k("i")} ${d("intro mode")}`],
|
|
67
66
|
Tasks: [`${k("a")} ${d("add")}`, `${k("↵")} ${d("mark done")}`, `${k("d")} ${d("toggle active")}`],
|
|
68
67
|
Findings: [`${k("a")} ${d("add")}`, `${k("d")} ${d("remove")}`],
|
|
69
|
-
"Review Queue": [`${k("
|
|
68
|
+
"Review Queue": [`${k("↵")} ${d("inspect")}`],
|
|
70
69
|
Skills: [`${k("t")} ${d("toggle")}`, `${k("d")} ${d("remove")}`],
|
|
71
70
|
Hooks: [`${k("a")} ${d("enable")}`, `${k("d")} ${d("disable")}`],
|
|
72
71
|
Health: [`${k("↑↓")} ${d("scroll")}`, `${k("esc")} ${d("back")}`],
|
package/mcp/dist/shell.js
CHANGED
|
@@ -162,11 +162,6 @@ export class PhrenShell {
|
|
|
162
162
|
this.setMessage(` Created skill "${name}" — edit ${dest}`);
|
|
163
163
|
break;
|
|
164
164
|
}
|
|
165
|
-
case "mq-edit": {
|
|
166
|
-
this.setMessage(" Queue editing has been removed. The review queue is now read-only.");
|
|
167
|
-
this.inputMqId = "";
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
165
|
}
|
|
171
166
|
}
|
|
172
167
|
// ── Raw key handling ───────────────────────────────────────────────────
|
|
@@ -12,6 +12,7 @@ const CATEGORY_BY_MODULE = {
|
|
|
12
12
|
"mcp-ops": "Operations and review",
|
|
13
13
|
"mcp-skills": "Skills management",
|
|
14
14
|
"mcp-hooks": "Hooks management",
|
|
15
|
+
"mcp-config": "Configuration",
|
|
15
16
|
"mcp-extract": "Extraction",
|
|
16
17
|
};
|
|
17
18
|
const MODULE_ORDER = Object.keys(CATEGORY_BY_MODULE);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phren/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Knowledge layer for AI agents. Claude remembers you. Phren remembers your work.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"mcp/dist",
|
|
11
|
+
"icon.svg",
|
|
11
12
|
"starter",
|
|
12
13
|
"skills"
|
|
13
14
|
],
|
package/skills/docs.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docs
|
|
3
|
+
description: Update and verify all phren documentation surfaces after code changes.
|
|
4
|
+
dependencies:
|
|
5
|
+
- git
|
|
6
|
+
---
|
|
7
|
+
# phren-docs - Documentation accuracy check and update
|
|
8
|
+
|
|
9
|
+
> Keep all phren documentation surfaces in sync with the code after any change.
|
|
10
|
+
|
|
11
|
+
Invoke this after adding tools, changing CLI commands, bumping versions, or editing hooks. It walks every documentation surface, checks what's stale, and updates `docs/documentation.html` (the canonical public-facing reference).
|
|
12
|
+
|
|
13
|
+
## When to run
|
|
14
|
+
|
|
15
|
+
- After adding, removing, or renaming MCP tools
|
|
16
|
+
- After changing CLI commands or their flags
|
|
17
|
+
- After bumping the version number
|
|
18
|
+
- After changing hook names, events, or behavior
|
|
19
|
+
- Before publishing to npm
|
|
20
|
+
- When the user says "update the docs" or "check the docs"
|
|
21
|
+
|
|
22
|
+
## Documentation surfaces
|
|
23
|
+
|
|
24
|
+
| File | What it contains | What to check |
|
|
25
|
+
|------|-----------------|---------------|
|
|
26
|
+
| `README.md` | Project overview, install steps, quick-start | Tool count, version badge, CLI examples |
|
|
27
|
+
| `CLAUDE.md` | In-repo instructions for Claude | Tool count (heading says "MCP Tools (N)"), CLI command list, key file list |
|
|
28
|
+
| `AGENTS.md` | Agent-facing instructions | Tool count, hook table, CLI commands |
|
|
29
|
+
| `CONTRIBUTING.md` | Dev setup, build/test commands | `npm run build`, `npm test`, publish steps |
|
|
30
|
+
| `CHANGELOG.md` | Release history | Latest version matches `package.json` version |
|
|
31
|
+
| `docs/index.html` | GitHub Pages landing page | Install commands, version references, feature list |
|
|
32
|
+
| `docs/documentation.html` | Full reference doc (primary surface) | Tool count, CLI commands, hook table, env vars table |
|
|
33
|
+
| `docs/api-reference.md` | API / tool reference | Tool signatures, return shapes |
|
|
34
|
+
| `docs/architecture.md` | Data-flow diagrams and architecture | File paths, hook names, flow descriptions |
|
|
35
|
+
| `docs/faq.md` | Common questions and answers | References to commands, file paths |
|
|
36
|
+
| `docs/llms.txt` | Short LLM-friendly summary | Tool count, version, install command |
|
|
37
|
+
| `docs/llms-full.txt` | Full LLM-readable reference | Complete tool list, CLI commands, env vars |
|
|
38
|
+
| `mcp/README.md` | MCP server README | Tool count, server entry point |
|
|
39
|
+
| `vscode-extension/README.md` | VS Code extension README | Feature list, commands |
|
|
40
|
+
|
|
41
|
+
## Step-by-step
|
|
42
|
+
|
|
43
|
+
### 1. Read the source of truth
|
|
44
|
+
|
|
45
|
+
The source of truth for counts and signatures lives in the code, not the docs:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Count exported MCP tools in index.ts
|
|
49
|
+
grep -c 'server\.tool(' mcp/src/index.ts
|
|
50
|
+
|
|
51
|
+
# Current version
|
|
52
|
+
node -p "require('./package.json').version"
|
|
53
|
+
|
|
54
|
+
# CLI commands (scan cli.ts / index.ts for subcommand registrations)
|
|
55
|
+
grep 'program\.' mcp/src/cli.ts | head -40
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Record: **tool count**, **version**, and the list of top-level CLI subcommands.
|
|
59
|
+
|
|
60
|
+
### 2. Check each documentation surface
|
|
61
|
+
|
|
62
|
+
For each surface in the table above:
|
|
63
|
+
|
|
64
|
+
1. Read the file
|
|
65
|
+
2. Find every place it mentions a tool count (e.g. "65 tools", "MCP Tools (65)")
|
|
66
|
+
3. Find every place it mentions the version number
|
|
67
|
+
4. Find every CLI command listing
|
|
68
|
+
5. Find the hook table (event names, what each hook does)
|
|
69
|
+
6. Note any stale references (old file paths, renamed tools, removed commands)
|
|
70
|
+
|
|
71
|
+
### 3. Spot-check critical numbers
|
|
72
|
+
|
|
73
|
+
These numbers appear in multiple files and must all agree:
|
|
74
|
+
|
|
75
|
+
| Item | Where to verify |
|
|
76
|
+
|------|----------------|
|
|
77
|
+
| MCP tool count | `mcp/src/index.ts` — count `server.tool(` calls |
|
|
78
|
+
| CLI subcommand count | `mcp/src/cli.ts` — count `program.command(` calls |
|
|
79
|
+
| Version | `package.json` → `version` field |
|
|
80
|
+
| Hook events | `mcp/src/init.ts` — look for hook registration |
|
|
81
|
+
|
|
82
|
+
Run `/parity` if it is installed to automate numeric cross-checking across surfaces.
|
|
83
|
+
|
|
84
|
+
### 4. Update `docs/documentation.html`
|
|
85
|
+
|
|
86
|
+
This is the primary public reference. It must reflect the current state of the code.
|
|
87
|
+
|
|
88
|
+
Sections to verify and update:
|
|
89
|
+
|
|
90
|
+
- **Tool reference table**: every tool name, description, and parameter signature
|
|
91
|
+
- **CLI commands block**: every `phren <subcommand>` with flags and description
|
|
92
|
+
- **Hooks table**: event name, what it runs, what it does
|
|
93
|
+
- **Environment variables table**: variable name, default, description
|
|
94
|
+
- **Version number** in the page title, install command snippets, and any badges
|
|
95
|
+
- **Tool count** in any summary sentence (e.g. "65 MCP tools")
|
|
96
|
+
|
|
97
|
+
When updating the HTML:
|
|
98
|
+
- Keep existing structure and CSS classes — do not restructure the page
|
|
99
|
+
- Update text content only; do not rewrite layout
|
|
100
|
+
- Preserve the `<details>` blocks for env var categories if they exist
|
|
101
|
+
|
|
102
|
+
### 5. Update `docs/llms.txt` and `docs/llms-full.txt`
|
|
103
|
+
|
|
104
|
+
These files are consumed by LLMs directly. Keep them plain text with no HTML.
|
|
105
|
+
|
|
106
|
+
`llms.txt` — short summary (under 60 lines):
|
|
107
|
+
- Tool count
|
|
108
|
+
- Install command
|
|
109
|
+
- One-line description of what phren does
|
|
110
|
+
|
|
111
|
+
`llms-full.txt` — comprehensive reference:
|
|
112
|
+
- All MCP tool signatures with descriptions
|
|
113
|
+
- All CLI commands
|
|
114
|
+
- All environment variables
|
|
115
|
+
- Directory structure
|
|
116
|
+
|
|
117
|
+
### 6. Update `CLAUDE.md` (in-repo)
|
|
118
|
+
|
|
119
|
+
The heading `## MCP Tools (N)` must match the actual tool count. Update N if it changed.
|
|
120
|
+
|
|
121
|
+
The CLI commands block must list every top-level command. Add or remove lines to match.
|
|
122
|
+
|
|
123
|
+
### 7. Sync version references
|
|
124
|
+
|
|
125
|
+
`CHANGELOG.md`: the top entry's version must match `package.json`. If a new version was bumped but the changelog has no entry yet, note it — do not fabricate one.
|
|
126
|
+
|
|
127
|
+
`README.md` and `docs/index.html`: update any hardcoded version strings (badges, `npm install @phren/cli@X.Y.Z`, etc.).
|
|
128
|
+
|
|
129
|
+
### 8. Report
|
|
130
|
+
|
|
131
|
+
After reviewing and updating, output:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
phren-docs
|
|
135
|
+
|
|
136
|
+
Version: 0.0.8
|
|
137
|
+
MCP tools: 65
|
|
138
|
+
CLI subcommands: 22
|
|
139
|
+
|
|
140
|
+
Surfaces checked: 14
|
|
141
|
+
|
|
142
|
+
Changes made:
|
|
143
|
+
- docs/documentation.html: updated tool count (64→65), added new env var PHREN_X
|
|
144
|
+
- CLAUDE.md: updated MCP Tools heading (64→65)
|
|
145
|
+
- docs/llms-full.txt: added PHREN_X to env vars section
|
|
146
|
+
|
|
147
|
+
No changes needed:
|
|
148
|
+
- README.md: version and tool count already correct
|
|
149
|
+
- CHANGELOG.md: top entry matches package.json version
|
|
150
|
+
- mcp/README.md: tool count correct
|
|
151
|
+
|
|
152
|
+
Warnings:
|
|
153
|
+
- docs/faq.md: references `phren init` — command was renamed to `phren link` in v0.0.7
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
List every file checked. Be specific about what changed and what line/section.
|
|
157
|
+
|
|
158
|
+
## What not to do
|
|
159
|
+
|
|
160
|
+
- Do not restructure or reformat documentation for style — only fix accuracy
|
|
161
|
+
- Do not add new sections or features to the docs without user direction
|
|
162
|
+
- Do not fabricate changelog entries for unreleased versions
|
|
163
|
+
- Do not silently skip a surface because it looks "probably fine" — check all of them
|
|
164
|
+
- Do not guess tool counts — always derive from `grep` on the source file
|
|
165
|
+
|
|
166
|
+
## Related skills
|
|
167
|
+
|
|
168
|
+
- `/parity`: numeric cross-check across all documentation surfaces
|
|
169
|
+
- `/consolidate`: surface cross-project patterns before updating architecture docs
|
|
170
|
+
- `/discover`: find gaps in project documentation
|