@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
|
@@ -1,1268 +1,136 @@
|
|
|
1
1
|
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import axios from 'axios';
|
|
2
|
-
import
|
|
3
|
-
import { appendFileSync } from 'fs';
|
|
4
|
-
import fs, { existsSync, mkdirSync, readdirSync, statSync, readFileSync, writeFileSync, mkdtempSync, chmodSync, constants, unlinkSync, createReadStream, createWriteStream, unlink as unlink$2, rmdirSync } from 'node:fs';
|
|
5
|
-
import os, { homedir, tmpdir } from 'node:os';
|
|
6
|
-
import path, { join, basename, dirname as dirname$1, resolve as resolve$1 } from 'node:path';
|
|
2
|
+
import { l as logger, c as configuration, g as encodeBase64, h as encrypt, e as decrypt, f as decodeBase64, i as isDebug, B as encryptLegacy, a as readSettings, C as getRandomBytes, D as libsodiumEncryptForPublicKey } from './persistence-DKfF81pd.mjs';
|
|
7
3
|
import { EventEmitter } from 'node:events';
|
|
8
4
|
import { io } from 'socket.io-client';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import './index-CPKdvi7J.mjs';
|
|
7
|
+
import { b as backoff, e as exponentialBackoffDelay } from './time-DgsBLJA_.mjs';
|
|
8
|
+
import { randomUUID, createHash } from 'node:crypto';
|
|
9
|
+
import fs, { existsSync, readFileSync, writeFileSync, mkdirSync, statSync, readdirSync, mkdtempSync, chmodSync, createReadStream, createWriteStream, unlink as unlink$2, rmdirSync } from 'node:fs';
|
|
10
|
+
import path, { join, dirname, resolve as resolve$1, basename } from 'node:path';
|
|
14
11
|
import { spawn, execFile, execSync, execFileSync } from 'node:child_process';
|
|
15
|
-
import { readFile, rm, open,
|
|
12
|
+
import { readFile, rm, open, writeFile as writeFile$1, rename as rename$1, unlink as unlink$1, stat as stat$1, readdir as readdir$1, copyFile, mkdir as mkdir$1, appendFile as appendFile$1 } from 'node:fs/promises';
|
|
13
|
+
import os, { tmpdir, homedir } from 'node:os';
|
|
16
14
|
import { promisify } from 'node:util';
|
|
17
15
|
import { spawn as spawn$1, exec } from 'child_process';
|
|
18
16
|
import { promisify as promisify$1 } from 'util';
|
|
19
17
|
import { readFile as readFile$1, writeFile, mkdir, rm as rm$1, stat, appendFile, rename, lstat, unlink, readdir } from 'fs/promises';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
18
|
+
import { resolve, join as join$1, dirname as dirname$1, sep } from 'path';
|
|
19
|
+
import { p as projectPath } from './projectPath-BTBIMB57.mjs';
|
|
22
20
|
import { createRequire } from 'node:module';
|
|
23
21
|
import WebSocket from 'ws';
|
|
24
22
|
import { randomUUID as randomUUID$1 } from 'crypto';
|
|
23
|
+
import tweetnacl from 'tweetnacl';
|
|
25
24
|
import { encode, decode } from '@stablelib/base64';
|
|
26
25
|
import { createInterface } from 'node:readline';
|
|
27
26
|
import { Expo } from 'expo-server-sdk';
|
|
27
|
+
import { c as cacheSessionKey } from './sessionKeyCache-B6cGadYL.mjs';
|
|
28
|
+
import chalk from 'chalk';
|
|
28
29
|
|
|
29
|
-
const DEBUG_TRUE_VALUES = /* @__PURE__ */ new Set(["1", "true"]);
|
|
30
|
-
function isDebug() {
|
|
31
|
-
return DEBUG_TRUE_VALUES.has(process.env.DEBUG?.toLowerCase() ?? "");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
var name = "@zonease/happy";
|
|
35
|
-
var version = "0.6.38";
|
|
36
|
-
var description = "Mobile and Web client for Claude Code, Codex, and Gemini";
|
|
37
|
-
var author = "ZonEaseTech";
|
|
38
|
-
var license = "MIT";
|
|
39
|
-
var type = "module";
|
|
40
|
-
var homepage = "https://github.com/ZonEaseTech/happy-wfs";
|
|
41
|
-
var bugs = "https://github.com/ZonEaseTech/happy-wfs/issues";
|
|
42
|
-
var repository = {
|
|
43
|
-
type: "git",
|
|
44
|
-
url: "git+https://github.com/ZonEaseTech/happy-wfs.git",
|
|
45
|
-
directory: "packages/happy-cli"
|
|
46
|
-
};
|
|
47
|
-
var bin = {
|
|
48
|
-
happy: "./bin/happy.mjs",
|
|
49
|
-
"happy-mcp": "./bin/happy-mcp.mjs"
|
|
50
|
-
};
|
|
51
|
-
var main = "./dist/index.cjs";
|
|
52
|
-
var module$1 = "./dist/index.mjs";
|
|
53
|
-
var types = "./dist/index.d.cts";
|
|
54
|
-
var exports$1 = {
|
|
55
|
-
".": {
|
|
56
|
-
require: {
|
|
57
|
-
types: "./dist/index.d.cts",
|
|
58
|
-
"default": "./dist/index.cjs"
|
|
59
|
-
},
|
|
60
|
-
"import": {
|
|
61
|
-
types: "./dist/index.d.mts",
|
|
62
|
-
"default": "./dist/index.mjs"
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
"./lib": {
|
|
66
|
-
require: {
|
|
67
|
-
types: "./dist/lib.d.cts",
|
|
68
|
-
"default": "./dist/lib.cjs"
|
|
69
|
-
},
|
|
70
|
-
"import": {
|
|
71
|
-
types: "./dist/lib.d.mts",
|
|
72
|
-
"default": "./dist/lib.mjs"
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"./codex/happyMcpStdioBridge": {
|
|
76
|
-
require: {
|
|
77
|
-
types: "./dist/codex/happyMcpStdioBridge.d.cts",
|
|
78
|
-
"default": "./dist/codex/happyMcpStdioBridge.cjs"
|
|
79
|
-
},
|
|
80
|
-
"import": {
|
|
81
|
-
types: "./dist/codex/happyMcpStdioBridge.d.mts",
|
|
82
|
-
"default": "./dist/codex/happyMcpStdioBridge.mjs"
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
var files = [
|
|
87
|
-
"dist",
|
|
88
|
-
"bin",
|
|
89
|
-
"scripts",
|
|
90
|
-
"package.json"
|
|
91
|
-
];
|
|
92
|
-
var scripts = {
|
|
93
|
-
"why do we need to build before running tests / dev?": "We need the binary to be built so we run daemon commands which directly run the binary - we don't want them to go out of sync or have custom spawn logic depending how we started happy",
|
|
94
|
-
typecheck: "tsc --noEmit",
|
|
95
|
-
build: "shx rm -rf dist && tsc --noEmit && pkgroll",
|
|
96
|
-
test: "$npm_execpath run build && vitest run",
|
|
97
|
-
"test:integration": "$npm_execpath run build && vitest run --config vitest.integration.config.ts",
|
|
98
|
-
start: "$npm_execpath run build && node ./bin/happy.mjs",
|
|
99
|
-
dev: "tsx src/index.ts",
|
|
100
|
-
"dev:local-server": "$npm_execpath run build && tsx --env-file .env.dev-local-server src/index.ts",
|
|
101
|
-
"dev:integration-test-env": "$npm_execpath run build && tsx --env-file .env.integration-test src/index.ts",
|
|
102
|
-
prepublishOnly: "$npm_execpath run build && $npm_execpath test",
|
|
103
|
-
release: "$npm_execpath install && release-it",
|
|
104
|
-
postinstall: "node scripts/unpack-tools.cjs",
|
|
105
|
-
"// ==== Dev/Stable Variant Management ====": "",
|
|
106
|
-
stable: "node scripts/env-wrapper.cjs stable",
|
|
107
|
-
"dev:variant": "node scripts/env-wrapper.cjs dev",
|
|
108
|
-
"// ==== Stable Version Quick Commands ====": "",
|
|
109
|
-
"stable:daemon:start": "node scripts/env-wrapper.cjs stable daemon start",
|
|
110
|
-
"stable:daemon:stop": "node scripts/env-wrapper.cjs stable daemon stop",
|
|
111
|
-
"stable:daemon:status": "node scripts/env-wrapper.cjs stable daemon status",
|
|
112
|
-
"stable:auth": "node scripts/env-wrapper.cjs stable auth",
|
|
113
|
-
"// ==== Development Version Quick Commands ====": "",
|
|
114
|
-
"dev:daemon:start": "node scripts/env-wrapper.cjs dev daemon start",
|
|
115
|
-
"dev:daemon:stop": "node scripts/env-wrapper.cjs dev daemon stop",
|
|
116
|
-
"dev:daemon:status": "node scripts/env-wrapper.cjs dev daemon status",
|
|
117
|
-
"dev:auth": "node scripts/env-wrapper.cjs dev auth",
|
|
118
|
-
"// ==== Setup ====": "",
|
|
119
|
-
"setup:dev": "node scripts/setup-dev.cjs",
|
|
120
|
-
doctor: "node scripts/env-wrapper.cjs stable doctor",
|
|
121
|
-
"// ==== Development Linking ====": "",
|
|
122
|
-
"link:dev": "node scripts/link-dev.cjs",
|
|
123
|
-
"unlink:dev": "node scripts/link-dev.cjs unlink"
|
|
124
|
-
};
|
|
125
|
-
var dependencies = {
|
|
126
|
-
"@agentclientprotocol/sdk": "^0.14.1",
|
|
127
|
-
"@paralleldrive/cuid2": "^2.2.2",
|
|
128
|
-
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
129
|
-
"@stablelib/base64": "^2.0.1",
|
|
130
|
-
"@stablelib/hex": "^2.0.1",
|
|
131
|
-
"@types/cross-spawn": "^6.0.6",
|
|
132
|
-
"@types/http-proxy": "^1.17.17",
|
|
133
|
-
"@types/qrcode-terminal": "^0.12.2",
|
|
134
|
-
"@types/react": "^19.2.7",
|
|
135
|
-
"@types/tmp": "^0.2.6",
|
|
136
|
-
"@types/ws": "^8.18.1",
|
|
137
|
-
ai: "^5.0.107",
|
|
138
|
-
axios: "^1.13.2",
|
|
139
|
-
chalk: "^5.6.2",
|
|
140
|
-
"cross-spawn": "^7.0.6",
|
|
141
|
-
"expo-server-sdk": "^3.15.0",
|
|
142
|
-
fastify: "^5.6.2",
|
|
143
|
-
"fastify-type-provider-zod": "4.0.2",
|
|
144
|
-
"http-proxy": "^1.18.1",
|
|
145
|
-
"http-proxy-middleware": "^3.0.5",
|
|
146
|
-
ink: "^6.5.1",
|
|
147
|
-
open: "^10.2.0",
|
|
148
|
-
"ps-list": "^8.1.1",
|
|
149
|
-
"qrcode-terminal": "^0.12.0",
|
|
150
|
-
react: "^19.2.0",
|
|
151
|
-
"socket.io-client": "^4.8.1",
|
|
152
|
-
tar: "^7.5.2",
|
|
153
|
-
tmp: "^0.2.5",
|
|
154
|
-
tweetnacl: "^1.0.3",
|
|
155
|
-
ws: "^8.19.0",
|
|
156
|
-
zod: "3.25.76"
|
|
157
|
-
};
|
|
158
|
-
var devDependencies = {
|
|
159
|
-
"@eslint/compat": "^1",
|
|
160
|
-
"@types/node": ">=20",
|
|
161
|
-
"cross-env": "^10.1.0",
|
|
162
|
-
dotenv: "^16.6.1",
|
|
163
|
-
eslint: "^9",
|
|
164
|
-
"eslint-config-prettier": "^10",
|
|
165
|
-
pkgroll: "^2.14.2",
|
|
166
|
-
"release-it": "^19.0.6",
|
|
167
|
-
shx: "^0.3.3",
|
|
168
|
-
"ts-node": "^10",
|
|
169
|
-
tsx: "^4.20.6",
|
|
170
|
-
typescript: "5.9.3",
|
|
171
|
-
vitest: "^3.2.4",
|
|
172
|
-
"happy-wire": "*"
|
|
173
|
-
};
|
|
174
|
-
var resolutions = {
|
|
175
|
-
"whatwg-url": "14.2.0",
|
|
176
|
-
"parse-path": "7.0.3",
|
|
177
|
-
"@types/parse-path": "7.0.3"
|
|
178
|
-
};
|
|
179
|
-
var publishConfig = {
|
|
180
|
-
registry: "https://registry.npmjs.org",
|
|
181
|
-
access: "public"
|
|
182
|
-
};
|
|
183
|
-
var packageManager = "yarn@1.22.22";
|
|
184
|
-
var optionalDependencies = {
|
|
185
|
-
"node-pty": "^1.0.0",
|
|
186
|
-
"@zonease/happy-tools-arm64-darwin": "1.0.0",
|
|
187
|
-
"@zonease/happy-tools-x64-darwin": "1.0.0",
|
|
188
|
-
"@zonease/happy-tools-arm64-linux": "1.0.0",
|
|
189
|
-
"@zonease/happy-tools-x64-linux": "1.0.0",
|
|
190
|
-
"@zonease/happy-tools-x64-win32": "1.0.0",
|
|
191
|
-
"@zonease/happy-tools-arm64-win32": "1.0.0"
|
|
192
|
-
};
|
|
193
|
-
var packageJson = {
|
|
194
|
-
name: name,
|
|
195
|
-
version: version,
|
|
196
|
-
description: description,
|
|
197
|
-
author: author,
|
|
198
|
-
license: license,
|
|
199
|
-
type: type,
|
|
200
|
-
homepage: homepage,
|
|
201
|
-
bugs: bugs,
|
|
202
|
-
repository: repository,
|
|
203
|
-
bin: bin,
|
|
204
|
-
main: main,
|
|
205
|
-
module: module$1,
|
|
206
|
-
types: types,
|
|
207
|
-
exports: exports$1,
|
|
208
|
-
files: files,
|
|
209
|
-
scripts: scripts,
|
|
210
|
-
dependencies: dependencies,
|
|
211
|
-
devDependencies: devDependencies,
|
|
212
|
-
resolutions: resolutions,
|
|
213
|
-
publishConfig: publishConfig,
|
|
214
|
-
packageManager: packageManager,
|
|
215
|
-
optionalDependencies: optionalDependencies
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
class Configuration {
|
|
219
|
-
serverUrl;
|
|
220
|
-
webappUrl;
|
|
221
|
-
isDaemonProcess;
|
|
222
|
-
// Directories and paths (from persistence)
|
|
223
|
-
happyHomeDir;
|
|
224
|
-
logsDir;
|
|
225
|
-
settingsFile;
|
|
226
|
-
privateKeyFile;
|
|
227
|
-
daemonStateFile;
|
|
228
|
-
daemonLockFile;
|
|
229
|
-
sessionKeysDir;
|
|
230
|
-
currentCliVersion;
|
|
231
|
-
isExperimentalEnabled;
|
|
232
|
-
disableCaffeinate;
|
|
233
|
-
constructor() {
|
|
234
|
-
this.serverUrl = process.env.HAPPY_SERVER_URL || "https://api-happy.zonease.org";
|
|
235
|
-
this.webappUrl = process.env.HAPPY_WEBAPP_URL || "https://happy.zonease.org";
|
|
236
|
-
const args = process.argv.slice(2);
|
|
237
|
-
this.isDaemonProcess = args.length >= 2 && args[0] === "daemon" && args[1] === "start-sync";
|
|
238
|
-
if (process.env.HAPPY_HOME_DIR) {
|
|
239
|
-
const expandedPath = process.env.HAPPY_HOME_DIR.replace(/^~/, homedir());
|
|
240
|
-
this.happyHomeDir = expandedPath;
|
|
241
|
-
} else {
|
|
242
|
-
this.happyHomeDir = join(homedir(), ".happy");
|
|
243
|
-
}
|
|
244
|
-
this.logsDir = join(this.happyHomeDir, "logs");
|
|
245
|
-
this.settingsFile = join(this.happyHomeDir, "settings.json");
|
|
246
|
-
this.privateKeyFile = join(this.happyHomeDir, "access.key");
|
|
247
|
-
this.daemonStateFile = join(this.happyHomeDir, "daemon.state.json");
|
|
248
|
-
this.daemonLockFile = join(this.happyHomeDir, "daemon.state.json.lock");
|
|
249
|
-
this.sessionKeysDir = join(this.happyHomeDir, "session-keys");
|
|
250
|
-
this.isExperimentalEnabled = ["true", "1", "yes"].includes(process.env.HAPPY_EXPERIMENTAL?.toLowerCase() || "");
|
|
251
|
-
this.disableCaffeinate = ["true", "1", "yes"].includes(process.env.HAPPY_DISABLE_CAFFEINATE?.toLowerCase() || "");
|
|
252
|
-
this.currentCliVersion = packageJson.version;
|
|
253
|
-
const variant = process.env.HAPPY_VARIANT || "stable";
|
|
254
|
-
if (variant === "dev" && !this.happyHomeDir.includes("dev")) {
|
|
255
|
-
console.warn('\u26A0\uFE0F WARNING: HAPPY_VARIANT=dev but HAPPY_HOME_DIR does not contain "dev"');
|
|
256
|
-
console.warn(` Current: ${this.happyHomeDir}`);
|
|
257
|
-
console.warn(` Expected: Should contain "dev" (e.g., ~/.happy-dev)`);
|
|
258
|
-
}
|
|
259
|
-
if (!this.isDaemonProcess && variant === "dev") {
|
|
260
|
-
console.log("\x1B[33m\u{1F527} DEV MODE\x1B[0m - Data: " + this.happyHomeDir);
|
|
261
|
-
}
|
|
262
|
-
if (!existsSync(this.happyHomeDir)) {
|
|
263
|
-
mkdirSync(this.happyHomeDir, { recursive: true });
|
|
264
|
-
}
|
|
265
|
-
if (!existsSync(this.logsDir)) {
|
|
266
|
-
mkdirSync(this.logsDir, { recursive: true });
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const configuration = new Configuration();
|
|
271
|
-
|
|
272
|
-
function createTimestampForFilename(date = /* @__PURE__ */ new Date()) {
|
|
273
|
-
return date.toLocaleString("sv-SE", {
|
|
274
|
-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
275
|
-
year: "numeric",
|
|
276
|
-
month: "2-digit",
|
|
277
|
-
day: "2-digit",
|
|
278
|
-
hour: "2-digit",
|
|
279
|
-
minute: "2-digit",
|
|
280
|
-
second: "2-digit"
|
|
281
|
-
}).replace(/[: ]/g, "-").replace(/,/g, "") + "-pid-" + process.pid;
|
|
282
|
-
}
|
|
283
|
-
function createTimestampForLogEntry(date = /* @__PURE__ */ new Date()) {
|
|
284
|
-
return date.toLocaleTimeString("en-US", {
|
|
285
|
-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
286
|
-
hour12: false,
|
|
287
|
-
hour: "2-digit",
|
|
288
|
-
minute: "2-digit",
|
|
289
|
-
second: "2-digit",
|
|
290
|
-
fractionalSecondDigits: 3
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
function getSessionLogPath() {
|
|
294
|
-
const timestamp = createTimestampForFilename();
|
|
295
|
-
const filename = configuration.isDaemonProcess ? `${timestamp}-daemon.log` : `${timestamp}.log`;
|
|
296
|
-
return join(configuration.logsDir, filename);
|
|
297
|
-
}
|
|
298
|
-
class Logger {
|
|
299
|
-
constructor(logFilePath = getSessionLogPath()) {
|
|
300
|
-
this.logFilePath = logFilePath;
|
|
301
|
-
if (process.env.DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING && process.env.HAPPY_SERVER_URL) {
|
|
302
|
-
this.dangerouslyUnencryptedServerLoggingUrl = process.env.HAPPY_SERVER_URL;
|
|
303
|
-
console.log(chalk.yellow("[REMOTE LOGGING] Sending logs to server for AI debugging"));
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
dangerouslyUnencryptedServerLoggingUrl;
|
|
307
|
-
// Use local timezone for simplicity of locating the logs,
|
|
308
|
-
// in practice you will not need absolute timestamps
|
|
309
|
-
localTimezoneTimestamp() {
|
|
310
|
-
return createTimestampForLogEntry();
|
|
311
|
-
}
|
|
312
|
-
debug(message, ...args) {
|
|
313
|
-
this.logToFile(`[${this.localTimezoneTimestamp()}]`, message, ...args);
|
|
314
|
-
}
|
|
315
|
-
debugLargeJson(message, object, maxStringLength = 100, maxArrayLength = 10) {
|
|
316
|
-
if (!isDebug()) {
|
|
317
|
-
this.debug(`In production, skipping message inspection`);
|
|
318
|
-
}
|
|
319
|
-
const truncateStrings = (obj) => {
|
|
320
|
-
if (typeof obj === "string") {
|
|
321
|
-
return obj.length > maxStringLength ? obj.substring(0, maxStringLength) + "... [truncated for logs]" : obj;
|
|
322
|
-
}
|
|
323
|
-
if (Array.isArray(obj)) {
|
|
324
|
-
const truncatedArray = obj.map((item) => truncateStrings(item)).slice(0, maxArrayLength);
|
|
325
|
-
if (obj.length > maxArrayLength) {
|
|
326
|
-
truncatedArray.push(`... [truncated array for logs up to ${maxArrayLength} items]`);
|
|
327
|
-
}
|
|
328
|
-
return truncatedArray;
|
|
329
|
-
}
|
|
330
|
-
if (obj && typeof obj === "object") {
|
|
331
|
-
const result = {};
|
|
332
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
333
|
-
if (key === "usage") {
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
result[key] = truncateStrings(value);
|
|
337
|
-
}
|
|
338
|
-
return result;
|
|
339
|
-
}
|
|
340
|
-
return obj;
|
|
341
|
-
};
|
|
342
|
-
const truncatedObject = truncateStrings(object);
|
|
343
|
-
const json = JSON.stringify(truncatedObject, null, 2);
|
|
344
|
-
this.logToFile(`[${this.localTimezoneTimestamp()}]`, message, "\n", json);
|
|
345
|
-
}
|
|
346
|
-
info(message, ...args) {
|
|
347
|
-
this.logToConsole("info", "", message, ...args);
|
|
348
|
-
this.debug(message, args);
|
|
349
|
-
}
|
|
350
|
-
infoDeveloper(message, ...args) {
|
|
351
|
-
this.debug(message, ...args);
|
|
352
|
-
if (isDebug()) {
|
|
353
|
-
this.logToConsole("info", "[DEV]", message, ...args);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
warn(message, ...args) {
|
|
357
|
-
this.logToConsole("warn", "", message, ...args);
|
|
358
|
-
this.debug(`[WARN] ${message}`, ...args);
|
|
359
|
-
}
|
|
360
|
-
getLogPath() {
|
|
361
|
-
return this.logFilePath;
|
|
362
|
-
}
|
|
363
|
-
logToConsole(level, prefix, message, ...args) {
|
|
364
|
-
switch (level) {
|
|
365
|
-
case "debug": {
|
|
366
|
-
console.log(chalk.gray(prefix), message, ...args);
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
case "error": {
|
|
370
|
-
console.error(chalk.red(prefix), message, ...args);
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
|
-
case "info": {
|
|
374
|
-
console.log(chalk.blue(prefix), message, ...args);
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
case "warn": {
|
|
378
|
-
console.log(chalk.yellow(prefix), message, ...args);
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
default: {
|
|
382
|
-
this.debug("Unknown log level:", level);
|
|
383
|
-
console.log(chalk.blue(prefix), message, ...args);
|
|
384
|
-
break;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
async sendToRemoteServer(level, message, ...args) {
|
|
389
|
-
if (!this.dangerouslyUnencryptedServerLoggingUrl) return;
|
|
390
|
-
try {
|
|
391
|
-
await fetch(this.dangerouslyUnencryptedServerLoggingUrl + "/logs-combined-from-cli-and-mobile-for-simple-ai-debugging", {
|
|
392
|
-
method: "POST",
|
|
393
|
-
headers: { "Content-Type": "application/json" },
|
|
394
|
-
body: JSON.stringify({
|
|
395
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
396
|
-
level,
|
|
397
|
-
message: `${message} ${args.map(
|
|
398
|
-
(a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)
|
|
399
|
-
).join(" ")}`,
|
|
400
|
-
source: "cli",
|
|
401
|
-
platform: process.platform
|
|
402
|
-
})
|
|
403
|
-
});
|
|
404
|
-
} catch (error) {
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
logToFile(prefix, message, ...args) {
|
|
408
|
-
const logLine = `${prefix} ${message} ${args.map((arg) => {
|
|
409
|
-
if (typeof arg === "string") return arg;
|
|
410
|
-
if (arg instanceof Error) return `${arg.message}
|
|
411
|
-
${arg.stack ?? ""}`;
|
|
412
|
-
return JSON.stringify(arg);
|
|
413
|
-
}).join(" ")}
|
|
414
|
-
`;
|
|
415
|
-
if (this.dangerouslyUnencryptedServerLoggingUrl) {
|
|
416
|
-
let level = "info";
|
|
417
|
-
if (prefix.includes(this.localTimezoneTimestamp())) {
|
|
418
|
-
level = "debug";
|
|
419
|
-
}
|
|
420
|
-
this.sendToRemoteServer(level, message, ...args).catch(() => {
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
try {
|
|
424
|
-
appendFileSync(this.logFilePath, logLine);
|
|
425
|
-
} catch (appendError) {
|
|
426
|
-
if (isDebug()) {
|
|
427
|
-
console.error("[DEV MODE ONLY THROWING] Failed to append to log file:", appendError);
|
|
428
|
-
throw appendError;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
let logger = new Logger();
|
|
434
|
-
async function listDaemonLogFiles(limit = 50) {
|
|
435
|
-
try {
|
|
436
|
-
const logsDir = configuration.logsDir;
|
|
437
|
-
if (!existsSync(logsDir)) {
|
|
438
|
-
return [];
|
|
439
|
-
}
|
|
440
|
-
const logs = readdirSync(logsDir).filter((file) => file.endsWith("-daemon.log")).map((file) => {
|
|
441
|
-
const fullPath = join(logsDir, file);
|
|
442
|
-
const stats = statSync(fullPath);
|
|
443
|
-
return { file, path: fullPath, modified: stats.mtime };
|
|
444
|
-
}).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
445
|
-
try {
|
|
446
|
-
const { readDaemonState } = await Promise.resolve().then(function () { return persistence; });
|
|
447
|
-
const state = await readDaemonState();
|
|
448
|
-
if (!state) {
|
|
449
|
-
return logs;
|
|
450
|
-
}
|
|
451
|
-
if (state.daemonLogPath && existsSync(state.daemonLogPath)) {
|
|
452
|
-
const stats = statSync(state.daemonLogPath);
|
|
453
|
-
const persisted = {
|
|
454
|
-
file: basename(state.daemonLogPath),
|
|
455
|
-
path: state.daemonLogPath,
|
|
456
|
-
modified: stats.mtime
|
|
457
|
-
};
|
|
458
|
-
const idx = logs.findIndex((l) => l.path === persisted.path);
|
|
459
|
-
if (idx >= 0) {
|
|
460
|
-
const [found] = logs.splice(idx, 1);
|
|
461
|
-
logs.unshift(found);
|
|
462
|
-
} else {
|
|
463
|
-
logs.unshift(persisted);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
} catch {
|
|
467
|
-
}
|
|
468
|
-
return logs.slice(0, Math.max(0, limit));
|
|
469
|
-
} catch {
|
|
470
|
-
return [];
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
async function getLatestDaemonLog() {
|
|
474
|
-
const [latest] = await listDaemonLogFiles(1);
|
|
475
|
-
return latest || null;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const sessionRoleSchema = z.enum(["user", "agent"]);
|
|
479
|
-
const sessionTextEventSchema = z.object({
|
|
480
|
-
t: z.literal("text"),
|
|
481
|
-
text: z.string(),
|
|
482
|
-
thinking: z.boolean().optional()
|
|
483
|
-
});
|
|
484
|
-
const sessionServiceMessageEventSchema = z.object({
|
|
485
|
-
t: z.literal("service"),
|
|
486
|
-
text: z.string()
|
|
487
|
-
});
|
|
488
|
-
const sessionToolCallStartEventSchema = z.object({
|
|
489
|
-
t: z.literal("tool-call-start"),
|
|
490
|
-
call: z.string(),
|
|
491
|
-
name: z.string(),
|
|
492
|
-
title: z.string(),
|
|
493
|
-
description: z.string(),
|
|
494
|
-
args: z.record(z.string(), z.unknown())
|
|
495
|
-
});
|
|
496
|
-
const sessionToolCallEndEventSchema = z.object({
|
|
497
|
-
t: z.literal("tool-call-end"),
|
|
498
|
-
call: z.string()
|
|
499
|
-
});
|
|
500
|
-
const sessionFileEventSchema = z.object({
|
|
501
|
-
t: z.literal("file"),
|
|
502
|
-
ref: z.string(),
|
|
503
|
-
name: z.string(),
|
|
504
|
-
size: z.number(),
|
|
505
|
-
image: z.object({
|
|
506
|
-
width: z.number(),
|
|
507
|
-
height: z.number(),
|
|
508
|
-
thumbhash: z.string()
|
|
509
|
-
}).optional()
|
|
510
|
-
});
|
|
511
|
-
const sessionTurnStartEventSchema = z.object({
|
|
512
|
-
t: z.literal("turn-start")
|
|
513
|
-
});
|
|
514
|
-
const sessionStartEventSchema = z.object({
|
|
515
|
-
t: z.literal("start"),
|
|
516
|
-
title: z.string().optional()
|
|
517
|
-
});
|
|
518
|
-
const sessionTurnEndStatusSchema = z.enum(["completed", "failed", "cancelled"]);
|
|
519
|
-
const sessionTurnEndEventSchema = z.object({
|
|
520
|
-
t: z.literal("turn-end"),
|
|
521
|
-
status: sessionTurnEndStatusSchema
|
|
522
|
-
});
|
|
523
|
-
const sessionStopEventSchema = z.object({
|
|
524
|
-
t: z.literal("stop")
|
|
525
|
-
});
|
|
526
|
-
const sessionEventSchema = z.discriminatedUnion("t", [
|
|
527
|
-
sessionTextEventSchema,
|
|
528
|
-
sessionServiceMessageEventSchema,
|
|
529
|
-
sessionToolCallStartEventSchema,
|
|
530
|
-
sessionToolCallEndEventSchema,
|
|
531
|
-
sessionFileEventSchema,
|
|
532
|
-
sessionTurnStartEventSchema,
|
|
533
|
-
sessionStartEventSchema,
|
|
534
|
-
sessionTurnEndEventSchema,
|
|
535
|
-
sessionStopEventSchema
|
|
536
|
-
]);
|
|
537
|
-
const sessionEnvelopeSchema = z.object({
|
|
538
|
-
id: z.string(),
|
|
539
|
-
time: z.number(),
|
|
540
|
-
role: sessionRoleSchema,
|
|
541
|
-
turn: z.string().optional(),
|
|
542
|
-
subagent: z.string().refine((value) => isCuid(value), {
|
|
543
|
-
message: "subagent must be a cuid2 value"
|
|
544
|
-
}).optional(),
|
|
545
|
-
ev: sessionEventSchema
|
|
546
|
-
}).superRefine((envelope, ctx) => {
|
|
547
|
-
if (envelope.ev.t === "service" && envelope.role !== "agent") {
|
|
548
|
-
ctx.addIssue({
|
|
549
|
-
code: z.ZodIssueCode.custom,
|
|
550
|
-
message: 'service events must use role "agent"',
|
|
551
|
-
path: ["role"]
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
if ((envelope.ev.t === "start" || envelope.ev.t === "stop") && envelope.role !== "agent") {
|
|
555
|
-
ctx.addIssue({
|
|
556
|
-
code: z.ZodIssueCode.custom,
|
|
557
|
-
message: `${envelope.ev.t} events must use role "agent"`,
|
|
558
|
-
path: ["role"]
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
});
|
|
562
|
-
const MessageMetaSchema$1 = z.object({
|
|
563
|
-
sentFrom: z.string().optional(),
|
|
564
|
-
permissionMode: z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "read-only", "safe-yolo", "yolo"]).optional(),
|
|
565
|
-
model: z.string().nullable().optional(),
|
|
566
|
-
fallbackModel: z.string().nullable().optional(),
|
|
567
|
-
reasoningEffort: z.string().nullable().optional(),
|
|
568
|
-
customSystemPrompt: z.string().nullable().optional(),
|
|
569
|
-
appendSystemPrompt: z.string().nullable().optional(),
|
|
570
|
-
allowedTools: z.array(z.string()).nullable().optional(),
|
|
571
|
-
disallowedTools: z.array(z.string()).nullable().optional(),
|
|
572
|
-
displayText: z.string().optional()
|
|
573
|
-
});
|
|
574
|
-
const UserMessageSchema$1 = z.object({
|
|
575
|
-
role: z.literal("user"),
|
|
576
|
-
content: z.object({
|
|
577
|
-
type: z.literal("text"),
|
|
578
|
-
text: z.string()
|
|
579
|
-
}),
|
|
580
|
-
localKey: z.string().optional(),
|
|
581
|
-
meta: MessageMetaSchema$1.optional()
|
|
582
|
-
});
|
|
583
|
-
const AgentMessageSchema$1 = z.object({
|
|
584
|
-
role: z.literal("agent"),
|
|
585
|
-
content: z.object({
|
|
586
|
-
type: z.string()
|
|
587
|
-
}).passthrough(),
|
|
588
|
-
meta: MessageMetaSchema$1.optional()
|
|
589
|
-
});
|
|
590
|
-
z.discriminatedUnion("role", [UserMessageSchema$1, AgentMessageSchema$1]);
|
|
591
|
-
const SessionMessageContentSchema = z.object({
|
|
592
|
-
c: z.string(),
|
|
593
|
-
t: z.literal("encrypted")
|
|
594
|
-
});
|
|
595
|
-
const SessionMessageSchema = z.object({
|
|
596
|
-
id: z.string(),
|
|
597
|
-
seq: z.number(),
|
|
598
|
-
localId: z.string().nullish(),
|
|
599
|
-
content: SessionMessageContentSchema,
|
|
600
|
-
createdAt: z.number(),
|
|
601
|
-
updatedAt: z.number()
|
|
602
|
-
});
|
|
603
|
-
const SessionProtocolMessageSchema = z.object({
|
|
604
|
-
role: z.literal("session"),
|
|
605
|
-
content: sessionEnvelopeSchema,
|
|
606
|
-
meta: MessageMetaSchema$1.optional()
|
|
607
|
-
});
|
|
608
|
-
z.discriminatedUnion("role", [
|
|
609
|
-
UserMessageSchema$1,
|
|
610
|
-
AgentMessageSchema$1,
|
|
611
|
-
SessionProtocolMessageSchema
|
|
612
|
-
]);
|
|
613
|
-
const VersionedEncryptedValueSchema = z.object({
|
|
614
|
-
version: z.number(),
|
|
615
|
-
value: z.string()
|
|
616
|
-
});
|
|
617
|
-
const VersionedNullableEncryptedValueSchema = z.object({
|
|
618
|
-
version: z.number(),
|
|
619
|
-
value: z.string().nullable()
|
|
620
|
-
});
|
|
621
|
-
const UpdateNewMessageBodySchema = z.object({
|
|
622
|
-
t: z.literal("new-message"),
|
|
623
|
-
sid: z.string(),
|
|
624
|
-
message: SessionMessageSchema
|
|
625
|
-
});
|
|
626
|
-
const UpdateSessionBodySchema = z.object({
|
|
627
|
-
t: z.literal("update-session"),
|
|
628
|
-
id: z.string(),
|
|
629
|
-
metadata: VersionedEncryptedValueSchema.nullish(),
|
|
630
|
-
agentState: VersionedNullableEncryptedValueSchema.nullish()
|
|
631
|
-
});
|
|
632
|
-
const VersionedMachineEncryptedValueSchema = z.object({
|
|
633
|
-
version: z.number(),
|
|
634
|
-
value: z.string()
|
|
635
|
-
});
|
|
636
|
-
const UpdateMachineBodySchema = z.object({
|
|
637
|
-
t: z.literal("update-machine"),
|
|
638
|
-
machineId: z.string(),
|
|
639
|
-
metadata: VersionedMachineEncryptedValueSchema.nullish(),
|
|
640
|
-
daemonState: VersionedMachineEncryptedValueSchema.nullish(),
|
|
641
|
-
active: z.boolean().optional(),
|
|
642
|
-
activeAt: z.number().optional()
|
|
643
|
-
});
|
|
644
|
-
const CoreUpdateBodySchema = z.discriminatedUnion("t", [
|
|
645
|
-
UpdateNewMessageBodySchema,
|
|
646
|
-
UpdateSessionBodySchema,
|
|
647
|
-
UpdateMachineBodySchema
|
|
648
|
-
]);
|
|
649
30
|
z.object({
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
MODEL_MODE_DEFAULT,
|
|
658
|
-
"claude-fable-5",
|
|
659
|
-
"claude-fable-5[1m]",
|
|
660
|
-
"claude-opus-5",
|
|
661
|
-
"claude-opus-5[1m]",
|
|
662
|
-
"claude-opus-4-8",
|
|
663
|
-
"claude-opus-4-8[1m]",
|
|
664
|
-
"claude-opus-4-6",
|
|
665
|
-
"claude-opus-4-6[1m]",
|
|
666
|
-
"claude-sonnet-4-6",
|
|
667
|
-
"claude-sonnet-4-6[1m]",
|
|
668
|
-
"claude-haiku-4-5",
|
|
669
|
-
"claude-fable-5-low",
|
|
670
|
-
"claude-fable-5-medium",
|
|
671
|
-
"claude-fable-5-high",
|
|
672
|
-
"claude-fable-5-xhigh",
|
|
673
|
-
"claude-fable-5-max",
|
|
674
|
-
"claude-fable-5[1m]-low",
|
|
675
|
-
"claude-fable-5[1m]-medium",
|
|
676
|
-
"claude-fable-5[1m]-high",
|
|
677
|
-
"claude-fable-5[1m]-xhigh",
|
|
678
|
-
"claude-fable-5[1m]-max",
|
|
679
|
-
"claude-opus-5-low",
|
|
680
|
-
"claude-opus-5-medium",
|
|
681
|
-
"claude-opus-5-high",
|
|
682
|
-
"claude-opus-5-xhigh",
|
|
683
|
-
"claude-opus-5-max",
|
|
684
|
-
"claude-opus-5[1m]-low",
|
|
685
|
-
"claude-opus-5[1m]-medium",
|
|
686
|
-
"claude-opus-5[1m]-high",
|
|
687
|
-
"claude-opus-5[1m]-xhigh",
|
|
688
|
-
"claude-opus-5[1m]-max",
|
|
689
|
-
"claude-opus-4-8-low",
|
|
690
|
-
"claude-opus-4-8-medium",
|
|
691
|
-
"claude-opus-4-8-high",
|
|
692
|
-
"claude-opus-4-8-xhigh",
|
|
693
|
-
"claude-opus-4-8-max",
|
|
694
|
-
"claude-opus-4-8[1m]-low",
|
|
695
|
-
"claude-opus-4-8[1m]-medium",
|
|
696
|
-
"claude-opus-4-8[1m]-high",
|
|
697
|
-
"claude-opus-4-8[1m]-xhigh",
|
|
698
|
-
"claude-opus-4-8[1m]-max",
|
|
699
|
-
"claude-opus-4-6-low",
|
|
700
|
-
"claude-opus-4-6-medium",
|
|
701
|
-
"claude-opus-4-6-high",
|
|
702
|
-
"claude-opus-4-6-max",
|
|
703
|
-
"claude-opus-4-6[1m]-low",
|
|
704
|
-
"claude-opus-4-6[1m]-medium",
|
|
705
|
-
"claude-opus-4-6[1m]-high",
|
|
706
|
-
"claude-opus-4-6[1m]-max",
|
|
707
|
-
"claude-sonnet-4-6-low",
|
|
708
|
-
"claude-sonnet-4-6-medium",
|
|
709
|
-
"claude-sonnet-4-6-high",
|
|
710
|
-
"claude-sonnet-4-6[1m]-low",
|
|
711
|
-
"claude-sonnet-4-6[1m]-medium",
|
|
712
|
-
"claude-sonnet-4-6[1m]-high",
|
|
713
|
-
"claude-haiku-4-5-low",
|
|
714
|
-
"claude-haiku-4-5-medium",
|
|
715
|
-
"claude-haiku-4-5-high",
|
|
716
|
-
"gpt-5.6-sol-low",
|
|
717
|
-
"gpt-5.6-sol-medium",
|
|
718
|
-
"gpt-5.6-sol-high",
|
|
719
|
-
"gpt-5.6-sol-xhigh",
|
|
720
|
-
"gpt-5.6-sol-max",
|
|
721
|
-
"gpt-5.6-terra-low",
|
|
722
|
-
"gpt-5.6-terra-medium",
|
|
723
|
-
"gpt-5.6-terra-high",
|
|
724
|
-
"gpt-5.6-terra-xhigh",
|
|
725
|
-
"gpt-5.6-luna-low",
|
|
726
|
-
"gpt-5.6-luna-medium",
|
|
727
|
-
"gpt-5.6-luna-high",
|
|
728
|
-
"gpt-5.6-luna-xhigh",
|
|
729
|
-
"gpt-5.5-low",
|
|
730
|
-
"gpt-5.5-medium",
|
|
731
|
-
"gpt-5.5-high",
|
|
732
|
-
"gpt-5.5-xhigh",
|
|
733
|
-
"gpt-5.4-low",
|
|
734
|
-
"gpt-5.4-medium",
|
|
735
|
-
"gpt-5.4-high",
|
|
736
|
-
"gpt-5.4-xhigh",
|
|
737
|
-
"gpt-5.3-codex-low",
|
|
738
|
-
"gpt-5.3-codex-medium",
|
|
739
|
-
"gpt-5.3-codex-high",
|
|
740
|
-
"gpt-5.3-codex-xhigh",
|
|
741
|
-
"gpt-5.2-codex-low",
|
|
742
|
-
"gpt-5.2-codex-medium",
|
|
743
|
-
"gpt-5.2-codex-high",
|
|
744
|
-
"gpt-5.2-codex-xhigh",
|
|
745
|
-
"gpt-5.2-low",
|
|
746
|
-
"gpt-5.2-medium",
|
|
747
|
-
"gpt-5.2-high",
|
|
748
|
-
"gpt-5.2-xhigh",
|
|
749
|
-
"gpt-5.1-codex-max-low",
|
|
750
|
-
"gpt-5.1-codex-max-medium",
|
|
751
|
-
"gpt-5.1-codex-max-high",
|
|
752
|
-
"gpt-5.1-codex-max-xhigh",
|
|
753
|
-
"gpt-5.1-codex-mini-medium",
|
|
754
|
-
"gpt-5.1-codex-mini-high",
|
|
755
|
-
"gemini-3-pro-preview",
|
|
756
|
-
"gemini-3-flash-preview",
|
|
757
|
-
"gemini-2.5-pro"
|
|
758
|
-
];
|
|
759
|
-
const CLAUDE_MODEL_MODES = [
|
|
760
|
-
MODEL_MODE_DEFAULT,
|
|
761
|
-
"claude-fable-5",
|
|
762
|
-
"claude-fable-5[1m]",
|
|
763
|
-
"claude-opus-5",
|
|
764
|
-
"claude-opus-5[1m]",
|
|
765
|
-
"claude-opus-4-8",
|
|
766
|
-
"claude-opus-4-8[1m]",
|
|
767
|
-
"claude-opus-4-6",
|
|
768
|
-
"claude-opus-4-6[1m]",
|
|
769
|
-
"claude-sonnet-4-6",
|
|
770
|
-
"claude-sonnet-4-6[1m]",
|
|
771
|
-
"claude-haiku-4-5",
|
|
772
|
-
"claude-fable-5-low",
|
|
773
|
-
"claude-fable-5-medium",
|
|
774
|
-
"claude-fable-5-high",
|
|
775
|
-
"claude-fable-5-xhigh",
|
|
776
|
-
"claude-fable-5-max",
|
|
777
|
-
"claude-fable-5[1m]-low",
|
|
778
|
-
"claude-fable-5[1m]-medium",
|
|
779
|
-
"claude-fable-5[1m]-high",
|
|
780
|
-
"claude-fable-5[1m]-xhigh",
|
|
781
|
-
"claude-fable-5[1m]-max",
|
|
782
|
-
"claude-opus-5-low",
|
|
783
|
-
"claude-opus-5-medium",
|
|
784
|
-
"claude-opus-5-high",
|
|
785
|
-
"claude-opus-5-xhigh",
|
|
786
|
-
"claude-opus-5-max",
|
|
787
|
-
"claude-opus-5[1m]-low",
|
|
788
|
-
"claude-opus-5[1m]-medium",
|
|
789
|
-
"claude-opus-5[1m]-high",
|
|
790
|
-
"claude-opus-5[1m]-xhigh",
|
|
791
|
-
"claude-opus-5[1m]-max",
|
|
792
|
-
"claude-opus-4-8-low",
|
|
793
|
-
"claude-opus-4-8-medium",
|
|
794
|
-
"claude-opus-4-8-high",
|
|
795
|
-
"claude-opus-4-8-xhigh",
|
|
796
|
-
"claude-opus-4-8-max",
|
|
797
|
-
"claude-opus-4-8[1m]-low",
|
|
798
|
-
"claude-opus-4-8[1m]-medium",
|
|
799
|
-
"claude-opus-4-8[1m]-high",
|
|
800
|
-
"claude-opus-4-8[1m]-xhigh",
|
|
801
|
-
"claude-opus-4-8[1m]-max",
|
|
802
|
-
"claude-opus-4-6-low",
|
|
803
|
-
"claude-opus-4-6-medium",
|
|
804
|
-
"claude-opus-4-6-high",
|
|
805
|
-
"claude-opus-4-6-max",
|
|
806
|
-
"claude-opus-4-6[1m]-low",
|
|
807
|
-
"claude-opus-4-6[1m]-medium",
|
|
808
|
-
"claude-opus-4-6[1m]-high",
|
|
809
|
-
"claude-opus-4-6[1m]-max",
|
|
810
|
-
"claude-sonnet-4-6-low",
|
|
811
|
-
"claude-sonnet-4-6-medium",
|
|
812
|
-
"claude-sonnet-4-6-high",
|
|
813
|
-
"claude-sonnet-4-6[1m]-low",
|
|
814
|
-
"claude-sonnet-4-6[1m]-medium",
|
|
815
|
-
"claude-sonnet-4-6[1m]-high",
|
|
816
|
-
"claude-haiku-4-5-low",
|
|
817
|
-
"claude-haiku-4-5-medium",
|
|
818
|
-
"claude-haiku-4-5-high"
|
|
819
|
-
];
|
|
820
|
-
const GEMINI_MODEL_MODES = [
|
|
821
|
-
MODEL_MODE_DEFAULT,
|
|
822
|
-
"gemini-3-pro-preview",
|
|
823
|
-
"gemini-3-flash-preview",
|
|
824
|
-
"gemini-2.5-pro"
|
|
825
|
-
];
|
|
826
|
-
const CODEX_MODEL_MODES = [
|
|
827
|
-
MODEL_MODE_DEFAULT,
|
|
828
|
-
"gpt-5.6-sol-low",
|
|
829
|
-
"gpt-5.6-sol-medium",
|
|
830
|
-
"gpt-5.6-sol-high",
|
|
831
|
-
"gpt-5.6-sol-xhigh",
|
|
832
|
-
"gpt-5.6-sol-max",
|
|
833
|
-
"gpt-5.6-terra-low",
|
|
834
|
-
"gpt-5.6-terra-medium",
|
|
835
|
-
"gpt-5.6-terra-high",
|
|
836
|
-
"gpt-5.6-terra-xhigh",
|
|
837
|
-
"gpt-5.6-luna-low",
|
|
838
|
-
"gpt-5.6-luna-medium",
|
|
839
|
-
"gpt-5.6-luna-high",
|
|
840
|
-
"gpt-5.6-luna-xhigh",
|
|
841
|
-
"gpt-5.5-low",
|
|
842
|
-
"gpt-5.5-medium",
|
|
843
|
-
"gpt-5.5-high",
|
|
844
|
-
"gpt-5.5-xhigh",
|
|
845
|
-
"gpt-5.4-low",
|
|
846
|
-
"gpt-5.4-medium",
|
|
847
|
-
"gpt-5.4-high",
|
|
848
|
-
"gpt-5.4-xhigh",
|
|
849
|
-
"gpt-5.3-codex-low",
|
|
850
|
-
"gpt-5.3-codex-medium",
|
|
851
|
-
"gpt-5.3-codex-high",
|
|
852
|
-
"gpt-5.3-codex-xhigh",
|
|
853
|
-
"gpt-5.2-codex-low",
|
|
854
|
-
"gpt-5.2-codex-medium",
|
|
855
|
-
"gpt-5.2-codex-high",
|
|
856
|
-
"gpt-5.2-codex-xhigh",
|
|
857
|
-
"gpt-5.2-low",
|
|
858
|
-
"gpt-5.2-medium",
|
|
859
|
-
"gpt-5.2-high",
|
|
860
|
-
"gpt-5.2-xhigh",
|
|
861
|
-
"gpt-5.1-codex-max-low",
|
|
862
|
-
"gpt-5.1-codex-max-medium",
|
|
863
|
-
"gpt-5.1-codex-max-high",
|
|
864
|
-
"gpt-5.1-codex-max-xhigh",
|
|
865
|
-
"gpt-5.1-codex-mini-medium",
|
|
866
|
-
"gpt-5.1-codex-mini-high"
|
|
867
|
-
];
|
|
868
|
-
const MODEL_MODE_SET = new Set(MODEL_MODES);
|
|
869
|
-
const CLAUDE_MODEL_MODE_SET = new Set(CLAUDE_MODEL_MODES);
|
|
870
|
-
const GEMINI_MODEL_MODE_SET = new Set(GEMINI_MODEL_MODES);
|
|
871
|
-
const CODEX_MODEL_MODE_SET = new Set(CODEX_MODEL_MODES);
|
|
872
|
-
function isModelMode(value) {
|
|
873
|
-
return MODEL_MODE_SET.has(value);
|
|
874
|
-
}
|
|
875
|
-
function isModelModeForAgent(agent, mode) {
|
|
876
|
-
if (!isModelMode(mode)) return false;
|
|
877
|
-
if (agent === "claude") return CLAUDE_MODEL_MODE_SET.has(mode);
|
|
878
|
-
if (agent === "gemini") return GEMINI_MODEL_MODE_SET.has(mode);
|
|
879
|
-
return CODEX_MODEL_MODE_SET.has(mode);
|
|
880
|
-
}
|
|
881
|
-
const CLAUDE_MODE_TO_SELECTION = {
|
|
882
|
-
"claude-fable-5-low": { family: "claude-fable-5", effort: "low" },
|
|
883
|
-
"claude-fable-5-medium": { family: "claude-fable-5", effort: "medium" },
|
|
884
|
-
"claude-fable-5-high": { family: "claude-fable-5", effort: "high" },
|
|
885
|
-
"claude-fable-5-xhigh": { family: "claude-fable-5", effort: "xhigh" },
|
|
886
|
-
"claude-fable-5-max": { family: "claude-fable-5", effort: "max" },
|
|
887
|
-
"claude-fable-5[1m]-low": { family: "claude-fable-5[1m]", effort: "low" },
|
|
888
|
-
"claude-fable-5[1m]-medium": { family: "claude-fable-5[1m]", effort: "medium" },
|
|
889
|
-
"claude-fable-5[1m]-high": { family: "claude-fable-5[1m]", effort: "high" },
|
|
890
|
-
"claude-fable-5[1m]-xhigh": { family: "claude-fable-5[1m]", effort: "xhigh" },
|
|
891
|
-
"claude-fable-5[1m]-max": { family: "claude-fable-5[1m]", effort: "max" },
|
|
892
|
-
"claude-opus-5-low": { family: "claude-opus-5", effort: "low" },
|
|
893
|
-
"claude-opus-5-medium": { family: "claude-opus-5", effort: "medium" },
|
|
894
|
-
"claude-opus-5-high": { family: "claude-opus-5", effort: "high" },
|
|
895
|
-
"claude-opus-5-xhigh": { family: "claude-opus-5", effort: "xhigh" },
|
|
896
|
-
"claude-opus-5-max": { family: "claude-opus-5", effort: "max" },
|
|
897
|
-
"claude-opus-5[1m]-low": { family: "claude-opus-5[1m]", effort: "low" },
|
|
898
|
-
"claude-opus-5[1m]-medium": { family: "claude-opus-5[1m]", effort: "medium" },
|
|
899
|
-
"claude-opus-5[1m]-high": { family: "claude-opus-5[1m]", effort: "high" },
|
|
900
|
-
"claude-opus-5[1m]-xhigh": { family: "claude-opus-5[1m]", effort: "xhigh" },
|
|
901
|
-
"claude-opus-5[1m]-max": { family: "claude-opus-5[1m]", effort: "max" },
|
|
902
|
-
"claude-opus-4-8-low": { family: "claude-opus-4-8", effort: "low" },
|
|
903
|
-
"claude-opus-4-8-medium": { family: "claude-opus-4-8", effort: "medium" },
|
|
904
|
-
"claude-opus-4-8-high": { family: "claude-opus-4-8", effort: "high" },
|
|
905
|
-
"claude-opus-4-8-xhigh": { family: "claude-opus-4-8", effort: "xhigh" },
|
|
906
|
-
"claude-opus-4-8-max": { family: "claude-opus-4-8", effort: "max" },
|
|
907
|
-
"claude-opus-4-8[1m]-low": { family: "claude-opus-4-8[1m]", effort: "low" },
|
|
908
|
-
"claude-opus-4-8[1m]-medium": { family: "claude-opus-4-8[1m]", effort: "medium" },
|
|
909
|
-
"claude-opus-4-8[1m]-high": { family: "claude-opus-4-8[1m]", effort: "high" },
|
|
910
|
-
"claude-opus-4-8[1m]-xhigh": { family: "claude-opus-4-8[1m]", effort: "xhigh" },
|
|
911
|
-
"claude-opus-4-8[1m]-max": { family: "claude-opus-4-8[1m]", effort: "max" },
|
|
912
|
-
"claude-opus-4-6-low": { family: "claude-opus-4-6", effort: "low" },
|
|
913
|
-
"claude-opus-4-6-medium": { family: "claude-opus-4-6", effort: "medium" },
|
|
914
|
-
"claude-opus-4-6-high": { family: "claude-opus-4-6", effort: "high" },
|
|
915
|
-
"claude-opus-4-6-max": { family: "claude-opus-4-6", effort: "max" },
|
|
916
|
-
"claude-opus-4-6[1m]-low": { family: "claude-opus-4-6[1m]", effort: "low" },
|
|
917
|
-
"claude-opus-4-6[1m]-medium": { family: "claude-opus-4-6[1m]", effort: "medium" },
|
|
918
|
-
"claude-opus-4-6[1m]-high": { family: "claude-opus-4-6[1m]", effort: "high" },
|
|
919
|
-
"claude-opus-4-6[1m]-max": { family: "claude-opus-4-6[1m]", effort: "max" },
|
|
920
|
-
"claude-sonnet-4-6-low": { family: "claude-sonnet-4-6", effort: "low" },
|
|
921
|
-
"claude-sonnet-4-6-medium": { family: "claude-sonnet-4-6", effort: "medium" },
|
|
922
|
-
"claude-sonnet-4-6-high": { family: "claude-sonnet-4-6", effort: "high" },
|
|
923
|
-
"claude-sonnet-4-6[1m]-low": { family: "claude-sonnet-4-6[1m]", effort: "low" },
|
|
924
|
-
"claude-sonnet-4-6[1m]-medium": { family: "claude-sonnet-4-6[1m]", effort: "medium" },
|
|
925
|
-
"claude-sonnet-4-6[1m]-high": { family: "claude-sonnet-4-6[1m]", effort: "high" },
|
|
926
|
-
"claude-haiku-4-5-low": { family: "claude-haiku-4-5", effort: "low" },
|
|
927
|
-
"claude-haiku-4-5-medium": { family: "claude-haiku-4-5", effort: "medium" },
|
|
928
|
-
"claude-haiku-4-5-high": { family: "claude-haiku-4-5", effort: "high" }
|
|
929
|
-
};
|
|
930
|
-
const CODEX_MODE_TO_SELECTION = {
|
|
931
|
-
"gpt-5.6-sol-low": { family: "gpt-5.6-sol", effort: "low" },
|
|
932
|
-
"gpt-5.6-sol-medium": { family: "gpt-5.6-sol", effort: "medium" },
|
|
933
|
-
"gpt-5.6-sol-high": { family: "gpt-5.6-sol", effort: "high" },
|
|
934
|
-
"gpt-5.6-sol-xhigh": { family: "gpt-5.6-sol", effort: "xhigh" },
|
|
935
|
-
"gpt-5.6-sol-max": { family: "gpt-5.6-sol", effort: "max" },
|
|
936
|
-
"gpt-5.6-terra-low": { family: "gpt-5.6-terra", effort: "low" },
|
|
937
|
-
"gpt-5.6-terra-medium": { family: "gpt-5.6-terra", effort: "medium" },
|
|
938
|
-
"gpt-5.6-terra-high": { family: "gpt-5.6-terra", effort: "high" },
|
|
939
|
-
"gpt-5.6-terra-xhigh": { family: "gpt-5.6-terra", effort: "xhigh" },
|
|
940
|
-
"gpt-5.6-luna-low": { family: "gpt-5.6-luna", effort: "low" },
|
|
941
|
-
"gpt-5.6-luna-medium": { family: "gpt-5.6-luna", effort: "medium" },
|
|
942
|
-
"gpt-5.6-luna-high": { family: "gpt-5.6-luna", effort: "high" },
|
|
943
|
-
"gpt-5.6-luna-xhigh": { family: "gpt-5.6-luna", effort: "xhigh" },
|
|
944
|
-
"gpt-5.5-low": { family: "gpt-5.5", effort: "low" },
|
|
945
|
-
"gpt-5.5-medium": { family: "gpt-5.5", effort: "medium" },
|
|
946
|
-
"gpt-5.5-high": { family: "gpt-5.5", effort: "high" },
|
|
947
|
-
"gpt-5.5-xhigh": { family: "gpt-5.5", effort: "xhigh" },
|
|
948
|
-
"gpt-5.4-low": { family: "gpt-5.4", effort: "low" },
|
|
949
|
-
"gpt-5.4-medium": { family: "gpt-5.4", effort: "medium" },
|
|
950
|
-
"gpt-5.4-high": { family: "gpt-5.4", effort: "high" },
|
|
951
|
-
"gpt-5.4-xhigh": { family: "gpt-5.4", effort: "xhigh" },
|
|
952
|
-
"gpt-5.3-codex-low": { family: "gpt-5.3-codex", effort: "low" },
|
|
953
|
-
"gpt-5.3-codex-medium": { family: "gpt-5.3-codex", effort: "medium" },
|
|
954
|
-
"gpt-5.3-codex-high": { family: "gpt-5.3-codex", effort: "high" },
|
|
955
|
-
"gpt-5.3-codex-xhigh": { family: "gpt-5.3-codex", effort: "xhigh" },
|
|
956
|
-
"gpt-5.2-codex-low": { family: "gpt-5.2-codex", effort: "low" },
|
|
957
|
-
"gpt-5.2-codex-medium": { family: "gpt-5.2-codex", effort: "medium" },
|
|
958
|
-
"gpt-5.2-codex-high": { family: "gpt-5.2-codex", effort: "high" },
|
|
959
|
-
"gpt-5.2-codex-xhigh": { family: "gpt-5.2-codex", effort: "xhigh" },
|
|
960
|
-
"gpt-5.2-low": { family: "gpt-5.2", effort: "low" },
|
|
961
|
-
"gpt-5.2-medium": { family: "gpt-5.2", effort: "medium" },
|
|
962
|
-
"gpt-5.2-high": { family: "gpt-5.2", effort: "high" },
|
|
963
|
-
"gpt-5.2-xhigh": { family: "gpt-5.2", effort: "xhigh" },
|
|
964
|
-
"gpt-5.1-codex-max-low": { family: "gpt-5.1-codex-max", effort: "low" },
|
|
965
|
-
"gpt-5.1-codex-max-medium": { family: "gpt-5.1-codex-max", effort: "medium" },
|
|
966
|
-
"gpt-5.1-codex-max-high": { family: "gpt-5.1-codex-max", effort: "high" },
|
|
967
|
-
"gpt-5.1-codex-max-xhigh": { family: "gpt-5.1-codex-max", effort: "xhigh" },
|
|
968
|
-
"gpt-5.1-codex-mini-medium": { family: "gpt-5.1-codex-mini", effort: "medium" },
|
|
969
|
-
"gpt-5.1-codex-mini-high": { family: "gpt-5.1-codex-mini", effort: "high" }
|
|
970
|
-
};
|
|
971
|
-
function parseClaudeModelMode(mode) {
|
|
972
|
-
const entry = CLAUDE_MODE_TO_SELECTION[mode];
|
|
973
|
-
if (entry) return entry;
|
|
974
|
-
if (mode === MODEL_MODE_DEFAULT) return { family: MODEL_MODE_DEFAULT, effort: null };
|
|
975
|
-
return { family: mode, effort: null };
|
|
976
|
-
}
|
|
977
|
-
function parseCodexModelMode(mode) {
|
|
978
|
-
return CODEX_MODE_TO_SELECTION[mode] ?? { family: MODEL_MODE_DEFAULT, effort: "medium" };
|
|
979
|
-
}
|
|
980
|
-
const FeishuWebhookConfigSchema = z$1.object({
|
|
981
|
-
url: z$1.string().url(),
|
|
982
|
-
secret: z$1.string().optional(),
|
|
983
|
-
enabled: z$1.boolean()
|
|
984
|
-
});
|
|
985
|
-
z$1.object({
|
|
986
|
-
url: z$1.string().nullable(),
|
|
987
|
-
secret_set: z$1.boolean(),
|
|
988
|
-
enabled: z$1.boolean(),
|
|
989
|
-
lastTestedAt: z$1.number().nullable()
|
|
990
|
-
});
|
|
991
|
-
z$1.object({
|
|
992
|
-
feishu: FeishuWebhookConfigSchema.extend({
|
|
993
|
-
lastTestedAt: z$1.number().optional()
|
|
994
|
-
}).optional(),
|
|
995
|
-
feishuMention: FeishuWebhookConfigSchema.extend({
|
|
996
|
-
lastTestedAt: z$1.number().optional()
|
|
997
|
-
}).optional(),
|
|
998
|
-
/**
|
|
999
|
-
* The account owner's own Feishu identity (open_id `ou_…` or tenant
|
|
1000
|
-
* user_id). When set, collaboration @ notifications sent to any owner's
|
|
1001
|
-
* mention webhook render this user as a real `<at>` ping instead of
|
|
1002
|
-
* plain text. The ping only fires if the user is in the bot's group.
|
|
1003
|
-
*/
|
|
1004
|
-
feishuUserId: z$1.string().optional()
|
|
1005
|
-
});
|
|
1006
|
-
const MemorySourceSchema = z$1.enum(["manual", "message-pin"]);
|
|
1007
|
-
z$1.object({
|
|
1008
|
-
id: z$1.string(),
|
|
1009
|
-
content: z$1.string().min(1).max(8e3),
|
|
1010
|
-
source: MemorySourceSchema,
|
|
1011
|
-
sourceSessionId: z$1.string().nullable(),
|
|
1012
|
-
sourceMessageId: z$1.string().nullable(),
|
|
1013
|
-
archivedAt: z$1.number().nullable(),
|
|
1014
|
-
createdAt: z$1.number(),
|
|
1015
|
-
updatedAt: z$1.number()
|
|
1016
|
-
});
|
|
1017
|
-
z$1.object({
|
|
1018
|
-
content: z$1.string().min(1).max(8e3),
|
|
1019
|
-
source: MemorySourceSchema.optional().default("manual"),
|
|
1020
|
-
sourceSessionId: z$1.string().optional(),
|
|
1021
|
-
sourceMessageId: z$1.string().optional()
|
|
1022
|
-
});
|
|
1023
|
-
z$1.object({
|
|
1024
|
-
content: z$1.string().min(1).max(8e3)
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
z$1.object({
|
|
1028
|
-
host: z$1.string(),
|
|
1029
|
-
platform: z$1.string(),
|
|
1030
|
-
happyCliVersion: z$1.string(),
|
|
1031
|
-
homeDir: z$1.string(),
|
|
1032
|
-
happyHomeDir: z$1.string(),
|
|
1033
|
-
happyLibDir: z$1.string(),
|
|
1034
|
-
displayName: z$1.string().optional(),
|
|
31
|
+
host: z.string(),
|
|
32
|
+
platform: z.string(),
|
|
33
|
+
happyCliVersion: z.string(),
|
|
34
|
+
homeDir: z.string(),
|
|
35
|
+
happyHomeDir: z.string(),
|
|
36
|
+
happyLibDir: z.string(),
|
|
37
|
+
displayName: z.string().optional(),
|
|
1035
38
|
// True when this machine was added with `happy device enroll`: it serves
|
|
1036
39
|
// shell/files/terminal over machine RPC but refuses `spawn-happy-session`,
|
|
1037
40
|
// so clients must keep it out of session pickers.
|
|
1038
|
-
deviceMode: z
|
|
41
|
+
deviceMode: z.boolean().optional()
|
|
1039
42
|
});
|
|
1040
|
-
z
|
|
1041
|
-
status: z
|
|
1042
|
-
z
|
|
1043
|
-
z
|
|
43
|
+
z.object({
|
|
44
|
+
status: z.union([
|
|
45
|
+
z.enum(["running", "shutting-down"]),
|
|
46
|
+
z.string()
|
|
1044
47
|
// Forward compatibility
|
|
1045
48
|
]),
|
|
1046
|
-
pid: z
|
|
1047
|
-
httpPort: z
|
|
1048
|
-
startedAt: z
|
|
1049
|
-
shutdownRequestedAt: z
|
|
1050
|
-
shutdownSource: z
|
|
1051
|
-
z
|
|
1052
|
-
z
|
|
49
|
+
pid: z.number().optional(),
|
|
50
|
+
httpPort: z.number().optional(),
|
|
51
|
+
startedAt: z.number().optional(),
|
|
52
|
+
shutdownRequestedAt: z.number().optional(),
|
|
53
|
+
shutdownSource: z.union([
|
|
54
|
+
z.enum(["mobile-app", "cli", "os-signal", "unknown"]),
|
|
55
|
+
z.string()
|
|
1053
56
|
// Forward compatibility
|
|
1054
57
|
]).optional()
|
|
1055
58
|
});
|
|
1056
|
-
const CollaborationMentionMetaSchema = z
|
|
1057
|
-
kind: z
|
|
1058
|
-
targetUserIds: z
|
|
1059
|
-
targetUsernames: z
|
|
59
|
+
const CollaborationMentionMetaSchema = z.object({
|
|
60
|
+
kind: z.literal("mention"),
|
|
61
|
+
targetUserIds: z.array(z.string()).default([]),
|
|
62
|
+
targetUsernames: z.array(z.string()).default([])
|
|
1060
63
|
});
|
|
1061
|
-
const MessageMetaSchema = z
|
|
1062
|
-
sentFrom: z
|
|
64
|
+
const MessageMetaSchema = z.object({
|
|
65
|
+
sentFrom: z.string().optional(),
|
|
1063
66
|
// Source identifier
|
|
1064
|
-
permissionMode: z
|
|
67
|
+
permissionMode: z.enum(["default", "acceptEdits", "bypassPermissions", "plan", "read-only", "safe-yolo", "yolo"]).optional(),
|
|
1065
68
|
// Permission mode for this message
|
|
1066
|
-
model: z
|
|
69
|
+
model: z.string().nullable().optional(),
|
|
1067
70
|
// Model name for this message (null = reset)
|
|
1068
|
-
reasoningEffort: z
|
|
71
|
+
reasoningEffort: z.string().nullable().optional(),
|
|
1069
72
|
// Reasoning effort for this message (null = reset)
|
|
1070
|
-
fallbackModel: z
|
|
73
|
+
fallbackModel: z.string().nullable().optional(),
|
|
1071
74
|
// Fallback model for this message (null = reset)
|
|
1072
|
-
customSystemPrompt: z
|
|
75
|
+
customSystemPrompt: z.string().nullable().optional(),
|
|
1073
76
|
// Custom system prompt for this message (null = reset)
|
|
1074
|
-
appendSystemPrompt: z
|
|
77
|
+
appendSystemPrompt: z.string().nullable().optional(),
|
|
1075
78
|
// Append to system prompt for this message (null = reset)
|
|
1076
|
-
allowedTools: z
|
|
79
|
+
allowedTools: z.array(z.string()).nullable().optional(),
|
|
1077
80
|
// Allowed tools for this message (null = reset)
|
|
1078
|
-
disallowedTools: z
|
|
81
|
+
disallowedTools: z.array(z.string()).nullable().optional(),
|
|
1079
82
|
// Disallowed tools for this message (null = reset)
|
|
1080
|
-
displayText: z
|
|
1081
|
-
humanOnly: z
|
|
1082
|
-
skipAiContext: z
|
|
83
|
+
displayText: z.string().optional(),
|
|
84
|
+
humanOnly: z.boolean().optional(),
|
|
85
|
+
skipAiContext: z.boolean().optional(),
|
|
1083
86
|
collaboration: CollaborationMentionMetaSchema.optional()
|
|
1084
87
|
});
|
|
1085
|
-
z
|
|
1086
|
-
session: z
|
|
1087
|
-
id: z
|
|
1088
|
-
tag: z
|
|
1089
|
-
seq: z
|
|
1090
|
-
createdAt: z
|
|
1091
|
-
updatedAt: z
|
|
1092
|
-
metadata: z
|
|
1093
|
-
metadataVersion: z
|
|
1094
|
-
agentState: z
|
|
1095
|
-
agentStateVersion: z
|
|
88
|
+
z.object({
|
|
89
|
+
session: z.object({
|
|
90
|
+
id: z.string(),
|
|
91
|
+
tag: z.string(),
|
|
92
|
+
seq: z.number(),
|
|
93
|
+
createdAt: z.number(),
|
|
94
|
+
updatedAt: z.number(),
|
|
95
|
+
metadata: z.string(),
|
|
96
|
+
metadataVersion: z.number(),
|
|
97
|
+
agentState: z.string().nullable(),
|
|
98
|
+
agentStateVersion: z.number()
|
|
1096
99
|
})
|
|
1097
100
|
});
|
|
1098
|
-
const ImageContentSchema = z
|
|
1099
|
-
type: z
|
|
1100
|
-
url: z
|
|
1101
|
-
width: z
|
|
1102
|
-
height: z
|
|
1103
|
-
mimeType: z
|
|
1104
|
-
thumbhash: z
|
|
101
|
+
const ImageContentSchema = z.object({
|
|
102
|
+
type: z.literal("image"),
|
|
103
|
+
url: z.string(),
|
|
104
|
+
width: z.number(),
|
|
105
|
+
height: z.number(),
|
|
106
|
+
mimeType: z.string(),
|
|
107
|
+
thumbhash: z.string().optional()
|
|
1105
108
|
});
|
|
1106
|
-
const UserMessageSchema = z
|
|
1107
|
-
role: z
|
|
1108
|
-
content: z
|
|
1109
|
-
z
|
|
1110
|
-
type: z
|
|
1111
|
-
text: z
|
|
109
|
+
const UserMessageSchema = z.object({
|
|
110
|
+
role: z.literal("user"),
|
|
111
|
+
content: z.union([
|
|
112
|
+
z.object({
|
|
113
|
+
type: z.literal("text"),
|
|
114
|
+
text: z.string()
|
|
1112
115
|
}),
|
|
1113
|
-
z
|
|
1114
|
-
type: z
|
|
1115
|
-
text: z
|
|
1116
|
-
images: z
|
|
116
|
+
z.object({
|
|
117
|
+
type: z.literal("mixed"),
|
|
118
|
+
text: z.string(),
|
|
119
|
+
images: z.array(ImageContentSchema)
|
|
1117
120
|
})
|
|
1118
121
|
]),
|
|
1119
|
-
localKey: z
|
|
122
|
+
localKey: z.string().optional(),
|
|
1120
123
|
meta: MessageMetaSchema.optional()
|
|
1121
124
|
});
|
|
1122
|
-
const AgentMessageSchema = z
|
|
1123
|
-
role: z
|
|
1124
|
-
content: z
|
|
1125
|
-
type: z
|
|
1126
|
-
data: z
|
|
125
|
+
const AgentMessageSchema = z.object({
|
|
126
|
+
role: z.literal("agent"),
|
|
127
|
+
content: z.object({
|
|
128
|
+
type: z.literal("output"),
|
|
129
|
+
data: z.any()
|
|
1127
130
|
}),
|
|
1128
131
|
meta: MessageMetaSchema.optional()
|
|
1129
132
|
});
|
|
1130
|
-
z
|
|
1131
|
-
|
|
1132
|
-
function encodeBase64(buffer, variant = "base64") {
|
|
1133
|
-
if (variant === "base64url") {
|
|
1134
|
-
return encodeBase64Url(buffer);
|
|
1135
|
-
}
|
|
1136
|
-
return Buffer.from(buffer).toString("base64");
|
|
1137
|
-
}
|
|
1138
|
-
function encodeBase64Url(buffer) {
|
|
1139
|
-
return Buffer.from(buffer).toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
1140
|
-
}
|
|
1141
|
-
function decodeBase64(base64, variant = "base64") {
|
|
1142
|
-
if (variant === "base64url") {
|
|
1143
|
-
const base64Standard = base64.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - base64.length % 4) % 4);
|
|
1144
|
-
return new Uint8Array(Buffer.from(base64Standard, "base64"));
|
|
1145
|
-
}
|
|
1146
|
-
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
1147
|
-
}
|
|
1148
|
-
function getRandomBytes(size) {
|
|
1149
|
-
return new Uint8Array(randomBytes(size));
|
|
1150
|
-
}
|
|
1151
|
-
function libsodiumPublicKeyFromSecretKey(seed) {
|
|
1152
|
-
const hashedSeed = new Uint8Array(createHash("sha512").update(seed).digest());
|
|
1153
|
-
const secretKey = hashedSeed.slice(0, 32);
|
|
1154
|
-
return new Uint8Array(tweetnacl.box.keyPair.fromSecretKey(secretKey).publicKey);
|
|
1155
|
-
}
|
|
1156
|
-
function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
|
|
1157
|
-
const ephemeralKeyPair = tweetnacl.box.keyPair();
|
|
1158
|
-
const nonce = getRandomBytes(tweetnacl.box.nonceLength);
|
|
1159
|
-
const encrypted = tweetnacl.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
|
|
1160
|
-
const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
|
|
1161
|
-
result.set(ephemeralKeyPair.publicKey, 0);
|
|
1162
|
-
result.set(nonce, ephemeralKeyPair.publicKey.length);
|
|
1163
|
-
result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
|
|
1164
|
-
return result;
|
|
1165
|
-
}
|
|
1166
|
-
function encryptLegacy(data, secret) {
|
|
1167
|
-
const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
|
|
1168
|
-
const encrypted = tweetnacl.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
|
|
1169
|
-
const result = new Uint8Array(nonce.length + encrypted.length);
|
|
1170
|
-
result.set(nonce);
|
|
1171
|
-
result.set(encrypted, nonce.length);
|
|
1172
|
-
return result;
|
|
1173
|
-
}
|
|
1174
|
-
function decryptLegacy(data, secret) {
|
|
1175
|
-
const nonce = data.slice(0, tweetnacl.secretbox.nonceLength);
|
|
1176
|
-
const encrypted = data.slice(tweetnacl.secretbox.nonceLength);
|
|
1177
|
-
const decrypted = tweetnacl.secretbox.open(encrypted, nonce, secret);
|
|
1178
|
-
if (!decrypted) {
|
|
1179
|
-
return null;
|
|
1180
|
-
}
|
|
1181
|
-
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
1182
|
-
}
|
|
1183
|
-
function encryptWithDataKey(data, dataKey) {
|
|
1184
|
-
const nonce = getRandomBytes(12);
|
|
1185
|
-
const cipher = createCipheriv("aes-256-gcm", dataKey, nonce);
|
|
1186
|
-
const plaintext = new TextEncoder().encode(JSON.stringify(data));
|
|
1187
|
-
const encrypted = Buffer.concat([
|
|
1188
|
-
cipher.update(plaintext),
|
|
1189
|
-
cipher.final()
|
|
1190
|
-
]);
|
|
1191
|
-
const authTag = cipher.getAuthTag();
|
|
1192
|
-
const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
|
|
1193
|
-
bundle.set([0], 0);
|
|
1194
|
-
bundle.set(nonce, 1);
|
|
1195
|
-
bundle.set(new Uint8Array(encrypted), 13);
|
|
1196
|
-
bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
|
|
1197
|
-
return bundle;
|
|
1198
|
-
}
|
|
1199
|
-
function decryptWithDataKey(bundle, dataKey) {
|
|
1200
|
-
if (bundle.length < 1) {
|
|
1201
|
-
return null;
|
|
1202
|
-
}
|
|
1203
|
-
if (bundle[0] !== 0) {
|
|
1204
|
-
return null;
|
|
1205
|
-
}
|
|
1206
|
-
if (bundle.length < 12 + 16 + 1) {
|
|
1207
|
-
return null;
|
|
1208
|
-
}
|
|
1209
|
-
const nonce = bundle.slice(1, 13);
|
|
1210
|
-
const authTag = bundle.slice(bundle.length - 16);
|
|
1211
|
-
const ciphertext = bundle.slice(13, bundle.length - 16);
|
|
1212
|
-
try {
|
|
1213
|
-
const decipher = createDecipheriv("aes-256-gcm", dataKey, nonce);
|
|
1214
|
-
decipher.setAuthTag(authTag);
|
|
1215
|
-
const decrypted = Buffer.concat([
|
|
1216
|
-
decipher.update(ciphertext),
|
|
1217
|
-
decipher.final()
|
|
1218
|
-
]);
|
|
1219
|
-
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
1220
|
-
} catch (error) {
|
|
1221
|
-
return null;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
function encrypt(key, variant, data) {
|
|
1225
|
-
if (variant === "legacy") {
|
|
1226
|
-
return encryptLegacy(data, key);
|
|
1227
|
-
} else {
|
|
1228
|
-
return encryptWithDataKey(data, key);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
function decrypt(key, variant, data) {
|
|
1232
|
-
if (variant === "legacy") {
|
|
1233
|
-
return decryptLegacy(data, key);
|
|
1234
|
-
} else {
|
|
1235
|
-
return decryptWithDataKey(data, key);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
async function delay(ms) {
|
|
1240
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1241
|
-
}
|
|
1242
|
-
function exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount) {
|
|
1243
|
-
let maxDelayRet = minDelay + (maxDelay - minDelay) / maxFailureCount * Math.min(currentFailureCount, maxFailureCount);
|
|
1244
|
-
return Math.round(Math.random() * maxDelayRet);
|
|
1245
|
-
}
|
|
1246
|
-
function createBackoff(opts) {
|
|
1247
|
-
return async (callback) => {
|
|
1248
|
-
let currentFailureCount = 0;
|
|
1249
|
-
const minDelay = 250;
|
|
1250
|
-
const maxDelay = 1e3;
|
|
1251
|
-
const maxFailureCount = 50;
|
|
1252
|
-
while (true) {
|
|
1253
|
-
try {
|
|
1254
|
-
return await callback();
|
|
1255
|
-
} catch (e) {
|
|
1256
|
-
if (currentFailureCount < maxFailureCount) {
|
|
1257
|
-
currentFailureCount++;
|
|
1258
|
-
}
|
|
1259
|
-
let waitForRequest = exponentialBackoffDelay(currentFailureCount, minDelay, maxDelay, maxFailureCount);
|
|
1260
|
-
await delay(waitForRequest);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
let backoff = createBackoff();
|
|
133
|
+
z.union([UserMessageSchema, AgentMessageSchema]);
|
|
1266
134
|
|
|
1267
135
|
class AsyncLock {
|
|
1268
136
|
permits = 1;
|
|
@@ -1962,12 +830,12 @@ function hasCompletionSemantics(text, customPhrases) {
|
|
|
1962
830
|
return hasEvidence || normalized.length <= 24;
|
|
1963
831
|
}
|
|
1964
832
|
|
|
1965
|
-
const ReviewResultSchema = z
|
|
1966
|
-
status: z
|
|
1967
|
-
summary: z
|
|
1968
|
-
missing: z
|
|
1969
|
-
evidence: z
|
|
1970
|
-
confidence: z
|
|
833
|
+
const ReviewResultSchema = z.object({
|
|
834
|
+
status: z.enum(["pass", "needs_follow_up", "uncertain"]),
|
|
835
|
+
summary: z.string(),
|
|
836
|
+
missing: z.array(z.string()),
|
|
837
|
+
evidence: z.array(z.string()),
|
|
838
|
+
confidence: z.enum(["high", "medium", "low"])
|
|
1971
839
|
});
|
|
1972
840
|
const DEFAULT_REVIEW_PROMPT = "\u4F60\u662F\u4EE3\u7801\u5B8C\u6210\u5EA6\u5BA1\u67E5 AI\u3002\u53EA\u5BA1\u67E5\u4EE3\u7801\u5B8C\u6210\u5EA6\uFF1A\u662F\u5426\u5BF9\u6807\u660E\u786E\u9700\u6C42\u3001GitHub Issue\u3001\u7528\u6237\u8865\u5145\u8981\u6C42\u3001brainstorming/pma/writing-plans \u8BA1\u5212\u3001git diff \u4E0E\u9A8C\u8BC1\u8BC1\u636E\u3002\u4E0D\u8981\u63D0\u51FA\u65E0\u5173\u91CD\u6784\u3001\u6CDB\u6CDB\u4F18\u5316\u3001\u6027\u80FD/\u5B89\u5168\u6DF1\u6316\uFF0C\u9664\u975E\u4EFB\u52A1\u660E\u786E\u8981\u6C42\u3002\u5982\u679C\u4E0A\u4E0B\u6587\u5305\u542B\u539F\u578B\u56FE\u3001\u539F\u578B\u4EE3\u7801\u3001prototype\u3001supervisor\u3001design\u3001Figma \u7B49\u5F15\u7528\uFF0C\u53EA\u5728\u4EE3\u7801\u5C42\u9762\u989D\u5916\u5BA1\u67E5 UI \u662F\u5426\u5BF9\u9F50\u539F\u578B\uFF1A\u7ED3\u6784\u3001\u5E03\u5C40\u3001\u6587\u6848\u3001\u72B6\u6001\u3001\u4EA4\u4E92\u548C\u6837\u5F0F token \u662F\u5426\u6709\u660E\u663E\u6F0F\u9879\uFF1B\u4E0D\u8981\u505A\u622A\u56FE/\u6D4F\u89C8\u5668/\u89C6\u89C9\u50CF\u7D20\u6BD4\u5BF9\u3002";
|
|
1973
841
|
const REVIEW_OUTPUT_CONTRACT = '\u4F60\u5FC5\u987B\u4FDD\u6301\u53EA\u8BFB\uFF1A\u4E0D\u8981\u4FEE\u6539\u6587\u4EF6\uFF0C\u4E0D\u8981\u6267\u884C\u4F1A\u6539\u53D8\u5DE5\u4F5C\u533A/\u7CFB\u7EDF\u72B6\u6001\u7684\u547D\u4EE4\uFF0C\u4E0D\u8981\u63D0\u4EA4\u3001\u63A8\u9001\u6216\u5B89\u88C5\u4F9D\u8D56\u3002\u4F60\u8FD0\u884C\u5728\u9694\u79BB\u76EE\u5F55\u4E2D\uFF1B\u4E0D\u8981\u628A\u9694\u79BB\u76EE\u5F55\uFF08\u4F8B\u5982 /tmp\uFF09\u4E0D\u662F git \u4ED3\u5E93\u5F53\u4F5C\u6F0F\u9879\u3002\u4EE3\u7801\u8BC1\u636E\u5DF2\u7ECF\u5728\u4E0B\u65B9\u9884\u91C7\u96C6\uFF0C\u8BF7\u53EA\u57FA\u4E8E\u4E0B\u65B9 GitHub Issue\u3001\u7528\u6237\u8981\u6C42\u3001\u8BA1\u5212\u3001\u4F1A\u8BDD\u6458\u8981\u548C\u4EE3\u7801\u8BC1\u636E\u5BA1\u67E5\u3002\u4E0D\u8981\u8981\u6C42\u8BFB\u53D6 it-note MCP\u3001AGENTS.md\u3001CLAUDE.md \u6216\u5176\u4ED6\u5916\u90E8\u89C4\u5219\uFF1B\u8FD9\u4E9B\u4E0D\u5C5E\u4E8E\u672C\u6B21\u81EA\u52A8\u5B8C\u6210\u5EA6\u5BA1\u67E5\u8303\u56F4\u3002\u8BF7\u53EA\u8F93\u51FA JSON\uFF0C\u4E0D\u8981\u8F93\u51FA Markdown\u3002\u683C\u5F0F\uFF1A{"status":"pass|needs_follow_up|uncertain","summary":"...","missing":["..."],"evidence":["..."],"confidence":"high|medium|low"}';
|
|
@@ -2479,12 +1347,6 @@ No git repository was found from session cwd or workspace repo metadata. Session
|
|
|
2479
1347
|
};
|
|
2480
1348
|
}
|
|
2481
1349
|
|
|
2482
|
-
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
2483
|
-
function projectPath() {
|
|
2484
|
-
const path = resolve(__dirname$1, "..");
|
|
2485
|
-
return path;
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
1350
|
function run$1(args, options) {
|
|
2489
1351
|
const RUNNER_PATH = resolve(join$1(projectPath(), "scripts", "ripgrep_launcher.cjs"));
|
|
2490
1352
|
return new Promise((resolve2, reject) => {
|
|
@@ -2531,7 +1393,7 @@ function resolveToolsDir() {
|
|
|
2531
1393
|
function findToolsDir() {
|
|
2532
1394
|
try {
|
|
2533
1395
|
const manifest = createRequire(import.meta.url).resolve(`${toolsPackageName()}/package.json`);
|
|
2534
|
-
return dirname
|
|
1396
|
+
return dirname(manifest);
|
|
2535
1397
|
} catch {
|
|
2536
1398
|
}
|
|
2537
1399
|
return legacyToolsDir();
|
|
@@ -2596,7 +1458,7 @@ let loadError = null;
|
|
|
2596
1458
|
function ensureSpawnHelperExecutable() {
|
|
2597
1459
|
if (process.platform === "win32") return;
|
|
2598
1460
|
try {
|
|
2599
|
-
const root = dirname
|
|
1461
|
+
const root = dirname(dirname(require.resolve("node-pty")));
|
|
2600
1462
|
const candidates = [
|
|
2601
1463
|
join(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
|
|
2602
1464
|
join(root, "build", "Release", "spawn-helper")
|
|
@@ -2686,7 +1548,7 @@ function spawnShell(opts) {
|
|
|
2686
1548
|
}
|
|
2687
1549
|
const shell = process.env.SHELL || (process.platform === "win32" ? "powershell.exe" : "bash");
|
|
2688
1550
|
const cwd = opts.cwd ?? process.cwd();
|
|
2689
|
-
const shellArgs = process.platform
|
|
1551
|
+
const shellArgs = process.platform === "win32" ? [] : isBashShell(shell) ? ["--rcfile", createHappyBashRc(), "-i"] : ["-l", "-i"];
|
|
2690
1552
|
const shellEnv = { ...process.env };
|
|
2691
1553
|
delete shellEnv.NO_COLOR;
|
|
2692
1554
|
delete shellEnv.NODE_DISABLE_COLORS;
|
|
@@ -2841,7 +1703,7 @@ function resolveSessionUploadPaths(params) {
|
|
|
2841
1703
|
tempRelativePath,
|
|
2842
1704
|
absolutePath,
|
|
2843
1705
|
tempAbsolutePath,
|
|
2844
|
-
directory: dirname(absolutePath)
|
|
1706
|
+
directory: dirname$1(absolutePath)
|
|
2845
1707
|
};
|
|
2846
1708
|
}
|
|
2847
1709
|
|
|
@@ -2862,6 +1724,10 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory, sessionId)
|
|
|
2862
1724
|
cwd: data.cwd === "/" ? void 0 : data.cwd,
|
|
2863
1725
|
timeout: data.timeout || 3e4,
|
|
2864
1726
|
// Default 30 seconds timeout
|
|
1727
|
+
// node's 1MB default kills the child and reports failure once
|
|
1728
|
+
// output crosses it — the command has already succeeded by
|
|
1729
|
+
// then, and the caller sees a truncated result with an error.
|
|
1730
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
2865
1731
|
// launchd and systemd hand the daemon a bare PATH, so without
|
|
2866
1732
|
// this a command that works when typed into the device terminal
|
|
2867
1733
|
// fails here with "command not found".
|
|
@@ -3403,19 +2269,24 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory, sessionId)
|
|
|
3403
2269
|
};
|
|
3404
2270
|
});
|
|
3405
2271
|
const outboundStates = /* @__PURE__ */ new Map();
|
|
3406
|
-
const emitEncrypted = (event, payload) => {
|
|
2272
|
+
const emitEncrypted = (event, payload, reliable = false) => {
|
|
3407
2273
|
const socket = rpcHandlerManager.getSocket();
|
|
3408
2274
|
if (!socket || !socket.connected) {
|
|
3409
2275
|
return;
|
|
3410
2276
|
}
|
|
3411
2277
|
const envelope = { sessionId: payload.sessionId, ptyId: payload.ptyId };
|
|
3412
|
-
if (
|
|
2278
|
+
if (reliable) envelope.reliable = true;
|
|
2279
|
+
if (event === "pty-output" && payload.data !== void 0) {
|
|
3413
2280
|
const key = rpcHandlerManager.getEncryptionKey();
|
|
3414
2281
|
const variant = rpcHandlerManager.getEncryptionVariant();
|
|
3415
2282
|
envelope.data = encodeBase64(encrypt(key, variant, payload.data));
|
|
3416
2283
|
} else if (event === "pty-exit" && typeof payload.exitCode === "number") {
|
|
3417
2284
|
envelope.exitCode = payload.exitCode;
|
|
3418
2285
|
}
|
|
2286
|
+
if (reliable) {
|
|
2287
|
+
socket.emit(event, envelope);
|
|
2288
|
+
return;
|
|
2289
|
+
}
|
|
3419
2290
|
socket.volatile.emit(event, envelope);
|
|
3420
2291
|
};
|
|
3421
2292
|
const splitOnUtf8Boundary = (merged) => {
|
|
@@ -3472,7 +2343,73 @@ function registerCommonHandlers(rpcHandlerManager, workingDirectory, sessionId)
|
|
|
3472
2343
|
outboundStates.delete(ptyId);
|
|
3473
2344
|
};
|
|
3474
2345
|
rpcHandlerManager.registerHandler("pty-start", async (data) => {
|
|
3475
|
-
logger.debug("[pty-start] request", { cols: data.cols, rows: data.rows, cwd: data.cwd });
|
|
2346
|
+
logger.debug("[pty-start] request", { cols: data.cols, rows: data.rows, cwd: data.cwd, exec: !!data.exec });
|
|
2347
|
+
if (data.exec) {
|
|
2348
|
+
const execId = randomUUID();
|
|
2349
|
+
const child = spawn$1(process.env.SHELL || "/bin/sh", ["-c", data.exec.command], {
|
|
2350
|
+
cwd: data.cwd,
|
|
2351
|
+
env: await resolveLoginShellEnv(),
|
|
2352
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2353
|
+
});
|
|
2354
|
+
const killTimer = setTimeout(() => child.kill("SIGTERM"), data.exec.timeoutMs ?? 3e5);
|
|
2355
|
+
child.stdout?.pause();
|
|
2356
|
+
child.stderr?.pause();
|
|
2357
|
+
setImmediate(() => {
|
|
2358
|
+
child.stdout?.resume();
|
|
2359
|
+
child.stderr?.resume();
|
|
2360
|
+
});
|
|
2361
|
+
const pending = { stdout: [], stderr: [] };
|
|
2362
|
+
let pendingBytes = 0;
|
|
2363
|
+
let frameCount = 0;
|
|
2364
|
+
let flushTimer = null;
|
|
2365
|
+
const flushExec = () => {
|
|
2366
|
+
if (flushTimer) {
|
|
2367
|
+
clearTimeout(flushTimer);
|
|
2368
|
+
flushTimer = null;
|
|
2369
|
+
}
|
|
2370
|
+
pendingBytes = 0;
|
|
2371
|
+
frameCount++;
|
|
2372
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
2373
|
+
if (pending[stream].length === 0) continue;
|
|
2374
|
+
const chunk = Buffer.concat(pending[stream]);
|
|
2375
|
+
pending[stream] = [];
|
|
2376
|
+
emitEncrypted("pty-output", {
|
|
2377
|
+
sessionId,
|
|
2378
|
+
ptyId: execId,
|
|
2379
|
+
data: { stream, chunk: chunk.toString("base64") }
|
|
2380
|
+
}, true);
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
for (const [stream, source] of [["stdout", child.stdout], ["stderr", child.stderr]]) {
|
|
2384
|
+
source?.on("data", (chunk) => {
|
|
2385
|
+
pending[stream].push(chunk);
|
|
2386
|
+
pendingBytes += chunk.length;
|
|
2387
|
+
if (pendingBytes >= PTY_OUTPUT_FLUSH_BYTES) {
|
|
2388
|
+
flushExec();
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
if (!flushTimer) flushTimer = setTimeout(flushExec, PTY_OUTPUT_FLUSH_MS);
|
|
2392
|
+
});
|
|
2393
|
+
}
|
|
2394
|
+
child.on("close", (code, signal) => {
|
|
2395
|
+
clearTimeout(killTimer);
|
|
2396
|
+
logger.debug(`[exec] close code=${code} signal=${signal} pending=${pendingBytes}`);
|
|
2397
|
+
flushExec();
|
|
2398
|
+
logger.debug(`[exec] flushed ${frameCount} frames, emitting exit`);
|
|
2399
|
+
emitEncrypted("pty-exit", { sessionId, ptyId: execId, exitCode: code ?? (signal ? 143 : 1) }, true);
|
|
2400
|
+
});
|
|
2401
|
+
child.on("error", (error) => {
|
|
2402
|
+
clearTimeout(killTimer);
|
|
2403
|
+
emitEncrypted("pty-output", {
|
|
2404
|
+
sessionId,
|
|
2405
|
+
ptyId: execId,
|
|
2406
|
+
data: { stream: "stderr", chunk: Buffer.from(`${error.message}
|
|
2407
|
+
`).toString("base64") }
|
|
2408
|
+
}, true);
|
|
2409
|
+
emitEncrypted("pty-exit", { sessionId, ptyId: execId, exitCode: 1 }, true);
|
|
2410
|
+
});
|
|
2411
|
+
return { ok: true, ptyId: execId };
|
|
2412
|
+
}
|
|
3476
2413
|
try {
|
|
3477
2414
|
const { ptyId, term } = spawnShell({
|
|
3478
2415
|
cols: data.cols,
|
|
@@ -4760,376 +3697,6 @@ class ApiSessionClient extends EventEmitter {
|
|
|
4760
3697
|
}
|
|
4761
3698
|
}
|
|
4762
3699
|
|
|
4763
|
-
const AnthropicConfigSchema = z.object({
|
|
4764
|
-
baseUrl: z.string().url().optional(),
|
|
4765
|
-
authToken: z.string().optional(),
|
|
4766
|
-
model: z.string().optional()
|
|
4767
|
-
});
|
|
4768
|
-
const OpenAIConfigSchema = z.object({
|
|
4769
|
-
apiKey: z.string().optional(),
|
|
4770
|
-
baseUrl: z.string().url().optional(),
|
|
4771
|
-
model: z.string().optional()
|
|
4772
|
-
});
|
|
4773
|
-
const AzureOpenAIConfigSchema = z.object({
|
|
4774
|
-
apiKey: z.string().optional(),
|
|
4775
|
-
endpoint: z.string().url().optional(),
|
|
4776
|
-
apiVersion: z.string().optional(),
|
|
4777
|
-
deploymentName: z.string().optional()
|
|
4778
|
-
});
|
|
4779
|
-
const TogetherAIConfigSchema = z.object({
|
|
4780
|
-
apiKey: z.string().optional(),
|
|
4781
|
-
model: z.string().optional()
|
|
4782
|
-
});
|
|
4783
|
-
const TmuxConfigSchema = z.object({
|
|
4784
|
-
sessionName: z.string().optional(),
|
|
4785
|
-
tmpDir: z.string().optional(),
|
|
4786
|
-
updateEnvironment: z.boolean().optional()
|
|
4787
|
-
});
|
|
4788
|
-
const EnvironmentVariableSchema = z.object({
|
|
4789
|
-
name: z.string().regex(/^[A-Z_][A-Z0-9_]*$/, "Invalid environment variable name"),
|
|
4790
|
-
value: z.string()
|
|
4791
|
-
});
|
|
4792
|
-
const ProfileCompatibilitySchema = z.object({
|
|
4793
|
-
claude: z.boolean().default(true),
|
|
4794
|
-
codex: z.boolean().default(true),
|
|
4795
|
-
gemini: z.boolean().default(true)
|
|
4796
|
-
});
|
|
4797
|
-
const AIBackendProfileSchema = z.object({
|
|
4798
|
-
id: z.string().uuid(),
|
|
4799
|
-
name: z.string().min(1).max(100),
|
|
4800
|
-
description: z.string().max(500).optional(),
|
|
4801
|
-
// Agent-specific configurations
|
|
4802
|
-
anthropicConfig: AnthropicConfigSchema.optional(),
|
|
4803
|
-
openaiConfig: OpenAIConfigSchema.optional(),
|
|
4804
|
-
azureOpenAIConfig: AzureOpenAIConfigSchema.optional(),
|
|
4805
|
-
togetherAIConfig: TogetherAIConfigSchema.optional(),
|
|
4806
|
-
// Tmux configuration
|
|
4807
|
-
tmuxConfig: TmuxConfigSchema.optional(),
|
|
4808
|
-
// Environment variables (validated)
|
|
4809
|
-
environmentVariables: z.array(EnvironmentVariableSchema).default([]),
|
|
4810
|
-
// Default session type for this profile
|
|
4811
|
-
defaultSessionType: z.enum(["simple", "worktree"]).optional(),
|
|
4812
|
-
// Default permission mode for this profile (supports both Claude and Codex modes)
|
|
4813
|
-
defaultPermissionMode: z.enum([
|
|
4814
|
-
"default",
|
|
4815
|
-
"acceptEdits",
|
|
4816
|
-
"bypassPermissions",
|
|
4817
|
-
"plan",
|
|
4818
|
-
// Claude modes
|
|
4819
|
-
"read-only",
|
|
4820
|
-
"safe-yolo",
|
|
4821
|
-
"yolo"
|
|
4822
|
-
// Codex modes
|
|
4823
|
-
]).optional(),
|
|
4824
|
-
// Default model mode for this profile
|
|
4825
|
-
defaultModelMode: z.string().optional(),
|
|
4826
|
-
// Compatibility metadata
|
|
4827
|
-
compatibility: ProfileCompatibilitySchema.default({ claude: true, codex: true, gemini: true }),
|
|
4828
|
-
// Built-in profile indicator
|
|
4829
|
-
isBuiltIn: z.boolean().default(false),
|
|
4830
|
-
// Metadata
|
|
4831
|
-
createdAt: z.number().default(() => Date.now()),
|
|
4832
|
-
updatedAt: z.number().default(() => Date.now()),
|
|
4833
|
-
version: z.string().default("1.0.0")
|
|
4834
|
-
});
|
|
4835
|
-
function validateProfileForAgent(profile, agent) {
|
|
4836
|
-
return profile.compatibility[agent];
|
|
4837
|
-
}
|
|
4838
|
-
function getProfileEnvironmentVariables(profile) {
|
|
4839
|
-
const envVars = {};
|
|
4840
|
-
profile.environmentVariables.forEach((envVar) => {
|
|
4841
|
-
envVars[envVar.name] = envVar.value;
|
|
4842
|
-
});
|
|
4843
|
-
if (profile.anthropicConfig) {
|
|
4844
|
-
if (profile.anthropicConfig.baseUrl) envVars.ANTHROPIC_BASE_URL = profile.anthropicConfig.baseUrl;
|
|
4845
|
-
if (profile.anthropicConfig.authToken) envVars.ANTHROPIC_AUTH_TOKEN = profile.anthropicConfig.authToken;
|
|
4846
|
-
if (profile.anthropicConfig.model) envVars.ANTHROPIC_MODEL = profile.anthropicConfig.model;
|
|
4847
|
-
}
|
|
4848
|
-
if (profile.openaiConfig) {
|
|
4849
|
-
if (profile.openaiConfig.apiKey) envVars.OPENAI_API_KEY = profile.openaiConfig.apiKey;
|
|
4850
|
-
if (profile.openaiConfig.baseUrl) envVars.OPENAI_BASE_URL = profile.openaiConfig.baseUrl;
|
|
4851
|
-
if (profile.openaiConfig.model) envVars.OPENAI_MODEL = profile.openaiConfig.model;
|
|
4852
|
-
}
|
|
4853
|
-
if (profile.azureOpenAIConfig) {
|
|
4854
|
-
if (profile.azureOpenAIConfig.apiKey) envVars.AZURE_OPENAI_API_KEY = profile.azureOpenAIConfig.apiKey;
|
|
4855
|
-
if (profile.azureOpenAIConfig.endpoint) envVars.AZURE_OPENAI_ENDPOINT = profile.azureOpenAIConfig.endpoint;
|
|
4856
|
-
if (profile.azureOpenAIConfig.apiVersion) envVars.AZURE_OPENAI_API_VERSION = profile.azureOpenAIConfig.apiVersion;
|
|
4857
|
-
if (profile.azureOpenAIConfig.deploymentName) envVars.AZURE_OPENAI_DEPLOYMENT_NAME = profile.azureOpenAIConfig.deploymentName;
|
|
4858
|
-
}
|
|
4859
|
-
if (profile.togetherAIConfig) {
|
|
4860
|
-
if (profile.togetherAIConfig.apiKey) envVars.TOGETHER_API_KEY = profile.togetherAIConfig.apiKey;
|
|
4861
|
-
if (profile.togetherAIConfig.model) envVars.TOGETHER_MODEL = profile.togetherAIConfig.model;
|
|
4862
|
-
}
|
|
4863
|
-
if (profile.tmuxConfig) {
|
|
4864
|
-
if (profile.tmuxConfig.sessionName !== void 0) envVars.TMUX_SESSION_NAME = profile.tmuxConfig.sessionName;
|
|
4865
|
-
if (profile.tmuxConfig.tmpDir) envVars.TMUX_TMPDIR = profile.tmuxConfig.tmpDir;
|
|
4866
|
-
if (profile.tmuxConfig.updateEnvironment !== void 0) {
|
|
4867
|
-
envVars.TMUX_UPDATE_ENVIRONMENT = profile.tmuxConfig.updateEnvironment.toString();
|
|
4868
|
-
}
|
|
4869
|
-
}
|
|
4870
|
-
return envVars;
|
|
4871
|
-
}
|
|
4872
|
-
const SUPPORTED_SCHEMA_VERSION = 2;
|
|
4873
|
-
const defaultSettings = {
|
|
4874
|
-
schemaVersion: SUPPORTED_SCHEMA_VERSION,
|
|
4875
|
-
onboardingCompleted: false,
|
|
4876
|
-
profiles: [],
|
|
4877
|
-
localEnvironmentVariables: {}
|
|
4878
|
-
};
|
|
4879
|
-
function migrateSettings(raw, fromVersion) {
|
|
4880
|
-
let migrated = { ...raw };
|
|
4881
|
-
if (fromVersion < 2) {
|
|
4882
|
-
if (!migrated.profiles) {
|
|
4883
|
-
migrated.profiles = [];
|
|
4884
|
-
}
|
|
4885
|
-
if (!migrated.localEnvironmentVariables) {
|
|
4886
|
-
migrated.localEnvironmentVariables = {};
|
|
4887
|
-
}
|
|
4888
|
-
migrated.schemaVersion = 2;
|
|
4889
|
-
}
|
|
4890
|
-
return migrated;
|
|
4891
|
-
}
|
|
4892
|
-
async function readSettings() {
|
|
4893
|
-
if (!existsSync(configuration.settingsFile)) {
|
|
4894
|
-
return { ...defaultSettings };
|
|
4895
|
-
}
|
|
4896
|
-
try {
|
|
4897
|
-
const content = await readFile(configuration.settingsFile, "utf8");
|
|
4898
|
-
const raw = JSON.parse(content);
|
|
4899
|
-
const schemaVersion = raw.schemaVersion ?? 1;
|
|
4900
|
-
if (schemaVersion > SUPPORTED_SCHEMA_VERSION) {
|
|
4901
|
-
logger.warn(
|
|
4902
|
-
`\u26A0\uFE0F Settings schema v${schemaVersion} > supported v${SUPPORTED_SCHEMA_VERSION}. Update happy-cli for full functionality.`
|
|
4903
|
-
);
|
|
4904
|
-
}
|
|
4905
|
-
const migrated = migrateSettings(raw, schemaVersion);
|
|
4906
|
-
if (migrated.profiles && Array.isArray(migrated.profiles)) {
|
|
4907
|
-
const validProfiles = [];
|
|
4908
|
-
for (const profile of migrated.profiles) {
|
|
4909
|
-
try {
|
|
4910
|
-
const validated = AIBackendProfileSchema.parse(profile);
|
|
4911
|
-
validProfiles.push(validated);
|
|
4912
|
-
} catch (error) {
|
|
4913
|
-
logger.warn(
|
|
4914
|
-
`\u26A0\uFE0F Invalid profile "${profile?.name || profile?.id || "unknown"}" - skipping. Error: ${error.message}`
|
|
4915
|
-
);
|
|
4916
|
-
}
|
|
4917
|
-
}
|
|
4918
|
-
migrated.profiles = validProfiles;
|
|
4919
|
-
}
|
|
4920
|
-
return { ...defaultSettings, ...migrated };
|
|
4921
|
-
} catch (error) {
|
|
4922
|
-
logger.warn(`Failed to read settings: ${error.message}`);
|
|
4923
|
-
return { ...defaultSettings };
|
|
4924
|
-
}
|
|
4925
|
-
}
|
|
4926
|
-
async function updateSettings(updater) {
|
|
4927
|
-
const LOCK_RETRY_INTERVAL_MS = 100;
|
|
4928
|
-
const MAX_LOCK_ATTEMPTS = 50;
|
|
4929
|
-
const STALE_LOCK_TIMEOUT_MS = 1e4;
|
|
4930
|
-
const lockFile = configuration.settingsFile + ".lock";
|
|
4931
|
-
const tmpFile = configuration.settingsFile + ".tmp";
|
|
4932
|
-
let fileHandle;
|
|
4933
|
-
let attempts = 0;
|
|
4934
|
-
while (attempts < MAX_LOCK_ATTEMPTS) {
|
|
4935
|
-
try {
|
|
4936
|
-
fileHandle = await open(lockFile, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);
|
|
4937
|
-
break;
|
|
4938
|
-
} catch (err) {
|
|
4939
|
-
if (err.code === "EEXIST") {
|
|
4940
|
-
attempts++;
|
|
4941
|
-
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
|
|
4942
|
-
try {
|
|
4943
|
-
const stats = await stat$1(lockFile);
|
|
4944
|
-
if (Date.now() - stats.mtimeMs > STALE_LOCK_TIMEOUT_MS) {
|
|
4945
|
-
await unlink$1(lockFile).catch(() => {
|
|
4946
|
-
});
|
|
4947
|
-
}
|
|
4948
|
-
} catch {
|
|
4949
|
-
}
|
|
4950
|
-
} else {
|
|
4951
|
-
throw err;
|
|
4952
|
-
}
|
|
4953
|
-
}
|
|
4954
|
-
}
|
|
4955
|
-
if (!fileHandle) {
|
|
4956
|
-
throw new Error(`Failed to acquire settings lock after ${MAX_LOCK_ATTEMPTS * LOCK_RETRY_INTERVAL_MS / 1e3} seconds`);
|
|
4957
|
-
}
|
|
4958
|
-
try {
|
|
4959
|
-
const current = await readSettings() || { ...defaultSettings };
|
|
4960
|
-
const updated = await updater(current);
|
|
4961
|
-
if (!existsSync(configuration.happyHomeDir)) {
|
|
4962
|
-
await mkdir$1(configuration.happyHomeDir, { recursive: true });
|
|
4963
|
-
}
|
|
4964
|
-
await writeFile$1(tmpFile, JSON.stringify(updated, null, 2));
|
|
4965
|
-
await rename$1(tmpFile, configuration.settingsFile);
|
|
4966
|
-
return updated;
|
|
4967
|
-
} finally {
|
|
4968
|
-
await fileHandle.close();
|
|
4969
|
-
await unlink$1(lockFile).catch(() => {
|
|
4970
|
-
});
|
|
4971
|
-
}
|
|
4972
|
-
}
|
|
4973
|
-
const credentialsSchema = z.object({
|
|
4974
|
-
token: z.string(),
|
|
4975
|
-
secret: z.string().base64().nullish(),
|
|
4976
|
-
// Legacy
|
|
4977
|
-
encryption: z.object({
|
|
4978
|
-
publicKey: z.string().base64(),
|
|
4979
|
-
machineKey: z.string().base64()
|
|
4980
|
-
}).nullish()
|
|
4981
|
-
});
|
|
4982
|
-
async function readCredentials() {
|
|
4983
|
-
if (!existsSync(configuration.privateKeyFile)) {
|
|
4984
|
-
return null;
|
|
4985
|
-
}
|
|
4986
|
-
try {
|
|
4987
|
-
const keyBase64 = await readFile(configuration.privateKeyFile, "utf8");
|
|
4988
|
-
const credentials = credentialsSchema.parse(JSON.parse(keyBase64));
|
|
4989
|
-
if (credentials.secret) {
|
|
4990
|
-
return {
|
|
4991
|
-
token: credentials.token,
|
|
4992
|
-
encryption: {
|
|
4993
|
-
type: "legacy",
|
|
4994
|
-
secret: new Uint8Array(Buffer.from(credentials.secret, "base64"))
|
|
4995
|
-
}
|
|
4996
|
-
};
|
|
4997
|
-
} else if (credentials.encryption) {
|
|
4998
|
-
return {
|
|
4999
|
-
token: credentials.token,
|
|
5000
|
-
encryption: {
|
|
5001
|
-
type: "dataKey",
|
|
5002
|
-
publicKey: new Uint8Array(Buffer.from(credentials.encryption.publicKey, "base64")),
|
|
5003
|
-
machineKey: new Uint8Array(Buffer.from(credentials.encryption.machineKey, "base64"))
|
|
5004
|
-
}
|
|
5005
|
-
};
|
|
5006
|
-
}
|
|
5007
|
-
} catch {
|
|
5008
|
-
return null;
|
|
5009
|
-
}
|
|
5010
|
-
return null;
|
|
5011
|
-
}
|
|
5012
|
-
async function writeCredentialsLegacy(credentials) {
|
|
5013
|
-
if (!existsSync(configuration.happyHomeDir)) {
|
|
5014
|
-
await mkdir$1(configuration.happyHomeDir, { recursive: true });
|
|
5015
|
-
}
|
|
5016
|
-
await writeFile$1(configuration.privateKeyFile, JSON.stringify({
|
|
5017
|
-
secret: encodeBase64(credentials.secret),
|
|
5018
|
-
token: credentials.token
|
|
5019
|
-
}, null, 2));
|
|
5020
|
-
}
|
|
5021
|
-
async function writeCredentialsDataKey(credentials) {
|
|
5022
|
-
if (!existsSync(configuration.happyHomeDir)) {
|
|
5023
|
-
await mkdir$1(configuration.happyHomeDir, { recursive: true });
|
|
5024
|
-
}
|
|
5025
|
-
await writeFile$1(configuration.privateKeyFile, JSON.stringify({
|
|
5026
|
-
encryption: { publicKey: encodeBase64(credentials.publicKey), machineKey: encodeBase64(credentials.machineKey) },
|
|
5027
|
-
token: credentials.token
|
|
5028
|
-
}, null, 2));
|
|
5029
|
-
}
|
|
5030
|
-
async function clearCredentials() {
|
|
5031
|
-
if (existsSync(configuration.privateKeyFile)) {
|
|
5032
|
-
await unlink$1(configuration.privateKeyFile);
|
|
5033
|
-
}
|
|
5034
|
-
}
|
|
5035
|
-
async function clearMachineId() {
|
|
5036
|
-
await updateSettings((settings) => ({
|
|
5037
|
-
...settings,
|
|
5038
|
-
machineId: void 0
|
|
5039
|
-
}));
|
|
5040
|
-
}
|
|
5041
|
-
async function readDaemonState() {
|
|
5042
|
-
try {
|
|
5043
|
-
if (!existsSync(configuration.daemonStateFile)) {
|
|
5044
|
-
return null;
|
|
5045
|
-
}
|
|
5046
|
-
const content = await readFile(configuration.daemonStateFile, "utf-8");
|
|
5047
|
-
return JSON.parse(content);
|
|
5048
|
-
} catch (error) {
|
|
5049
|
-
console.error(`[PERSISTENCE] Daemon state file corrupted: ${configuration.daemonStateFile}`, error);
|
|
5050
|
-
return null;
|
|
5051
|
-
}
|
|
5052
|
-
}
|
|
5053
|
-
function writeDaemonState(state) {
|
|
5054
|
-
writeFileSync(configuration.daemonStateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
5055
|
-
}
|
|
5056
|
-
async function clearDaemonState() {
|
|
5057
|
-
if (existsSync(configuration.daemonStateFile)) {
|
|
5058
|
-
await unlink$1(configuration.daemonStateFile);
|
|
5059
|
-
}
|
|
5060
|
-
if (existsSync(configuration.daemonLockFile)) {
|
|
5061
|
-
try {
|
|
5062
|
-
await unlink$1(configuration.daemonLockFile);
|
|
5063
|
-
} catch {
|
|
5064
|
-
}
|
|
5065
|
-
}
|
|
5066
|
-
}
|
|
5067
|
-
async function acquireDaemonLock(maxAttempts = 5, delayIncrementMs = 200) {
|
|
5068
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
5069
|
-
try {
|
|
5070
|
-
const fileHandle = await open(
|
|
5071
|
-
configuration.daemonLockFile,
|
|
5072
|
-
constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY
|
|
5073
|
-
);
|
|
5074
|
-
await fileHandle.writeFile(String(process.pid));
|
|
5075
|
-
return fileHandle;
|
|
5076
|
-
} catch (error) {
|
|
5077
|
-
if (error.code === "EEXIST") {
|
|
5078
|
-
try {
|
|
5079
|
-
const lockPid = readFileSync(configuration.daemonLockFile, "utf-8").trim();
|
|
5080
|
-
if (lockPid && !isNaN(Number(lockPid))) {
|
|
5081
|
-
try {
|
|
5082
|
-
process.kill(Number(lockPid), 0);
|
|
5083
|
-
} catch {
|
|
5084
|
-
unlinkSync(configuration.daemonLockFile);
|
|
5085
|
-
continue;
|
|
5086
|
-
}
|
|
5087
|
-
}
|
|
5088
|
-
} catch {
|
|
5089
|
-
}
|
|
5090
|
-
}
|
|
5091
|
-
if (attempt === maxAttempts) {
|
|
5092
|
-
return null;
|
|
5093
|
-
}
|
|
5094
|
-
const delayMs = attempt * delayIncrementMs;
|
|
5095
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
5096
|
-
}
|
|
5097
|
-
}
|
|
5098
|
-
return null;
|
|
5099
|
-
}
|
|
5100
|
-
async function releaseDaemonLock(lockHandle) {
|
|
5101
|
-
try {
|
|
5102
|
-
await lockHandle.close();
|
|
5103
|
-
} catch {
|
|
5104
|
-
}
|
|
5105
|
-
try {
|
|
5106
|
-
if (existsSync(configuration.daemonLockFile)) {
|
|
5107
|
-
unlinkSync(configuration.daemonLockFile);
|
|
5108
|
-
}
|
|
5109
|
-
} catch {
|
|
5110
|
-
}
|
|
5111
|
-
}
|
|
5112
|
-
|
|
5113
|
-
var persistence = /*#__PURE__*/Object.freeze({
|
|
5114
|
-
__proto__: null,
|
|
5115
|
-
AIBackendProfileSchema: AIBackendProfileSchema,
|
|
5116
|
-
SUPPORTED_SCHEMA_VERSION: SUPPORTED_SCHEMA_VERSION,
|
|
5117
|
-
acquireDaemonLock: acquireDaemonLock,
|
|
5118
|
-
clearCredentials: clearCredentials,
|
|
5119
|
-
clearDaemonState: clearDaemonState,
|
|
5120
|
-
clearMachineId: clearMachineId,
|
|
5121
|
-
getProfileEnvironmentVariables: getProfileEnvironmentVariables,
|
|
5122
|
-
readCredentials: readCredentials,
|
|
5123
|
-
readDaemonState: readDaemonState,
|
|
5124
|
-
readSettings: readSettings,
|
|
5125
|
-
releaseDaemonLock: releaseDaemonLock,
|
|
5126
|
-
updateSettings: updateSettings,
|
|
5127
|
-
validateProfileForAgent: validateProfileForAgent,
|
|
5128
|
-
writeCredentialsDataKey: writeCredentialsDataKey,
|
|
5129
|
-
writeCredentialsLegacy: writeCredentialsLegacy,
|
|
5130
|
-
writeDaemonState: writeDaemonState
|
|
5131
|
-
});
|
|
5132
|
-
|
|
5133
3700
|
function buildRunningDaemonState(previousState, currentRuntimeState, opts = {}) {
|
|
5134
3701
|
const currentHttpPort = currentRuntimeState?.httpPort;
|
|
5135
3702
|
const currentStartedAt = currentRuntimeState?.startedAt;
|
|
@@ -6633,49 +5200,49 @@ async function truncateSessionFile$1(jsonlPath, truncateBeforeUuid) {
|
|
|
6633
5200
|
}
|
|
6634
5201
|
}
|
|
6635
5202
|
|
|
6636
|
-
const GeminiSessionLineSchema = z
|
|
6637
|
-
z
|
|
6638
|
-
type: z
|
|
6639
|
-
message: z
|
|
6640
|
-
timestamp: z
|
|
6641
|
-
uuid: z
|
|
5203
|
+
const GeminiSessionLineSchema = z.discriminatedUnion("type", [
|
|
5204
|
+
z.object({
|
|
5205
|
+
type: z.literal("user"),
|
|
5206
|
+
message: z.string(),
|
|
5207
|
+
timestamp: z.number(),
|
|
5208
|
+
uuid: z.string()
|
|
6642
5209
|
}),
|
|
6643
|
-
z
|
|
6644
|
-
type: z
|
|
6645
|
-
message: z
|
|
6646
|
-
timestamp: z
|
|
6647
|
-
uuid: z
|
|
6648
|
-
model: z
|
|
5210
|
+
z.object({
|
|
5211
|
+
type: z.literal("assistant"),
|
|
5212
|
+
message: z.string(),
|
|
5213
|
+
timestamp: z.number(),
|
|
5214
|
+
uuid: z.string(),
|
|
5215
|
+
model: z.string().optional()
|
|
6649
5216
|
}),
|
|
6650
|
-
z
|
|
6651
|
-
type: z
|
|
6652
|
-
name: z
|
|
6653
|
-
callId: z
|
|
6654
|
-
input: z
|
|
6655
|
-
timestamp: z
|
|
6656
|
-
uuid: z
|
|
5217
|
+
z.object({
|
|
5218
|
+
type: z.literal("tool-call"),
|
|
5219
|
+
name: z.string(),
|
|
5220
|
+
callId: z.string(),
|
|
5221
|
+
input: z.unknown(),
|
|
5222
|
+
timestamp: z.number(),
|
|
5223
|
+
uuid: z.string()
|
|
6657
5224
|
}),
|
|
6658
|
-
z
|
|
6659
|
-
type: z
|
|
6660
|
-
callId: z
|
|
6661
|
-
output: z
|
|
6662
|
-
isError: z
|
|
6663
|
-
timestamp: z
|
|
6664
|
-
uuid: z
|
|
5225
|
+
z.object({
|
|
5226
|
+
type: z.literal("tool-result"),
|
|
5227
|
+
callId: z.string(),
|
|
5228
|
+
output: z.unknown(),
|
|
5229
|
+
isError: z.boolean().optional(),
|
|
5230
|
+
timestamp: z.number(),
|
|
5231
|
+
uuid: z.string()
|
|
6665
5232
|
}),
|
|
6666
|
-
z
|
|
6667
|
-
type: z
|
|
6668
|
-
filePath: z
|
|
6669
|
-
description: z
|
|
6670
|
-
diff: z
|
|
6671
|
-
timestamp: z
|
|
6672
|
-
uuid: z
|
|
5233
|
+
z.object({
|
|
5234
|
+
type: z.literal("file-edit"),
|
|
5235
|
+
filePath: z.string(),
|
|
5236
|
+
description: z.string(),
|
|
5237
|
+
diff: z.string().optional(),
|
|
5238
|
+
timestamp: z.number(),
|
|
5239
|
+
uuid: z.string()
|
|
6673
5240
|
}),
|
|
6674
|
-
z
|
|
6675
|
-
type: z
|
|
6676
|
-
key: z
|
|
6677
|
-
value: z
|
|
6678
|
-
timestamp: z
|
|
5241
|
+
z.object({
|
|
5242
|
+
type: z.literal("meta"),
|
|
5243
|
+
key: z.string(),
|
|
5244
|
+
value: z.unknown(),
|
|
5245
|
+
timestamp: z.number()
|
|
6679
5246
|
})
|
|
6680
5247
|
]);
|
|
6681
5248
|
|
|
@@ -7413,7 +5980,7 @@ async function forkAndTruncateCodexSession(codexSessionId, truncateBeforeUuid) {
|
|
|
7413
5980
|
if (!originalPath) {
|
|
7414
5981
|
return { success: false, errorMessage: `Codex session file not found for: ${codexSessionId}` };
|
|
7415
5982
|
}
|
|
7416
|
-
const dir = dirname
|
|
5983
|
+
const dir = dirname(originalPath);
|
|
7417
5984
|
const now = /* @__PURE__ */ new Date();
|
|
7418
5985
|
const dateStr = now.toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
7419
5986
|
const newUUID = randomUUID();
|
|
@@ -7687,6 +6254,11 @@ class ApiMachineClient {
|
|
|
7687
6254
|
});
|
|
7688
6255
|
}
|
|
7689
6256
|
socket;
|
|
6257
|
+
/** The daemon's live connection. Reused for device RPC so a CLI command does
|
|
6258
|
+
* not spend ~500ms building its own TLS + WebSocket handshake. */
|
|
6259
|
+
get rpcSocket() {
|
|
6260
|
+
return this.socket;
|
|
6261
|
+
}
|
|
7690
6262
|
keepAliveInterval = null;
|
|
7691
6263
|
rpcHandlerManager;
|
|
7692
6264
|
claudeCache = new SessionCache({
|
|
@@ -8356,33 +6928,6 @@ class PushNotificationClient {
|
|
|
8356
6928
|
}
|
|
8357
6929
|
}
|
|
8358
6930
|
|
|
8359
|
-
function keyPath(sessionId) {
|
|
8360
|
-
return join(configuration.sessionKeysDir, `${sessionId}.key`);
|
|
8361
|
-
}
|
|
8362
|
-
async function cacheSessionKey(sessionId, sessionAESKey, machineKey) {
|
|
8363
|
-
if (!existsSync(configuration.sessionKeysDir)) {
|
|
8364
|
-
mkdirSync(configuration.sessionKeysDir, { recursive: true });
|
|
8365
|
-
}
|
|
8366
|
-
const encrypted = encryptWithDataKey(encodeBase64(sessionAESKey), machineKey);
|
|
8367
|
-
await writeFile$1(keyPath(sessionId), encrypted);
|
|
8368
|
-
}
|
|
8369
|
-
function readCachedSessionKey(sessionId, machineKey) {
|
|
8370
|
-
const p = keyPath(sessionId);
|
|
8371
|
-
if (!existsSync(p)) {
|
|
8372
|
-
return null;
|
|
8373
|
-
}
|
|
8374
|
-
try {
|
|
8375
|
-
const blob = new Uint8Array(readFileSync(p));
|
|
8376
|
-
const b64 = decryptWithDataKey(blob, machineKey);
|
|
8377
|
-
if (typeof b64 !== "string") {
|
|
8378
|
-
return null;
|
|
8379
|
-
}
|
|
8380
|
-
return decodeBase64(b64);
|
|
8381
|
-
} catch {
|
|
8382
|
-
return null;
|
|
8383
|
-
}
|
|
8384
|
-
}
|
|
8385
|
-
|
|
8386
6931
|
function startOfflineReconnection(config) {
|
|
8387
6932
|
let reconnected = false;
|
|
8388
6933
|
let session = null;
|
|
@@ -8907,62 +7452,8 @@ class ApiClient {
|
|
|
8907
7452
|
}
|
|
8908
7453
|
|
|
8909
7454
|
var api = /*#__PURE__*/Object.freeze({
|
|
8910
|
-
|
|
8911
|
-
|
|
7455
|
+
__proto__: null,
|
|
7456
|
+
ApiClient: ApiClient
|
|
8912
7457
|
});
|
|
8913
7458
|
|
|
8914
|
-
|
|
8915
|
-
input_tokens: z$1.number().int().nonnegative(),
|
|
8916
|
-
cache_creation_input_tokens: z$1.number().int().nonnegative().optional(),
|
|
8917
|
-
cache_read_input_tokens: z$1.number().int().nonnegative().optional(),
|
|
8918
|
-
output_tokens: z$1.number().int().nonnegative(),
|
|
8919
|
-
service_tier: z$1.string().nullish()
|
|
8920
|
-
}).passthrough();
|
|
8921
|
-
const RawJSONLinesSchema = z$1.discriminatedUnion("type", [
|
|
8922
|
-
// User message - validates uuid and message.content
|
|
8923
|
-
z$1.object({
|
|
8924
|
-
type: z$1.literal("user"),
|
|
8925
|
-
isSidechain: z$1.boolean().optional(),
|
|
8926
|
-
isMeta: z$1.boolean().optional(),
|
|
8927
|
-
uuid: z$1.string(),
|
|
8928
|
-
// Used in getMessageKey()
|
|
8929
|
-
message: z$1.object({
|
|
8930
|
-
content: z$1.union([z$1.string(), z$1.any()])
|
|
8931
|
-
// Used in sessionScanner.ts
|
|
8932
|
-
}).passthrough()
|
|
8933
|
-
}).passthrough(),
|
|
8934
|
-
// Assistant message - only validates uuid and type
|
|
8935
|
-
// message object is optional to handle synthetic error messages (isApiErrorMessage: true)
|
|
8936
|
-
// which may have different structure than normal assistant messages
|
|
8937
|
-
z$1.object({
|
|
8938
|
-
uuid: z$1.string(),
|
|
8939
|
-
type: z$1.literal("assistant"),
|
|
8940
|
-
message: z$1.object({
|
|
8941
|
-
usage: UsageSchema.optional(),
|
|
8942
|
-
// Used in apiSession.ts
|
|
8943
|
-
model: z$1.string().optional()
|
|
8944
|
-
// Used for cost calculation
|
|
8945
|
-
}).passthrough().optional()
|
|
8946
|
-
}).passthrough(),
|
|
8947
|
-
// Summary message - validates summary and leafUuid
|
|
8948
|
-
z$1.object({
|
|
8949
|
-
type: z$1.literal("summary"),
|
|
8950
|
-
summary: z$1.string(),
|
|
8951
|
-
// Used in apiSession.ts
|
|
8952
|
-
leafUuid: z$1.string()
|
|
8953
|
-
// Used in getMessageKey()
|
|
8954
|
-
}).passthrough(),
|
|
8955
|
-
// System message - validates uuid
|
|
8956
|
-
z$1.object({
|
|
8957
|
-
type: z$1.literal("system"),
|
|
8958
|
-
uuid: z$1.string()
|
|
8959
|
-
// Used in getMessageKey()
|
|
8960
|
-
}).passthrough(),
|
|
8961
|
-
// Progress message - hook progress events, not counted toward message limits
|
|
8962
|
-
z$1.object({
|
|
8963
|
-
type: z$1.literal("progress"),
|
|
8964
|
-
uuid: z$1.string()
|
|
8965
|
-
}).passthrough()
|
|
8966
|
-
]);
|
|
8967
|
-
|
|
8968
|
-
export { persistence as $, ApiClient as A, GeminiSessionWriter as B, buildResumeContextFromSessionLog as C, AsyncLock as D, readDaemonState as E, clearDaemonState as F, GEMINI_MODEL_MODES as G, updateSettings as H, InvalidateSync as I, encodeBase64Url as J, writeCredentialsLegacy as K, writeCredentialsDataKey as L, MODEL_MODE_DEFAULT as M, acquireDaemonLock as N, writeDaemonState as O, releaseDaemonLock as P, validateProfileForAgent as Q, RawJSONLinesSchema as R, getProfileEnvironmentVariables as S, findClaudeProjectId as T, libsodiumPublicKeyFromSecretKey as U, clearCredentials as V, clearMachineId as W, decryptLegacy as X, decryptWithDataKey as Y, readCachedSessionKey as Z, getLatestDaemonLog as _, ApiSessionClient as a, api as a0, parseClaudeModelMode as b, configuration as c, encrypt as d, encodeBase64 as e, decodeBase64 as f, decrypt as g, resolveToolsDir as h, isModelModeForAgent as i, projectPath as j, packageJson as k, logger as l, saveToolOutputRecord as m, saveDiffRecords as n, isDebug as o, parseCodexModelMode as p, extractUserText as q, readCredentials as r, startOfflineReconnection as s, isSystemMessage as t, generateStableUuid as u, findCodexSessionFile as v, connectionState as w, readSettings as x, delay as y, readGeminiSessionLog as z };
|
|
7459
|
+
export { ApiClient as A, GeminiSessionWriter as G, InvalidateSync as I, ApiSessionClient as a, saveToolOutputRecord as b, saveDiffRecords as c, connectionState as d, extractUserText as e, findCodexSessionFile as f, generateStableUuid as g, readGeminiSessionLog as h, isSystemMessage as i, buildResumeContextFromSessionLog as j, AsyncLock as k, findClaudeProjectId as l, api as m, resolveToolsDir as r, startOfflineReconnection as s };
|