happy-imou-cloud 2.0.7 → 2.0.8

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 (26) hide show
  1. package/bin/happy-cloud.mjs +1 -1
  2. package/dist/{api-Dwkm7s_E.cjs → api-CN-WqYd_.cjs} +3 -4
  3. package/dist/{api-dwwHBzLc.mjs → api-D-uiH_TF.mjs} +3 -4
  4. package/dist/{command-Cfq3Uc0S.mjs → command-DGFsZx58.mjs} +3 -3
  5. package/dist/{command-DiAVIsxX.cjs → command-DjIfRZQS.cjs} +3 -3
  6. package/dist/{index-CfqxEoyl.cjs → index-DM6z3aeG.cjs} +189 -26
  7. package/dist/{index-HyqLXzw-.mjs → index-DhheEtRl.mjs} +187 -24
  8. package/dist/index.cjs +3 -3
  9. package/dist/index.mjs +3 -3
  10. package/dist/lib.cjs +1 -1
  11. package/dist/lib.mjs +1 -1
  12. package/dist/{BaseReasoningProcessor-ClrT-x-H.mjs → names-BjEof0E2.mjs} +98 -3
  13. package/dist/{BaseReasoningProcessor-DphULXS-.cjs → names-BnV67N_O.cjs} +100 -2
  14. package/dist/{persistence-hbhwAYIV.cjs → persistence-DBGkO8gB.cjs} +110 -1
  15. package/dist/{persistence-Dg-rxY2a.mjs → persistence-DiNg1DPF.mjs} +100 -4
  16. package/dist/{registerKillSessionHandler-D1ouN10n.cjs → registerKillSessionHandler-CYc0SIjF.cjs} +2 -2
  17. package/dist/{registerKillSessionHandler-BAvk4GYO.mjs → registerKillSessionHandler-Cu9rHGsI.mjs} +2 -2
  18. package/dist/{runClaude-CZmJ7qEP.cjs → runClaude-CPhWaFrX.cjs} +5 -5
  19. package/dist/{runClaude-OxYbt3ZQ.mjs → runClaude-DAR_hw3C.mjs} +4 -4
  20. package/dist/{runCodex-CtncAgso.cjs → runCodex--QLrOs8X.cjs} +24 -25
  21. package/dist/{runCodex-ByVTEbSY.mjs → runCodex-B4QAb-Go.mjs} +5 -6
  22. package/dist/{runGemini-ChwjLmhI.cjs → runGemini-CDyhCucw.cjs} +20 -21
  23. package/dist/{runGemini-BRO6A2jm.mjs → runGemini-DqowSR2w.mjs} +5 -6
  24. package/package.json +3 -4
  25. package/scripts/build.mjs +66 -0
  26. package/scripts/release-smoke.mjs +166 -30
@@ -3,12 +3,11 @@
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
5
  var node_crypto = require('node:crypto');
6
- var api = require('./api-Dwkm7s_E.cjs');
7
- var persistence = require('./persistence-hbhwAYIV.cjs');
8
- var BaseReasoningProcessor = require('./BaseReasoningProcessor-DphULXS-.cjs');
9
- var index = require('./index-CfqxEoyl.cjs');
10
- var registerKillSessionHandler = require('./registerKillSessionHandler-D1ouN10n.cjs');
11
- var happyProtocol = require('happy-protocol');
6
+ var api = require('./api-CN-WqYd_.cjs');
7
+ var persistence = require('./persistence-DBGkO8gB.cjs');
8
+ var names = require('./names-BnV67N_O.cjs');
9
+ var index = require('./index-DM6z3aeG.cjs');
10
+ var registerKillSessionHandler = require('./registerKillSessionHandler-CYc0SIjF.cjs');
12
11
  require('axios');
13
12
  require('chalk');
14
13
  require('fs');
@@ -185,7 +184,7 @@ const GeminiDisplay = ({ messageBuffer, logPath, currentModel, onExit }) => {
185
184
  ));
186
185
  };
187
186
 
188
- class GeminiPermissionHandler extends BaseReasoningProcessor.BasePermissionHandler {
187
+ class GeminiPermissionHandler extends names.BasePermissionHandler {
189
188
  currentPermissionMode = "default";
190
189
  constructor(session) {
191
190
  super(session);
@@ -270,7 +269,7 @@ class GeminiPermissionHandler extends BaseReasoningProcessor.BasePermissionHandl
270
269
  }
271
270
  }
272
271
 
273
- class GeminiReasoningProcessor extends BaseReasoningProcessor.BaseReasoningProcessor {
272
+ class GeminiReasoningProcessor extends names.BaseReasoningProcessor {
274
273
  getToolName() {
275
274
  return "GeminiReasoning";
276
275
  }
@@ -601,7 +600,7 @@ async function runGemini(opts) {
601
600
  } catch (error) {
602
601
  api.logger.debug("[Gemini] Failed to fetch cloud token:", error);
603
602
  }
604
- const { state, metadata } = BaseReasoningProcessor.createSessionMetadata({
603
+ const { state, metadata } = names.createSessionMetadata({
605
604
  flavor: "gemini",
606
605
  machineId,
607
606
  startedBy: opts.startedBy
@@ -629,7 +628,7 @@ async function runGemini(opts) {
629
628
  pendingSessionSwap = null;
630
629
  }
631
630
  };
632
- const { session: initialSession, reconnectionHandle } = BaseReasoningProcessor.setupOfflineReconnection({
631
+ const { session: initialSession, reconnectionHandle } = names.setupOfflineReconnection({
633
632
  api: api$1,
634
633
  sessionTag,
635
634
  metadata,
@@ -951,13 +950,13 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
951
950
  if (isInvestigationTool && msg.args && typeof msg.args === "object" && "objective" in msg.args) {
952
951
  api.logger.debug(`[gemini] \u{1F50D} Investigation objective: ${String(msg.args.objective).substring(0, 150)}...`);
953
952
  }
954
- const canonicalToolName = happyProtocol.resolveCanonicalToolNameV2(msg.toolName);
953
+ const canonicalToolName = names.resolveCanonicalToolNameV2(msg.toolName);
955
954
  messageBuffer.addMessage(`Executing: ${msg.toolName}${toolArgs ? ` ${toolArgs}${toolArgs.length >= 100 ? "..." : ""}` : ""}`, "tool");
956
955
  session.sendAgentMessage("gemini", {
957
956
  type: "tool-call",
958
957
  name: canonicalToolName,
959
958
  callId: msg.callId,
960
- input: happyProtocol.attachToolHappierMetaV2(msg.args, {
959
+ input: names.attachToolHappierMetaV2(msg.args, {
961
960
  v: 2,
962
961
  protocol: "acp",
963
962
  provider: "gemini",
@@ -968,7 +967,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
968
967
  });
969
968
  break;
970
969
  case "tool-result":
971
- const isError = happyProtocol.inferToolResultError(msg.result);
970
+ const isError = names.inferToolResultError(msg.result);
972
971
  const resultText = typeof msg.result === "string" ? msg.result.substring(0, 200) : JSON.stringify(msg.result).substring(0, 200);
973
972
  const truncatedResult = resultText + (typeof msg.result === "string" && msg.result.length > 200 ? "..." : "");
974
973
  const resultSize = typeof msg.result === "string" ? msg.result.length : JSON.stringify(msg.result).length;
@@ -989,12 +988,12 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
989
988
  session.sendAgentMessage("gemini", {
990
989
  type: "tool-result",
991
990
  callId: msg.callId,
992
- output: happyProtocol.attachToolHappierMetaV2(msg.result, {
991
+ output: names.attachToolHappierMetaV2(msg.result, {
993
992
  v: 2,
994
993
  protocol: "acp",
995
994
  provider: "gemini",
996
995
  rawToolName: msg.toolName,
997
- canonicalToolName: happyProtocol.resolveCanonicalToolNameV2(msg.toolName)
996
+ canonicalToolName: names.resolveCanonicalToolNameV2(msg.toolName)
998
997
  }),
999
998
  id: node_crypto.randomUUID(),
1000
999
  isError
@@ -1044,12 +1043,12 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1044
1043
  const { call_id, type, ...inputs } = execApprovalMsg;
1045
1044
  api.logger.debug(`[gemini] Exec approval request received: ${callId}`);
1046
1045
  messageBuffer.addMessage(`Exec approval requested: ${callId}`, "tool");
1047
- const execCanonicalToolName = happyProtocol.resolveCanonicalToolNameV2("GeminiBash");
1046
+ const execCanonicalToolName = names.resolveCanonicalToolNameV2("GeminiBash");
1048
1047
  session.sendAgentMessage("gemini", {
1049
1048
  type: "tool-call",
1050
1049
  name: execCanonicalToolName,
1051
1050
  callId,
1052
- input: happyProtocol.attachToolHappierMetaV2(inputs, {
1051
+ input: names.attachToolHappierMetaV2(inputs, {
1053
1052
  v: 2,
1054
1053
  protocol: "acp",
1055
1054
  provider: "gemini",
@@ -1067,12 +1066,12 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1067
1066
  const filesMsg = changeCount === 1 ? "1 file" : `${changeCount} files`;
1068
1067
  messageBuffer.addMessage(`Modifying ${filesMsg}...`, "tool");
1069
1068
  api.logger.debug(`[gemini] Patch apply begin: ${patchCallId}, files: ${changeCount}`);
1070
- const patchCanonicalToolName = happyProtocol.resolveCanonicalToolNameV2("GeminiPatch");
1069
+ const patchCanonicalToolName = names.resolveCanonicalToolNameV2("GeminiPatch");
1071
1070
  session.sendAgentMessage("gemini", {
1072
1071
  type: "tool-call",
1073
1072
  name: patchCanonicalToolName,
1074
1073
  callId: patchCallId,
1075
- input: happyProtocol.attachToolHappierMetaV2({
1074
+ input: names.attachToolHappierMetaV2({
1076
1075
  auto_approved,
1077
1076
  changes
1078
1077
  }, {
@@ -1100,7 +1099,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1100
1099
  session.sendAgentMessage("gemini", {
1101
1100
  type: "tool-result",
1102
1101
  callId: patchEndCallId,
1103
- output: happyProtocol.attachToolHappierMetaV2({
1102
+ output: names.attachToolHappierMetaV2({
1104
1103
  stdout,
1105
1104
  stderr,
1106
1105
  success
@@ -1109,7 +1108,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1109
1108
  protocol: "acp",
1110
1109
  provider: "gemini",
1111
1110
  rawToolName: "GeminiPatch",
1112
- canonicalToolName: happyProtocol.resolveCanonicalToolNameV2("GeminiPatch")
1111
+ canonicalToolName: names.resolveCanonicalToolNameV2("GeminiPatch")
1113
1112
  }),
1114
1113
  id: node_crypto.randomUUID(),
1115
1114
  isError: !success
@@ -1,12 +1,11 @@
1
1
  import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { l as logger, b as connectionState, A as ApiClient, i as isAuthenticationRequiredError } from './api-dwwHBzLc.mjs';
5
- import { readSettings } from './persistence-Dg-rxY2a.mjs';
6
- import { B as BasePermissionHandler, a as BaseReasoningProcessor, c as createSessionMetadata, s as setupOfflineReconnection } from './BaseReasoningProcessor-ClrT-x-H.mjs';
7
- import { i as initialMachineMetadata, n as notifyDaemonSessionStarted, g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-HyqLXzw-.mjs';
8
- import { M as MessageQueue2, h as hashObject, a as MessageBuffer, r as registerKillSessionHandler } from './registerKillSessionHandler-BAvk4GYO.mjs';
9
- import { attachToolHappierMetaV2, resolveCanonicalToolNameV2, inferToolResultError } from 'happy-protocol';
4
+ import { l as logger, b as connectionState, A as ApiClient, i as isAuthenticationRequiredError } from './api-D-uiH_TF.mjs';
5
+ import { readSettings } from './persistence-DiNg1DPF.mjs';
6
+ import { B as BasePermissionHandler, a as BaseReasoningProcessor, c as createSessionMetadata, s as setupOfflineReconnection, b as attachToolHappierMetaV2, r as resolveCanonicalToolNameV2, i as inferToolResultError } from './names-BjEof0E2.mjs';
7
+ import { i as initialMachineMetadata, n as notifyDaemonSessionStarted, g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-DhheEtRl.mjs';
8
+ import { M as MessageQueue2, h as hashObject, a as MessageBuffer, r as registerKillSessionHandler } from './registerKillSessionHandler-Cu9rHGsI.mjs';
10
9
  import 'axios';
11
10
  import 'chalk';
12
11
  import 'fs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "happy-imou-cloud",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "hicloud - Imou 企业定制版。关键是 happy!移动端远程 AI 编程工具,支持 Claude Code、Codex 和 Gemini CLI",
5
5
  "author": "long.zhu",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "// ==== TypeScript & Build ====": "",
44
44
  "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",
45
45
  "typecheck": "tsc --noEmit",
46
- "build": "shx rm -rf dist && npx tsc --noEmit && pkgroll",
46
+ "build": "node ./scripts/build.mjs",
47
47
  "// ==== Testing ====": "",
48
48
  "test": "yarn build && vitest run",
49
49
  "test:integration": "yarn build && vitest run --config vitest.integration.config.ts",
@@ -59,7 +59,7 @@
59
59
  "dev:local-server": "yarn build && tsx --env-file .env.dev-local-server src/index.ts",
60
60
  "dev:integration-test-env": "yarn build && tsx --env-file .env.integration-test src/index.ts",
61
61
  "// ==== Release ====": "",
62
- "prepublishOnly": "yarn release:smoke",
62
+ "prepublishOnly": "yarn release:smoke",
63
63
  "release": "yarn install && release-it",
64
64
  "release:smoke": "node ./scripts/release-smoke.mjs",
65
65
  "// ==== Dev/Stable Variant Management ====": "",
@@ -99,7 +99,6 @@
99
99
  "expo-server-sdk": "^3.15.0",
100
100
  "fastify": "^5.6.2",
101
101
  "fastify-type-provider-zod": "4.0.2",
102
- "happy-protocol": "0.1.0",
103
102
  "http-proxy": "^1.18.1",
104
103
  "http-proxy-middleware": "^3.0.5",
105
104
  "ink": "^6.5.1",
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import { existsSync, readFileSync, rmSync } from 'node:fs';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ const packageRoot = resolve(here, '..');
10
+ const workspaceRoot = resolve(packageRoot, '..', '..');
11
+ const packageJson = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8'));
12
+
13
+ function resolveTool(binName, packageSpecs) {
14
+ const suffix = process.platform === 'win32' ? '.cmd' : '';
15
+ const packageLocalBin = resolve(packageRoot, 'node_modules', '.bin', `${binName}${suffix}`);
16
+ const workspaceLocalBin = resolve(workspaceRoot, 'node_modules', '.bin', `${binName}${suffix}`);
17
+
18
+ if (existsSync(packageLocalBin)) {
19
+ return {
20
+ command: packageLocalBin,
21
+ prefixArgs: [],
22
+ };
23
+ }
24
+
25
+ if (existsSync(workspaceLocalBin)) {
26
+ return {
27
+ command: workspaceLocalBin,
28
+ prefixArgs: [],
29
+ };
30
+ }
31
+
32
+ return {
33
+ command: 'npx',
34
+ prefixArgs: ['-y', ...packageSpecs.flatMap((packageSpec) => ['-p', packageSpec]), binName],
35
+ };
36
+ }
37
+
38
+ function runStep(name, command, args) {
39
+ console.log(`\n[build] ${name}`);
40
+ console.log(`> ${command} ${args.join(' ')}`);
41
+
42
+ const result = spawnSync(command, args, {
43
+ cwd: packageRoot,
44
+ stdio: 'inherit',
45
+ shell: process.platform === 'win32',
46
+ env: process.env,
47
+ });
48
+
49
+ if (result.status !== 0) {
50
+ throw new Error(`[build] Step failed: ${name}`);
51
+ }
52
+ }
53
+
54
+ function runTool(name, tool, args) {
55
+ runStep(name, tool.command, [...tool.prefixArgs, ...args]);
56
+ }
57
+
58
+ const tsc = resolveTool('tsc', [`typescript@${packageJson.devDependencies.typescript}`]);
59
+ const pkgroll = resolveTool('pkgroll', [
60
+ `pkgroll@${packageJson.devDependencies.pkgroll}`,
61
+ `typescript@${packageJson.devDependencies.typescript}`,
62
+ ]);
63
+
64
+ rmSync(resolve(packageRoot, 'dist'), { recursive: true, force: true });
65
+ runTool('typecheck', tsc, ['--noEmit']);
66
+ runTool('bundle', pkgroll, []);
@@ -1,66 +1,202 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from 'node:child_process';
4
+ import { existsSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
4
6
  import { fileURLToPath } from 'node:url';
5
- import { dirname, resolve } from 'node:path';
7
+ import { dirname, join, resolve } from 'node:path';
6
8
 
7
9
  const here = dirname(fileURLToPath(import.meta.url));
8
10
  const packageRoot = resolve(here, '..');
11
+ const workspaceRoot = resolve(packageRoot, '..', '..');
12
+ const packageJson = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8'));
13
+
14
+ function resolveTool(binName, packageName) {
15
+ const suffix = process.platform === 'win32' ? '.cmd' : '';
16
+ const packageLocalBin = resolve(packageRoot, 'node_modules', '.bin', `${binName}${suffix}`);
17
+ const workspaceLocalBin = resolve(workspaceRoot, 'node_modules', '.bin', `${binName}${suffix}`);
18
+
19
+ if (existsSync(packageLocalBin)) {
20
+ return {
21
+ command: packageLocalBin,
22
+ prefixArgs: [],
23
+ };
24
+ }
25
+
26
+ if (existsSync(workspaceLocalBin)) {
27
+ return {
28
+ command: workspaceLocalBin,
29
+ prefixArgs: [],
30
+ };
31
+ }
32
+
33
+ const version =
34
+ packageJson.devDependencies?.[packageName]
35
+ ?? packageJson.dependencies?.[packageName];
36
+
37
+ return {
38
+ command: 'npx',
39
+ prefixArgs: ['-y', '-p', `${packageName}@${version}`, binName],
40
+ };
41
+ }
42
+
43
+ function shouldUseShell(command) {
44
+ if (process.platform !== 'win32') {
45
+ return false;
46
+ }
47
+
48
+ return !/\.exe$/i.test(command);
49
+ }
9
50
 
10
51
  function runStep(name, command, args, options = {}) {
11
52
  console.log(`\n[release-smoke] ${name}`);
12
53
  console.log(`> ${command} ${args.join(' ')}`);
13
-
54
+
14
55
  const result = spawnSync(command, args, {
15
56
  cwd: packageRoot,
16
57
  stdio: 'inherit',
17
- shell: process.platform === 'win32',
18
- env: process.env,
58
+ shell: shouldUseShell(command),
59
+ env: {
60
+ ...process.env,
61
+ NODE_ENV: 'development',
62
+ YARN_PRODUCTION: 'false',
63
+ npm_config_production: 'false',
64
+ },
65
+ ...options,
66
+ });
67
+
68
+ if (result.status !== 0) {
69
+ throw new Error(`[release-smoke] Step failed: ${name}`);
70
+ }
71
+ }
72
+
73
+ function runStepCapture(name, command, args, options = {}) {
74
+ console.log(`\n[release-smoke] ${name}`);
75
+ console.log(`> ${command} ${args.join(' ')}`);
76
+
77
+ const result = spawnSync(command, args, {
78
+ cwd: packageRoot,
79
+ stdio: 'pipe',
80
+ encoding: 'utf8',
81
+ shell: shouldUseShell(command),
82
+ env: {
83
+ ...process.env,
84
+ NODE_ENV: 'development',
85
+ YARN_PRODUCTION: 'false',
86
+ npm_config_production: 'false',
87
+ },
19
88
  ...options,
20
89
  });
21
90
 
22
91
  if (result.status !== 0) {
92
+ if (result.stdout) {
93
+ process.stdout.write(result.stdout);
94
+ }
95
+ if (result.stderr) {
96
+ process.stderr.write(result.stderr);
97
+ }
23
98
  throw new Error(`[release-smoke] Step failed: ${name}`);
24
99
  }
100
+
101
+ return result.stdout;
25
102
  }
26
103
 
27
- function shouldRunProviderSmoke(provider) {
28
- return process.env[`HAPPY_SMOKE_${provider.toUpperCase()}`] === '1';
104
+ function runToolStep(name, tool, args, options = {}) {
105
+ runStep(name, tool.command, [...tool.prefixArgs, ...args], options);
29
106
  }
30
107
 
108
+ function verifyPackedInstall() {
109
+ const tempRoot = mkdtempSync(join(tmpdir(), 'happy-cli-release-smoke-'));
110
+ let tarballPath = null;
111
+
112
+ try {
113
+ const packOutput = runStepCapture('pack tarball', 'npm', ['pack', '--json', '--ignore-scripts']);
114
+ const packResult = JSON.parse(packOutput);
115
+ const tarballFile = Array.isArray(packResult) ? packResult[0]?.filename : null;
116
+
117
+ if (typeof tarballFile !== 'string' || tarballFile.length === 0) {
118
+ throw new Error('[release-smoke] npm pack did not return a tarball filename');
119
+ }
120
+
121
+ tarballPath = resolve(packageRoot, tarballFile);
122
+
123
+ writeFileSync(
124
+ join(tempRoot, 'package.json'),
125
+ JSON.stringify({ private: true, name: 'happy-cli-release-smoke' }, null, 2)
126
+ );
127
+
128
+ runStep('install packed tarball', 'npm', [
129
+ 'install',
130
+ '--ignore-scripts',
131
+ '--no-audit',
132
+ '--fund=false',
133
+ tarballPath,
134
+ ], {
135
+ cwd: tempRoot,
136
+ });
137
+
138
+ runStep('run packed cli help', 'node', [
139
+ join(tempRoot, 'node_modules', 'happy-imou-cloud', 'bin', 'happy-cloud.mjs'),
140
+ '--help',
141
+ ], {
142
+ cwd: tempRoot,
143
+ });
144
+ } finally {
145
+ if (tarballPath) {
146
+ try {
147
+ unlinkSync(tarballPath);
148
+ } catch {}
149
+ }
150
+
151
+ try {
152
+ rmSync(tempRoot, { recursive: true, force: true });
153
+ } catch {}
154
+ }
155
+ }
156
+
157
+ function shouldRunProviderSmoke(provider) {
158
+ return process.env[`HAPPY_SMOKE_${provider.toUpperCase()}`] === '1';
159
+ }
160
+
31
161
  function main() {
32
- runStep('typecheck', 'yarn', ['tsc', '--noEmit']);
33
- runStep('unit runtime suite', 'yarn', [
34
- 'vitest',
162
+ const tsc = resolveTool('tsc', 'typescript');
163
+ const vitest = resolveTool('vitest', 'vitest');
164
+
165
+ runToolStep('typecheck', tsc, ['--noEmit']);
166
+ runToolStep('unit runtime suite', vitest, [
35
167
  'run',
168
+ 'src/agent/acp/AcpBackend.test.ts',
36
169
  'src/agent/acp/AcpBackend.startup.test.ts',
170
+ 'src/agent/acp/AcpBackend.waitForResponseComplete.test.ts',
171
+ 'src/agent/acp/AcpBackend.initDelay.test.ts',
37
172
  'src/agent/acp/acpSpawn.test.ts',
38
173
  'src/agent/acp/createAcpFilteredStdoutReadable.multiline.test.ts',
39
174
  'src/agent/acp/killProcessTree.test.ts',
40
- 'src/runtime/executeProvider.test.ts',
41
- 'src/runtime/command.test.ts',
42
- 'src/runtime/launch.test.ts',
43
- 'src/runtime/RuntimeShell.test.ts',
44
- 'src/runtime/createDefaultRuntimeShell.test.ts',
45
- 'src/security/signedTransport.test.ts',
46
- 'src/agent/initializeAgents.test.ts',
47
- 'src/agent/factories/factories.test.ts',
48
- 'src/packageContract.test.ts',
175
+ 'src/runtime/executeProvider.test.ts',
176
+ 'src/runtime/command.test.ts',
177
+ 'src/runtime/launch.test.ts',
178
+ 'src/runtime/RuntimeShell.test.ts',
179
+ 'src/runtime/createDefaultRuntimeShell.test.ts',
180
+ 'src/security/signedTransport.test.ts',
181
+ 'src/agent/initializeAgents.test.ts',
182
+ 'src/agent/factories/factories.test.ts',
183
+ 'src/packageContract.test.ts',
49
184
  ]);
50
185
  runStep('build', 'yarn', ['build']);
51
- runStep('runtime providers', 'yarn', ['tsx', 'src/index.ts', 'runtime', 'providers']);
52
- runStep('help', 'yarn', ['tsx', 'src/index.ts', '--help']);
186
+ runStep('runtime providers', 'node', ['./bin/happy-cloud.mjs', 'runtime', 'providers']);
187
+ runStep('help', 'node', ['./bin/happy-cloud.mjs', '--help']);
188
+ verifyPackedInstall();
53
189
 
54
190
  if (shouldRunProviderSmoke('cursor')) {
55
- runStep('cursor smoke', 'yarn', ['tsx', 'src/index.ts', 'cursor', 'release smoke']);
191
+ runStep('cursor smoke', 'node', ['./bin/happy-cloud.mjs', 'cursor', 'release smoke']);
56
192
  }
57
193
  }
58
-
59
- try {
60
- main();
61
- console.log('\n[release-smoke] All required steps passed');
62
- } catch (error) {
63
- const message = error instanceof Error ? error.message : String(error);
64
- console.error(`\n${message}`);
65
- process.exit(1);
66
- }
194
+
195
+ try {
196
+ main();
197
+ console.log('\n[release-smoke] All required steps passed');
198
+ } catch (error) {
199
+ const message = error instanceof Error ? error.message : String(error);
200
+ console.error(`\n${message}`);
201
+ process.exit(1);
202
+ }