@phren/cli 0.0.28 → 0.0.32

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 (147) 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} +22 -21
  7. package/mcp/dist/{cli.js → cli/cli.js} +13 -13
  8. package/mcp/dist/{cli-config.js → cli/config.js} +9 -9
  9. package/mcp/dist/{cli-extract.js → cli/extract.js} +8 -8
  10. package/mcp/dist/{cli-govern.js → cli/govern.js} +10 -9
  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} +42 -57
  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} +8 -7
  21. package/mcp/dist/cli-hooks-git.js +243 -0
  22. package/mcp/dist/cli-hooks-prompt.js +319 -0
  23. package/mcp/dist/cli-hooks-session-handlers.js +349 -0
  24. package/mcp/dist/cli-hooks-stop.js +557 -0
  25. package/mcp/dist/{content-archive.js → content/archive.js} +8 -9
  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} +12 -12
  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} +131 -13
  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} +4 -4
  41. package/mcp/dist/{governance-audit.js → governance/audit.js} +2 -2
  42. package/mcp/dist/{governance-locks.js → governance/locks.js} +14 -9
  43. package/mcp/dist/{governance-policy.js → governance/policy.js} +10 -12
  44. package/mcp/dist/{governance-rbac.js → governance/rbac.js} +3 -3
  45. package/mcp/dist/{governance-scores.js → governance/scores.js} +8 -10
  46. package/mcp/dist/hooks.js +39 -31
  47. package/mcp/dist/index-query.js +4 -1
  48. package/mcp/dist/index.js +53 -29
  49. package/mcp/dist/{init-config.js → init/config.js} +6 -6
  50. package/mcp/dist/{init.js → init/init.js} +28 -29
  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} +3 -3
  54. package/mcp/dist/init-bootstrap.js +68 -0
  55. package/mcp/dist/init-detect.js +38 -0
  56. package/mcp/dist/init-dryrun.js +55 -0
  57. package/mcp/dist/init-env.js +114 -0
  58. package/mcp/dist/init-fresh.js +239 -0
  59. package/mcp/dist/init-hooks.js +26 -0
  60. package/mcp/dist/init-mcp.js +65 -0
  61. package/mcp/dist/init-migrate.js +51 -0
  62. package/mcp/dist/init-modes.js +135 -0
  63. package/mcp/dist/init-npm.js +37 -0
  64. package/mcp/dist/init-project-local.js +99 -0
  65. package/mcp/dist/init-semantic.js +48 -0
  66. package/mcp/dist/init-types.js +1 -0
  67. package/mcp/dist/init-uninstall.js +482 -0
  68. package/mcp/dist/init-update.js +96 -0
  69. package/mcp/dist/init-walkthrough-merge.js +90 -0
  70. package/mcp/dist/init-walkthrough.js +529 -0
  71. package/mcp/dist/{link-checksums.js → link/checksums.js} +5 -5
  72. package/mcp/dist/{link-context.js → link/context.js} +4 -4
  73. package/mcp/dist/{link-doctor.js → link/doctor.js} +20 -22
  74. package/mcp/dist/{link.js → link/link.js} +26 -31
  75. package/mcp/dist/{link-skills.js → link/skills.js} +10 -10
  76. package/mcp/dist/logger.js +11 -3
  77. package/mcp/dist/phren-art.js +0 -6
  78. package/mcp/dist/phren-paths.js +30 -12
  79. package/mcp/dist/proactivity.js +2 -2
  80. package/mcp/dist/profile-store.js +5 -6
  81. package/mcp/dist/project-config.js +2 -2
  82. package/mcp/dist/project-topics.js +1 -1
  83. package/mcp/dist/query-correlation.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} +3 -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} +15 -24
  90. package/mcp/dist/shared/governance.js +4 -0
  91. package/mcp/dist/{shared-index.js → shared/index.js} +92 -123
  92. package/mcp/dist/{shared-ollama.js → shared/ollama.js} +2 -2
  93. package/mcp/dist/{shared-retrieval.js → shared/retrieval.js} +16 -21
  94. package/mcp/dist/{shared-search-fallback.js → shared/search-fallback.js} +17 -20
  95. package/mcp/dist/{shared-sqljs.js → shared/sqljs.js} +3 -3
  96. package/mcp/dist/{shared-vector-index.js → shared/vector-index.js} +3 -3
  97. package/mcp/dist/shared.js +4 -59
  98. package/mcp/dist/{shell-entry.js → shell/entry.js} +6 -6
  99. package/mcp/dist/{shell-input.js → shell/input.js} +13 -13
  100. package/mcp/dist/{shell-palette.js → shell/palette.js} +3 -3
  101. package/mcp/dist/{shell-render.js → shell/render.js} +1 -1
  102. package/mcp/dist/{shell.js → shell/shell.js} +11 -11
  103. package/mcp/dist/{shell-state-store.js → shell/state-store.js} +5 -5
  104. package/mcp/dist/{shell-view-list.js → shell/view-list.js} +1 -1
  105. package/mcp/dist/{shell-view.js → shell/view.js} +13 -13
  106. package/mcp/dist/{skill-files.js → skill/files.js} +9 -9
  107. package/mcp/dist/{skill-registry.js → skill/registry.js} +4 -4
  108. package/mcp/dist/{skill-state.js → skill/state.js} +1 -1
  109. package/mcp/dist/startup-embedding.js +2 -2
  110. package/mcp/dist/status.js +15 -14
  111. package/mcp/dist/{tasks-github.js → task/github.js} +2 -2
  112. package/mcp/dist/{task-hygiene.js → task/hygiene.js} +4 -4
  113. package/mcp/dist/{task-lifecycle.js → task/lifecycle.js} +7 -7
  114. package/mcp/dist/telemetry.js +3 -4
  115. package/mcp/dist/tool-registry.js +29 -17
  116. package/mcp/dist/tools/config.js +515 -0
  117. package/mcp/dist/{mcp-data.js → tools/data.js} +8 -10
  118. package/mcp/dist/{mcp-extract-facts.js → tools/extract-facts.js} +6 -6
  119. package/mcp/dist/{mcp-extract.js → tools/extract.js} +6 -6
  120. package/mcp/dist/{mcp-finding.js → tools/finding.js} +97 -124
  121. package/mcp/dist/{mcp-graph.js → tools/graph.js} +11 -14
  122. package/mcp/dist/{mcp-hooks.js → tools/hooks.js} +6 -6
  123. package/mcp/dist/{mcp-memory.js → tools/memory.js} +5 -5
  124. package/mcp/dist/{mcp-ops.js → tools/ops.js} +169 -71
  125. package/mcp/dist/{mcp-search.js → tools/search.js} +19 -23
  126. package/mcp/dist/{mcp-session.js → tools/session.js} +48 -23
  127. package/mcp/dist/{mcp-skills.js → tools/skills.js} +33 -35
  128. package/mcp/dist/{mcp-tasks.js → tools/tasks.js} +155 -282
  129. package/mcp/dist/{memory-ui-data.js → ui/data.js} +31 -17
  130. package/mcp/dist/{memory-ui.js → ui/memory-ui.js} +3 -3
  131. package/mcp/dist/{memory-ui-page.js → ui/page.js} +4 -6
  132. package/mcp/dist/{memory-ui-server.js → ui/server.js} +30 -22
  133. package/mcp/dist/update.js +2 -2
  134. package/mcp/dist/utils.js +51 -11
  135. package/package.json +2 -2
  136. package/scripts/preuninstall.mjs +31 -0
  137. package/starter/global/CLAUDE.md +3 -2
  138. package/mcp/dist/mcp-config.js +0 -551
  139. package/mcp/dist/shared-governance.js +0 -4
  140. /package/mcp/dist/{content-metadata.js → content/metadata.js} +0 -0
  141. /package/mcp/dist/{shared-stemmer.js → shared/stemmer.js} +0 -0
  142. /package/mcp/dist/{shell-types.js → shell/types.js} +0 -0
  143. /package/mcp/dist/{mcp-types.js → tools/types.js} +0 -0
  144. /package/mcp/dist/{memory-ui-assets.js → ui/assets.js} +0 -0
  145. /package/mcp/dist/{memory-ui-graph.js → ui/graph.js} +0 -0
  146. /package/mcp/dist/{memory-ui-scripts.js → ui/scripts.js} +0 -0
  147. /package/mcp/dist/{memory-ui-styles.js → ui/styles.js} +0 -0
@@ -1,9 +1,10 @@
1
1
  import * as crypto from "crypto";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
- import { appendAuditLog, debugLog, isRecord, memoryScoresFile, memoryUsageLogFile, runtimeFile } from "./shared.js";
5
- import { withFileLock, isFiniteNumber, hasValidSchemaVersion } from "./shared-governance.js";
6
- import { errorMessage } from "./utils.js";
4
+ import { appendAuditLog, debugLog, isRecord, memoryScoresFile, memoryUsageLogFile, runtimeFile } from "../shared.js";
5
+ import { withFileLock, isFiniteNumber, hasValidSchemaVersion } from "../shared/governance.js";
6
+ import { errorMessage } from "../utils.js";
7
+ import { logger } from "../logger.js";
7
8
  const GOVERNANCE_SCHEMA_VERSION = 1;
8
9
  const DEFAULT_MEMORY_SCORES_FILE = {
9
10
  schemaVersion: GOVERNANCE_SCHEMA_VERSION,
@@ -114,8 +115,7 @@ function readScoreJournal(phrenPath) {
114
115
  return JSON.parse(line);
115
116
  }
116
117
  catch (err) {
117
- if ((process.env.PHREN_DEBUG))
118
- process.stderr.write(`[phren] readScoreJournal parseLine: ${errorMessage(err)}\n`);
118
+ logger.debug("scores", `readScoreJournal parseLine: ${errorMessage(err)}`);
119
119
  return null;
120
120
  }
121
121
  })
@@ -147,8 +147,7 @@ function claimScoreJournal(phrenPath) {
147
147
  return JSON.parse(line);
148
148
  }
149
149
  catch (err) {
150
- if ((process.env.PHREN_DEBUG))
151
- process.stderr.write(`[phren] claimScoreJournal parseLine: ${errorMessage(err)}\n`);
150
+ logger.debug("scores", `claimScoreJournal parseLine: ${errorMessage(err)}`);
152
151
  return null;
153
152
  }
154
153
  })
@@ -163,8 +162,7 @@ function claimScoreJournal(phrenPath) {
163
162
  fs.unlinkSync(claimedFile);
164
163
  }
165
164
  catch (err) {
166
- if ((process.env.PHREN_DEBUG))
167
- process.stderr.write(`[phren] claimScoreJournal unlinkClaim: ${errorMessage(err)}\n`);
165
+ logger.debug("scores", `claimScoreJournal unlinkClaim: ${errorMessage(err)}`);
168
166
  }
169
167
  }
170
168
  }
@@ -276,7 +274,7 @@ export function recordFeedback(phrenPath, key, feedback, sessionId) {
276
274
  appendAuditLog(phrenPath, "memory_feedback", `key=${key} feedback=${feedback}`);
277
275
  // When feedback is "helpful", mark correlated query entries for future boost
278
276
  if (feedback === "helpful" && sessionId) {
279
- import("./query-correlation.js").then(({ markCorrelationsHelpful: markHelpful }) => {
277
+ import("../query-correlation.js").then(({ markCorrelationsHelpful: markHelpful }) => {
280
278
  const colonIdx = key.indexOf(":");
281
279
  const docKey = colonIdx >= 0 ? key.slice(0, colonIdx) : key;
282
280
  markHelpful(phrenPath, sessionId, docKey);
package/mcp/dist/hooks.js CHANGED
@@ -9,6 +9,8 @@ import { EXEC_TIMEOUT_QUICK_MS, PhrenError, debugLog, runtimeFile, homePath, ins
9
9
  import { errorMessage } from "./utils.js";
10
10
  import { hookConfigPath } from "./provider-adapters.js";
11
11
  import { PACKAGE_SPEC } from "./package-metadata.js";
12
+ import { logger } from "./logger.js";
13
+ import { withFileLock } from "./shared/governance.js";
12
14
  export function commandExists(cmd) {
13
15
  try {
14
16
  const whichCmd = process.platform === "win32" ? "where.exe" : "which";
@@ -67,10 +69,6 @@ function phrenPackageSpec() {
67
69
  export function shellEscape(s) {
68
70
  return "'" + s.replace(/'/g, "'\\''") + "'";
69
71
  }
70
- /** @deprecated Use shellEscape instead */
71
- function shellSingleQuote(value) {
72
- return shellEscape(value);
73
- }
74
72
  function buildPackageLifecycleCommands() {
75
73
  const packageSpec = phrenPackageSpec();
76
74
  return {
@@ -84,10 +82,10 @@ export function buildLifecycleCommands(phrenPath) {
84
82
  const entry = resolveCliEntryScript();
85
83
  const isWindows = process.platform === "win32";
86
84
  const escapedPhren = phrenPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
87
- const quotedPhren = shellSingleQuote(phrenPath);
85
+ const quotedPhren = shellEscape(phrenPath);
88
86
  if (entry) {
89
87
  const escapedEntry = entry.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
90
- const quotedEntry = shellSingleQuote(entry);
88
+ const quotedEntry = shellEscape(entry);
91
89
  if (isWindows) {
92
90
  return {
93
91
  sessionStart: `set "PHREN_PATH=${escapedPhren}" && node "${escapedEntry}" hook-session-start`,
@@ -126,7 +124,7 @@ function withHookToolEnv(command, tool) {
126
124
  if (process.platform === "win32") {
127
125
  return `set "PHREN_HOOK_TOOL=${tool}" && ${command}`;
128
126
  }
129
- return `PHREN_HOOK_TOOL=${shellSingleQuote(tool)} ${command}`;
127
+ return `PHREN_HOOK_TOOL=${shellEscape(tool)} ${command}`;
130
128
  }
131
129
  function withHookToolLifecycleCommands(lifecycle, tool) {
132
130
  return {
@@ -153,10 +151,10 @@ function installSessionWrapper(tool, phrenPath) {
153
151
  const content = `#!/bin/sh
154
152
  set -u
155
153
 
156
- REAL_BIN=${shellSingleQuote(realBinary)}
157
- DEFAULT_PHREN_PATH=${shellSingleQuote(phrenPath)}
154
+ REAL_BIN=${shellEscape(realBinary)}
155
+ DEFAULT_PHREN_PATH=${shellEscape(phrenPath)}
158
156
  PHREN_PATH="\${PHREN_PATH:-$DEFAULT_PHREN_PATH}"
159
- ENTRY_SCRIPT=${shellSingleQuote(entry || "")}
157
+ ENTRY_SCRIPT=${shellEscape(entry || "")}
160
158
  export PHREN_HOOK_TOOL="${tool}"
161
159
 
162
160
  if [ ! -x "$REAL_BIN" ]; then
@@ -399,9 +397,7 @@ async function validateAndResolveWebhook(webhook) {
399
397
  }
400
398
  catch (err) {
401
399
  debugLog(`validateAndResolveWebhook lookup failed for ${parsed.hostname}: ${errorMessage(err)}`);
402
- // DNS resolution failed; allow the fetch to proceed with the original URL
403
- // (fetch will do its own resolution and may fail with a network error)
404
- return { resolvedUrl: webhook, host: parsed.host };
400
+ return { error: `webhook hostname "${parsed.hostname}" could not be resolved: ${errorMessage(err)}` };
405
401
  }
406
402
  }
407
403
  const DEFAULT_CUSTOM_HOOK_TIMEOUT = 5000;
@@ -430,18 +426,24 @@ export function readCustomHooks(phrenPath) {
430
426
  function appendHookErrorLog(phrenPath, event, message) {
431
427
  const logPath = runtimeFile(phrenPath, "hook-errors.log");
432
428
  const line = `[${new Date().toISOString()}] [${event}] ${message}\n`;
433
- fs.appendFileSync(logPath, line);
434
429
  try {
435
- const stat = fs.statSync(logPath);
436
- if (stat.size > 200_000) {
437
- const content = fs.readFileSync(logPath, "utf-8");
438
- const lines = content.split("\n").filter(Boolean);
439
- atomicWriteText(logPath, lines.slice(-HOOK_ERROR_LOG_MAX_LINES).join("\n") + "\n");
440
- }
430
+ withFileLock(logPath, () => {
431
+ fs.appendFileSync(logPath, line);
432
+ try {
433
+ const stat = fs.statSync(logPath);
434
+ if (stat.size > 200_000) {
435
+ const content = fs.readFileSync(logPath, "utf-8");
436
+ const lines = content.split("\n").filter(Boolean);
437
+ atomicWriteText(logPath, lines.slice(-HOOK_ERROR_LOG_MAX_LINES).join("\n") + "\n");
438
+ }
439
+ }
440
+ catch (err) {
441
+ logger.debug("appendHookErrorLog rotate", errorMessage(err));
442
+ }
443
+ });
441
444
  }
442
445
  catch (err) {
443
- if (process.env.PHREN_DEBUG)
444
- process.stderr.write(`[phren] appendHookErrorLog rotate: ${errorMessage(err)}\n`);
446
+ logger.debug("appendHookErrorLog lock", errorMessage(err));
445
447
  }
446
448
  }
447
449
  export function runCustomHooks(phrenPath, event, env = {}) {
@@ -488,8 +490,7 @@ export function runCustomHooks(phrenPath, event, env = {}) {
488
490
  appendHookErrorLog(phrenPath, event, message);
489
491
  }
490
492
  catch (logErr) {
491
- if (process.env.PHREN_DEBUG)
492
- process.stderr.write(`[phren] runCustomHooks webhookErrorLog: ${errorMessage(logErr)}\n`);
493
+ logger.debug("runCustomHooks webhookErrorLog", errorMessage(logErr));
493
494
  }
494
495
  });
495
496
  continue;
@@ -503,12 +504,22 @@ export function runCustomHooks(phrenPath, event, env = {}) {
503
504
  continue;
504
505
  }
505
506
  const shellArgs = isWindows ? ["/c", hook.command] : ["-c", hook.command];
507
+ // On Windows, cmd /c expands %VAR% in the command string.
508
+ // Sanitize env values to prevent shell metacharacter injection.
509
+ const mergedEnv = { ...process.env, PHREN_PATH: phrenPath, PHREN_HOOK_EVENT: event, ...env };
510
+ if (isWindows) {
511
+ for (const [key, val] of Object.entries(mergedEnv)) {
512
+ if (typeof val === "string") {
513
+ mergedEnv[key] = val.replace(/[&|<>^%]/g, "");
514
+ }
515
+ }
516
+ }
506
517
  try {
507
518
  execFileSync(shellCmd, shellArgs, {
508
519
  cwd: phrenPath,
509
520
  encoding: "utf8",
510
521
  timeout: hook.timeout ?? DEFAULT_CUSTOM_HOOK_TIMEOUT,
511
- env: { ...process.env, PHREN_PATH: phrenPath, PHREN_HOOK_EVENT: event, ...env },
522
+ env: mergedEnv,
512
523
  stdio: ["ignore", "ignore", "pipe"],
513
524
  });
514
525
  }
@@ -520,8 +531,7 @@ export function runCustomHooks(phrenPath, event, env = {}) {
520
531
  appendHookErrorLog(phrenPath, event, errorMessage(err));
521
532
  }
522
533
  catch (logErr) {
523
- if (process.env.PHREN_DEBUG)
524
- process.stderr.write(`[phren] runCustomHooks hookErrorLog: ${errorMessage(logErr)}\n`);
534
+ logger.debug("runCustomHooks hookErrorLog", errorMessage(logErr));
525
535
  }
526
536
  }
527
537
  }
@@ -572,8 +582,7 @@ export function configureAllHooks(phrenPath, options = {}) {
572
582
  existing = JSON.parse(fs.readFileSync(cursorFile, "utf8"));
573
583
  }
574
584
  catch (err) {
575
- if (process.env.PHREN_DEBUG)
576
- process.stderr.write(`[phren] configureAllHooks cursorRead: ${errorMessage(err)}\n`);
585
+ logger.debug("configureAllHooks cursorRead", errorMessage(err));
577
586
  }
578
587
  const config = {
579
588
  ...existing,
@@ -604,8 +613,7 @@ export function configureAllHooks(phrenPath, options = {}) {
604
613
  existing = JSON.parse(fs.readFileSync(codexFile, "utf8"));
605
614
  }
606
615
  catch (err) {
607
- if (process.env.PHREN_DEBUG)
608
- process.stderr.write(`[phren] configureAllHooks codexRead: ${errorMessage(err)}\n`);
616
+ logger.debug("configureAllHooks codexRead", errorMessage(err));
609
617
  }
610
618
  const config = {
611
619
  ...existing,
@@ -1,5 +1,6 @@
1
1
  import * as path from "path";
2
2
  import { debugLog } from "./shared.js";
3
+ import { logger } from "./logger.js";
3
4
  function describeSqlValue(value) {
4
5
  if (value === null)
5
6
  return "null";
@@ -78,7 +79,9 @@ export function queryRows(db, sql, params) {
78
79
  return results[0].values;
79
80
  }
80
81
  catch (err) {
81
- debugLog(`queryRows failed: ${err instanceof Error ? err.message : "unknown error"}`);
82
+ const msg = err instanceof Error ? err.message : "unknown error";
83
+ logger.debug("queryRows", `DB query failed: ${msg}`);
84
+ debugLog(`queryRows failed: ${msg}`);
82
85
  return null;
83
86
  }
84
87
  }
package/mcp/dist/index.js CHANGED
@@ -4,22 +4,22 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import { findPhrenPathWithArg, debugLog, runtimeDir, } from "./shared.js";
7
- import { log as structuredLog } from "./logger.js";
8
- import { buildIndex, updateFileInIndex as updateFileInIndexFn, } from "./shared-index.js";
7
+ import { log as structuredLog, logger } from "./logger.js";
8
+ import { buildIndex, updateFileInIndex as updateFileInIndexFn, } from "./shared/index.js";
9
9
  import { runCustomHooks } from "./hooks.js";
10
- import { register as registerSearch } from "./mcp-search.js";
11
- import { register as registerTask } from "./mcp-tasks.js";
12
- import { register as registerFinding } from "./mcp-finding.js";
13
- import { register as registerMemory } from "./mcp-memory.js";
14
- import { register as registerData } from "./mcp-data.js";
15
- import { register as registerGraph } from "./mcp-graph.js";
16
- import { register as registerSession } from "./mcp-session.js";
17
- import { register as registerOps } from "./mcp-ops.js";
18
- import { register as registerSkills } from "./mcp-skills.js";
19
- import { register as registerHooks } from "./mcp-hooks.js";
20
- import { register as registerExtract } from "./mcp-extract.js";
21
- import { register as registerConfig } from "./mcp-config.js";
22
- import { mcpResponse } from "./mcp-types.js";
10
+ import { register as registerSearch } from "./tools/search.js";
11
+ import { register as registerTask } from "./tools/tasks.js";
12
+ import { register as registerFinding } from "./tools/finding.js";
13
+ import { register as registerMemory } from "./tools/memory.js";
14
+ import { register as registerData } from "./tools/data.js";
15
+ import { register as registerGraph } from "./tools/graph.js";
16
+ import { register as registerSession } from "./tools/session.js";
17
+ import { register as registerOps } from "./tools/ops.js";
18
+ import { register as registerSkills } from "./tools/skills.js";
19
+ import { register as registerHooks } from "./tools/hooks.js";
20
+ import { register as registerExtract } from "./tools/extract.js";
21
+ import { register as registerConfig } from "./tools/config.js";
22
+ import { mcpResponse } from "./tools/types.js";
23
23
  import { errorMessage } from "./utils.js";
24
24
  import { runTopLevelCommand } from "./entrypoint.js";
25
25
  import { startEmbeddingWarmup } from "./startup-embedding.js";
@@ -48,14 +48,12 @@ function cleanStaleLocks(phrenPath) {
48
48
  }
49
49
  }
50
50
  catch (err) {
51
- if ((process.env.PHREN_DEBUG))
52
- process.stderr.write(`[phren] cleanStaleLocks statFile: ${errorMessage(err)}\n`);
51
+ logger.warn("cleanStaleLocks", `statFile: ${errorMessage(err)}`);
53
52
  }
54
53
  }
55
54
  }
56
55
  catch (err) {
57
- if ((process.env.PHREN_DEBUG))
58
- process.stderr.write(`[phren] cleanStaleLocks readdir: ${errorMessage(err)}\n`);
56
+ logger.warn("cleanStaleLocks", `readdir: ${errorMessage(err)}`);
59
57
  }
60
58
  }
61
59
  async function main() {
@@ -67,7 +65,7 @@ async function main() {
67
65
  db = await buildIndex(phrenPath, profile);
68
66
  indexReady = true;
69
67
  // Load embedding cache and kick off background embedding (fire-and-forget)
70
- const { getEmbeddingCache } = await import("./shared-embedding-cache.js");
68
+ const { getEmbeddingCache } = await import("./shared/embedding-cache.js");
71
69
  const embCache = getEmbeddingCache(phrenPath);
72
70
  void startEmbeddingWarmup(db, embCache);
73
71
  }
@@ -83,21 +81,29 @@ async function main() {
83
81
  const WRITE_TIMEOUT_MS = 30_000;
84
82
  async function rebuildIndex() {
85
83
  runCustomHooks(phrenPath, "pre-index");
86
- indexReady = false;
84
+ const oldDb = db;
87
85
  try {
88
- db?.close();
86
+ indexReady = false;
87
+ db = await buildIndex(phrenPath, profile);
88
+ indexReady = true;
89
+ try {
90
+ oldDb?.close();
91
+ }
92
+ catch (err) {
93
+ logger.warn("rebuildIndex", `dbClose: ${errorMessage(err)}`);
94
+ }
89
95
  }
90
96
  catch (err) {
91
- if ((process.env.PHREN_DEBUG))
92
- process.stderr.write(`[phren] rebuildIndex dbClose: ${errorMessage(err)}\n`);
97
+ // Restore old state on failure
98
+ db = oldDb;
99
+ indexReady = !!oldDb;
100
+ throw err;
93
101
  }
94
- db = await buildIndex(phrenPath, profile);
95
- indexReady = true;
96
102
  runCustomHooks(phrenPath, "post-index");
97
103
  }
98
104
  async function withWriteQueue(fn) {
99
105
  if (writeQueueDepth >= MAX_QUEUE_DEPTH) {
100
- throw new Error(`Write queue full (${MAX_QUEUE_DEPTH} items). Try again shortly.`);
106
+ return mcpResponse({ ok: false, error: `Write queue full (${MAX_QUEUE_DEPTH} items). Try again shortly.`, errorCode: "TIMEOUT" });
101
107
  }
102
108
  writeQueueDepth++;
103
109
  const run = writeQueue.then(async () => {
@@ -158,8 +164,7 @@ async function main() {
158
164
  trackToolCall(phrenPath, registeredName);
159
165
  }
160
166
  catch (err) {
161
- if ((process.env.PHREN_DEBUG))
162
- process.stderr.write(`[phren] trackToolCall: ${errorMessage(err)}\n`);
167
+ logger.warn("trackToolCall", errorMessage(err));
163
168
  }
164
169
  return handler(...args);
165
170
  };
@@ -197,6 +202,25 @@ async function main() {
197
202
  const transport = new StdioServerTransport();
198
203
  await server.connect(transport);
199
204
  console.error(`phren-mcp running (${phrenPath})`);
205
+ // Graceful shutdown: drain write queue and close DB before exit
206
+ async function shutdown(signal) {
207
+ structuredLog("info", "shutdown", `Received ${signal}, draining write queue...`);
208
+ try {
209
+ await writeQueue;
210
+ }
211
+ catch {
212
+ // Write queue errors already logged
213
+ }
214
+ try {
215
+ db?.close();
216
+ }
217
+ catch (err) {
218
+ logger.warn("shutdown", `dbClose: ${errorMessage(err)}`);
219
+ }
220
+ process.exit(0);
221
+ }
222
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
223
+ process.on("SIGINT", () => void shutdown("SIGINT"));
200
224
  }
201
225
  if (!handledTopLevelCommand) {
202
226
  main().catch((err) => {
@@ -4,12 +4,12 @@
4
4
  */
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
- import { buildLifecycleCommands, commandExists } from "./hooks.js";
8
- import { isRecord, hookConfigPath, homePath, readRootManifest, atomicWriteText, } from "./shared.js";
9
- import { isFeatureEnabled, errorMessage } from "./utils.js";
10
- import { probeVsCodeConfig, resolveCodexMcpConfig, resolveCopilotMcpConfig, resolveCursorMcpConfig, } from "./provider-adapters.js";
11
- import { getMcpEnabledPreference, getHooksEnabledPreference } from "./init-preferences.js";
12
- import { resolveEntryScript, log, VERSION } from "./init-shared.js";
7
+ import { buildLifecycleCommands, commandExists } from "../hooks.js";
8
+ import { isRecord, hookConfigPath, homePath, readRootManifest, atomicWriteText, } from "../shared.js";
9
+ import { isFeatureEnabled, errorMessage } from "../utils.js";
10
+ import { probeVsCodeConfig, resolveCodexMcpConfig, resolveCopilotMcpConfig, resolveCursorMcpConfig, } from "../provider-adapters.js";
11
+ import { getMcpEnabledPreference, getHooksEnabledPreference } from "./preferences.js";
12
+ import { resolveEntryScript, log, VERSION } from "./shared.js";
13
13
  function getObjectProp(value, key) {
14
14
  const candidate = value[key];
15
15
  return isRecord(candidate) ? candidate : undefined;
@@ -6,24 +6,25 @@ import * as fs from "fs";
6
6
  import * as path from "path";
7
7
  import * as crypto from "crypto";
8
8
  import { execFileSync, spawnSync } from "child_process";
9
- import { configureAllHooks } from "./hooks.js";
10
- import { getMachineName, machineFilePath, persistMachineName } from "./machine-identity.js";
11
- import { atomicWriteText, debugLog, isRecord, hookConfigPath, homeDir, homePath, expandHomePath, findPhrenPath, getProjectDirs, readRootManifest, writeRootManifest, } from "./shared.js";
12
- import { isValidProjectName, errorMessage } from "./utils.js";
13
- import { codexJsonCandidates, copilotMcpCandidates, cursorMcpCandidates, vscodeMcpCandidates, } from "./provider-adapters.js";
14
- export { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, resetVSCodeProbeCache, patchJsonFile, } from "./init-config.js";
15
- export { getMcpEnabledPreference, setMcpEnabledPreference, getHooksEnabledPreference, setHooksEnabledPreference, } from "./init-preferences.js";
16
- export { PROJECT_OWNERSHIP_MODES, parseProjectOwnershipMode, getProjectOwnershipDefault, } from "./project-config.js";
17
- export { PROACTIVITY_LEVELS, getProactivityLevel, getProactivityLevelForFindings, getProactivityLevelForTask, } from "./proactivity.js";
18
- export { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, getVerifyOutcomeNote, listTemplates, detectProjectDir, isProjectTracked, ensureLocalGitRepo, resolvePreferredHomeDir, inferInitScaffoldFromRepo, } from "./init-setup.js";
9
+ import { configureAllHooks } from "../hooks.js";
10
+ import { getMachineName, machineFilePath, persistMachineName } from "../machine-identity.js";
11
+ import { atomicWriteText, debugLog, isRecord, hookConfigPath, homeDir, homePath, expandHomePath, findPhrenPath, getProjectDirs, readRootManifest, writeRootManifest, } from "../shared.js";
12
+ import { isValidProjectName, errorMessage } from "../utils.js";
13
+ import { codexJsonCandidates, copilotMcpCandidates, cursorMcpCandidates, vscodeMcpCandidates, } from "../provider-adapters.js";
14
+ import { logger } from "../logger.js";
15
+ export { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, resetVSCodeProbeCache, patchJsonFile, } from "./config.js";
16
+ export { getMcpEnabledPreference, setMcpEnabledPreference, getHooksEnabledPreference, setHooksEnabledPreference, } from "./preferences.js";
17
+ export { PROJECT_OWNERSHIP_MODES, parseProjectOwnershipMode, getProjectOwnershipDefault, } from "../project-config.js";
18
+ export { PROACTIVITY_LEVELS, getProactivityLevel, getProactivityLevelForFindings, getProactivityLevelForTask, } from "../proactivity.js";
19
+ export { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, getVerifyOutcomeNote, listTemplates, detectProjectDir, isProjectTracked, ensureLocalGitRepo, resolvePreferredHomeDir, inferInitScaffoldFromRepo, } from "./setup.js";
19
20
  // Imports from helpers (used internally in this file)
20
- import { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, removeMcpServerAtPath, removeTomlMcpServer, isPhrenCommand, patchJsonFile, } from "./init-config.js";
21
- import { getMcpEnabledPreference, getHooksEnabledPreference, setMcpEnabledPreference, setHooksEnabledPreference, writeInstallPreferences, writeGovernanceInstallPreferences, readInstallPreferences, } from "./init-preferences.js";
22
- import { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, applyStarterTemplateUpdates, listTemplates, applyTemplate, ensureProjectScaffold, ensureLocalGitRepo, bootstrapFromExisting, ensureGitignoreEntry, upsertProjectEnvVar, updateMachinesYaml, detectProjectDir, isProjectTracked, inferInitScaffoldFromRepo, } from "./init-setup.js";
23
- import { DEFAULT_PHREN_PATH, STARTER_DIR, VERSION, log, confirmPrompt } from "./init-shared.js";
24
- import { PROJECT_OWNERSHIP_MODES, getProjectOwnershipDefault, } from "./project-config.js";
25
- import { getWorkflowPolicy, updateWorkflowPolicy } from "./shared-governance.js";
26
- import { addProjectToProfile } from "./profile-store.js";
21
+ import { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, removeMcpServerAtPath, removeTomlMcpServer, isPhrenCommand, patchJsonFile, } from "./config.js";
22
+ import { getMcpEnabledPreference, getHooksEnabledPreference, setMcpEnabledPreference, setHooksEnabledPreference, writeInstallPreferences, writeGovernanceInstallPreferences, readInstallPreferences, } from "./preferences.js";
23
+ import { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, applyStarterTemplateUpdates, listTemplates, applyTemplate, ensureProjectScaffold, ensureLocalGitRepo, bootstrapFromExisting, ensureGitignoreEntry, upsertProjectEnvVar, updateMachinesYaml, detectProjectDir, isProjectTracked, inferInitScaffoldFromRepo, } from "./setup.js";
24
+ import { DEFAULT_PHREN_PATH, STARTER_DIR, VERSION, log, confirmPrompt } from "./shared.js";
25
+ import { PROJECT_OWNERSHIP_MODES, getProjectOwnershipDefault, } from "../project-config.js";
26
+ import { getWorkflowPolicy, updateWorkflowPolicy } from "../shared/governance.js";
27
+ import { addProjectToProfile } from "../profile-store.js";
27
28
  const PHREN_NPM_PACKAGE_NAME = "@phren/cli";
28
29
  function parseVersion(version) {
29
30
  const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?/);
@@ -289,7 +290,7 @@ async function runWalkthrough(phrenPath) {
289
290
  log(style.success(`✓ ${item}`));
290
291
  }
291
292
  };
292
- const { renderPhrenArt } = await import("./phren-art.js");
293
+ const { renderPhrenArt } = await import("../phren-art.js");
293
294
  log("");
294
295
  log(renderPhrenArt(" "));
295
296
  log("");
@@ -434,7 +435,7 @@ async function runWalkthrough(phrenPath) {
434
435
  log(" Change later: set PHREN_OLLAMA_URL=off to disable");
435
436
  let ollamaEnabled = false;
436
437
  try {
437
- const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl } = await import("./shared-ollama.js");
438
+ const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl } = await import("../shared/ollama.js");
438
439
  if (getOllamaUrl()) {
439
440
  const ollamaUp = await checkOllamaAvailable();
440
441
  if (ollamaUp) {
@@ -463,8 +464,7 @@ async function runWalkthrough(phrenPath) {
463
464
  }
464
465
  }
465
466
  catch (err) {
466
- if ((process.env.PHREN_DEBUG))
467
- process.stderr.write(`[phren] init ollamaCheck: ${errorMessage(err)}\n`);
467
+ logger.debug("init", `init ollamaCheck: ${errorMessage(err)}`);
468
468
  }
469
469
  printSection("Auto-Capture (Optional)");
470
470
  log("After each session, phren scans the conversation for insight-signal phrases");
@@ -663,7 +663,7 @@ async function runWalkthrough(phrenPath) {
663
663
  };
664
664
  }
665
665
  export async function warmSemanticSearch(phrenPath, profile) {
666
- const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("./shared-ollama.js");
666
+ const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("../shared/ollama.js");
667
667
  const ollamaUrl = getOllamaUrl();
668
668
  if (!ollamaUrl)
669
669
  return "Semantic search: disabled.";
@@ -674,10 +674,10 @@ export async function warmSemanticSearch(phrenPath, profile) {
674
674
  if (!await checkModelAvailable()) {
675
675
  return `Semantic search not warmed: model ${model} is not pulled yet.`;
676
676
  }
677
- const { buildIndex, listIndexedDocumentPaths } = await import("./shared-index.js");
678
- const { getEmbeddingCache, formatEmbeddingCoverage } = await import("./shared-embedding-cache.js");
679
- const { backgroundEmbedMissingDocs } = await import("./startup-embedding.js");
680
- const { getPersistentVectorIndex } = await import("./shared-vector-index.js");
677
+ const { buildIndex, listIndexedDocumentPaths } = await import("../shared/index.js");
678
+ const { getEmbeddingCache, formatEmbeddingCoverage } = await import("../shared/embedding-cache.js");
679
+ const { backgroundEmbedMissingDocs } = await import("../startup-embedding.js");
680
+ const { getPersistentVectorIndex } = await import("../shared/vector-index.js");
681
681
  const db = await buildIndex(phrenPath, profile);
682
682
  try {
683
683
  const cache = getEmbeddingCache(phrenPath);
@@ -1450,7 +1450,7 @@ export async function runInit(opts = {}) {
1450
1450
  const walkthroughCoveredOllama = Boolean(process.env._PHREN_WALKTHROUGH_OLLAMA_SKIP) || (!hasExistingInstall && !opts.yes);
1451
1451
  if (!walkthroughCoveredOllama) {
1452
1452
  try {
1453
- const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl } = await import("./shared-ollama.js");
1453
+ const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl } = await import("../shared/ollama.js");
1454
1454
  if (getOllamaUrl()) {
1455
1455
  const ollamaUp = await checkOllamaAvailable();
1456
1456
  if (ollamaUp) {
@@ -1471,8 +1471,7 @@ export async function runInit(opts = {}) {
1471
1471
  }
1472
1472
  }
1473
1473
  catch (err) {
1474
- if ((process.env.PHREN_DEBUG))
1475
- process.stderr.write(`[phren] init ollamaInstallHint: ${errorMessage(err)}\n`);
1474
+ logger.debug("init", `init ollamaInstallHint: ${errorMessage(err)}`);
1476
1475
  }
1477
1476
  }
1478
1477
  for (const envLabel of writeWalkthroughEnvDefaults(phrenPath, opts)) {
@@ -4,9 +4,9 @@
4
4
  import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import * as crypto from "crypto";
7
- import { debugLog, installPreferencesFile } from "./phren-paths.js";
8
- import { errorMessage } from "./utils.js";
9
- import { withFileLock } from "./shared-governance.js";
7
+ import { debugLog, installPreferencesFile } from "../phren-paths.js";
8
+ import { errorMessage } from "../utils.js";
9
+ import { withFileLock } from "../shared/governance.js";
10
10
  function preferencesFile(phrenPath) {
11
11
  return installPreferencesFile(phrenPath);
12
12
  }
@@ -5,19 +5,20 @@ import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import * as os from "os";
7
7
  import * as yaml from "js-yaml";
8
- import { atomicWriteText, debugLog, findProjectNameCaseInsensitive, hookConfigPath, EXEC_TIMEOUT_QUICK_MS, readRootManifest, sessionsDir, runtimeHealthFile, isRecord, } from "./shared.js";
9
- import { addProjectToProfile, listProfiles, resolveActiveProfile, setMachineProfile } from "./profile-store.js";
10
- import { getMachineName } from "./machine-identity.js";
8
+ import { atomicWriteText, debugLog, findProjectNameCaseInsensitive, hookConfigPath, EXEC_TIMEOUT_QUICK_MS, readRootManifest, sessionsDir, runtimeHealthFile, isRecord, } from "../shared.js";
9
+ import { addProjectToProfile, listProfiles, resolveActiveProfile, setMachineProfile } from "../profile-store.js";
10
+ import { getMachineName } from "../machine-identity.js";
11
11
  import { execFileSync } from "child_process";
12
- import { GOVERNANCE_SCHEMA_VERSION, } from "./shared-governance.js";
13
- import { STOP_WORDS, errorMessage } from "./utils.js";
14
- import { ROOT, STARTER_DIR, VERSION, resolveEntryScript, commandVersion, versionAtLeast, nearestWritableTarget } from "./init-shared.js";
15
- import { readInstallPreferences } from "./init-preferences.js";
16
- import { TASKS_FILENAME } from "./data-tasks.js";
17
- import { getProjectOwnershipDefault, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, } from "./project-config.js";
18
- import { getBuiltinTopicConfig, normalizeBuiltinTopicDomain } from "./project-topics.js";
19
- import { writeSkillMd } from "./link-skills.js";
20
- import { syncScopeSkillsToDir } from "./skill-files.js";
12
+ import { GOVERNANCE_SCHEMA_VERSION, } from "../shared/governance.js";
13
+ import { STOP_WORDS, errorMessage } from "../utils.js";
14
+ import { ROOT, STARTER_DIR, VERSION, resolveEntryScript, commandVersion, versionAtLeast, nearestWritableTarget } from "./shared.js";
15
+ import { readInstallPreferences } from "./preferences.js";
16
+ import { TASKS_FILENAME } from "../data/tasks.js";
17
+ import { getProjectOwnershipDefault, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, } from "../project-config.js";
18
+ import { getBuiltinTopicConfig, normalizeBuiltinTopicDomain } from "../project-topics.js";
19
+ import { writeSkillMd } from "../link/skills.js";
20
+ import { syncScopeSkillsToDir } from "../skill/files.js";
21
+ import { logger } from "../logger.js";
21
22
  const LEGACY_SAMPLE_PROJECTS = new Set(["my-api", "my-frontend"]);
22
23
  function normalizeProjects(raw) {
23
24
  if (!Array.isArray(raw))
@@ -1052,16 +1053,14 @@ export function updateMachinesYaml(phrenPath, machine, profile) {
1052
1053
  }
1053
1054
  }
1054
1055
  catch (err) {
1055
- if ((process.env.PHREN_DEBUG))
1056
- process.stderr.write(`[phren] updateMachinesYaml parse: ${errorMessage(err)}\n`);
1056
+ logger.debug("setup", `updateMachinesYaml parse: ${errorMessage(err)}`);
1057
1057
  }
1058
1058
  // Passive init/link refreshes should keep an existing mapping; explicit overrides can remap.
1059
1059
  if (hasExistingMapping && !machine && !profile)
1060
1060
  return;
1061
1061
  const mapping = setMachineProfile(phrenPath, machineName, profileName);
1062
- if (!mapping.ok && (process.env.PHREN_DEBUG)) {
1063
- process.stderr.write(`[phren] updateMachinesYaml setMachineProfile: ${mapping.error}\n`);
1064
- }
1062
+ if (!mapping.ok)
1063
+ logger.debug("setup", `updateMachinesYaml setMachineProfile: ${mapping.error}`);
1065
1064
  }
1066
1065
  /**
1067
1066
  * Detect if a directory looks like a project that should be bootstrapped.
@@ -1262,8 +1261,7 @@ export function runPostInitVerify(phrenPath) {
1262
1261
  ftsOk = entries.some(d => d.isDirectory() && !d.name.startsWith("."));
1263
1262
  }
1264
1263
  catch (err) {
1265
- if ((process.env.PHREN_DEBUG))
1266
- process.stderr.write(`[phren] runPostInitVerify projectScan: ${errorMessage(err)}\n`);
1264
+ logger.debug("setup", `runPostInitVerify projectScan: ${errorMessage(err)}`);
1267
1265
  ftsOk = false;
1268
1266
  }
1269
1267
  checks.push({
@@ -5,9 +5,9 @@
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
7
  import { execFileSync } from "child_process";
8
- import { homePath, EXEC_TIMEOUT_QUICK_MS, debugLog } from "./shared.js";
9
- import { errorMessage } from "./utils.js";
10
- import { ROOT as PACKAGE_ROOT, VERSION } from "./package-metadata.js";
8
+ import { homePath, EXEC_TIMEOUT_QUICK_MS, debugLog } from "../shared.js";
9
+ import { errorMessage } from "../utils.js";
10
+ import { ROOT as PACKAGE_ROOT, VERSION } from "../package-metadata.js";
11
11
  export const ROOT = PACKAGE_ROOT;
12
12
  export { VERSION };
13
13
  export const STARTER_DIR = path.join(ROOT, "starter");