helloloop 0.8.6 → 0.10.0

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 (52) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +230 -498
  4. package/hosts/claude/marketplace/plugins/helloloop/.claude-plugin/plugin.json +1 -1
  5. package/hosts/gemini/extension/gemini-extension.json +1 -1
  6. package/native/windows-hidden-shell-proxy/HelloLoopHiddenShellProxy.csproj +11 -0
  7. package/native/windows-hidden-shell-proxy/Program.cs +498 -0
  8. package/package.json +4 -2
  9. package/src/activity_projection.mjs +294 -0
  10. package/src/analyze_confirmation.mjs +3 -1
  11. package/src/analyzer.mjs +2 -1
  12. package/src/auto_execution_options.mjs +13 -0
  13. package/src/background_launch.mjs +73 -0
  14. package/src/cli.mjs +51 -1
  15. package/src/cli_analyze_command.mjs +12 -14
  16. package/src/cli_args.mjs +106 -32
  17. package/src/cli_command_handlers.mjs +73 -25
  18. package/src/cli_support.mjs +2 -0
  19. package/src/common.mjs +11 -0
  20. package/src/dashboard_command.mjs +371 -0
  21. package/src/dashboard_tui.mjs +289 -0
  22. package/src/dashboard_web.mjs +351 -0
  23. package/src/dashboard_web_client.mjs +167 -0
  24. package/src/dashboard_web_page.mjs +49 -0
  25. package/src/engine_event_parser_codex.mjs +167 -0
  26. package/src/engine_process_support.mjs +7 -2
  27. package/src/engine_selection.mjs +24 -0
  28. package/src/engine_selection_probe.mjs +10 -6
  29. package/src/engine_selection_settings.mjs +53 -44
  30. package/src/execution_interactivity.mjs +12 -0
  31. package/src/host_continuation.mjs +305 -0
  32. package/src/install_codex.mjs +20 -30
  33. package/src/install_shared.mjs +9 -0
  34. package/src/node_process_launch.mjs +28 -0
  35. package/src/process.mjs +2 -0
  36. package/src/runner_execute_task.mjs +15 -1
  37. package/src/runner_execution_support.mjs +69 -3
  38. package/src/runner_once.mjs +5 -0
  39. package/src/runner_status.mjs +72 -4
  40. package/src/runtime_engine_support.mjs +52 -5
  41. package/src/runtime_engine_task.mjs +7 -0
  42. package/src/runtime_settings.mjs +105 -0
  43. package/src/runtime_settings_loader.mjs +19 -0
  44. package/src/shell_invocation.mjs +227 -9
  45. package/src/supervisor_cli_support.mjs +49 -0
  46. package/src/supervisor_guardian.mjs +307 -0
  47. package/src/supervisor_runtime.mjs +142 -83
  48. package/src/supervisor_state.mjs +64 -0
  49. package/src/supervisor_watch.mjs +364 -0
  50. package/src/terminal_session_limits.mjs +1 -21
  51. package/src/windows_hidden_shell_proxy.mjs +405 -0
  52. package/src/workspace_registry.mjs +155 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.8.6",
3
+ "version": "0.10.0",
4
4
  "description": "HelloLoop 的 Claude Code 原生插件元数据,用于多 CLI 宿主分发。",
5
5
  "author": {
6
6
  "name": "HelloLoop"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.8.6",
3
+ "version": "0.10.0",
4
4
  "description": "HelloLoop 的 Gemini CLI 原生扩展,用于按开发文档接续推进项目开发。",
5
5
  "contextFileName": "GEMINI.md",
6
6
  "excludeTools": [
@@ -0,0 +1,11 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <OutputType>WinExe</OutputType>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ <AssemblyName>HelloLoopHiddenShellProxy</AssemblyName>
8
+ <RootNamespace>HelloLoopHiddenShellProxy</RootNamespace>
9
+ <UseAppHost>true</UseAppHost>
10
+ </PropertyGroup>
11
+ </Project>
@@ -0,0 +1,498 @@
1
+ using System;
2
+ using System.Collections;
3
+ using System.Collections.Generic;
4
+ using System.IO;
5
+ using Microsoft.Win32.SafeHandles;
6
+ using System.Reflection;
7
+ using System.Runtime.InteropServices;
8
+ using System.Text;
9
+
10
+ namespace HelloLoopHiddenShellProxy
11
+ {
12
+ internal static class Program
13
+ {
14
+ private const string RealPwshEnv = "HELLOLOOP_REAL_PWSH";
15
+ private const string RealPowerShellEnv = "HELLOLOOP_REAL_POWERSHELL";
16
+ private const string OriginalPathEnv = "HELLOLOOP_ORIGINAL_PATH";
17
+ private const string ProxyEnabledEnv = "HELLOLOOP_HIDDEN_SHELL_PROXY_ENABLED";
18
+ private const string ProxyTargetExeEnv = "HELLOLOOP_PROXY_TARGET_EXE";
19
+
20
+ private static readonly IntPtr InvalidHandleValue = new IntPtr(-1);
21
+
22
+ private const int StdInputHandle = -10;
23
+ private const int StdOutputHandle = -11;
24
+ private const int StdErrorHandle = -12;
25
+
26
+ private const uint DuplicateSameAccess = 0x00000002;
27
+ private const uint CreateNoWindow = 0x08000000;
28
+ private const uint CreateUnicodeEnvironment = 0x00000400;
29
+
30
+ private const int StartfUseShowWindow = 0x00000001;
31
+ private const int StartfUseStdHandles = 0x00000100;
32
+ private const short SwHide = 0;
33
+ private const uint Infinite = 0xFFFFFFFF;
34
+
35
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
36
+ private struct STARTUPINFO
37
+ {
38
+ public int cb;
39
+ public string lpReserved;
40
+ public string lpDesktop;
41
+ public string lpTitle;
42
+ public int dwX;
43
+ public int dwY;
44
+ public int dwXSize;
45
+ public int dwYSize;
46
+ public int dwXCountChars;
47
+ public int dwYCountChars;
48
+ public int dwFillAttribute;
49
+ public int dwFlags;
50
+ public short wShowWindow;
51
+ public short cbReserved2;
52
+ public IntPtr lpReserved2;
53
+ public IntPtr hStdInput;
54
+ public IntPtr hStdOutput;
55
+ public IntPtr hStdError;
56
+ }
57
+
58
+ [StructLayout(LayoutKind.Sequential)]
59
+ private struct PROCESS_INFORMATION
60
+ {
61
+ public IntPtr hProcess;
62
+ public IntPtr hThread;
63
+ public int dwProcessId;
64
+ public int dwThreadId;
65
+ }
66
+
67
+ private sealed class LaunchRequest
68
+ {
69
+ public LaunchRequest(string executable, IDictionary<string, string> environmentVariables)
70
+ {
71
+ Executable = executable ?? string.Empty;
72
+ EnvironmentVariables = environmentVariables ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
73
+ }
74
+
75
+ public string Executable { get; private set; }
76
+
77
+ public IDictionary<string, string> EnvironmentVariables { get; private set; }
78
+ }
79
+
80
+ [DllImport("kernel32.dll", SetLastError = true)]
81
+ private static extern IntPtr GetStdHandle(int handleId);
82
+
83
+ [DllImport("kernel32.dll", SetLastError = true)]
84
+ private static extern IntPtr GetCurrentProcess();
85
+
86
+ [DllImport("kernel32.dll", SetLastError = true)]
87
+ [return: MarshalAs(UnmanagedType.Bool)]
88
+ private static extern bool DuplicateHandle(
89
+ IntPtr hSourceProcessHandle,
90
+ IntPtr hSourceHandle,
91
+ IntPtr hTargetProcessHandle,
92
+ out IntPtr lpTargetHandle,
93
+ uint dwDesiredAccess,
94
+ [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
95
+ uint dwOptions);
96
+
97
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
98
+ [return: MarshalAs(UnmanagedType.Bool)]
99
+ private static extern bool CreateProcessW(
100
+ string lpApplicationName,
101
+ StringBuilder lpCommandLine,
102
+ IntPtr lpProcessAttributes,
103
+ IntPtr lpThreadAttributes,
104
+ [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
105
+ uint dwCreationFlags,
106
+ IntPtr lpEnvironment,
107
+ string lpCurrentDirectory,
108
+ ref STARTUPINFO lpStartupInfo,
109
+ out PROCESS_INFORMATION lpProcessInformation);
110
+
111
+ [DllImport("kernel32.dll", SetLastError = true)]
112
+ private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
113
+
114
+ [DllImport("kernel32.dll", SetLastError = true)]
115
+ [return: MarshalAs(UnmanagedType.Bool)]
116
+ private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
117
+
118
+ [DllImport("kernel32.dll", SetLastError = true)]
119
+ [return: MarshalAs(UnmanagedType.Bool)]
120
+ private static extern bool CloseHandle(IntPtr hObject);
121
+
122
+ private static int Main(string[] args)
123
+ {
124
+ try
125
+ {
126
+ var request = ResolveLaunchRequest();
127
+ if (string.IsNullOrWhiteSpace(request.Executable) || !File.Exists(request.Executable))
128
+ {
129
+ WriteErrorLine("[HelloLoop hidden-shell-proxy] 未找到真实可执行文件,可检查 HELLOLOOP_PROXY_TARGET_EXE / HELLOLOOP_REAL_PWSH / HELLOLOOP_REAL_POWERSHELL。");
130
+ return 127;
131
+ }
132
+
133
+ return LaunchHiddenProcess(request, args ?? new string[0]);
134
+ }
135
+ catch (Exception ex)
136
+ {
137
+ WriteErrorLine(string.Format("[HelloLoop hidden-shell-proxy] {0}", ex.Message));
138
+ return 1;
139
+ }
140
+ }
141
+
142
+ private static int LaunchHiddenProcess(LaunchRequest request, string[] args)
143
+ {
144
+ var startupInfo = new STARTUPINFO();
145
+ startupInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
146
+ startupInfo.dwFlags = StartfUseShowWindow;
147
+ startupInfo.wShowWindow = SwHide;
148
+
149
+ var duplicatedHandles = new List<IntPtr>();
150
+ ConfigureStandardHandles(ref startupInfo, duplicatedHandles);
151
+
152
+ var processInfo = new PROCESS_INFORMATION();
153
+ var environmentBlock = BuildEnvironmentBlock(request.EnvironmentVariables);
154
+ GCHandle pinnedEnvironment = default(GCHandle);
155
+ IntPtr environmentPointer = IntPtr.Zero;
156
+
157
+ try
158
+ {
159
+ if (environmentBlock != null && environmentBlock.Length > 0)
160
+ {
161
+ pinnedEnvironment = GCHandle.Alloc(environmentBlock, GCHandleType.Pinned);
162
+ environmentPointer = pinnedEnvironment.AddrOfPinnedObject();
163
+ }
164
+
165
+ var commandLine = new StringBuilder(BuildCommandLine(request.Executable, args));
166
+ var shouldInheritHandles = (startupInfo.dwFlags & StartfUseStdHandles) == StartfUseStdHandles;
167
+ var created = CreateProcessW(
168
+ request.Executable,
169
+ commandLine,
170
+ IntPtr.Zero,
171
+ IntPtr.Zero,
172
+ shouldInheritHandles,
173
+ CreateNoWindow | CreateUnicodeEnvironment,
174
+ environmentPointer,
175
+ null,
176
+ ref startupInfo,
177
+ out processInfo);
178
+
179
+ if (!created)
180
+ {
181
+ throw new InvalidOperationException(
182
+ string.Format("启动真实进程失败:{0}(Win32Error={1})", request.Executable, Marshal.GetLastWin32Error()));
183
+ }
184
+
185
+ WaitForSingleObject(processInfo.hProcess, Infinite);
186
+
187
+ uint exitCode;
188
+ if (!GetExitCodeProcess(processInfo.hProcess, out exitCode))
189
+ {
190
+ throw new InvalidOperationException(
191
+ string.Format("读取真实进程退出码失败(Win32Error={0})。", Marshal.GetLastWin32Error()));
192
+ }
193
+
194
+ return unchecked((int)exitCode);
195
+ }
196
+ finally
197
+ {
198
+ if (pinnedEnvironment.IsAllocated)
199
+ {
200
+ pinnedEnvironment.Free();
201
+ }
202
+
203
+ CloseHandleIfNeeded(processInfo.hThread);
204
+ CloseHandleIfNeeded(processInfo.hProcess);
205
+
206
+ foreach (var handle in duplicatedHandles)
207
+ {
208
+ CloseHandleIfNeeded(handle);
209
+ }
210
+ }
211
+ }
212
+
213
+ private static void ConfigureStandardHandles(ref STARTUPINFO startupInfo, ICollection<IntPtr> duplicatedHandles)
214
+ {
215
+ var stdin = DuplicateStandardHandle(StdInputHandle);
216
+ var stdout = DuplicateStandardHandle(StdOutputHandle);
217
+ var stderr = DuplicateStandardHandle(StdErrorHandle);
218
+
219
+ if (IsValidHandle(stdin) && IsValidHandle(stdout) && IsValidHandle(stderr))
220
+ {
221
+ startupInfo.dwFlags |= StartfUseStdHandles;
222
+ startupInfo.hStdInput = stdin;
223
+ startupInfo.hStdOutput = stdout;
224
+ startupInfo.hStdError = stderr;
225
+ duplicatedHandles.Add(stdin);
226
+ duplicatedHandles.Add(stdout);
227
+ duplicatedHandles.Add(stderr);
228
+ return;
229
+ }
230
+
231
+ CloseHandleIfNeeded(stdin);
232
+ CloseHandleIfNeeded(stdout);
233
+ CloseHandleIfNeeded(stderr);
234
+ }
235
+
236
+ private static IntPtr DuplicateStandardHandle(int handleId)
237
+ {
238
+ var source = GetStdHandle(handleId);
239
+ if (!IsValidHandle(source))
240
+ {
241
+ return IntPtr.Zero;
242
+ }
243
+
244
+ IntPtr duplicated;
245
+ var duplicatedOk = DuplicateHandle(
246
+ GetCurrentProcess(),
247
+ source,
248
+ GetCurrentProcess(),
249
+ out duplicated,
250
+ 0,
251
+ true,
252
+ DuplicateSameAccess);
253
+
254
+ return duplicatedOk ? duplicated : IntPtr.Zero;
255
+ }
256
+
257
+ private static bool IsValidHandle(IntPtr handle)
258
+ {
259
+ return handle != IntPtr.Zero && handle != InvalidHandleValue;
260
+ }
261
+
262
+ private static void CloseHandleIfNeeded(IntPtr handle)
263
+ {
264
+ if (IsValidHandle(handle))
265
+ {
266
+ CloseHandle(handle);
267
+ }
268
+ }
269
+
270
+ private static LaunchRequest ResolveLaunchRequest()
271
+ {
272
+ var explicitTarget = Environment.GetEnvironmentVariable(ProxyTargetExeEnv);
273
+ if (IsUsableExecutable(explicitTarget))
274
+ {
275
+ return new LaunchRequest(Path.GetFullPath(explicitTarget), BuildLaunchEnvironment());
276
+ }
277
+
278
+ var targetShell = ResolveTargetShell();
279
+ return new LaunchRequest(targetShell, BuildLaunchEnvironment());
280
+ }
281
+
282
+ private static IDictionary<string, string> BuildLaunchEnvironment()
283
+ {
284
+ var environment = CaptureCurrentEnvironment();
285
+ var originalPath = Environment.GetEnvironmentVariable(OriginalPathEnv);
286
+ if (!string.IsNullOrWhiteSpace(originalPath))
287
+ {
288
+ environment["PATH"] = originalPath;
289
+ }
290
+
291
+ environment.Remove(RealPwshEnv);
292
+ environment.Remove(RealPowerShellEnv);
293
+ environment.Remove(OriginalPathEnv);
294
+ environment.Remove(ProxyEnabledEnv);
295
+ environment.Remove(ProxyTargetExeEnv);
296
+ return environment;
297
+ }
298
+
299
+ private static Dictionary<string, string> CaptureCurrentEnvironment()
300
+ {
301
+ var environment = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
302
+ foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables())
303
+ {
304
+ var key = Convert.ToString(entry.Key);
305
+ if (string.IsNullOrWhiteSpace(key))
306
+ {
307
+ continue;
308
+ }
309
+
310
+ environment[key] = Convert.ToString(entry.Value) ?? string.Empty;
311
+ }
312
+ return environment;
313
+ }
314
+
315
+ private static byte[] BuildEnvironmentBlock(IDictionary<string, string> environment)
316
+ {
317
+ if (environment == null || environment.Count == 0)
318
+ {
319
+ return null;
320
+ }
321
+
322
+ var keys = new List<string>(environment.Keys);
323
+ keys.Sort(StringComparer.OrdinalIgnoreCase);
324
+
325
+ var builder = new StringBuilder();
326
+ foreach (var key in keys)
327
+ {
328
+ builder.Append(key);
329
+ builder.Append('=');
330
+ builder.Append(environment[key] ?? string.Empty);
331
+ builder.Append('\0');
332
+ }
333
+ builder.Append('\0');
334
+ return Encoding.Unicode.GetBytes(builder.ToString());
335
+ }
336
+
337
+ private static string BuildCommandLine(string executable, IEnumerable<string> args)
338
+ {
339
+ var builder = new StringBuilder();
340
+ builder.Append(QuoteArgument(executable));
341
+
342
+ foreach (var arg in args)
343
+ {
344
+ builder.Append(' ');
345
+ builder.Append(QuoteArgument(arg ?? string.Empty));
346
+ }
347
+
348
+ return builder.ToString();
349
+ }
350
+
351
+ private static string QuoteArgument(string argument)
352
+ {
353
+ if (string.IsNullOrEmpty(argument))
354
+ {
355
+ return "\"\"";
356
+ }
357
+
358
+ var needsQuotes = argument.IndexOfAny(new[] { ' ', '\t', '"' }) >= 0;
359
+ if (!needsQuotes)
360
+ {
361
+ return argument;
362
+ }
363
+
364
+ var builder = new StringBuilder();
365
+ builder.Append('"');
366
+ var backslashCount = 0;
367
+
368
+ foreach (var character in argument)
369
+ {
370
+ if (character == '\\')
371
+ {
372
+ backslashCount++;
373
+ continue;
374
+ }
375
+
376
+ if (character == '"')
377
+ {
378
+ builder.Append('\\', (backslashCount * 2) + 1);
379
+ builder.Append('"');
380
+ backslashCount = 0;
381
+ continue;
382
+ }
383
+
384
+ if (backslashCount > 0)
385
+ {
386
+ builder.Append('\\', backslashCount);
387
+ backslashCount = 0;
388
+ }
389
+
390
+ builder.Append(character);
391
+ }
392
+
393
+ if (backslashCount > 0)
394
+ {
395
+ builder.Append('\\', backslashCount * 2);
396
+ }
397
+
398
+ builder.Append('"');
399
+ return builder.ToString();
400
+ }
401
+
402
+ private static string ResolveTargetShell()
403
+ {
404
+ var assemblyPath = Assembly.GetEntryAssembly() != null
405
+ ? Assembly.GetEntryAssembly().Location
406
+ : AppDomain.CurrentDomain.BaseDirectory;
407
+ var requestedName = Path.GetFileName(assemblyPath).ToLowerInvariant();
408
+ var wantsPwsh = requestedName.StartsWith("pwsh", StringComparison.OrdinalIgnoreCase);
409
+ var explicitTarget = Environment.GetEnvironmentVariable(wantsPwsh ? RealPwshEnv : RealPowerShellEnv);
410
+
411
+ if (IsUsableExecutable(explicitTarget))
412
+ {
413
+ return Path.GetFullPath(explicitTarget);
414
+ }
415
+
416
+ var searchName = wantsPwsh ? "pwsh.exe" : "powershell.exe";
417
+ var fromOriginalPath = FindFromOriginalPath(searchName);
418
+ if (IsUsableExecutable(fromOriginalPath))
419
+ {
420
+ return Path.GetFullPath(fromOriginalPath);
421
+ }
422
+
423
+ var fallback = wantsPwsh
424
+ ? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "PowerShell", "7", "pwsh.exe")
425
+ : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
426
+ return IsUsableExecutable(fallback) ? Path.GetFullPath(fallback) : string.Empty;
427
+ }
428
+
429
+ private static bool IsUsableExecutable(string candidate)
430
+ {
431
+ if (string.IsNullOrWhiteSpace(candidate))
432
+ {
433
+ return false;
434
+ }
435
+
436
+ var fullCandidate = Path.GetFullPath(candidate);
437
+ var selfPath = Assembly.GetEntryAssembly() != null
438
+ ? Path.GetFullPath(Assembly.GetEntryAssembly().Location)
439
+ : string.Empty;
440
+ return !string.Equals(fullCandidate, selfPath, StringComparison.OrdinalIgnoreCase) && File.Exists(fullCandidate);
441
+ }
442
+
443
+ private static string FindFromOriginalPath(string executableName)
444
+ {
445
+ var originalPath = Environment.GetEnvironmentVariable(OriginalPathEnv);
446
+ if (string.IsNullOrWhiteSpace(originalPath))
447
+ {
448
+ return null;
449
+ }
450
+
451
+ var directories = originalPath.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
452
+ foreach (var directory in directories)
453
+ {
454
+ var cleanDirectory = directory.Trim().Trim('"');
455
+ if (string.IsNullOrWhiteSpace(cleanDirectory))
456
+ {
457
+ continue;
458
+ }
459
+
460
+ var candidate = Path.Combine(cleanDirectory, executableName);
461
+ if (IsUsableExecutable(candidate))
462
+ {
463
+ return candidate;
464
+ }
465
+ }
466
+
467
+ return null;
468
+ }
469
+
470
+ private static Stream CreateStandardStream(int handleId, FileAccess access)
471
+ {
472
+ var handle = GetStdHandle(handleId);
473
+ if (!IsValidHandle(handle))
474
+ {
475
+ return Stream.Null;
476
+ }
477
+
478
+ return new FileStream(new SafeFileHandle(handle, false), access);
479
+ }
480
+
481
+ private static void WriteErrorLine(string message)
482
+ {
483
+ using (var error = CreateStandardStream(StdErrorHandle, FileAccess.Write))
484
+ {
485
+ if (ReferenceEquals(error, Stream.Null))
486
+ {
487
+ return;
488
+ }
489
+
490
+ using (var writer = new StreamWriter(error, Encoding.UTF8, 1024, true))
491
+ {
492
+ writer.AutoFlush = true;
493
+ writer.WriteLine(message);
494
+ }
495
+ }
496
+ }
497
+ }
498
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloloop",
3
- "version": "0.8.6",
3
+ "version": "0.10.0",
4
4
  "description": "面向 Codex CLI、Claude Code、Gemini CLI 的多宿主开发工作流插件",
5
5
  "author": "HelloLoop",
6
6
  "license": "Apache-2.0",
@@ -23,6 +23,7 @@
23
23
  "README.md",
24
24
  "bin",
25
25
  "hosts",
26
+ "native",
26
27
  "package.json",
27
28
  "scripts",
28
29
  "skills",
@@ -30,7 +31,8 @@
30
31
  "templates"
31
32
  ],
32
33
  "scripts": {
33
- "test": "node --test tests/analyze_cli.test.mjs tests/analyze_cli_path_resolution.test.mjs tests/analyze_intent_cli.test.mjs tests/analyze_runtime_failure.test.mjs tests/output_schema_contract.test.mjs tests/engine_process_support.test.mjs tests/engine_selection_cli.test.mjs tests/cli_surface.test.mjs tests/cli_doctor_surface.test.mjs tests/host_lifecycle_integrity.test.mjs tests/user_settings_lifecycle.test.mjs tests/host_single_host_integrity.test.mjs tests/install_script.test.mjs tests/mainline_continuation.test.mjs tests/multi_host_runtime.test.mjs tests/multi_host_runtime_recovery.test.mjs tests/process_shell.test.mjs tests/prompt_guardrails.test.mjs tests/ralph_loop.test.mjs tests/runtime_recovery.test.mjs tests/plugin_bundle.test.mjs tests/supervisor_runtime.test.mjs tests/terminal_session_limits.test.mjs"
34
+ "test": "node -e \"import('./src/cli.mjs').then(() => console.log('HelloLoop CLI import ok'))\"",
35
+ "test:repo": "node --test tests/output_schema_contract.test.mjs tests/cli_surface.test.mjs tests/cli_doctor_surface.test.mjs tests/prompt_guardrails.test.mjs tests/runtime_recovery.test.mjs tests/terminal_session_limits.test.mjs"
34
36
  },
35
37
  "engines": {
36
38
  "node": ">=20"