@getmarrow/install 0.1.68 → 0.1.70
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/README.md +92 -59
- package/package.json +1 -1
- package/src/governed-runner.js +40 -25
- package/src/installer.js +170 -79
- package/src/marrow-own-tools.js +121 -0
- package/src/mcp-runtime.js +361 -309
- package/src/owner-env.js +2 -1
- package/src/pins.js +3 -3
- package/src/runtime-core.js +594 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Marrow's own MCP tools: the 58 names the `marrow` server registers (all profiles), in the
|
|
4
|
+
// order of @getmarrow/mcp src/tool-catalog.ts (fix/own-tool-exact 4311df21). Generated from
|
|
5
|
+
// test/fixtures/marrow-own-tool-names.json; a test keeps the two equal.
|
|
6
|
+
const MARROW_OWN_TOOL_NAMES = Object.freeze([
|
|
7
|
+
'marrow_accept_detected',
|
|
8
|
+
'marrow_agent_performance',
|
|
9
|
+
'marrow_agent_runtime',
|
|
10
|
+
'marrow_agent_status',
|
|
11
|
+
'marrow_arbitrate',
|
|
12
|
+
'marrow_ask',
|
|
13
|
+
'marrow_assign_project_policy_profile',
|
|
14
|
+
'marrow_auto',
|
|
15
|
+
'marrow_buyer_proof',
|
|
16
|
+
'marrow_commit',
|
|
17
|
+
'marrow_completion_contracts',
|
|
18
|
+
'marrow_coordinate',
|
|
19
|
+
'marrow_create_handoff',
|
|
20
|
+
'marrow_create_key',
|
|
21
|
+
'marrow_create_policy_profile',
|
|
22
|
+
'marrow_dashboard',
|
|
23
|
+
'marrow_decision_brief',
|
|
24
|
+
'marrow_decision_trace',
|
|
25
|
+
'marrow_delete_memory',
|
|
26
|
+
'marrow_digest',
|
|
27
|
+
'marrow_evaluate_completion_contract',
|
|
28
|
+
'marrow_export_memories',
|
|
29
|
+
'marrow_first_value',
|
|
30
|
+
'marrow_fleet_lessons',
|
|
31
|
+
'marrow_get_key',
|
|
32
|
+
'marrow_get_memory',
|
|
33
|
+
'marrow_governance_control_plane',
|
|
34
|
+
'marrow_governance_timeline',
|
|
35
|
+
'marrow_handoff_status',
|
|
36
|
+
'marrow_hermes_integration',
|
|
37
|
+
'marrow_import_memories',
|
|
38
|
+
'marrow_install_template',
|
|
39
|
+
'marrow_list_keys',
|
|
40
|
+
'marrow_list_memories',
|
|
41
|
+
'marrow_list_templates',
|
|
42
|
+
'marrow_mark_outdated',
|
|
43
|
+
'marrow_mode_recommend',
|
|
44
|
+
'marrow_model_usage',
|
|
45
|
+
'marrow_orient',
|
|
46
|
+
'marrow_policy_profiles',
|
|
47
|
+
'marrow_policy_resolve',
|
|
48
|
+
'marrow_record_deployment_memory',
|
|
49
|
+
'marrow_replay_compare',
|
|
50
|
+
'marrow_retrieve_memories',
|
|
51
|
+
'marrow_revoke_key',
|
|
52
|
+
'marrow_rotate_key',
|
|
53
|
+
'marrow_run',
|
|
54
|
+
'marrow_runtime_status',
|
|
55
|
+
'marrow_session_end',
|
|
56
|
+
'marrow_share_memory',
|
|
57
|
+
'marrow_status',
|
|
58
|
+
'marrow_supersede_memory',
|
|
59
|
+
'marrow_think',
|
|
60
|
+
'marrow_update_handoff',
|
|
61
|
+
'marrow_update_memory',
|
|
62
|
+
'marrow_value_report',
|
|
63
|
+
'marrow_workflow',
|
|
64
|
+
'marrow_workflow_gate',
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
// A matcher or guard skips only these names on a server named exactly `marrow` (case-sensitive),
|
|
68
|
+
// and only where the host's label or payload proves that server. Any other tool, including an
|
|
69
|
+
// unregistered marrow_* name, a case variant or a padded name, still reaches the hook.
|
|
70
|
+
const MARROW_OWN_SERVER = 'marrow';
|
|
71
|
+
|
|
72
|
+
// The names go into regex sources unescaped, so each must be a plain identifier.
|
|
73
|
+
function checkedNames(names) {
|
|
74
|
+
if (!Array.isArray(names) || names.length === 0) throw new Error('invalid Marrow tool name list');
|
|
75
|
+
for (const name of names) {
|
|
76
|
+
if (typeof name !== 'string' || !/^marrow_[a-z0-9_]+$/.test(name)) throw new Error(`invalid Marrow tool name: ${name}`);
|
|
77
|
+
}
|
|
78
|
+
return names;
|
|
79
|
+
}
|
|
80
|
+
checkedNames(MARROW_OWN_TOOL_NAMES);
|
|
81
|
+
|
|
82
|
+
// One helper builds every host's matcher. Claude Code, Cursor and Gemini test them as JavaScript
|
|
83
|
+
// regexes, unanchored and without the m flag, so `^` and `$` are the start and end of the label.
|
|
84
|
+
// Every consuming part is `[\s\S]*`, so a label padded with a line terminator, NUL or space
|
|
85
|
+
// anywhere still matches, under a search and a full match.
|
|
86
|
+
function buildOwnToolMatchers(names = MARROW_OWN_TOOL_NAMES) {
|
|
87
|
+
const own = `(?:${checkedNames(names).join('|')})`;
|
|
88
|
+
// Shared with @getmarrow/mcp NATIVE_HOOK_MATCHER (byte-identical). Claude Code names an MCP tool
|
|
89
|
+
// `mcp__<server>__<tool>` and maps every other character to `_` without trimming, so the exact
|
|
90
|
+
// label `mcp__marrow__<own>` comes only from server `marrow`: that whole label is skipped, and any
|
|
91
|
+
// other label holding `mcp__` or `functions.` anywhere reaches the hook.
|
|
92
|
+
const mcpTail = `^(?!mcp__${MARROW_OWN_SERVER}__${own}$)[\\s\\S]*(?:functions\\.|mcp__)[\\s\\S]*`;
|
|
93
|
+
// Cursor preToolUse names an MCP tool `MCP:<tool>`, without its server, so no MCP label is
|
|
94
|
+
// skipped; Marrow's own tools are told apart in the hook (beforeMCPExecution carries the server).
|
|
95
|
+
const cursorMcp = '[\\s\\S]*MCP:[\\s\\S]*';
|
|
96
|
+
return {
|
|
97
|
+
claude: `Bash|Edit|Write|MultiEdit|Read|Glob|Grep|Search|WebSearch|Task|${mcpTail}`,
|
|
98
|
+
// Codex keeps its own native tools (apply_patch included) and the shared MCP part.
|
|
99
|
+
codex: `Bash|apply_patch|Edit|Write|MultiEdit|${mcpTail}`,
|
|
100
|
+
cursor: `Shell|Write|Delete|Task|Read|Glob|Grep|Search|WebSearch|List|${cursorMcp}`,
|
|
101
|
+
cursorPreToolUseHostApproval: `Write|Delete|Task|Read|Glob|Grep|Search|WebSearch|List|${cursorMcp}`,
|
|
102
|
+
// Gemini names an MCP tool `mcp_<server>_<tool>`, which other server/tool pairs can also
|
|
103
|
+
// produce, so every `mcp_` label reaches the hook (its payload's mcp_context names the server).
|
|
104
|
+
// Gemini tool names start with a letter: a label that does not (a padded one) reaches it too.
|
|
105
|
+
gemini: '^(?:run_shell_command|write_file|replace|edit_file|delete_file|read_file|read_many_files|glob|grep_search|list_directory|get_file_info|web_search|google_web_search|mcp_[\\s\\S]*)$|^[^A-Za-z_][\\s\\S]*',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Cursor beforeMCPExecution has no matcher: its guard allows at once only when the server is
|
|
110
|
+
// exactly `marrow` and the tool is exactly one of the names (a Set, so no regex and no prototype
|
|
111
|
+
// keys). The source runs inside `node -e '...'`.
|
|
112
|
+
function cursorOwnToolGuardCondition(names = MARROW_OWN_TOOL_NAMES) {
|
|
113
|
+
return `ev.mcp_server_name===${JSON.stringify(MARROW_OWN_SERVER)}&&typeof ev.tool_name==="string"&&new Set(${JSON.stringify(checkedNames(names))}).has(ev.tool_name)`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
MARROW_OWN_TOOL_NAMES,
|
|
118
|
+
MARROW_OWN_SERVER,
|
|
119
|
+
buildOwnToolMatchers,
|
|
120
|
+
cursorOwnToolGuardCondition,
|
|
121
|
+
};
|