@zonease/happy 0.6.38 → 0.6.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{types-BWpRU1VN.mjs → api-CIZKyfSn.mjs} +136 -1725
- package/dist/{types-DvTsFaqR.cjs → api-CwOCQeLH.cjs} +317 -1961
- package/dist/auth-0VnlXT9f.mjs +181 -0
- package/dist/auth-BE8dD20T.mjs +270 -0
- package/dist/auth-BIleVCw0.cjs +274 -0
- package/dist/auth-Cas9DR3b.cjs +183 -0
- package/dist/browser-Cc08m7of.cjs +22 -0
- package/dist/browser-Dll5hxOV.mjs +20 -0
- package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
- package/dist/claudeLocal-WkgLbl1a.cjs +352 -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-Draa-5XC.cjs} +21 -34
- package/dist/{config-_GW4YBCP.mjs → config-rTT4qTU5.mjs} +7 -20
- package/dist/connect-BfC1tYP_.mjs +679 -0
- package/dist/connect-CJZ73syK.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-CM_QcJnB.mjs +159 -0
- package/dist/controlClient-DZMIsKsT.cjs +168 -0
- package/dist/deviceExec-CU1R9CRb.cjs +84 -0
- package/dist/deviceExec-D93AOVV4.mjs +81 -0
- package/dist/diagnose-B3D1a_v0.cjs +60 -0
- package/dist/diagnose-CuRKXxt1.mjs +58 -0
- package/dist/doctor-C08m5Z9f.cjs +78 -0
- package/dist/doctor-Cya9YSA0.cjs +214 -0
- package/dist/doctor-DZYB6IVc.mjs +211 -0
- package/dist/doctor-ON7pN5G5.mjs +74 -0
- package/dist/downloadImage-DfSFLb-h.mjs +887 -0
- package/dist/downloadImage-MQMrUUxS.cjs +897 -0
- package/dist/enroll-BxlbVftP.cjs +115 -0
- package/dist/enroll-C52x8oly.mjs +113 -0
- package/dist/evidence-Ccd9iYcj.mjs +127 -0
- package/dist/evidence-CjWBG5rX.cjs +129 -0
- package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
- package/dist/formatImageMessage-DbyG8c2j.cjs +46 -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-BokHRgFW.cjs +98 -0
- package/dist/install-C_cp8b2-.cjs +96 -0
- package/dist/install-DAeCn8ae.mjs +94 -0
- package/dist/install-oRAjVLjP.mjs +95 -0
- package/dist/lib.cjs +18 -12
- package/dist/lib.mjs +13 -7
- package/dist/{loadableToolOutput-va3RLplh.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
- package/dist/{loadableToolOutput-5vdQB98M.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
- package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
- package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
- package/dist/persistence-BFjvtUad.mjs +944 -0
- package/dist/persistence-JLUn_Nou.cjs +996 -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-BDn2aE3Q.cjs +2152 -0
- package/dist/run-DBZqN6Kn.mjs +2128 -0
- package/dist/runClaude-DNHvERX0.mjs +3763 -0
- package/dist/runClaude-uaKxPZPm.cjs +3766 -0
- package/dist/{runCodex-skq0j05d.cjs → runCodex-82UrZLme.cjs} +169 -153
- package/dist/{runCodex-DiKzBf9q.mjs → runCodex-C-RTM0wA.mjs} +36 -20
- package/dist/{runGemini-BeqrVq8R.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
- package/dist/{runGemini-CVp-CEIh.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
- package/dist/{runOneShot-BQNkNW61.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
- package/dist/{runOneShot-ltCpHbBB.mjs → runOneShot-ioARRHrx.mjs} +14 -38
- package/dist/{serve-BECdtivY.cjs → serve-BtdAhkIE.cjs} +35 -58
- package/dist/{serve-BNdoEDVx.mjs → serve-CwibwU6N.mjs} +12 -35
- package/dist/session-2sU4Bu1R.mjs +108 -0
- package/dist/session-D--F87zL.cjs +110 -0
- package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
- package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
- package/dist/sessionList-BCSw3qYt.mjs +51 -0
- package/dist/sessionList-ICJsjNtJ.cjs +54 -0
- package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
- package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
- package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
- package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
- package/dist/ssh-BTOlhhxi.cjs +333 -0
- package/dist/ssh-DL_AkRAD.mjs +328 -0
- package/dist/systemdScope-BeOtAkhk.mjs +25 -0
- package/dist/systemdScope-DW3-UoKB.cjs +29 -0
- package/dist/task-CQzrHRZe.mjs +165 -0
- package/dist/task-CSpaC9HX.cjs +167 -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-BiKyRAb1.cjs +77 -0
- package/dist/uninstall-nFMFGUVM.mjs +75 -0
- package/dist/update-BcqRHXf2.mjs +109 -0
- package/dist/update-Dw8pgsAT.cjs +111 -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,10 @@
|
|
|
1
|
+
import { resolve, dirname } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
4
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
function projectPath() {
|
|
6
|
+
const path = resolve(__dirname$1, "..");
|
|
7
|
+
return path;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { projectPath as p };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('path');
|
|
4
|
+
var url = require('url');
|
|
5
|
+
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
const __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('projectPath-ChLhdOyt.cjs', document.baseURI).href))));
|
|
8
|
+
function projectPath() {
|
|
9
|
+
const path$1 = path.resolve(__dirname$1, "..");
|
|
10
|
+
return path$1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
exports.projectPath = projectPath;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var trimIdent = require('./trimIdent-4gvk9Wk6.cjs');
|
|
4
|
+
var common = require('./common-CZvSRU4p.cjs');
|
|
5
|
+
|
|
6
|
+
const CHAT_TITLE_INSTRUCTION = trimIdent.trimIdent(`
|
|
7
|
+
# Chat title
|
|
8
|
+
|
|
9
|
+
On your first response, call "change_title" to set a descriptive title based on the user's message. Update the title whenever the conversation's main focus shifts to a different topic or task.
|
|
10
|
+
`);
|
|
11
|
+
function isOrchestratorWorkerSession(env = process.env) {
|
|
12
|
+
return env[common.ORCHESTRATOR_ENV_KEYS.oneshot] === "1" || !!env[common.ORCHESTRATOR_ENV_KEYS.executionId];
|
|
13
|
+
}
|
|
14
|
+
function shouldEnableOrchestratorTools() {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function getBaseSystemPrompt(env = process.env) {
|
|
18
|
+
if (isOrchestratorWorkerSession(env)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return CHAT_TITLE_INSTRUCTION;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
exports.getBaseSystemPrompt = getBaseSystemPrompt;
|
|
25
|
+
exports.shouldEnableOrchestratorTools = shouldEnableOrchestratorTools;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as trimIdent } from './trimIdent-BAjmv_TG.mjs';
|
|
2
|
+
import { O as ORCHESTRATOR_ENV_KEYS } from './common-BdNgghUJ.mjs';
|
|
3
|
+
|
|
4
|
+
const CHAT_TITLE_INSTRUCTION = trimIdent(`
|
|
5
|
+
# Chat title
|
|
6
|
+
|
|
7
|
+
On your first response, call "change_title" to set a descriptive title based on the user's message. Update the title whenever the conversation's main focus shifts to a different topic or task.
|
|
8
|
+
`);
|
|
9
|
+
function isOrchestratorWorkerSession(env = process.env) {
|
|
10
|
+
return env[ORCHESTRATOR_ENV_KEYS.oneshot] === "1" || !!env[ORCHESTRATOR_ENV_KEYS.executionId];
|
|
11
|
+
}
|
|
12
|
+
function shouldEnableOrchestratorTools() {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
function getBaseSystemPrompt(env = process.env) {
|
|
16
|
+
if (isOrchestratorWorkerSession(env)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return CHAT_TITLE_INSTRUCTION;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { getBaseSystemPrompt as g, shouldEnableOrchestratorTools as s };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { access } from 'node:fs/promises';
|
|
3
|
+
import { constants } from 'node:fs';
|
|
4
|
+
import { join, resolve, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { p as parseWorkflowArgs, s as stringFlag, b as booleanFlag } from './workflowCommon-B0d01Y_a.mjs';
|
|
8
|
+
|
|
9
|
+
const CLI_PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
10
|
+
function printReleaseHelp() {
|
|
11
|
+
console.log(`
|
|
12
|
+
${chalk.bold("happy release")} - Verify before publishing
|
|
13
|
+
|
|
14
|
+
${chalk.bold("Usage:")}
|
|
15
|
+
happy release guard [options]
|
|
16
|
+
|
|
17
|
+
${chalk.bold("Options:")}
|
|
18
|
+
--package <name> happy-cli | happy-app | happy-server (default: happy-cli)
|
|
19
|
+
--publish <target> none | npm (default: none)
|
|
20
|
+
--yes Actually publish after all checks pass
|
|
21
|
+
--dry-run Alias for the default safe mode; never publishes
|
|
22
|
+
--full For happy-cli, run the full test suite instead of focused command tests
|
|
23
|
+
--json Print final machine-readable result
|
|
24
|
+
-h, --help Show this help
|
|
25
|
+
|
|
26
|
+
${chalk.bold("Safety:")}
|
|
27
|
+
Publishing never happens unless both --publish npm and --yes are present.
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
function commandName(command) {
|
|
31
|
+
if (process.platform !== "win32") return command;
|
|
32
|
+
if (command === "yarn") return "yarn.cmd";
|
|
33
|
+
if (command === "npm") return "npm.cmd";
|
|
34
|
+
if (command === "npx") return "npx.cmd";
|
|
35
|
+
return command;
|
|
36
|
+
}
|
|
37
|
+
async function pathExists(path) {
|
|
38
|
+
try {
|
|
39
|
+
await access(path, constants.F_OK);
|
|
40
|
+
return true;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function findWorkspaceRoot(start) {
|
|
46
|
+
let current = resolve(start);
|
|
47
|
+
while (true) {
|
|
48
|
+
if (await pathExists(join(current, "packages", "happy-cli", "package.json"))) {
|
|
49
|
+
return current;
|
|
50
|
+
}
|
|
51
|
+
const parent = dirname(current);
|
|
52
|
+
if (parent === current) return null;
|
|
53
|
+
current = parent;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function parseGuardPackage(value) {
|
|
57
|
+
if (!value || value === "happy-cli") return "happy-cli";
|
|
58
|
+
if (value === "happy-app" || value === "happy-server") return value;
|
|
59
|
+
throw new Error("--package must be one of: happy-cli, happy-app, happy-server.");
|
|
60
|
+
}
|
|
61
|
+
async function packageDirectory(packageName) {
|
|
62
|
+
if (packageName === "happy-cli") return CLI_PACKAGE_ROOT;
|
|
63
|
+
const workspaceRoot = await findWorkspaceRoot(process.cwd()) ?? await findWorkspaceRoot(CLI_PACKAGE_ROOT);
|
|
64
|
+
if (!workspaceRoot) {
|
|
65
|
+
throw new Error(`Cannot find monorepo root for ${packageName}. Run this from the Happy AI repository checkout.`);
|
|
66
|
+
}
|
|
67
|
+
return join(workspaceRoot, "packages", packageName);
|
|
68
|
+
}
|
|
69
|
+
async function runGuardStep(step) {
|
|
70
|
+
if (step.optional && !await pathExists(step.cwd)) {
|
|
71
|
+
console.log(chalk.yellow(`\u21B7 ${step.name} skipped: ${step.cwd} not found`));
|
|
72
|
+
return { name: step.name, status: "skipped", exitCode: null };
|
|
73
|
+
}
|
|
74
|
+
console.log(chalk.cyan(`
|
|
75
|
+
\u25B6 ${step.name}`));
|
|
76
|
+
console.log(chalk.gray(` ${step.command} ${step.args.join(" ")}`));
|
|
77
|
+
const exitCode = await new Promise((resolvePromise) => {
|
|
78
|
+
const child = spawn(commandName(step.command), step.args, {
|
|
79
|
+
cwd: step.cwd,
|
|
80
|
+
stdio: "inherit",
|
|
81
|
+
env: process.env
|
|
82
|
+
});
|
|
83
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
84
|
+
child.on("error", () => resolvePromise(1));
|
|
85
|
+
});
|
|
86
|
+
return { name: step.name, status: exitCode === 0 ? "passed" : "failed", exitCode };
|
|
87
|
+
}
|
|
88
|
+
function guardSteps(packageName, packageDir, full, includePublishDryRun) {
|
|
89
|
+
const publishDryRun = includePublishDryRun ? [{ name: "npm publish dry-run", command: "npm", args: ["publish", "--dry-run", "--registry=https://registry.npmjs.org"], cwd: packageDir }] : [];
|
|
90
|
+
if (packageName === "happy-cli") {
|
|
91
|
+
const testStep = full ? { name: "Full test suite", command: "yarn", args: ["test"], cwd: packageDir } : { name: "Focused workflow tests", command: "npx", args: ["vitest", "run", "src/commands/workflowReports.test.ts"], cwd: packageDir };
|
|
92
|
+
return [
|
|
93
|
+
{ name: "Typecheck", command: "yarn", args: ["typecheck"], cwd: packageDir },
|
|
94
|
+
testStep,
|
|
95
|
+
{ name: "Build", command: "yarn", args: ["build"], cwd: packageDir },
|
|
96
|
+
...publishDryRun
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
if (packageName === "happy-app") {
|
|
100
|
+
return [
|
|
101
|
+
{ name: "Typecheck", command: "yarn", args: ["typecheck"], cwd: packageDir },
|
|
102
|
+
{ name: "Parse changelog", command: "npx", args: ["tsx", "sources/scripts/parseChangelog.ts"], cwd: packageDir }
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
return [
|
|
106
|
+
{ name: "Build", command: "yarn", args: ["build"], cwd: packageDir }
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
async function handleReleaseCommand(args) {
|
|
110
|
+
const action = args[0];
|
|
111
|
+
if (!action || action === "-h" || action === "--help") {
|
|
112
|
+
printReleaseHelp();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (action !== "guard") {
|
|
116
|
+
throw new Error(`Unknown release command: ${action}. Use "happy release guard".`);
|
|
117
|
+
}
|
|
118
|
+
const parsed = parseWorkflowArgs(args.slice(1), /* @__PURE__ */ new Set(["--package", "--publish"]));
|
|
119
|
+
const packageName = parseGuardPackage(stringFlag(parsed, "--package"));
|
|
120
|
+
const publishTarget = stringFlag(parsed, "--publish") ?? "none";
|
|
121
|
+
const dryRunOnly = booleanFlag(parsed, "--dry-run");
|
|
122
|
+
if (publishTarget !== "none" && publishTarget !== "npm") {
|
|
123
|
+
throw new Error("--publish must be one of: none, npm.");
|
|
124
|
+
}
|
|
125
|
+
const packageDir = await packageDirectory(packageName);
|
|
126
|
+
const includePublishDryRun = packageName === "happy-cli" || publishTarget === "npm";
|
|
127
|
+
const steps = guardSteps(packageName, packageDir, booleanFlag(parsed, "--full"), includePublishDryRun);
|
|
128
|
+
const results = [];
|
|
129
|
+
for (const step of steps) {
|
|
130
|
+
const result = await runGuardStep(step);
|
|
131
|
+
results.push(result);
|
|
132
|
+
if (result.status === "failed") {
|
|
133
|
+
console.error(chalk.red(`
|
|
134
|
+
\u2717 Release guard failed at: ${result.name}`));
|
|
135
|
+
if (booleanFlag(parsed, "--json")) {
|
|
136
|
+
console.log(JSON.stringify({ packageName, packageDir, publishTarget, dryRunOnly, results, ok: false }, null, 2));
|
|
137
|
+
}
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (publishTarget === "npm" && packageName !== "happy-cli") {
|
|
142
|
+
throw new Error("npm publish is currently supported only for happy-cli.");
|
|
143
|
+
}
|
|
144
|
+
if (publishTarget === "npm" && !dryRunOnly) {
|
|
145
|
+
if (!booleanFlag(parsed, "--yes")) {
|
|
146
|
+
console.log(chalk.yellow("\n\u2713 Checks passed. Skipping publish because --yes was not provided."));
|
|
147
|
+
console.log(chalk.gray(" To publish: happy release guard --package happy-cli --publish npm --yes"));
|
|
148
|
+
} else {
|
|
149
|
+
const publishResult = await runGuardStep({
|
|
150
|
+
name: "npm publish",
|
|
151
|
+
command: "npm",
|
|
152
|
+
args: ["publish", "--registry=https://registry.npmjs.org"],
|
|
153
|
+
cwd: packageDir
|
|
154
|
+
});
|
|
155
|
+
results.push(publishResult);
|
|
156
|
+
if (publishResult.status === "failed") process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
const reason = dryRunOnly ? "Dry-run mode; no publish requested." : "No publish requested.";
|
|
160
|
+
console.log(chalk.green(`
|
|
161
|
+
\u2713 Release guard passed. ${reason}`));
|
|
162
|
+
}
|
|
163
|
+
if (booleanFlag(parsed, "--json")) {
|
|
164
|
+
console.log(JSON.stringify({ packageName, packageDir, publishTarget, dryRunOnly, results, ok: true }, null, 2));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { handleReleaseCommand };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var promises = require('node:fs/promises');
|
|
5
|
+
var fs = require('node:fs');
|
|
6
|
+
var path = require('node:path');
|
|
7
|
+
var node_url = require('node:url');
|
|
8
|
+
var node_child_process = require('node:child_process');
|
|
9
|
+
var workflowCommon = require('./workflowCommon-Bl568-rt.cjs');
|
|
10
|
+
|
|
11
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
|
+
const CLI_PACKAGE_ROOT = path.resolve(path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('release-EhOJeAZe.cjs', document.baseURI).href)))), "..", "..");
|
|
13
|
+
function printReleaseHelp() {
|
|
14
|
+
console.log(`
|
|
15
|
+
${chalk.bold("happy release")} - Verify before publishing
|
|
16
|
+
|
|
17
|
+
${chalk.bold("Usage:")}
|
|
18
|
+
happy release guard [options]
|
|
19
|
+
|
|
20
|
+
${chalk.bold("Options:")}
|
|
21
|
+
--package <name> happy-cli | happy-app | happy-server (default: happy-cli)
|
|
22
|
+
--publish <target> none | npm (default: none)
|
|
23
|
+
--yes Actually publish after all checks pass
|
|
24
|
+
--dry-run Alias for the default safe mode; never publishes
|
|
25
|
+
--full For happy-cli, run the full test suite instead of focused command tests
|
|
26
|
+
--json Print final machine-readable result
|
|
27
|
+
-h, --help Show this help
|
|
28
|
+
|
|
29
|
+
${chalk.bold("Safety:")}
|
|
30
|
+
Publishing never happens unless both --publish npm and --yes are present.
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
function commandName(command) {
|
|
34
|
+
if (process.platform !== "win32") return command;
|
|
35
|
+
if (command === "yarn") return "yarn.cmd";
|
|
36
|
+
if (command === "npm") return "npm.cmd";
|
|
37
|
+
if (command === "npx") return "npx.cmd";
|
|
38
|
+
return command;
|
|
39
|
+
}
|
|
40
|
+
async function pathExists(path) {
|
|
41
|
+
try {
|
|
42
|
+
await promises.access(path, fs.constants.F_OK);
|
|
43
|
+
return true;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function findWorkspaceRoot(start) {
|
|
49
|
+
let current = path.resolve(start);
|
|
50
|
+
while (true) {
|
|
51
|
+
if (await pathExists(path.join(current, "packages", "happy-cli", "package.json"))) {
|
|
52
|
+
return current;
|
|
53
|
+
}
|
|
54
|
+
const parent = path.dirname(current);
|
|
55
|
+
if (parent === current) return null;
|
|
56
|
+
current = parent;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function parseGuardPackage(value) {
|
|
60
|
+
if (!value || value === "happy-cli") return "happy-cli";
|
|
61
|
+
if (value === "happy-app" || value === "happy-server") return value;
|
|
62
|
+
throw new Error("--package must be one of: happy-cli, happy-app, happy-server.");
|
|
63
|
+
}
|
|
64
|
+
async function packageDirectory(packageName) {
|
|
65
|
+
if (packageName === "happy-cli") return CLI_PACKAGE_ROOT;
|
|
66
|
+
const workspaceRoot = await findWorkspaceRoot(process.cwd()) ?? await findWorkspaceRoot(CLI_PACKAGE_ROOT);
|
|
67
|
+
if (!workspaceRoot) {
|
|
68
|
+
throw new Error(`Cannot find monorepo root for ${packageName}. Run this from the Happy AI repository checkout.`);
|
|
69
|
+
}
|
|
70
|
+
return path.join(workspaceRoot, "packages", packageName);
|
|
71
|
+
}
|
|
72
|
+
async function runGuardStep(step) {
|
|
73
|
+
if (step.optional && !await pathExists(step.cwd)) {
|
|
74
|
+
console.log(chalk.yellow(`\u21B7 ${step.name} skipped: ${step.cwd} not found`));
|
|
75
|
+
return { name: step.name, status: "skipped", exitCode: null };
|
|
76
|
+
}
|
|
77
|
+
console.log(chalk.cyan(`
|
|
78
|
+
\u25B6 ${step.name}`));
|
|
79
|
+
console.log(chalk.gray(` ${step.command} ${step.args.join(" ")}`));
|
|
80
|
+
const exitCode = await new Promise((resolvePromise) => {
|
|
81
|
+
const child = node_child_process.spawn(commandName(step.command), step.args, {
|
|
82
|
+
cwd: step.cwd,
|
|
83
|
+
stdio: "inherit",
|
|
84
|
+
env: process.env
|
|
85
|
+
});
|
|
86
|
+
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
87
|
+
child.on("error", () => resolvePromise(1));
|
|
88
|
+
});
|
|
89
|
+
return { name: step.name, status: exitCode === 0 ? "passed" : "failed", exitCode };
|
|
90
|
+
}
|
|
91
|
+
function guardSteps(packageName, packageDir, full, includePublishDryRun) {
|
|
92
|
+
const publishDryRun = includePublishDryRun ? [{ name: "npm publish dry-run", command: "npm", args: ["publish", "--dry-run", "--registry=https://registry.npmjs.org"], cwd: packageDir }] : [];
|
|
93
|
+
if (packageName === "happy-cli") {
|
|
94
|
+
const testStep = full ? { name: "Full test suite", command: "yarn", args: ["test"], cwd: packageDir } : { name: "Focused workflow tests", command: "npx", args: ["vitest", "run", "src/commands/workflowReports.test.ts"], cwd: packageDir };
|
|
95
|
+
return [
|
|
96
|
+
{ name: "Typecheck", command: "yarn", args: ["typecheck"], cwd: packageDir },
|
|
97
|
+
testStep,
|
|
98
|
+
{ name: "Build", command: "yarn", args: ["build"], cwd: packageDir },
|
|
99
|
+
...publishDryRun
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
if (packageName === "happy-app") {
|
|
103
|
+
return [
|
|
104
|
+
{ name: "Typecheck", command: "yarn", args: ["typecheck"], cwd: packageDir },
|
|
105
|
+
{ name: "Parse changelog", command: "npx", args: ["tsx", "sources/scripts/parseChangelog.ts"], cwd: packageDir }
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
return [
|
|
109
|
+
{ name: "Build", command: "yarn", args: ["build"], cwd: packageDir }
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
async function handleReleaseCommand(args) {
|
|
113
|
+
const action = args[0];
|
|
114
|
+
if (!action || action === "-h" || action === "--help") {
|
|
115
|
+
printReleaseHelp();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (action !== "guard") {
|
|
119
|
+
throw new Error(`Unknown release command: ${action}. Use "happy release guard".`);
|
|
120
|
+
}
|
|
121
|
+
const parsed = workflowCommon.parseWorkflowArgs(args.slice(1), /* @__PURE__ */ new Set(["--package", "--publish"]));
|
|
122
|
+
const packageName = parseGuardPackage(workflowCommon.stringFlag(parsed, "--package"));
|
|
123
|
+
const publishTarget = workflowCommon.stringFlag(parsed, "--publish") ?? "none";
|
|
124
|
+
const dryRunOnly = workflowCommon.booleanFlag(parsed, "--dry-run");
|
|
125
|
+
if (publishTarget !== "none" && publishTarget !== "npm") {
|
|
126
|
+
throw new Error("--publish must be one of: none, npm.");
|
|
127
|
+
}
|
|
128
|
+
const packageDir = await packageDirectory(packageName);
|
|
129
|
+
const includePublishDryRun = packageName === "happy-cli" || publishTarget === "npm";
|
|
130
|
+
const steps = guardSteps(packageName, packageDir, workflowCommon.booleanFlag(parsed, "--full"), includePublishDryRun);
|
|
131
|
+
const results = [];
|
|
132
|
+
for (const step of steps) {
|
|
133
|
+
const result = await runGuardStep(step);
|
|
134
|
+
results.push(result);
|
|
135
|
+
if (result.status === "failed") {
|
|
136
|
+
console.error(chalk.red(`
|
|
137
|
+
\u2717 Release guard failed at: ${result.name}`));
|
|
138
|
+
if (workflowCommon.booleanFlag(parsed, "--json")) {
|
|
139
|
+
console.log(JSON.stringify({ packageName, packageDir, publishTarget, dryRunOnly, results, ok: false }, null, 2));
|
|
140
|
+
}
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (publishTarget === "npm" && packageName !== "happy-cli") {
|
|
145
|
+
throw new Error("npm publish is currently supported only for happy-cli.");
|
|
146
|
+
}
|
|
147
|
+
if (publishTarget === "npm" && !dryRunOnly) {
|
|
148
|
+
if (!workflowCommon.booleanFlag(parsed, "--yes")) {
|
|
149
|
+
console.log(chalk.yellow("\n\u2713 Checks passed. Skipping publish because --yes was not provided."));
|
|
150
|
+
console.log(chalk.gray(" To publish: happy release guard --package happy-cli --publish npm --yes"));
|
|
151
|
+
} else {
|
|
152
|
+
const publishResult = await runGuardStep({
|
|
153
|
+
name: "npm publish",
|
|
154
|
+
command: "npm",
|
|
155
|
+
args: ["publish", "--registry=https://registry.npmjs.org"],
|
|
156
|
+
cwd: packageDir
|
|
157
|
+
});
|
|
158
|
+
results.push(publishResult);
|
|
159
|
+
if (publishResult.status === "failed") process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
const reason = dryRunOnly ? "Dry-run mode; no publish requested." : "No publish requested.";
|
|
163
|
+
console.log(chalk.green(`
|
|
164
|
+
\u2713 Release guard passed. ${reason}`));
|
|
165
|
+
}
|
|
166
|
+
if (workflowCommon.booleanFlag(parsed, "--json")) {
|
|
167
|
+
console.log(JSON.stringify({ packageName, packageDir, publishTarget, dryRunOnly, results, ok: true }, null, 2));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
exports.handleReleaseCommand = handleReleaseCommand;
|