@zonease/happy 0.6.38 → 0.6.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/happy.mjs +10 -0
- package/dist/{types-DvTsFaqR.cjs → api-C7FyJfZ1.cjs} +400 -1964
- package/dist/{types-BWpRU1VN.mjs → api-D6WL40-U.mjs} +220 -1729
- package/dist/auth-C7ZScWEw.cjs +274 -0
- package/dist/auth-DCsIoZLT.cjs +183 -0
- package/dist/auth-DO9GexAR.mjs +181 -0
- package/dist/auth-DxJ3VvrX.mjs +270 -0
- package/dist/browser-AoVGRX7y.mjs +20 -0
- package/dist/browser-DzgO4oaD.cjs +22 -0
- package/dist/claudeLocal-C6BdzhDx.cjs +352 -0
- package/dist/claudeLocal-CWNGpJ0-.mjs +344 -0
- package/dist/codex/happyMcpStdioBridge.cjs +4 -1
- package/dist/codex/happyMcpStdioBridge.mjs +4 -1
- package/dist/common-BdNgghUJ.mjs +75 -0
- package/dist/common-CZvSRU4p.cjs +83 -0
- package/dist/{config-0Xnc8ARM.cjs → config-CclB3QW9.cjs} +21 -34
- package/dist/{config-_GW4YBCP.mjs → config-DZk-mJ0K.mjs} +7 -20
- package/dist/connect-BXLUKJ5P.mjs +679 -0
- package/dist/connect-k9CqDJ-T.cjs +681 -0
- package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
- package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
- package/dist/controlClient-B23M-WPp.cjs +177 -0
- package/dist/controlClient-DB5tDU7V.mjs +167 -0
- package/dist/deviceKeys-BTdo34Uz.mjs +175 -0
- package/dist/deviceKeys-C540DcXl.cjs +182 -0
- package/dist/diagnose-B3D1a_v0.cjs +60 -0
- package/dist/diagnose-CuRKXxt1.mjs +58 -0
- package/dist/doctor-BQGLhrcI.cjs +214 -0
- package/dist/doctor-C08m5Z9f.cjs +78 -0
- package/dist/doctor-CU4JLGQ1.mjs +211 -0
- package/dist/doctor-ON7pN5G5.mjs +74 -0
- package/dist/downloadImage-DZXI3mXL.mjs +887 -0
- package/dist/downloadImage-cQ1Z7hkC.cjs +897 -0
- package/dist/enroll-B55BQR56.mjs +113 -0
- package/dist/enroll-Bo-CNio1.cjs +115 -0
- package/dist/evidence-DQp8QWcv.cjs +129 -0
- package/dist/evidence-DTYRAaOZ.mjs +127 -0
- package/dist/formatImageMessage-CixDYY6G.cjs +46 -0
- package/dist/formatImageMessage-DbKSSjMx.mjs +43 -0
- package/dist/github-DKcyF1zp.mjs +57 -0
- package/dist/github-h9GhJJ_C.cjs +59 -0
- package/dist/index-CDTNgfUf.cjs +578 -0
- package/dist/index-CPKdvi7J.mjs +554 -0
- package/dist/index.cjs +812 -40
- package/dist/index.mjs +813 -40
- package/dist/install-B1e6rdy7.mjs +94 -0
- package/dist/install-CgUPGIoF.mjs +95 -0
- package/dist/install-D7Ir7ciZ.cjs +96 -0
- package/dist/install-DSDufaPd.cjs +98 -0
- package/dist/lib.cjs +18 -12
- package/dist/lib.d.cts +77 -0
- package/dist/lib.d.mts +77 -0
- package/dist/lib.mjs +13 -7
- package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Bfei9wPq.mjs} +4 -2
- package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-CbLGtvST.cjs} +63 -61
- package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
- package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
- package/dist/persistence-CBTtC_dm.cjs +996 -0
- package/dist/persistence-DKfF81pd.mjs +944 -0
- package/dist/projectPath-BTBIMB57.mjs +10 -0
- package/dist/projectPath-ChLhdOyt.cjs +13 -0
- package/dist/prompt-BTWDZZO0.cjs +25 -0
- package/dist/prompt-BsAZsPbo.mjs +22 -0
- package/dist/release-BMEzNONE.mjs +168 -0
- package/dist/release-EhOJeAZe.cjs +171 -0
- package/dist/run-BVZsMNwN.mjs +2164 -0
- package/dist/run-CURx7LhK.cjs +2188 -0
- package/dist/runClaude-6Gi0sYQy.mjs +3763 -0
- package/dist/runClaude-CL3Kt5ex.cjs +3766 -0
- package/dist/{runCodex-DiKzBf9q.mjs → runCodex-ClwEgJ7M.mjs} +36 -20
- package/dist/{runCodex-skq0j05d.cjs → runCodex-YKyVBkJ3.cjs} +169 -153
- package/dist/{runGemini-BeqrVq8R.mjs → runGemini-BPWxVr60.mjs} +34 -17
- package/dist/{runGemini-CVp-CEIh.cjs → runGemini-Xz2W1spn.cjs} +212 -195
- package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-CdCWiiLr.mjs} +14 -38
- package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-DjZyCvDI.cjs} +31 -55
- package/dist/{serve-BNdoEDVx.mjs → serve-B48JttQ3.mjs} +12 -35
- package/dist/{serve-BECdtivY.cjs → serve-B8vaWQA0.cjs} +35 -58
- package/dist/session-BXboDn2V.mjs +108 -0
- package/dist/session-BZO25zxp.cjs +110 -0
- package/dist/sessionKeyCache-B6cGadYL.mjs +33 -0
- package/dist/sessionKeyCache-CDmexJ9p.cjs +36 -0
- package/dist/sessionList-CgAYZpNj.mjs +51 -0
- package/dist/sessionList-lQ-nqEhc.cjs +54 -0
- package/dist/sessionSummary-CcORiQSq.cjs +393 -0
- package/dist/sessionSummary-DCWQoaDP.mjs +387 -0
- package/dist/spawnHappyCLI-KiazE3kL.cjs +70 -0
- package/dist/spawnHappyCLI-yBIP_Oqi.mjs +66 -0
- package/dist/ssh-q5uZhqBf.mjs +359 -0
- package/dist/ssh-yMllSHu5.cjs +365 -0
- package/dist/systemdScope-BeOtAkhk.mjs +25 -0
- package/dist/systemdScope-DW3-UoKB.cjs +29 -0
- package/dist/task-_nr7J19j.cjs +167 -0
- package/dist/task-wNX1N2i4.mjs +165 -0
- package/dist/time-Bj2HRkKH.cjs +33 -0
- package/dist/time-DgsBLJA_.mjs +29 -0
- package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
- package/dist/trimIdent-BAjmv_TG.mjs +20 -0
- package/dist/types-BoJh4Qfv.mjs +57 -0
- package/dist/types-DWeB7aqh.cjs +59 -0
- package/dist/uninstall-Buaz7d-X.cjs +77 -0
- package/dist/uninstall-Dxf6_4mQ.mjs +75 -0
- package/dist/update-CGlIfa8e.cjs +111 -0
- package/dist/update-CnnoX2cV.mjs +109 -0
- package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
- package/dist/workflowCommon-Bl568-rt.cjs +62 -0
- package/dist/workflowReports-BEWuQesA.cjs +113 -0
- package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
- package/package.json +1 -1
- package/dist/index-BbCDDvoB.cjs +0 -11376
- package/dist/index-vvZXdswy.mjs +0 -11336
- package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
- package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { execFileSync, execSync } from 'node:child_process';
|
|
3
|
+
import { realpathSync } from 'node:fs';
|
|
4
|
+
import { p as packageJson } from './persistence-DKfF81pd.mjs';
|
|
5
|
+
import { checkIfDaemonRunningAndCleanupStaleState, stopDaemon } from './controlClient-DB5tDU7V.mjs';
|
|
6
|
+
import { s as spawnHappyCLI } from './spawnHappyCLI-yBIP_Oqi.mjs';
|
|
7
|
+
import 'node:fs/promises';
|
|
8
|
+
import 'node:os';
|
|
9
|
+
import 'node:path';
|
|
10
|
+
import 'zod';
|
|
11
|
+
import 'node:crypto';
|
|
12
|
+
import 'tweetnacl';
|
|
13
|
+
import 'fs';
|
|
14
|
+
import './projectPath-BTBIMB57.mjs';
|
|
15
|
+
import 'path';
|
|
16
|
+
import 'url';
|
|
17
|
+
import 'child_process';
|
|
18
|
+
|
|
19
|
+
const PACKAGE_NAME = "@zonease/happy";
|
|
20
|
+
function detectPackageManager() {
|
|
21
|
+
try {
|
|
22
|
+
const whichOutput = execSync("which happy", { encoding: "utf-8" }).trim();
|
|
23
|
+
const realPath = realpathSync(whichOutput);
|
|
24
|
+
if (realPath.includes("/pnpm/") || realPath.includes("/pnpm-global/")) {
|
|
25
|
+
return "pnpm";
|
|
26
|
+
}
|
|
27
|
+
if (realPath.includes("/.yarn/") || realPath.includes("/yarn/")) {
|
|
28
|
+
return "yarn";
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
return "npm";
|
|
33
|
+
}
|
|
34
|
+
function getUpgradeCommand(pm) {
|
|
35
|
+
switch (pm) {
|
|
36
|
+
case "pnpm":
|
|
37
|
+
return ["pnpm", "add", "-g", `${PACKAGE_NAME}@latest`];
|
|
38
|
+
case "yarn":
|
|
39
|
+
return ["yarn", "global", "add", `${PACKAGE_NAME}@latest`];
|
|
40
|
+
case "npm":
|
|
41
|
+
return ["npm", "install", "-g", `${PACKAGE_NAME}@latest`];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function getLatestVersion() {
|
|
45
|
+
try {
|
|
46
|
+
return execFileSync("npm", ["view", PACKAGE_NAME, "version"], { encoding: "utf-8" }).trim();
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function handleUpdateCommand() {
|
|
52
|
+
const currentVersion = packageJson.version;
|
|
53
|
+
console.log(chalk.gray("Checking for updates..."));
|
|
54
|
+
const latestVersion = getLatestVersion();
|
|
55
|
+
if (!latestVersion) {
|
|
56
|
+
console.error(chalk.red("Failed to check latest version. Please check your network connection."));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
console.log(`Current version: ${chalk.cyan(currentVersion)}`);
|
|
60
|
+
console.log(`Latest version: ${chalk.cyan(latestVersion)}`);
|
|
61
|
+
console.log("");
|
|
62
|
+
if (currentVersion === latestVersion) {
|
|
63
|
+
console.log(chalk.green("\u2713 Already up to date"));
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
const pm = detectPackageManager();
|
|
67
|
+
const command = getUpgradeCommand(pm);
|
|
68
|
+
console.log(`Upgrading via ${chalk.bold(pm)}...`);
|
|
69
|
+
try {
|
|
70
|
+
execFileSync(command[0], command.slice(1), { stdio: "inherit" });
|
|
71
|
+
} catch {
|
|
72
|
+
console.error(chalk.red(`
|
|
73
|
+
\u2717 Upgrade failed. You can try manually:`));
|
|
74
|
+
console.error(chalk.gray(` ${command.join(" ")}`));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
console.log(chalk.green(`
|
|
78
|
+
\u2713 Upgraded to ${latestVersion}`));
|
|
79
|
+
try {
|
|
80
|
+
const daemonRunning = await checkIfDaemonRunningAndCleanupStaleState();
|
|
81
|
+
if (daemonRunning) {
|
|
82
|
+
console.log("Restarting daemon...");
|
|
83
|
+
await stopDaemon();
|
|
84
|
+
const child = spawnHappyCLI(["daemon", "start-sync"], {
|
|
85
|
+
detached: true,
|
|
86
|
+
stdio: "ignore",
|
|
87
|
+
env: process.env
|
|
88
|
+
});
|
|
89
|
+
child.unref();
|
|
90
|
+
let started = false;
|
|
91
|
+
for (let i = 0; i < 50; i++) {
|
|
92
|
+
if (await checkIfDaemonRunningAndCleanupStaleState()) {
|
|
93
|
+
started = true;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
97
|
+
}
|
|
98
|
+
if (started) {
|
|
99
|
+
console.log(chalk.green("\u2713 Daemon restarted"));
|
|
100
|
+
} else {
|
|
101
|
+
console.log(chalk.yellow('\u26A0 Daemon restart timed out. Run "happy daemon start" manually.'));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { handleUpdateCommand };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
function parseWorkflowArgs(args, valueFlags) {
|
|
4
|
+
const positionals = [];
|
|
5
|
+
const flags = /* @__PURE__ */ new Map();
|
|
6
|
+
for (let i = 0; i < args.length; i++) {
|
|
7
|
+
const arg = args[i];
|
|
8
|
+
if (!arg.startsWith("-") || arg === "-") {
|
|
9
|
+
positionals.push(arg);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const equalIndex = arg.indexOf("=");
|
|
13
|
+
const flag = equalIndex === -1 ? arg : arg.slice(0, equalIndex);
|
|
14
|
+
if (equalIndex !== -1) {
|
|
15
|
+
flags.set(flag, arg.slice(equalIndex + 1));
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (valueFlags.has(flag)) {
|
|
19
|
+
const value = args[++i];
|
|
20
|
+
if (!value || value.startsWith("--")) {
|
|
21
|
+
throw new Error(`${flag} requires a value.`);
|
|
22
|
+
}
|
|
23
|
+
flags.set(flag, value);
|
|
24
|
+
} else {
|
|
25
|
+
flags.set(flag, true);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { positionals, flags };
|
|
29
|
+
}
|
|
30
|
+
function stringFlag(parsed, flag) {
|
|
31
|
+
const value = parsed.flags.get(flag);
|
|
32
|
+
if (value === void 0 || value === true) return void 0;
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function numberFlag(parsed, flag) {
|
|
36
|
+
const value = stringFlag(parsed, flag);
|
|
37
|
+
if (value === void 0) return void 0;
|
|
38
|
+
const parsedValue = Number(value);
|
|
39
|
+
if (!Number.isInteger(parsedValue)) {
|
|
40
|
+
throw new Error(`${flag} must be an integer.`);
|
|
41
|
+
}
|
|
42
|
+
return parsedValue;
|
|
43
|
+
}
|
|
44
|
+
function booleanFlag(parsed, flag) {
|
|
45
|
+
return parsed.flags.get(flag) === true;
|
|
46
|
+
}
|
|
47
|
+
async function printOrWriteOutput(content, outputPath) {
|
|
48
|
+
if (outputPath) {
|
|
49
|
+
await writeFile(outputPath, content, "utf8");
|
|
50
|
+
console.log(outputPath);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(content);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { printOrWriteOutput as a, booleanFlag as b, numberFlag as n, parseWorkflowArgs as p, stringFlag as s };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('node:fs/promises');
|
|
4
|
+
|
|
5
|
+
function parseWorkflowArgs(args, valueFlags) {
|
|
6
|
+
const positionals = [];
|
|
7
|
+
const flags = /* @__PURE__ */ new Map();
|
|
8
|
+
for (let i = 0; i < args.length; i++) {
|
|
9
|
+
const arg = args[i];
|
|
10
|
+
if (!arg.startsWith("-") || arg === "-") {
|
|
11
|
+
positionals.push(arg);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const equalIndex = arg.indexOf("=");
|
|
15
|
+
const flag = equalIndex === -1 ? arg : arg.slice(0, equalIndex);
|
|
16
|
+
if (equalIndex !== -1) {
|
|
17
|
+
flags.set(flag, arg.slice(equalIndex + 1));
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (valueFlags.has(flag)) {
|
|
21
|
+
const value = args[++i];
|
|
22
|
+
if (!value || value.startsWith("--")) {
|
|
23
|
+
throw new Error(`${flag} requires a value.`);
|
|
24
|
+
}
|
|
25
|
+
flags.set(flag, value);
|
|
26
|
+
} else {
|
|
27
|
+
flags.set(flag, true);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { positionals, flags };
|
|
31
|
+
}
|
|
32
|
+
function stringFlag(parsed, flag) {
|
|
33
|
+
const value = parsed.flags.get(flag);
|
|
34
|
+
if (value === void 0 || value === true) return void 0;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function numberFlag(parsed, flag) {
|
|
38
|
+
const value = stringFlag(parsed, flag);
|
|
39
|
+
if (value === void 0) return void 0;
|
|
40
|
+
const parsedValue = Number(value);
|
|
41
|
+
if (!Number.isInteger(parsedValue)) {
|
|
42
|
+
throw new Error(`${flag} must be an integer.`);
|
|
43
|
+
}
|
|
44
|
+
return parsedValue;
|
|
45
|
+
}
|
|
46
|
+
function booleanFlag(parsed, flag) {
|
|
47
|
+
return parsed.flags.get(flag) === true;
|
|
48
|
+
}
|
|
49
|
+
async function printOrWriteOutput(content, outputPath) {
|
|
50
|
+
if (outputPath) {
|
|
51
|
+
await promises.writeFile(outputPath, content, "utf8");
|
|
52
|
+
console.log(outputPath);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(content);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.booleanFlag = booleanFlag;
|
|
59
|
+
exports.numberFlag = numberFlag;
|
|
60
|
+
exports.parseWorkflowArgs = parseWorkflowArgs;
|
|
61
|
+
exports.printOrWriteOutput = printOrWriteOutput;
|
|
62
|
+
exports.stringFlag = stringFlag;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
|
|
5
|
+
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
6
|
+
const LOG_EXTENSIONS = /* @__PURE__ */ new Set([".log", ".txt", ".jsonl"]);
|
|
7
|
+
function bashQuote(value) {
|
|
8
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
9
|
+
}
|
|
10
|
+
function inferEvidenceKind(target) {
|
|
11
|
+
if (/^https?:\/\//i.test(target)) return "url";
|
|
12
|
+
const extension = path.extname(target).toLowerCase();
|
|
13
|
+
if (IMAGE_EXTENSIONS.has(extension)) return "image";
|
|
14
|
+
if (LOG_EXTENSIONS.has(extension)) return "log";
|
|
15
|
+
return "file";
|
|
16
|
+
}
|
|
17
|
+
function buildGithubTakeoverReport(input) {
|
|
18
|
+
const targetLabel = input.target || "(issue-or-pr)";
|
|
19
|
+
const repoLine = input.repo ? `- Repository: \`${input.repo}\`` : "- Repository: infer from URL or current checkout";
|
|
20
|
+
const modeLine = input.mode && input.mode !== "auto" ? `- Mode: ${input.mode}` : "- Mode: auto-detect PR vs issue";
|
|
21
|
+
return `# GitHub Task Takeover
|
|
22
|
+
|
|
23
|
+
- Target: \`${targetLabel}\`
|
|
24
|
+
${repoLine}
|
|
25
|
+
${modeLine}
|
|
26
|
+
|
|
27
|
+
## Execution Checklist
|
|
28
|
+
|
|
29
|
+
1. Read repository instructions first: \`AGENTS.md\`, \`CLAUDE.md\`, and scoped rules.
|
|
30
|
+
2. Fetch the PR/issue body, comments, unresolved review threads, changed files, and CI status.
|
|
31
|
+
3. Summarize the requested outcome, blockers, and acceptance criteria before editing.
|
|
32
|
+
4. Claim or create the local task/plan record if the repository uses PMA.
|
|
33
|
+
5. Preserve existing user/agent changes; do not reset or overwrite unrelated files.
|
|
34
|
+
6. Implement the smallest safe patch.
|
|
35
|
+
7. Run focused verification and then the package-required typecheck/build/test command.
|
|
36
|
+
8. Report changed files, verification results, and any remaining blockers.
|
|
37
|
+
|
|
38
|
+
## Copy-Paste Agent Prompt
|
|
39
|
+
|
|
40
|
+
Take over GitHub work for \`${targetLabel}\`${input.repo ? ` in \`${input.repo}\`` : ""}.
|
|
41
|
+
|
|
42
|
+
- Inspect repository instructions before editing.
|
|
43
|
+
- Read PR/issue metadata, comments, unresolved review threads, changed files, and CI.
|
|
44
|
+
- Identify exactly what must be fixed.
|
|
45
|
+
- Implement the minimal patch without touching unrelated user changes.
|
|
46
|
+
- Run focused tests plus the repository-required verification.
|
|
47
|
+
- Return a concise Chinese summary with changed files and verification evidence.
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
function buildRemoteDiagnoseReport(input) {
|
|
51
|
+
const serviceClause = input.service ? `SERVICE=${bashQuote(input.service)}` : `SERVICE=${bashQuote("<service-name>")}`;
|
|
52
|
+
const keywordClause = input.keyword ? `KEYWORD=${bashQuote(input.keyword)}` : `KEYWORD=${bashQuote("<error-keyword>")}`;
|
|
53
|
+
const healthUrl = input.healthUrl ?? "http://127.0.0.1:8090/health";
|
|
54
|
+
return `# Remote Diagnosis Evidence Pack
|
|
55
|
+
|
|
56
|
+
- Host: \`${input.host}\`
|
|
57
|
+
- Since: \`${input.since}\`
|
|
58
|
+
- Service: \`${input.service ?? "(optional)"}\`
|
|
59
|
+
- Keyword: \`${input.keyword ?? "(optional)"}\`
|
|
60
|
+
- Health URL: \`${healthUrl}\`
|
|
61
|
+
|
|
62
|
+
Run these commands manually after confirming the target host. They are read-only evidence commands.
|
|
63
|
+
|
|
64
|
+
\`\`\`bash
|
|
65
|
+
HOST=${bashQuote(input.host)}
|
|
66
|
+
${serviceClause}
|
|
67
|
+
${keywordClause}
|
|
68
|
+
SINCE=${bashQuote(input.since)}
|
|
69
|
+
|
|
70
|
+
ssh "$HOST" 'hostname; date; uptime; df -h; free -m'
|
|
71
|
+
ssh "$HOST" 'systemctl --failed --no-pager || true'
|
|
72
|
+
ssh "$HOST" 'docker ps --format "table {{.Names}}\\t{{.Image}}\\t{{.Status}}" || true'
|
|
73
|
+
ssh "$HOST" "curl -fsS ${healthUrl} || true"
|
|
74
|
+
ssh "$HOST" "journalctl --since \\"$SINCE\\" -p warning..alert --no-pager | tail -200 || true"
|
|
75
|
+
ssh "$HOST" "docker logs --since \\"$SINCE\\" \\"$SERVICE\\" 2>&1 | tail -300 || true"
|
|
76
|
+
ssh "$HOST" "grep -RIn --exclude-dir=node_modules --exclude-dir=.git \\"$KEYWORD\\" /tmp /var/log 2>/dev/null | tail -100 || true"
|
|
77
|
+
\`\`\`
|
|
78
|
+
|
|
79
|
+
## Evidence To Return
|
|
80
|
+
|
|
81
|
+
- Exact failing request or user-visible symptom.
|
|
82
|
+
- Health check output.
|
|
83
|
+
- Last 200 warning/error journal lines.
|
|
84
|
+
- Last 300 service log lines.
|
|
85
|
+
- Any screenshot or UI evidence path, added with \`happy evidence add <path>\`.
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
function renderEvidenceReport(entries, title = "Evidence Report") {
|
|
89
|
+
const lines = [`# ${title}`, "", `Total evidence: ${entries.length}`, ""];
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
const session = entry.sessionId ? ` session=${entry.sessionId}` : "";
|
|
92
|
+
lines.push(`## ${entry.title}`);
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(`- ID: \`${entry.id}\``);
|
|
95
|
+
lines.push(`- Created: ${entry.createdAt}`);
|
|
96
|
+
lines.push(`- Kind: ${entry.kind}${session}`);
|
|
97
|
+
lines.push(`- Target: \`${entry.target}\``);
|
|
98
|
+
if (entry.note) lines.push(`- Note: ${entry.note}`);
|
|
99
|
+
if (entry.kind === "image") {
|
|
100
|
+
const label = entry.title || path.basename(entry.target);
|
|
101
|
+
const imageTarget = entry.target.startsWith("/") ? `file://${entry.target}` : entry.target;
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(``);
|
|
104
|
+
}
|
|
105
|
+
lines.push("");
|
|
106
|
+
}
|
|
107
|
+
return lines.join("\n").trimEnd();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
exports.buildGithubTakeoverReport = buildGithubTakeoverReport;
|
|
111
|
+
exports.buildRemoteDiagnoseReport = buildRemoteDiagnoseReport;
|
|
112
|
+
exports.inferEvidenceKind = inferEvidenceKind;
|
|
113
|
+
exports.renderEvidenceReport = renderEvidenceReport;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { basename, extname } from 'node:path';
|
|
2
|
+
|
|
3
|
+
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
4
|
+
const LOG_EXTENSIONS = /* @__PURE__ */ new Set([".log", ".txt", ".jsonl"]);
|
|
5
|
+
function bashQuote(value) {
|
|
6
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
7
|
+
}
|
|
8
|
+
function inferEvidenceKind(target) {
|
|
9
|
+
if (/^https?:\/\//i.test(target)) return "url";
|
|
10
|
+
const extension = extname(target).toLowerCase();
|
|
11
|
+
if (IMAGE_EXTENSIONS.has(extension)) return "image";
|
|
12
|
+
if (LOG_EXTENSIONS.has(extension)) return "log";
|
|
13
|
+
return "file";
|
|
14
|
+
}
|
|
15
|
+
function buildGithubTakeoverReport(input) {
|
|
16
|
+
const targetLabel = input.target || "(issue-or-pr)";
|
|
17
|
+
const repoLine = input.repo ? `- Repository: \`${input.repo}\`` : "- Repository: infer from URL or current checkout";
|
|
18
|
+
const modeLine = input.mode && input.mode !== "auto" ? `- Mode: ${input.mode}` : "- Mode: auto-detect PR vs issue";
|
|
19
|
+
return `# GitHub Task Takeover
|
|
20
|
+
|
|
21
|
+
- Target: \`${targetLabel}\`
|
|
22
|
+
${repoLine}
|
|
23
|
+
${modeLine}
|
|
24
|
+
|
|
25
|
+
## Execution Checklist
|
|
26
|
+
|
|
27
|
+
1. Read repository instructions first: \`AGENTS.md\`, \`CLAUDE.md\`, and scoped rules.
|
|
28
|
+
2. Fetch the PR/issue body, comments, unresolved review threads, changed files, and CI status.
|
|
29
|
+
3. Summarize the requested outcome, blockers, and acceptance criteria before editing.
|
|
30
|
+
4. Claim or create the local task/plan record if the repository uses PMA.
|
|
31
|
+
5. Preserve existing user/agent changes; do not reset or overwrite unrelated files.
|
|
32
|
+
6. Implement the smallest safe patch.
|
|
33
|
+
7. Run focused verification and then the package-required typecheck/build/test command.
|
|
34
|
+
8. Report changed files, verification results, and any remaining blockers.
|
|
35
|
+
|
|
36
|
+
## Copy-Paste Agent Prompt
|
|
37
|
+
|
|
38
|
+
Take over GitHub work for \`${targetLabel}\`${input.repo ? ` in \`${input.repo}\`` : ""}.
|
|
39
|
+
|
|
40
|
+
- Inspect repository instructions before editing.
|
|
41
|
+
- Read PR/issue metadata, comments, unresolved review threads, changed files, and CI.
|
|
42
|
+
- Identify exactly what must be fixed.
|
|
43
|
+
- Implement the minimal patch without touching unrelated user changes.
|
|
44
|
+
- Run focused tests plus the repository-required verification.
|
|
45
|
+
- Return a concise Chinese summary with changed files and verification evidence.
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function buildRemoteDiagnoseReport(input) {
|
|
49
|
+
const serviceClause = input.service ? `SERVICE=${bashQuote(input.service)}` : `SERVICE=${bashQuote("<service-name>")}`;
|
|
50
|
+
const keywordClause = input.keyword ? `KEYWORD=${bashQuote(input.keyword)}` : `KEYWORD=${bashQuote("<error-keyword>")}`;
|
|
51
|
+
const healthUrl = input.healthUrl ?? "http://127.0.0.1:8090/health";
|
|
52
|
+
return `# Remote Diagnosis Evidence Pack
|
|
53
|
+
|
|
54
|
+
- Host: \`${input.host}\`
|
|
55
|
+
- Since: \`${input.since}\`
|
|
56
|
+
- Service: \`${input.service ?? "(optional)"}\`
|
|
57
|
+
- Keyword: \`${input.keyword ?? "(optional)"}\`
|
|
58
|
+
- Health URL: \`${healthUrl}\`
|
|
59
|
+
|
|
60
|
+
Run these commands manually after confirming the target host. They are read-only evidence commands.
|
|
61
|
+
|
|
62
|
+
\`\`\`bash
|
|
63
|
+
HOST=${bashQuote(input.host)}
|
|
64
|
+
${serviceClause}
|
|
65
|
+
${keywordClause}
|
|
66
|
+
SINCE=${bashQuote(input.since)}
|
|
67
|
+
|
|
68
|
+
ssh "$HOST" 'hostname; date; uptime; df -h; free -m'
|
|
69
|
+
ssh "$HOST" 'systemctl --failed --no-pager || true'
|
|
70
|
+
ssh "$HOST" 'docker ps --format "table {{.Names}}\\t{{.Image}}\\t{{.Status}}" || true'
|
|
71
|
+
ssh "$HOST" "curl -fsS ${healthUrl} || true"
|
|
72
|
+
ssh "$HOST" "journalctl --since \\"$SINCE\\" -p warning..alert --no-pager | tail -200 || true"
|
|
73
|
+
ssh "$HOST" "docker logs --since \\"$SINCE\\" \\"$SERVICE\\" 2>&1 | tail -300 || true"
|
|
74
|
+
ssh "$HOST" "grep -RIn --exclude-dir=node_modules --exclude-dir=.git \\"$KEYWORD\\" /tmp /var/log 2>/dev/null | tail -100 || true"
|
|
75
|
+
\`\`\`
|
|
76
|
+
|
|
77
|
+
## Evidence To Return
|
|
78
|
+
|
|
79
|
+
- Exact failing request or user-visible symptom.
|
|
80
|
+
- Health check output.
|
|
81
|
+
- Last 200 warning/error journal lines.
|
|
82
|
+
- Last 300 service log lines.
|
|
83
|
+
- Any screenshot or UI evidence path, added with \`happy evidence add <path>\`.
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
function renderEvidenceReport(entries, title = "Evidence Report") {
|
|
87
|
+
const lines = [`# ${title}`, "", `Total evidence: ${entries.length}`, ""];
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
const session = entry.sessionId ? ` session=${entry.sessionId}` : "";
|
|
90
|
+
lines.push(`## ${entry.title}`);
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push(`- ID: \`${entry.id}\``);
|
|
93
|
+
lines.push(`- Created: ${entry.createdAt}`);
|
|
94
|
+
lines.push(`- Kind: ${entry.kind}${session}`);
|
|
95
|
+
lines.push(`- Target: \`${entry.target}\``);
|
|
96
|
+
if (entry.note) lines.push(`- Note: ${entry.note}`);
|
|
97
|
+
if (entry.kind === "image") {
|
|
98
|
+
const label = entry.title || basename(entry.target);
|
|
99
|
+
const imageTarget = entry.target.startsWith("/") ? `file://${entry.target}` : entry.target;
|
|
100
|
+
lines.push("");
|
|
101
|
+
lines.push(``);
|
|
102
|
+
}
|
|
103
|
+
lines.push("");
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n").trimEnd();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { buildRemoteDiagnoseReport as a, buildGithubTakeoverReport as b, inferEvidenceKind as i, renderEvidenceReport as r };
|