@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.
@@ -579,96 +579,7 @@ export function renderProjectReferenceEnhancementScript(authToken) {
579
579
  })();`;
580
580
  }
581
581
  export function renderReviewQueueEditSyncScript() {
582
- return `(function() {
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, '&amp;')
613
- .replace(/</g, '&lt;')
614
- .replace(/>/g, '&gt;')
615
- .replace(/"/g, '&quot;');
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 { PhrenError, computePhrenLiveStateToken, getProjectDirs, } from "./shared.js";
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));
@@ -134,7 +134,7 @@ let cachedPhrenPath;
134
134
  let cachedPhrenPathKey;
135
135
  export function findPhrenPath() {
136
136
  const cacheKey = [
137
- ((process.env.PHREN_PATH || 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 || process.env.PHREN_PATH)?.trim();
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 || process.env.PHREN_PATH) ?? ""),
173
+ ((process.env.PHREN_PATH) ?? ""),
174
174
  process.env.HOME ?? "",
175
175
  process.env.USERPROFILE ?? "",
176
176
  process.cwd(),
@@ -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`)} (:mq approve|reject)`);
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", "mq approve", "mq reject",
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
- ":mq approve", ":mq reject", ":mq edit", ":machine map",
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("[ a approve · d reject ]")}`);
625
+ host.setMessage(` ${style.dim(item.id ?? "")} ${item.text} ${style.dim("[ read-only ]")}`);
644
626
  }
645
627
  break;
646
628
  case "Skills":
@@ -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("a")} ${d("approve")} ${k("r")} ${d("reject")} ${k("e")} ${d("edit")}`,
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(":mq approve|reject|edit <id>")}`,
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")}`,
@@ -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("a")} ${d("keep")}`, `${k("d")} ${d("discard")}`, `${k("e")} ${d("edit")}`],
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.7",
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