@phren/cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +590 -0
  3. package/mcp/dist/capabilities/cli.js +61 -0
  4. package/mcp/dist/capabilities/index.js +15 -0
  5. package/mcp/dist/capabilities/mcp.js +61 -0
  6. package/mcp/dist/capabilities/types.js +57 -0
  7. package/mcp/dist/capabilities/vscode.js +61 -0
  8. package/mcp/dist/capabilities/web-ui.js +61 -0
  9. package/mcp/dist/cli-actions.js +302 -0
  10. package/mcp/dist/cli-config.js +580 -0
  11. package/mcp/dist/cli-extract.js +305 -0
  12. package/mcp/dist/cli-govern.js +371 -0
  13. package/mcp/dist/cli-graph.js +169 -0
  14. package/mcp/dist/cli-hooks-citations.js +44 -0
  15. package/mcp/dist/cli-hooks-context.js +56 -0
  16. package/mcp/dist/cli-hooks-globs.js +83 -0
  17. package/mcp/dist/cli-hooks-output.js +130 -0
  18. package/mcp/dist/cli-hooks-retrieval.js +2 -0
  19. package/mcp/dist/cli-hooks-session.js +1402 -0
  20. package/mcp/dist/cli-hooks.js +350 -0
  21. package/mcp/dist/cli-namespaces.js +989 -0
  22. package/mcp/dist/cli-ops.js +253 -0
  23. package/mcp/dist/cli-search.js +407 -0
  24. package/mcp/dist/cli.js +108 -0
  25. package/mcp/dist/content-archive.js +278 -0
  26. package/mcp/dist/content-citation.js +391 -0
  27. package/mcp/dist/content-dedup.js +622 -0
  28. package/mcp/dist/content-learning.js +472 -0
  29. package/mcp/dist/content-metadata.js +186 -0
  30. package/mcp/dist/content-validate.js +462 -0
  31. package/mcp/dist/core-finding.js +54 -0
  32. package/mcp/dist/core-project.js +36 -0
  33. package/mcp/dist/core-search.js +50 -0
  34. package/mcp/dist/data-access.js +400 -0
  35. package/mcp/dist/data-tasks.js +821 -0
  36. package/mcp/dist/embedding.js +344 -0
  37. package/mcp/dist/entrypoint.js +387 -0
  38. package/mcp/dist/finding-context.js +172 -0
  39. package/mcp/dist/finding-impact.js +181 -0
  40. package/mcp/dist/finding-journal.js +122 -0
  41. package/mcp/dist/finding-lifecycle.js +259 -0
  42. package/mcp/dist/governance-audit.js +22 -0
  43. package/mcp/dist/governance-locks.js +96 -0
  44. package/mcp/dist/governance-policy.js +648 -0
  45. package/mcp/dist/governance-scores.js +355 -0
  46. package/mcp/dist/hooks.js +449 -0
  47. package/mcp/dist/impact-scoring.js +22 -0
  48. package/mcp/dist/index-query.js +168 -0
  49. package/mcp/dist/index.js +205 -0
  50. package/mcp/dist/init-config.js +336 -0
  51. package/mcp/dist/init-preferences.js +62 -0
  52. package/mcp/dist/init-setup.js +1305 -0
  53. package/mcp/dist/init-shared.js +29 -0
  54. package/mcp/dist/init.js +1730 -0
  55. package/mcp/dist/link-checksums.js +62 -0
  56. package/mcp/dist/link-context.js +257 -0
  57. package/mcp/dist/link-doctor.js +591 -0
  58. package/mcp/dist/link-skills.js +212 -0
  59. package/mcp/dist/link.js +596 -0
  60. package/mcp/dist/logger.js +15 -0
  61. package/mcp/dist/machine-identity.js +38 -0
  62. package/mcp/dist/mcp-config.js +254 -0
  63. package/mcp/dist/mcp-data.js +315 -0
  64. package/mcp/dist/mcp-extract-facts.js +78 -0
  65. package/mcp/dist/mcp-extract.js +133 -0
  66. package/mcp/dist/mcp-finding.js +557 -0
  67. package/mcp/dist/mcp-graph.js +339 -0
  68. package/mcp/dist/mcp-hooks.js +256 -0
  69. package/mcp/dist/mcp-memory.js +58 -0
  70. package/mcp/dist/mcp-ops.js +328 -0
  71. package/mcp/dist/mcp-search.js +628 -0
  72. package/mcp/dist/mcp-session.js +651 -0
  73. package/mcp/dist/mcp-skills.js +189 -0
  74. package/mcp/dist/mcp-tasks.js +551 -0
  75. package/mcp/dist/mcp-types.js +7 -0
  76. package/mcp/dist/memory-ui-assets.js +6 -0
  77. package/mcp/dist/memory-ui-data.js +513 -0
  78. package/mcp/dist/memory-ui-graph.js +1910 -0
  79. package/mcp/dist/memory-ui-page.js +353 -0
  80. package/mcp/dist/memory-ui-scripts.js +1387 -0
  81. package/mcp/dist/memory-ui-server.js +1218 -0
  82. package/mcp/dist/memory-ui-styles.js +555 -0
  83. package/mcp/dist/memory-ui.js +9 -0
  84. package/mcp/dist/package-metadata.js +13 -0
  85. package/mcp/dist/phren-art.js +52 -0
  86. package/mcp/dist/phren-core.js +108 -0
  87. package/mcp/dist/phren-dotenv.js +67 -0
  88. package/mcp/dist/phren-paths.js +476 -0
  89. package/mcp/dist/proactivity.js +172 -0
  90. package/mcp/dist/profile-store.js +228 -0
  91. package/mcp/dist/project-config.js +85 -0
  92. package/mcp/dist/project-locator.js +25 -0
  93. package/mcp/dist/project-topics.js +1134 -0
  94. package/mcp/dist/provider-adapters.js +176 -0
  95. package/mcp/dist/runtime-profile.js +18 -0
  96. package/mcp/dist/session-checkpoints.js +131 -0
  97. package/mcp/dist/session-utils.js +68 -0
  98. package/mcp/dist/shared-content.js +8 -0
  99. package/mcp/dist/shared-embedding-cache.js +143 -0
  100. package/mcp/dist/shared-fragment-graph.js +456 -0
  101. package/mcp/dist/shared-governance.js +4 -0
  102. package/mcp/dist/shared-index.js +1334 -0
  103. package/mcp/dist/shared-ollama.js +192 -0
  104. package/mcp/dist/shared-paths.js +1 -0
  105. package/mcp/dist/shared-retrieval.js +796 -0
  106. package/mcp/dist/shared-search-fallback.js +375 -0
  107. package/mcp/dist/shared-sqljs.js +42 -0
  108. package/mcp/dist/shared-stemmer.js +171 -0
  109. package/mcp/dist/shared-vector-index.js +199 -0
  110. package/mcp/dist/shared.js +114 -0
  111. package/mcp/dist/shell-entry.js +209 -0
  112. package/mcp/dist/shell-input.js +943 -0
  113. package/mcp/dist/shell-palette.js +119 -0
  114. package/mcp/dist/shell-render.js +252 -0
  115. package/mcp/dist/shell-state-store.js +81 -0
  116. package/mcp/dist/shell-types.js +13 -0
  117. package/mcp/dist/shell-view-list.js +14 -0
  118. package/mcp/dist/shell-view.js +707 -0
  119. package/mcp/dist/shell.js +352 -0
  120. package/mcp/dist/skill-files.js +117 -0
  121. package/mcp/dist/skill-registry.js +279 -0
  122. package/mcp/dist/skill-state.js +28 -0
  123. package/mcp/dist/startup-embedding.js +57 -0
  124. package/mcp/dist/status.js +323 -0
  125. package/mcp/dist/synonyms.json +670 -0
  126. package/mcp/dist/task-hygiene.js +251 -0
  127. package/mcp/dist/task-lifecycle.js +347 -0
  128. package/mcp/dist/tasks-github.js +76 -0
  129. package/mcp/dist/telemetry.js +165 -0
  130. package/mcp/dist/test-global-setup.js +37 -0
  131. package/mcp/dist/tool-registry.js +104 -0
  132. package/mcp/dist/update.js +97 -0
  133. package/mcp/dist/utils.js +543 -0
  134. package/package.json +67 -0
  135. package/skills/README.md +7 -0
  136. package/skills/consolidate/SKILL.md +152 -0
  137. package/skills/discover/SKILL.md +175 -0
  138. package/skills/init/SKILL.md +216 -0
  139. package/skills/profiles/SKILL.md +121 -0
  140. package/skills/sync/SKILL.md +261 -0
  141. package/starter/README.md +74 -0
  142. package/starter/global/CLAUDE.md +89 -0
  143. package/starter/global/skills/humanize.md +30 -0
  144. package/starter/global/skills/pipeline.md +35 -0
  145. package/starter/global/skills/release.md +35 -0
  146. package/starter/machines.yaml +8 -0
  147. package/starter/my-api/.claude/skills/README.md +7 -0
  148. package/starter/my-api/CLAUDE.md +33 -0
  149. package/starter/my-api/FINDINGS.md +9 -0
  150. package/starter/my-api/summary.md +7 -0
  151. package/starter/my-api/tasks.md +7 -0
  152. package/starter/my-first-project/.claude/skills/README.md +7 -0
  153. package/starter/my-first-project/CLAUDE.md +49 -0
  154. package/starter/my-first-project/FINDINGS.md +24 -0
  155. package/starter/my-first-project/summary.md +11 -0
  156. package/starter/my-first-project/tasks.md +25 -0
  157. package/starter/my-frontend/.claude/skills/README.md +7 -0
  158. package/starter/my-frontend/CLAUDE.md +33 -0
  159. package/starter/my-frontend/FINDINGS.md +9 -0
  160. package/starter/my-frontend/summary.md +7 -0
  161. package/starter/my-frontend/tasks.md +7 -0
  162. package/starter/profiles/default.yaml +4 -0
  163. package/starter/profiles/personal.yaml +4 -0
  164. package/starter/profiles/work.yaml +4 -0
  165. package/starter/templates/README.md +7 -0
  166. package/starter/templates/frontend/CLAUDE.md +23 -0
  167. package/starter/templates/frontend/FINDINGS.md +7 -0
  168. package/starter/templates/frontend/reference/README.md +4 -0
  169. package/starter/templates/frontend/summary.md +7 -0
  170. package/starter/templates/frontend/tasks.md +11 -0
  171. package/starter/templates/library/CLAUDE.md +22 -0
  172. package/starter/templates/library/FINDINGS.md +7 -0
  173. package/starter/templates/library/reference/README.md +4 -0
  174. package/starter/templates/library/summary.md +7 -0
  175. package/starter/templates/library/tasks.md +11 -0
  176. package/starter/templates/monorepo/CLAUDE.md +21 -0
  177. package/starter/templates/monorepo/FINDINGS.md +7 -0
  178. package/starter/templates/monorepo/reference/README.md +4 -0
  179. package/starter/templates/monorepo/summary.md +7 -0
  180. package/starter/templates/monorepo/tasks.md +11 -0
  181. package/starter/templates/python-project/CLAUDE.md +21 -0
  182. package/starter/templates/python-project/FINDINGS.md +7 -0
  183. package/starter/templates/python-project/reference/README.md +4 -0
  184. package/starter/templates/python-project/summary.md +7 -0
  185. package/starter/templates/python-project/tasks.md +10 -0
@@ -0,0 +1,189 @@
1
+ import { mcpResponse } from "./mcp-types.js";
2
+ import { z } from "zod";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { isValidProjectName } 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
+ export function register(server, ctx) {
10
+ const { phrenPath, profile, withWriteQueue, updateFileInIndex } = ctx;
11
+ // ── list_skills ──────────────────────────────────────────────────────────
12
+ server.registerTool("list_skills", {
13
+ title: "◆ phren · skills",
14
+ description: "List all installed skills across global and project scopes.",
15
+ inputSchema: z.object({
16
+ project: z.string().optional().describe("Filter to a specific project. Omit for all."),
17
+ }),
18
+ }, async ({ project }) => {
19
+ if (project && !isValidProjectName(project)) {
20
+ return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
21
+ }
22
+ const resolvedSkills = project ? buildSkillManifest(phrenPath, profile, project).skills : null;
23
+ const rawSkills = project ? null : getAllSkills(phrenPath, profile);
24
+ const skills = resolvedSkills || rawSkills || [];
25
+ if (!skills.length) {
26
+ return mcpResponse({ ok: true, message: project ? `No skills found for "${project}".` : "No skills found.", data: { skills: [] } });
27
+ }
28
+ const lines = skills.map(s => `${s.command} -> ${s.name} (${s.source}; ${s.enabled ? "enabled" : "disabled"})${s.description ? ` — ${s.description}` : ""}`);
29
+ const serialized = resolvedSkills
30
+ ? resolvedSkills.map(({ name, source, format, path: p, description, enabled, command, aliases, visibleToAgents, commandRegistered, overrides, mirrorTargets }) => ({
31
+ name,
32
+ source,
33
+ format,
34
+ path: p,
35
+ description: description ?? null,
36
+ enabled,
37
+ command: command ?? null,
38
+ aliases,
39
+ visibleToAgents,
40
+ commandRegistered,
41
+ overrides,
42
+ mirrorTargets,
43
+ }))
44
+ : (rawSkills || []).map(({ name, source, format, path: p, description, enabled, command, aliases }) => ({
45
+ name,
46
+ source,
47
+ format,
48
+ path: p,
49
+ description: description ?? null,
50
+ enabled,
51
+ command: command ?? null,
52
+ aliases,
53
+ visibleToAgents: enabled,
54
+ commandRegistered: enabled,
55
+ overrides: [],
56
+ mirrorTargets: [],
57
+ }));
58
+ return mcpResponse({
59
+ ok: true,
60
+ message: `${skills.length} skill(s):\n${lines.join("\n")}`,
61
+ data: { skills: serialized },
62
+ });
63
+ });
64
+ // ── read_skill ───────────────────────────────────────────────────────────
65
+ server.registerTool("read_skill", {
66
+ title: "◆ phren · read skill",
67
+ description: "Read a skill file's full contents with parsed frontmatter and validation.",
68
+ inputSchema: z.object({
69
+ name: z.string().describe("Skill name (without .md)."),
70
+ project: z.string().optional().describe("Project scope. Omit to search all."),
71
+ }),
72
+ }, async ({ name, project }) => {
73
+ if (project && !isValidProjectName(project)) {
74
+ return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
75
+ }
76
+ const result = findSkill(phrenPath, profile, project, name);
77
+ if (!result) {
78
+ return mcpResponse({ ok: false, error: `Skill "${name}" not found${project ? ` in "${project}"` : ""}.` });
79
+ }
80
+ if ("error" in result) {
81
+ return mcpResponse({ ok: false, error: result.error });
82
+ }
83
+ const content = fs.readFileSync(result.path, "utf8");
84
+ const { frontmatter, body } = parseSkillFrontmatter(content);
85
+ const { valid, errors } = validateSkillFrontmatter(content, result.path);
86
+ return mcpResponse({
87
+ ok: true,
88
+ message: content,
89
+ data: { path: result.path, content, frontmatter: frontmatter ?? null, body, valid, errors },
90
+ });
91
+ });
92
+ // ── write_skill ──────────────────────────────────────────────────────────
93
+ server.registerTool("write_skill", {
94
+ title: "◆ phren · write skill",
95
+ description: "Create or update a skill file with frontmatter validation. Scope: 'global' or a project name.",
96
+ inputSchema: z.object({
97
+ name: z.string().describe("Skill name (without .md)."),
98
+ content: z.string().describe("Full skill content including YAML frontmatter."),
99
+ scope: z.string().describe("'global' or a project name."),
100
+ }),
101
+ }, async ({ name, content, scope }) => {
102
+ if (scope.toLowerCase() !== "global" && !isValidProjectName(scope)) {
103
+ return mcpResponse({ ok: false, error: `Invalid scope: "${scope}". Use 'global' or a project name.` });
104
+ }
105
+ // Validate name is a safe basename: no path separators, no .. segments
106
+ const safeName = name.replace(/\.md$/i, "");
107
+ if (!safeName || safeName.includes("/") || safeName.includes("\\") || safeName.includes("..") || path.basename(safeName) !== safeName) {
108
+ return mcpResponse({ ok: false, error: `Invalid skill name: "${name}". Must be a simple filename with no path separators or traversal sequences.` });
109
+ }
110
+ const { valid, errors } = validateSkillFrontmatter(content);
111
+ if (!valid) {
112
+ return mcpResponse({ ok: false, error: `Invalid frontmatter: ${errors.join("; ")}` });
113
+ }
114
+ return withWriteQueue(async () => {
115
+ const destDir = scope.toLowerCase() === "global"
116
+ ? path.join(phrenPath, "global", "skills")
117
+ : path.join(phrenPath, scope, "skills");
118
+ if (scope.toLowerCase() !== "global" && !fs.existsSync(path.join(phrenPath, scope))) {
119
+ return mcpResponse({ ok: false, error: `Project "${scope}" not found.` });
120
+ }
121
+ fs.mkdirSync(destDir, { recursive: true });
122
+ const existing = findLocalSkill(phrenPath, scope, safeName);
123
+ const dest = existing
124
+ ? existing.path
125
+ : path.join(destDir, `${safeName}.md`);
126
+ const existed = Boolean(existing) || fs.existsSync(dest);
127
+ fs.writeFileSync(dest, content);
128
+ updateFileInIndex(dest);
129
+ return mcpResponse({ ok: true, message: `${existed ? "Updated" : "Created"} skill "${name}" in ${scope}.`, data: { path: dest, created: !existed } });
130
+ });
131
+ });
132
+ // ── remove_skill ─────────────────────────────────────────────────────────
133
+ server.registerTool("remove_skill", {
134
+ title: "◆ phren · remove skill",
135
+ description: "Remove a skill file by name.",
136
+ inputSchema: z.object({
137
+ name: z.string().describe("Skill name (without .md)."),
138
+ project: z.string().optional().describe("Project scope. Omit to search all."),
139
+ }),
140
+ }, async ({ name, project }) => {
141
+ if (project && !isValidProjectName(project)) {
142
+ return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
143
+ }
144
+ const result = project ? findLocalSkill(phrenPath, project, name) : findSkill(phrenPath, profile, project, name);
145
+ if (!result) {
146
+ return mcpResponse({ ok: false, error: `Skill "${name}" not found${project ? ` in "${project}"` : ""}.` });
147
+ }
148
+ if ("error" in result) {
149
+ return mcpResponse({ ok: false, error: result.error });
150
+ }
151
+ return withWriteQueue(async () => {
152
+ const removedPath = removeSkillPath(result.format === "folder" ? result.root : result.path);
153
+ updateFileInIndex(result.path); // called after delete so indexer removes the entry
154
+ return mcpResponse({ ok: true, message: `Removed skill "${name}" (${removedPath}).`, data: { path: removedPath } });
155
+ });
156
+ });
157
+ for (const action of [
158
+ { tool: "enable_skill", enabled: true, verb: "Enable" },
159
+ { tool: "disable_skill", enabled: false, verb: "Disable" },
160
+ ]) {
161
+ server.registerTool(action.tool, {
162
+ title: `◆ phren · ${action.enabled ? "enable" : "disable"} skill`,
163
+ description: `${action.verb} a skill without deleting its file.`,
164
+ inputSchema: z.object({
165
+ name: z.string().describe("Skill name (without .md)."),
166
+ project: z.string().describe("Project scope or 'global'."),
167
+ }),
168
+ }, async ({ name, project }) => {
169
+ if (project.toLowerCase() !== "global" && !isValidProjectName(project)) {
170
+ return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
171
+ }
172
+ const result = findSkill(phrenPath, profile, project, name);
173
+ if (!result) {
174
+ return mcpResponse({ ok: false, error: `Skill "${name}" not found in "${project}".` });
175
+ }
176
+ if ("error" in result) {
177
+ return mcpResponse({ ok: false, error: result.error });
178
+ }
179
+ return withWriteQueue(async () => {
180
+ setSkillEnabledAndSync(phrenPath, project, result.name, action.enabled);
181
+ return mcpResponse({
182
+ ok: true,
183
+ message: `${action.verb}d skill "${result.name}" in ${project}.`,
184
+ data: { name: result.name, project, enabled: action.enabled },
185
+ });
186
+ });
187
+ });
188
+ }
189
+ }