memtrace-skills 1.2.7 → 1.2.8

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/dist/skills.js CHANGED
@@ -5,7 +5,8 @@ import path from 'path';
5
5
  * Handles the subset of YAML used in skill files (no nested objects).
6
6
  */
7
7
  function parseFrontmatter(raw) {
8
- const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
8
+ // Skill files are LF in git but CRLF in a Windows checkout; read both.
9
+ const match = raw.replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
9
10
  if (!match)
10
11
  return null;
11
12
  const frontmatterRaw = match[1];
@@ -0,0 +1 @@
1
+ export declare const MEMTRACE_TOOL_NAMES: readonly string[];
@@ -0,0 +1,101 @@
1
+ // Every tool the Memtrace MCP server registers, by its bare name.
2
+ //
3
+ // Pi registers each one as `memtrace_<name>`, so the Pi installer rewrites
4
+ // these names wherever skill text mentions them. Deriving the list from the
5
+ // tools skills happen to allow missed any tool no skill allowed (e.g.
6
+ // find_code_review_issues). `installer_tool_list_matches_the_router` in
7
+ // crates/memtrace-mcp/src/server.rs pins this list to the server's router.
8
+ export const MEMTRACE_TOOL_NAMES = Object.freeze([
9
+ 'analyze_relationships',
10
+ 'ask_docs',
11
+ 'calculate_cyclomatic_complexity',
12
+ 'check_job_status',
13
+ 'cleanup_episodes',
14
+ 'cleanup_stale_records',
15
+ 'cleanup_worktrees',
16
+ 'create_anchor',
17
+ 'delete_repository',
18
+ 'detect_changes',
19
+ 'embed_diag',
20
+ 'embed_reset_breaker',
21
+ 'export_query_audit',
22
+ 'find_api_calls',
23
+ 'find_api_endpoints',
24
+ 'find_ast_review_issues',
25
+ 'find_bridge_symbols',
26
+ 'find_central_symbols',
27
+ 'find_code',
28
+ 'find_code_review_issues',
29
+ 'find_cross_module_issues',
30
+ 'find_dead_code',
31
+ 'find_dependency_path',
32
+ 'find_duplicate_code',
33
+ 'find_hotspots',
34
+ 'find_import_cycles',
35
+ 'find_most_complex_functions',
36
+ 'find_symbol',
37
+ 'find_tool_definitions',
38
+ 'find_yaml_rule_matches',
39
+ 'fleet_acquire_lease',
40
+ 'fleet_audit',
41
+ 'fleet_branch_context',
42
+ 'fleet_get_episode',
43
+ 'fleet_get_escalation',
44
+ 'fleet_get_node_state',
45
+ 'fleet_list_escalations',
46
+ 'fleet_preflight',
47
+ 'fleet_publish_intent',
48
+ 'fleet_query_episodes',
49
+ 'fleet_record_episode',
50
+ 'fleet_release_lease',
51
+ 'fleet_renew_lease',
52
+ 'fleet_resolve_escalation',
53
+ 'fleet_status',
54
+ 'fleet_submit_verdict',
55
+ 'fleet_ydoc_append',
56
+ 'fleet_ydoc_read',
57
+ 'get_api_topology',
58
+ 'get_arc',
59
+ 'get_changes_since',
60
+ 'get_cochange_context',
61
+ 'get_codebase_briefing',
62
+ 'get_daily_briefing',
63
+ 'get_directory_tree',
64
+ 'get_episode_replay',
65
+ 'get_evolution',
66
+ 'get_function_quality_metrics',
67
+ 'get_impact',
68
+ 'get_process_flow',
69
+ 'get_repository_stats',
70
+ 'get_service_diagram',
71
+ 'get_source_window',
72
+ 'get_style_fingerprint',
73
+ 'get_symbol_context',
74
+ 'get_timeline',
75
+ 'governing_contracts',
76
+ 'governing_rules',
77
+ 'index_directory',
78
+ 'ingest_graph_fragment',
79
+ 'link_repositories',
80
+ 'link_symbols',
81
+ 'list_anchors',
82
+ 'list_communities',
83
+ 'list_indexed_repositories',
84
+ 'list_jobs',
85
+ 'list_processes',
86
+ 'list_watched_paths',
87
+ 'list_worktrees',
88
+ 'mem_diag',
89
+ 'preflight_check',
90
+ 'read_doc',
91
+ 'recall_decision',
92
+ 'record_external_episode',
93
+ 'replay_history',
94
+ 'review_agent_sessions',
95
+ 'review_github_pr',
96
+ 'search_docs',
97
+ 'unwatch_directory',
98
+ 'verify_intent',
99
+ 'watch_directory',
100
+ 'why_is_this_here',
101
+ ]);
@@ -1,5 +1,13 @@
1
+ import { Skill } from '../skills.js';
1
2
  import { Transformer, InstallContext } from './types.js';
2
3
  export declare function piSettingsPath(ctx: InstallContext): string;
3
4
  /** Resolve the pi-package directory shipped inside the memtrace npm bundle. */
4
5
  export declare function resolveBundledPiPackage(fromDir?: string): string;
6
+ /**
7
+ * Every Memtrace tool name skill text may mention, bare (`find_code`): the
8
+ * server's full tool list, plus any tool a skill allows. The allowed tools
9
+ * alone missed tools no skill allows, which then stayed bare in Pi skills.
10
+ */
11
+ export declare function memtraceToolNames(skills: readonly Skill[]): string[];
12
+ export declare function transformForPi(text: string, toolNames: readonly string[]): string;
5
13
  export declare const piTransformer: Transformer;
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  import { removeMemtraceSkills, skillName } from './shared.js';
6
6
  import { safeReadJson, writeJsonAtomic } from '../fs-safe.js';
7
7
  import { commandExists } from '../utils.js';
8
+ import { MEMTRACE_TOOL_NAMES } from '../tool-names.js';
8
9
  // Pi (https://pi.dev/docs/latest/packages) uses native pi packages — not MCP JSON
9
10
  // config like Cursor. The bundled `pi-package/` extension spawns `memtrace mcp`
10
11
  // itself and registers every Memtrace tool as a native Pi tool (`memtrace_*`).
@@ -30,8 +31,32 @@ export function resolveBundledPiPackage(fromDir = path.dirname(fileURLToPath(imp
30
31
  }
31
32
  throw new Error('bundled pi-package not found (reinstall memtrace from npm)');
32
33
  }
33
- function transformForPi(text) {
34
- return text.replace(/mcp__memtrace__/g, 'memtrace_');
34
+ const MEMTRACE_TOOL_PREFIX = 'mcp__memtrace__';
35
+ /**
36
+ * Every Memtrace tool name skill text may mention, bare (`find_code`): the
37
+ * server's full tool list, plus any tool a skill allows. The allowed tools
38
+ * alone missed tools no skill allows, which then stayed bare in Pi skills.
39
+ */
40
+ export function memtraceToolNames(skills) {
41
+ const names = new Set(MEMTRACE_TOOL_NAMES);
42
+ for (const skill of skills) {
43
+ for (const tool of skill.frontmatter['allowed-tools'] ?? []) {
44
+ if (tool.startsWith(MEMTRACE_TOOL_PREFIX))
45
+ names.add(tool.slice(MEMTRACE_TOOL_PREFIX.length));
46
+ }
47
+ }
48
+ return [...names].sort();
49
+ }
50
+ // Pi registers each Memtrace tool as `memtrace_<name>`. Skill bodies name tools
51
+ // bare (`find_code`), so rewriting only the `mcp__memtrace__` prefix changed
52
+ // nothing in them: every Pi skill allowed `memtrace_get_evolution` while its
53
+ // prose told the agent to call `get_evolution`.
54
+ export function transformForPi(text, toolNames) {
55
+ const prefixed = text.replace(/mcp__memtrace__/g, 'memtrace_');
56
+ if (toolNames.length === 0)
57
+ return prefixed;
58
+ const bare = new RegExp(`(?<![A-Za-z0-9_])(${toolNames.join('|')})(?![A-Za-z0-9_])`, 'g');
59
+ return prefixed.replace(bare, 'memtrace_$1');
35
60
  }
36
61
  function transformAllowedTool(tool) {
37
62
  return tool
@@ -40,23 +65,28 @@ function transformAllowedTool(tool) {
40
65
  .replace(/^Grep$/, 'grep')
41
66
  .replace(/^Glob$/, 'find');
42
67
  }
43
- function skillMarkdownForPi(skill) {
68
+ function skillMarkdownForPi(skill, toolNames) {
44
69
  const name = skillName(skill);
45
- const safeDesc = skill.frontmatter.description.replace(/"/g, '\\"').trim();
70
+ // The description is what Pi routes on, so it names tools the way Pi
71
+ // registers them too.
72
+ const safeDesc = transformForPi(skill.frontmatter.description, toolNames)
73
+ .replace(/"/g, '\\"')
74
+ .trim();
46
75
  const tools = skill.frontmatter['allowed-tools'];
47
76
  const toolsLine = tools?.length
48
77
  ? `\nallowed-tools: ${tools.map(transformAllowedTool).join(' ')}`
49
78
  : '';
50
- const body = transformForPi(skill.body);
79
+ const body = transformForPi(skill.body, toolNames);
51
80
  return `---\nname: ${name}\ndescription: "${safeDesc}"${toolsLine}\n---\n\n${body}`;
52
81
  }
53
82
  function writeSkillsForPi(skills, rootDir) {
54
83
  removeMemtraceSkills(rootDir);
84
+ const toolNames = memtraceToolNames(skills);
55
85
  for (const skill of skills) {
56
86
  const name = skillName(skill);
57
87
  const outDir = path.join(rootDir, name);
58
88
  fs.mkdirSync(outDir, { recursive: true });
59
- fs.writeFileSync(path.join(outDir, 'SKILL.md'), skillMarkdownForPi(skill));
89
+ fs.writeFileSync(path.join(outDir, 'SKILL.md'), skillMarkdownForPi(skill, toolNames));
60
90
  }
61
91
  return skills.length;
62
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memtrace-skills",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "Memtrace skills for AI coding agents — codebase exploration, temporal evolution, impact analysis, and more.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- export const PLUGIN_ASSET_PATHS: readonly ['commands', 'README.md'];
1
+ export const PLUGIN_ASSET_PATHS: readonly ['commands', 'references', 'README.md'];
2
2
  export const PLUGIN_MANIFEST_PATH: string;
3
3
  export const LEGACY_PLUGIN_ASSET_PATHS: readonly [
4
4
  'hooks',
@@ -1,7 +1,11 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
 
4
- export const PLUGIN_ASSET_PATHS = Object.freeze(['commands', 'README.md']);
4
+ // `references/` holds the parameter spec that 25 skills send the agent to
5
+ // ("bundled at the memtrace-skills plugin root"); without it here the
6
+ // plugin install never wrote the file those skills name. Only the Claude
7
+ // Code plugin carries it; other agents' skill installs do not.
8
+ export const PLUGIN_ASSET_PATHS = Object.freeze(['commands', 'references', 'README.md']);
5
9
  export const PLUGIN_MANIFEST_PATH = path.join('.claude-plugin', 'plugin.json');
6
10
  export const LEGACY_PLUGIN_ASSET_PATHS = Object.freeze([
7
11
  'hooks',
@@ -89,6 +89,8 @@ the repository.
89
89
  | `limit` | integer | no | `20` | Max 100 |
90
90
  | `as_of` | string | no | now | Time-travel search |
91
91
  | `include_diagnostics` | boolean | no | `false` | Include `id`, `score` in results |
92
+ | `include_dependency_checks` | boolean | no | `true` | With diagnostics, set false for scores without pre-edit risk checks |
93
+ | `include_context` | boolean | no | auto | Bounded processes, communities and selected callers/callees; default on for concepts, off for identifiers |
92
94
 
93
95
  No `kind` param — use `find_symbol(kind=...)` instead.
94
96
 
@@ -128,8 +130,11 @@ No parameters. Call once at session start to get `repo_id` values.
128
130
  | `branch` | string | no | `"main"` |
129
131
  | `as_of` | string | no | now |
130
132
  | `view` | string | no | `"live"` |
133
+ | `include_content` | boolean | no | `false` |
134
+ | `limit` | integer | no | `20` (max `200`) |
135
+ | `offset` | integer | no | `0` |
131
136
 
132
- Returns: symbol, callers, callees, type_references, community, processes, api_callers_cross_repo.
137
+ Returns compact symbol locations, relationship sections, community and process context. Source bodies require `include_content: true`, or use `get_source_window`. Each section has `pagination` metadata with `available`, `returned`, `offset`, and `next_offset`. The offset applies independently to each section; repeat with that section's `next_offset` to continue it. These pages cover the bounded graph result: `graph_truncated` and `available_is_lower_bound` remain true when an internal graph cap was reached.
133
138
 
134
139
  ### `analyze_relationships`
135
140
  | Field | Type | Required | Default | Notes |
@@ -269,6 +274,10 @@ Returns `cochanged_files[]` with `file_path`, `cochange_count`, `last_cochanged_
269
274
  | `repo_id` | string | yes | — |
270
275
  | `process` | string | yes | — |
271
276
  | `branch` | string | no | `"main"` |
277
+ | `limit` | integer | no | `20` (max `200`) |
278
+ | `offset` | integer | no | `0` |
279
+
280
+ Returns ordered steps, `total_steps`, `returned_steps`, `next_offset`, and `scan_truncated`. Follow `next_offset` to continue. The existing internal scan cap still applies; `scan_truncated` signals when pagination cannot expose the entire process.
272
281
 
273
282
  ### `find_dependency_path`
274
283
  | Field | Type | Required | Default | Notes |