very-happy-cli 0.2.126 → 0.2.128
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/{AcpBackend-C9eu6CDu.cjs → AcpBackend-BYU6J2n0.cjs} +2 -2
- package/dist/{AcpBackend-BzGpBAZ0.mjs → AcpBackend-D7987ody.mjs} +2 -2
- package/dist/{AcpSessionManager-B223yT78.mjs → AcpSessionManager-BwrjVZyn.mjs} +1 -1
- package/dist/{AcpSessionManager-DQ1e_0gc.cjs → AcpSessionManager-artXJgqb.cjs} +1 -1
- package/dist/{agentGuidance-Tm8Z5HYp.cjs → agentGuidance-B1xYgHx6.cjs} +63 -33
- package/dist/{agentGuidance-BR0OFumQ.mjs → agentGuidance-BPGPaNlo.mjs} +62 -35
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-Bjd1nG0P.mjs → config-DSBE0Az0.mjs} +4 -4
- package/dist/{config-C0mofvCH.cjs → config-Dmkzs3o4.cjs} +4 -4
- package/dist/{index-BP56asuS.mjs → index-35FahgEU.mjs} +4 -4
- package/dist/{index-HW-KdG6W.cjs → index-CJmXLSQc.cjs} +4 -4
- package/dist/{index-D4eCRu9x.mjs → index-CfM6ewd8.mjs} +249 -27
- package/dist/{index-Cw9Zj1Zr.cjs → index-D_YVlpsW.cjs} +254 -30
- package/dist/{index-CV6sAa4a.mjs → index-m0Dnccc_.mjs} +13 -9
- package/dist/{index-CMbKpntk.cjs → index-vyTJsT_R.cjs} +13 -9
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{installTerminalHooks-CNp1LExn.cjs → installTerminalHooks-C1zwiJJ2.cjs} +4 -4
- package/dist/{installTerminalHooks-D-CNSalI.mjs → installTerminalHooks-ClrFe2fA.mjs} +4 -4
- package/dist/lib.cjs +2 -2
- package/dist/lib.d.cts +1 -0
- package/dist/lib.d.mts +1 -0
- package/dist/lib.mjs +2 -2
- package/dist/{limits-DlbYYtOw.mjs → limits-BNTLh2lw.mjs} +9 -9
- package/dist/{limits-DG1OQnCb.cjs → limits-CrwtFbi8.cjs} +7 -7
- package/dist/{mcp-BtZoIIIM.cjs → mcp-Bc_mmJt8.cjs} +4 -4
- package/dist/{mcp-D3oV_dH-.mjs → mcp-BsohER5A.mjs} +4 -4
- package/dist/{runGemini-BfCSOPL1.cjs → runGemini-B2GesRWm.cjs} +6 -6
- package/dist/{runGemini-BJ8bU1pP.mjs → runGemini-B9S85Vms.mjs} +6 -6
- package/dist/{runOpenClaw-DTgOpJnO.mjs → runOpenClaw-Byhq-B1y.mjs} +5 -5
- package/dist/{runOpenClaw-CBlHXEAT.cjs → runOpenClaw-DCK-R8qe.cjs} +5 -5
- package/dist/{send-CDK1bZFj.cjs → send-CPdT1nOg.cjs} +4 -4
- package/dist/{send-9duZlpGX.mjs → send-DQS1zNWp.mjs} +4 -4
- package/dist/{sessions-CNkLCorF.cjs → sessions-DC0IKaD9.cjs} +4 -4
- package/dist/{sessions-jAFOkKvW.mjs → sessions-DIOdWnPe.mjs} +4 -4
- package/dist/{spawn-BG5oHi_f.mjs → spawn-DV4pIAHZ.mjs} +4 -4
- package/dist/{spawn-J-A5WGZ7.cjs → spawn-DrnCW2QK.cjs} +4 -4
- package/dist/{teams-MgWeyutG.cjs → teams-CwXEJs9I.cjs} +41 -6
- package/dist/{teams-Cuqsk7Ty.mjs → teams-DlTHOiCk.mjs} +38 -3
- package/dist/todo-BwXURAbQ.mjs +128 -0
- package/dist/todo-DrME15xq.cjs +132 -0
- package/dist/{types-n_VWu9qe.mjs → types-CFs8FmiY.mjs} +318 -6
- package/dist/{types-P5deH8Ls.cjs → types-DfatCoQL.cjs} +327 -12
- package/package.json +7 -7
- package/dist/resources-CVl7NdOB.cjs +0 -83
- package/dist/resources-D-mn7ptO.mjs +0 -80
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
|
|
2
2
|
import os, { homedir, userInfo, tmpdir } from 'node:os';
|
|
3
3
|
import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
4
|
-
import {
|
|
5
|
-
import { z as readDaemonState, l as logger, c as configuration, A as clearDaemonState, B as ensurePrivateDirectory, D as hardenPrivateFile, p as packageJson,
|
|
4
|
+
import { j as getProjectPath, h as BUILTIN_TODO_DISCOVERY, p as projectPath, k as initializeSandbox, w as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, f as delay, l as AsyncLock, S as STREAM_DELTA_MAX_CHARS, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, m as commandOnPath, n as deriveLocalCliUpdateSummary, o as isClaudeSessionId, q as getLocalHappyAgentCredentialPath, r as readLocalHappyAgentCredentials, t as parseExactVersion, u as compareExactVersions, v as extractCompleteLines, x as decideBackfill, y as parseTerminalHookPayload, z as tmuxArgs, C as scrubTmuxClientEnv, D as decideMirrorBinding, E as MIRROR_BACKFILL_LINES_DEFAULT, F as mirrorLineKey, G as mirrorLocalId, H as detectCLIAvailability, J as detectResumeSupport, K as summarizeSpawnSessionForLog, L as shellescape, A as ApiClient, N as fetchCliUpdateState, O as resolveCliUpdateCheckInterval, P as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, i as isValidSessionId, Q as listVhTerminals, T as isValidTerminalId, U as readVhTerminal, V as sendToVhTerminal, W as TITLE_PROMPT_PREFIX, X as BOARD_ANALYZER_PROMPT_PREFIX, g as connectionState, Y as startOfflineReconnection, c as createEnvelope, Z as CodexAppServerClient } from './types-CFs8FmiY.mjs';
|
|
5
|
+
import { z as readDaemonState, l as logger, c as configuration, A as clearDaemonState, B as ensurePrivateDirectory, D as hardenPrivateFile, p as packageJson, g as readSettings, E as readCredentials, s as credentialRelayProblem, i as encodeBase64, F as readSettingsOutcome, G as updateSettings, H as encodeBase64Url, m as decodeBase64, I as writeCredentialsLegacy, J as writeCredentialsDataKey, d as readCredentialsForConfiguredRelay, j as encrypt, r as readPersistedSessions, w as writePrivateFileSync, K as decryptWithDataKey, L as decryptLegacy, M as persistSession, k as decrypt, f as ensurePrivateDirectorySync, N as acquireDaemonLock, O as deletePersistedSessions, P as writeDaemonState, Q as writeSettings, R as releaseDaemonLock, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES, S as clearCredentials, T as clearMachineId, U as SandboxConfigSchema, V as getLatestDaemonLog } from './limits-BNTLh2lw.mjs';
|
|
6
6
|
import spawn$1, { spawn } from 'cross-spawn';
|
|
7
7
|
import path, { join, resolve, basename, isAbsolute, dirname, sep, delimiter, normalize } from 'node:path';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
9
|
import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, unlinkSync, renameSync, writeFileSync, accessSync, constants, openSync, fsyncSync, closeSync, rmSync as rmSync$1, chmodSync as chmodSync$1 } from 'node:fs';
|
|
10
|
-
import {
|
|
10
|
+
import { f as trimIdent, A as AGENT_GUIDANCE, t as teamScopePath, T as TeamConnectionPreflightError, e as createTeamsClient, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, g as TEAM_TOOL_NAMES, r as registerTeamsTools, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, h as REPORT_PROGRESS_TOOL_TITLE, i as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-BPGPaNlo.mjs';
|
|
11
11
|
import { readFile, writeFile, rename, unlink, mkdir, symlink, rm, readlink, lstat, stat, open as open$1, appendFile } from 'node:fs/promises';
|
|
12
12
|
import fs, { watch, access } from 'fs/promises';
|
|
13
13
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
@@ -647,7 +647,7 @@ function shouldIncludeCoAuthoredBy() {
|
|
|
647
647
|
|
|
648
648
|
const BASE_SYSTEM_PROMPT = (() => trimIdent(`
|
|
649
649
|
ALWAYS when you start a new chat - you must call a tool "mcp__happy__change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a change to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
|
|
650
|
-
`))() + "\n\n" + AGENT_GUIDANCE;
|
|
650
|
+
`))() + "\n\n" + AGENT_GUIDANCE + "\n\n" + BUILTIN_TODO_DISCOVERY;
|
|
651
651
|
const CO_AUTHORED_CREDITS = (() => trimIdent(`
|
|
652
652
|
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
653
653
|
|
|
@@ -4742,6 +4742,7 @@ function createSessionMetadata(opts) {
|
|
|
4742
4742
|
version: packageJson.version,
|
|
4743
4743
|
os: os.platform(),
|
|
4744
4744
|
machineId: opts.machineId,
|
|
4745
|
+
...opts.teamOperationId ? { teamOperationId: opts.teamOperationId } : {},
|
|
4745
4746
|
homeDir: os.homedir(),
|
|
4746
4747
|
happyHomeDir: configuration.happyHomeDir,
|
|
4747
4748
|
happyLibDir: projectPath(),
|
|
@@ -5831,7 +5832,8 @@ async function sendUserMessage(sessionId, persisted, text, client, options = {})
|
|
|
5831
5832
|
text
|
|
5832
5833
|
},
|
|
5833
5834
|
meta: {
|
|
5834
|
-
sentFrom: options.sentFrom ?? "cli"
|
|
5835
|
+
sentFrom: options.sentFrom ?? "cli",
|
|
5836
|
+
...options.model ? { model: options.model } : {}
|
|
5835
5837
|
}
|
|
5836
5838
|
};
|
|
5837
5839
|
const encrypted = encodeBase64(encrypt(
|
|
@@ -8800,6 +8802,100 @@ async function claimSessionOrExit(happySessionId, options) {
|
|
|
8800
8802
|
process.on("exit", () => releaseSessionLock(happySessionId));
|
|
8801
8803
|
}
|
|
8802
8804
|
|
|
8805
|
+
const TEAM_SKILL = `---
|
|
8806
|
+
name: very-happy-teams
|
|
8807
|
+
description: Coordinate coding agents through Very Happy teams: delegate tasks, exchange messages, review results, and recover interrupted work. Use when asked to organize or participate in an agent team.
|
|
8808
|
+
---
|
|
8809
|
+
|
|
8810
|
+
# Very Happy Agent Teams
|
|
8811
|
+
|
|
8812
|
+
Use the team_* tools in a managed Very Happy session. If absent, explain that this host needs Very Happy Teams setup; reading this skill alone does not establish a connection.
|
|
8813
|
+
|
|
8814
|
+
Start with team_inspect if already assigned. Otherwise team_create or team_join connects the current session. A scoped worker cannot create another root identity or use account-wide tools to bypass its scope.
|
|
8815
|
+
|
|
8816
|
+
Work yourself when delegation would add needless overhead. Delegate independent work with a clear goal and acceptance criteria. When delegating within your assignment, pass its parentTaskId. Members may delegate further within their existing authority. After delegating child work, wait for those results instead of continuing parallel edits yourself. Waiting parents yield their execution slot to their children; the team limit counts progressing leaf assignments, not OS processes.
|
|
8817
|
+
|
|
8818
|
+
Name exactly one integrator for each team. Workers edit only their assigned worktrees; they must not merge main, publish releases, change global daemon or npm installations, or allocate shared backlog IDs. The integrator serializes these operations. Across teams, the owner coordinates shared resources: a worktree is not a global lock.
|
|
8819
|
+
|
|
8820
|
+
Use a unique requestId for each action and reuse it with identical arguments when the outcome is unknown. Inspect state before retrying; a timeout does not prove no action occurred. A delivered message is not proof its recipient processed it.
|
|
8821
|
+
|
|
8822
|
+
Inspect the current attemptId and goalVersion before team_submit. Include artifact locations and verification evidence. The owner reviews and accepts or returns the result. All children completing does not automatically satisfy the parent goal.
|
|
8823
|
+
|
|
8824
|
+
Acceptance and cleanup are separate. Never delete dirty worktrees, stop user-owned sessions, or bypass permissions to finish cleanup. Use team_cancel or team_handoff and inspect the resulting status. Keep summaries concise; do not repeatedly forward full descendant transcripts.
|
|
8825
|
+
|
|
8826
|
+
A root member may create a persistent schedule for itself with the schedule tools; team_inspect shows schedules. Timely delivery requires an online daemon. A scheduled delivery does not prove the model completed the work. Pause or cancel schedules explicitly when they are no longer needed.
|
|
8827
|
+
|
|
8828
|
+
On restart inspect authoritative state and messages before taking new actions. Do not invent completed work from a previous context. Scope credentials are runtime-owned; never read, print, or copy them into prompts.
|
|
8829
|
+
`;
|
|
8830
|
+
const PI_TEAMS_EXTENSION = `// Managed by Very Happy Agent Teams.
|
|
8831
|
+
export default async function(pi) {
|
|
8832
|
+
const endpoint = process.env.HAPPY_MCP_URL;
|
|
8833
|
+
if (!endpoint) return;
|
|
8834
|
+
const url = new URL(endpoint);
|
|
8835
|
+
if (!['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname) || url.protocol !== 'http:') throw new Error('Very Happy MCP must be local');
|
|
8836
|
+
const {readFile} = await import('node:fs/promises');
|
|
8837
|
+
const {join} = await import('node:path');
|
|
8838
|
+
const {homedir} = await import('node:os');
|
|
8839
|
+
pi.on('tool_call', async (event, ctx) => {
|
|
8840
|
+
let mode = process.env.HAPPY_PERMISSION_MODE || 'default';
|
|
8841
|
+
const sid = process.env.HAPPY_SESSION_ID;
|
|
8842
|
+
if (sid && /^[a-zA-Z0-9_-]+$/.test(sid)) {
|
|
8843
|
+
try { mode = JSON.parse(await readFile(join(process.env.HAPPY_HOME_DIR || join(homedir(), '.happy'), 'session-modes', sid + '.json'), 'utf8')).permissionMode; }
|
|
8844
|
+
catch (error) { if (error.code !== 'ENOENT') mode = 'default'; }
|
|
8845
|
+
}
|
|
8846
|
+
if (mode === 'yolo') mode = 'bypassPermissions';
|
|
8847
|
+
if (!['default','plan','acceptEdits','bypassPermissions'].includes(mode)) mode = 'default';
|
|
8848
|
+
if (mode === 'bypassPermissions') return;
|
|
8849
|
+
if (['read','ls','find','grep','team_inspect','change_title','report_progress'].includes(event.toolName)) return;
|
|
8850
|
+
if (mode === 'plan') return {block:true,reason:'Plan mode allows read-only tools'};
|
|
8851
|
+
if (mode === 'acceptEdits' && ['write','edit'].includes(event.toolName)) return;
|
|
8852
|
+
try {
|
|
8853
|
+
const allowed = await ctx.ui.confirm('Allow ' + event.toolName + '?', JSON.stringify(event.input || {}).slice(0,4000));
|
|
8854
|
+
if (allowed === true) return;
|
|
8855
|
+
} catch {}
|
|
8856
|
+
return {block:true,reason:'Tool requires explicit approval'};
|
|
8857
|
+
});
|
|
8858
|
+
let nextId = 0;
|
|
8859
|
+
async function rpc(method, params) {
|
|
8860
|
+
const requestId = ++nextId;
|
|
8861
|
+
const response = await fetch(endpoint, { method: 'POST', redirect: 'error', headers: {'content-type':'application/json', accept:'application/json, text/event-stream'}, body: JSON.stringify({jsonrpc:'2.0',id:requestId,method,params}), signal: AbortSignal.timeout(30000) });
|
|
8862
|
+
if (!response.ok) throw new Error('Very Happy tools unavailable (HTTP ' + response.status + ')');
|
|
8863
|
+
const body = await response.text();
|
|
8864
|
+
let data;
|
|
8865
|
+
if ((response.headers.get('content-type') || '').includes('text/event-stream')) {
|
|
8866
|
+
for (const event of body.split(/\\r?\\n\\r?\\n/)) {
|
|
8867
|
+
const payload = event.split(/\\r?\\n/).filter(line => line.startsWith('data:')).map(line => line.slice(5).trimStart()).join('\\n');
|
|
8868
|
+
if (payload) { const candidate = JSON.parse(payload); if (candidate.id === requestId) data = candidate; }
|
|
8869
|
+
}
|
|
8870
|
+
} else data = JSON.parse(body);
|
|
8871
|
+
if (!data || data.error) throw new Error('Very Happy tool request failed');
|
|
8872
|
+
return data.result;
|
|
8873
|
+
}
|
|
8874
|
+
await rpc('initialize', {protocolVersion:'2024-11-05',capabilities:{},clientInfo:{name:'very-happy-pi-teams',version:'1'}});
|
|
8875
|
+
const available = await rpc('tools/list', {});
|
|
8876
|
+
for (const tool of available.tools || []) {
|
|
8877
|
+
pi.registerTool({name:tool.name,label:tool.name,description:tool.description || tool.name,parameters:tool.inputSchema,
|
|
8878
|
+
async execute(_id, args) { const result = await rpc('tools/call', {name:tool.name,arguments:args}); return {content:result.content,details:{isError:!!result.isError}}; }
|
|
8879
|
+
});
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8882
|
+
`;
|
|
8883
|
+
|
|
8884
|
+
function teamInitialPrompt(goal, root, directory) {
|
|
8885
|
+
const role = root ? "You are the team lead. Inspect your assigned goal, arrange independent work when useful, review member results, integrate changes, and submit the final result for the user to accept. Delegate under your assigned goal using parentTaskId. You must not accept your own root goal." : "You are a team member. Inspect your assigned task and work in your assigned worktree. Delegate within your task when useful, then submit evidence for the lead to review.";
|
|
8886
|
+
return `${TEAM_SKILL}
|
|
8887
|
+
|
|
8888
|
+
## Your role
|
|
8889
|
+
${role}
|
|
8890
|
+
|
|
8891
|
+
## Working directory
|
|
8892
|
+
${directory ? JSON.stringify(directory) : "Use your current managed session working directory."}
|
|
8893
|
+
Delegate from this working directory unless a different repository was explicitly requested.
|
|
8894
|
+
|
|
8895
|
+
## Assigned goal
|
|
8896
|
+
${goal}`;
|
|
8897
|
+
}
|
|
8898
|
+
|
|
8803
8899
|
const MAX_LINE_CHARS = 500;
|
|
8804
8900
|
const MAX_ARGS_CHARS = 160;
|
|
8805
8901
|
function truncateText(text, max = MAX_LINE_CHARS) {
|
|
@@ -9381,7 +9477,7 @@ function createTeamWorker(deps) {
|
|
|
9381
9477
|
let knownSessionIds = /* @__PURE__ */ new Set();
|
|
9382
9478
|
const action = async (teamId, requestId, value) => (await http.post(`/v1/teams/${encodeURIComponent(teamId)}/actions`, { requestId, action: value })).data;
|
|
9383
9479
|
async function complete(op, receipt) {
|
|
9384
|
-
await action(op.teamId, `complete-${op.id}`, { type: "complete-operation", operationId: op.id, machineId: deps.machineId, claimId: receipt.claimId, ...receipt.sessionId ? { sessionId: receipt.sessionId } : {} });
|
|
9480
|
+
await action(op.teamId, `complete-${op.id}`, { type: "complete-operation", operationId: op.id, machineId: deps.machineId, claimId: receipt.claimId, ...receipt.sessionId ? { sessionId: receipt.sessionId } : {}, ...op.type === "spawn" && receipt.directory ? { workingDirectory: receipt.directory } : {} });
|
|
9385
9481
|
writeReceipt(home, { ...receipt, phase: "completed" });
|
|
9386
9482
|
}
|
|
9387
9483
|
async function execute(op) {
|
|
@@ -9394,7 +9490,7 @@ function createTeamWorker(deps) {
|
|
|
9394
9490
|
}
|
|
9395
9491
|
return;
|
|
9396
9492
|
}
|
|
9397
|
-
const claimed = await action(op.teamId, `claim-${op.id}`, { type: "claim-operation", operationId: op.id, machineId: deps.machineId });
|
|
9493
|
+
const claimed = await action(op.teamId, `claim-${op.id}`, { type: "claim-operation", operationId: op.id, machineId: deps.machineId, ...op.teamLaunchVersion === 1 ? { teamLaunchVersion: 1 } : {} });
|
|
9398
9494
|
if (!claimed.operation?.claimId) throw new Error("Operation claim did not return a receipt");
|
|
9399
9495
|
op = claimed.operation;
|
|
9400
9496
|
credential = claimed.credential;
|
|
@@ -9405,7 +9501,7 @@ function createTeamWorker(deps) {
|
|
|
9405
9501
|
try {
|
|
9406
9502
|
if (op.type === "spawn") {
|
|
9407
9503
|
if (receipt.phase === "prepared") {
|
|
9408
|
-
if (!credential) credential = (await action(op.teamId, `claim-${op.id}`, { type: "claim-operation", operationId: op.id, machineId: deps.machineId })).credential;
|
|
9504
|
+
if (!credential) credential = (await action(op.teamId, `claim-${op.id}`, { type: "claim-operation", operationId: op.id, machineId: deps.machineId, ...op.teamLaunchVersion === 1 ? { teamLaunchVersion: 1 } : {} })).credential;
|
|
9409
9505
|
if (!credential) throw new Error("No scoped credential for worker");
|
|
9410
9506
|
const current = (await http.get(`/v1/teams/${encodeURIComponent(op.teamId)}`)).data.team;
|
|
9411
9507
|
const task = current.tasks.find((t) => t.id === op.taskId);
|
|
@@ -9445,7 +9541,7 @@ function createTeamWorker(deps) {
|
|
|
9445
9541
|
return;
|
|
9446
9542
|
}
|
|
9447
9543
|
const key = await waitForSessionKey(receipt.sessionId, 1e4);
|
|
9448
|
-
await sendUserMessage(receipt.sessionId, key, op.prompt, "teams", { localId: `teams-initial-${op.id}`, sentFrom: "team" });
|
|
9544
|
+
await sendUserMessage(receipt.sessionId, key, teamInitialPrompt(op.prompt, bot?.root === true, receipt.directory), "teams", { localId: `teams-initial-${op.id}`, sentFrom: "team", ...op.model ? { model: op.model } : {} });
|
|
9449
9545
|
receipt = { ...receipt, phase: "delivered" };
|
|
9450
9546
|
writeReceipt(home, receipt);
|
|
9451
9547
|
}
|
|
@@ -9547,7 +9643,7 @@ Use the teams tools to inspect current task state before acting. This message is
|
|
|
9547
9643
|
const status = axios.isAxiosError(error) ? error.response?.status : void 0;
|
|
9548
9644
|
if (status !== 404) deps.log("Teams schedule advancement unavailable; regular reconciliation continues");
|
|
9549
9645
|
}
|
|
9550
|
-
const { data } = await http.get("/v1/teams/operations", { params: { machineId: deps.machineId, schedulesVersion: 1 } });
|
|
9646
|
+
const { data } = await http.get("/v1/teams/operations", { params: { machineId: deps.machineId, schedulesVersion: 1, teamLaunchVersion: 1 } });
|
|
9551
9647
|
knownSessionIds = new Set((data.teams ?? []).flatMap((team) => team.bots.flatMap((bot) => bot.sessionId ? [bot.sessionId] : [])));
|
|
9552
9648
|
for (const op of data.operations) {
|
|
9553
9649
|
if (closed) break;
|
|
@@ -9591,6 +9687,7 @@ const hostSuffix = process.env.HAPPY_VARIANT === "dev" ? "-dev" : "";
|
|
|
9591
9687
|
const startupCliAvailability = detectCLIAvailability();
|
|
9592
9688
|
const initialMachineMetadata = {
|
|
9593
9689
|
teamsVersion: 1,
|
|
9690
|
+
teamLaunchVersion: 1,
|
|
9594
9691
|
host: os$1.hostname() + hostSuffix,
|
|
9595
9692
|
platform: os$1.platform(),
|
|
9596
9693
|
happyCliVersion: packageJson.version,
|
|
@@ -10861,7 +10958,8 @@ async function startDaemon() {
|
|
|
10861
10958
|
});
|
|
10862
10959
|
void apiMachine.updateMachineMetadata((current) => ({
|
|
10863
10960
|
...current ?? initialMachineMetadata,
|
|
10864
|
-
teamsVersion: 1
|
|
10961
|
+
teamsVersion: 1,
|
|
10962
|
+
teamLaunchVersion: 1
|
|
10865
10963
|
})).catch(() => logger.debug("[DAEMON RUN] Teams capability publication will retry on reconnect"));
|
|
10866
10964
|
const cleanupAndShutdown = async (source, errorMessage) => {
|
|
10867
10965
|
logger.debug(`[DAEMON RUN] Starting proper cleanup (source: ${source}, errorMessage: ${errorMessage})...`);
|
|
@@ -10900,6 +10998,113 @@ async function startDaemon() {
|
|
|
10900
10998
|
}
|
|
10901
10999
|
}
|
|
10902
11000
|
|
|
11001
|
+
const TEAMS_ADOPT_CAPABILITY = "teams-adopt-v1";
|
|
11002
|
+
const TeamAdoptSchema = z.object({
|
|
11003
|
+
requestId: z.string().min(1).max(128),
|
|
11004
|
+
name: z.string().trim().min(1).max(128),
|
|
11005
|
+
teamId: z.string().min(1).max(128).optional()
|
|
11006
|
+
}).strict();
|
|
11007
|
+
async function retainIntent(path, input) {
|
|
11008
|
+
await mkdir(dirname(path), { recursive: true, mode: 448 });
|
|
11009
|
+
let file;
|
|
11010
|
+
try {
|
|
11011
|
+
file = await open$1(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 384);
|
|
11012
|
+
} catch (error) {
|
|
11013
|
+
if (error.code !== "EEXIST") throw new Error("Cannot retain team connection request");
|
|
11014
|
+
}
|
|
11015
|
+
if (file) {
|
|
11016
|
+
try {
|
|
11017
|
+
await file.writeFile(JSON.stringify(input));
|
|
11018
|
+
await file.sync();
|
|
11019
|
+
} finally {
|
|
11020
|
+
await file.close();
|
|
11021
|
+
}
|
|
11022
|
+
return { fresh: true };
|
|
11023
|
+
}
|
|
11024
|
+
const existing = await open$1(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
11025
|
+
try {
|
|
11026
|
+
const stat = await existing.stat();
|
|
11027
|
+
if (!stat.isFile() || process.platform !== "win32" && (stat.mode & 63) !== 0 || typeof process.getuid === "function" && stat.uid !== process.getuid()) throw new Error("Unsafe team connection receipt");
|
|
11028
|
+
const stored = JSON.parse(await existing.readFile("utf8"));
|
|
11029
|
+
const { resolvedTeamId, guidanceDelivered, ...request } = stored;
|
|
11030
|
+
const previous = TeamAdoptSchema.parse(request);
|
|
11031
|
+
if (JSON.stringify(previous) !== JSON.stringify(input)) throw new Error("Another team connection request already exists; retry the original request");
|
|
11032
|
+
if (resolvedTeamId !== void 0 && (typeof resolvedTeamId !== "string" || !resolvedTeamId)) throw new Error("Invalid connection receipt");
|
|
11033
|
+
if (guidanceDelivered !== void 0 && typeof guidanceDelivered !== "boolean") throw new Error("Invalid guidance receipt");
|
|
11034
|
+
return { resolvedTeamId, guidanceDelivered };
|
|
11035
|
+
} finally {
|
|
11036
|
+
await existing.close();
|
|
11037
|
+
}
|
|
11038
|
+
}
|
|
11039
|
+
async function retainTeam(path, input, resolvedTeamId, guidanceDelivered = false) {
|
|
11040
|
+
const temporary = `${path}.${randomUUID()}.new`;
|
|
11041
|
+
const file = await open$1(temporary, "wx", 384);
|
|
11042
|
+
try {
|
|
11043
|
+
await file.writeFile(JSON.stringify({ ...input, resolvedTeamId, guidanceDelivered }));
|
|
11044
|
+
await file.sync();
|
|
11045
|
+
} finally {
|
|
11046
|
+
await file.close();
|
|
11047
|
+
}
|
|
11048
|
+
try {
|
|
11049
|
+
await rename(temporary, path);
|
|
11050
|
+
} finally {
|
|
11051
|
+
await unlink(temporary).catch(() => {
|
|
11052
|
+
});
|
|
11053
|
+
}
|
|
11054
|
+
}
|
|
11055
|
+
function createTeamAdoption(sessionId) {
|
|
11056
|
+
const client = createTeamsClient(sessionId);
|
|
11057
|
+
let current;
|
|
11058
|
+
return (raw) => {
|
|
11059
|
+
const parsed = TeamAdoptSchema.safeParse(raw);
|
|
11060
|
+
if (!parsed.success) return { error: "Invalid team connection request" };
|
|
11061
|
+
if (process.env.VH_TEAM_SCOPE_FILE) return { error: "Assigned team members cannot create or join another team" };
|
|
11062
|
+
let path;
|
|
11063
|
+
try {
|
|
11064
|
+
path = `${teamScopePath(sessionId)}.adopt.json`;
|
|
11065
|
+
} catch {
|
|
11066
|
+
return { error: "A managed session identity is required" };
|
|
11067
|
+
}
|
|
11068
|
+
const input = parsed.data;
|
|
11069
|
+
const signature = JSON.stringify(input);
|
|
11070
|
+
if (current) {
|
|
11071
|
+
if (current.signature !== signature && current.safeToChange) current = void 0;
|
|
11072
|
+
else if (current.signature !== signature) return { error: "Another team connection request already exists; retry the original request" };
|
|
11073
|
+
}
|
|
11074
|
+
if (current) {
|
|
11075
|
+
const result = current.result;
|
|
11076
|
+
if (result && "error" in result) current = void 0;
|
|
11077
|
+
return result ?? { status: "pending", requestId: input.requestId };
|
|
11078
|
+
}
|
|
11079
|
+
const operation = { signature };
|
|
11080
|
+
current = operation;
|
|
11081
|
+
void (async () => {
|
|
11082
|
+
let intent;
|
|
11083
|
+
try {
|
|
11084
|
+
intent = await retainIntent(path, input);
|
|
11085
|
+
const connected = await client.initialize(input, { resumeAdoption: true, expectedTeamId: intent.resolvedTeamId, onTeamResolved: (teamId) => retainTeam(path, input, teamId, intent?.guidanceDelivered) });
|
|
11086
|
+
const instructions = `${TEAM_SKILL}
|
|
11087
|
+
|
|
11088
|
+
This session is now connected as the team lead. Call team_inspect to read the authoritative state before continuing the user's goal. Do not call team_create or team_join again.`;
|
|
11089
|
+
if (!intent.guidanceDelivered) {
|
|
11090
|
+
const key = await waitForSessionKey(sessionId, 1e4);
|
|
11091
|
+
await sendUserMessage(sessionId, key, instructions, "teams", { localId: `teams-adopt-${input.requestId}`, sentFrom: "team" });
|
|
11092
|
+
await retainTeam(path, input, connected.team.id, true);
|
|
11093
|
+
}
|
|
11094
|
+
operation.result = { status: "connected", teamId: connected.team.id, botId: connected.botId, instructions };
|
|
11095
|
+
} catch (error) {
|
|
11096
|
+
if (error instanceof TeamConnectionPreflightError && intent?.fresh && !intent.resolvedTeamId) {
|
|
11097
|
+
await unlink(path).catch(() => {
|
|
11098
|
+
});
|
|
11099
|
+
operation.safeToChange = true;
|
|
11100
|
+
}
|
|
11101
|
+
operation.result = { error: error instanceof Error ? error.message : "Team connection failed; retry the same request", ...operation.safeToChange ? { safeToChange: true } : {} };
|
|
11102
|
+
}
|
|
11103
|
+
})();
|
|
11104
|
+
return { status: "pending", requestId: input.requestId };
|
|
11105
|
+
};
|
|
11106
|
+
}
|
|
11107
|
+
|
|
10903
11108
|
const PERSONAL_MEMORY_SOFT_LIMIT_CHARS = 2e3;
|
|
10904
11109
|
function headingTitle(line) {
|
|
10905
11110
|
const m = /^##(?!#)\s*(.*?)\s*$/.exec(line);
|
|
@@ -11543,6 +11748,11 @@ async function startHappyServer(client, options) {
|
|
|
11543
11748
|
resolve(new URL(`http://127.0.0.1:${addr.port}`));
|
|
11544
11749
|
});
|
|
11545
11750
|
});
|
|
11751
|
+
const adoptionEnabled = !process.env.VH_TEAM_SCOPE_FILE;
|
|
11752
|
+
if (adoptionEnabled) {
|
|
11753
|
+
client.rpcHandlerManager.registerHandler("teams-adopt", createTeamAdoption(client.sessionId));
|
|
11754
|
+
client.updateMetadata((metadata) => ({ ...metadata, capabilities: [.../* @__PURE__ */ new Set([...metadata.capabilities ?? [], TEAMS_ADOPT_CAPABILITY])] }));
|
|
11755
|
+
}
|
|
11546
11756
|
logger.debug(`[happyMCP] server:ready sessionId=${client.sessionId} url=${baseUrl.toString()}`);
|
|
11547
11757
|
return {
|
|
11548
11758
|
url: baseUrl.toString(),
|
|
@@ -11556,6 +11766,7 @@ async function startHappyServer(client, options) {
|
|
|
11556
11766
|
],
|
|
11557
11767
|
stop: () => {
|
|
11558
11768
|
logger.debug(`[happyMCP] server:stop sessionId=${client.sessionId}`);
|
|
11769
|
+
if (adoptionEnabled) client.rpcHandlerManager.unregisterHandler("teams-adopt");
|
|
11559
11770
|
server.close();
|
|
11560
11771
|
}
|
|
11561
11772
|
};
|
|
@@ -11812,7 +12023,7 @@ function registerSideQuestionHandler(rpc, deps) {
|
|
|
11812
12023
|
const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
|
|
11813
12024
|
const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
|
|
11814
12025
|
const run = deps.run ?? (async (input) => {
|
|
11815
|
-
const { query } = await import('./index-
|
|
12026
|
+
const { query } = await import('./index-35FahgEU.mjs');
|
|
11816
12027
|
return runSideQuestion(query, input);
|
|
11817
12028
|
});
|
|
11818
12029
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -15873,6 +16084,7 @@ function buildCodexTurnPrompt(opts) {
|
|
|
15873
16084
|
parts.push(opts.message);
|
|
15874
16085
|
if (opts.includeTitleInstruction) {
|
|
15875
16086
|
parts.push(CHANGE_TITLE_INSTRUCTION);
|
|
16087
|
+
parts.push(BUILTIN_TODO_DISCOVERY);
|
|
15876
16088
|
}
|
|
15877
16089
|
return parts.join("\n\n");
|
|
15878
16090
|
}
|
|
@@ -16765,7 +16977,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16765
16977
|
process.exit(0);
|
|
16766
16978
|
} else if (subcommand === "install-terminal-hooks") {
|
|
16767
16979
|
try {
|
|
16768
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-
|
|
16980
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-ClrFe2fA.mjs');
|
|
16769
16981
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
16770
16982
|
if (command.action === "help") {
|
|
16771
16983
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -16782,7 +16994,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16782
16994
|
}
|
|
16783
16995
|
} else if (subcommand === "spawn") {
|
|
16784
16996
|
try {
|
|
16785
|
-
const { handleSpawnCommand } = await import('./spawn-
|
|
16997
|
+
const { handleSpawnCommand } = await import('./spawn-DV4pIAHZ.mjs');
|
|
16786
16998
|
await handleSpawnCommand(args.slice(1));
|
|
16787
16999
|
} catch (error) {
|
|
16788
17000
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -16794,7 +17006,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16794
17006
|
return;
|
|
16795
17007
|
} else if (subcommand === "sessions") {
|
|
16796
17008
|
try {
|
|
16797
|
-
const { handleSessionsCommand } = await import('./sessions-
|
|
17009
|
+
const { handleSessionsCommand } = await import('./sessions-DIOdWnPe.mjs');
|
|
16798
17010
|
await handleSessionsCommand(args.slice(1));
|
|
16799
17011
|
} catch (error) {
|
|
16800
17012
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -16806,7 +17018,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16806
17018
|
return;
|
|
16807
17019
|
} else if (subcommand === "send") {
|
|
16808
17020
|
try {
|
|
16809
|
-
const { handleSendCommand } = await import('./send-
|
|
17021
|
+
const { handleSendCommand } = await import('./send-DQS1zNWp.mjs');
|
|
16810
17022
|
await handleSendCommand(args.slice(1));
|
|
16811
17023
|
} catch (error) {
|
|
16812
17024
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -16912,9 +17124,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16912
17124
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
16913
17125
|
const projectId = args[3];
|
|
16914
17126
|
try {
|
|
16915
|
-
const { saveGoogleCloudProjectToConfig } = await import('./config-
|
|
16916
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-
|
|
16917
|
-
const { ApiClient: ApiClient2 } = await import('./types-
|
|
17127
|
+
const { saveGoogleCloudProjectToConfig } = await import('./config-DSBE0Az0.mjs');
|
|
17128
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-BNTLh2lw.mjs').then(function (n) { return n.W; });
|
|
17129
|
+
const { ApiClient: ApiClient2 } = await import('./types-CFs8FmiY.mjs').then(function (n) { return n._; });
|
|
16918
17130
|
let userEmail = void 0;
|
|
16919
17131
|
try {
|
|
16920
17132
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -16945,7 +17157,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16945
17157
|
}
|
|
16946
17158
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
16947
17159
|
try {
|
|
16948
|
-
const { readGeminiLocalConfig } = await import('./config-
|
|
17160
|
+
const { readGeminiLocalConfig } = await import('./config-DSBE0Az0.mjs');
|
|
16949
17161
|
const config = readGeminiLocalConfig();
|
|
16950
17162
|
if (config.googleCloudProject) {
|
|
16951
17163
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -16985,7 +17197,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
16985
17197
|
process.exit(0);
|
|
16986
17198
|
}
|
|
16987
17199
|
try {
|
|
16988
|
-
const { runGemini } = await import('./runGemini-
|
|
17200
|
+
const { runGemini } = await import('./runGemini-B9S85Vms.mjs');
|
|
16989
17201
|
let startedBy = void 0;
|
|
16990
17202
|
for (let i = 1; i < args.length; i++) {
|
|
16991
17203
|
if (args[i] === "--started-by") {
|
|
@@ -17015,7 +17227,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17015
17227
|
}
|
|
17016
17228
|
};
|
|
17017
17229
|
try {
|
|
17018
|
-
const { runAcp, resolveAcpAgentConfig } = await import('./index-
|
|
17230
|
+
const { runAcp, resolveAcpAgentConfig } = await import('./index-m0Dnccc_.mjs');
|
|
17019
17231
|
const parsed = parsePiRunnerArgs(args.slice(1));
|
|
17020
17232
|
const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
|
|
17021
17233
|
const { credentials } = await authAndSetupMachineIfNeeded();
|
|
@@ -17042,7 +17254,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17042
17254
|
return;
|
|
17043
17255
|
} else if (subcommand === "acp") {
|
|
17044
17256
|
try {
|
|
17045
|
-
const { runAcp, resolveAcpAgentConfig } = await import('./index-
|
|
17257
|
+
const { runAcp, resolveAcpAgentConfig } = await import('./index-m0Dnccc_.mjs');
|
|
17046
17258
|
let startedBy = void 0;
|
|
17047
17259
|
let verbose = false;
|
|
17048
17260
|
const acpArgs = [];
|
|
@@ -17082,7 +17294,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17082
17294
|
return;
|
|
17083
17295
|
} else if (subcommand === "openclaw") {
|
|
17084
17296
|
try {
|
|
17085
|
-
const { runOpenClaw } = await import('./runOpenClaw-
|
|
17297
|
+
const { runOpenClaw } = await import('./runOpenClaw-Byhq-B1y.mjs');
|
|
17086
17298
|
let startedBy = void 0;
|
|
17087
17299
|
let verbose = false;
|
|
17088
17300
|
let gatewayUrl;
|
|
@@ -17131,9 +17343,18 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17131
17343
|
process.exit(1);
|
|
17132
17344
|
}
|
|
17133
17345
|
return;
|
|
17346
|
+
} else if (subcommand === "todo") {
|
|
17347
|
+
try {
|
|
17348
|
+
const { handleTodoCommand } = await import('./todo-BwXURAbQ.mjs');
|
|
17349
|
+
await handleTodoCommand(args.slice(1));
|
|
17350
|
+
} catch (error) {
|
|
17351
|
+
console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
|
|
17352
|
+
process.exitCode = 1;
|
|
17353
|
+
}
|
|
17354
|
+
return;
|
|
17134
17355
|
} else if (subcommand === "teams") {
|
|
17135
17356
|
try {
|
|
17136
|
-
const { handleTeamsCommand } = await import('./teams-
|
|
17357
|
+
const { handleTeamsCommand } = await import('./teams-DlTHOiCk.mjs');
|
|
17137
17358
|
await handleTeamsCommand(args.slice(1));
|
|
17138
17359
|
} catch (error) {
|
|
17139
17360
|
console.error(error instanceof Error ? error.message : "Teams command failed");
|
|
@@ -17142,7 +17363,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17142
17363
|
return;
|
|
17143
17364
|
} else if (subcommand === "mcp" && args.length === 1) {
|
|
17144
17365
|
try {
|
|
17145
|
-
const { handleMcpCommand } = await import('./mcp-
|
|
17366
|
+
const { handleMcpCommand } = await import('./mcp-BsohER5A.mjs');
|
|
17146
17367
|
await handleMcpCommand();
|
|
17147
17368
|
} catch (error) {
|
|
17148
17369
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -17369,6 +17590,7 @@ ${chalk.bold("Usage:")}
|
|
|
17369
17590
|
Install optional Claude terminal mirror hooks
|
|
17370
17591
|
(add --remove to uninstall them)
|
|
17371
17592
|
very-happy connect Connect AI vendor API keys
|
|
17593
|
+
very-happy todo Built-in Todos and official agent skill (todo --help)
|
|
17372
17594
|
very-happy sandbox Configure and manage OS-level sandboxing
|
|
17373
17595
|
very-happy notify Send push notification
|
|
17374
17596
|
very-happy mcp Stdio MCP server exposing copy_to_clipboard for a
|
|
@@ -17503,4 +17725,4 @@ ${chalk.bold("Examples:")}
|
|
|
17503
17725
|
}
|
|
17504
17726
|
}
|
|
17505
17727
|
|
|
17506
|
-
export { ALLOWED_SPAWN_PERMISSION_MODES as A, hashObject as B, startHappyServer as C, DEFAULT_RECENT_LIMIT as D,
|
|
17728
|
+
export { ALLOWED_SPAWN_PERMISSION_MODES as A, hashObject as B, startHappyServer as C, DEFAULT_RECENT_LIMIT as D, TitleGenerator as E, BasePermissionHandler as F, GEMINI_MODEL_ENV as G, writeSessionModeFile as H, normalizeAcpPermissionMode as I, removeSessionModeFile as J, GEMINI_API_KEY_ENV as K, GOOGLE_API_KEY_ENV as L, MAX_READ_LIMIT as M, BaseReasoningProcessor as N, MessageBuffer as O, PI_TEAMS_EXTENSION as P, CHANGE_TITLE_INSTRUCTION as Q, SPAWN_AGENTS as S, TEAM_SKILL as T, sessionWebUrl as a, sanitizeSpawnPermissionMode as b, checkIfDaemonRunningAndCleanupStaleState as c, sendUserMessage as d, listSessions as e, stopSession as f, resolvePermissionRequest as g, archiveSession as h, isValidSpawnOrigin as i, DEFAULT_GEMINI_MODEL as j, setTerminalTitleViaDaemon as k, listAccountSessions as l, registerAssistantSessionTools as m, initialMachineMetadata as n, createSessionMetadata as o, pushClipboardViaDaemon as p, query as q, readSessionTranscript as r, spawnDaemonSession as s, tmuxSupportsSessionEnv as t, setupOfflineReconnection as u, notifyDaemonSessionStarted as v, waitForSessionKey as w, MessageQueue2 as x, registerKillSessionHandler as y, StreamRelay as z };
|