mumucc 0.1.8 → 0.2.0
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/.gitignore.bak +11 -0
- package/package.json +1 -1
- package/shims/bun-bundle.ts +3 -0
- package/shims/globals.ts +1 -1
- package/src/cli/print.ts +1 -3
- package/src/components/LogoV2/ChannelsNotice.tsx +3 -3
- package/src/interactiveHelpers.tsx +1 -1
- package/src/main.tsx +3 -1
- package/src/services/mcp/channelAllowlist.ts +1 -1
- package/src/services/mcp/channelNotification.ts +4 -90
- package/src/services/mcp/channelPermissions.ts +1 -1
- package/src/utils/env.ts +4 -1
package/.gitignore.bak
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mumucc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Open-source AI coding assistant CLI with multi-model support (Anthropic, OpenAI/GPT, DeepSeek, GLM, Ollama, etc.), MCP integration, agent swarms, and out-of-the-box developer experience.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/shims/bun-bundle.ts
CHANGED
|
@@ -28,6 +28,9 @@ const DEFAULT_ENABLED: Set<string> = new Set([
|
|
|
28
28
|
'HOOK_PROMPTS',
|
|
29
29
|
'DOWNLOAD_USER_SETTINGS',
|
|
30
30
|
'UPLOAD_USER_SETTINGS',
|
|
31
|
+
'KAIROS', // mumucc: 启用 channels/proactive 功能
|
|
32
|
+
'KAIROS_CHANNELS', // mumucc: 启用 channels 支持
|
|
33
|
+
'PROACTIVE', // mumucc: 启用 proactive 功能
|
|
31
34
|
])
|
|
32
35
|
|
|
33
36
|
// Parse env override
|
package/shims/globals.ts
CHANGED
package/src/cli/print.ts
CHANGED
|
@@ -4671,9 +4671,7 @@ function handleChannelEnable(
|
|
|
4671
4671
|
response: { subtype: 'error', request_id: requestId, error },
|
|
4672
4672
|
})
|
|
4673
4673
|
|
|
4674
|
-
|
|
4675
|
-
return respondError('channels feature not available in this build')
|
|
4676
|
-
}
|
|
4674
|
+
// mumucc: channels 已强制启用,不再检查 feature flag
|
|
4677
4675
|
|
|
4678
4676
|
// Only a 'connected' client has .capabilities and .client to register the
|
|
4679
4677
|
// handler on. The pool spread at the call site matches mcp_status.
|
|
@@ -43,7 +43,7 @@ export function ChannelsNotice() {
|
|
|
43
43
|
}
|
|
44
44
|
let t2;
|
|
45
45
|
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
|
46
|
-
t2 = <Text dimColor={true}>Channels
|
|
46
|
+
t2 = <Text dimColor={true}>Channels 初始化中...</Text>; // mumucc: 友好提示
|
|
47
47
|
$[3] = t2;
|
|
48
48
|
} else {
|
|
49
49
|
t2 = $[3];
|
|
@@ -70,7 +70,7 @@ export function ChannelsNotice() {
|
|
|
70
70
|
}
|
|
71
71
|
let t2;
|
|
72
72
|
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
|
|
73
|
-
t2 = <Text dimColor={true}>Channels
|
|
73
|
+
t2 = <Text dimColor={true}>Channels 可通过 API key 或 OAuth 使用</Text>; // mumucc: 移除 OAuth 强制要求
|
|
74
74
|
$[9] = t2;
|
|
75
75
|
} else {
|
|
76
76
|
t2 = $[9];
|
|
@@ -99,7 +99,7 @@ export function ChannelsNotice() {
|
|
|
99
99
|
let t3;
|
|
100
100
|
if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
|
|
101
101
|
t2 = <Text dimColor={true}>Inbound messages will be silently dropped</Text>;
|
|
102
|
-
t3 = <Text dimColor={true}>
|
|
102
|
+
t3 = <Text dimColor={true}>Channels 已启用 (mumucc)</Text>; // mumucc: 去掉管理员设置提示
|
|
103
103
|
$[15] = t2;
|
|
104
104
|
$[16] = t3;
|
|
105
105
|
} else {
|
|
@@ -263,7 +263,7 @@ export async function showSetupScreens(root: Root, permissionMode: PermissionMod
|
|
|
263
263
|
// named. dev:true here is for the flag label in ChannelsNotice
|
|
264
264
|
// (hasNonDev check); the allowlist bypass it also grants is moot
|
|
265
265
|
// since the gate blocks upstream.
|
|
266
|
-
if (
|
|
266
|
+
if (false) { // mumucc: 跳过 channels 禁用检查,直接显示确认对话框
|
|
267
267
|
setAllowedChannels([...getAllowedChannels(), ...devChannels.map(c => ({
|
|
268
268
|
...c,
|
|
269
269
|
dev: true
|
package/src/main.tsx
CHANGED
|
@@ -1681,9 +1681,10 @@ async function run(): Promise<CommanderCommand> {
|
|
|
1681
1681
|
const channelOpts = options as {
|
|
1682
1682
|
channels?: string[];
|
|
1683
1683
|
dangerouslyLoadDevelopmentChannels?: string[];
|
|
1684
|
+
channelsDev?: string[]; // mumucc: 短别名
|
|
1684
1685
|
};
|
|
1685
1686
|
const rawChannels = channelOpts.channels;
|
|
1686
|
-
const rawDev = channelOpts.dangerouslyLoadDevelopmentChannels;
|
|
1687
|
+
const rawDev = channelOpts.dangerouslyLoadDevelopmentChannels ?? channelOpts.channelsDev; // mumucc: 支持短别名
|
|
1687
1688
|
// Always parse + set. ChannelsNotice reads getAllowedChannels() and
|
|
1688
1689
|
// renders the appropriate branch (disabled/noAuth/policyBlocked/
|
|
1689
1690
|
// listening) in the startup screen. gateChannelServer() enforces.
|
|
@@ -3844,6 +3845,7 @@ async function run(): Promise<CommanderCommand> {
|
|
|
3844
3845
|
if (feature('KAIROS') || feature('KAIROS_CHANNELS')) {
|
|
3845
3846
|
program.addOption(new Option('--channels <servers...>', 'MCP servers whose channel notifications (inbound push) should register this session. Space-separated server names.').hideHelp());
|
|
3846
3847
|
program.addOption(new Option('--dangerously-load-development-channels <servers...>', 'Load channel servers not on the approved allowlist. For local channel development only. Shows a confirmation dialog at startup.').hideHelp());
|
|
3848
|
+
program.addOption(new Option('--channels-dev <servers...>', 'mumucc: --dangerously-load-development-channels 的短别名').hideHelp()); // mumucc: 短别名
|
|
3847
3849
|
}
|
|
3848
3850
|
|
|
3849
3851
|
// Teammate identity options (set by leader when spawning tmux teammates)
|
|
@@ -49,7 +49,7 @@ export function getChannelAllowlist(): ChannelAllowlistEntry[] {
|
|
|
49
49
|
* Default false; GrowthBook 5-min refresh.
|
|
50
50
|
*/
|
|
51
51
|
export function isChannelsEnabled(): boolean {
|
|
52
|
-
return
|
|
52
|
+
return true // mumucc: 强制启用 channels
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -205,44 +205,11 @@ export function gateChannelServer(
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
// session state.
|
|
211
|
-
if (!isChannelsEnabled()) {
|
|
212
|
-
return {
|
|
213
|
-
action: 'skip',
|
|
214
|
-
kind: 'disabled',
|
|
215
|
-
reason: 'channels feature is not currently available',
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// OAuth-only. API key users (console) are blocked — there's no
|
|
220
|
-
// channelsEnabled admin surface in console yet, so the policy opt-in
|
|
221
|
-
// flow doesn't exist for them. Drop this when console parity lands.
|
|
222
|
-
if (!getClaudeAIOAuthTokens()?.accessToken) {
|
|
223
|
-
return {
|
|
224
|
-
action: 'skip',
|
|
225
|
-
kind: 'auth',
|
|
226
|
-
reason: 'channels requires claude.ai authentication (run /login)',
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Teams/Enterprise opt-in. Managed orgs must explicitly enable channels.
|
|
231
|
-
// Default OFF — absent or false blocks. Keyed off subscription tier, not
|
|
232
|
-
// "policy settings exist" — a team org with zero configured policy keys
|
|
233
|
-
// (remote endpoint returns 404) is still a managed org and must not fall
|
|
234
|
-
// through to the unmanaged path.
|
|
208
|
+
// mumucc: 跳过 runtime gate、OAuth 检查和 Team/Enterprise 策略检查
|
|
209
|
+
// 让 API key 模式和所有用户都能使用 channels
|
|
235
210
|
const sub = getSubscriptionType()
|
|
236
211
|
const managed = sub === 'team' || sub === 'enterprise'
|
|
237
212
|
const policy = managed ? getSettingsForSource('policySettings') : undefined
|
|
238
|
-
if (managed && policy?.channelsEnabled !== true) {
|
|
239
|
-
return {
|
|
240
|
-
action: 'skip',
|
|
241
|
-
kind: 'policy',
|
|
242
|
-
reason:
|
|
243
|
-
'channels not enabled by org policy (set channelsEnabled: true in managed settings)',
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
213
|
|
|
247
214
|
// User-level session opt-in. A server must be explicitly listed in
|
|
248
215
|
// --channels to push inbound this session — protects against a trusted
|
|
@@ -256,61 +223,8 @@ export function gateChannelServer(
|
|
|
256
223
|
}
|
|
257
224
|
}
|
|
258
225
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// the runtime name is just plugin:slack:X — could be slack@anthropic or
|
|
262
|
-
// slack@evil depending on what's installed. Verify they match before
|
|
263
|
-
// trusting the tag for the allowlist check below. Source is stashed on
|
|
264
|
-
// the config at addPluginScopeToServers — undefined (non-plugin server,
|
|
265
|
-
// shouldn't happen for plugin-kind entry) or @-less (builtin/inline)
|
|
266
|
-
// both fail the comparison.
|
|
267
|
-
const actual = pluginSource
|
|
268
|
-
? parsePluginIdentifier(pluginSource).marketplace
|
|
269
|
-
: undefined
|
|
270
|
-
if (actual !== entry.marketplace) {
|
|
271
|
-
return {
|
|
272
|
-
action: 'skip',
|
|
273
|
-
kind: 'marketplace',
|
|
274
|
-
reason: `you asked for plugin:${entry.name}@${entry.marketplace} but the installed ${entry.name} plugin is from ${actual ?? 'an unknown source'}`,
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Approved-plugin allowlist. Marketplace gate already verified
|
|
279
|
-
// tag == reality, so this is a pure entry check. entry.dev (per-entry,
|
|
280
|
-
// not the session-wide bit) bypasses — so accepting the dev dialog for
|
|
281
|
-
// one entry doesn't leak allowlist-bypass to --channels entries.
|
|
282
|
-
if (!entry.dev) {
|
|
283
|
-
const { entries, source } = getEffectiveChannelAllowlist(
|
|
284
|
-
sub,
|
|
285
|
-
policy?.allowedChannelPlugins,
|
|
286
|
-
)
|
|
287
|
-
if (
|
|
288
|
-
!entries.some(
|
|
289
|
-
e => e.plugin === entry.name && e.marketplace === entry.marketplace,
|
|
290
|
-
)
|
|
291
|
-
) {
|
|
292
|
-
return {
|
|
293
|
-
action: 'skip',
|
|
294
|
-
kind: 'allowlist',
|
|
295
|
-
reason:
|
|
296
|
-
source === 'org'
|
|
297
|
-
? `plugin ${entry.name}@${entry.marketplace} is not on your org's approved channels list (set allowedChannelPlugins in managed settings)`
|
|
298
|
-
: `plugin ${entry.name}@${entry.marketplace} is not on the approved channels allowlist (use --dangerously-load-development-channels for local dev)`,
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
} else {
|
|
303
|
-
// server-kind: allowlist schema is {marketplace, plugin} — a server entry
|
|
304
|
-
// can never match. Without this, --channels server:plugin:foo:bar would
|
|
305
|
-
// match a plugin's runtime name and register with no allowlist check.
|
|
306
|
-
if (!entry.dev) {
|
|
307
|
-
return {
|
|
308
|
-
action: 'skip',
|
|
309
|
-
kind: 'allowlist',
|
|
310
|
-
reason: `server ${entry.name} is not on the approved channels allowlist (use --dangerously-load-development-channels for local dev)`,
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
226
|
+
// mumucc: 跳过 marketplace 验证和 allowlist 检查,允许所有 channel 服务器注册
|
|
227
|
+
// 原始代码在此处检查 plugin marketplace 匹配和 allowlist,对于自建 fork 不需要
|
|
314
228
|
|
|
315
229
|
return { action: 'register' }
|
|
316
230
|
}
|
|
@@ -34,7 +34,7 @@ import { getFeatureValue_CACHED_MAY_BE_STALE } from '../analytics/growthbook.js'
|
|
|
34
34
|
* don't apply until restart.
|
|
35
35
|
*/
|
|
36
36
|
export function isChannelPermissionRelayEnabled(): boolean {
|
|
37
|
-
return
|
|
37
|
+
return true // mumucc: 强制启用 channel permission relay
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export type ChannelPermissionResponse = {
|
package/src/utils/env.ts
CHANGED
|
@@ -22,7 +22,10 @@ export const getGlobalClaudeFile = memoize((): string => {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const filename = `.mumucc${fileSuffixForOauthConfig()}.json`
|
|
25
|
-
|
|
25
|
+
// Always keep global config inside the mumucc config dir (~/.mumucc/.mumucc.json)
|
|
26
|
+
// to avoid polluting HOME root and to prevent any overlap with standard Claude Code
|
|
27
|
+
// config (~/.claude.json). CLAUDE_CONFIG_DIR override is still respected.
|
|
28
|
+
return join(process.env.CLAUDE_CONFIG_DIR || getClaudeConfigHomeDir(), filename)
|
|
26
29
|
})
|
|
27
30
|
|
|
28
31
|
const hasInternetAccess = memoize(async (): Promise<boolean> => {
|