@zonease/happy 0.6.38 → 0.6.39

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.
Files changed (109) hide show
  1. package/dist/{types-BWpRU1VN.mjs → api-CIZKyfSn.mjs} +136 -1725
  2. package/dist/{types-DvTsFaqR.cjs → api-CwOCQeLH.cjs} +317 -1961
  3. package/dist/auth-0VnlXT9f.mjs +181 -0
  4. package/dist/auth-BE8dD20T.mjs +270 -0
  5. package/dist/auth-BIleVCw0.cjs +274 -0
  6. package/dist/auth-Cas9DR3b.cjs +183 -0
  7. package/dist/browser-Cc08m7of.cjs +22 -0
  8. package/dist/browser-Dll5hxOV.mjs +20 -0
  9. package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
  10. package/dist/claudeLocal-WkgLbl1a.cjs +352 -0
  11. package/dist/codex/happyMcpStdioBridge.cjs +4 -1
  12. package/dist/codex/happyMcpStdioBridge.mjs +4 -1
  13. package/dist/common-BdNgghUJ.mjs +75 -0
  14. package/dist/common-CZvSRU4p.cjs +83 -0
  15. package/dist/{config-0Xnc8ARM.cjs → config-Draa-5XC.cjs} +21 -34
  16. package/dist/{config-_GW4YBCP.mjs → config-rTT4qTU5.mjs} +7 -20
  17. package/dist/connect-BfC1tYP_.mjs +679 -0
  18. package/dist/connect-CJZ73syK.cjs +681 -0
  19. package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
  20. package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
  21. package/dist/controlClient-CM_QcJnB.mjs +159 -0
  22. package/dist/controlClient-DZMIsKsT.cjs +168 -0
  23. package/dist/deviceExec-CU1R9CRb.cjs +84 -0
  24. package/dist/deviceExec-D93AOVV4.mjs +81 -0
  25. package/dist/diagnose-B3D1a_v0.cjs +60 -0
  26. package/dist/diagnose-CuRKXxt1.mjs +58 -0
  27. package/dist/doctor-C08m5Z9f.cjs +78 -0
  28. package/dist/doctor-Cya9YSA0.cjs +214 -0
  29. package/dist/doctor-DZYB6IVc.mjs +211 -0
  30. package/dist/doctor-ON7pN5G5.mjs +74 -0
  31. package/dist/downloadImage-DfSFLb-h.mjs +887 -0
  32. package/dist/downloadImage-MQMrUUxS.cjs +897 -0
  33. package/dist/enroll-BxlbVftP.cjs +115 -0
  34. package/dist/enroll-C52x8oly.mjs +113 -0
  35. package/dist/evidence-Ccd9iYcj.mjs +127 -0
  36. package/dist/evidence-CjWBG5rX.cjs +129 -0
  37. package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
  38. package/dist/formatImageMessage-DbyG8c2j.cjs +46 -0
  39. package/dist/github-DKcyF1zp.mjs +57 -0
  40. package/dist/github-h9GhJJ_C.cjs +59 -0
  41. package/dist/index-CDTNgfUf.cjs +578 -0
  42. package/dist/index-CPKdvi7J.mjs +554 -0
  43. package/dist/index.cjs +812 -40
  44. package/dist/index.mjs +813 -40
  45. package/dist/install-BokHRgFW.cjs +98 -0
  46. package/dist/install-C_cp8b2-.cjs +96 -0
  47. package/dist/install-DAeCn8ae.mjs +94 -0
  48. package/dist/install-oRAjVLjP.mjs +95 -0
  49. package/dist/lib.cjs +18 -12
  50. package/dist/lib.mjs +13 -7
  51. package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
  52. package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
  53. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  54. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  55. package/dist/persistence-BFjvtUad.mjs +944 -0
  56. package/dist/persistence-JLUn_Nou.cjs +996 -0
  57. package/dist/projectPath-BTBIMB57.mjs +10 -0
  58. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  59. package/dist/prompt-BTWDZZO0.cjs +25 -0
  60. package/dist/prompt-BsAZsPbo.mjs +22 -0
  61. package/dist/release-BMEzNONE.mjs +168 -0
  62. package/dist/release-EhOJeAZe.cjs +171 -0
  63. package/dist/run-BDn2aE3Q.cjs +2152 -0
  64. package/dist/run-DBZqN6Kn.mjs +2128 -0
  65. package/dist/runClaude-DNHvERX0.mjs +3763 -0
  66. package/dist/runClaude-uaKxPZPm.cjs +3766 -0
  67. package/dist/{runCodex-skq0j05d.cjs → runCodex-82UrZLme.cjs} +169 -153
  68. package/dist/{runCodex-DiKzBf9q.mjs → runCodex-C-RTM0wA.mjs} +36 -20
  69. package/dist/{runGemini-BeqrVq8R.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
  70. package/dist/{runGemini-CVp-CEIh.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
  71. package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
  72. package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-ioARRHrx.mjs} +14 -38
  73. package/dist/{serve-BECdtivY.cjs → serve-BtdAhkIE.cjs} +35 -58
  74. package/dist/{serve-BNdoEDVx.mjs → serve-CwibwU6N.mjs} +12 -35
  75. package/dist/session-2sU4Bu1R.mjs +108 -0
  76. package/dist/session-D--F87zL.cjs +110 -0
  77. package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
  78. package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
  79. package/dist/sessionList-BCSw3qYt.mjs +51 -0
  80. package/dist/sessionList-ICJsjNtJ.cjs +54 -0
  81. package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
  82. package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
  83. package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
  84. package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
  85. package/dist/ssh-BTOlhhxi.cjs +333 -0
  86. package/dist/ssh-DL_AkRAD.mjs +328 -0
  87. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  88. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  89. package/dist/task-CQzrHRZe.mjs +165 -0
  90. package/dist/task-CSpaC9HX.cjs +167 -0
  91. package/dist/time-Bj2HRkKH.cjs +33 -0
  92. package/dist/time-DgsBLJA_.mjs +29 -0
  93. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  94. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  95. package/dist/types-BoJh4Qfv.mjs +57 -0
  96. package/dist/types-DWeB7aqh.cjs +59 -0
  97. package/dist/uninstall-BiKyRAb1.cjs +77 -0
  98. package/dist/uninstall-nFMFGUVM.mjs +75 -0
  99. package/dist/update-BcqRHXf2.mjs +109 -0
  100. package/dist/update-Dw8pgsAT.cjs +111 -0
  101. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  102. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  103. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  104. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  105. package/package.json +1 -1
  106. package/dist/index-BbCDDvoB.cjs +0 -11376
  107. package/dist/index-vvZXdswy.mjs +0 -11336
  108. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  109. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var path = require('node:path');
4
+ var os = require('node:os');
5
+
6
+ const SERVICE_NAME = "happy-daemon.service";
7
+ function systemdScopeFor(isRoot) {
8
+ if (isRoot) {
9
+ return {
10
+ system: true,
11
+ unitPath: path.join("/etc/systemd/system", SERVICE_NAME),
12
+ systemctlFlag: "",
13
+ wantedBy: "multi-user.target"
14
+ };
15
+ }
16
+ return {
17
+ system: false,
18
+ unitPath: path.join(os.homedir(), ".config", "systemd", "user", SERVICE_NAME),
19
+ systemctlFlag: "--user",
20
+ wantedBy: "default.target"
21
+ };
22
+ }
23
+ function isRootUser() {
24
+ return typeof process.getuid === "function" && process.getuid() === 0;
25
+ }
26
+
27
+ exports.SERVICE_NAME = SERVICE_NAME;
28
+ exports.isRootUser = isRootUser;
29
+ exports.systemdScopeFor = systemdScopeFor;
@@ -0,0 +1,165 @@
1
+ import chalk from 'chalk';
2
+ import { resolve } from 'node:path';
3
+ import { r as readCredentials } from './persistence-BFjvtUad.mjs';
4
+ import { r as runSessionList } from './sessionList-BCSw3qYt.mjs';
5
+ import { r as runSessionSummary } from './sessionSummary-lHGBWQSb.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-BE8dD20T.mjs';
16
+ import 'qrcode-terminal';
17
+ import './time-DgsBLJA_.mjs';
18
+ import './browser-Dll5hxOV.mjs';
19
+ import 'open';
20
+ import 'react';
21
+ import 'ink';
22
+ import './sessionKeyCache-D2BwO91C.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,167 @@
1
+ 'use strict';
2
+
3
+ var chalk = require('chalk');
4
+ var path = require('node:path');
5
+ var logger = require('./persistence-JLUn_Nou.cjs');
6
+ var sessionList = require('./sessionList-ICJsjNtJ.cjs');
7
+ var sessionSummary = require('./sessionSummary-Bkz52BPh.cjs');
8
+ var workflowCommon = require('./workflowCommon-Bl568-rt.cjs');
9
+ require('node:fs/promises');
10
+ require('node:fs');
11
+ require('node:os');
12
+ require('zod');
13
+ require('node:crypto');
14
+ require('tweetnacl');
15
+ require('fs');
16
+ require('axios');
17
+ require('./auth-BIleVCw0.cjs');
18
+ require('qrcode-terminal');
19
+ require('./time-Bj2HRkKH.cjs');
20
+ require('./browser-Cc08m7of.cjs');
21
+ require('open');
22
+ require('react');
23
+ require('ink');
24
+ require('./sessionKeyCache-4Tp8pJ3N.cjs');
25
+
26
+ function printTaskHelp() {
27
+ console.log(`
28
+ ${chalk.bold("happy task")} - Agent handoff helpers
29
+
30
+ ${chalk.bold("Usage:")}
31
+ happy task brief --session <sessionId> [options]
32
+ happy task brief <sessionId> [options]
33
+ happy task brief --recent [--project <path>] [options]
34
+
35
+ ${chalk.bold("Options:")}
36
+ --session <id> Happy session ID to summarize
37
+ --recent Pick the most recent session, optionally filtered by --project
38
+ --project <path> Project path filter for --recent
39
+ --limit <n> Raw messages to compact (default: 200)
40
+ --max-turns <n> Compact turns to include (default: 80)
41
+ --text-limit <n> Max chars per text block (default: 800)
42
+ --out <path> Write the brief to a markdown file
43
+ --json Print machine-readable JSON
44
+ -h, --help Show this help
45
+ `);
46
+ }
47
+ function collectSessionText(summary) {
48
+ const chunks = [];
49
+ if (summary.storedSummary) chunks.push(summary.storedSummary);
50
+ for (const turn of summary.turns) {
51
+ if (turn.user?.text) chunks.push(turn.user.text);
52
+ for (const text of turn.assistantTexts) chunks.push(text.text);
53
+ }
54
+ return chunks.join("\n");
55
+ }
56
+ function extractMatchingLines(text, patterns, limit) {
57
+ const seen = /* @__PURE__ */ new Set();
58
+ const lines = [];
59
+ for (const line of text.split("\n")) {
60
+ const trimmed = line.replace(/^[-*]\s*/, "").trim();
61
+ if (!trimmed || seen.has(trimmed)) continue;
62
+ if (patterns.some((pattern) => pattern.test(trimmed))) {
63
+ seen.add(trimmed);
64
+ lines.push(trimmed);
65
+ }
66
+ if (lines.length >= limit) break;
67
+ }
68
+ return lines;
69
+ }
70
+ function bulletList(lines, fallback) {
71
+ if (lines.length === 0) return `- ${fallback}`;
72
+ return lines.map((line) => `- ${line}`).join("\n");
73
+ }
74
+ function buildBriefMarkdown(summary, source) {
75
+ const text = collectSessionText(summary);
76
+ const done = extractMatchingLines(text, [/完成|已实现|通过|passed|fixed|implemented|verified/i], 6);
77
+ const blockers = extractMatchingLines(text, [/失败|阻塞|blocked|failed|error|E401|unrelated/i], 6);
78
+ const next = extractMatchingLines(text, [/继续|下一步|TODO|todo|next|publish|发布|验证|verify/i], 6);
79
+ return `# Happy Task Brief
80
+
81
+ - Source: ${source}
82
+ - Session: \`${summary.sessionId}\`
83
+ - Active: ${summary.active ? "yes" : "no"}
84
+ - Agent: ${summary.agent.name ?? "(unknown)"}${summary.agent.model ? ` / ${summary.agent.model}` : ""}
85
+ - Machine: ${summary.machine.name ?? summary.machine.id ?? "(unknown)"}
86
+ - Path: ${summary.path ?? "(unknown)"}
87
+ - Updated: ${new Date(summary.updatedAt).toISOString()}
88
+
89
+ ## Stored Summary
90
+
91
+ ${summary.storedSummary ?? "(none)"}
92
+
93
+ ## Recent Conversation
94
+
95
+ ${summary.summaryText}
96
+
97
+ ## Done / Evidence
98
+
99
+ ${bulletList(done, "No explicit completion evidence detected in the compact window.")}
100
+
101
+ ## Blockers / Risks
102
+
103
+ ${bulletList(blockers, "No explicit blocker detected in the compact window.")}
104
+
105
+ ## Suggested Next Actions
106
+
107
+ ${bulletList(next, "Continue from the latest user request and verify before reporting completion.")}
108
+
109
+ ## Continuation Prompt
110
+
111
+ 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.
112
+ `;
113
+ }
114
+ function findRecentSession(sessions, projectPath) {
115
+ if (!projectPath) return sessions[0];
116
+ const resolved = path.resolve(projectPath);
117
+ return sessions.find((session) => {
118
+ if (!session.path) return false;
119
+ const path$1 = path.resolve(session.path);
120
+ return path$1 === resolved || path$1.startsWith(`${resolved}/`) || resolved.startsWith(`${path$1}/`);
121
+ });
122
+ }
123
+ async function handleTaskCommand(args) {
124
+ const action = args[0];
125
+ if (!action || action === "-h" || action === "--help") {
126
+ printTaskHelp();
127
+ return;
128
+ }
129
+ if (action !== "brief") {
130
+ throw new Error(`Unknown task command: ${action}. Use "happy task brief".`);
131
+ }
132
+ const parsed = workflowCommon.parseWorkflowArgs(args.slice(1), /* @__PURE__ */ new Set(["--session", "--project", "--limit", "--max-turns", "--text-limit", "--out"]));
133
+ const credentials = await logger.readCredentials();
134
+ if (!credentials) {
135
+ throw new Error('No happy credentials found. Run "happy auth login" first.');
136
+ }
137
+ let sessionId = workflowCommon.stringFlag(parsed, "--session") ?? parsed.positionals[0];
138
+ let source = "session";
139
+ if (!sessionId && workflowCommon.booleanFlag(parsed, "--recent")) {
140
+ const result = await sessionList.runSessionList(credentials, { status: "all", limit: 150 });
141
+ const recent = findRecentSession(result.sessions, workflowCommon.stringFlag(parsed, "--project"));
142
+ if (!recent) {
143
+ throw new Error("No matching recent session found.");
144
+ }
145
+ sessionId = recent.sessionId;
146
+ source = "recent";
147
+ }
148
+ if (!sessionId) {
149
+ throw new Error('Session ID required. Use "happy task brief --session <id>" or "--recent".');
150
+ }
151
+ const input = {
152
+ sessionId,
153
+ limit: workflowCommon.numberFlag(parsed, "--limit"),
154
+ maxTurns: workflowCommon.numberFlag(parsed, "--max-turns"),
155
+ textLimit: workflowCommon.numberFlag(parsed, "--text-limit"),
156
+ includeTools: true
157
+ };
158
+ const summary = await sessionSummary.runSessionSummary(credentials, input);
159
+ const brief = buildBriefMarkdown(summary, source);
160
+ if (workflowCommon.booleanFlag(parsed, "--json")) {
161
+ console.log(JSON.stringify({ source, summary, brief }, null, 2));
162
+ return;
163
+ }
164
+ await workflowCommon.printOrWriteOutput(brief, workflowCommon.stringFlag(parsed, "--out"));
165
+ }
166
+
167
+ exports.handleTaskCommand = 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-JLUn_Nou.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-DZMIsKsT.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;