@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.
- package/mcp/dist/capabilities/cli.js +2 -5
- package/mcp/dist/capabilities/mcp.js +5 -8
- package/mcp/dist/capabilities/types.js +2 -5
- package/mcp/dist/capabilities/vscode.js +2 -5
- package/mcp/dist/capabilities/web-ui.js +2 -5
- package/mcp/dist/{cli-actions.js → cli/actions.js} +25 -21
- package/mcp/dist/{cli.js → cli/cli.js} +13 -13
- package/mcp/dist/{cli-config.js → cli/config.js} +12 -12
- package/mcp/dist/{cli-extract.js → cli/extract.js} +8 -8
- package/mcp/dist/{cli-govern.js → cli/govern.js} +28 -17
- package/mcp/dist/{cli-graph.js → cli/graph.js} +10 -9
- package/mcp/dist/{cli-hooks-citations.js → cli/hooks-citations.js} +2 -2
- package/mcp/dist/{cli-hooks-context.js → cli/hooks-context.js} +23 -23
- package/mcp/dist/{cli-hooks-globs.js → cli/hooks-globs.js} +4 -4
- package/mcp/dist/{cli-hooks-output.js → cli/hooks-output.js} +9 -10
- package/mcp/dist/{cli-hooks-session.js → cli/hooks-session.js} +58 -117
- package/mcp/dist/{cli-hooks.js → cli/hooks.js} +27 -26
- package/mcp/dist/{cli-namespaces.js → cli/namespaces.js} +25 -24
- package/mcp/dist/{cli-ops.js → cli/ops.js} +9 -9
- package/mcp/dist/{cli-search.js → cli/search.js} +12 -11
- package/mcp/dist/cli-hooks-git.js +243 -0
- package/mcp/dist/cli-hooks-prompt.js +323 -0
- package/mcp/dist/cli-hooks-session-handlers.js +337 -0
- package/mcp/dist/cli-hooks-stop.js +519 -0
- package/mcp/dist/{content-archive.js → content/archive.js} +16 -29
- package/mcp/dist/{content-citation.js → content/citation.js} +5 -5
- package/mcp/dist/{content-dedup.js → content/dedup.js} +9 -12
- package/mcp/dist/{content-learning.js → content/learning.js} +41 -20
- package/mcp/dist/{content-validate.js → content/validate.js} +5 -5
- package/mcp/dist/{core-finding.js → core/finding.js} +4 -4
- package/mcp/dist/{core-project.js → core/project.js} +4 -4
- package/mcp/dist/{core-search.js → core/search.js} +2 -2
- package/mcp/dist/{data-access.js → data/access.js} +142 -15
- package/mcp/dist/{data-tasks.js → data/tasks.js} +7 -5
- package/mcp/dist/embedding.js +9 -14
- package/mcp/dist/entrypoint.js +11 -11
- package/mcp/dist/{finding-context.js → finding/context.js} +2 -2
- package/mcp/dist/{finding-impact.js → finding/impact.js} +3 -3
- package/mcp/dist/{finding-journal.js → finding/journal.js} +4 -4
- package/mcp/dist/{finding-lifecycle.js → finding/lifecycle.js} +13 -7
- package/mcp/dist/governance/audit.js +30 -0
- package/mcp/dist/{governance-locks.js → governance/locks.js} +14 -9
- package/mcp/dist/{governance-policy.js → governance/policy.js} +23 -12
- package/mcp/dist/{governance-rbac.js → governance/rbac.js} +4 -4
- package/mcp/dist/{governance-scores.js → governance/scores.js} +10 -11
- package/mcp/dist/hooks.js +53 -37
- package/mcp/dist/index-query.js +4 -1
- package/mcp/dist/index.js +54 -30
- package/mcp/dist/{init-config.js → init/config.js} +6 -6
- package/mcp/dist/{init.js → init/init.js} +80 -69
- package/mcp/dist/{init-preferences.js → init/preferences.js} +3 -3
- package/mcp/dist/{init-setup.js → init/setup.js} +17 -19
- package/mcp/dist/{init-shared.js → init/shared.js} +4 -4
- package/mcp/dist/init-bootstrap.js +21 -0
- package/mcp/dist/init-detect.js +38 -0
- package/mcp/dist/init-env.js +114 -0
- package/mcp/dist/init-fresh.js +234 -0
- package/mcp/dist/init-hooks.js +26 -0
- package/mcp/dist/init-mcp.js +65 -0
- package/mcp/dist/init-modes.js +135 -0
- package/mcp/dist/init-npm.js +37 -0
- package/mcp/dist/init-project-local.js +99 -0
- package/mcp/dist/init-semantic.js +48 -0
- package/mcp/dist/init-types.js +1 -0
- package/mcp/dist/init-uninstall.js +504 -0
- package/mcp/dist/init-update.js +96 -0
- package/mcp/dist/init-walkthrough.js +524 -0
- package/mcp/dist/{link-checksums.js → link/checksums.js} +5 -5
- package/mcp/dist/{link-context.js → link/context.js} +4 -4
- package/mcp/dist/{link-doctor.js → link/doctor.js} +20 -22
- package/mcp/dist/{link.js → link/link.js} +26 -31
- package/mcp/dist/{link-skills.js → link/skills.js} +10 -10
- package/mcp/dist/logger.js +11 -3
- package/mcp/dist/package-metadata.js +1 -1
- package/mcp/dist/phren-art.js +4 -126
- package/mcp/dist/phren-paths.js +30 -12
- package/mcp/dist/proactivity.js +3 -3
- package/mcp/dist/profile-store.js +5 -6
- package/mcp/dist/project-config.js +2 -2
- package/mcp/dist/project-topics.js +17 -47
- package/mcp/dist/provider-adapters.js +1 -1
- package/mcp/dist/query-correlation.js +1 -1
- package/mcp/dist/runtime-profile.js +1 -1
- package/mcp/dist/{session-checkpoints.js → session/checkpoints.js} +3 -3
- package/mcp/dist/{session-utils.js → session/utils.js} +1 -1
- package/mcp/dist/{shared-content.js → shared/content.js} +7 -7
- package/mcp/dist/{shared-data-utils.js → shared/data-utils.js} +28 -3
- package/mcp/dist/{shared-embedding-cache.js → shared/embedding-cache.js} +3 -3
- package/mcp/dist/{shared-fragment-graph.js → shared/fragment-graph.js} +19 -42
- package/mcp/dist/shared/governance.js +4 -0
- package/mcp/dist/{shared-index.js → shared/index.js} +105 -132
- package/mcp/dist/{shared-ollama.js → shared/ollama.js} +25 -7
- package/mcp/dist/shared/process.js +24 -0
- package/mcp/dist/{shared-retrieval.js → shared/retrieval.js} +22 -24
- package/mcp/dist/{shared-search-fallback.js → shared/search-fallback.js} +18 -20
- package/mcp/dist/{shared-sqljs.js → shared/sqljs.js} +3 -3
- package/mcp/dist/{shared-vector-index.js → shared/vector-index.js} +3 -3
- package/mcp/dist/shared.js +6 -60
- package/mcp/dist/{shell-entry.js → shell/entry.js} +6 -6
- package/mcp/dist/{shell-input.js → shell/input.js} +13 -13
- package/mcp/dist/{shell-palette.js → shell/palette.js} +3 -3
- package/mcp/dist/{shell-render.js → shell/render.js} +2 -2
- package/mcp/dist/{shell.js → shell/shell.js} +11 -11
- package/mcp/dist/{shell-state-store.js → shell/state-store.js} +5 -5
- package/mcp/dist/{shell-view-list.js → shell/view-list.js} +1 -1
- package/mcp/dist/{shell-view.js → shell/view.js} +13 -13
- package/mcp/dist/{skill-files.js → skill/files.js} +9 -9
- package/mcp/dist/{skill-registry.js → skill/registry.js} +5 -5
- package/mcp/dist/{skill-state.js → skill/state.js} +1 -4
- package/mcp/dist/startup-embedding.js +2 -2
- package/mcp/dist/status.js +15 -14
- package/mcp/dist/{tasks-github.js → task/github.js} +3 -2
- package/mcp/dist/{task-hygiene.js → task/hygiene.js} +4 -4
- package/mcp/dist/{task-lifecycle.js → task/lifecycle.js} +8 -13
- package/mcp/dist/telemetry.js +3 -4
- package/mcp/dist/tool-registry.js +29 -17
- package/mcp/dist/tools/config.js +530 -0
- package/mcp/dist/{mcp-data.js → tools/data.js} +8 -10
- package/mcp/dist/{mcp-extract-facts.js → tools/extract-facts.js} +6 -6
- package/mcp/dist/{mcp-extract.js → tools/extract.js} +6 -6
- package/mcp/dist/tools/finding.js +584 -0
- package/mcp/dist/{mcp-graph.js → tools/graph.js} +11 -14
- package/mcp/dist/{mcp-hooks.js → tools/hooks.js} +6 -6
- package/mcp/dist/{mcp-memory.js → tools/memory.js} +5 -5
- package/mcp/dist/tools/ops.js +468 -0
- package/mcp/dist/tools/search.js +672 -0
- package/mcp/dist/{mcp-session.js → tools/session.js} +51 -25
- package/mcp/dist/{mcp-skills.js → tools/skills.js} +42 -35
- package/mcp/dist/{mcp-tasks.js → tools/tasks.js} +155 -282
- package/mcp/dist/{memory-ui-data.js → ui/data.js} +31 -17
- package/mcp/dist/{memory-ui.js → ui/memory-ui.js} +3 -3
- package/mcp/dist/{memory-ui-page.js → ui/page.js} +5 -7
- package/mcp/dist/ui/server.js +1024 -0
- package/mcp/dist/update.js +2 -2
- package/mcp/dist/utils.js +63 -19
- package/package.json +2 -2
- package/scripts/preuninstall.mjs +31 -0
- package/starter/global/CLAUDE.md +3 -2
- package/mcp/dist/governance-audit.js +0 -22
- package/mcp/dist/mcp-config.js +0 -551
- package/mcp/dist/mcp-finding.js +0 -594
- package/mcp/dist/mcp-ops.js +0 -363
- package/mcp/dist/mcp-search.js +0 -668
- package/mcp/dist/memory-ui-server.js +0 -1411
- package/mcp/dist/shared-governance.js +0 -4
- /package/mcp/dist/{content-metadata.js → content/metadata.js} +0 -0
- /package/mcp/dist/{shared-stemmer.js → shared/stemmer.js} +0 -0
- /package/mcp/dist/{shell-types.js → shell/types.js} +0 -0
- /package/mcp/dist/{mcp-types.js → tools/types.js} +0 -0
- /package/mcp/dist/{memory-ui-assets.js → ui/assets.js} +0 -0
- /package/mcp/dist/{memory-ui-graph.js → ui/graph.js} +0 -0
- /package/mcp/dist/{memory-ui-scripts.js → ui/scripts.js} +0 -0
- /package/mcp/dist/{memory-ui-styles.js → ui/styles.js} +0 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { debugLog } from "
|
|
1
|
+
import { debugLog } from "../shared.js";
|
|
2
2
|
const DEFAULT_OLLAMA_URL = "http://localhost:11434";
|
|
3
3
|
const DEFAULT_EMBEDDING_MODEL = "nomic-embed-text";
|
|
4
4
|
const DEFAULT_EXTRACT_MODEL = "llama3.2";
|
|
5
5
|
const MAX_EMBED_INPUT_CHARS = 6000;
|
|
6
|
+
const CLOUD_EMBEDDING_TIMEOUT_MS = 15_000;
|
|
7
|
+
const OLLAMA_HEALTH_TIMEOUT_MS = 2_000;
|
|
8
|
+
const OLLAMA_EMBEDDING_TIMEOUT_MS = 10_000;
|
|
9
|
+
const OLLAMA_GENERATE_TIMEOUT_MS = 60_000;
|
|
10
|
+
/** @internal Exported for tests. */
|
|
6
11
|
export function prepareEmbeddingInput(text) {
|
|
7
12
|
return text
|
|
8
13
|
.replace(/<!--[\s\S]*?-->/g, " ")
|
|
@@ -44,7 +49,7 @@ async function embedTextCloud(input, baseUrl, model, apiKey) {
|
|
|
44
49
|
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
45
50
|
try {
|
|
46
51
|
const controller = new AbortController();
|
|
47
|
-
const id = setTimeout(() => controller.abort(),
|
|
52
|
+
const id = setTimeout(() => controller.abort(), CLOUD_EMBEDDING_TIMEOUT_MS);
|
|
48
53
|
const res = await fetch(`${baseUrl}/embeddings`, {
|
|
49
54
|
method: "POST",
|
|
50
55
|
headers,
|
|
@@ -85,7 +90,7 @@ export async function checkOllamaAvailable(url) {
|
|
|
85
90
|
return false;
|
|
86
91
|
try {
|
|
87
92
|
const controller = new AbortController();
|
|
88
|
-
const id = setTimeout(() => controller.abort(),
|
|
93
|
+
const id = setTimeout(() => controller.abort(), OLLAMA_HEALTH_TIMEOUT_MS);
|
|
89
94
|
const res = await fetch(`${baseUrl}/api/tags`, { signal: controller.signal });
|
|
90
95
|
clearTimeout(id);
|
|
91
96
|
return res.ok;
|
|
@@ -104,7 +109,7 @@ export async function checkModelAvailable(model, url) {
|
|
|
104
109
|
const modelName = model ?? getEmbeddingModel();
|
|
105
110
|
try {
|
|
106
111
|
const controller = new AbortController();
|
|
107
|
-
const id = setTimeout(() => controller.abort(),
|
|
112
|
+
const id = setTimeout(() => controller.abort(), OLLAMA_HEALTH_TIMEOUT_MS);
|
|
108
113
|
const res = await fetch(`${baseUrl}/api/tags`, { signal: controller.signal });
|
|
109
114
|
clearTimeout(id);
|
|
110
115
|
if (!res.ok)
|
|
@@ -131,7 +136,7 @@ export async function embedText(text, model, url) {
|
|
|
131
136
|
return null;
|
|
132
137
|
try {
|
|
133
138
|
const controller = new AbortController();
|
|
134
|
-
const id = setTimeout(() => controller.abort(),
|
|
139
|
+
const id = setTimeout(() => controller.abort(), OLLAMA_EMBEDDING_TIMEOUT_MS);
|
|
135
140
|
const res = await fetch(`${baseUrl}/api/embed`, {
|
|
136
141
|
method: "POST",
|
|
137
142
|
headers: { "Content-Type": "application/json" },
|
|
@@ -158,7 +163,7 @@ export async function generateText(prompt, model, url) {
|
|
|
158
163
|
const modelName = model ?? getExtractModel();
|
|
159
164
|
try {
|
|
160
165
|
const controller = new AbortController();
|
|
161
|
-
const id = setTimeout(() => controller.abort(),
|
|
166
|
+
const id = setTimeout(() => controller.abort(), OLLAMA_GENERATE_TIMEOUT_MS);
|
|
162
167
|
const res = await fetch(`${baseUrl}/api/generate`, {
|
|
163
168
|
method: "POST",
|
|
164
169
|
headers: { "Content-Type": "application/json" },
|
|
@@ -178,4 +183,17 @@ export async function generateText(prompt, model, url) {
|
|
|
178
183
|
return null;
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Probe Ollama availability and model readiness in one call.
|
|
188
|
+
* Returns a status enum so callers can branch on it without repeating the check logic.
|
|
189
|
+
*/
|
|
190
|
+
export async function checkOllamaStatus() {
|
|
191
|
+
if (!getOllamaUrl())
|
|
192
|
+
return "disabled";
|
|
193
|
+
const ollamaUp = await checkOllamaAvailable();
|
|
194
|
+
if (!ollamaUp)
|
|
195
|
+
return "not_running";
|
|
196
|
+
const modelReady = await checkModelAvailable();
|
|
197
|
+
return modelReady ? "ready" : "no_model";
|
|
198
|
+
}
|
|
199
|
+
export { cosineSimilarity } from "../embedding.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared process helpers for spawning detached child processes.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
import { resolveRuntimeProfile } from "../runtime-profile.js";
|
|
6
|
+
/**
|
|
7
|
+
* Spawn a detached child process with the standard phren environment.
|
|
8
|
+
* When logFd is provided, stdout/stderr are redirected to that fd.
|
|
9
|
+
* When omitted, all stdio is ignored.
|
|
10
|
+
* Returns the ChildProcess so callers can attach `.unref()` or `.on("exit", ...)`.
|
|
11
|
+
*/
|
|
12
|
+
export function spawnDetachedChild(args, opts) {
|
|
13
|
+
return spawn(process.execPath, args, {
|
|
14
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
15
|
+
detached: true,
|
|
16
|
+
stdio: opts.logFd !== undefined ? ["ignore", opts.logFd, opts.logFd] : "ignore",
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
PHREN_PATH: opts.phrenPath,
|
|
20
|
+
PHREN_PROFILE: resolveRuntimeProfile(opts.phrenPath),
|
|
21
|
+
...opts.extraEnv,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// shared-retrieval.ts — shared retrieval core used by hooks and MCP search.
|
|
2
|
-
import { getQualityMultiplier, entryScoreKey, } from "./
|
|
3
|
-
import { queryDocRows, queryRows, cosineFallback, extractSnippet, getDocSourceKey,
|
|
4
|
-
import { filterTrustedFindingsDetailed, } from "./
|
|
5
|
-
import { parseCitationComment } from "
|
|
6
|
-
import { getHighImpactFindings } from "
|
|
7
|
-
import { buildFtsQueryVariants, buildRelaxedFtsQuery, isFeatureEnabled, STOP_WORDS, errorMessage } from "
|
|
2
|
+
import { getQualityMultiplier, entryScoreKey, } from "./governance.js";
|
|
3
|
+
import { queryDocRows, queryRows, cosineFallback, extractSnippet, getDocSourceKey, getFragmentBoostDocs, decodeFiniteNumber, rowToDocWithRowid, buildIndex, } from "./index.js";
|
|
4
|
+
import { filterTrustedFindingsDetailed, } from "./content.js";
|
|
5
|
+
import { parseCitationComment } from "../content/citation.js";
|
|
6
|
+
import { getHighImpactFindings } from "../finding/impact.js";
|
|
7
|
+
import { buildFtsQueryVariants, buildRelaxedFtsQuery, isFeatureEnabled, STOP_WORDS, errorMessage } from "../utils.js";
|
|
8
|
+
import { logger } from "../logger.js";
|
|
8
9
|
import * as fs from "fs";
|
|
9
10
|
import * as path from "path";
|
|
10
|
-
import { getProjectGlobBoost } from "
|
|
11
|
-
import { vectorFallback, deterministicSeed } from "./
|
|
12
|
-
import { getOllamaUrl, getCloudEmbeddingUrl } from "./
|
|
13
|
-
import { keywordFallbackSearch } from "
|
|
14
|
-
import { debugLog } from "
|
|
11
|
+
import { getProjectGlobBoost } from "../cli/hooks-globs.js";
|
|
12
|
+
import { vectorFallback, deterministicSeed } from "./search-fallback.js";
|
|
13
|
+
import { getOllamaUrl, getCloudEmbeddingUrl } from "./ollama.js";
|
|
14
|
+
import { keywordFallbackSearch } from "../core/search.js";
|
|
15
|
+
import { debugLog } from "../shared.js";
|
|
15
16
|
// ── Scoring constants ─────────────────────────────────────────────────────────
|
|
16
17
|
/** Number of docs sampled for token-overlap semantic fallback search. */
|
|
17
18
|
const SEMANTIC_FALLBACK_SAMPLE_LIMIT = 100;
|
|
@@ -182,6 +183,7 @@ const RRF_K = 60;
|
|
|
182
183
|
* Documents appearing in multiple tiers get a higher combined score.
|
|
183
184
|
* Formula: score(d) = Σ 1/(k + rank_i) for each tier i containing d, where k=60 (standard).
|
|
184
185
|
*/
|
|
186
|
+
/** @internal Exported for tests. */
|
|
185
187
|
export function rrfMerge(tiers, k = RRF_K) {
|
|
186
188
|
const scores = new Map();
|
|
187
189
|
const docs = new Map();
|
|
@@ -266,6 +268,7 @@ function semanticFallbackDocs(db, prompt, project) {
|
|
|
266
268
|
.map((x) => x.doc);
|
|
267
269
|
return scored;
|
|
268
270
|
}
|
|
271
|
+
/** @internal Exported for tests. */
|
|
269
272
|
export function shouldRunVectorExpansion(rows, prompt, desiredResults = VECTOR_FALLBACK_SKIP_COUNT) {
|
|
270
273
|
if (!rows || rows.length === 0)
|
|
271
274
|
return true;
|
|
@@ -383,8 +386,7 @@ export async function searchDocumentsAsync(db, safeQuery, prompt, keywords, dete
|
|
|
383
386
|
}
|
|
384
387
|
catch (err) {
|
|
385
388
|
// Vector search failure is non-fatal — return sync result
|
|
386
|
-
|
|
387
|
-
process.stderr.write(`[phren] hybridSearch vectorFallback: ${errorMessage(err)}\n`);
|
|
389
|
+
logger.debug("hybridSearch vectorFallback", errorMessage(err));
|
|
388
390
|
return syncResult;
|
|
389
391
|
}
|
|
390
392
|
}
|
|
@@ -483,9 +485,7 @@ export async function searchKnowledgeRows(db, options) {
|
|
|
483
485
|
}
|
|
484
486
|
}
|
|
485
487
|
catch (err) {
|
|
486
|
-
|
|
487
|
-
process.stderr.write(`[phren] vectorFallback: ${errorMessage(err)}\n`);
|
|
488
|
-
}
|
|
488
|
+
logger.debug("vectorFallback", errorMessage(err));
|
|
489
489
|
}
|
|
490
490
|
}
|
|
491
491
|
return { safeQuery, rows, usedFallback };
|
|
@@ -494,7 +494,7 @@ export async function searchKnowledgeRows(db, options) {
|
|
|
494
494
|
* Parse PHREN_FEDERATION_PATHS env var and return valid, distinct paths.
|
|
495
495
|
* Paths are colon-separated. The local phrenPath is excluded to avoid duplicate results.
|
|
496
496
|
*/
|
|
497
|
-
|
|
497
|
+
function parseFederationPaths(localPhrenPath) {
|
|
498
498
|
const raw = process.env.PHREN_FEDERATION_PATHS ?? "";
|
|
499
499
|
if (!raw.trim())
|
|
500
500
|
return [];
|
|
@@ -523,9 +523,7 @@ export async function searchFederatedStores(localPhrenPath, options) {
|
|
|
523
523
|
}
|
|
524
524
|
}
|
|
525
525
|
catch (err) {
|
|
526
|
-
|
|
527
|
-
process.stderr.write(`[phren] federatedSearch storePath=${storePath}: ${errorMessage(err)}\n`);
|
|
528
|
-
}
|
|
526
|
+
logger.debug(`federatedSearch storePath=${storePath}`, errorMessage(err));
|
|
529
527
|
// Federation errors are non-fatal — continue with other stores
|
|
530
528
|
}
|
|
531
529
|
}
|
|
@@ -628,7 +626,7 @@ export function rankResults(rows, intent, gitCtx, detectedProject, phrenPathLoca
|
|
|
628
626
|
if (canonicalRows)
|
|
629
627
|
ranked = [...canonicalRows, ...ranked];
|
|
630
628
|
}
|
|
631
|
-
const entityBoost = query ?
|
|
629
|
+
const entityBoost = query ? getFragmentBoostDocs(db, query) : new Set();
|
|
632
630
|
const entityBoostPaths = new Set();
|
|
633
631
|
for (const doc of ranked) {
|
|
634
632
|
// Use getDocSourceKey to build the full project/relFile key, matching what
|
|
@@ -739,7 +737,8 @@ export function rankResults(rows, intent, gitCtx, detectedProject, phrenPathLoca
|
|
|
739
737
|
}
|
|
740
738
|
return ranked;
|
|
741
739
|
}
|
|
742
|
-
/** Mark snippet lines with stale citations (cited file missing or line content changed).
|
|
740
|
+
/** Mark snippet lines with stale citations (cited file missing or line content changed).
|
|
741
|
+
* @internal Exported for tests. */
|
|
743
742
|
export function markStaleCitations(snippet) {
|
|
744
743
|
const lines = snippet.split("\n");
|
|
745
744
|
const result = [];
|
|
@@ -771,8 +770,7 @@ export function markStaleCitations(snippet) {
|
|
|
771
770
|
}
|
|
772
771
|
}
|
|
773
772
|
catch (err) {
|
|
774
|
-
|
|
775
|
-
process.stderr.write(`[phren] applyCitationAnnotations fileRead: ${errorMessage(err)}\n`);
|
|
773
|
+
logger.debug("applyCitationAnnotations fileRead", errorMessage(err));
|
|
776
774
|
stale = true;
|
|
777
775
|
}
|
|
778
776
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from "crypto";
|
|
2
|
-
import { debugLog } from "
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { debugLog } from "../shared.js";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
import { STOP_WORDS, errorMessage } from "../utils.js";
|
|
5
|
+
import { porterStem } from "./stemmer.js";
|
|
6
|
+
import { classifyFile, normalizeIndexedContent, rowToDocWithRowid } from "./index.js";
|
|
7
|
+
import { embedText, cosineSimilarity, getEmbeddingModel, getOllamaUrl, getCloudEmbeddingUrl } from "./ollama.js";
|
|
8
|
+
import { getEmbeddingCache } from "./embedding-cache.js";
|
|
9
|
+
import { getPersistentVectorIndex } from "./vector-index.js";
|
|
9
10
|
import * as fs from "fs";
|
|
10
11
|
import * as path from "path";
|
|
11
12
|
const HYBRID_SEARCH_FLAG = "PHREN_FEATURE_HYBRID_SEARCH";
|
|
@@ -16,6 +17,7 @@ const COSINE_WINDOW_COUNT = 4;
|
|
|
16
17
|
function splitPathSegments(filePath) {
|
|
17
18
|
return filePath.split(/[\\/]+/).filter(Boolean);
|
|
18
19
|
}
|
|
20
|
+
/** @internal Exported for tests. */
|
|
19
21
|
export function deriveVectorDocIdentity(phrenPath, fullPath) {
|
|
20
22
|
const normalizedPhrenPath = phrenPath.replace(/[\\/]+/g, "/").replace(/\/+$/, "");
|
|
21
23
|
const normalizedFullPath = fullPath.replace(/[\\/]+/g, "/");
|
|
@@ -123,8 +125,10 @@ function tfidfCosine(docs, query, corpusN) {
|
|
|
123
125
|
const N = corpusN ?? docs.length;
|
|
124
126
|
// Compute document frequency for each term, keyed by a fingerprint of the candidate doc set
|
|
125
127
|
// so that different subsets and incremental index mutations get distinct cache entries.
|
|
128
|
+
const corpusSize = docTokenLists.length;
|
|
129
|
+
const corpusLengthSum = docTokenLists.reduce((sum, tl) => sum + tl.length, 0);
|
|
126
130
|
const candidateFingerprint = docTokenLists.map(tl => tl.slice(0, 4).join(",")).join("|").slice(0, 128);
|
|
127
|
-
const cacheKey = `fp:${candidateFingerprint}`;
|
|
131
|
+
const cacheKey = `fp:${corpusSize}:${corpusLengthSum}:${candidateFingerprint}`;
|
|
128
132
|
const cachedDf = dfCache.get(cacheKey);
|
|
129
133
|
const df = cachedDf ?? new Map();
|
|
130
134
|
// Compute DF for any terms not yet in cache
|
|
@@ -181,8 +185,7 @@ export function cosineFallback(db, query, excludeRowids, limit) {
|
|
|
181
185
|
}
|
|
182
186
|
}
|
|
183
187
|
catch (err) {
|
|
184
|
-
|
|
185
|
-
process.stderr.write(`[phren] cosineFallback count: ${errorMessage(err)}\n`);
|
|
188
|
+
logger.debug("cosineFallback count", errorMessage(err));
|
|
186
189
|
return [];
|
|
187
190
|
}
|
|
188
191
|
if (totalDocs > COSINE_MAX_CORPUS) {
|
|
@@ -210,8 +213,7 @@ export function cosineFallback(db, query, excludeRowids, limit) {
|
|
|
210
213
|
ftsRows.push(...ftsRes[0].values);
|
|
211
214
|
}
|
|
212
215
|
catch (err) {
|
|
213
|
-
|
|
214
|
-
process.stderr.write(`[phren] cosineFallback FTS pre-filter: ${errorMessage(err)}\n`);
|
|
216
|
+
logger.debug("cosineFallback FTS pre-filter", errorMessage(err));
|
|
215
217
|
}
|
|
216
218
|
}
|
|
217
219
|
// If FTS gave fewer than cap, supplement with deterministic rowid windows.
|
|
@@ -248,8 +250,7 @@ export function cosineFallback(db, query, excludeRowids, limit) {
|
|
|
248
250
|
}
|
|
249
251
|
}
|
|
250
252
|
catch (err) {
|
|
251
|
-
|
|
252
|
-
process.stderr.write(`[phren] cosineFallback deterministicSample: ${errorMessage(err)}\n`);
|
|
253
|
+
logger.debug("cosineFallback deterministicSample", errorMessage(err));
|
|
253
254
|
}
|
|
254
255
|
}
|
|
255
256
|
if (ftsRows.length === 0)
|
|
@@ -259,8 +260,7 @@ export function cosineFallback(db, query, excludeRowids, limit) {
|
|
|
259
260
|
}
|
|
260
261
|
}
|
|
261
262
|
catch (err) {
|
|
262
|
-
|
|
263
|
-
process.stderr.write(`[phren] cosineFallback loadDocs: ${errorMessage(err)}\n`);
|
|
263
|
+
logger.debug("cosineFallback loadDocs", errorMessage(err));
|
|
264
264
|
return [];
|
|
265
265
|
}
|
|
266
266
|
// Separate rowids, DocRows, and content strings for scoring
|
|
@@ -305,8 +305,7 @@ export async function vectorFallback(phrenPath, query, excludePaths, limit, proj
|
|
|
305
305
|
await cache.load();
|
|
306
306
|
}
|
|
307
307
|
catch (err) {
|
|
308
|
-
|
|
309
|
-
process.stderr.write(`[phren] vectorFallback cacheLoad: ${errorMessage(err)}\n`);
|
|
308
|
+
logger.debug("vectorFallback cacheLoad", errorMessage(err));
|
|
310
309
|
}
|
|
311
310
|
}
|
|
312
311
|
if (cache.size() === 0)
|
|
@@ -357,8 +356,7 @@ export async function vectorFallback(phrenPath, query, excludePaths, limit, proj
|
|
|
357
356
|
}
|
|
358
357
|
}
|
|
359
358
|
catch (err) {
|
|
360
|
-
|
|
361
|
-
process.stderr.write(`[phren] vectorFallback fileRead: ${errorMessage(err)}\n`);
|
|
359
|
+
logger.debug("vectorFallback fileRead", errorMessage(err));
|
|
362
360
|
}
|
|
363
361
|
return { project: entryProject, filename, type, content, path: e.path };
|
|
364
362
|
});
|
|
@@ -2,7 +2,8 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import { errorMessage } from "
|
|
5
|
+
import { errorMessage } from "../utils.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
6
7
|
const require = createRequire(import.meta.url);
|
|
7
8
|
/**
|
|
8
9
|
* Locate the sql.js-fts5 WASM binary by require.resolve with path-probe fallback.
|
|
@@ -15,8 +16,7 @@ function findWasmBinary() {
|
|
|
15
16
|
return fs.readFileSync(resolved);
|
|
16
17
|
}
|
|
17
18
|
catch (err) {
|
|
18
|
-
|
|
19
|
-
process.stderr.write(`[phren] findWasmBinary requireResolve: ${errorMessage(err)}\n`);
|
|
19
|
+
logger.debug("sqljs", `findWasmBinary requireResolve: ${errorMessage(err)}`);
|
|
20
20
|
// fall through to path probing
|
|
21
21
|
}
|
|
22
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as crypto from "crypto";
|
|
3
|
-
import { runtimeFile, debugLog } from "
|
|
4
|
-
import { withFileLock } from "./
|
|
5
|
-
import { errorMessage } from "
|
|
3
|
+
import { runtimeFile, debugLog } from "../shared.js";
|
|
4
|
+
import { withFileLock } from "./governance.js";
|
|
5
|
+
import { errorMessage } from "../utils.js";
|
|
6
6
|
const VECTOR_INDEX_VERSION = 1;
|
|
7
7
|
const VECTOR_INDEX_TABLE_COUNT = 4;
|
|
8
8
|
const VECTOR_INDEX_BITS_PER_TABLE = 12;
|
package/mcp/dist/shared.js
CHANGED
|
@@ -2,6 +2,8 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { debugLog, runtimeFile } from "./phren-paths.js";
|
|
4
4
|
import { errorMessage } from "./utils.js";
|
|
5
|
+
import { withFileLock } from "./governance/locks.js";
|
|
6
|
+
const MAX_LOG_LINES = 1000;
|
|
5
7
|
export { HOOK_TOOL_NAMES, hookConfigPath } from "./provider-adapters.js";
|
|
6
8
|
export { EXEC_TIMEOUT_MS, EXEC_TIMEOUT_QUICK_MS, PhrenError, phrenOk, phrenErr, forwardErr, parsePhrenErrorCode, isRecord, withDefaults, FINDING_TYPES, FINDING_TAGS, KNOWN_OBSERVATION_TAGS, DOC_TYPES, capCache, RESERVED_PROJECT_DIR_NAMES, } from "./phren-core.js";
|
|
7
9
|
export { ROOT_MANIFEST_FILENAME, homeDir, homePath, expandHomePath, defaultPhrenPath, rootManifestPath, readRootManifest, writeRootManifest, resolveInstallContext, findNearestPhrenPath, isProjectLocalMode, runtimeDir, tryUnlink, sessionsDir, runtimeFile, installPreferencesFile, runtimeHealthFile, shellStateFile, sessionMetricsFile, memoryScoresFile, memoryUsageLogFile, sessionMarker, debugLog, appendIndexEvent, resolveFindingsPath, findPhrenPath, ensurePhrenPath, findPhrenPathWithArg, normalizeProjectNameForCreate, findProjectNameCaseInsensitive, findArchivedProjectNameCaseInsensitive, getProjectDirs, collectNativeMemoryFiles, computePhrenLiveStateToken, getPhrenPath, qualityMarkers, atomicWriteText, } from "./phren-paths.js";
|
|
@@ -30,75 +32,19 @@ export function impactLogFile(phrenPath) {
|
|
|
30
32
|
export function appendAuditLog(phrenPath, event, details) {
|
|
31
33
|
const logPath = runtimeFile(phrenPath, "audit.log");
|
|
32
34
|
const line = `[${new Date().toISOString()}] ${event} ${details}\n`;
|
|
33
|
-
const lockPath = logPath + ".lock";
|
|
34
|
-
const maxWait = 5000;
|
|
35
|
-
const pollMs = 50;
|
|
36
|
-
const staleMs = 30_000;
|
|
37
|
-
const waiter = new Int32Array(new SharedArrayBuffer(4));
|
|
38
|
-
// Q82: use an inline lock (same protocol as withFileLock) to guard the
|
|
39
|
-
// append + conditional rotation so concurrent processes don't read the same
|
|
40
|
-
// old content and race to write a truncated version each.
|
|
41
|
-
let waited = 0;
|
|
42
|
-
let hasLock = false;
|
|
43
35
|
try {
|
|
44
|
-
fs.mkdirSync(path.dirname(
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
fs.writeFileSync(lockPath, `${process.pid}\n${Date.now()}`, { flag: "wx" });
|
|
48
|
-
hasLock = true;
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
catch (err) {
|
|
52
|
-
if ((process.env.PHREN_DEBUG))
|
|
53
|
-
process.stderr.write(`[phren] appendAuditLog lockWrite: ${errorMessage(err)}\n`);
|
|
54
|
-
try {
|
|
55
|
-
const stat = fs.statSync(lockPath);
|
|
56
|
-
if (Date.now() - stat.mtimeMs > staleMs) {
|
|
57
|
-
try {
|
|
58
|
-
fs.unlinkSync(lockPath);
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// Another process may have claimed or removed the stale lock between
|
|
62
|
-
// statSync and unlinkSync. Sleep before retrying to avoid a spin loop.
|
|
63
|
-
Atomics.wait(waiter, 0, 0, pollMs);
|
|
64
|
-
waited += pollMs;
|
|
65
|
-
}
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
catch (statErr) {
|
|
70
|
-
if ((process.env.PHREN_DEBUG))
|
|
71
|
-
process.stderr.write(`[phren] appendAuditLog staleStat: ${errorMessage(statErr)}\n`);
|
|
72
|
-
}
|
|
73
|
-
Atomics.wait(waiter, 0, 0, pollMs);
|
|
74
|
-
waited += pollMs;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (hasLock) {
|
|
36
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
37
|
+
withFileLock(logPath, () => {
|
|
78
38
|
fs.appendFileSync(logPath, line);
|
|
79
39
|
const stat = fs.statSync(logPath);
|
|
80
40
|
if (stat.size > 1_000_000) {
|
|
81
41
|
const content = fs.readFileSync(logPath, "utf8");
|
|
82
42
|
const lines = content.split("\n");
|
|
83
|
-
fs.writeFileSync(logPath, lines.slice(-
|
|
43
|
+
fs.writeFileSync(logPath, lines.slice(-MAX_LOG_LINES).join("\n") + "\n");
|
|
84
44
|
}
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
debugLog(`Audit log skipped (lock timeout): ${event} ${details}`);
|
|
88
|
-
}
|
|
45
|
+
});
|
|
89
46
|
}
|
|
90
47
|
catch (err) {
|
|
91
48
|
debugLog(`Audit log write failed: ${errorMessage(err)}`);
|
|
92
49
|
}
|
|
93
|
-
finally {
|
|
94
|
-
if (hasLock) {
|
|
95
|
-
try {
|
|
96
|
-
fs.unlinkSync(lockPath);
|
|
97
|
-
}
|
|
98
|
-
catch (err) {
|
|
99
|
-
if ((process.env.PHREN_DEBUG))
|
|
100
|
-
process.stderr.write(`[phren] appendAuditLog unlock: ${errorMessage(err)}\n`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
50
|
}
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* Extracted from shell.ts to keep the orchestrator under 300 lines.
|
|
4
4
|
*/
|
|
5
5
|
import { PhrenShell } from "./shell.js";
|
|
6
|
-
import { style, clearScreen, clearToEnd, shellStartupFrames, gradient, badge } from "./
|
|
7
|
-
import { createPhrenAnimator } from "
|
|
8
|
-
import { errorMessage } from "
|
|
9
|
-
import { computePhrenLiveStateToken } from "
|
|
10
|
-
import { VERSION } from "
|
|
11
|
-
import { loadShellState, saveShellState } from "./
|
|
6
|
+
import { style, clearScreen, clearToEnd, shellStartupFrames, gradient, badge } from "./render.js";
|
|
7
|
+
import { createPhrenAnimator } from "../phren-art.js";
|
|
8
|
+
import { errorMessage } from "../utils.js";
|
|
9
|
+
import { computePhrenLiveStateToken } from "../shared.js";
|
|
10
|
+
import { VERSION } from "../init/shared.js";
|
|
11
|
+
import { loadShellState, saveShellState } from "./state-store.js";
|
|
12
12
|
const LIVE_STATE_POLL_MS = 2000;
|
|
13
13
|
function renderIntroFrame(frame, footer) {
|
|
14
14
|
clearScreen();
|
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
import { execFileSync } from "child_process";
|
|
6
6
|
import * as fs from "fs";
|
|
7
7
|
import * as path from "path";
|
|
8
|
-
import { addTask, addFinding, addProjectToProfile, completeTask, listProjectCards, pinTask, readTasks, readFindings, readReviewQueue, removeFinding, removeProjectFromProfile, resetShellState, saveShellState, setMachineProfile, tidyDoneTasks, canonicalTaskFilePath, unpinTask, updateTask, workNextTask, loadShellState, resolveTaskFilePath, } from "
|
|
9
|
-
import { runtimeFile } from "
|
|
10
|
-
import { handleGovernMemories } from "
|
|
11
|
-
import { runSearch } from "
|
|
12
|
-
import { consolidateProjectFindings } from "
|
|
13
|
-
import { style } from "./
|
|
14
|
-
import { SUB_VIEWS, TAB_ICONS } from "./
|
|
15
|
-
import { getProjectSkills, getHookEntries, writeInstallPreferences } from "./
|
|
16
|
-
import { removeSkillPath, setSkillEnabledAndSync } from "
|
|
17
|
-
import { resultMsg, editDistance, tokenize, expandIds, normalizeSection, tasksByFilter, queueByFilter, } from "./
|
|
18
|
-
import { errorMessage } from "
|
|
8
|
+
import { addTask, addFinding, addProjectToProfile, completeTask, listProjectCards, pinTask, readTasks, readFindings, readReviewQueue, removeFinding, removeProjectFromProfile, resetShellState, saveShellState, setMachineProfile, tidyDoneTasks, canonicalTaskFilePath, unpinTask, updateTask, workNextTask, loadShellState, resolveTaskFilePath, } from "../data/access.js";
|
|
9
|
+
import { runtimeFile } from "../shared.js";
|
|
10
|
+
import { handleGovernMemories } from "../cli/govern.js";
|
|
11
|
+
import { runSearch } from "../cli/search.js";
|
|
12
|
+
import { consolidateProjectFindings } from "../governance/policy.js";
|
|
13
|
+
import { style } from "./render.js";
|
|
14
|
+
import { SUB_VIEWS, TAB_ICONS } from "./types.js";
|
|
15
|
+
import { getProjectSkills, getHookEntries, writeInstallPreferences } from "./view.js";
|
|
16
|
+
import { removeSkillPath, setSkillEnabledAndSync } from "../skill/files.js";
|
|
17
|
+
import { resultMsg, editDistance, tokenize, expandIds, normalizeSection, tasksByFilter, queueByFilter, } from "./palette.js";
|
|
18
|
+
import { errorMessage } from "../utils.js";
|
|
19
|
+
import { logger } from "../logger.js";
|
|
19
20
|
function taskFileForProject(phrenPath, project) {
|
|
20
21
|
return resolveTaskFilePath(phrenPath, project)
|
|
21
22
|
?? canonicalTaskFilePath(phrenPath, project)
|
|
@@ -379,8 +380,7 @@ export async function executePalette(host, input) {
|
|
|
379
380
|
}
|
|
380
381
|
}
|
|
381
382
|
catch (err) {
|
|
382
|
-
|
|
383
|
-
process.stderr.write(`[phren] shell status gitStatus: ${errorMessage(err)}\n`);
|
|
383
|
+
logger.debug("shell-input", `shell status gitStatus: ${errorMessage(err)}`);
|
|
384
384
|
}
|
|
385
385
|
const auditPathNew = runtimeFile(host.phrenPath, "audit.log");
|
|
386
386
|
const auditPathLegacy = path.join(host.phrenPath, ".config", "audit.log");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
|
-
import { runLink } from "
|
|
5
|
-
import { runPhrenUpdate } from "
|
|
6
|
-
import { EXEC_TIMEOUT_MS, } from "
|
|
4
|
+
import { runLink } from "../link/link.js";
|
|
5
|
+
import { runPhrenUpdate } from "../update.js";
|
|
6
|
+
import { EXEC_TIMEOUT_MS, } from "../shared.js";
|
|
7
7
|
export function resultMsg(r) {
|
|
8
8
|
if (!r.ok)
|
|
9
9
|
return r.error;
|
|
@@ -37,7 +37,7 @@ export function separator(width = 50) {
|
|
|
37
37
|
export function stripAnsi(s) {
|
|
38
38
|
return s.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
function visibleWidth(s) {
|
|
41
41
|
return stripAnsi(s).length;
|
|
42
42
|
}
|
|
43
43
|
export function padToWidth(s, width) {
|
|
@@ -150,7 +150,7 @@ const PHREN_LOGO = [
|
|
|
150
150
|
"██║ ██║ ██║██║ ██║███████╗██║ ╚████║",
|
|
151
151
|
"╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝",
|
|
152
152
|
];
|
|
153
|
-
import { PHREN_ART as PHREN_STARTUP_ART } from "
|
|
153
|
+
import { PHREN_ART as PHREN_STARTUP_ART } from "../phren-art.js";
|
|
154
154
|
// ── Line-based viewport: edge-triggered scroll (stable, no jumpiness) ─────────
|
|
155
155
|
export function lineViewport(allLines, cursorFirstLine, cursorLastLine, height, prevStart) {
|
|
156
156
|
if (allLines.length === 0 || height <= 0)
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { addTask, addFinding, loadShellState, saveShellState, } from "
|
|
4
|
-
import { style } from "./
|
|
5
|
-
import { MAX_UNDO_STACK, } from "./
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
3
|
+
import { addTask, addFinding, loadShellState, saveShellState, } from "../data/access.js";
|
|
4
|
+
import { style } from "./render.js";
|
|
5
|
+
import { MAX_UNDO_STACK, } from "./types.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
7
|
+
import { resultMsg, defaultRunHooks, defaultRunUpdate, defaultRunRelink, } from "./palette.js";
|
|
8
|
+
import { runDoctor } from "../link/link.js";
|
|
9
|
+
import { renderShell, } from "./view.js";
|
|
10
|
+
import { executePalette, completeInput as completeInputFn, getListItems, handleNavigateKey, applyViewShortcut, } from "./input.js";
|
|
11
|
+
import { errorMessage } from "../utils.js";
|
|
11
12
|
// ── Shell class ──────────────────────────────────────────────────────────────
|
|
12
13
|
export class PhrenShell {
|
|
13
14
|
phrenPath;
|
|
@@ -72,8 +73,7 @@ export class PhrenShell {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
catch (err) {
|
|
75
|
-
|
|
76
|
-
process.stderr.write(`[phren] shell pushUndo: ${errorMessage(err)}\n`);
|
|
76
|
+
logger.debug("shell", `shell pushUndo: ${errorMessage(err)}`);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
popUndo() {
|
|
@@ -294,4 +294,4 @@ export class PhrenShell {
|
|
|
294
294
|
return completeInputFn(line, this.phrenPath, this.profile, this.state);
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
-
export { startShell } from "./
|
|
297
|
+
export { startShell } from "./entry.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { phrenOk, shellStateFile } from "
|
|
4
|
-
import { withSafeLock } from "
|
|
5
|
-
import { errorMessage } from "
|
|
3
|
+
import { phrenOk, shellStateFile } from "../shared.js";
|
|
4
|
+
import { withSafeLock } from "../shared/data-utils.js";
|
|
5
|
+
import { errorMessage } from "../utils.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
6
7
|
const SHELL_STATE_VERSION = 3;
|
|
7
8
|
const VALID_VIEWS = new Set(["Projects", "Tasks", "Findings", "Review Queue", "Skills", "Hooks", "Machines/Profiles", "Health"]);
|
|
8
9
|
export function loadShellState(phrenPath) {
|
|
@@ -33,8 +34,7 @@ export function loadShellState(phrenPath) {
|
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
|
-
|
|
37
|
-
process.stderr.write(`[phren] loadShellState parse: ${errorMessage(err)}\n`);
|
|
37
|
+
logger.debug("shell-state", `loadShellState parse: ${errorMessage(err)}`);
|
|
38
38
|
return fallback;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RESET, padToWidth, truncateLine, lineViewport, style } from "./
|
|
1
|
+
import { RESET, padToWidth, truncateLine, lineViewport, style } from "./render.js";
|
|
2
2
|
export function formatSelectableLine(line, cols, selected) {
|
|
3
3
|
return selected
|
|
4
4
|
? `\x1b[7m${padToWidth(line, cols)}${RESET}`
|