@phren/cli 0.0.50 → 0.0.52

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.
@@ -15,6 +15,19 @@ import { runSearch, runFragmentSearch, parseFragmentSearchArgs, runRelatedDocs,
15
15
  import { resolveRuntimeProfile } from "../runtime-profile.js";
16
16
  import { getProjectConsolidationStatus, CONSOLIDATION_ENTRY_THRESHOLD } from "../content/validate.js";
17
17
  import { listAllSessions } from "../tools/session.js";
18
+ function resolveProjectStorePath(phrenPath, project) {
19
+ try {
20
+ const { getNonPrimaryStores } = require("../store-registry.js");
21
+ if (fs.existsSync(path.join(phrenPath, project)))
22
+ return phrenPath;
23
+ for (const store of getNonPrimaryStores(phrenPath)) {
24
+ if (fs.existsSync(path.join(store.path, project)))
25
+ return store.path;
26
+ }
27
+ }
28
+ catch { /* fall through */ }
29
+ return phrenPath;
30
+ }
18
31
  async function runAndPrint(fn) {
19
32
  const result = await fn();
20
33
  if (result.lines.length > 0)
@@ -69,7 +82,8 @@ export async function handleTruths(project) {
69
82
  process.exit(1);
70
83
  }
71
84
  const phrenPath = getPhrenPath();
72
- const truthsPath = path.join(phrenPath, project, "truths.md");
85
+ const storePath = resolveProjectStorePath(phrenPath, project);
86
+ const truthsPath = path.join(storePath, project, "truths.md");
73
87
  if (!fs.existsSync(truthsPath)) {
74
88
  console.log(`No truths pinned for "${project}" yet.`);
75
89
  console.log(`\nPin one: phren pin ${project} "your truth here"`);
@@ -375,7 +389,8 @@ export async function handleConsolidationStatus(args) {
375
389
  ? (() => {
376
390
  if (!isValidProjectName(project))
377
391
  return null;
378
- const dir = path.join(phrenPath, project);
392
+ const storePath = resolveProjectStorePath(phrenPath, project);
393
+ const dir = path.join(storePath, project);
379
394
  return fs.existsSync(dir) ? [dir] : [];
380
395
  })()
381
396
  : getProjectDirs(phrenPath, profile);
@@ -79,7 +79,7 @@ export async function runCliCommand(command, args) {
79
79
  case "tasks":
80
80
  return handleTaskView(getProfile());
81
81
  case "sessions":
82
- return handleSessionsView(args);
82
+ return await handleSessionsView(args);
83
83
  case "task":
84
84
  return handleTaskNamespace(args);
85
85
  case "finding":
@@ -4,6 +4,19 @@ import { execFileSync } from "child_process";
4
4
  import { expandHomePath, findArchivedProjectNameCaseInsensitive, findProjectNameCaseInsensitive, getPhrenPath, getProjectDirs, homePath, hookConfigPath, normalizeProjectNameForCreate, readRootManifest, } from "../shared.js";
5
5
  import { isValidProjectName, errorMessage } from "../utils.js";
6
6
  import { logger } from "../logger.js";
7
+ function resolveProjectStorePath(phrenPath, project) {
8
+ try {
9
+ const { getNonPrimaryStores } = require("../store-registry.js");
10
+ if (fs.existsSync(path.join(phrenPath, project)))
11
+ return phrenPath;
12
+ for (const store of getNonPrimaryStores(phrenPath)) {
13
+ if (fs.existsSync(path.join(store.path, project)))
14
+ return store.path;
15
+ }
16
+ }
17
+ catch { /* fall through */ }
18
+ return phrenPath;
19
+ }
7
20
  import { readInstallPreferences, writeInstallPreferences } from "../init/preferences.js";
8
21
  import { buildSkillManifest, findLocalSkill, findSkill, getAllSkills } from "../skill/registry.js";
9
22
  import { detectSkillCollisions } from "../link/skills.js";
@@ -252,10 +265,17 @@ export function handleHooksNamespace(args) {
252
265
  const hooksEnabled = prefs.hooksEnabled !== false;
253
266
  const toolPrefs = prefs.hookTools && typeof prefs.hookTools === "object" ? prefs.hookTools : {};
254
267
  const project = getOptionValue(args.slice(1), "--project");
255
- if (project && (!isValidProjectName(project) || !fs.existsSync(path.join(phrenPath, project)))) {
268
+ if (project && !isValidProjectName(project)) {
256
269
  console.error(`Project "${project}" not found.`);
257
270
  process.exit(1);
258
271
  }
272
+ if (project) {
273
+ const storePath = resolveProjectStorePath(phrenPath, project);
274
+ if (!fs.existsSync(path.join(storePath, project))) {
275
+ console.error(`Project "${project}" not found.`);
276
+ process.exit(1);
277
+ }
278
+ }
259
279
  const rows = HOOK_TOOLS.map((tool) => ({
260
280
  tool,
261
281
  hookType: "lifecycle",
@@ -663,7 +683,8 @@ export async function handleProjectsNamespace(args, profile) {
663
683
  process.exit(1);
664
684
  }
665
685
  const phrenPath = getPhrenPath();
666
- const projectDir = path.join(phrenPath, name);
686
+ const storePath = resolveProjectStorePath(phrenPath, name);
687
+ const projectDir = path.join(storePath, name);
667
688
  if (!fs.existsSync(projectDir)) {
668
689
  console.error(`Project "${name}" not found.`);
669
690
  process.exit(1);
@@ -673,16 +694,16 @@ export async function handleProjectsNamespace(args, profile) {
673
694
  const summaryPath = path.join(projectDir, "summary.md");
674
695
  if (fs.existsSync(summaryPath))
675
696
  exported.summary = fs.readFileSync(summaryPath, "utf8");
676
- const learningsResult = readFindings(phrenPath, name);
697
+ const learningsResult = readFindings(storePath, name);
677
698
  if (learningsResult.ok)
678
699
  exported.learnings = learningsResult.data;
679
700
  const findingsPath = path.join(projectDir, "FINDINGS.md");
680
701
  if (fs.existsSync(findingsPath))
681
702
  exported.findingsRaw = fs.readFileSync(findingsPath, "utf8");
682
- const taskResult = readTasks(phrenPath, name);
703
+ const taskResult = readTasks(storePath, name);
683
704
  if (taskResult.ok) {
684
705
  exported.task = taskResult.data.items;
685
- const taskRawPath = resolveTaskFilePath(phrenPath, name);
706
+ const taskRawPath = resolveTaskFilePath(storePath, name);
686
707
  if (taskRawPath && fs.existsSync(taskRawPath))
687
708
  exported.taskRaw = fs.readFileSync(taskRawPath, "utf8");
688
709
  }
@@ -799,8 +820,9 @@ export async function handleProjectsNamespace(args, profile) {
799
820
  const phrenPath = getPhrenPath();
800
821
  if (subcommand === "archive") {
801
822
  const activeProject = findProjectNameCaseInsensitive(phrenPath, name);
802
- const projectDir = activeProject ? path.join(phrenPath, activeProject) : path.join(phrenPath, name);
803
- const archiveDir = path.join(phrenPath, `${activeProject ?? name}.archived`);
823
+ const storePath = resolveProjectStorePath(phrenPath, activeProject ?? name);
824
+ const projectDir = activeProject ? path.join(storePath, activeProject) : path.join(storePath, name);
825
+ const archiveDir = path.join(storePath, `${activeProject ?? name}.archived`);
804
826
  if (!fs.existsSync(projectDir)) {
805
827
  console.error(`Project "${name}" not found.`);
806
828
  process.exit(1);
@@ -826,8 +848,9 @@ export async function handleProjectsNamespace(args, profile) {
826
848
  process.exit(1);
827
849
  }
828
850
  const archivedProject = findArchivedProjectNameCaseInsensitive(phrenPath, name);
829
- const projectDir = path.join(phrenPath, archivedProject ?? name);
830
- const archiveDir = path.join(phrenPath, `${archivedProject ?? name}.archived`);
851
+ const storePath = resolveProjectStorePath(phrenPath, archivedProject ?? name);
852
+ const projectDir = path.join(storePath, archivedProject ?? name);
853
+ const archiveDir = path.join(storePath, `${archivedProject ?? name}.archived`);
831
854
  if (!fs.existsSync(archiveDir)) {
832
855
  const available = fs.readdirSync(phrenPath)
833
856
  .filter((e) => e.endsWith(".archived"))
@@ -1323,8 +1346,10 @@ export async function handleFindingNamespace(args) {
1323
1346
  console.error("Usage: phren finding list <project>");
1324
1347
  process.exit(1);
1325
1348
  }
1349
+ const phrenPath = getPhrenPath();
1326
1350
  const { readFindings } = await import("../data/access.js");
1327
- const result = readFindings(getPhrenPath(), project);
1351
+ const storePath = resolveProjectStorePath(phrenPath, project);
1352
+ const result = readFindings(storePath, project);
1328
1353
  if (!result.ok) {
1329
1354
  console.error(result.error);
1330
1355
  process.exit(1);
@@ -49,7 +49,7 @@ export function handleTaskView(profile) {
49
49
  }
50
50
  console.log(`\n${totalActive} active, ${totalQueue} queued across ${docs.length} project(s).`);
51
51
  }
52
- export function handleSessionsView(args) {
52
+ export async function handleSessionsView(args) {
53
53
  const phrenPath = getPhrenPath();
54
54
  const sessionId = args[0];
55
55
  if (sessionId) {
@@ -60,7 +60,7 @@ export function handleSessionsView(args) {
60
60
  console.error(`Session "${sessionId}" not found.`);
61
61
  process.exit(1);
62
62
  }
63
- const artifacts = getSessionArtifacts(phrenPath, session.sessionId);
63
+ const artifacts = await getSessionArtifacts(phrenPath, session.sessionId);
64
64
  console.log(`Session: ${session.sessionId.slice(0, 8)}`);
65
65
  console.log(`Project: ${session.project ?? "—"}`);
66
66
  console.log(`Started: ${session.startedAt.slice(0, 16).replace("T", " ")}`);
@@ -74,6 +74,24 @@ export function checkConsolidationNeeded(phrenPath, profile) {
74
74
  results.push(status);
75
75
  }
76
76
  }
77
+ // Include projects from team stores
78
+ try {
79
+ const storeRegistry = require("../store-registry.js");
80
+ const { getNonPrimaryStores } = storeRegistry;
81
+ for (const store of getNonPrimaryStores(phrenPath)) {
82
+ if (!fs.existsSync(store.path))
83
+ continue;
84
+ for (const dir of getProjectDirs(store.path)) {
85
+ const status = getProjectConsolidationStatus(dir);
86
+ if (status && status.recommended) {
87
+ results.push(status);
88
+ }
89
+ }
90
+ }
91
+ }
92
+ catch {
93
+ // store-registry not available or error loading, continue with primary only
94
+ }
77
95
  return results;
78
96
  }
79
97
  /**
@@ -559,6 +559,7 @@ export function readReviewQueueAcrossProjects(phrenPath, profile) {
559
559
  Conflicts: 2,
560
560
  };
561
561
  const items = [];
562
+ const seen = new Set(projects);
562
563
  for (const project of projects) {
563
564
  const result = readReviewQueue(phrenPath, project);
564
565
  if (!result.ok)
@@ -567,6 +568,32 @@ export function readReviewQueueAcrossProjects(phrenPath, profile) {
567
568
  items.push({ project, ...item });
568
569
  }
569
570
  }
571
+ // Include projects from team stores
572
+ try {
573
+ const storeRegistry = require("../store-registry.js");
574
+ const { getNonPrimaryStores } = storeRegistry;
575
+ for (const store of getNonPrimaryStores(phrenPath)) {
576
+ if (!fs.existsSync(store.path))
577
+ continue;
578
+ const storeDirs = getProjectDirs(store.path)
579
+ .map((d) => path.basename(d))
580
+ .filter((p) => p !== "global");
581
+ for (const storeProject of storeDirs) {
582
+ if (seen.has(storeProject))
583
+ continue;
584
+ seen.add(storeProject);
585
+ const result = readReviewQueue(store.path, storeProject);
586
+ if (!result.ok)
587
+ continue;
588
+ for (const item of result.data) {
589
+ items.push({ project: storeProject, ...item });
590
+ }
591
+ }
592
+ }
593
+ }
594
+ catch {
595
+ // store-registry not available or error loading, continue with primary only
596
+ }
570
597
  items.sort((a, b) => {
571
598
  const aDate = a.date === "unknown" ? "" : a.date;
572
599
  const bDate = b.date === "unknown" ? "" : b.date;
@@ -352,9 +352,11 @@ export function readTasks(phrenPath, project) {
352
352
  return phrenOk(parseTaskContent(project, taskPath, content));
353
353
  }
354
354
  export function readTasksAcrossProjects(phrenPath, profile) {
355
- const projects = getProjectDirs(phrenPath, profile).map((dir) => path.basename(dir)).sort();
356
355
  const result = [];
357
- for (const project of projects) {
356
+ const seen = new Set();
357
+ // Primary store projects (with profile filtering)
358
+ const primaryProjects = getProjectDirs(phrenPath, profile).map((dir) => path.basename(dir)).sort();
359
+ for (const project of primaryProjects) {
358
360
  const file = canonicalTaskFilePath(phrenPath, project);
359
361
  if (!file || !fs.existsSync(file))
360
362
  continue;
@@ -362,7 +364,30 @@ export function readTasksAcrossProjects(phrenPath, profile) {
362
364
  if (!parsed.ok)
363
365
  continue;
364
366
  result.push(parsed.data);
367
+ seen.add(project);
365
368
  }
369
+ // Non-primary store projects (no profile — team stores don't have profiles)
370
+ try {
371
+ const { getNonPrimaryStores } = require("../store-registry.js");
372
+ for (const store of getNonPrimaryStores(phrenPath)) {
373
+ if (!fs.existsSync(store.path))
374
+ continue;
375
+ const storeProjects = getProjectDirs(store.path).map((dir) => path.basename(dir));
376
+ for (const project of storeProjects) {
377
+ if (seen.has(project))
378
+ continue;
379
+ seen.add(project);
380
+ const file = canonicalTaskFilePath(store.path, project);
381
+ if (!file || !fs.existsSync(file))
382
+ continue;
383
+ const parsed = readTasks(store.path, project);
384
+ if (!parsed.ok)
385
+ continue;
386
+ result.push(parsed.data);
387
+ }
388
+ }
389
+ }
390
+ catch { /* store-registry not available — primary only */ }
366
391
  return result;
367
392
  }
368
393
  export function resolveTaskItem(phrenPath, project, match) {