@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,18 +1,18 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import * as crypto from "crypto";
|
|
4
|
-
import { debugLog, appendAuditLog, phrenOk, phrenErr, PhrenError } from "
|
|
5
|
-
import { normalizeMemoryScope } from "
|
|
6
|
-
import { withFileLock } from "
|
|
7
|
-
import { isValidProjectName, safeProjectPath } from "
|
|
8
|
-
import { getMachineName } from "
|
|
9
|
-
import { buildCitationComment, buildSourceComment, getHeadCommit, getRepoRoot, inferCitationLocation, isFindingProvenanceSource, } from "./
|
|
10
|
-
import { isDuplicateFinding, scanForSecrets, normalizeObservationTags, resolveCoref, detectConflicts, extractDynamicEntities } from "./
|
|
11
|
-
import { validateFindingsFormat, validateFinding } from "./
|
|
12
|
-
import { countActiveFindings, autoArchiveToReference } from "./
|
|
13
|
-
import { resolveAutoFindingTaskItem, resolveFindingTaskReference, resolveFindingSessionId, } from "
|
|
14
|
-
import { buildLifecycleComments, extractFindingType, parseFindingLifecycle, stripLifecycleComments, } from "
|
|
15
|
-
import { METADATA_REGEX, } from "./
|
|
4
|
+
import { debugLog, appendAuditLog, phrenOk, phrenErr, PhrenError } from "../shared.js";
|
|
5
|
+
import { normalizeMemoryScope } from "../shared.js";
|
|
6
|
+
import { withFileLock } from "../shared/governance.js";
|
|
7
|
+
import { isValidProjectName, safeProjectPath } from "../utils.js";
|
|
8
|
+
import { getMachineName } from "../machine-identity.js";
|
|
9
|
+
import { buildCitationComment, buildSourceComment, getHeadCommit, getRepoRoot, inferCitationLocation, isFindingProvenanceSource, } from "./citation.js";
|
|
10
|
+
import { isDuplicateFinding, scanForSecrets, normalizeObservationTags, resolveCoref, detectConflicts, extractDynamicEntities } from "./dedup.js";
|
|
11
|
+
import { validateFindingsFormat, validateFinding } from "./validate.js";
|
|
12
|
+
import { countActiveFindings, autoArchiveToReference } from "./archive.js";
|
|
13
|
+
import { resolveAutoFindingTaskItem, resolveFindingTaskReference, resolveFindingSessionId, } from "../finding/context.js";
|
|
14
|
+
import { buildLifecycleComments, extractFindingType, parseFindingLifecycle, stripLifecycleComments, } from "../finding/lifecycle.js";
|
|
15
|
+
import { METADATA_REGEX, } from "./metadata.js";
|
|
16
16
|
/** Default cap for active findings before auto-archiving is triggered. */
|
|
17
17
|
const DEFAULT_FINDINGS_CAP = 20;
|
|
18
18
|
const LIFECYCLE_ANNOTATION_RE = METADATA_REGEX.lifecycleAnnotation;
|
|
@@ -123,7 +123,8 @@ export function autoDetectFindingType(text) {
|
|
|
123
123
|
return 'context';
|
|
124
124
|
return null;
|
|
125
125
|
}
|
|
126
|
-
function prepareFinding(
|
|
126
|
+
function prepareFinding(opts) {
|
|
127
|
+
const { finding: learning, project, fullHistory, extraAnnotations, citationInput, source, nowIso, inferredRepo, headCommit, phrenPath } = opts;
|
|
127
128
|
const secretType = scanForSecrets(learning);
|
|
128
129
|
if (secretType) {
|
|
129
130
|
return { status: "rejected", reason: `Contains ${secretType}` };
|
|
@@ -208,7 +209,11 @@ function insertFindingIntoContent(content, today, bullet, citationComment) {
|
|
|
208
209
|
// Use positional insertion (not String.replace) to avoid: (1) special $& replacement patterns
|
|
209
210
|
// if bullet contains $ chars, and (2) inserting inside an archived <details> block when a
|
|
210
211
|
// duplicate date header exists from a prior consolidation run.
|
|
211
|
-
|
|
212
|
+
// Search for todayHeader only after the last </details> close tag so we never
|
|
213
|
+
// insert into an archived block whose date happens to match today.
|
|
214
|
+
const lastDetailsClose = content.lastIndexOf("</details>");
|
|
215
|
+
const searchFrom = lastDetailsClose >= 0 ? lastDetailsClose : 0;
|
|
216
|
+
const idx = content.indexOf(todayHeader, searchFrom);
|
|
212
217
|
if (idx !== -1) {
|
|
213
218
|
const insertAt = idx + todayHeader.length;
|
|
214
219
|
return content.slice(0, insertAt) + `\n\n${bullet}\n${citationComment}` + content.slice(insertAt);
|
|
@@ -288,7 +293,10 @@ export function addFindingToFile(phrenPath, project, learning, citationInput, op
|
|
|
288
293
|
if (!fs.existsSync(resolvedDir))
|
|
289
294
|
return phrenErr(`Project "${project}" does not exist.`, PhrenError.INVALID_PROJECT_NAME);
|
|
290
295
|
const result = withFileLock(learningsPath, () => {
|
|
291
|
-
const preparedForNewFile = prepareFinding(
|
|
296
|
+
const preparedForNewFile = prepareFinding({
|
|
297
|
+
finding: learning, project, fullHistory: "", extraAnnotations: opts?.extraAnnotations,
|
|
298
|
+
citationInput: resolvedCitationInput, source, nowIso, inferredRepo, headCommit, phrenPath,
|
|
299
|
+
});
|
|
292
300
|
if (!fs.existsSync(learningsPath)) {
|
|
293
301
|
if (preparedForNewFile.status === "rejected") {
|
|
294
302
|
return phrenErr(`Rejected: finding appears to contain a secret (${preparedForNewFile.reason.replace(/^Contains /, "")}). Strip credentials before saving.`, PhrenError.VALIDATION_ERROR);
|
|
@@ -297,7 +305,9 @@ export function addFindingToFile(phrenPath, project, learning, citationInput, op
|
|
|
297
305
|
return phrenOk(`Skipped duplicate finding for "${project}": already exists with similar wording.`);
|
|
298
306
|
}
|
|
299
307
|
const newContent = `# ${project} Findings\n\n## ${today}\n\n${preparedForNewFile.finding.bullet}\n${preparedForNewFile.finding.citationComment}\n`;
|
|
300
|
-
|
|
308
|
+
const tmpPath = learningsPath + ".tmp." + process.pid;
|
|
309
|
+
fs.writeFileSync(tmpPath, newContent);
|
|
310
|
+
fs.renameSync(tmpPath, learningsPath);
|
|
301
311
|
return phrenOk({
|
|
302
312
|
content: newContent,
|
|
303
313
|
citation: buildFindingCitation(resolvedCitationInput, nowIso, inferredRepo, headCommit),
|
|
@@ -316,7 +326,10 @@ export function addFindingToFile(phrenPath, project, learning, citationInput, op
|
|
|
316
326
|
.filter(line => !line.startsWith("- ") || !line.toLowerCase().includes(supersedesText.slice(0, 40).toLowerCase()))
|
|
317
327
|
.join("\n")
|
|
318
328
|
: content;
|
|
319
|
-
const prepared = prepareFinding(
|
|
329
|
+
const prepared = prepareFinding({
|
|
330
|
+
finding: learning, project, fullHistory: historyForDedup, extraAnnotations: opts?.extraAnnotations,
|
|
331
|
+
citationInput: resolvedCitationInput, source, nowIso, inferredRepo, headCommit, phrenPath,
|
|
332
|
+
});
|
|
320
333
|
if (prepared.status === "rejected") {
|
|
321
334
|
return phrenErr(`Rejected: finding appears to contain a secret (${prepared.reason.replace(/^Contains /, "")}). Strip credentials before saving.`, PhrenError.VALIDATION_ERROR);
|
|
322
335
|
}
|
|
@@ -430,7 +443,10 @@ export function addFindingsToFile(phrenPath, project, learnings, opts) {
|
|
|
430
443
|
rejected.push({ text: learning, reason: lengthError });
|
|
431
444
|
continue;
|
|
432
445
|
}
|
|
433
|
-
const prepared = prepareFinding(
|
|
446
|
+
const prepared = prepareFinding({
|
|
447
|
+
finding: learning, project, fullHistory: content, extraAnnotations,
|
|
448
|
+
citationInput: resolvedCitationInput, source, nowIso, inferredRepo, headCommit, phrenPath,
|
|
449
|
+
});
|
|
434
450
|
if (prepared.status === "rejected") {
|
|
435
451
|
rejected.push({ text: learning, reason: prepared.reason });
|
|
436
452
|
continue;
|
|
@@ -445,7 +461,9 @@ export function addFindingsToFile(phrenPath, project, learnings, opts) {
|
|
|
445
461
|
added.push(learning);
|
|
446
462
|
}
|
|
447
463
|
if (added.length > 0) {
|
|
448
|
-
|
|
464
|
+
const tmpPath = learningsPath + ".tmp." + process.pid;
|
|
465
|
+
fs.writeFileSync(tmpPath, content.endsWith("\n") ? content : `${content}\n`);
|
|
466
|
+
fs.renameSync(tmpPath, learningsPath);
|
|
449
467
|
}
|
|
450
468
|
return phrenOk({ content, wrote: added.length > 0 });
|
|
451
469
|
}
|
|
@@ -460,7 +478,10 @@ export function addFindingsToFile(phrenPath, project, learnings, opts) {
|
|
|
460
478
|
rejected.push({ text: learning, reason: lengthError });
|
|
461
479
|
continue;
|
|
462
480
|
}
|
|
463
|
-
const prepared = prepareFinding(
|
|
481
|
+
const prepared = prepareFinding({
|
|
482
|
+
finding: learning, project, fullHistory: content, extraAnnotations,
|
|
483
|
+
citationInput: resolvedCitationInput, source, nowIso, inferredRepo, headCommit, phrenPath,
|
|
484
|
+
});
|
|
464
485
|
if (prepared.status === "rejected") {
|
|
465
486
|
rejected.push({ text: learning, reason: prepared.reason });
|
|
466
487
|
continue;
|
|
@@ -2,11 +2,11 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import * as crypto from "crypto";
|
|
4
4
|
import { execFileSync } from "child_process";
|
|
5
|
-
import { debugLog, EXEC_TIMEOUT_MS, getProjectDirs } from "
|
|
6
|
-
import { errorMessage } from "
|
|
7
|
-
import { countActiveFindings } from "./
|
|
8
|
-
import { isTaskFileName } from "
|
|
9
|
-
import { METADATA_REGEX } from "./
|
|
5
|
+
import { debugLog, EXEC_TIMEOUT_MS, getProjectDirs } from "../shared.js";
|
|
6
|
+
import { errorMessage } from "../utils.js";
|
|
7
|
+
import { countActiveFindings } from "./archive.js";
|
|
8
|
+
import { isTaskFileName } from "../data/tasks.js";
|
|
9
|
+
import { METADATA_REGEX } from "./metadata.js";
|
|
10
10
|
/** Maximum allowed length for a single finding entry (token budget protection). */
|
|
11
11
|
export const MAX_FINDING_LENGTH = 2000;
|
|
12
12
|
function safeParseDate(s) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isValidProjectName } from "
|
|
2
|
-
import { addFindingToFile, } from "
|
|
3
|
-
import { removeFinding as removeFindingStore, } from "
|
|
4
|
-
import { MAX_FINDING_LENGTH } from "
|
|
1
|
+
import { isValidProjectName } from "../utils.js";
|
|
2
|
+
import { addFindingToFile, } from "../shared/content.js";
|
|
3
|
+
import { removeFinding as removeFindingStore, } from "../data/access.js";
|
|
4
|
+
import { MAX_FINDING_LENGTH } from "../content/validate.js";
|
|
5
5
|
/**
|
|
6
6
|
* Validate and add a single finding. Shared validation logic used by
|
|
7
7
|
* both CLI `phren add-finding` and MCP `add_finding` tool.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
|
-
import { phrenErr, phrenOk, readRootManifest } from "
|
|
3
|
-
import { bootstrapFromExisting } from "
|
|
4
|
-
import { resolveActiveProfile } from "
|
|
5
|
-
import { TASKS_FILENAME } from "
|
|
2
|
+
import { phrenErr, phrenOk, readRootManifest } from "../shared.js";
|
|
3
|
+
import { bootstrapFromExisting } from "../init/setup.js";
|
|
4
|
+
import { resolveActiveProfile } from "../profile-store.js";
|
|
5
|
+
import { TASKS_FILENAME } from "../data/tasks.js";
|
|
6
6
|
export function addProjectFromPath(phrenPath, targetPath, requestedProfile, ownership) {
|
|
7
7
|
if (!targetPath) {
|
|
8
8
|
return phrenErr("Path is required. Pass the current project directory explicitly to avoid adding the wrong working directory.");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { STOP_WORDS } from "
|
|
2
|
-
import { queryDocRows } from "
|
|
1
|
+
import { STOP_WORDS } from "../utils.js";
|
|
2
|
+
import { queryDocRows } from "../shared/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Keyword overlap fallback for when FTS5 returns no results.
|
|
5
5
|
* Scans all docs (optionally filtered by project/type), scores each by
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
+
// Barrel module: re-exports task, profile, and shell-state APIs from their
|
|
2
|
+
// dedicated modules (data-tasks.ts, profile-store.ts, shell-state-store.ts)
|
|
3
|
+
// and owns finding/queue logic directly.
|
|
1
4
|
import * as fs from "fs";
|
|
2
5
|
import * as path from "path";
|
|
3
6
|
import * as yaml from "js-yaml";
|
|
4
|
-
import { phrenErr, PhrenError, phrenOk, forwardErr, getProjectDirs, isRecord, } from "
|
|
5
|
-
import { normalizeQueueEntryText, } from "
|
|
6
|
-
import { addFindingToFile, } from "
|
|
7
|
-
import { isValidProjectName, queueFilePath, safeProjectPath } from "
|
|
8
|
-
import { parseCitationComment, parseSourceComment, } from "
|
|
9
|
-
import { parseFindingLifecycle, } from "
|
|
10
|
-
import { METADATA_REGEX, isCitationLine, isArchiveStart, isArchiveEnd, parseFindingId, parseAllContradictions, stripComments, normalizeFindingText, } from "
|
|
11
|
-
import { withSafeLock, ensureProject } from "
|
|
12
|
-
export { readTasks, readTasksAcrossProjects, resolveTaskItem, addTask, addTasks, completeTasks, completeTask, removeTask, removeTasks, updateTask, linkTaskIssue, pinTask, unpinTask, workNextTask, tidyDoneTasks, taskMarkdown, appendChildFinding, promoteTask, TASKS_FILENAME, TASK_FILE_ALIASES, canonicalTaskFilePath, resolveTaskFilePath, isTaskFileName, } from "./
|
|
13
|
-
export { addProjectToProfile, listMachines, listProfiles, listProjectCards, removeProjectFromProfile, setMachineProfile, } from "
|
|
14
|
-
export { loadShellState, resetShellState, saveShellState, } from "
|
|
15
|
-
export { getRuntimeHealth as readRuntimeHealth } from "
|
|
7
|
+
import { phrenErr, PhrenError, phrenOk, forwardErr, getProjectDirs, isRecord, } from "../shared.js";
|
|
8
|
+
import { normalizeQueueEntryText, } from "../shared/governance.js";
|
|
9
|
+
import { addFindingToFile, } from "../shared/content.js";
|
|
10
|
+
import { isValidProjectName, queueFilePath, safeProjectPath } from "../utils.js";
|
|
11
|
+
import { parseCitationComment, parseSourceComment, } from "../content/citation.js";
|
|
12
|
+
import { parseFindingLifecycle, } from "../finding/lifecycle.js";
|
|
13
|
+
import { METADATA_REGEX, isCitationLine, isArchiveStart, isArchiveEnd, parseFindingId, parseAllContradictions, stripComments, normalizeFindingText, } from "../content/metadata.js";
|
|
14
|
+
import { withSafeLock, ensureProject } from "../shared/data-utils.js";
|
|
15
|
+
export { readTasks, readTasksAcrossProjects, resolveTaskItem, addTask, addTasks, completeTasks, completeTask, removeTask, removeTasks, updateTask, linkTaskIssue, pinTask, unpinTask, workNextTask, tidyDoneTasks, taskMarkdown, appendChildFinding, promoteTask, TASKS_FILENAME, TASK_FILE_ALIASES, canonicalTaskFilePath, resolveTaskFilePath, isTaskFileName, } from "./tasks.js";
|
|
16
|
+
export { addProjectToProfile, listMachines, listProfiles, listProjectCards, removeProjectFromProfile, setMachineProfile, } from "../profile-store.js";
|
|
17
|
+
export { loadShellState, resetShellState, saveShellState, } from "../shell/state-store.js";
|
|
18
|
+
export { getRuntimeHealth as readRuntimeHealth } from "../shared/governance.js";
|
|
16
19
|
function extractDateHeading(line) {
|
|
17
20
|
const heading = line.match(/^##\s+(.+)$/);
|
|
18
21
|
if (!heading)
|
|
@@ -113,7 +116,6 @@ export function readFindings(phrenPath, project, opts = {}) {
|
|
|
113
116
|
const includeArchived = opts.includeArchived ?? false;
|
|
114
117
|
for (let i = 0; i < lines.length; i++) {
|
|
115
118
|
const line = lines[i];
|
|
116
|
-
const trimmed = line.trim();
|
|
117
119
|
const archiveStartMatch = isArchiveStart(line);
|
|
118
120
|
const archiveEnd = isArchiveEnd(line);
|
|
119
121
|
if (archiveStartMatch) {
|
|
@@ -273,10 +275,63 @@ export function removeFinding(phrenPath, project, match) {
|
|
|
273
275
|
const matched = lines[idx];
|
|
274
276
|
lines.splice(idx, removeCount);
|
|
275
277
|
const normalized = lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
276
|
-
|
|
278
|
+
const tmp = filePath + ".tmp." + process.pid;
|
|
279
|
+
fs.writeFileSync(tmp, normalized);
|
|
280
|
+
fs.renameSync(tmp, filePath);
|
|
277
281
|
return phrenOk(`Removed from ${project}: ${matched}`);
|
|
278
282
|
});
|
|
279
283
|
}
|
|
284
|
+
export function removeFindings(phrenPath, project, matches) {
|
|
285
|
+
const ensured = ensureProject(phrenPath, project);
|
|
286
|
+
if (!ensured.ok)
|
|
287
|
+
return forwardErr(ensured);
|
|
288
|
+
const findingsPath = path.resolve(path.join(ensured.data, 'FINDINGS.md'));
|
|
289
|
+
if (!findingsPath.startsWith(phrenPath + path.sep) && findingsPath !== phrenPath) {
|
|
290
|
+
return phrenErr(`FINDINGS.md path escapes phren store`, PhrenError.VALIDATION_ERROR);
|
|
291
|
+
}
|
|
292
|
+
if (!fs.existsSync(findingsPath))
|
|
293
|
+
return phrenErr(`No FINDINGS.md file found for "${project}". Add a finding first with add_finding or :find add.`, PhrenError.FILE_NOT_FOUND);
|
|
294
|
+
return withSafeLock(findingsPath, () => {
|
|
295
|
+
const lines = fs.readFileSync(findingsPath, "utf8").split("\n");
|
|
296
|
+
const removed = [];
|
|
297
|
+
const errors = [];
|
|
298
|
+
const bulletLines = collectFindingBulletLines(lines);
|
|
299
|
+
const activeBullets = bulletLines.filter(({ archived }) => !archived);
|
|
300
|
+
const archivedBullets = bulletLines.filter(({ archived }) => archived);
|
|
301
|
+
// Collect indices to remove (with citation lines) in one pass over matches
|
|
302
|
+
const indicesToRemove = new Set();
|
|
303
|
+
for (const match of matches) {
|
|
304
|
+
const needle = normalizeFindingText(match);
|
|
305
|
+
const activeMatch = findMatchingFindingBullet(activeBullets.filter(({ i }) => !indicesToRemove.has(i)), needle, match);
|
|
306
|
+
if (activeMatch.kind === "ambiguous") {
|
|
307
|
+
errors.push(match);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (activeMatch.kind === "not_found") {
|
|
311
|
+
const archivedMatch = findMatchingFindingBullet(archivedBullets, needle, match);
|
|
312
|
+
if (archivedMatch.kind === "ambiguous" || archivedMatch.kind === "found") {
|
|
313
|
+
errors.push(match);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
errors.push(match);
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
const idx = activeMatch.idx;
|
|
320
|
+
indicesToRemove.add(idx);
|
|
321
|
+
if (isCitationLine(lines[idx + 1] || ""))
|
|
322
|
+
indicesToRemove.add(idx + 1);
|
|
323
|
+
removed.push(lines[idx]);
|
|
324
|
+
}
|
|
325
|
+
if (removed.length > 0) {
|
|
326
|
+
const filtered = lines.filter((_, i) => !indicesToRemove.has(i));
|
|
327
|
+
const normalized = filtered.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
328
|
+
const tmp = findingsPath + ".tmp." + process.pid;
|
|
329
|
+
fs.writeFileSync(tmp, normalized);
|
|
330
|
+
fs.renameSync(tmp, findingsPath);
|
|
331
|
+
}
|
|
332
|
+
return phrenOk({ removed, errors });
|
|
333
|
+
});
|
|
334
|
+
}
|
|
280
335
|
export function editFinding(phrenPath, project, oldText, newText) {
|
|
281
336
|
const ensured = ensureProject(phrenPath, project);
|
|
282
337
|
if (!ensured.ok)
|
|
@@ -312,7 +367,9 @@ export function editFinding(phrenPath, project, oldText, newText) {
|
|
|
312
367
|
const metaSuffix = metaMatch ? " " + metaMatch.join(" ") : "";
|
|
313
368
|
lines[idx] = `- ${newTextTrimmed}${metaSuffix}`;
|
|
314
369
|
const normalized = lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
315
|
-
|
|
370
|
+
const tmp = findingsPath + ".tmp." + process.pid;
|
|
371
|
+
fs.writeFileSync(tmp, normalized);
|
|
372
|
+
fs.renameSync(tmp, findingsPath);
|
|
316
373
|
return phrenOk(`Updated finding in ${project}`);
|
|
317
374
|
});
|
|
318
375
|
}
|
|
@@ -384,6 +441,76 @@ export function readReviewQueue(phrenPath, project) {
|
|
|
384
441
|
}
|
|
385
442
|
return phrenOk(items);
|
|
386
443
|
}
|
|
444
|
+
/** Locate a queue line and apply a mutation within a file lock. */
|
|
445
|
+
function withQueueLineOp(phrenPath, project, lineText, op) {
|
|
446
|
+
const ensured = ensureProject(phrenPath, project);
|
|
447
|
+
if (!ensured.ok)
|
|
448
|
+
return forwardErr(ensured);
|
|
449
|
+
const file = queuePath(phrenPath, project);
|
|
450
|
+
if (!fs.existsSync(file))
|
|
451
|
+
return phrenErr(`No review queue found for "${project}".`, PhrenError.FILE_NOT_FOUND);
|
|
452
|
+
return withSafeLock(file, () => {
|
|
453
|
+
const lines = fs.readFileSync(file, "utf8").split("\n");
|
|
454
|
+
const idx = lines.findIndex((l) => l.trim() === lineText.trim());
|
|
455
|
+
if (idx === -1)
|
|
456
|
+
return phrenErr(`Queue item not found in "${project}".`, PhrenError.NOT_FOUND);
|
|
457
|
+
return op(lines, idx, file);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
function writeQueueLines(file, lines) {
|
|
461
|
+
const content = lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
462
|
+
const tmp = file + ".tmp." + process.pid;
|
|
463
|
+
fs.writeFileSync(tmp, content);
|
|
464
|
+
fs.renameSync(tmp, file);
|
|
465
|
+
}
|
|
466
|
+
/** Remove a queue item's line from review.md (finding stays in FINDINGS.md). */
|
|
467
|
+
export function approveQueueItem(phrenPath, project, lineText) {
|
|
468
|
+
return withQueueLineOp(phrenPath, project, lineText, (lines, idx, file) => {
|
|
469
|
+
lines.splice(idx, 1);
|
|
470
|
+
writeQueueLines(file, lines);
|
|
471
|
+
return phrenOk(`Approved queue item in ${project}`);
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
/** Remove a queue item from review.md AND remove the corresponding finding from FINDINGS.md. */
|
|
475
|
+
export function rejectQueueItem(phrenPath, project, lineText) {
|
|
476
|
+
const lockResult = withQueueLineOp(phrenPath, project, lineText, (lines, idx, file) => {
|
|
477
|
+
lines.splice(idx, 1);
|
|
478
|
+
writeQueueLines(file, lines);
|
|
479
|
+
return phrenOk("ok");
|
|
480
|
+
});
|
|
481
|
+
if (!lockResult.ok)
|
|
482
|
+
return lockResult;
|
|
483
|
+
const parsed = parseQueueLine(lineText);
|
|
484
|
+
if (parsed.text) {
|
|
485
|
+
const removeResult = removeFinding(phrenPath, project, parsed.text);
|
|
486
|
+
if (!removeResult.ok) {
|
|
487
|
+
return phrenOk(`Rejected queue item from ${project} (note: finding not found in FINDINGS.md — may have already been removed)`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return phrenOk(`Rejected and removed queue item from ${project}`);
|
|
491
|
+
}
|
|
492
|
+
/** Edit a queue item's text in review.md and the corresponding finding in FINDINGS.md. */
|
|
493
|
+
export function editQueueItem(phrenPath, project, lineText, newText) {
|
|
494
|
+
const trimmed = newText.replace(/[\r\n]+/g, " ").trim();
|
|
495
|
+
if (!trimmed)
|
|
496
|
+
return phrenErr("New text cannot be empty.", PhrenError.EMPTY_INPUT);
|
|
497
|
+
const parsed = parseQueueLine(lineText);
|
|
498
|
+
const lockResult = withQueueLineOp(phrenPath, project, lineText, (lines, idx, file) => {
|
|
499
|
+
const dateMatch = lines[idx].match(/^- \[(\d{4}-\d{2}-\d{2})\]\s*/);
|
|
500
|
+
lines[idx] = dateMatch ? `- [${dateMatch[1]}] ${trimmed}` : `- ${trimmed}`;
|
|
501
|
+
writeQueueLines(file, lines);
|
|
502
|
+
return phrenOk("ok");
|
|
503
|
+
});
|
|
504
|
+
if (!lockResult.ok)
|
|
505
|
+
return lockResult;
|
|
506
|
+
if (parsed.text) {
|
|
507
|
+
const editResult = editFinding(phrenPath, project, parsed.text, trimmed);
|
|
508
|
+
if (!editResult.ok) {
|
|
509
|
+
return phrenOk(`Updated queue item in ${project} (note: corresponding finding not found in FINDINGS.md)`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return phrenOk(`Updated queue item in ${project}`);
|
|
513
|
+
}
|
|
387
514
|
export function readReviewQueueAcrossProjects(phrenPath, profile) {
|
|
388
515
|
const validation = validateAggregateQueueProfile(phrenPath, profile);
|
|
389
516
|
if (!validation.ok)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { randomBytes, randomUUID } from "crypto";
|
|
4
|
-
import { phrenErr, PhrenError, phrenOk, forwardErr, getProjectDirs, } from "
|
|
5
|
-
import { validateTaskFormat } from "
|
|
6
|
-
import { safeProjectPath } from "
|
|
7
|
-
import { withSafeLock, ensureProject } from "
|
|
4
|
+
import { phrenErr, PhrenError, phrenOk, forwardErr, getProjectDirs, } from "../shared.js";
|
|
5
|
+
import { validateTaskFormat } from "../shared/content.js";
|
|
6
|
+
import { safeProjectPath } from "../utils.js";
|
|
7
|
+
import { withSafeLock, ensureProject } from "../shared/data-utils.js";
|
|
8
8
|
const ACTIVE_HEADINGS = new Set(["active", "in progress", "in-progress", "current", "wip"]);
|
|
9
9
|
const QUEUE_HEADINGS = new Set(["queue", "queued", "task", "todo", "upcoming", "next"]);
|
|
10
10
|
const DONE_HEADINGS = new Set(["done", "completed", "finished", "archived"]);
|
|
@@ -408,7 +408,7 @@ export function addTask(phrenPath, project, item, opts) {
|
|
|
408
408
|
return phrenOk(newItem);
|
|
409
409
|
});
|
|
410
410
|
}
|
|
411
|
-
export function addTasks(phrenPath, project, items) {
|
|
411
|
+
export function addTasks(phrenPath, project, items, opts) {
|
|
412
412
|
const bPath = canonicalTaskFilePath(phrenPath, project);
|
|
413
413
|
if (!bPath)
|
|
414
414
|
return phrenErr(`Project name "${project}" is not valid.`, PhrenError.INVALID_PROJECT_NAME);
|
|
@@ -429,10 +429,12 @@ export function addTasks(phrenPath, project, items) {
|
|
|
429
429
|
}
|
|
430
430
|
parsed.data.items.Queue.push({
|
|
431
431
|
id: `Q${parsed.data.items.Queue.length + 1}`,
|
|
432
|
+
stableId: newBid(),
|
|
432
433
|
section: "Queue",
|
|
433
434
|
line,
|
|
434
435
|
checked: false,
|
|
435
436
|
priority: normalizePriority(line),
|
|
437
|
+
scope: opts?.scope,
|
|
436
438
|
});
|
|
437
439
|
added.push(line);
|
|
438
440
|
}
|
package/mcp/dist/embedding.js
CHANGED
|
@@ -2,9 +2,10 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import * as crypto from "crypto";
|
|
4
4
|
import { debugLog, runtimeDir, } from "./shared.js";
|
|
5
|
-
import { withFileLock } from "./shared
|
|
5
|
+
import { withFileLock } from "./shared/governance.js";
|
|
6
6
|
import { errorMessage } from "./utils.js";
|
|
7
|
-
import { bootstrapSqlJs } from "./shared
|
|
7
|
+
import { bootstrapSqlJs } from "./shared/sqljs.js";
|
|
8
|
+
import { logger } from "./logger.js";
|
|
8
9
|
let sqlJsLoader = bootstrapSqlJs;
|
|
9
10
|
const EMBED_CACHE_DB = "embed-cache.db";
|
|
10
11
|
function getCacheDbPath(phrenPath) {
|
|
@@ -79,8 +80,7 @@ async function openCacheDb(phrenPath) {
|
|
|
79
80
|
db?.close();
|
|
80
81
|
}
|
|
81
82
|
catch (e2) {
|
|
82
|
-
|
|
83
|
-
process.stderr.write(`[phren] embedding openCacheDb dbClose: ${e2 instanceof Error ? e2.message : String(e2)}\n`);
|
|
83
|
+
logger.debug("embedding", `embedding openCacheDb dbClose: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
84
84
|
}
|
|
85
85
|
throw err;
|
|
86
86
|
}
|
|
@@ -126,14 +126,12 @@ function persistDb(phrenPath, db) {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
catch (err) {
|
|
129
|
-
|
|
130
|
-
process.stderr.write(`[phren] embedding persistDb onDiskLoad: ${errorMessage(err)}\n`);
|
|
129
|
+
logger.debug("embedding", `embedding persistDb onDiskLoad: ${errorMessage(err)}`);
|
|
131
130
|
try {
|
|
132
131
|
onDisk?.close();
|
|
133
132
|
}
|
|
134
133
|
catch (e2) {
|
|
135
|
-
|
|
136
|
-
process.stderr.write(`[phren] embedding persistDb onDiskClose: ${e2 instanceof Error ? e2.message : String(e2)}\n`);
|
|
134
|
+
logger.debug("embedding", `embedding persistDb onDiskClose: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
137
135
|
}
|
|
138
136
|
onDisk = null;
|
|
139
137
|
}
|
|
@@ -149,8 +147,7 @@ function persistDb(phrenPath, db) {
|
|
|
149
147
|
onDisk.close();
|
|
150
148
|
}
|
|
151
149
|
catch (e2) {
|
|
152
|
-
|
|
153
|
-
process.stderr.write(`[phren] embedding persistDb onDiskCloseFinally: ${e2 instanceof Error ? e2.message : String(e2)}\n`);
|
|
150
|
+
logger.debug("embedding", `embedding persistDb onDiskCloseFinally: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
154
151
|
}
|
|
155
152
|
}
|
|
156
153
|
});
|
|
@@ -269,8 +266,7 @@ export async function getCachedEmbedding(phrenPath, text, apiKey, model) {
|
|
|
269
266
|
db?.close();
|
|
270
267
|
}
|
|
271
268
|
catch (e2) {
|
|
272
|
-
|
|
273
|
-
process.stderr.write(`[phren] embedding getCachedEmbedding dbClose: ${e2 instanceof Error ? e2.message : String(e2)}\n`);
|
|
269
|
+
logger.debug("embedding", `embedding getCachedEmbedding dbClose: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
274
270
|
}
|
|
275
271
|
}
|
|
276
272
|
}
|
|
@@ -320,8 +316,7 @@ export async function getCachedEmbeddings(phrenPath, texts, apiKey, model) {
|
|
|
320
316
|
db?.close();
|
|
321
317
|
}
|
|
322
318
|
catch (e2) {
|
|
323
|
-
|
|
324
|
-
process.stderr.write(`[phren] embedding getCachedEmbeddings dbClose: ${e2 instanceof Error ? e2.message : String(e2)}\n`);
|
|
319
|
+
logger.debug("embedding", `embedding getCachedEmbeddings dbClose: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
325
320
|
}
|
|
326
321
|
}
|
|
327
322
|
}
|
package/mcp/dist/entrypoint.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { parseMcpMode, runInit } from "./init.js";
|
|
3
|
+
import { parseMcpMode, runInit } from "./init/init.js";
|
|
4
4
|
import { errorMessage } from "./utils.js";
|
|
5
|
+
import { logger } from "./logger.js";
|
|
5
6
|
import { defaultPhrenPath, findPhrenPath } from "./shared.js";
|
|
6
|
-
import { addProjectFromPath } from "./core
|
|
7
|
+
import { addProjectFromPath } from "./core/project.js";
|
|
7
8
|
import { PROJECT_OWNERSHIP_MODES, getProjectOwnershipDefault, parseProjectOwnershipMode, } from "./project-config.js";
|
|
8
9
|
const HELP_TEXT = `phren - persistent knowledge for your agents
|
|
9
10
|
|
|
@@ -344,7 +345,7 @@ export async function runTopLevelCommand(argv) {
|
|
|
344
345
|
return finish();
|
|
345
346
|
}
|
|
346
347
|
if (argvCommand === "uninstall") {
|
|
347
|
-
const { runUninstall } = await import("./init.js");
|
|
348
|
+
const { runUninstall } = await import("./init/init.js");
|
|
348
349
|
const skipConfirm = argv.includes("--yes") || argv.includes("-y");
|
|
349
350
|
await runUninstall({ yes: skipConfirm });
|
|
350
351
|
return finish();
|
|
@@ -355,8 +356,8 @@ export async function runTopLevelCommand(argv) {
|
|
|
355
356
|
return finish();
|
|
356
357
|
}
|
|
357
358
|
if (argvCommand === "verify") {
|
|
358
|
-
const { runPostInitVerify, getVerifyOutcomeNote } = await import("./init.js");
|
|
359
|
-
const { getWorkflowPolicy } = await import("./shared
|
|
359
|
+
const { runPostInitVerify, getVerifyOutcomeNote } = await import("./init/init.js");
|
|
360
|
+
const { getWorkflowPolicy } = await import("./shared/governance.js");
|
|
360
361
|
const phrenPath = findPhrenPath() || defaultPhrenPath();
|
|
361
362
|
const result = runPostInitVerify(phrenPath);
|
|
362
363
|
console.log(`phren verify: ${result.ok ? "ok" : "issues found"}`);
|
|
@@ -376,7 +377,7 @@ export async function runTopLevelCommand(argv) {
|
|
|
376
377
|
return finish(result.ok ? 0 : 1);
|
|
377
378
|
}
|
|
378
379
|
if (argvCommand === "mcp-mode") {
|
|
379
|
-
const { runMcpMode } = await import("./init.js");
|
|
380
|
+
const { runMcpMode } = await import("./init/init.js");
|
|
380
381
|
try {
|
|
381
382
|
await runMcpMode(argv[1]);
|
|
382
383
|
return finish();
|
|
@@ -387,7 +388,7 @@ export async function runTopLevelCommand(argv) {
|
|
|
387
388
|
}
|
|
388
389
|
}
|
|
389
390
|
if (argvCommand === "hooks-mode") {
|
|
390
|
-
const { runHooksMode } = await import("./init.js");
|
|
391
|
+
const { runHooksMode } = await import("./init/init.js");
|
|
391
392
|
try {
|
|
392
393
|
await runHooksMode(argv[1]);
|
|
393
394
|
return finish();
|
|
@@ -405,19 +406,18 @@ export async function runTopLevelCommand(argv) {
|
|
|
405
406
|
return finish();
|
|
406
407
|
}
|
|
407
408
|
if (!argvCommand && process.stdin.isTTY && process.stdout.isTTY) {
|
|
408
|
-
const { runCliCommand } = await import("./cli.js");
|
|
409
|
+
const { runCliCommand } = await import("./cli/cli.js");
|
|
409
410
|
await runCliCommand("shell", []);
|
|
410
411
|
return finish();
|
|
411
412
|
}
|
|
412
413
|
if (argvCommand && CLI_COMMANDS.includes(argvCommand)) {
|
|
413
|
-
const { runCliCommand } = await import("./cli.js");
|
|
414
|
+
const { runCliCommand } = await import("./cli/cli.js");
|
|
414
415
|
try {
|
|
415
416
|
const { trackCliCommand } = await import("./telemetry.js");
|
|
416
417
|
trackCliCommand(defaultPhrenPath(), argvCommand);
|
|
417
418
|
}
|
|
418
419
|
catch (err) {
|
|
419
|
-
|
|
420
|
-
process.stderr.write(`[phren] cli trackCliCommand: ${errorMessage(err)}\n`);
|
|
420
|
+
logger.debug("cli", `trackCliCommand: ${errorMessage(err)}`);
|
|
421
421
|
}
|
|
422
422
|
await runCliCommand(argvCommand, argv.slice(1));
|
|
423
423
|
return finish();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import { safeProjectPath } from "
|
|
4
|
-
import { resolveTaskFilePath } from "
|
|
3
|
+
import { safeProjectPath } from "../utils.js";
|
|
4
|
+
import { resolveTaskFilePath } from "../data/tasks.js";
|
|
5
5
|
const ACTIVE_HEADINGS = new Set(["active", "in progress", "in-progress", "current", "wip"]);
|
|
6
6
|
const QUEUE_HEADINGS = new Set(["queue", "queued", "task", "todo", "upcoming", "next"]);
|
|
7
7
|
const DONE_HEADINGS = new Set(["done", "completed", "finished", "archived"]);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as crypto from "crypto";
|
|
2
2
|
import * as fs from "fs";
|
|
3
|
-
import { impactLogFile } from "
|
|
4
|
-
import { withFileLock } from "
|
|
5
|
-
import { normalizeFindingText } from "
|
|
3
|
+
import { impactLogFile } from "../shared.js";
|
|
4
|
+
import { withFileLock } from "../shared/governance.js";
|
|
5
|
+
import { normalizeFindingText } from "../content/metadata.js";
|
|
6
6
|
let highImpactCache = null;
|
|
7
7
|
function nowIso() {
|
|
8
8
|
return new Date().toISOString();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import * as crypto from "crypto";
|
|
4
|
-
import { runtimeDir, phrenOk, phrenErr, PhrenError } from "
|
|
5
|
-
import { withFileLock } from "
|
|
6
|
-
import { addFindingToFile } from "
|
|
7
|
-
import { isValidProjectName, errorMessage } from "
|
|
4
|
+
import { runtimeDir, phrenOk, phrenErr, PhrenError } from "../shared.js";
|
|
5
|
+
import { withFileLock } from "../shared/governance.js";
|
|
6
|
+
import { addFindingToFile } from "../shared/content.js";
|
|
7
|
+
import { isValidProjectName, errorMessage } from "../utils.js";
|
|
8
8
|
function journalRoot(phrenPath) {
|
|
9
9
|
const dir = path.join(runtimeDir(phrenPath), "finding-journal");
|
|
10
10
|
fs.mkdirSync(dir, { recursive: true });
|