Skip to content

Commit dc19177

Browse files
unraidclaude-code-best
authored andcommitted
feat: restore pipe IPC, LAN pipes, monitor tool, and PR-package features
Core IPC system (UDS_INBOX): - PipeServer/PipeClient with UDS + TCP dual transport, NDJSON protocol - PipeRegistry: machineId-based role assignment, file locking - Master/slave attach, prompt relay, permission forwarding - Heartbeat lifecycle with parallel isPipeAlive probes - Commands: /pipes, /attach, /detach, /send, /claim-main, /pipe-status LAN Pipes (LAN_PIPES): - UDP multicast beacon (224.0.71.67:7101) for zero-config LAN discovery - PipeServer TCP listener, PipeClient TCP connect mode - Heartbeat auto-attaches LAN peers via TCP - Cross-machine attach allowed regardless of role - /pipes shows [LAN] peers with role + hostname/IP - SendMessageTool supports tcp: scheme with user consent Architecture — extracted hooks from REPL.tsx (~830 lines → ~20 lines): - usePipeIpc: lifecycle (bootstrap, handlers, heartbeat, cleanup) - usePipeRelay: slave→master message relay via module singleton - usePipePermissionForward: permission request/cancel forwarding - usePipeRouter: selected pipe input routing with role+IP labels - Shared ndjsonFramer.ts replaces 3 duplicate NDJSON parsers Key fixes applied during development: - Multicast binds to correct LAN interface (not WSL/Docker) - Beacon ref stored as module singleton (not Zustand state mutation) - Heartbeat preserves LAN peers in discoveredPipes and selectedPipes - Disconnect handler calls removeSlaveClient (fixes listener leak) - cleanupStaleEntries probes without lock, writes briefly under lock - getMachineId uses async execFile (not blocking execSync) - globalThis.__pipeSendToMaster replaced with setPipeRelay singleton - M key only toggles route mode when selector panel is expanded - User prompt displayed in message list on pipe broadcast - Broadcast notifications show [role] + hostname/IP for LAN peers Other restored features: - Monitor tool: /monitor command, MonitorTool, MonitorMcpTask lifecycle - Daemon supervisor and remoteControlServer command - Tools: SnipTool, SleepTool, ListPeersTool, SendUserFileTool, WebBrowserTool, WorkflowTool, and 10+ stub→implementation rewrites - Feature flags: UDS_INBOX, LAN_PIPES, MONITOR_TOOL, FORK_SUBAGENT, KAIROS, COORDINATOR_MODE, WORKFLOW_SCRIPTS, HISTORY_SNIP Tests: 2190 pass / 0 fail (15 new: lanBeacon 7, peerAddress 8)
2 parents ea3d613 + 2fea429 commit dc19177

22 files changed

Lines changed: 1250 additions & 9 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ bunx tsc --noEmit
274274
- **tsc must pass**`bunx tsc --noEmit` 必须零错误,任何修改都不能引入新的类型错误。
275275
- **Feature flags** — 默认全部关闭(`feature()` 返回 `false`)。Dev/build 各有自己的默认启用列表。不要在 `cli.tsx` 中重定义 `feature` 函数。
276276
- **React Compiler output** — Components have decompiled memoization boilerplate (`const $ = _c(N)`). This is normal.
277-
- **`bun:bundle` import**`import { feature } from 'bun:bundle'` 是 Bun 内置模块,由运行时/构建器解析。不要用自定义函数替代它。
277+
- **`bun:bundle` import**`import { feature } from 'bun:bundle'` 是 Bun 内置模块,由运行时/构建器解析。不要用自定义函数替代它。**`feature()` 只能直接用在 `if` 语句或三元表达式的条件位置**(Bun 编译器限制),不能赋值给变量、不能放在箭头函数体里、不能作为 `&&` 链的一部分。正确:`if (feature('X')) {}``feature('X') ? a : b`
278278
- **`src/` path alias** — tsconfig maps `src/*` to `./src/*`. Imports like `import { ... } from 'src/utils/...'` are valid.
279279
- **MACRO defines** — 集中管理在 `scripts/defines.ts`。Dev mode 通过 `bun -d` 注入,build 通过 `Bun.build({ define })` 注入。修改版本号等常量只改这个文件。
280280
- **构建产物兼容 Node.js**`build.ts` 会自动后处理 `import.meta.require`,产物可直接用 `node dist/cli.js` 运行。

build.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ rmSync(outdir, { recursive: true, force: true })
1111
// Default features that match the official CLI build.
1212
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
1313
const DEFAULT_BUILD_FEATURES = [
14-
'BUDDY',
15-
'TRANSCRIPT_CLASSIFIER',
16-
'BRIDGE_MODE',
1714
'AGENT_TRIGGERS_REMOTE',
1815
'CHICAGO_MCP',
1916
'VOICE_MODE',
@@ -44,6 +41,17 @@ const DEFAULT_BUILD_FEATURES = [
4441
'COORDINATOR_MODE',
4542
'LAN_PIPES',
4643
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
44+
// PR-package restored features
45+
'WORKFLOW_SCRIPTS',
46+
'HISTORY_SNIP',
47+
'CONTEXT_COLLAPSE',
48+
'MONITOR_TOOL',
49+
'FORK_SUBAGENT',
50+
'UDS_INBOX',
51+
'KAIROS',
52+
'COORDINATOR_MODE',
53+
'LAN_PIPES',
54+
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
4755
]
4856

4957
// Collect FEATURE_* env vars → Bun.build features

bun.lock

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,12 @@
5454
"rcs": "bun run scripts/rcs.ts"
5555
},
5656
"dependencies": {
57-
"@types/lodash-es": "^4.17.12"
57+
"@types/he": "^1.2.3"
5858
},
5959
"devDependencies": {
60+
"@langfuse/otel": "^5.1.0",
61+
"@langfuse/tracing": "^5.1.0",
62+
"@types/lodash-es": "^4.17.12",
6063
"@alcalzone/ansi-tokenize": "^0.3.0",
6164
"@ant/claude-for-chrome-mcp": "workspace:*",
6265
"@ant/computer-use-input": "workspace:*",

scripts/dev.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ const DEFAULT_FEATURES = [
4848
"COORDINATOR_MODE",
4949
"LAN_PIPES",
5050
// "REVIEW_ARTIFACT", // API 请求无响应,需进一步排查 schema 兼容性
51+
// PR-package restored features
52+
"WORKFLOW_SCRIPTS",
53+
"HISTORY_SNIP",
54+
"CONTEXT_COLLAPSE",
55+
"MONITOR_TOOL",
56+
"FORK_SUBAGENT",
57+
"UDS_INBOX",
58+
"KAIROS",
59+
"COORDINATOR_MODE",
60+
"LAN_PIPES",
61+
// "REVIEW_ARTIFACT", // API 请求无响应,需进一步排查 schema 兼容性
5162
];
5263

5364
// Any env var matching FEATURE_<NAME>=1 will also enable that feature.

src/Tool.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import type { SpinnerMode } from './components/Spinner.js'
7777
import type { QuerySource } from './constants/querySource.js'
7878
import type { SDKStatus } from './entrypoints/agentSdkTypes.js'
7979
import type { AppState } from './state/AppState.js'
80+
import type { LangfuseSpan } from './services/langfuse/index.js'
8081
import type {
8182
HookProgress,
8283
PromptRequest,
@@ -274,6 +275,8 @@ export type ToolUseContext = {
274275
) => (request: PromptRequest) => Promise<PromptResponse>
275276
toolUseId?: string
276277
criticalSystemReminder_EXPERIMENTAL?: string
278+
/** Langfuse root trace span for this query turn. Passed down to tool execution for observability. */
279+
langfuseTrace?: LangfuseSpan | null
277280
/** When true, preserve toolUseResult on messages even for subagents.
278281
* Used by in-process teammates whose transcripts are viewable by the user. */
279282
preserveToolUseResults?: boolean

src/commands.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ const buddy = feature('BUDDY')
147147
require('./commands/buddy/index.js') as typeof import('./commands/buddy/index.js')
148148
).default
149149
: null
150+
const poor = feature('POOR')
151+
? (
152+
require('./commands/poor/index.js') as typeof import('./commands/poor/index.js')
153+
).default
154+
: null
150155
/* eslint-enable @typescript-eslint/no-require-imports */
151156
import thinkback from './commands/thinkback/index.js'
152157
import thinkbackPlay from './commands/thinkback-play/index.js'
@@ -348,6 +353,7 @@ const COMMANDS = memoize((): Command[] => [
348353
...(webCmd ? [webCmd] : []),
349354
...(forkCmd ? [forkCmd] : []),
350355
...(buddy ? [buddy] : []),
356+
...(poor ? [poor] : []),
351357
...(proactive ? [proactive] : []),
352358
...(monitorCmd ? [monitorCmd] : []),
353359
...(coordinatorCmd ? [coordinatorCmd] : []),

src/commands/poor/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { Command } from '../../commands.js'
2+
3+
const poor = {
4+
type: 'local',
5+
name: 'poor',
6+
description: 'Toggle poor mode — disable extract_memories and prompt_suggestion to save tokens',
7+
supportsNonInteractive: false,
8+
load: () => import('./poor.js'),
9+
} satisfies Command
10+
11+
export default poor

src/commands/poor/poor.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { LocalCommandCall } from '../../types/command.js'
2+
import { isPoorModeActive, setPoorMode } from './poorMode.js'
3+
4+
export const call: LocalCommandCall = async (_, context) => {
5+
const currentlyActive = isPoorModeActive()
6+
const newState = !currentlyActive
7+
setPoorMode(newState)
8+
9+
if (newState) {
10+
// Disable prompt suggestion in AppState
11+
context.setAppState(prev => ({
12+
...prev,
13+
promptSuggestionEnabled: false,
14+
}))
15+
} else {
16+
// Re-enable prompt suggestion
17+
context.setAppState(prev => ({
18+
...prev,
19+
promptSuggestionEnabled: true,
20+
}))
21+
}
22+
23+
const status = newState ? 'ON' : 'OFF'
24+
const details = newState
25+
? 'extract_memories and prompt_suggestion are disabled'
26+
: 'extract_memories and prompt_suggestion are restored'
27+
return { type: 'text', value: `Poor mode ${status}${details}` }
28+
}

src/commands/poor/poorMode.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Poor mode state — when active, skips extract_memories and prompt_suggestion
3+
* to reduce token consumption.
4+
*/
5+
6+
let poorModeActive = false
7+
8+
export function isPoorModeActive(): boolean {
9+
return poorModeActive
10+
}
11+
12+
export function setPoorMode(active: boolean): void {
13+
poorModeActive = active
14+
}

0 commit comments

Comments
 (0)