@zonease/happy 0.6.38 → 0.6.40
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/bin/happy.mjs +10 -0
- package/dist/{types-DvTsFaqR.cjs → api-C7FyJfZ1.cjs} +400 -1964
- package/dist/{types-BWpRU1VN.mjs → api-D6WL40-U.mjs} +220 -1729
- package/dist/auth-C7ZScWEw.cjs +274 -0
- package/dist/auth-DCsIoZLT.cjs +183 -0
- package/dist/auth-DO9GexAR.mjs +181 -0
- package/dist/auth-DxJ3VvrX.mjs +270 -0
- package/dist/browser-AoVGRX7y.mjs +20 -0
- package/dist/browser-DzgO4oaD.cjs +22 -0
- package/dist/claudeLocal-C6BdzhDx.cjs +352 -0
- package/dist/claudeLocal-CWNGpJ0-.mjs +344 -0
- package/dist/codex/happyMcpStdioBridge.cjs +4 -1
- package/dist/codex/happyMcpStdioBridge.mjs +4 -1
- package/dist/common-BdNgghUJ.mjs +75 -0
- package/dist/common-CZvSRU4p.cjs +83 -0
- package/dist/{config-0Xnc8ARM.cjs → config-CclB3QW9.cjs} +21 -34
- package/dist/{config-_GW4YBCP.mjs → config-DZk-mJ0K.mjs} +7 -20
- package/dist/connect-BXLUKJ5P.mjs +679 -0
- package/dist/connect-k9CqDJ-T.cjs +681 -0
- package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
- package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
- package/dist/controlClient-B23M-WPp.cjs +177 -0
- package/dist/controlClient-DB5tDU7V.mjs +167 -0
- package/dist/deviceKeys-BTdo34Uz.mjs +175 -0
- package/dist/deviceKeys-C540DcXl.cjs +182 -0
- package/dist/diagnose-B3D1a_v0.cjs +60 -0
- package/dist/diagnose-CuRKXxt1.mjs +58 -0
- package/dist/doctor-BQGLhrcI.cjs +214 -0
- package/dist/doctor-C08m5Z9f.cjs +78 -0
- package/dist/doctor-CU4JLGQ1.mjs +211 -0
- package/dist/doctor-ON7pN5G5.mjs +74 -0
- package/dist/downloadImage-DZXI3mXL.mjs +887 -0
- package/dist/downloadImage-cQ1Z7hkC.cjs +897 -0
- package/dist/enroll-B55BQR56.mjs +113 -0
- package/dist/enroll-Bo-CNio1.cjs +115 -0
- package/dist/evidence-DQp8QWcv.cjs +129 -0
- package/dist/evidence-DTYRAaOZ.mjs +127 -0
- package/dist/formatImageMessage-CixDYY6G.cjs +46 -0
- package/dist/formatImageMessage-DbKSSjMx.mjs +43 -0
- package/dist/github-DKcyF1zp.mjs +57 -0
- package/dist/github-h9GhJJ_C.cjs +59 -0
- package/dist/index-CDTNgfUf.cjs +578 -0
- package/dist/index-CPKdvi7J.mjs +554 -0
- package/dist/index.cjs +812 -40
- package/dist/index.mjs +813 -40
- package/dist/install-B1e6rdy7.mjs +94 -0
- package/dist/install-CgUPGIoF.mjs +95 -0
- package/dist/install-D7Ir7ciZ.cjs +96 -0
- package/dist/install-DSDufaPd.cjs +98 -0
- package/dist/lib.cjs +18 -12
- package/dist/lib.d.cts +77 -0
- package/dist/lib.d.mts +77 -0
- package/dist/lib.mjs +13 -7
- package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Bfei9wPq.mjs} +4 -2
- package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-CbLGtvST.cjs} +63 -61
- package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
- package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
- package/dist/persistence-CBTtC_dm.cjs +996 -0
- package/dist/persistence-DKfF81pd.mjs +944 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/prompt-BTWDZZO0.cjs +25 -0
- package/dist/prompt-BsAZsPbo.mjs +22 -0
- package/dist/release-BMEzNONE.mjs +168 -0
- package/dist/release-EhOJeAZe.cjs +171 -0
- package/dist/run-BVZsMNwN.mjs +2164 -0
- package/dist/run-CURx7LhK.cjs +2188 -0
- package/dist/runClaude-6Gi0sYQy.mjs +3763 -0
- package/dist/runClaude-CL3Kt5ex.cjs +3766 -0
- package/dist/{runCodex-DiKzBf9q.mjs → runCodex-ClwEgJ7M.mjs} +36 -20
- package/dist/{runCodex-skq0j05d.cjs → runCodex-YKyVBkJ3.cjs} +169 -153
- package/dist/{runGemini-BeqrVq8R.mjs → runGemini-BPWxVr60.mjs} +34 -17
- package/dist/{runGemini-CVp-CEIh.cjs → runGemini-Xz2W1spn.cjs} +212 -195
- package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-CdCWiiLr.mjs} +14 -38
- package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-DjZyCvDI.cjs} +31 -55
- package/dist/{serve-BNdoEDVx.mjs → serve-B48JttQ3.mjs} +12 -35
- package/dist/{serve-BECdtivY.cjs → serve-B8vaWQA0.cjs} +35 -58
- package/dist/session-BXboDn2V.mjs +108 -0
- package/dist/session-BZO25zxp.cjs +110 -0
- package/dist/sessionKeyCache-B6cGadYL.mjs +33 -0
- package/dist/sessionKeyCache-CDmexJ9p.cjs +36 -0
- package/dist/sessionList-CgAYZpNj.mjs +51 -0
- package/dist/sessionList-lQ-nqEhc.cjs +54 -0
- package/dist/sessionSummary-CcORiQSq.cjs +393 -0
- package/dist/sessionSummary-DCWQoaDP.mjs +387 -0
- package/dist/spawnHappyCLI-KiazE3kL.cjs +70 -0
- package/dist/spawnHappyCLI-yBIP_Oqi.mjs +66 -0
- package/dist/ssh-q5uZhqBf.mjs +359 -0
- package/dist/ssh-yMllSHu5.cjs +365 -0
- package/dist/systemdScope-BeOtAkhk.mjs +25 -0
- package/dist/systemdScope-DW3-UoKB.cjs +29 -0
- package/dist/task-_nr7J19j.cjs +167 -0
- package/dist/task-wNX1N2i4.mjs +165 -0
- package/dist/time-Bj2HRkKH.cjs +33 -0
- package/dist/time-DgsBLJA_.mjs +29 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-BoJh4Qfv.mjs +57 -0
- package/dist/types-DWeB7aqh.cjs +59 -0
- package/dist/uninstall-Buaz7d-X.cjs +77 -0
- package/dist/uninstall-Dxf6_4mQ.mjs +75 -0
- package/dist/update-CGlIfa8e.cjs +111 -0
- package/dist/update-CnnoX2cV.mjs +109 -0
- package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
- package/dist/workflowCommon-Bl568-rt.cjs +62 -0
- package/dist/workflowReports-BEWuQesA.cjs +113 -0
- package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
- package/package.json +1 -1
- package/dist/index-BbCDDvoB.cjs +0 -11376
- package/dist/index-vvZXdswy.mjs +0 -11336
- package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
- package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { r as readCredentials } from './persistence-DKfF81pd.mjs';
|
|
4
|
+
import { r as runSessionList } from './sessionList-CgAYZpNj.mjs';
|
|
5
|
+
import { r as runSessionSummary } from './sessionSummary-DCWQoaDP.mjs';
|
|
6
|
+
import { p as parseWorkflowArgs, s as stringFlag, b as booleanFlag, n as numberFlag, a as printOrWriteOutput } from './workflowCommon-B0d01Y_a.mjs';
|
|
7
|
+
import 'node:fs/promises';
|
|
8
|
+
import 'node:fs';
|
|
9
|
+
import 'node:os';
|
|
10
|
+
import 'zod';
|
|
11
|
+
import 'node:crypto';
|
|
12
|
+
import 'tweetnacl';
|
|
13
|
+
import 'fs';
|
|
14
|
+
import 'axios';
|
|
15
|
+
import './auth-DxJ3VvrX.mjs';
|
|
16
|
+
import 'qrcode-terminal';
|
|
17
|
+
import './time-DgsBLJA_.mjs';
|
|
18
|
+
import './browser-AoVGRX7y.mjs';
|
|
19
|
+
import 'open';
|
|
20
|
+
import 'react';
|
|
21
|
+
import 'ink';
|
|
22
|
+
import './sessionKeyCache-B6cGadYL.mjs';
|
|
23
|
+
|
|
24
|
+
function printTaskHelp() {
|
|
25
|
+
console.log(`
|
|
26
|
+
${chalk.bold("happy task")} - Agent handoff helpers
|
|
27
|
+
|
|
28
|
+
${chalk.bold("Usage:")}
|
|
29
|
+
happy task brief --session <sessionId> [options]
|
|
30
|
+
happy task brief <sessionId> [options]
|
|
31
|
+
happy task brief --recent [--project <path>] [options]
|
|
32
|
+
|
|
33
|
+
${chalk.bold("Options:")}
|
|
34
|
+
--session <id> Happy session ID to summarize
|
|
35
|
+
--recent Pick the most recent session, optionally filtered by --project
|
|
36
|
+
--project <path> Project path filter for --recent
|
|
37
|
+
--limit <n> Raw messages to compact (default: 200)
|
|
38
|
+
--max-turns <n> Compact turns to include (default: 80)
|
|
39
|
+
--text-limit <n> Max chars per text block (default: 800)
|
|
40
|
+
--out <path> Write the brief to a markdown file
|
|
41
|
+
--json Print machine-readable JSON
|
|
42
|
+
-h, --help Show this help
|
|
43
|
+
`);
|
|
44
|
+
}
|
|
45
|
+
function collectSessionText(summary) {
|
|
46
|
+
const chunks = [];
|
|
47
|
+
if (summary.storedSummary) chunks.push(summary.storedSummary);
|
|
48
|
+
for (const turn of summary.turns) {
|
|
49
|
+
if (turn.user?.text) chunks.push(turn.user.text);
|
|
50
|
+
for (const text of turn.assistantTexts) chunks.push(text.text);
|
|
51
|
+
}
|
|
52
|
+
return chunks.join("\n");
|
|
53
|
+
}
|
|
54
|
+
function extractMatchingLines(text, patterns, limit) {
|
|
55
|
+
const seen = /* @__PURE__ */ new Set();
|
|
56
|
+
const lines = [];
|
|
57
|
+
for (const line of text.split("\n")) {
|
|
58
|
+
const trimmed = line.replace(/^[-*]\s*/, "").trim();
|
|
59
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
60
|
+
if (patterns.some((pattern) => pattern.test(trimmed))) {
|
|
61
|
+
seen.add(trimmed);
|
|
62
|
+
lines.push(trimmed);
|
|
63
|
+
}
|
|
64
|
+
if (lines.length >= limit) break;
|
|
65
|
+
}
|
|
66
|
+
return lines;
|
|
67
|
+
}
|
|
68
|
+
function bulletList(lines, fallback) {
|
|
69
|
+
if (lines.length === 0) return `- ${fallback}`;
|
|
70
|
+
return lines.map((line) => `- ${line}`).join("\n");
|
|
71
|
+
}
|
|
72
|
+
function buildBriefMarkdown(summary, source) {
|
|
73
|
+
const text = collectSessionText(summary);
|
|
74
|
+
const done = extractMatchingLines(text, [/完成|已实现|通过|passed|fixed|implemented|verified/i], 6);
|
|
75
|
+
const blockers = extractMatchingLines(text, [/失败|阻塞|blocked|failed|error|E401|unrelated/i], 6);
|
|
76
|
+
const next = extractMatchingLines(text, [/继续|下一步|TODO|todo|next|publish|发布|验证|verify/i], 6);
|
|
77
|
+
return `# Happy Task Brief
|
|
78
|
+
|
|
79
|
+
- Source: ${source}
|
|
80
|
+
- Session: \`${summary.sessionId}\`
|
|
81
|
+
- Active: ${summary.active ? "yes" : "no"}
|
|
82
|
+
- Agent: ${summary.agent.name ?? "(unknown)"}${summary.agent.model ? ` / ${summary.agent.model}` : ""}
|
|
83
|
+
- Machine: ${summary.machine.name ?? summary.machine.id ?? "(unknown)"}
|
|
84
|
+
- Path: ${summary.path ?? "(unknown)"}
|
|
85
|
+
- Updated: ${new Date(summary.updatedAt).toISOString()}
|
|
86
|
+
|
|
87
|
+
## Stored Summary
|
|
88
|
+
|
|
89
|
+
${summary.storedSummary ?? "(none)"}
|
|
90
|
+
|
|
91
|
+
## Recent Conversation
|
|
92
|
+
|
|
93
|
+
${summary.summaryText}
|
|
94
|
+
|
|
95
|
+
## Done / Evidence
|
|
96
|
+
|
|
97
|
+
${bulletList(done, "No explicit completion evidence detected in the compact window.")}
|
|
98
|
+
|
|
99
|
+
## Blockers / Risks
|
|
100
|
+
|
|
101
|
+
${bulletList(blockers, "No explicit blocker detected in the compact window.")}
|
|
102
|
+
|
|
103
|
+
## Suggested Next Actions
|
|
104
|
+
|
|
105
|
+
${bulletList(next, "Continue from the latest user request and verify before reporting completion.")}
|
|
106
|
+
|
|
107
|
+
## Continuation Prompt
|
|
108
|
+
|
|
109
|
+
Continue session \`${summary.sessionId}\` from this brief. Preserve existing user changes, inspect the repository rules before editing, implement only the requested scope, run focused verification, and summarize changed files plus test results in Chinese.
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
function findRecentSession(sessions, projectPath) {
|
|
113
|
+
if (!projectPath) return sessions[0];
|
|
114
|
+
const resolved = resolve(projectPath);
|
|
115
|
+
return sessions.find((session) => {
|
|
116
|
+
if (!session.path) return false;
|
|
117
|
+
const path = resolve(session.path);
|
|
118
|
+
return path === resolved || path.startsWith(`${resolved}/`) || resolved.startsWith(`${path}/`);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async function handleTaskCommand(args) {
|
|
122
|
+
const action = args[0];
|
|
123
|
+
if (!action || action === "-h" || action === "--help") {
|
|
124
|
+
printTaskHelp();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (action !== "brief") {
|
|
128
|
+
throw new Error(`Unknown task command: ${action}. Use "happy task brief".`);
|
|
129
|
+
}
|
|
130
|
+
const parsed = parseWorkflowArgs(args.slice(1), /* @__PURE__ */ new Set(["--session", "--project", "--limit", "--max-turns", "--text-limit", "--out"]));
|
|
131
|
+
const credentials = await readCredentials();
|
|
132
|
+
if (!credentials) {
|
|
133
|
+
throw new Error('No happy credentials found. Run "happy auth login" first.');
|
|
134
|
+
}
|
|
135
|
+
let sessionId = stringFlag(parsed, "--session") ?? parsed.positionals[0];
|
|
136
|
+
let source = "session";
|
|
137
|
+
if (!sessionId && booleanFlag(parsed, "--recent")) {
|
|
138
|
+
const result = await runSessionList(credentials, { status: "all", limit: 150 });
|
|
139
|
+
const recent = findRecentSession(result.sessions, stringFlag(parsed, "--project"));
|
|
140
|
+
if (!recent) {
|
|
141
|
+
throw new Error("No matching recent session found.");
|
|
142
|
+
}
|
|
143
|
+
sessionId = recent.sessionId;
|
|
144
|
+
source = "recent";
|
|
145
|
+
}
|
|
146
|
+
if (!sessionId) {
|
|
147
|
+
throw new Error('Session ID required. Use "happy task brief --session <id>" or "--recent".');
|
|
148
|
+
}
|
|
149
|
+
const input = {
|
|
150
|
+
sessionId,
|
|
151
|
+
limit: numberFlag(parsed, "--limit"),
|
|
152
|
+
maxTurns: numberFlag(parsed, "--max-turns"),
|
|
153
|
+
textLimit: numberFlag(parsed, "--text-limit"),
|
|
154
|
+
includeTools: true
|
|
155
|
+
};
|
|
156
|
+
const summary = await runSessionSummary(credentials, input);
|
|
157
|
+
const brief = buildBriefMarkdown(summary, source);
|
|
158
|
+
if (booleanFlag(parsed, "--json")) {
|
|
159
|
+
console.log(JSON.stringify({ source, summary, brief }, null, 2));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await printOrWriteOutput(brief, stringFlag(parsed, "--out"));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { handleTaskCommand };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
async function delay(ms) {
|
|
4
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
}
|
|
6
|
+
function exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount) {
|
|
7
|
+
let maxDelayRet = minDelay + (maxDelay - minDelay) / maxFailureCount * Math.min(currentFailureCount, maxFailureCount);
|
|
8
|
+
return Math.round(Math.random() * maxDelayRet);
|
|
9
|
+
}
|
|
10
|
+
function createBackoff(opts) {
|
|
11
|
+
return async (callback) => {
|
|
12
|
+
let currentFailureCount = 0;
|
|
13
|
+
const minDelay = 250;
|
|
14
|
+
const maxDelay = 1e3;
|
|
15
|
+
const maxFailureCount = 50;
|
|
16
|
+
while (true) {
|
|
17
|
+
try {
|
|
18
|
+
return await callback();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
if (currentFailureCount < maxFailureCount) {
|
|
21
|
+
currentFailureCount++;
|
|
22
|
+
}
|
|
23
|
+
let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount);
|
|
24
|
+
await delay(waitForRequest);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let backoff = createBackoff();
|
|
30
|
+
|
|
31
|
+
exports.backoff = backoff;
|
|
32
|
+
exports.delay = delay;
|
|
33
|
+
exports.exponentialBackoffDelay = exponentialBackoffDelay;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
async function delay(ms) {
|
|
2
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
}
|
|
4
|
+
function exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount) {
|
|
5
|
+
let maxDelayRet = minDelay + (maxDelay - minDelay) / maxFailureCount * Math.min(currentFailureCount, maxFailureCount);
|
|
6
|
+
return Math.round(Math.random() * maxDelayRet);
|
|
7
|
+
}
|
|
8
|
+
function createBackoff(opts) {
|
|
9
|
+
return async (callback) => {
|
|
10
|
+
let currentFailureCount = 0;
|
|
11
|
+
const minDelay = 250;
|
|
12
|
+
const maxDelay = 1e3;
|
|
13
|
+
const maxFailureCount = 50;
|
|
14
|
+
while (true) {
|
|
15
|
+
try {
|
|
16
|
+
return await callback();
|
|
17
|
+
} catch (e) {
|
|
18
|
+
if (currentFailureCount < maxFailureCount) {
|
|
19
|
+
currentFailureCount++;
|
|
20
|
+
}
|
|
21
|
+
let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount);
|
|
22
|
+
await delay(waitForRequest);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
let backoff = createBackoff();
|
|
28
|
+
|
|
29
|
+
export { backoff as b, delay as d, exponentialBackoffDelay as e };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function trimIdent(text) {
|
|
4
|
+
const lines = text.split("\n");
|
|
5
|
+
while (lines.length > 0 && lines[0].trim() === "") {
|
|
6
|
+
lines.shift();
|
|
7
|
+
}
|
|
8
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
9
|
+
lines.pop();
|
|
10
|
+
}
|
|
11
|
+
const minSpaces = lines.reduce((min, line) => {
|
|
12
|
+
if (line.trim() === "") {
|
|
13
|
+
return min;
|
|
14
|
+
}
|
|
15
|
+
const leadingSpaces = line.match(/^\s*/)[0].length;
|
|
16
|
+
return Math.min(min, leadingSpaces);
|
|
17
|
+
}, Infinity);
|
|
18
|
+
const trimmedLines = lines.map((line) => line.slice(minSpaces));
|
|
19
|
+
return trimmedLines.join("\n");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
exports.trimIdent = trimIdent;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function trimIdent(text) {
|
|
2
|
+
const lines = text.split("\n");
|
|
3
|
+
while (lines.length > 0 && lines[0].trim() === "") {
|
|
4
|
+
lines.shift();
|
|
5
|
+
}
|
|
6
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
7
|
+
lines.pop();
|
|
8
|
+
}
|
|
9
|
+
const minSpaces = lines.reduce((min, line) => {
|
|
10
|
+
if (line.trim() === "") {
|
|
11
|
+
return min;
|
|
12
|
+
}
|
|
13
|
+
const leadingSpaces = line.match(/^\s*/)[0].length;
|
|
14
|
+
return Math.min(min, leadingSpaces);
|
|
15
|
+
}, Infinity);
|
|
16
|
+
const trimmedLines = lines.map((line) => line.slice(minSpaces));
|
|
17
|
+
return trimmedLines.join("\n");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { trimIdent as t };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const UsageSchema = z.object({
|
|
4
|
+
input_tokens: z.number().int().nonnegative(),
|
|
5
|
+
cache_creation_input_tokens: z.number().int().nonnegative().optional(),
|
|
6
|
+
cache_read_input_tokens: z.number().int().nonnegative().optional(),
|
|
7
|
+
output_tokens: z.number().int().nonnegative(),
|
|
8
|
+
service_tier: z.string().nullish()
|
|
9
|
+
}).passthrough();
|
|
10
|
+
const RawJSONLinesSchema = z.discriminatedUnion("type", [
|
|
11
|
+
// User message - validates uuid and message.content
|
|
12
|
+
z.object({
|
|
13
|
+
type: z.literal("user"),
|
|
14
|
+
isSidechain: z.boolean().optional(),
|
|
15
|
+
isMeta: z.boolean().optional(),
|
|
16
|
+
uuid: z.string(),
|
|
17
|
+
// Used in getMessageKey()
|
|
18
|
+
message: z.object({
|
|
19
|
+
content: z.union([z.string(), z.any()])
|
|
20
|
+
// Used in sessionScanner.ts
|
|
21
|
+
}).passthrough()
|
|
22
|
+
}).passthrough(),
|
|
23
|
+
// Assistant message - only validates uuid and type
|
|
24
|
+
// message object is optional to handle synthetic error messages (isApiErrorMessage: true)
|
|
25
|
+
// which may have different structure than normal assistant messages
|
|
26
|
+
z.object({
|
|
27
|
+
uuid: z.string(),
|
|
28
|
+
type: z.literal("assistant"),
|
|
29
|
+
message: z.object({
|
|
30
|
+
usage: UsageSchema.optional(),
|
|
31
|
+
// Used in apiSession.ts
|
|
32
|
+
model: z.string().optional()
|
|
33
|
+
// Used for cost calculation
|
|
34
|
+
}).passthrough().optional()
|
|
35
|
+
}).passthrough(),
|
|
36
|
+
// Summary message - validates summary and leafUuid
|
|
37
|
+
z.object({
|
|
38
|
+
type: z.literal("summary"),
|
|
39
|
+
summary: z.string(),
|
|
40
|
+
// Used in apiSession.ts
|
|
41
|
+
leafUuid: z.string()
|
|
42
|
+
// Used in getMessageKey()
|
|
43
|
+
}).passthrough(),
|
|
44
|
+
// System message - validates uuid
|
|
45
|
+
z.object({
|
|
46
|
+
type: z.literal("system"),
|
|
47
|
+
uuid: z.string()
|
|
48
|
+
// Used in getMessageKey()
|
|
49
|
+
}).passthrough(),
|
|
50
|
+
// Progress message - hook progress events, not counted toward message limits
|
|
51
|
+
z.object({
|
|
52
|
+
type: z.literal("progress"),
|
|
53
|
+
uuid: z.string()
|
|
54
|
+
}).passthrough()
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export { RawJSONLinesSchema as R };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var z = require('zod');
|
|
4
|
+
|
|
5
|
+
const UsageSchema = z.z.object({
|
|
6
|
+
input_tokens: z.z.number().int().nonnegative(),
|
|
7
|
+
cache_creation_input_tokens: z.z.number().int().nonnegative().optional(),
|
|
8
|
+
cache_read_input_tokens: z.z.number().int().nonnegative().optional(),
|
|
9
|
+
output_tokens: z.z.number().int().nonnegative(),
|
|
10
|
+
service_tier: z.z.string().nullish()
|
|
11
|
+
}).passthrough();
|
|
12
|
+
const RawJSONLinesSchema = z.z.discriminatedUnion("type", [
|
|
13
|
+
// User message - validates uuid and message.content
|
|
14
|
+
z.z.object({
|
|
15
|
+
type: z.z.literal("user"),
|
|
16
|
+
isSidechain: z.z.boolean().optional(),
|
|
17
|
+
isMeta: z.z.boolean().optional(),
|
|
18
|
+
uuid: z.z.string(),
|
|
19
|
+
// Used in getMessageKey()
|
|
20
|
+
message: z.z.object({
|
|
21
|
+
content: z.z.union([z.z.string(), z.z.any()])
|
|
22
|
+
// Used in sessionScanner.ts
|
|
23
|
+
}).passthrough()
|
|
24
|
+
}).passthrough(),
|
|
25
|
+
// Assistant message - only validates uuid and type
|
|
26
|
+
// message object is optional to handle synthetic error messages (isApiErrorMessage: true)
|
|
27
|
+
// which may have different structure than normal assistant messages
|
|
28
|
+
z.z.object({
|
|
29
|
+
uuid: z.z.string(),
|
|
30
|
+
type: z.z.literal("assistant"),
|
|
31
|
+
message: z.z.object({
|
|
32
|
+
usage: UsageSchema.optional(),
|
|
33
|
+
// Used in apiSession.ts
|
|
34
|
+
model: z.z.string().optional()
|
|
35
|
+
// Used for cost calculation
|
|
36
|
+
}).passthrough().optional()
|
|
37
|
+
}).passthrough(),
|
|
38
|
+
// Summary message - validates summary and leafUuid
|
|
39
|
+
z.z.object({
|
|
40
|
+
type: z.z.literal("summary"),
|
|
41
|
+
summary: z.z.string(),
|
|
42
|
+
// Used in apiSession.ts
|
|
43
|
+
leafUuid: z.z.string()
|
|
44
|
+
// Used in getMessageKey()
|
|
45
|
+
}).passthrough(),
|
|
46
|
+
// System message - validates uuid
|
|
47
|
+
z.z.object({
|
|
48
|
+
type: z.z.literal("system"),
|
|
49
|
+
uuid: z.z.string()
|
|
50
|
+
// Used in getMessageKey()
|
|
51
|
+
}).passthrough(),
|
|
52
|
+
// Progress message - hook progress events, not counted toward message limits
|
|
53
|
+
z.z.object({
|
|
54
|
+
type: z.z.literal("progress"),
|
|
55
|
+
uuid: z.z.string()
|
|
56
|
+
}).passthrough()
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
exports.RawJSONLinesSchema = RawJSONLinesSchema;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var logger = require('./persistence-CBTtC_dm.cjs');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var child_process = require('child_process');
|
|
6
|
+
var path = require('path');
|
|
7
|
+
var os = require('os');
|
|
8
|
+
var systemdScope = require('./systemdScope-DW3-UoKB.cjs');
|
|
9
|
+
var controlClient = require('./controlClient-B23M-WPp.cjs');
|
|
10
|
+
require('node:fs/promises');
|
|
11
|
+
require('node:fs');
|
|
12
|
+
require('node:os');
|
|
13
|
+
require('node:path');
|
|
14
|
+
require('zod');
|
|
15
|
+
require('node:crypto');
|
|
16
|
+
require('tweetnacl');
|
|
17
|
+
require('chalk');
|
|
18
|
+
require('./projectPath-ChLhdOyt.cjs');
|
|
19
|
+
require('url');
|
|
20
|
+
|
|
21
|
+
const PLIST_LABEL = "com.happy-cli.daemon";
|
|
22
|
+
const PLIST_PATH = path.join(os.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
23
|
+
async function uninstall$2() {
|
|
24
|
+
if (!fs.existsSync(PLIST_PATH)) {
|
|
25
|
+
logger.logger.info("No LaunchAgent found. Auto-start is not enabled.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
child_process.execSync(`launchctl unload ${PLIST_PATH}`, { stdio: "ignore" });
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
fs.unlinkSync(PLIST_PATH);
|
|
33
|
+
logger.logger.info("Daemon auto-start disabled.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function uninstall$1() {
|
|
37
|
+
const scopes = [systemdScope.systemdScopeFor(true), systemdScope.systemdScopeFor(false)].filter((scope) => fs.existsSync(scope.unitPath));
|
|
38
|
+
if (scopes.length === 0) {
|
|
39
|
+
logger.logger.info("No systemd service found. Auto-start is not enabled.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const scope of scopes) {
|
|
43
|
+
if (scope.system && !systemdScope.isRootUser()) {
|
|
44
|
+
logger.logger.info(`Skipping ${scope.unitPath} \u2014 removing it needs root: sudo happy daemon disable`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
child_process.execSync(`systemctl ${scope.systemctlFlag} disable --now ${systemdScope.SERVICE_NAME}`.trim(), { stdio: "ignore" });
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
fs.unlinkSync(scope.unitPath);
|
|
52
|
+
try {
|
|
53
|
+
child_process.execSync(`systemctl ${scope.systemctlFlag} daemon-reload`.trim(), { stdio: "ignore" });
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
logger.logger.info(`Removed ${scope.unitPath}`);
|
|
57
|
+
}
|
|
58
|
+
logger.logger.info("Daemon auto-start disabled.");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function uninstall() {
|
|
62
|
+
if (process.platform === "darwin") {
|
|
63
|
+
logger.logger.info("Removing daemon auto-start for macOS...");
|
|
64
|
+
await uninstall$2();
|
|
65
|
+
} else if (process.platform === "linux") {
|
|
66
|
+
logger.logger.info("Removing daemon auto-start for Linux...");
|
|
67
|
+
await uninstall$1();
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`Unsupported platform: ${process.platform}. Only macOS and Linux are supported.`);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await controlClient.stopDaemon();
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
exports.uninstall = uninstall;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { l as logger } from './persistence-DKfF81pd.mjs';
|
|
2
|
+
import { existsSync, unlinkSync } from 'fs';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { s as systemdScopeFor, i as isRootUser, S as SERVICE_NAME } from './systemdScope-BeOtAkhk.mjs';
|
|
7
|
+
import { stopDaemon } from './controlClient-DB5tDU7V.mjs';
|
|
8
|
+
import 'node:fs/promises';
|
|
9
|
+
import 'node:fs';
|
|
10
|
+
import 'node:os';
|
|
11
|
+
import 'node:path';
|
|
12
|
+
import 'zod';
|
|
13
|
+
import 'node:crypto';
|
|
14
|
+
import 'tweetnacl';
|
|
15
|
+
import 'chalk';
|
|
16
|
+
import './projectPath-BTBIMB57.mjs';
|
|
17
|
+
import 'url';
|
|
18
|
+
|
|
19
|
+
const PLIST_LABEL = "com.happy-cli.daemon";
|
|
20
|
+
const PLIST_PATH = join(os.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
21
|
+
async function uninstall$2() {
|
|
22
|
+
if (!existsSync(PLIST_PATH)) {
|
|
23
|
+
logger.info("No LaunchAgent found. Auto-start is not enabled.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
execSync(`launchctl unload ${PLIST_PATH}`, { stdio: "ignore" });
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
unlinkSync(PLIST_PATH);
|
|
31
|
+
logger.info("Daemon auto-start disabled.");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function uninstall$1() {
|
|
35
|
+
const scopes = [systemdScopeFor(true), systemdScopeFor(false)].filter((scope) => existsSync(scope.unitPath));
|
|
36
|
+
if (scopes.length === 0) {
|
|
37
|
+
logger.info("No systemd service found. Auto-start is not enabled.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const scope of scopes) {
|
|
41
|
+
if (scope.system && !isRootUser()) {
|
|
42
|
+
logger.info(`Skipping ${scope.unitPath} \u2014 removing it needs root: sudo happy daemon disable`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
execSync(`systemctl ${scope.systemctlFlag} disable --now ${SERVICE_NAME}`.trim(), { stdio: "ignore" });
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
unlinkSync(scope.unitPath);
|
|
50
|
+
try {
|
|
51
|
+
execSync(`systemctl ${scope.systemctlFlag} daemon-reload`.trim(), { stdio: "ignore" });
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
logger.info(`Removed ${scope.unitPath}`);
|
|
55
|
+
}
|
|
56
|
+
logger.info("Daemon auto-start disabled.");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function uninstall() {
|
|
60
|
+
if (process.platform === "darwin") {
|
|
61
|
+
logger.info("Removing daemon auto-start for macOS...");
|
|
62
|
+
await uninstall$2();
|
|
63
|
+
} else if (process.platform === "linux") {
|
|
64
|
+
logger.info("Removing daemon auto-start for Linux...");
|
|
65
|
+
await uninstall$1();
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error(`Unsupported platform: ${process.platform}. Only macOS and Linux are supported.`);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await stopDaemon();
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { uninstall };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var node_child_process = require('node:child_process');
|
|
5
|
+
var fs = require('node:fs');
|
|
6
|
+
var logger = require('./persistence-CBTtC_dm.cjs');
|
|
7
|
+
var controlClient = require('./controlClient-B23M-WPp.cjs');
|
|
8
|
+
var spawnHappyCLI = require('./spawnHappyCLI-KiazE3kL.cjs');
|
|
9
|
+
require('node:fs/promises');
|
|
10
|
+
require('node:os');
|
|
11
|
+
require('node:path');
|
|
12
|
+
require('zod');
|
|
13
|
+
require('node:crypto');
|
|
14
|
+
require('tweetnacl');
|
|
15
|
+
require('fs');
|
|
16
|
+
require('./projectPath-ChLhdOyt.cjs');
|
|
17
|
+
require('path');
|
|
18
|
+
require('url');
|
|
19
|
+
require('child_process');
|
|
20
|
+
|
|
21
|
+
const PACKAGE_NAME = "@zonease/happy";
|
|
22
|
+
function detectPackageManager() {
|
|
23
|
+
try {
|
|
24
|
+
const whichOutput = node_child_process.execSync("which happy", { encoding: "utf-8" }).trim();
|
|
25
|
+
const realPath = fs.realpathSync(whichOutput);
|
|
26
|
+
if (realPath.includes("/pnpm/") || realPath.includes("/pnpm-global/")) {
|
|
27
|
+
return "pnpm";
|
|
28
|
+
}
|
|
29
|
+
if (realPath.includes("/.yarn/") || realPath.includes("/yarn/")) {
|
|
30
|
+
return "yarn";
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
return "npm";
|
|
35
|
+
}
|
|
36
|
+
function getUpgradeCommand(pm) {
|
|
37
|
+
switch (pm) {
|
|
38
|
+
case "pnpm":
|
|
39
|
+
return ["pnpm", "add", "-g", `${PACKAGE_NAME}@latest`];
|
|
40
|
+
case "yarn":
|
|
41
|
+
return ["yarn", "global", "add", `${PACKAGE_NAME}@latest`];
|
|
42
|
+
case "npm":
|
|
43
|
+
return ["npm", "install", "-g", `${PACKAGE_NAME}@latest`];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function getLatestVersion() {
|
|
47
|
+
try {
|
|
48
|
+
return node_child_process.execFileSync("npm", ["view", PACKAGE_NAME, "version"], { encoding: "utf-8" }).trim();
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function handleUpdateCommand() {
|
|
54
|
+
const currentVersion = logger.packageJson.version;
|
|
55
|
+
console.log(chalk.gray("Checking for updates..."));
|
|
56
|
+
const latestVersion = getLatestVersion();
|
|
57
|
+
if (!latestVersion) {
|
|
58
|
+
console.error(chalk.red("Failed to check latest version. Please check your network connection."));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
console.log(`Current version: ${chalk.cyan(currentVersion)}`);
|
|
62
|
+
console.log(`Latest version: ${chalk.cyan(latestVersion)}`);
|
|
63
|
+
console.log("");
|
|
64
|
+
if (currentVersion === latestVersion) {
|
|
65
|
+
console.log(chalk.green("\u2713 Already up to date"));
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
const pm = detectPackageManager();
|
|
69
|
+
const command = getUpgradeCommand(pm);
|
|
70
|
+
console.log(`Upgrading via ${chalk.bold(pm)}...`);
|
|
71
|
+
try {
|
|
72
|
+
node_child_process.execFileSync(command[0], command.slice(1), { stdio: "inherit" });
|
|
73
|
+
} catch {
|
|
74
|
+
console.error(chalk.red(`
|
|
75
|
+
\u2717 Upgrade failed. You can try manually:`));
|
|
76
|
+
console.error(chalk.gray(` ${command.join(" ")}`));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
console.log(chalk.green(`
|
|
80
|
+
\u2713 Upgraded to ${latestVersion}`));
|
|
81
|
+
try {
|
|
82
|
+
const daemonRunning = await controlClient.checkIfDaemonRunningAndCleanupStaleState();
|
|
83
|
+
if (daemonRunning) {
|
|
84
|
+
console.log("Restarting daemon...");
|
|
85
|
+
await controlClient.stopDaemon();
|
|
86
|
+
const child = spawnHappyCLI.spawnHappyCLI(["daemon", "start-sync"], {
|
|
87
|
+
detached: true,
|
|
88
|
+
stdio: "ignore",
|
|
89
|
+
env: process.env
|
|
90
|
+
});
|
|
91
|
+
child.unref();
|
|
92
|
+
let started = false;
|
|
93
|
+
for (let i = 0; i < 50; i++) {
|
|
94
|
+
if (await controlClient.checkIfDaemonRunningAndCleanupStaleState()) {
|
|
95
|
+
started = true;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
99
|
+
}
|
|
100
|
+
if (started) {
|
|
101
|
+
console.log(chalk.green("\u2713 Daemon restarted"));
|
|
102
|
+
} else {
|
|
103
|
+
console.log(chalk.yellow('\u26A0 Daemon restart timed out. Run "happy daemon start" manually.'));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
exports.handleUpdateCommand = handleUpdateCommand;
|