@zonease/happy 0.6.37 → 0.6.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/{types-DYCJXXdA.mjs → api-CIZKyfSn.mjs} +136 -1725
  2. package/dist/{types-BrTorNAy.cjs → api-CwOCQeLH.cjs} +317 -1961
  3. package/dist/auth-0VnlXT9f.mjs +181 -0
  4. package/dist/auth-BE8dD20T.mjs +270 -0
  5. package/dist/auth-BIleVCw0.cjs +274 -0
  6. package/dist/auth-Cas9DR3b.cjs +183 -0
  7. package/dist/browser-Cc08m7of.cjs +22 -0
  8. package/dist/browser-Dll5hxOV.mjs +20 -0
  9. package/dist/claudeLocal-CPT3zcIU.mjs +344 -0
  10. package/dist/claudeLocal-WkgLbl1a.cjs +352 -0
  11. package/dist/codex/happyMcpStdioBridge.cjs +4 -1
  12. package/dist/codex/happyMcpStdioBridge.mjs +4 -1
  13. package/dist/common-BdNgghUJ.mjs +75 -0
  14. package/dist/common-CZvSRU4p.cjs +83 -0
  15. package/dist/{config-D_g6ohaV.cjs → config-Draa-5XC.cjs} +21 -34
  16. package/dist/{config-DPn-cbpz.mjs → config-rTT4qTU5.mjs} +7 -20
  17. package/dist/connect-BfC1tYP_.mjs +679 -0
  18. package/dist/connect-CJZ73syK.cjs +681 -0
  19. package/dist/{constants-B4x1K7by.cjs → constants-E_UWYTo3.cjs} +2 -2
  20. package/dist/{constants-BO9OAFOT.mjs → constants-pmXZGibX.mjs} +1 -1
  21. package/dist/controlClient-CM_QcJnB.mjs +159 -0
  22. package/dist/controlClient-DZMIsKsT.cjs +168 -0
  23. package/dist/deviceExec-CU1R9CRb.cjs +84 -0
  24. package/dist/deviceExec-D93AOVV4.mjs +81 -0
  25. package/dist/diagnose-B3D1a_v0.cjs +60 -0
  26. package/dist/diagnose-CuRKXxt1.mjs +58 -0
  27. package/dist/doctor-C08m5Z9f.cjs +78 -0
  28. package/dist/doctor-Cya9YSA0.cjs +214 -0
  29. package/dist/doctor-DZYB6IVc.mjs +211 -0
  30. package/dist/doctor-ON7pN5G5.mjs +74 -0
  31. package/dist/downloadImage-DfSFLb-h.mjs +887 -0
  32. package/dist/downloadImage-MQMrUUxS.cjs +897 -0
  33. package/dist/enroll-BxlbVftP.cjs +115 -0
  34. package/dist/enroll-C52x8oly.mjs +113 -0
  35. package/dist/evidence-Ccd9iYcj.mjs +127 -0
  36. package/dist/evidence-CjWBG5rX.cjs +129 -0
  37. package/dist/formatImageMessage-B4lSxlk2.mjs +43 -0
  38. package/dist/formatImageMessage-DbyG8c2j.cjs +46 -0
  39. package/dist/github-DKcyF1zp.mjs +57 -0
  40. package/dist/github-h9GhJJ_C.cjs +59 -0
  41. package/dist/index-CDTNgfUf.cjs +578 -0
  42. package/dist/index-CPKdvi7J.mjs +554 -0
  43. package/dist/index.cjs +812 -40
  44. package/dist/index.mjs +813 -40
  45. package/dist/install-BokHRgFW.cjs +98 -0
  46. package/dist/install-C_cp8b2-.cjs +96 -0
  47. package/dist/install-DAeCn8ae.mjs +94 -0
  48. package/dist/install-oRAjVLjP.mjs +95 -0
  49. package/dist/lib.cjs +18 -12
  50. package/dist/lib.d.cts +16 -16
  51. package/dist/lib.d.mts +16 -16
  52. package/dist/lib.mjs +13 -7
  53. package/dist/{loadableToolOutput-lQH8Kb_w.mjs → loadableToolOutput-Cuygmd4K.mjs} +4 -2
  54. package/dist/{loadableToolOutput-CasonFIt.cjs → loadableToolOutput-DDCJjywt.cjs} +63 -61
  55. package/dist/mcpToolSchemas-CjeTfrAs.mjs +62 -0
  56. package/dist/mcpToolSchemas-DK42yoZ_.cjs +64 -0
  57. package/dist/persistence-BFjvtUad.mjs +944 -0
  58. package/dist/persistence-JLUn_Nou.cjs +996 -0
  59. package/dist/projectPath-BTBIMB57.mjs +10 -0
  60. package/dist/projectPath-ChLhdOyt.cjs +13 -0
  61. package/dist/prompt-BTWDZZO0.cjs +25 -0
  62. package/dist/prompt-BsAZsPbo.mjs +22 -0
  63. package/dist/release-BMEzNONE.mjs +168 -0
  64. package/dist/release-EhOJeAZe.cjs +171 -0
  65. package/dist/run-BDn2aE3Q.cjs +2152 -0
  66. package/dist/run-DBZqN6Kn.mjs +2128 -0
  67. package/dist/runClaude-DNHvERX0.mjs +3763 -0
  68. package/dist/runClaude-uaKxPZPm.cjs +3766 -0
  69. package/dist/{runCodex-BTt3fxG4.cjs → runCodex-82UrZLme.cjs} +169 -153
  70. package/dist/{runCodex-BXCB5trB.mjs → runCodex-C-RTM0wA.mjs} +36 -20
  71. package/dist/{runGemini-37HHbp9n.mjs → runGemini-Bm6-4Xm2.mjs} +34 -17
  72. package/dist/{runGemini-C-0nSFBv.cjs → runGemini-CXMr4Jwb.cjs} +212 -195
  73. package/dist/{runOneShot-CXhbFJ2j.cjs → runOneShot-1B6RMYT7.cjs} +31 -55
  74. package/dist/{runOneShot-USX8QPfE.mjs → runOneShot-ioARRHrx.mjs} +14 -38
  75. package/dist/{serve-DZAq-_1F.cjs → serve-BtdAhkIE.cjs} +35 -58
  76. package/dist/{serve-BRedJPzL.mjs → serve-CwibwU6N.mjs} +12 -35
  77. package/dist/session-2sU4Bu1R.mjs +108 -0
  78. package/dist/session-D--F87zL.cjs +110 -0
  79. package/dist/sessionKeyCache-4Tp8pJ3N.cjs +36 -0
  80. package/dist/sessionKeyCache-D2BwO91C.mjs +33 -0
  81. package/dist/sessionList-BCSw3qYt.mjs +51 -0
  82. package/dist/sessionList-ICJsjNtJ.cjs +54 -0
  83. package/dist/sessionSummary-Bkz52BPh.cjs +393 -0
  84. package/dist/sessionSummary-lHGBWQSb.mjs +387 -0
  85. package/dist/spawnHappyCLI-CoORX0YW.mjs +66 -0
  86. package/dist/spawnHappyCLI-D_V-AAoP.cjs +70 -0
  87. package/dist/ssh-BTOlhhxi.cjs +333 -0
  88. package/dist/ssh-DL_AkRAD.mjs +328 -0
  89. package/dist/systemdScope-BeOtAkhk.mjs +25 -0
  90. package/dist/systemdScope-DW3-UoKB.cjs +29 -0
  91. package/dist/task-CQzrHRZe.mjs +165 -0
  92. package/dist/task-CSpaC9HX.cjs +167 -0
  93. package/dist/time-Bj2HRkKH.cjs +33 -0
  94. package/dist/time-DgsBLJA_.mjs +29 -0
  95. package/dist/trimIdent-4gvk9Wk6.cjs +22 -0
  96. package/dist/trimIdent-BAjmv_TG.mjs +20 -0
  97. package/dist/types-BoJh4Qfv.mjs +57 -0
  98. package/dist/types-DWeB7aqh.cjs +59 -0
  99. package/dist/uninstall-BiKyRAb1.cjs +77 -0
  100. package/dist/uninstall-nFMFGUVM.mjs +75 -0
  101. package/dist/update-BcqRHXf2.mjs +109 -0
  102. package/dist/update-Dw8pgsAT.cjs +111 -0
  103. package/dist/workflowCommon-B0d01Y_a.mjs +56 -0
  104. package/dist/workflowCommon-Bl568-rt.cjs +62 -0
  105. package/dist/workflowReports-BEWuQesA.cjs +113 -0
  106. package/dist/workflowReports-Dd8-4-8f.mjs +108 -0
  107. package/package.json +1 -1
  108. package/dist/index-BlkHOkB3.cjs +0 -11312
  109. package/dist/index-DJ2VpGiR.mjs +0 -11272
  110. package/dist/mcpToolSchemas-CdPXJQmb.mjs +0 -175
  111. package/dist/mcpToolSchemas-f-kttjFw.cjs +0 -186
@@ -0,0 +1,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;