@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,22 +1,23 @@
|
|
|
1
|
-
import { mcpResponse } from "./
|
|
1
|
+
import { mcpResponse } from "./types.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as crypto from "crypto";
|
|
6
6
|
import { execFileSync } from "child_process";
|
|
7
|
-
import { debugLog, isMemoryScopeVisible, normalizeMemoryScope } from "
|
|
8
|
-
import { withFileLock } from "
|
|
9
|
-
import { isValidProjectName, errorMessage } from "
|
|
10
|
-
import { runCustomHooks } from "
|
|
11
|
-
import { readExtractedFacts } from "./
|
|
12
|
-
import { resolveFindingSessionId } from "
|
|
13
|
-
import { readTasks } from "
|
|
14
|
-
import { readFindings } from "
|
|
15
|
-
import { getProjectDirs } from "
|
|
16
|
-
import { getActiveTaskForSession } from "
|
|
17
|
-
import { listTaskCheckpoints, writeTaskCheckpoint } from "
|
|
18
|
-
import { markImpactEntriesCompletedForSession } from "
|
|
19
|
-
import { atomicWriteJson, debugError, scanSessionFiles } from "
|
|
7
|
+
import { debugLog, isMemoryScopeVisible, normalizeMemoryScope } from "../shared.js";
|
|
8
|
+
import { withFileLock } from "../shared/governance.js";
|
|
9
|
+
import { isValidProjectName, errorMessage } from "../utils.js";
|
|
10
|
+
import { runCustomHooks } from "../hooks.js";
|
|
11
|
+
import { readExtractedFacts } from "./extract-facts.js";
|
|
12
|
+
import { resolveFindingSessionId } from "../finding/context.js";
|
|
13
|
+
import { readTasks } from "../data/tasks.js";
|
|
14
|
+
import { readFindings } from "../data/access.js";
|
|
15
|
+
import { getProjectDirs } from "../shared.js";
|
|
16
|
+
import { getActiveTaskForSession } from "../task/lifecycle.js";
|
|
17
|
+
import { listTaskCheckpoints, writeTaskCheckpoint } from "../session/checkpoints.js";
|
|
18
|
+
import { markImpactEntriesCompletedForSession } from "../finding/impact.js";
|
|
19
|
+
import { atomicWriteJson, debugError, scanSessionFiles } from "../session/utils.js";
|
|
20
|
+
import { getRuntimeHealth } from "../governance/policy.js";
|
|
20
21
|
const STALE_SESSION_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
21
22
|
function collectGitStatusSnapshot(cwd) {
|
|
22
23
|
try {
|
|
@@ -165,7 +166,8 @@ function writeLastSummary(phrenPath, summary, sessionId, project) {
|
|
|
165
166
|
debugError("writeLastSummary", err);
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
/** Find the most recent session with a summary (including ended sessions).
|
|
169
|
+
/** Find the most recent session with a summary (including ended sessions).
|
|
170
|
+
* @internal Exported for tests. */
|
|
169
171
|
export function findMostRecentSummary(phrenPath) {
|
|
170
172
|
return findMostRecentSummaryWithProject(phrenPath).summary;
|
|
171
173
|
}
|
|
@@ -215,6 +217,10 @@ function cleanupStaleSessions(phrenPath) {
|
|
|
215
217
|
let cleaned = 0;
|
|
216
218
|
for (const { fullPath, data: state } of results) {
|
|
217
219
|
try {
|
|
220
|
+
// Only clean up sessions that have ended (have endedAt). Active sessions
|
|
221
|
+
// (no endedAt) should never be removed regardless of age.
|
|
222
|
+
if (state && !state.endedAt)
|
|
223
|
+
continue;
|
|
218
224
|
// prefer startedAt from the JSON content over mtime (reliable on noatime mounts)
|
|
219
225
|
const ageMs = state?.startedAt
|
|
220
226
|
? Date.now() - new Date(state.startedAt).getTime()
|
|
@@ -347,7 +353,7 @@ function hasCompletedTasksInSession(phrenPath, sessionId, project) {
|
|
|
347
353
|
return artifacts.tasks.some((task) => task.section === "Done" && task.checked);
|
|
348
354
|
}
|
|
349
355
|
/** Compute what changed since the last session ended. */
|
|
350
|
-
|
|
356
|
+
function computeSessionDiff(phrenPath, project, lastSessionEnd) {
|
|
351
357
|
const projectDir = path.join(phrenPath, project);
|
|
352
358
|
const findingsPath = path.join(projectDir, "FINDINGS.md");
|
|
353
359
|
if (!fs.existsSync(findingsPath))
|
|
@@ -403,16 +409,15 @@ export function register(server, ctx) {
|
|
|
403
409
|
if (agentScope !== undefined && !normalizedAgentScope) {
|
|
404
410
|
return mcpResponse({ ok: false, error: `Invalid agentScope: "${agentScope}". Use lowercase letters/numbers with '-' or '_' (max 64 chars).` });
|
|
405
411
|
}
|
|
406
|
-
// Find most recent prior session for context
|
|
412
|
+
// Find most recent prior session for context.
|
|
413
|
+
// When no explicit project is provided, prefer the last ENDED session's
|
|
414
|
+
// project (completed context) over an active session from a different client.
|
|
415
|
+
const priorEnded = findMostRecentSummaryWithProject(phrenPath);
|
|
407
416
|
const priorResult = findMostRecentSession(phrenPath);
|
|
408
417
|
const prior = priorResult?.state ?? null;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const priorEnded = prior ? null : findMostRecentSummaryWithProject(phrenPath);
|
|
413
|
-
const priorSummary = prior?.summary ?? priorEnded?.summary ?? null;
|
|
414
|
-
const priorProject = prior?.project ?? priorEnded?.project;
|
|
415
|
-
const priorEndedAt = prior?.endedAt ?? priorEnded?.endedAt;
|
|
418
|
+
const priorSummary = priorEnded?.summary ?? prior?.summary ?? null;
|
|
419
|
+
const priorProject = priorEnded?.project ?? prior?.project;
|
|
420
|
+
const priorEndedAt = priorEnded?.endedAt ?? prior?.endedAt;
|
|
416
421
|
// Create new session with unique ID in its own file
|
|
417
422
|
const sessionId = crypto.randomUUID();
|
|
418
423
|
const next = {
|
|
@@ -521,10 +526,31 @@ export function register(server, ctx) {
|
|
|
521
526
|
debugError("session_start contextDiff", err);
|
|
522
527
|
}
|
|
523
528
|
}
|
|
529
|
+
// ── Surface sync/health warnings ────────────────────────────────────
|
|
530
|
+
const sessionWarnings = [];
|
|
531
|
+
try {
|
|
532
|
+
const health = getRuntimeHealth(phrenPath);
|
|
533
|
+
if (health.lastAutoSave?.status === "error") {
|
|
534
|
+
sessionWarnings.push(`Last auto-save failed: ${health.lastAutoSave.detail ?? "unknown"}`);
|
|
535
|
+
}
|
|
536
|
+
if (health.lastSync?.lastPushStatus === "error") {
|
|
537
|
+
sessionWarnings.push(`Last push failed: ${health.lastSync.lastPushDetail ?? "unknown"}`);
|
|
538
|
+
}
|
|
539
|
+
const unsynced = health.lastSync?.unsyncedCommits;
|
|
540
|
+
if (typeof unsynced === "number" && unsynced > 0) {
|
|
541
|
+
sessionWarnings.push(`${unsynced} unsynced commit${unsynced === 1 ? "" : "s"} — run 'phren doctor' or check git remote`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
debugError("session_start runtimeHealth", err);
|
|
546
|
+
}
|
|
547
|
+
if (sessionWarnings.length > 0) {
|
|
548
|
+
parts.push(`## Sync warnings\n${sessionWarnings.map(w => `- ${w}`).join("\n")}`);
|
|
549
|
+
}
|
|
524
550
|
const message = parts.length > 0
|
|
525
551
|
? `Session started (${sessionId.slice(0, 8)}).\n\n${parts.join("\n\n")}`
|
|
526
552
|
: `Session started (${sessionId.slice(0, 8)}). No prior context found.`;
|
|
527
|
-
return mcpResponse({ ok: true, message, data: { sessionId, project: activeProject, agentScope: activeScope } });
|
|
553
|
+
return mcpResponse({ ok: true, message, data: { sessionId, project: activeProject, agentScope: activeScope, warnings: sessionWarnings.length > 0 ? sessionWarnings : undefined } });
|
|
528
554
|
});
|
|
529
555
|
server.registerTool("session_end", {
|
|
530
556
|
title: "◆ phren · session end",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { mcpResponse } from "./
|
|
1
|
+
import { mcpResponse } from "./types.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import * as path from "path";
|
|
5
|
-
import { isValidProjectName, safeProjectPath } from "
|
|
6
|
-
import { parseSkillFrontmatter, validateSkillFrontmatter } from "
|
|
7
|
-
import { removeSkillPath, setSkillEnabledAndSync } from "
|
|
8
|
-
import { buildSkillManifest, findLocalSkill, findSkill, getAllSkills } from "
|
|
5
|
+
import { isValidProjectName, safeProjectPath } from "../utils.js";
|
|
6
|
+
import { parseSkillFrontmatter, validateSkillFrontmatter } from "../link/skills.js";
|
|
7
|
+
import { removeSkillPath, setSkillEnabledAndSync } from "../skill/files.js";
|
|
8
|
+
import { buildSkillManifest, findLocalSkill, findSkill, getAllSkills } from "../skill/registry.js";
|
|
9
9
|
export function register(server, ctx) {
|
|
10
10
|
const { phrenPath, profile, withWriteQueue, updateFileInIndex } = ctx;
|
|
11
11
|
// ── list_skills ──────────────────────────────────────────────────────────
|
|
@@ -80,6 +80,15 @@ export function register(server, ctx) {
|
|
|
80
80
|
if ("error" in result) {
|
|
81
81
|
return mcpResponse({ ok: false, error: result.error });
|
|
82
82
|
}
|
|
83
|
+
// Verify skill path doesn't escape phren via symlink
|
|
84
|
+
try {
|
|
85
|
+
const realPath = fs.realpathSync(result.path);
|
|
86
|
+
const phrenReal = fs.realpathSync(phrenPath);
|
|
87
|
+
if (!realPath.startsWith(phrenReal + path.sep) && !realPath.startsWith(path.dirname(phrenReal) + path.sep)) {
|
|
88
|
+
return mcpResponse({ ok: false, error: `Skill path resolves outside phren store.` });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch { /* path doesn't exist or can't resolve — let readFileSync handle it */ }
|
|
83
92
|
const content = fs.readFileSync(result.path, "utf8");
|
|
84
93
|
const { frontmatter, body } = parseSkillFrontmatter(content);
|
|
85
94
|
const { valid, errors } = validateSkillFrontmatter(content, result.path);
|
|
@@ -165,36 +174,34 @@ export function register(server, ctx) {
|
|
|
165
174
|
return mcpResponse({ ok: true, message: `Removed skill "${name}" (${removedPath}).`, data: { path: removedPath } });
|
|
166
175
|
});
|
|
167
176
|
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
data: { name: result.name, project, enabled: action.enabled },
|
|
196
|
-
});
|
|
177
|
+
// ── toggle_skill ─────────────────────────────────────────────────────
|
|
178
|
+
server.registerTool("toggle_skill", {
|
|
179
|
+
title: "◆ phren · toggle skill",
|
|
180
|
+
description: "Enable or disable a skill without deleting its file.",
|
|
181
|
+
inputSchema: z.object({
|
|
182
|
+
name: z.string().describe("Skill name (without .md)."),
|
|
183
|
+
enabled: z.boolean().describe("true to enable, false to disable."),
|
|
184
|
+
project: z.string().describe("Project scope or 'global'."),
|
|
185
|
+
}),
|
|
186
|
+
}, async ({ name, enabled, project }) => {
|
|
187
|
+
if (project.toLowerCase() !== "global" && !isValidProjectName(project)) {
|
|
188
|
+
return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
|
|
189
|
+
}
|
|
190
|
+
const result = findSkill(phrenPath, profile, project, name);
|
|
191
|
+
if (!result) {
|
|
192
|
+
return mcpResponse({ ok: false, error: `Skill "${name}" not found in "${project}".` });
|
|
193
|
+
}
|
|
194
|
+
if ("error" in result) {
|
|
195
|
+
return mcpResponse({ ok: false, error: result.error });
|
|
196
|
+
}
|
|
197
|
+
const verb = enabled ? "Enable" : "Disable";
|
|
198
|
+
return withWriteQueue(async () => {
|
|
199
|
+
setSkillEnabledAndSync(phrenPath, project, result.name, enabled);
|
|
200
|
+
return mcpResponse({
|
|
201
|
+
ok: true,
|
|
202
|
+
message: `${verb}d skill "${result.name}" in ${project}.`,
|
|
203
|
+
data: { name: result.name, project, enabled },
|
|
197
204
|
});
|
|
198
205
|
});
|
|
199
|
-
}
|
|
206
|
+
});
|
|
200
207
|
}
|