metame-cli 1.5.21 → 1.5.23

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 CHANGED
@@ -614,12 +614,13 @@ Level mapping:
614
614
 
615
615
  ## Hook Optimizations (Default On)
616
616
 
617
- MetaMe installs and maintains core Claude hooks automatically on launch:
617
+ MetaMe keeps Claude hooks minimal and non-essential:
618
618
 
619
- - `UserPromptSubmit` hook (`scripts/hooks/intent-engine.js`): Unified intent engine for team dispatch, ops assist, and task creation hints.
620
619
  - `UserPromptSubmit` hook (`scripts/signal-capture.js`): captures high-signal preference/task traces with layered filtering.
621
620
  - `Stop` hook (`scripts/hooks/stop-session-capture.js`): records session-end/tool-failure signals with watermark protection.
622
621
 
622
+ Semantic intent recognition and prompt hint injection now run only inside the daemon runtime, so Claude and Codex share the same injection path.
623
+
623
624
  If hook installation fails, MetaMe logs and continues the session (non-blocking fallback).
624
625
 
625
626
  ## How It Works
package/index.js CHANGED
@@ -540,11 +540,28 @@ if (syntaxErrors.length > 0) {
540
540
  const changed = syncDirFiles(group.srcDir, destDir, { fileList: group.fileList });
541
541
  return updated || changed;
542
542
  }, false);
543
- if (scriptsUpdated) {
543
+ if (scriptsUpdated) {
544
544
  console.log(`${icon("pkg")} Scripts synced to ~/.metame/.`);
545
545
  }
546
546
  }
547
547
 
548
+ try {
549
+ const runtimeEnvFile = path.join(METAME_DIR, 'runtime-env.json');
550
+ const runtimeNodeModules = path.join(__dirname, 'node_modules');
551
+ const runtimeEnvPayload = {
552
+ metameRoot: __dirname,
553
+ nodeModules: runtimeNodeModules,
554
+ generatedAt: new Date().toISOString(),
555
+ };
556
+ const nextContent = JSON.stringify(runtimeEnvPayload, null, 2) + '\n';
557
+ const prevContent = fs.existsSync(runtimeEnvFile) ? fs.readFileSync(runtimeEnvFile, 'utf8') : '';
558
+ if (prevContent !== nextContent) {
559
+ fs.writeFileSync(runtimeEnvFile, nextContent, 'utf8');
560
+ }
561
+ } catch (e) {
562
+ console.log(`${icon("warn")} Runtime env sync skipped: ${e.message}`);
563
+ }
564
+
548
565
  // Docs: lazy-load references for CLAUDE.md pointer instructions
549
566
  syncDirFiles(path.join(__dirname, 'scripts', 'docs'), path.join(METAME_DIR, 'docs'));
550
567
  // Bin: CLI tools (dispatch_to etc.)
@@ -756,12 +773,17 @@ function ensureHookInstalled() {
756
773
  console.log(`${icon("hook")} MetaMe: Stop session capture hook installed.`);
757
774
  }
758
775
 
759
- // Migrate: remove standalone team-context.js hook (superseded by intent-engine)
776
+ // Migrate: remove obsolete semantic injection hooks.
777
+ // Intent routing now happens only inside the daemon runtime so Claude/Codex
778
+ // share one platform-agnostic path.
760
779
  if (settings.hooks?.UserPromptSubmit) {
761
780
  const before = settings.hooks.UserPromptSubmit.length;
762
781
  for (const entry of settings.hooks.UserPromptSubmit) {
763
782
  if (entry.hooks) {
764
- entry.hooks = entry.hooks.filter(h => !(h.command && h.command.includes('team-context.js')));
783
+ entry.hooks = entry.hooks.filter((h) => {
784
+ const cmd = h && h.command ? String(h.command) : '';
785
+ return !(cmd.includes('team-context.js') || cmd.includes('intent-engine.js'));
786
+ });
765
787
  }
766
788
  }
767
789
  settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit.filter(
@@ -770,27 +792,6 @@ function ensureHookInstalled() {
770
792
  if (settings.hooks.UserPromptSubmit.length !== before) modified = true;
771
793
  }
772
794
 
773
- // Ensure intent-engine hook (unified intent detection + hint injection)
774
- const intentEngineScript = path.join(METAME_DIR, 'hooks', 'intent-engine.js').replace(/\\/g, '/');
775
- const intentEngineCommand = `node "${intentEngineScript}"`;
776
- const intentEngineInstalled = (settings.hooks?.UserPromptSubmit || []).some(entry =>
777
- entry.hooks?.some(h => h.command && h.command.includes('intent-engine.js'))
778
- );
779
-
780
- if (!intentEngineInstalled) {
781
- if (!settings.hooks) settings.hooks = {};
782
- if (!settings.hooks.UserPromptSubmit) settings.hooks.UserPromptSubmit = [];
783
-
784
- settings.hooks.UserPromptSubmit.push({
785
- hooks: [{
786
- type: 'command',
787
- command: intentEngineCommand,
788
- }]
789
- });
790
- modified = true;
791
- console.log(`${icon("hook")} MetaMe: Intent engine hook installed.`);
792
- }
793
-
794
795
  if (modified) {
795
796
  fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2), 'utf8');
796
797
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metame-cli",
3
- "version": "1.5.21",
3
+ "version": "1.5.23",
4
4
  "description": "The Cognitive Profile Layer for Claude Code. Knows how you think, not just what you said.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,111 @@
1
+ 'use strict';
2
+
3
+ function extractPathFromText(input) {
4
+ const text = String(input || '');
5
+ const unixMatch = text.match(/(?:~\/|\/|\.\/|\.\.\/)[^\s,。;;!!??"“”'‘’`]+/);
6
+ if (unixMatch) return unixMatch[0].replace(/[,。;;!!??]+$/, '');
7
+
8
+ const windowsMatch = text.match(/[A-Za-z]:[\\/][^\s,。;;!!??"“”'‘’`]+/);
9
+ if (windowsMatch) return windowsMatch[0].replace(/[,。;;!!??]+$/, '');
10
+
11
+ return '';
12
+ }
13
+
14
+ function detectCloneIntent(text) {
15
+ if (!text || text.startsWith('/') || text.length < 3) return false;
16
+ const cloneKeywords = ['分身', '再造', '克隆', '副本', '另一个自己', '另一个我'];
17
+ const hasCloneKeyword = cloneKeywords.some(k => text.includes(k));
18
+ if (hasCloneKeyword) {
19
+ const excludePatterns = [/已经/, /存在/, /有了/, /好了/, /完成/, /搞定/, /配置好/, /怎么建/, /如何建/, /方法/, /步骤/];
20
+ if (excludePatterns.some(p => p.test(text))) return false;
21
+ return true;
22
+ }
23
+ const actionKeywords = ['新建', '创建', '造', '做一个', '加一个', '增加', '添加'];
24
+ const hasAction = actionKeywords.some(k => text.includes(k));
25
+ if (hasAction && /分身|数字/.test(text)) return true;
26
+ if (/让.*做分身|叫.*做分身|甲.*做分身/.test(text)) return true;
27
+ return false;
28
+ }
29
+
30
+ function detectTeamIntent(text) {
31
+ if (!text || text.startsWith('/') || text.length < 4) return false;
32
+ if (/走team|用team|通过team|team里|team中|团队里|团队中|走团队|用团队|在team|在团队|team.*已经|团队.*已经|team.*讨论|团队.*讨论/.test(text)) return false;
33
+ if ((text.includes('团队') || text.includes('工作组'))) {
34
+ if (/(新建|创建|造一个|加一个|组建|设置|建|搞)/.test(text)) {
35
+ if (/怎么|如何|方法|步骤/.test(text)) return false;
36
+ return true;
37
+ }
38
+ }
39
+ if (/^(新建|创建|建|搞).*团队/.test(text)) return true;
40
+ return false;
41
+ }
42
+
43
+ function isLikelyDirectAgentAction(input) {
44
+ const text = String(input || '').trim();
45
+ return /^(?:请|帮我|麻烦|给我|给这个群|给当前群|在这个群|把这个群|把当前群|将这个群|这个群|当前群|本群|群里|我想|我要|我需要|创建|新建|新增|搞一个|加一个|create|bind|绑定|列出|查看|显示|有哪些|解绑|取消绑定|断开绑定|修改|调整)/i.test(text);
46
+ }
47
+
48
+ function looksLikeAgentIssueReport(input) {
49
+ const text = String(input || '').trim();
50
+ const hasIssueWords = /(用户反馈|反馈|报错|bug|问题|故障|异常|修复|改一下|修一下|任务|工单|代码)/i.test(text);
51
+ const hasAgentWords = /(agent|智能体|session|会话|目录|工作区|绑定|切换)/i.test(text);
52
+ return hasIssueWords && hasAgentWords;
53
+ }
54
+
55
+ function classifyAgentIntent(input) {
56
+ const text = String(input || '').trim();
57
+ if (!text || text.startsWith('/')) return null;
58
+
59
+ const workspaceDir = extractPathFromText(text);
60
+ const hasWorkspacePath = !!workspaceDir;
61
+ const directAction = isLikelyDirectAgentAction(text);
62
+ const issueReport = looksLikeAgentIssueReport(text);
63
+ if (issueReport && !directAction) return null;
64
+
65
+ const hasThirdPartyName = /(阿里|百度|腾讯|字节|谷歌|google|openai|微软|microsoft|deepseek|豆包|通义|文心|kimi)/i.test(text);
66
+ const hasAgentWord = /(智能体|agent|助手|机器人)/i.test(text);
67
+ const isAboutOurAgents = /(我的|我们的|当前|这个群|这里的|metame)/i.test(text);
68
+ if (hasThirdPartyName && hasAgentWord && !isAboutOurAgents) return null;
69
+
70
+ const hasAgentContext = /(agent|智能体|工作区|人设|绑定|当前群|这个群|chat|workspace)/i.test(text);
71
+ const wantsList = /(列出|查看|显示|有哪些|list|show)/i.test(text) && /(agent|智能体|工作区|绑定)/i.test(text);
72
+ const wantsUnbind = /(解绑|取消绑定|断开绑定|unbind|unassign)/i.test(text) && hasAgentContext;
73
+ const wantsEditRole =
74
+ ((/(角色|职责|人设)/i.test(text) && /(改|修改|调整|更新|变成|改成|改为)/i.test(text)) ||
75
+ /(把这个agent|把当前agent|当前群.*角色|当前群.*职责)/i.test(text));
76
+ const wantsCreate =
77
+ (/(创建|新建|新增|搞一个|加一个|create)/i.test(text) && /(agent|智能体|人设|工作区)/i.test(text) && (directAction || hasWorkspacePath));
78
+ const wantsBind =
79
+ !wantsCreate &&
80
+ (/(绑定|bind)/i.test(text) && hasAgentContext && (directAction || hasWorkspacePath));
81
+ const wantsActivate = /(?:在新群|新群里|新群中|目标群|另一个群).{0,12}(激活|activate)|(?:激活|activate).{0,12}(agent|智能体|绑定)|\/activate/i.test(text);
82
+ const wantsReset =
83
+ /(重置|清空|删除).{0,24}(agent|智能体|助手|角色|职责|人设).{0,12}(角色|职责|人设)?/i.test(text) ||
84
+ /(?:角色|职责|人设).{0,12}(重置|清空|删除)/i.test(text) ||
85
+ /\/agent reset/i.test(text);
86
+ const wantsSoul = /(soul|灵魂|身份设定|人格设定)/i.test(text) && /(查看|修复|编辑|修改|更新|repair|edit|show|看)/i.test(text);
87
+ const wantsAgentDoc =
88
+ /(?:agent|智能体|机器人|bot).{0,12}(文档|手册|说明|guide)/i.test(text) ||
89
+ /(?:怎么|如何|手册|文档|说明).{0,12}(配置|管理|使用).{0,12}(agent|智能体|机器人|bot)/i.test(text) ||
90
+ /(?:agent|智能体|机器人|bot).{0,12}(怎么|如何).{0,12}(配置|管理|使用)/i.test(text);
91
+
92
+ if (wantsList) return { action: 'list', workspaceDir };
93
+ if (wantsUnbind) return { action: 'unbind', workspaceDir };
94
+ if (wantsEditRole) return { action: 'edit_role', workspaceDir };
95
+ if (wantsCreate) return { action: 'create', workspaceDir };
96
+ if (wantsBind) return { action: 'bind', workspaceDir };
97
+ if (wantsAgentDoc) return { action: 'agent_doc', workspaceDir };
98
+ if (wantsActivate) return { action: 'activate', workspaceDir };
99
+ if (wantsReset) return { action: 'reset', workspaceDir };
100
+ if (wantsSoul) return { action: 'soul', workspaceDir };
101
+ if (detectCloneIntent(text)) return { action: 'wizard_clone', workspaceDir };
102
+ if (detectTeamIntent(text)) return { action: 'wizard_team', workspaceDir };
103
+ return null;
104
+ }
105
+
106
+ module.exports = {
107
+ classifyAgentIntent,
108
+ detectCloneIntent,
109
+ detectTeamIntent,
110
+ extractPathFromText,
111
+ };