@phren/cli 0.0.28 → 0.0.33

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.
Files changed (153) hide show
  1. package/mcp/dist/capabilities/cli.js +2 -5
  2. package/mcp/dist/capabilities/mcp.js +5 -8
  3. package/mcp/dist/capabilities/types.js +2 -5
  4. package/mcp/dist/capabilities/vscode.js +2 -5
  5. package/mcp/dist/capabilities/web-ui.js +2 -5
  6. package/mcp/dist/{cli-actions.js → cli/actions.js} +25 -21
  7. package/mcp/dist/{cli.js → cli/cli.js} +13 -13
  8. package/mcp/dist/{cli-config.js → cli/config.js} +12 -12
  9. package/mcp/dist/{cli-extract.js → cli/extract.js} +8 -8
  10. package/mcp/dist/{cli-govern.js → cli/govern.js} +28 -17
  11. package/mcp/dist/{cli-graph.js → cli/graph.js} +10 -9
  12. package/mcp/dist/{cli-hooks-citations.js → cli/hooks-citations.js} +2 -2
  13. package/mcp/dist/{cli-hooks-context.js → cli/hooks-context.js} +23 -23
  14. package/mcp/dist/{cli-hooks-globs.js → cli/hooks-globs.js} +4 -4
  15. package/mcp/dist/{cli-hooks-output.js → cli/hooks-output.js} +9 -10
  16. package/mcp/dist/{cli-hooks-session.js → cli/hooks-session.js} +58 -117
  17. package/mcp/dist/{cli-hooks.js → cli/hooks.js} +27 -26
  18. package/mcp/dist/{cli-namespaces.js → cli/namespaces.js} +25 -24
  19. package/mcp/dist/{cli-ops.js → cli/ops.js} +9 -9
  20. package/mcp/dist/{cli-search.js → cli/search.js} +12 -11
  21. package/mcp/dist/cli-hooks-git.js +243 -0
  22. package/mcp/dist/cli-hooks-prompt.js +323 -0
  23. package/mcp/dist/cli-hooks-session-handlers.js +337 -0
  24. package/mcp/dist/cli-hooks-stop.js +519 -0
  25. package/mcp/dist/{content-archive.js → content/archive.js} +16 -29
  26. package/mcp/dist/{content-citation.js → content/citation.js} +5 -5
  27. package/mcp/dist/{content-dedup.js → content/dedup.js} +9 -12
  28. package/mcp/dist/{content-learning.js → content/learning.js} +41 -20
  29. package/mcp/dist/{content-validate.js → content/validate.js} +5 -5
  30. package/mcp/dist/{core-finding.js → core/finding.js} +4 -4
  31. package/mcp/dist/{core-project.js → core/project.js} +4 -4
  32. package/mcp/dist/{core-search.js → core/search.js} +2 -2
  33. package/mcp/dist/{data-access.js → data/access.js} +142 -15
  34. package/mcp/dist/{data-tasks.js → data/tasks.js} +7 -5
  35. package/mcp/dist/embedding.js +9 -14
  36. package/mcp/dist/entrypoint.js +11 -11
  37. package/mcp/dist/{finding-context.js → finding/context.js} +2 -2
  38. package/mcp/dist/{finding-impact.js → finding/impact.js} +3 -3
  39. package/mcp/dist/{finding-journal.js → finding/journal.js} +4 -4
  40. package/mcp/dist/{finding-lifecycle.js → finding/lifecycle.js} +13 -7
  41. package/mcp/dist/governance/audit.js +30 -0
  42. package/mcp/dist/{governance-locks.js → governance/locks.js} +14 -9
  43. package/mcp/dist/{governance-policy.js → governance/policy.js} +23 -12
  44. package/mcp/dist/{governance-rbac.js → governance/rbac.js} +4 -4
  45. package/mcp/dist/{governance-scores.js → governance/scores.js} +10 -11
  46. package/mcp/dist/hooks.js +53 -37
  47. package/mcp/dist/index-query.js +4 -1
  48. package/mcp/dist/index.js +54 -30
  49. package/mcp/dist/{init-config.js → init/config.js} +6 -6
  50. package/mcp/dist/{init.js → init/init.js} +80 -69
  51. package/mcp/dist/{init-preferences.js → init/preferences.js} +3 -3
  52. package/mcp/dist/{init-setup.js → init/setup.js} +17 -19
  53. package/mcp/dist/{init-shared.js → init/shared.js} +4 -4
  54. package/mcp/dist/init-bootstrap.js +21 -0
  55. package/mcp/dist/init-detect.js +38 -0
  56. package/mcp/dist/init-env.js +114 -0
  57. package/mcp/dist/init-fresh.js +234 -0
  58. package/mcp/dist/init-hooks.js +26 -0
  59. package/mcp/dist/init-mcp.js +65 -0
  60. package/mcp/dist/init-modes.js +135 -0
  61. package/mcp/dist/init-npm.js +37 -0
  62. package/mcp/dist/init-project-local.js +99 -0
  63. package/mcp/dist/init-semantic.js +48 -0
  64. package/mcp/dist/init-types.js +1 -0
  65. package/mcp/dist/init-uninstall.js +504 -0
  66. package/mcp/dist/init-update.js +96 -0
  67. package/mcp/dist/init-walkthrough.js +524 -0
  68. package/mcp/dist/{link-checksums.js → link/checksums.js} +5 -5
  69. package/mcp/dist/{link-context.js → link/context.js} +4 -4
  70. package/mcp/dist/{link-doctor.js → link/doctor.js} +20 -22
  71. package/mcp/dist/{link.js → link/link.js} +26 -31
  72. package/mcp/dist/{link-skills.js → link/skills.js} +10 -10
  73. package/mcp/dist/logger.js +11 -3
  74. package/mcp/dist/package-metadata.js +1 -1
  75. package/mcp/dist/phren-art.js +4 -126
  76. package/mcp/dist/phren-paths.js +30 -12
  77. package/mcp/dist/proactivity.js +3 -3
  78. package/mcp/dist/profile-store.js +5 -6
  79. package/mcp/dist/project-config.js +2 -2
  80. package/mcp/dist/project-topics.js +17 -47
  81. package/mcp/dist/provider-adapters.js +1 -1
  82. package/mcp/dist/query-correlation.js +1 -1
  83. package/mcp/dist/runtime-profile.js +1 -1
  84. package/mcp/dist/{session-checkpoints.js → session/checkpoints.js} +3 -3
  85. package/mcp/dist/{session-utils.js → session/utils.js} +1 -1
  86. package/mcp/dist/{shared-content.js → shared/content.js} +7 -7
  87. package/mcp/dist/{shared-data-utils.js → shared/data-utils.js} +28 -3
  88. package/mcp/dist/{shared-embedding-cache.js → shared/embedding-cache.js} +3 -3
  89. package/mcp/dist/{shared-fragment-graph.js → shared/fragment-graph.js} +19 -42
  90. package/mcp/dist/shared/governance.js +4 -0
  91. package/mcp/dist/{shared-index.js → shared/index.js} +105 -132
  92. package/mcp/dist/{shared-ollama.js → shared/ollama.js} +25 -7
  93. package/mcp/dist/shared/process.js +24 -0
  94. package/mcp/dist/{shared-retrieval.js → shared/retrieval.js} +22 -24
  95. package/mcp/dist/{shared-search-fallback.js → shared/search-fallback.js} +18 -20
  96. package/mcp/dist/{shared-sqljs.js → shared/sqljs.js} +3 -3
  97. package/mcp/dist/{shared-vector-index.js → shared/vector-index.js} +3 -3
  98. package/mcp/dist/shared.js +6 -60
  99. package/mcp/dist/{shell-entry.js → shell/entry.js} +6 -6
  100. package/mcp/dist/{shell-input.js → shell/input.js} +13 -13
  101. package/mcp/dist/{shell-palette.js → shell/palette.js} +3 -3
  102. package/mcp/dist/{shell-render.js → shell/render.js} +2 -2
  103. package/mcp/dist/{shell.js → shell/shell.js} +11 -11
  104. package/mcp/dist/{shell-state-store.js → shell/state-store.js} +5 -5
  105. package/mcp/dist/{shell-view-list.js → shell/view-list.js} +1 -1
  106. package/mcp/dist/{shell-view.js → shell/view.js} +13 -13
  107. package/mcp/dist/{skill-files.js → skill/files.js} +9 -9
  108. package/mcp/dist/{skill-registry.js → skill/registry.js} +5 -5
  109. package/mcp/dist/{skill-state.js → skill/state.js} +1 -4
  110. package/mcp/dist/startup-embedding.js +2 -2
  111. package/mcp/dist/status.js +15 -14
  112. package/mcp/dist/{tasks-github.js → task/github.js} +3 -2
  113. package/mcp/dist/{task-hygiene.js → task/hygiene.js} +4 -4
  114. package/mcp/dist/{task-lifecycle.js → task/lifecycle.js} +8 -13
  115. package/mcp/dist/telemetry.js +3 -4
  116. package/mcp/dist/tool-registry.js +29 -17
  117. package/mcp/dist/tools/config.js +530 -0
  118. package/mcp/dist/{mcp-data.js → tools/data.js} +8 -10
  119. package/mcp/dist/{mcp-extract-facts.js → tools/extract-facts.js} +6 -6
  120. package/mcp/dist/{mcp-extract.js → tools/extract.js} +6 -6
  121. package/mcp/dist/tools/finding.js +584 -0
  122. package/mcp/dist/{mcp-graph.js → tools/graph.js} +11 -14
  123. package/mcp/dist/{mcp-hooks.js → tools/hooks.js} +6 -6
  124. package/mcp/dist/{mcp-memory.js → tools/memory.js} +5 -5
  125. package/mcp/dist/tools/ops.js +468 -0
  126. package/mcp/dist/tools/search.js +672 -0
  127. package/mcp/dist/{mcp-session.js → tools/session.js} +51 -25
  128. package/mcp/dist/{mcp-skills.js → tools/skills.js} +42 -35
  129. package/mcp/dist/{mcp-tasks.js → tools/tasks.js} +155 -282
  130. package/mcp/dist/{memory-ui-data.js → ui/data.js} +31 -17
  131. package/mcp/dist/{memory-ui.js → ui/memory-ui.js} +3 -3
  132. package/mcp/dist/{memory-ui-page.js → ui/page.js} +5 -7
  133. package/mcp/dist/ui/server.js +1024 -0
  134. package/mcp/dist/update.js +2 -2
  135. package/mcp/dist/utils.js +63 -19
  136. package/package.json +2 -2
  137. package/scripts/preuninstall.mjs +31 -0
  138. package/starter/global/CLAUDE.md +3 -2
  139. package/mcp/dist/governance-audit.js +0 -22
  140. package/mcp/dist/mcp-config.js +0 -551
  141. package/mcp/dist/mcp-finding.js +0 -594
  142. package/mcp/dist/mcp-ops.js +0 -363
  143. package/mcp/dist/mcp-search.js +0 -668
  144. package/mcp/dist/memory-ui-server.js +0 -1411
  145. package/mcp/dist/shared-governance.js +0 -4
  146. /package/mcp/dist/{content-metadata.js → content/metadata.js} +0 -0
  147. /package/mcp/dist/{shared-stemmer.js → shared/stemmer.js} +0 -0
  148. /package/mcp/dist/{shell-types.js → shell/types.js} +0 -0
  149. /package/mcp/dist/{mcp-types.js → tools/types.js} +0 -0
  150. /package/mcp/dist/{memory-ui-assets.js → ui/assets.js} +0 -0
  151. /package/mcp/dist/{memory-ui-graph.js → ui/graph.js} +0 -0
  152. /package/mcp/dist/{memory-ui-scripts.js → ui/scripts.js} +0 -0
  153. /package/mcp/dist/{memory-ui-styles.js → ui/styles.js} +0 -0
@@ -1,20 +1,21 @@
1
- import { buildHookContext, handleGuardSkip, debugLog, appendAuditLog, runtimeFile, sessionMarker, EXEC_TIMEOUT_MS, getPhrenPath, getProjectDirs, findProjectNameCaseInsensitive, homePath, updateRuntimeHealth, withFileLock, getWorkflowPolicy, appendReviewQueue, recordFeedback, getQualityMultiplier, detectProject, isProjectHookEnabled, readProjectConfig, getProjectSourcePath, detectProjectDir, ensureLocalGitRepo, isProjectTracked, repairPreexistingInstall, getProactivityLevelForTask, getProactivityLevelForFindings, hasExplicitFindingSignal, shouldAutoCaptureFindingsForLevel, FINDING_SENSITIVITY_CONFIG, isFeatureEnabled, errorMessage, bootstrapPhrenDotEnv, finalizeTaskSession, appendFindingJournal, runDoctor, resolveRuntimeProfile, } from "./cli-hooks-context.js";
2
- import { sessionMetricsFile, qualityMarkers, } from "./shared.js";
3
- import { autoMergeConflicts, mergeTask, mergeFindings, } from "./shared-content.js";
4
- import { runGit } from "./utils.js";
5
- import { readInstallPreferences } from "./init-preferences.js";
1
+ import { buildHookContext, handleGuardSkip, debugLog, appendAuditLog, runtimeFile, sessionMarker, EXEC_TIMEOUT_MS, getPhrenPath, getProjectDirs, findProjectNameCaseInsensitive, homePath, updateRuntimeHealth, withFileLock, getWorkflowPolicy, appendReviewQueue, recordFeedback, getQualityMultiplier, detectProject, isProjectHookEnabled, readProjectConfig, getProjectSourcePath, detectProjectDir, ensureLocalGitRepo, isProjectTracked, repairPreexistingInstall, getProactivityLevelForTask, getProactivityLevelForFindings, hasExplicitFindingSignal, shouldAutoCaptureFindingsForLevel, FINDING_SENSITIVITY_CONFIG, isFeatureEnabled, errorMessage, bootstrapPhrenDotEnv, finalizeTaskSession, appendFindingJournal, runDoctor, resolveRuntimeProfile, buildSyncStatus, } from "./hooks-context.js";
2
+ import { sessionMetricsFile, qualityMarkers, } from "../shared.js";
3
+ import { autoMergeConflicts, mergeTask, mergeFindings, } from "../shared/content.js";
4
+ import { runGit } from "../utils.js";
5
+ import { readInstallPreferences } from "../init/preferences.js";
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
8
  import * as os from "os";
9
- import { execFileSync, spawn } from "child_process";
9
+ import { execFileSync } from "child_process";
10
+ import { spawnDetachedChild } from "../shared/process.js";
10
11
  import { fileURLToPath } from "url";
11
- import { isTaskFileName, TASKS_FILENAME } from "./data-tasks.js";
12
- import { buildIndex, queryRows, } from "./shared-index.js";
13
- import { filterTaskByPriority } from "./shared-retrieval.js";
14
- function getRuntimeProfile() {
15
- return resolveRuntimeProfile(getPhrenPath());
16
- }
17
- export { buildHookContext, checkHookGuard, handleGuardSkip } from "./cli-hooks-context.js";
12
+ import { isTaskFileName, TASKS_FILENAME } from "../data/tasks.js";
13
+ import { buildIndex, queryRows, } from "../shared/index.js";
14
+ import { filterTaskByPriority } from "../shared/retrieval.js";
15
+ import { logger } from "../logger.js";
16
+ const SYNC_LOCK_STALE_MS = 10 * 60 * 1000; // 10 minutes
17
+ const MAINTENANCE_LOCK_STALE_MS = 2 * 60 * 60 * 1000; // 2 hours
18
+ export { buildHookContext, handleGuardSkip } from "./hooks-context.js";
18
19
  /** Read JSON from stdin if it's not a TTY. Returns null if stdin is a TTY or parsing fails. */
19
20
  function readStdinJson() {
20
21
  if (process.stdin.isTTY)
@@ -23,8 +24,7 @@ function readStdinJson() {
23
24
  return JSON.parse(fs.readFileSync(0, "utf-8"));
24
25
  }
25
26
  catch (err) {
26
- if (process.env.PHREN_DEBUG)
27
- process.stderr.write(`[phren] readStdinJson: ${errorMessage(err)}\n`);
27
+ logger.debug("hooks-session", `readStdinJson: ${errorMessage(err)}`);
28
28
  return null;
29
29
  }
30
30
  }
@@ -230,13 +230,17 @@ export function trackSessionMetrics(phrenPathLocal, sessionId, selected) {
230
230
  }
231
231
  // ── Background maintenance ───────────────────────────────────────────────────
232
232
  export function resolveSubprocessArgs(command) {
233
- const distEntry = path.join(path.dirname(fileURLToPath(import.meta.url)), "index.js");
234
- if (fs.existsSync(distEntry))
235
- return [distEntry, command];
236
- const sourceEntry = process.argv.find((a) => /[\\/]index\.(ts|js)$/.test(a) && fs.existsSync(a));
237
- const runner = process.argv[1];
238
- if (sourceEntry && runner)
239
- return [runner, sourceEntry, command];
233
+ // Prefer the entry script that started this process
234
+ const entry = process.argv[1];
235
+ if (entry && fs.existsSync(entry) && /index\.(ts|js)$/.test(entry))
236
+ return [entry, command];
237
+ // Fallback: look for index.js next to this file or one level up (for subdirectory builds)
238
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
239
+ for (const dir of [thisDir, path.dirname(thisDir)]) {
240
+ const candidate = path.join(dir, "index.js");
241
+ if (fs.existsSync(candidate))
242
+ return [candidate, command];
243
+ }
240
244
  return null;
241
245
  }
242
246
  function scheduleBackgroundSync(phrenPathLocal) {
@@ -248,7 +252,7 @@ function scheduleBackgroundSync(phrenPathLocal) {
248
252
  try {
249
253
  if (fs.existsSync(lockPath)) {
250
254
  const ageMs = Date.now() - fs.statSync(lockPath).mtimeMs;
251
- if (ageMs <= 10 * 60 * 1000)
255
+ if (ageMs <= SYNC_LOCK_STALE_MS)
252
256
  return false;
253
257
  fs.unlinkSync(lockPath);
254
258
  }
@@ -261,16 +265,7 @@ function scheduleBackgroundSync(phrenPathLocal) {
261
265
  fs.writeFileSync(lockPath, JSON.stringify({ startedAt: new Date().toISOString(), pid: process.pid }) + "\n", { flag: "wx" });
262
266
  const logFd = fs.openSync(logPath, "a");
263
267
  fs.writeSync(logFd, `[${new Date().toISOString()}] spawn ${process.execPath} ${spawnArgs.join(" ")}\n`);
264
- const child = spawn(process.execPath, spawnArgs, {
265
- cwd: process.cwd(),
266
- detached: true,
267
- stdio: ["ignore", logFd, logFd],
268
- env: {
269
- ...process.env,
270
- PHREN_PATH: phrenPathLocal,
271
- PHREN_PROFILE: getRuntimeProfile(),
272
- },
273
- });
268
+ const child = spawnDetachedChild(spawnArgs, { phrenPath: phrenPathLocal, logFd });
274
269
  child.unref();
275
270
  fs.closeSync(logFd);
276
271
  return true;
@@ -293,7 +288,7 @@ function scheduleBackgroundMaintenance(phrenPathLocal, project) {
293
288
  if (fs.existsSync(markers.lock)) {
294
289
  try {
295
290
  const ageMs = Date.now() - fs.statSync(markers.lock).mtimeMs;
296
- if (ageMs <= 2 * 60 * 60 * 1000)
291
+ if (ageMs <= MAINTENANCE_LOCK_STALE_MS)
297
292
  return false;
298
293
  fs.unlinkSync(markers.lock);
299
294
  }
@@ -319,8 +314,7 @@ function scheduleBackgroundMaintenance(phrenPathLocal, project) {
319
314
  }
320
315
  catch (err) {
321
316
  // Another process already claimed the lock
322
- if (process.env.PHREN_DEBUG)
323
- process.stderr.write(`[phren] backgroundMaintenance lockClaim: ${errorMessage(err)}\n`);
317
+ logger.debug("hooks-session", `backgroundMaintenance lockClaim: ${errorMessage(err)}`);
324
318
  return false;
325
319
  }
326
320
  try {
@@ -336,40 +330,28 @@ function scheduleBackgroundMaintenance(phrenPathLocal, project) {
336
330
  const logPath = path.join(logDir, "background-maintenance.log");
337
331
  const logFd = fs.openSync(logPath, "a");
338
332
  fs.writeSync(logFd, `[${new Date().toISOString()}] spawn ${process.execPath} ${spawnArgs.join(" ")}\n`);
339
- const child = spawn(process.execPath, spawnArgs, {
340
- cwd: process.cwd(),
341
- detached: true,
342
- stdio: ["ignore", logFd, logFd],
343
- env: {
344
- ...process.env,
345
- PHREN_PATH: phrenPathLocal,
346
- PHREN_PROFILE: getRuntimeProfile(),
347
- },
348
- });
333
+ const child = spawnDetachedChild(spawnArgs, { phrenPath: phrenPathLocal, logFd });
349
334
  child.on("exit", (code, signal) => {
350
335
  const msg = `[${new Date().toISOString()}] exit code=${code ?? "null"} signal=${signal ?? "none"}\n`;
351
336
  try {
352
337
  fs.appendFileSync(logPath, msg);
353
338
  }
354
339
  catch (err) {
355
- if (process.env.PHREN_DEBUG)
356
- process.stderr.write(`[phren] backgroundMaintenance exitLog: ${errorMessage(err)}\n`);
340
+ logger.debug("hooks-session", `backgroundMaintenance exitLog: ${errorMessage(err)}`);
357
341
  }
358
342
  if (code === 0) {
359
343
  try {
360
344
  fs.writeFileSync(markers.done, new Date().toISOString() + "\n");
361
345
  }
362
346
  catch (err) {
363
- if (process.env.PHREN_DEBUG)
364
- process.stderr.write(`[phren] backgroundMaintenance doneMarker: ${errorMessage(err)}\n`);
347
+ logger.debug("hooks-session", `backgroundMaintenance doneMarker: ${errorMessage(err)}`);
365
348
  }
366
349
  }
367
350
  try {
368
351
  fs.unlinkSync(markers.lock);
369
352
  }
370
353
  catch (err) {
371
- if (process.env.PHREN_DEBUG)
372
- process.stderr.write(`[phren] backgroundMaintenance unlockOnExit: ${errorMessage(err)}\n`);
354
+ logger.debug("hooks-session", `backgroundMaintenance unlockOnExit: ${errorMessage(err)}`);
373
355
  }
374
356
  });
375
357
  child.on("error", (spawnErr) => {
@@ -378,15 +360,13 @@ function scheduleBackgroundMaintenance(phrenPathLocal, project) {
378
360
  fs.appendFileSync(logPath, msg);
379
361
  }
380
362
  catch (err) {
381
- if (process.env.PHREN_DEBUG)
382
- process.stderr.write(`[phren] backgroundMaintenance errorLog: ${errorMessage(err)}\n`);
363
+ logger.debug("hooks-session", `backgroundMaintenance errorLog: ${errorMessage(err)}`);
383
364
  }
384
365
  try {
385
366
  fs.unlinkSync(markers.lock);
386
367
  }
387
368
  catch (err) {
388
- if (process.env.PHREN_DEBUG)
389
- process.stderr.write(`[phren] backgroundMaintenance unlockOnError: ${errorMessage(err)}\n`);
369
+ logger.debug("hooks-session", `backgroundMaintenance unlockOnError: ${errorMessage(err)}`);
390
370
  }
391
371
  });
392
372
  fs.closeSync(logFd);
@@ -401,15 +381,13 @@ function scheduleBackgroundMaintenance(phrenPathLocal, project) {
401
381
  fs.appendFileSync(path.join(logDir, "background-maintenance.log"), `[${new Date().toISOString()}] spawn failed: ${errMsg}\n`);
402
382
  }
403
383
  catch (err) {
404
- if (process.env.PHREN_DEBUG)
405
- process.stderr.write(`[phren] backgroundMaintenance logSpawnFailure: ${errorMessage(err)}\n`);
384
+ logger.debug("hooks-session", `backgroundMaintenance logSpawnFailure: ${errorMessage(err)}`);
406
385
  }
407
386
  try {
408
387
  fs.unlinkSync(markers.lock);
409
388
  }
410
389
  catch (err) {
411
- if (process.env.PHREN_DEBUG)
412
- process.stderr.write(`[phren] backgroundMaintenance unlockOnFailure: ${errorMessage(err)}\n`);
390
+ logger.debug("hooks-session", `backgroundMaintenance unlockOnFailure: ${errorMessage(err)}`);
413
391
  }
414
392
  return false;
415
393
  }
@@ -608,12 +586,11 @@ export async function handleHookSessionStart() {
608
586
  const maintenanceScheduled = scheduleBackgroundMaintenance(phrenPath);
609
587
  const unsyncedCommits = hasRemote ? await countUnsyncedCommits(phrenPath) : 0;
610
588
  try {
611
- const { trackSession } = await import("./telemetry.js");
589
+ const { trackSession } = await import("../telemetry.js");
612
590
  trackSession(phrenPath);
613
591
  }
614
592
  catch (err) {
615
- if (process.env.PHREN_DEBUG)
616
- process.stderr.write(`[phren] hookSessionStart trackSession: ${errorMessage(err)}\n`);
593
+ logger.debug("hooks-session", `hookSessionStart trackSession: ${errorMessage(err)}`);
617
594
  }
618
595
  updateRuntimeHealth(phrenPath, {
619
596
  lastSessionStartAt: startedAt,
@@ -779,8 +756,7 @@ export async function handleHookStop() {
779
756
  }
780
757
  }
781
758
  catch (err) {
782
- if (process.env.PHREN_DEBUG)
783
- process.stderr.write(`[phren] hookStop transcriptParse: ${errorMessage(err)}\n`);
759
+ logger.debug("hooks-session", `hookStop transcriptParse: ${errorMessage(err)}`);
784
760
  }
785
761
  }
786
762
  captureInput = assistantTexts.join("\n");
@@ -804,8 +780,7 @@ export async function handleHookStop() {
804
780
  }
805
781
  }
806
782
  catch (err) {
807
- if (process.env.PHREN_DEBUG)
808
- process.stderr.write(`[phren] hookStop sessionCapCheck: ${errorMessage(err)}\n`);
783
+ logger.debug("hooks-session", `hookStop sessionCapCheck: ${errorMessage(err)}`);
809
784
  }
810
785
  }
811
786
  if (!capReached) {
@@ -1026,12 +1001,7 @@ export async function handleBackgroundSync() {
1026
1001
  const unsyncedCommits = await countUnsyncedCommits(phrenPathLocal);
1027
1002
  updateRuntimeHealth(phrenPathLocal, {
1028
1003
  lastAutoSave: { at: now, status: "saved-local", detail: "background sync skipped; no remote configured" },
1029
- lastSync: {
1030
- lastPushAt: now,
1031
- lastPushStatus: "saved-local",
1032
- lastPushDetail: "background sync skipped; no remote configured",
1033
- unsyncedCommits,
1034
- },
1004
+ lastSync: buildSyncStatus({ now, pushStatus: "saved-local", pushDetail: "background sync skipped; no remote configured", unsyncedCommits }),
1035
1005
  });
1036
1006
  appendAuditLog(phrenPathLocal, "background_sync", "status=saved-local detail=no_remote");
1037
1007
  return;
@@ -1040,12 +1010,7 @@ export async function handleBackgroundSync() {
1040
1010
  if (push.ok) {
1041
1011
  updateRuntimeHealth(phrenPathLocal, {
1042
1012
  lastAutoSave: { at: now, status: "saved-pushed", detail: "commit pushed by background sync" },
1043
- lastSync: {
1044
- lastPushAt: now,
1045
- lastPushStatus: "saved-pushed",
1046
- lastPushDetail: "commit pushed by background sync",
1047
- unsyncedCommits: 0,
1048
- },
1013
+ lastSync: buildSyncStatus({ now, pushStatus: "saved-pushed", pushDetail: "commit pushed by background sync", unsyncedCommits: 0 }),
1049
1014
  });
1050
1015
  appendAuditLog(phrenPathLocal, "background_sync", "status=saved-pushed");
1051
1016
  return;
@@ -1054,34 +1019,18 @@ export async function handleBackgroundSync() {
1054
1019
  if (recovered.ok) {
1055
1020
  updateRuntimeHealth(phrenPathLocal, {
1056
1021
  lastAutoSave: { at: now, status: "saved-pushed", detail: recovered.detail },
1057
- lastSync: {
1058
- lastPullAt: now,
1059
- lastPullStatus: recovered.pullStatus,
1060
- lastPullDetail: recovered.pullDetail,
1061
- lastSuccessfulPullAt: now,
1062
- lastPushAt: now,
1063
- lastPushStatus: "saved-pushed",
1064
- lastPushDetail: recovered.detail,
1065
- unsyncedCommits: 0,
1066
- },
1022
+ lastSync: buildSyncStatus({ now, pushStatus: "saved-pushed", pushDetail: recovered.detail, pullAt: now, pullStatus: recovered.pullStatus, pullDetail: recovered.pullDetail, successfulPullAt: now, unsyncedCommits: 0 }),
1067
1023
  });
1068
1024
  appendAuditLog(phrenPathLocal, "background_sync", `status=saved-pushed detail=${JSON.stringify(recovered.detail)}`);
1069
1025
  return;
1070
1026
  }
1071
1027
  const unsyncedCommits = await countUnsyncedCommits(phrenPathLocal);
1028
+ const failDetail = recovered.detail || push.error || "background sync push failed";
1072
1029
  updateRuntimeHealth(phrenPathLocal, {
1073
- lastAutoSave: { at: now, status: "saved-local", detail: recovered.detail || push.error || "background sync push failed" },
1074
- lastSync: {
1075
- lastPullAt: now,
1076
- lastPullStatus: recovered.pullStatus,
1077
- lastPullDetail: recovered.pullDetail,
1078
- lastPushAt: now,
1079
- lastPushStatus: "saved-local",
1080
- lastPushDetail: recovered.detail || push.error || "background sync push failed",
1081
- unsyncedCommits,
1082
- },
1030
+ lastAutoSave: { at: now, status: "saved-local", detail: failDetail },
1031
+ lastSync: buildSyncStatus({ now, pushStatus: "saved-local", pushDetail: failDetail, pullAt: now, pullStatus: recovered.pullStatus, pullDetail: recovered.pullDetail, unsyncedCommits }),
1083
1032
  });
1084
- appendAuditLog(phrenPathLocal, "background_sync", `status=saved-local detail=${JSON.stringify(recovered.detail || push.error || "background sync push failed")}`);
1033
+ appendAuditLog(phrenPathLocal, "background_sync", `status=saved-local detail=${JSON.stringify(failDetail)}`);
1085
1034
  }
1086
1035
  finally {
1087
1036
  try {
@@ -1098,7 +1047,7 @@ function scheduleWeeklyGovernance() {
1098
1047
  if (daysSince >= 7) {
1099
1048
  const spawnArgs = resolveSubprocessArgs("background-maintenance");
1100
1049
  if (spawnArgs) {
1101
- const child = spawn(process.execPath, spawnArgs, { detached: true, stdio: "ignore" });
1050
+ const child = spawnDetachedChild(spawnArgs, { phrenPath: getPhrenPath() });
1102
1051
  child.unref();
1103
1052
  fs.writeFileSync(lastGovPath, Date.now().toString());
1104
1053
  debugLog("hook_stop: scheduled weekly governance run");
@@ -1225,8 +1174,7 @@ export async function handleHookTool() {
1225
1174
  raw = fs.readFileSync(0, "utf-8");
1226
1175
  }
1227
1176
  catch (err) {
1228
- if (process.env.PHREN_DEBUG)
1229
- process.stderr.write(`[phren] hookTool stdinRead: ${errorMessage(err)}\n`);
1177
+ logger.debug("hooks-session", `hookTool stdinRead: ${errorMessage(err)}`);
1230
1178
  process.exit(0);
1231
1179
  }
1232
1180
  }
@@ -1235,8 +1183,7 @@ export async function handleHookTool() {
1235
1183
  data = JSON.parse(raw);
1236
1184
  }
1237
1185
  catch (err) {
1238
- if (process.env.PHREN_DEBUG)
1239
- process.stderr.write(`[phren] hookTool stdinParse: ${errorMessage(err)}\n`);
1186
+ logger.debug("hooks-session", `hookTool stdinParse: ${errorMessage(err)}`);
1240
1187
  process.exit(0);
1241
1188
  }
1242
1189
  const toolName = String(data.tool_name ?? data.tool ?? "");
@@ -1287,8 +1234,7 @@ export async function handleHookTool() {
1287
1234
  fs.appendFileSync(logFile, JSON.stringify(entry) + "\n");
1288
1235
  }
1289
1236
  catch (err) {
1290
- if (process.env.PHREN_DEBUG)
1291
- process.stderr.write(`[phren] hookTool toolLog: ${errorMessage(err)}\n`);
1237
+ logger.debug("hooks-session", `hookTool toolLog: ${errorMessage(err)}`);
1292
1238
  }
1293
1239
  const cooldownFile = runtimeFile(ctx.phrenPath, "hook-tool-cooldown");
1294
1240
  try {
@@ -1301,8 +1247,7 @@ export async function handleHookTool() {
1301
1247
  }
1302
1248
  }
1303
1249
  catch (err) {
1304
- if (process.env.PHREN_DEBUG)
1305
- process.stderr.write(`[phren] hookTool cooldownStat: ${errorMessage(err)}\n`);
1250
+ logger.debug("hooks-session", `hookTool cooldownStat: ${errorMessage(err)}`);
1306
1251
  }
1307
1252
  if (activeProject && sessionId) {
1308
1253
  try {
@@ -1318,8 +1263,7 @@ export async function handleHookTool() {
1318
1263
  }
1319
1264
  }
1320
1265
  catch (err) {
1321
- if (process.env.PHREN_DEBUG)
1322
- process.stderr.write(`[phren] hookTool sessionCapCheck: ${errorMessage(err)}\n`);
1266
+ logger.debug("hooks-session", `hookTool sessionCapCheck: ${errorMessage(err)}`);
1323
1267
  }
1324
1268
  }
1325
1269
  const findingsLevelForTool = getProactivityLevelForFindings(ctx.phrenPath);
@@ -1335,8 +1279,7 @@ export async function handleHookTool() {
1335
1279
  fs.writeFileSync(cooldownFile, Date.now().toString());
1336
1280
  }
1337
1281
  catch (err) {
1338
- if (process.env.PHREN_DEBUG)
1339
- process.stderr.write(`[phren] hookTool cooldownWrite: ${errorMessage(err)}\n`);
1282
+ logger.debug("hooks-session", `hookTool cooldownWrite: ${errorMessage(err)}`);
1340
1283
  }
1341
1284
  if (sessionId) {
1342
1285
  try {
@@ -1346,15 +1289,13 @@ export async function handleHookTool() {
1346
1289
  count = Number.parseInt(fs.readFileSync(capFile, "utf8").trim(), 10) || 0;
1347
1290
  }
1348
1291
  catch (err) {
1349
- if (process.env.PHREN_DEBUG)
1350
- process.stderr.write(`[phren] hookTool capFileRead: ${errorMessage(err)}\n`);
1292
+ logger.debug("hooks-session", `hookTool capFileRead: ${errorMessage(err)}`);
1351
1293
  }
1352
1294
  count += candidates.length;
1353
1295
  fs.writeFileSync(capFile, count.toString());
1354
1296
  }
1355
1297
  catch (err) {
1356
- if (process.env.PHREN_DEBUG)
1357
- process.stderr.write(`[phren] hookTool capFileWrite: ${errorMessage(err)}\n`);
1298
+ logger.debug("hooks-session", `hookTool capFileWrite: ${errorMessage(err)}`);
1358
1299
  }
1359
1300
  }
1360
1301
  }
@@ -4,38 +4,39 @@
4
4
  // cli-hooks-session.ts — session lifecycle hooks, metrics, background maintenance
5
5
  // cli-hooks-output.ts — hook output formatting
6
6
  // cli-hooks-globs.ts — project glob matching
7
- import { debugLog, sessionMarker, sessionsDir, getPhrenPath, } from "./shared.js";
8
- import { mergeConfig, } from "./shared-governance.js";
9
- import { buildIndex, detectProject, } from "./shared-index.js";
10
- import { isProjectHookEnabled } from "./project-config.js";
11
- import { checkConsolidationNeeded, } from "./shared-content.js";
12
- import { buildRobustFtsQuery, extractKeywordEntries, isFeatureEnabled, clampInt, errorMessage, loadSynonymMap, learnSynonym, STOP_WORDS, } from "./utils.js";
13
- import { getHooksEnabledPreference } from "./init.js";
14
- import { isToolHookEnabled } from "./hooks.js";
15
- import { handleExtractMemories } from "./cli-extract.js";
16
- import { appendAuditLog } from "./shared.js";
17
- import { updateRuntimeHealth } from "./shared-governance.js";
18
- import { getProactivityLevelForTask, getProactivityLevelForFindings } from "./proactivity.js";
19
- import { FINDING_SENSITIVITY_CONFIG } from "./cli-config.js";
7
+ import { debugLog, sessionMarker, sessionsDir, getPhrenPath, } from "../shared.js";
8
+ import { mergeConfig, } from "../shared/governance.js";
9
+ import { buildIndex, detectProject, } from "../shared/index.js";
10
+ import { isProjectHookEnabled } from "../project-config.js";
11
+ import { checkConsolidationNeeded, } from "../shared/content.js";
12
+ import { buildRobustFtsQuery, extractKeywordEntries, isFeatureEnabled, clampInt, errorMessage, loadSynonymMap, learnSynonym, STOP_WORDS, } from "../utils.js";
13
+ import { getHooksEnabledPreference } from "../init/init.js";
14
+ import { logger } from "../logger.js";
15
+ import { isToolHookEnabled } from "../hooks.js";
16
+ import { handleExtractMemories } from "./extract.js";
17
+ import { appendAuditLog } from "../shared.js";
18
+ import { updateRuntimeHealth } from "../shared/governance.js";
19
+ import { getProactivityLevelForTask, getProactivityLevelForFindings } from "../proactivity.js";
20
+ import { FINDING_SENSITIVITY_CONFIG } from "./config.js";
20
21
  import * as fs from "fs";
21
22
  // ── Re-exports from focused modules ─────────────────────────────────────────
22
23
  // Citations
23
- export { parseCitations, validateCitation, annotateStale, clearCitationValidCache, } from "./cli-hooks-citations.js";
24
+ export { parseCitations, validateCitation, annotateStale, clearCitationValidCache, } from "./hooks-citations.js";
24
25
  // Globs
25
- export { getProjectGlobBoost, clearProjectGlobCache, } from "./cli-hooks-globs.js";
26
+ export { getProjectGlobBoost, clearProjectGlobCache, } from "./hooks-globs.js";
26
27
  // Retrieval
27
- export { detectTaskIntent, filterTaskByPriority, searchDocuments, applyTrustFilter, rankResults, selectSnippets, } from "./shared-retrieval.js";
28
+ export { detectTaskIntent, filterTaskByPriority, searchDocuments, applyTrustFilter, rankResults, selectSnippets, } from "../shared/retrieval.js";
28
29
  // Output
29
- export { buildHookOutput, } from "./cli-hooks-output.js";
30
+ export { buildHookOutput, } from "./hooks-output.js";
30
31
  // Session
31
- export { handleHookSessionStart, handleHookStop, handleBackgroundSync, handleHookContext, handleHookTool, trackSessionMetrics, filterConversationInsightsForProactivity, extractToolFindings, filterToolFindingsForProactivity, resolveSubprocessArgs, } from "./cli-hooks-session.js";
32
+ export { handleHookSessionStart, handleHookStop, handleBackgroundSync, handleHookContext, handleHookTool, trackSessionMetrics, filterConversationInsightsForProactivity, extractToolFindings, filterToolFindingsForProactivity, resolveSubprocessArgs, } from "./hooks-session.js";
32
33
  // ── Imports for the orchestrator ─────────────────────────────────────────────
33
- import { searchDocumentsAsync, applyTrustFilter, rankResults, selectSnippets, detectTaskIntent, } from "./shared-retrieval.js";
34
- import { buildHookOutput } from "./cli-hooks-output.js";
35
- import { getGitContext, trackSessionMetrics, } from "./cli-hooks-session.js";
36
- import { approximateTokens } from "./shared-retrieval.js";
37
- import { resolveRuntimeProfile } from "./runtime-profile.js";
38
- import { handleTaskPromptLifecycle } from "./task-lifecycle.js";
34
+ import { searchDocumentsAsync, applyTrustFilter, rankResults, selectSnippets, detectTaskIntent, } from "../shared/retrieval.js";
35
+ import { buildHookOutput } from "./hooks-output.js";
36
+ import { getGitContext, trackSessionMetrics, } from "./hooks-session.js";
37
+ import { approximateTokens } from "../shared/retrieval.js";
38
+ import { resolveRuntimeProfile } from "../runtime-profile.js";
39
+ import { handleTaskPromptLifecycle } from "../task/lifecycle.js";
39
40
  function synonymTermKnown(term, map) {
40
41
  if (Object.prototype.hasOwnProperty.call(map, term))
41
42
  return true;
@@ -126,7 +127,7 @@ export async function handleHookPrompt() {
126
127
  }
127
128
  catch (err) {
128
129
  if (process.env.PHREN_DEBUG)
129
- process.stderr.write(`[phren] hookPrompt stdinRead: ${errorMessage(err)}\n`);
130
+ logger.debug("cli-hooks", `hookPrompt stdinRead: ${errorMessage(err)}`);
130
131
  process.exit(0);
131
132
  }
132
133
  const input = parseHookInput(raw);
@@ -362,7 +363,7 @@ export async function handleHookPrompt() {
362
363
  }
363
364
  catch (err) {
364
365
  if (process.env.PHREN_DEBUG)
365
- process.stderr.write(`[phren] hookPrompt noticeFileWrite: ${errorMessage(err)}\n`);
366
+ logger.debug("cli-hooks", `hookPrompt noticeFileWrite: ${errorMessage(err)}`);
366
367
  }
367
368
  }
368
369
  }
@@ -1,20 +1,21 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import { execFileSync } from "child_process";
4
- import { expandHomePath, findArchivedProjectNameCaseInsensitive, findProjectNameCaseInsensitive, getPhrenPath, getProjectDirs, homePath, hookConfigPath, normalizeProjectNameForCreate, readRootManifest, } from "./shared.js";
5
- import { isValidProjectName, errorMessage } from "./utils.js";
6
- import { readInstallPreferences, writeInstallPreferences } from "./init-preferences.js";
7
- import { buildSkillManifest, findLocalSkill, findSkill, getAllSkills } from "./skill-registry.js";
8
- import { detectSkillCollisions } from "./link-skills.js";
9
- import { setSkillEnabledAndSync, syncSkillLinksForScope } from "./skill-files.js";
10
- import { findProjectDir } from "./project-locator.js";
11
- import { TASK_FILE_ALIASES, addTask, completeTask, updateTask, reorderTask, pinTask, removeTask, workNextTask, tidyDoneTasks, linkTaskIssue, promoteTask, resolveTaskItem } from "./data-tasks.js";
12
- import { buildTaskIssueBody, createGithubIssueForTask, parseGithubIssueUrl, resolveProjectGithubRepo } from "./tasks-github.js";
13
- import { PROJECT_HOOK_EVENTS, PROJECT_OWNERSHIP_MODES, isProjectHookEnabled, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, writeProjectHookConfig, } from "./project-config.js";
14
- import { addFinding, removeFinding } from "./core-finding.js";
15
- import { supersedeFinding, retractFinding, resolveFindingContradiction } from "./finding-lifecycle.js";
16
- import { readCustomHooks, getHookTarget, HOOK_EVENT_VALUES, validateCustomHookCommand } from "./hooks.js";
17
- import { runtimeFile } from "./shared.js";
4
+ import { expandHomePath, findArchivedProjectNameCaseInsensitive, findProjectNameCaseInsensitive, getPhrenPath, getProjectDirs, homePath, hookConfigPath, normalizeProjectNameForCreate, readRootManifest, } from "../shared.js";
5
+ import { isValidProjectName, errorMessage } from "../utils.js";
6
+ import { logger } from "../logger.js";
7
+ import { readInstallPreferences, writeInstallPreferences } from "../init/preferences.js";
8
+ import { buildSkillManifest, findLocalSkill, findSkill, getAllSkills } from "../skill/registry.js";
9
+ import { detectSkillCollisions } from "../link/skills.js";
10
+ import { setSkillEnabledAndSync, syncSkillLinksForScope } from "../skill/files.js";
11
+ import { findProjectDir } from "../project-locator.js";
12
+ import { TASK_FILE_ALIASES, addTask, completeTask, updateTask, reorderTask, pinTask, removeTask, workNextTask, tidyDoneTasks, linkTaskIssue, promoteTask, resolveTaskItem } from "../data/tasks.js";
13
+ import { buildTaskIssueBody, createGithubIssueForTask, parseGithubIssueUrl, resolveProjectGithubRepo } from "../task/github.js";
14
+ import { PROJECT_HOOK_EVENTS, PROJECT_OWNERSHIP_MODES, isProjectHookEnabled, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, writeProjectHookConfig, } from "../project-config.js";
15
+ import { addFinding, removeFinding } from "../core/finding.js";
16
+ import { supersedeFinding, retractFinding, resolveFindingContradiction } from "../finding/lifecycle.js";
17
+ import { readCustomHooks, getHookTarget, HOOK_EVENT_VALUES, validateCustomHookCommand } from "../hooks.js";
18
+ import { runtimeFile } from "../shared.js";
18
19
  const HOOK_TOOLS = ["claude", "copilot", "cursor", "codex"];
19
20
  function printSkillsUsage() {
20
21
  console.log("Usage:");
@@ -78,7 +79,7 @@ function openInEditor(filePath) {
78
79
  }
79
80
  catch (err) {
80
81
  if ((process.env.PHREN_DEBUG))
81
- process.stderr.write(`[phren] openInEditor: ${errorMessage(err)}\n`);
82
+ logger.debug("cli-namespaces", `openInEditor: ${errorMessage(err)}`);
82
83
  console.error(`Editor "${editor}" failed. Set $EDITOR to your preferred editor.`);
83
84
  process.exit(1);
84
85
  }
@@ -147,7 +148,7 @@ export function handleSkillsNamespace(args, profile) {
147
148
  }
148
149
  catch (err) {
149
150
  if ((process.env.PHREN_DEBUG))
150
- process.stderr.write(`[phren] skill add symlinkFailed: ${errorMessage(err)}\n`);
151
+ logger.debug("cli-namespaces", `skill add symlinkFailed: ${errorMessage(err)}`);
151
152
  fs.copyFileSync(source, dest);
152
153
  console.log(`Copied skill ${fileName} into ${project}.`);
153
154
  }
@@ -457,7 +458,7 @@ export function handleDetectSkills(args, profile) {
457
458
  }
458
459
  catch (err) {
459
460
  if ((process.env.PHREN_DEBUG))
460
- process.stderr.write(`[phren] skillList lstat: ${errorMessage(err)}\n`);
461
+ logger.debug("cli-namespaces", `skillList lstat: ${errorMessage(err)}`);
461
462
  }
462
463
  const name = entry.replace(/\.md$/, "");
463
464
  if (trackedSkills.has(name))
@@ -666,7 +667,7 @@ export async function handleProjectsNamespace(args, profile) {
666
667
  console.error(`Project "${name}" not found.`);
667
668
  process.exit(1);
668
669
  }
669
- const { readFindings, readTasks, resolveTaskFilePath, TASKS_FILENAME } = await import("./data-access.js");
670
+ const { readFindings, readTasks, resolveTaskFilePath } = await import("../data/access.js");
670
671
  const exported = { project: name, exportedAt: new Date().toISOString(), version: 1 };
671
672
  const summaryPath = path.join(projectDir, "summary.md");
672
673
  if (fs.existsSync(summaryPath))
@@ -721,7 +722,7 @@ export async function handleProjectsNamespace(args, profile) {
721
722
  console.error("Invalid import payload: missing project field.");
722
723
  process.exit(1);
723
724
  }
724
- const { TASKS_FILENAME } = await import("./data-access.js");
725
+ const { TASKS_FILENAME } = await import("../data/access.js");
725
726
  const phrenPath = getPhrenPath();
726
727
  const projectName = normalizeProjectNameForCreate(String(decoded.project));
727
728
  if (!isValidProjectName(projectName)) {
@@ -874,7 +875,7 @@ function handleProjectsList(profile) {
874
875
  }
875
876
  catch (err) {
876
877
  if ((process.env.PHREN_DEBUG))
877
- process.stderr.write(`[phren] projects list readdir: ${errorMessage(err)}\n`);
878
+ logger.debug("cli-namespaces", `projects list readdir: ${errorMessage(err)}`);
878
879
  dirFiles = new Set();
879
880
  }
880
881
  const tags = [];
@@ -917,7 +918,7 @@ async function handleProjectsRemove(name, profile) {
917
918
  }
918
919
  catch (err) {
919
920
  if ((process.env.PHREN_DEBUG))
920
- process.stderr.write(`[phren] projects remove countFiles: ${errorMessage(err)}\n`);
921
+ logger.debug("cli-namespaces", `projects remove countFiles: ${errorMessage(err)}`);
921
922
  }
922
923
  const readline = await import("readline");
923
924
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -956,7 +957,7 @@ export async function handleTaskNamespace(args) {
956
957
  }
957
958
  if (subcommand === "list") {
958
959
  // Delegate to the cross-project task view (same as `phren tasks`)
959
- const { handleTaskView } = await import("./cli-ops.js");
960
+ const { handleTaskView } = await import("./ops.js");
960
961
  return handleTaskView(args[1] || "default");
961
962
  }
962
963
  if (subcommand === "add") {
@@ -1321,7 +1322,7 @@ export async function handleFindingNamespace(args) {
1321
1322
  console.error("Usage: phren finding list <project>");
1322
1323
  process.exit(1);
1323
1324
  }
1324
- const { readFindings } = await import("./data-access.js");
1325
+ const { readFindings } = await import("../data/access.js");
1325
1326
  const result = readFindings(getPhrenPath(), project);
1326
1327
  if (!result.ok) {
1327
1328
  console.error(result.error);
@@ -1441,7 +1442,7 @@ export async function handleFindingNamespace(args) {
1441
1442
  const project = args[1];
1442
1443
  const phrenPath = getPhrenPath();
1443
1444
  const RESERVED_DIRS = new Set(["global", ".runtime", ".sessions", ".config"]);
1444
- const { readFindings } = await import("./data-access.js");
1445
+ const { readFindings } = await import("../data/access.js");
1445
1446
  const projects = project
1446
1447
  ? [project]
1447
1448
  : fs.readdirSync(phrenPath, { withFileTypes: true })
@@ -1,13 +1,13 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
3
  import { execFileSync } from "child_process";
4
- import { EXEC_TIMEOUT_MS, findProjectNameCaseInsensitive, getPhrenPath, normalizeProjectNameForCreate, } from "./shared.js";
5
- import { isValidProjectName, errorMessage } from "./utils.js";
6
- import { readTasksAcrossProjects, TASKS_FILENAME } from "./data-access.js";
7
- import { applyGravity } from "./data-tasks.js";
8
- import { buildIndex, queryRows } from "./shared-index.js";
9
- import { resolveSubprocessArgs } from "./cli-hooks.js";
10
- import { listAllSessions, getSessionArtifacts } from "./mcp-session.js";
4
+ import { EXEC_TIMEOUT_MS, findProjectNameCaseInsensitive, getPhrenPath, normalizeProjectNameForCreate, } from "../shared.js";
5
+ import { isValidProjectName, errorMessage } from "../utils.js";
6
+ import { readTasksAcrossProjects, TASKS_FILENAME } from "../data/access.js";
7
+ import { applyGravity } from "../data/tasks.js";
8
+ import { buildIndex, queryRows } from "../shared/index.js";
9
+ import { resolveSubprocessArgs } from "./hooks.js";
10
+ import { listAllSessions, getSessionArtifacts } from "../tools/session.js";
11
11
  export function handleTaskView(profile) {
12
12
  const docs = readTasksAcrossProjects(getPhrenPath(), profile);
13
13
  if (!docs.length) {
@@ -100,8 +100,8 @@ export function handleSessionsView(args) {
100
100
  console.log(`\n${sessions.length} session(s). Use \`phren sessions <id>\` to drill into one.`);
101
101
  }
102
102
  export async function handleQuickstart() {
103
- const { runInit } = await import("./init.js");
104
- const { runLink } = await import("./link.js");
103
+ const { runInit } = await import("../init/init.js");
104
+ const { runLink } = await import("../link/link.js");
105
105
  const dirBasename = path.basename(process.cwd());
106
106
  const readline = await import("readline");
107
107
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });