@zonease/happy 0.6.37 → 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 (111) hide show
  1. package/dist/{types-DYCJXXdA.mjs → api-CIZKyfSn.mjs} +136 -1725
  2. package/dist/{types-BrTorNAy.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-D_g6ohaV.cjs → config-Draa-5XC.cjs} +21 -34
  16. package/dist/{config-DPn-cbpz.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.d.cts +16 -16
  51. package/dist/lib.d.mts +16 -16
  52. package/dist/lib.mjs +13 -7
  53. package/dist/{loadableToolOutput-lQH8Kb_w.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
  54. package/dist/{loadableToolOutput-CasonFIt.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
  55. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  56. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  57. package/dist/persistence-BFjvtUad.mjs +944 -0
  58. package/dist/persistence-JLUn_Nou.cjs +996 -0
  59. package/dist/projectPath-BTBIMB57.mjs +10 -0
  60. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  61. package/dist/prompt-BTWDZZO0.cjs +25 -0
  62. package/dist/prompt-BsAZsPbo.mjs +22 -0
  63. package/dist/release-BMEzNONE.mjs +168 -0
  64. package/dist/release-EhOJeAZe.cjs +171 -0
  65. package/dist/run-BDn2aE3Q.cjs +2152 -0
  66. package/dist/run-DBZqN6Kn.mjs +2128 -0
  67. package/dist/runClaude-DNHvERX0.mjs +3763 -0
  68. package/dist/runClaude-uaKxPZPm.cjs +3766 -0
  69. package/dist/{runCodex-BTt3fxG4.cjs → runCodex-82UrZLme.cjs} +169 -153
  70. package/dist/{runCodex-BXCB5trB.mjs → runCodex-C-RTM0wA.mjs} +36 -20
  71. package/dist/{runGemini-37HHbp9n.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
  72. package/dist/{runGemini-C-0nSFBv.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
  73. package/dist/{runOneShot-CXhbFJ2j.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
  74. package/dist/{runOneShot-USX8QPfE.mjs → runOneShot-ioARRHrx.mjs} +14 -38
  75. package/dist/{serve-DZAq-_1F.cjs → serve-BtdAhkIE.cjs} +35 -58
  76. package/dist/{serve-BRedJPzL.mjs → serve-CwibwU6N.mjs} +12 -35
  77. package/dist/session-2sU4Bu1R.mjs +108 -0
  78. package/dist/session-D--F87zL.cjs +110 -0
  79. package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
  80. package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
  81. package/dist/sessionList-BCSw3qYt.mjs +51 -0
  82. package/dist/sessionList-ICJsjNtJ.cjs +54 -0
  83. package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
  84. package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
  85. package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
  86. package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
  87. package/dist/ssh-BTOlhhxi.cjs +333 -0
  88. package/dist/ssh-DL_AkRAD.mjs +328 -0
  89. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  90. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  91. package/dist/task-CQzrHRZe.mjs +165 -0
  92. package/dist/task-CSpaC9HX.cjs +167 -0
  93. package/dist/time-Bj2HRkKH.cjs +33 -0
  94. package/dist/time-DgsBLJA_.mjs +29 -0
  95. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  96. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  97. package/dist/types-BoJh4Qfv.mjs +57 -0
  98. package/dist/types-DWeB7aqh.cjs +59 -0
  99. package/dist/uninstall-BiKyRAb1.cjs +77 -0
  100. package/dist/uninstall-nFMFGUVM.mjs +75 -0
  101. package/dist/update-BcqRHXf2.mjs +109 -0
  102. package/dist/update-Dw8pgsAT.cjs +111 -0
  103. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  104. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  105. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  106. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  107. package/package.json +1 -1
  108. package/dist/index-BlkHOkB3.cjs +0 -11312
  109. package/dist/index-DJ2VpGiR.mjs +0 -11272
  110. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  111. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
@@ -0,0 +1,344 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { resolve, join } from 'node:path';
3
+ import { createInterface } from 'node:readline';
4
+ import { existsSync, readFileSync, readdirSync, statSync, mkdirSync } from 'node:fs';
5
+ import { randomUUID } from 'node:crypto';
6
+ import { l as logger } from './persistence-BFjvtUad.mjs';
7
+ import { homedir } from 'node:os';
8
+ import { p as projectPath } from './projectPath-BTBIMB57.mjs';
9
+ import { g as getBaseSystemPrompt } from './prompt-BsAZsPbo.mjs';
10
+
11
+ function getProjectPath(workingDirectory) {
12
+ const projectId = resolve(workingDirectory).replace(/[^a-zA-Z0-9-]/g, "-");
13
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
14
+ return join(claudeConfigDir, "projects", projectId);
15
+ }
16
+
17
+ function claudeCheckSession(sessionId, path) {
18
+ const projectDir = getProjectPath(path);
19
+ const sessionFile = join(projectDir, `${sessionId}.jsonl`);
20
+ const sessionExists = existsSync(sessionFile);
21
+ if (!sessionExists) {
22
+ logger.debug(`[claudeCheckSession] Path ${sessionFile} does not exist`);
23
+ return false;
24
+ }
25
+ const sessionData = readFileSync(sessionFile, "utf-8").split("\n");
26
+ const hasGoodMessage = !!sessionData.find((v, index) => {
27
+ if (!v.trim()) return false;
28
+ try {
29
+ const parsed = JSON.parse(v);
30
+ return typeof parsed.uuid === "string" && parsed.uuid.length > 0 || // Claude Code 2.1.x
31
+ typeof parsed.messageId === "string" && parsed.messageId.length > 0 || // Older Claude Code
32
+ typeof parsed.leafUuid === "string" && parsed.leafUuid.length > 0;
33
+ } catch (e) {
34
+ logger.debug(`[claudeCheckSession] Malformed JSON at line ${index + 1}:`, e);
35
+ return false;
36
+ }
37
+ });
38
+ logger.debug(`[claudeCheckSession] Session ${sessionId}: ${hasGoodMessage ? "valid" : "invalid"}`);
39
+ return hasGoodMessage;
40
+ }
41
+
42
+ function claudeFindLastSession(workingDirectory) {
43
+ try {
44
+ const projectDir = getProjectPath(workingDirectory);
45
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
46
+ const files = readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
47
+ const sessionId = f.replace(".jsonl", "");
48
+ if (!uuidPattern.test(sessionId)) {
49
+ return null;
50
+ }
51
+ if (claudeCheckSession(sessionId, workingDirectory)) {
52
+ return {
53
+ name: f,
54
+ sessionId,
55
+ mtime: statSync(join(projectDir, f)).mtime.getTime()
56
+ };
57
+ }
58
+ return null;
59
+ }).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
60
+ return files.length > 0 ? files[0].sessionId : null;
61
+ } catch (e) {
62
+ logger.debug("[claudeFindLastSession] Error finding sessions:", e);
63
+ return null;
64
+ }
65
+ }
66
+
67
+ const DEFAULT_COMMIT_ATTRIBUTION = [
68
+ "Generated with [Claude Code](https://claude.ai/code)",
69
+ "",
70
+ "Co-Authored-By: Claude <noreply@anthropic.com>"
71
+ ].join("\n");
72
+ function getClaudeSettingsPath() {
73
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
74
+ return join(claudeConfigDir, "settings.json");
75
+ }
76
+ function readClaudeSettings() {
77
+ try {
78
+ const settingsPath = getClaudeSettingsPath();
79
+ if (!existsSync(settingsPath)) {
80
+ logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
81
+ return null;
82
+ }
83
+ const settingsContent = readFileSync(settingsPath, "utf-8");
84
+ const settings = JSON.parse(settingsContent);
85
+ logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
86
+ logger.debug(`[ClaudeSettings] attribution: ${JSON.stringify(settings.attribution)}, includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
87
+ return settings;
88
+ } catch (error) {
89
+ logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
90
+ return null;
91
+ }
92
+ }
93
+ function getCommitAttribution() {
94
+ const settings = readClaudeSettings();
95
+ if (!settings) return null;
96
+ if (settings.attribution?.commit !== void 0) {
97
+ return settings.attribution.commit || null;
98
+ }
99
+ if (settings.includeCoAuthoredBy === true) {
100
+ return DEFAULT_COMMIT_ATTRIBUTION;
101
+ }
102
+ return null;
103
+ }
104
+
105
+ const systemPrompt = (() => {
106
+ const base = getBaseSystemPrompt();
107
+ if (base === null) return "";
108
+ const attribution = getCommitAttribution();
109
+ if (!attribution) return base;
110
+ return base + "\n\n# Commit\n\nWhen making commit messages, add this footer:\n\n" + attribution;
111
+ })();
112
+
113
+ class ExitCodeError extends Error {
114
+ exitCode;
115
+ constructor(exitCode) {
116
+ super(`Process exited with code: ${exitCode}`);
117
+ this.name = "ExitCodeError";
118
+ this.exitCode = exitCode;
119
+ }
120
+ }
121
+ const claudeCliPath = resolve(join(projectPath(), "scripts", "claude_local_launcher.cjs"));
122
+ async function claudeLocal(opts) {
123
+ const projectDir = getProjectPath(opts.path);
124
+ mkdirSync(projectDir, { recursive: true });
125
+ const hasContinueFlag = opts.claudeArgs?.includes("--continue");
126
+ const hasResumeFlag = opts.claudeArgs?.includes("--resume");
127
+ const hasUserSessionControl = hasContinueFlag || hasResumeFlag;
128
+ let startFrom = opts.sessionId;
129
+ const extractFlag = (flags, withValue = false) => {
130
+ if (!opts.claudeArgs) return { found: false };
131
+ for (const flag of flags) {
132
+ const index = opts.claudeArgs.indexOf(flag);
133
+ if (index !== -1) {
134
+ if (withValue && index + 1 < opts.claudeArgs.length) {
135
+ const nextArg = opts.claudeArgs[index + 1];
136
+ if (!nextArg.startsWith("-")) {
137
+ const value = nextArg;
138
+ opts.claudeArgs = opts.claudeArgs.filter((_, i) => i !== index && i !== index + 1);
139
+ return { found: true, value };
140
+ }
141
+ }
142
+ if (!withValue) {
143
+ opts.claudeArgs = opts.claudeArgs.filter((_, i) => i !== index);
144
+ return { found: true };
145
+ }
146
+ return { found: false };
147
+ }
148
+ }
149
+ return { found: false };
150
+ };
151
+ const sessionIdFlag = extractFlag(["--session-id"], true);
152
+ if (sessionIdFlag.found && sessionIdFlag.value) {
153
+ startFrom = null;
154
+ logger.debug(`[ClaudeLocal] Using explicit --session-id: ${sessionIdFlag.value}`);
155
+ }
156
+ if (!startFrom && !sessionIdFlag.value) {
157
+ const resumeFlag = extractFlag(["--resume", "-r"], true);
158
+ if (resumeFlag.found) {
159
+ if (resumeFlag.value) {
160
+ startFrom = resumeFlag.value;
161
+ logger.debug(`[ClaudeLocal] Using provided session ID from --resume: ${startFrom}`);
162
+ } else {
163
+ const lastSession = claudeFindLastSession(opts.path);
164
+ if (lastSession) {
165
+ startFrom = lastSession;
166
+ logger.debug(`[ClaudeLocal] --resume: Found last session: ${lastSession}`);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ if (!startFrom && !sessionIdFlag.value) {
172
+ const continueFlag = extractFlag(["--continue", "-c"], false);
173
+ if (continueFlag.found) {
174
+ const lastSession = claudeFindLastSession(opts.path);
175
+ if (lastSession) {
176
+ startFrom = lastSession;
177
+ logger.debug(`[ClaudeLocal] --continue: Found last session: ${lastSession}`);
178
+ }
179
+ }
180
+ }
181
+ const explicitSessionId = sessionIdFlag.value || null;
182
+ let newSessionId = null;
183
+ let effectiveSessionId = startFrom;
184
+ if (!opts.hookSettingsPath) {
185
+ newSessionId = startFrom ? null : explicitSessionId || randomUUID();
186
+ effectiveSessionId = startFrom || newSessionId;
187
+ if (startFrom) {
188
+ logger.debug(`[ClaudeLocal] Resuming session: ${startFrom}`);
189
+ opts.onSessionFound(startFrom);
190
+ } else if (explicitSessionId) {
191
+ logger.debug(`[ClaudeLocal] Using explicit session ID: ${explicitSessionId}`);
192
+ opts.onSessionFound(explicitSessionId);
193
+ } else {
194
+ logger.debug(`[ClaudeLocal] Generated new session ID: ${newSessionId}`);
195
+ opts.onSessionFound(newSessionId);
196
+ }
197
+ } else {
198
+ if (startFrom) {
199
+ logger.debug(`[ClaudeLocal] Will resume existing session: ${startFrom}`);
200
+ } else if (hasUserSessionControl) {
201
+ logger.debug(`[ClaudeLocal] User passed ${hasContinueFlag ? "--continue" : "--resume"} flag, session ID will be determined by hook`);
202
+ } else {
203
+ logger.debug(`[ClaudeLocal] Fresh start, session ID will be provided by hook`);
204
+ }
205
+ }
206
+ let thinking = false;
207
+ let stopThinkingTimeout = null;
208
+ const updateThinking = (newThinking) => {
209
+ if (thinking !== newThinking) {
210
+ thinking = newThinking;
211
+ logger.debug(`[ClaudeLocal] Thinking state changed to: ${thinking}`);
212
+ if (opts.onThinkingChange) {
213
+ opts.onThinkingChange(thinking);
214
+ }
215
+ }
216
+ };
217
+ try {
218
+ process.stdin.pause();
219
+ await new Promise((r, reject) => {
220
+ const args = [];
221
+ if (!opts.hookSettingsPath) {
222
+ const hasResumeFlag2 = opts.claudeArgs?.includes("--resume") || opts.claudeArgs?.includes("-r");
223
+ if (startFrom) {
224
+ args.push("--resume", startFrom);
225
+ } else if (!hasResumeFlag2 && newSessionId) {
226
+ args.push("--session-id", newSessionId);
227
+ }
228
+ } else {
229
+ if (startFrom) {
230
+ args.push("--resume", startFrom);
231
+ }
232
+ }
233
+ args.push("--append-system-prompt", systemPrompt);
234
+ if (opts.mcpServers && Object.keys(opts.mcpServers).length > 0) {
235
+ args.push("--mcp-config", JSON.stringify({ mcpServers: opts.mcpServers }));
236
+ }
237
+ if (opts.allowedTools && opts.allowedTools.length > 0) {
238
+ args.push("--allowedTools", opts.allowedTools.join(","));
239
+ }
240
+ if (opts.claudeArgs) {
241
+ args.push(...opts.claudeArgs);
242
+ }
243
+ if (opts.hookSettingsPath) {
244
+ args.push("--settings", opts.hookSettingsPath);
245
+ logger.debug(`[ClaudeLocal] Using hook settings: ${opts.hookSettingsPath}`);
246
+ }
247
+ if (!claudeCliPath || !existsSync(claudeCliPath)) {
248
+ throw new Error("Claude local launcher not found. Please ensure HAPPY_PROJECT_ROOT is set correctly for development.");
249
+ }
250
+ const env = {
251
+ ...process.env,
252
+ ...opts.claudeEnvVars
253
+ };
254
+ logger.debug(`[ClaudeLocal] Spawning launcher: ${claudeCliPath}`);
255
+ logger.debug(`[ClaudeLocal] Args: ${JSON.stringify(args)}`);
256
+ const child = spawn("node", [claudeCliPath, ...args], {
257
+ stdio: ["inherit", "inherit", "inherit", "pipe"],
258
+ signal: opts.abort,
259
+ cwd: opts.path,
260
+ env
261
+ });
262
+ if (child.stdio[3]) {
263
+ const rl = createInterface({
264
+ input: child.stdio[3],
265
+ crlfDelay: Infinity
266
+ });
267
+ const activeFetches = /* @__PURE__ */ new Map();
268
+ rl.on("line", (line) => {
269
+ try {
270
+ const message = JSON.parse(line);
271
+ switch (message.type) {
272
+ case "fetch-start":
273
+ activeFetches.set(message.id, {
274
+ hostname: message.hostname,
275
+ path: message.path,
276
+ startTime: message.timestamp
277
+ });
278
+ if (stopThinkingTimeout) {
279
+ clearTimeout(stopThinkingTimeout);
280
+ stopThinkingTimeout = null;
281
+ }
282
+ updateThinking(true);
283
+ break;
284
+ case "fetch-end":
285
+ activeFetches.delete(message.id);
286
+ if (activeFetches.size === 0 && thinking && !stopThinkingTimeout) {
287
+ stopThinkingTimeout = setTimeout(() => {
288
+ if (activeFetches.size === 0) {
289
+ updateThinking(false);
290
+ }
291
+ stopThinkingTimeout = null;
292
+ }, 500);
293
+ }
294
+ break;
295
+ default:
296
+ logger.debug(`[ClaudeLocal] Unknown message type: ${message.type}`);
297
+ }
298
+ } catch (e) {
299
+ logger.debug(`[ClaudeLocal] Non-JSON line from fd3: ${line}`);
300
+ }
301
+ });
302
+ rl.on("error", (err) => {
303
+ console.error("Error reading from fd 3:", err);
304
+ });
305
+ child.on("exit", () => {
306
+ if (stopThinkingTimeout) {
307
+ clearTimeout(stopThinkingTimeout);
308
+ }
309
+ updateThinking(false);
310
+ });
311
+ }
312
+ child.on("error", (error) => {
313
+ });
314
+ child.on("exit", (code, signal) => {
315
+ if (signal === "SIGTERM" && opts.abort.aborted) {
316
+ r();
317
+ } else if (signal) {
318
+ reject(new Error(`Process terminated with signal: ${signal}`));
319
+ } else if (code !== 0 && code !== null) {
320
+ reject(new ExitCodeError(code));
321
+ } else {
322
+ r();
323
+ }
324
+ });
325
+ });
326
+ } finally {
327
+ process.stdin.resume();
328
+ if (stopThinkingTimeout) {
329
+ clearTimeout(stopThinkingTimeout);
330
+ stopThinkingTimeout = null;
331
+ }
332
+ updateThinking(false);
333
+ }
334
+ return effectiveSessionId;
335
+ }
336
+
337
+ var claudeLocal$1 = /*#__PURE__*/Object.freeze({
338
+ __proto__: null,
339
+ ExitCodeError: ExitCodeError,
340
+ claudeCliPath: claudeCliPath,
341
+ claudeLocal: claudeLocal
342
+ });
343
+
344
+ export { ExitCodeError as E, claudeLocal as a, claudeCheckSession as b, claudeCliPath as c, claudeLocal$1 as d, getProjectPath as g, systemPrompt as s };
@@ -0,0 +1,352 @@
1
+ 'use strict';
2
+
3
+ var node_child_process = require('node:child_process');
4
+ var path = require('node:path');
5
+ var node_readline = require('node:readline');
6
+ var fs = require('node:fs');
7
+ var node_crypto = require('node:crypto');
8
+ var logger = require('./persistence-JLUn_Nou.cjs');
9
+ var os = require('node:os');
10
+ var projectPath = require('./projectPath-ChLhdOyt.cjs');
11
+ var prompt = require('./prompt-BTWDZZO0.cjs');
12
+
13
+ function getProjectPath(workingDirectory) {
14
+ const projectId = path.resolve(workingDirectory).replace(/[^a-zA-Z0-9-]/g, "-");
15
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
16
+ return path.join(claudeConfigDir, "projects", projectId);
17
+ }
18
+
19
+ function claudeCheckSession(sessionId, path$1) {
20
+ const projectDir = getProjectPath(path$1);
21
+ const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);
22
+ const sessionExists = fs.existsSync(sessionFile);
23
+ if (!sessionExists) {
24
+ logger.logger.debug(`[claudeCheckSession] Path ${sessionFile} does not exist`);
25
+ return false;
26
+ }
27
+ const sessionData = fs.readFileSync(sessionFile, "utf-8").split("\n");
28
+ const hasGoodMessage = !!sessionData.find((v, index) => {
29
+ if (!v.trim()) return false;
30
+ try {
31
+ const parsed = JSON.parse(v);
32
+ return typeof parsed.uuid === "string" && parsed.uuid.length > 0 || // Claude Code 2.1.x
33
+ typeof parsed.messageId === "string" && parsed.messageId.length > 0 || // Older Claude Code
34
+ typeof parsed.leafUuid === "string" && parsed.leafUuid.length > 0;
35
+ } catch (e) {
36
+ logger.logger.debug(`[claudeCheckSession] Malformed JSON at line ${index + 1}:`, e);
37
+ return false;
38
+ }
39
+ });
40
+ logger.logger.debug(`[claudeCheckSession] Session ${sessionId}: ${hasGoodMessage ? "valid" : "invalid"}`);
41
+ return hasGoodMessage;
42
+ }
43
+
44
+ function claudeFindLastSession(workingDirectory) {
45
+ try {
46
+ const projectDir = getProjectPath(workingDirectory);
47
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
48
+ const files = fs.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => {
49
+ const sessionId = f.replace(".jsonl", "");
50
+ if (!uuidPattern.test(sessionId)) {
51
+ return null;
52
+ }
53
+ if (claudeCheckSession(sessionId, workingDirectory)) {
54
+ return {
55
+ name: f,
56
+ sessionId,
57
+ mtime: fs.statSync(path.join(projectDir, f)).mtime.getTime()
58
+ };
59
+ }
60
+ return null;
61
+ }).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
62
+ return files.length > 0 ? files[0].sessionId : null;
63
+ } catch (e) {
64
+ logger.logger.debug("[claudeFindLastSession] Error finding sessions:", e);
65
+ return null;
66
+ }
67
+ }
68
+
69
+ const DEFAULT_COMMIT_ATTRIBUTION = [
70
+ "Generated with [Claude Code](https://claude.ai/code)",
71
+ "",
72
+ "Co-Authored-By: Claude <noreply@anthropic.com>"
73
+ ].join("\n");
74
+ function getClaudeSettingsPath() {
75
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
76
+ return path.join(claudeConfigDir, "settings.json");
77
+ }
78
+ function readClaudeSettings() {
79
+ try {
80
+ const settingsPath = getClaudeSettingsPath();
81
+ if (!fs.existsSync(settingsPath)) {
82
+ logger.logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
83
+ return null;
84
+ }
85
+ const settingsContent = fs.readFileSync(settingsPath, "utf-8");
86
+ const settings = JSON.parse(settingsContent);
87
+ logger.logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
88
+ logger.logger.debug(`[ClaudeSettings] attribution: ${JSON.stringify(settings.attribution)}, includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
89
+ return settings;
90
+ } catch (error) {
91
+ logger.logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
92
+ return null;
93
+ }
94
+ }
95
+ function getCommitAttribution() {
96
+ const settings = readClaudeSettings();
97
+ if (!settings) return null;
98
+ if (settings.attribution?.commit !== void 0) {
99
+ return settings.attribution.commit || null;
100
+ }
101
+ if (settings.includeCoAuthoredBy === true) {
102
+ return DEFAULT_COMMIT_ATTRIBUTION;
103
+ }
104
+ return null;
105
+ }
106
+
107
+ const systemPrompt = (() => {
108
+ const base = prompt.getBaseSystemPrompt();
109
+ if (base === null) return "";
110
+ const attribution = getCommitAttribution();
111
+ if (!attribution) return base;
112
+ return base + "\n\n# Commit\n\nWhen making commit messages, add this footer:\n\n" + attribution;
113
+ })();
114
+
115
+ class ExitCodeError extends Error {
116
+ exitCode;
117
+ constructor(exitCode) {
118
+ super(`Process exited with code: ${exitCode}`);
119
+ this.name = "ExitCodeError";
120
+ this.exitCode = exitCode;
121
+ }
122
+ }
123
+ const claudeCliPath = path.resolve(path.join(projectPath.projectPath(), "scripts", "claude_local_launcher.cjs"));
124
+ async function claudeLocal(opts) {
125
+ const projectDir = getProjectPath(opts.path);
126
+ fs.mkdirSync(projectDir, { recursive: true });
127
+ const hasContinueFlag = opts.claudeArgs?.includes("--continue");
128
+ const hasResumeFlag = opts.claudeArgs?.includes("--resume");
129
+ const hasUserSessionControl = hasContinueFlag || hasResumeFlag;
130
+ let startFrom = opts.sessionId;
131
+ const extractFlag = (flags, withValue = false) => {
132
+ if (!opts.claudeArgs) return { found: false };
133
+ for (const flag of flags) {
134
+ const index = opts.claudeArgs.indexOf(flag);
135
+ if (index !== -1) {
136
+ if (withValue && index + 1 < opts.claudeArgs.length) {
137
+ const nextArg = opts.claudeArgs[index + 1];
138
+ if (!nextArg.startsWith("-")) {
139
+ const value = nextArg;
140
+ opts.claudeArgs = opts.claudeArgs.filter((_, i) => i !== index && i !== index + 1);
141
+ return { found: true, value };
142
+ }
143
+ }
144
+ if (!withValue) {
145
+ opts.claudeArgs = opts.claudeArgs.filter((_, i) => i !== index);
146
+ return { found: true };
147
+ }
148
+ return { found: false };
149
+ }
150
+ }
151
+ return { found: false };
152
+ };
153
+ const sessionIdFlag = extractFlag(["--session-id"], true);
154
+ if (sessionIdFlag.found && sessionIdFlag.value) {
155
+ startFrom = null;
156
+ logger.logger.debug(`[ClaudeLocal] Using explicit --session-id: ${sessionIdFlag.value}`);
157
+ }
158
+ if (!startFrom && !sessionIdFlag.value) {
159
+ const resumeFlag = extractFlag(["--resume", "-r"], true);
160
+ if (resumeFlag.found) {
161
+ if (resumeFlag.value) {
162
+ startFrom = resumeFlag.value;
163
+ logger.logger.debug(`[ClaudeLocal] Using provided session ID from --resume: ${startFrom}`);
164
+ } else {
165
+ const lastSession = claudeFindLastSession(opts.path);
166
+ if (lastSession) {
167
+ startFrom = lastSession;
168
+ logger.logger.debug(`[ClaudeLocal] --resume: Found last session: ${lastSession}`);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ if (!startFrom && !sessionIdFlag.value) {
174
+ const continueFlag = extractFlag(["--continue", "-c"], false);
175
+ if (continueFlag.found) {
176
+ const lastSession = claudeFindLastSession(opts.path);
177
+ if (lastSession) {
178
+ startFrom = lastSession;
179
+ logger.logger.debug(`[ClaudeLocal] --continue: Found last session: ${lastSession}`);
180
+ }
181
+ }
182
+ }
183
+ const explicitSessionId = sessionIdFlag.value || null;
184
+ let newSessionId = null;
185
+ let effectiveSessionId = startFrom;
186
+ if (!opts.hookSettingsPath) {
187
+ newSessionId = startFrom ? null : explicitSessionId || node_crypto.randomUUID();
188
+ effectiveSessionId = startFrom || newSessionId;
189
+ if (startFrom) {
190
+ logger.logger.debug(`[ClaudeLocal] Resuming session: ${startFrom}`);
191
+ opts.onSessionFound(startFrom);
192
+ } else if (explicitSessionId) {
193
+ logger.logger.debug(`[ClaudeLocal] Using explicit session ID: ${explicitSessionId}`);
194
+ opts.onSessionFound(explicitSessionId);
195
+ } else {
196
+ logger.logger.debug(`[ClaudeLocal] Generated new session ID: ${newSessionId}`);
197
+ opts.onSessionFound(newSessionId);
198
+ }
199
+ } else {
200
+ if (startFrom) {
201
+ logger.logger.debug(`[ClaudeLocal] Will resume existing session: ${startFrom}`);
202
+ } else if (hasUserSessionControl) {
203
+ logger.logger.debug(`[ClaudeLocal] User passed ${hasContinueFlag ? "--continue" : "--resume"} flag, session ID will be determined by hook`);
204
+ } else {
205
+ logger.logger.debug(`[ClaudeLocal] Fresh start, session ID will be provided by hook`);
206
+ }
207
+ }
208
+ let thinking = false;
209
+ let stopThinkingTimeout = null;
210
+ const updateThinking = (newThinking) => {
211
+ if (thinking !== newThinking) {
212
+ thinking = newThinking;
213
+ logger.logger.debug(`[ClaudeLocal] Thinking state changed to: ${thinking}`);
214
+ if (opts.onThinkingChange) {
215
+ opts.onThinkingChange(thinking);
216
+ }
217
+ }
218
+ };
219
+ try {
220
+ process.stdin.pause();
221
+ await new Promise((r, reject) => {
222
+ const args = [];
223
+ if (!opts.hookSettingsPath) {
224
+ const hasResumeFlag2 = opts.claudeArgs?.includes("--resume") || opts.claudeArgs?.includes("-r");
225
+ if (startFrom) {
226
+ args.push("--resume", startFrom);
227
+ } else if (!hasResumeFlag2 && newSessionId) {
228
+ args.push("--session-id", newSessionId);
229
+ }
230
+ } else {
231
+ if (startFrom) {
232
+ args.push("--resume", startFrom);
233
+ }
234
+ }
235
+ args.push("--append-system-prompt", systemPrompt);
236
+ if (opts.mcpServers && Object.keys(opts.mcpServers).length > 0) {
237
+ args.push("--mcp-config", JSON.stringify({ mcpServers: opts.mcpServers }));
238
+ }
239
+ if (opts.allowedTools && opts.allowedTools.length > 0) {
240
+ args.push("--allowedTools", opts.allowedTools.join(","));
241
+ }
242
+ if (opts.claudeArgs) {
243
+ args.push(...opts.claudeArgs);
244
+ }
245
+ if (opts.hookSettingsPath) {
246
+ args.push("--settings", opts.hookSettingsPath);
247
+ logger.logger.debug(`[ClaudeLocal] Using hook settings: ${opts.hookSettingsPath}`);
248
+ }
249
+ if (!claudeCliPath || !fs.existsSync(claudeCliPath)) {
250
+ throw new Error("Claude local launcher not found. Please ensure HAPPY_PROJECT_ROOT is set correctly for development.");
251
+ }
252
+ const env = {
253
+ ...process.env,
254
+ ...opts.claudeEnvVars
255
+ };
256
+ logger.logger.debug(`[ClaudeLocal] Spawning launcher: ${claudeCliPath}`);
257
+ logger.logger.debug(`[ClaudeLocal] Args: ${JSON.stringify(args)}`);
258
+ const child = node_child_process.spawn("node", [claudeCliPath, ...args], {
259
+ stdio: ["inherit", "inherit", "inherit", "pipe"],
260
+ signal: opts.abort,
261
+ cwd: opts.path,
262
+ env
263
+ });
264
+ if (child.stdio[3]) {
265
+ const rl = node_readline.createInterface({
266
+ input: child.stdio[3],
267
+ crlfDelay: Infinity
268
+ });
269
+ const activeFetches = /* @__PURE__ */ new Map();
270
+ rl.on("line", (line) => {
271
+ try {
272
+ const message = JSON.parse(line);
273
+ switch (message.type) {
274
+ case "fetch-start":
275
+ activeFetches.set(message.id, {
276
+ hostname: message.hostname,
277
+ path: message.path,
278
+ startTime: message.timestamp
279
+ });
280
+ if (stopThinkingTimeout) {
281
+ clearTimeout(stopThinkingTimeout);
282
+ stopThinkingTimeout = null;
283
+ }
284
+ updateThinking(true);
285
+ break;
286
+ case "fetch-end":
287
+ activeFetches.delete(message.id);
288
+ if (activeFetches.size === 0 && thinking && !stopThinkingTimeout) {
289
+ stopThinkingTimeout = setTimeout(() => {
290
+ if (activeFetches.size === 0) {
291
+ updateThinking(false);
292
+ }
293
+ stopThinkingTimeout = null;
294
+ }, 500);
295
+ }
296
+ break;
297
+ default:
298
+ logger.logger.debug(`[ClaudeLocal] Unknown message type: ${message.type}`);
299
+ }
300
+ } catch (e) {
301
+ logger.logger.debug(`[ClaudeLocal] Non-JSON line from fd3: ${line}`);
302
+ }
303
+ });
304
+ rl.on("error", (err) => {
305
+ console.error("Error reading from fd 3:", err);
306
+ });
307
+ child.on("exit", () => {
308
+ if (stopThinkingTimeout) {
309
+ clearTimeout(stopThinkingTimeout);
310
+ }
311
+ updateThinking(false);
312
+ });
313
+ }
314
+ child.on("error", (error) => {
315
+ });
316
+ child.on("exit", (code, signal) => {
317
+ if (signal === "SIGTERM" && opts.abort.aborted) {
318
+ r();
319
+ } else if (signal) {
320
+ reject(new Error(`Process terminated with signal: ${signal}`));
321
+ } else if (code !== 0 && code !== null) {
322
+ reject(new ExitCodeError(code));
323
+ } else {
324
+ r();
325
+ }
326
+ });
327
+ });
328
+ } finally {
329
+ process.stdin.resume();
330
+ if (stopThinkingTimeout) {
331
+ clearTimeout(stopThinkingTimeout);
332
+ stopThinkingTimeout = null;
333
+ }
334
+ updateThinking(false);
335
+ }
336
+ return effectiveSessionId;
337
+ }
338
+
339
+ var claudeLocal$1 = /*#__PURE__*/Object.freeze({
340
+ __proto__: null,
341
+ ExitCodeError: ExitCodeError,
342
+ claudeCliPath: claudeCliPath,
343
+ claudeLocal: claudeLocal
344
+ });
345
+
346
+ exports.ExitCodeError = ExitCodeError;
347
+ exports.claudeCheckSession = claudeCheckSession;
348
+ exports.claudeCliPath = claudeCliPath;
349
+ exports.claudeLocal = claudeLocal;
350
+ exports.claudeLocal$1 = claudeLocal$1;
351
+ exports.getProjectPath = getProjectPath;
352
+ exports.systemPrompt = systemPrompt;