@nextclaw/service 0.1.1

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 (242) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli/commands/agent/agent-runtime.utils.d.ts +15 -0
  3. package/dist/cli/commands/agent/agent-runtime.utils.js +85 -0
  4. package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +21 -0
  5. package/dist/cli/commands/agent/cli-agent-runner.utils.js +89 -0
  6. package/dist/cli/commands/agent/index.d.ts +3 -0
  7. package/dist/cli/commands/agent/index.js +3 -0
  8. package/dist/cli/commands/agent/services/agent-commands.service.d.ts +17 -0
  9. package/dist/cli/commands/agent/services/agent-commands.service.js +112 -0
  10. package/dist/cli/commands/companion/index.d.ts +15 -0
  11. package/dist/cli/commands/companion/index.js +24 -0
  12. package/dist/cli/commands/companion/services/companion-process.service.d.ts +17 -0
  13. package/dist/cli/commands/companion/services/companion-process.service.js +49 -0
  14. package/dist/cli/commands/config/index.d.ts +2 -0
  15. package/dist/cli/commands/config/index.js +2 -0
  16. package/dist/cli/commands/config/services/config-commands.service.d.ts +18 -0
  17. package/dist/cli/commands/config/services/config-commands.service.js +133 -0
  18. package/dist/cli/commands/cron/index.d.ts +2 -0
  19. package/dist/cli/commands/cron/index.js +2 -0
  20. package/dist/cli/commands/cron/services/cron-commands.service.d.ts +22 -0
  21. package/dist/cli/commands/cron/services/cron-commands.service.js +107 -0
  22. package/dist/cli/commands/cron/services/cron-local.service.d.ts +25 -0
  23. package/dist/cli/commands/cron/services/cron-local.service.js +95 -0
  24. package/dist/cli/commands/cron/utils/cron-job.utils.d.ts +31 -0
  25. package/dist/cli/commands/cron/utils/cron-job.utils.js +15 -0
  26. package/dist/cli/commands/diagnostics/index.d.ts +2 -0
  27. package/dist/cli/commands/diagnostics/index.js +2 -0
  28. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.d.ts +22 -0
  29. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.js +319 -0
  30. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.d.ts +23 -0
  31. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.js +66 -0
  32. package/dist/cli/commands/gateway/index.d.ts +14 -0
  33. package/dist/cli/commands/gateway/index.js +15 -0
  34. package/dist/cli/commands/logs/index.d.ts +12 -0
  35. package/dist/cli/commands/logs/index.js +29 -0
  36. package/dist/cli/commands/mcp/index.d.ts +14 -0
  37. package/dist/cli/commands/mcp/index.js +193 -0
  38. package/dist/cli/commands/restart/index.d.ts +20 -0
  39. package/dist/cli/commands/restart/index.js +88 -0
  40. package/dist/cli/commands/secrets/index.d.ts +22 -0
  41. package/dist/cli/commands/secrets/index.js +280 -0
  42. package/dist/cli/commands/serve/index.d.ts +14 -0
  43. package/dist/cli/commands/serve/index.js +19 -0
  44. package/dist/cli/commands/skills/index.d.ts +26 -0
  45. package/dist/cli/commands/skills/index.js +147 -0
  46. package/dist/cli/commands/skills/marketplace-client.d.ts +31 -0
  47. package/dist/cli/commands/skills/marketplace-client.js +84 -0
  48. package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +25 -0
  49. package/dist/cli/commands/skills/marketplace-command-options.utils.js +31 -0
  50. package/dist/cli/commands/skills/marketplace-identity.utils.d.ts +14 -0
  51. package/dist/cli/commands/skills/marketplace-identity.utils.js +77 -0
  52. package/dist/cli/commands/skills/marketplace-network-retry.d.ts +4 -0
  53. package/dist/cli/commands/skills/marketplace-network-retry.js +32 -0
  54. package/dist/cli/commands/skills/marketplace.metadata.d.ts +29 -0
  55. package/dist/cli/commands/skills/marketplace.metadata.js +158 -0
  56. package/dist/cli/commands/skills/marketplace.service.d.ts +46 -0
  57. package/dist/cli/commands/skills/marketplace.service.js +238 -0
  58. package/dist/cli/commands/skills/skills-query.service.d.ts +141 -0
  59. package/dist/cli/commands/skills/skills-query.service.js +212 -0
  60. package/dist/cli/commands/start/index.d.ts +18 -0
  61. package/dist/cli/commands/start/index.js +25 -0
  62. package/dist/cli/commands/stop/index.d.ts +12 -0
  63. package/dist/cli/commands/stop/index.js +11 -0
  64. package/dist/cli/commands/ui/index.d.ts +14 -0
  65. package/dist/cli/commands/ui/index.js +17 -0
  66. package/dist/cli/commands/usage/index.d.ts +2 -0
  67. package/dist/cli/commands/usage/index.js +2 -0
  68. package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +22 -0
  69. package/dist/cli/commands/usage/services/llm-usage-command.service.js +160 -0
  70. package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +43 -0
  71. package/dist/cli/commands/usage/services/llm-usage-query.service.js +85 -0
  72. package/dist/commands/channel/channel-config-view.d.ts +7 -0
  73. package/dist/commands/channel/channel-config-view.js +7 -0
  74. package/dist/commands/channel/index.d.ts +28 -0
  75. package/dist/commands/channel/index.js +224 -0
  76. package/dist/commands/platform-auth/index.d.ts +2 -0
  77. package/dist/commands/platform-auth/index.js +2 -0
  78. package/dist/commands/platform-auth/services/account-status.service.d.ts +18 -0
  79. package/dist/commands/platform-auth/services/account-status.service.js +34 -0
  80. package/dist/commands/platform-auth/services/platform-auth-commands.service.d.ts +77 -0
  81. package/dist/commands/platform-auth/services/platform-auth-commands.service.js +295 -0
  82. package/dist/commands/platform-auth/utils/payload.utils.d.ts +28 -0
  83. package/dist/commands/platform-auth/utils/payload.utils.js +87 -0
  84. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +18 -0
  85. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +111 -0
  86. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.d.ts +9 -0
  87. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.js +183 -0
  88. package/dist/commands/plugin/index.d.ts +30 -0
  89. package/dist/commands/plugin/index.js +266 -0
  90. package/dist/commands/plugin/plugin-command-utils.d.ts +13 -0
  91. package/dist/commands/plugin/plugin-command-utils.js +37 -0
  92. package/dist/commands/plugin/plugin-extension-registry.d.ts +10 -0
  93. package/dist/commands/plugin/plugin-extension-registry.js +35 -0
  94. package/dist/commands/plugin/plugin-mutation-actions.d.ts +15 -0
  95. package/dist/commands/plugin/plugin-mutation-actions.js +162 -0
  96. package/dist/commands/plugin/plugin-registry-loader.d.ts +15 -0
  97. package/dist/commands/plugin/plugin-registry-loader.js +43 -0
  98. package/dist/commands/plugin/plugin-reload.d.ts +13 -0
  99. package/dist/commands/plugin/plugin-reload.js +42 -0
  100. package/dist/commands/remote/index.d.ts +47 -0
  101. package/dist/commands/remote/index.js +174 -0
  102. package/dist/commands/remote/services/remote-access-host.service.d.ts +41 -0
  103. package/dist/commands/remote/services/remote-access-host.service.js +126 -0
  104. package/dist/commands/remote/services/remote-runtime-support.service.d.ts +15 -0
  105. package/dist/commands/remote/services/remote-runtime-support.service.js +79 -0
  106. package/dist/commands/remote/services/remote-service-control.service.d.ts +33 -0
  107. package/dist/commands/remote/services/remote-service-control.service.js +188 -0
  108. package/dist/commands/remote/utils/platform-api-base.utils.d.ts +14 -0
  109. package/dist/commands/remote/utils/platform-api-base.utils.js +39 -0
  110. package/dist/commands/service/index.d.ts +16 -0
  111. package/dist/commands/service/index.js +31 -0
  112. package/dist/commands/service/services/autostart/host-autostart-command.service.d.ts +29 -0
  113. package/dist/commands/service/services/autostart/host-autostart-command.service.js +158 -0
  114. package/dist/commands/service/services/autostart/host-autostart-runtime.service.d.ts +23 -0
  115. package/dist/commands/service/services/autostart/host-autostart-runtime.service.js +53 -0
  116. package/dist/commands/service/services/autostart/host-autostart.service.d.ts +41 -0
  117. package/dist/commands/service/services/autostart/host-autostart.service.js +48 -0
  118. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.d.ts +48 -0
  119. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +433 -0
  120. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.d.ts +54 -0
  121. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +405 -0
  122. package/dist/commands/service/services/autostart/windows-task-autostart.service.d.ts +54 -0
  123. package/dist/commands/service/services/autostart/windows-task-autostart.service.js +403 -0
  124. package/dist/commands/service/types/autostart/host-autostart.types.d.ts +64 -0
  125. package/dist/commands/service/types/autostart/host-autostart.types.js +1 -0
  126. package/dist/index.d.ts +4 -0
  127. package/dist/index.js +3 -0
  128. package/dist/launcher/npm-runtime-bundle-layout.store.d.ts +23 -0
  129. package/dist/launcher/npm-runtime-bundle-layout.store.js +37 -0
  130. package/dist/launcher/npm-runtime-bundle-manifest.service.d.ts +9 -0
  131. package/dist/launcher/npm-runtime-bundle-manifest.service.js +39 -0
  132. package/dist/launcher/npm-runtime-bundle.service.d.ts +47 -0
  133. package/dist/launcher/npm-runtime-bundle.service.js +150 -0
  134. package/dist/launcher/npm-runtime-bundle.types.d.ts +49 -0
  135. package/dist/launcher/npm-runtime-bundle.types.js +1 -0
  136. package/dist/launcher/npm-runtime-launcher.service.d.ts +19 -0
  137. package/dist/launcher/npm-runtime-launcher.service.js +57 -0
  138. package/dist/launcher/npm-runtime-update-command.service.d.ts +12 -0
  139. package/dist/launcher/npm-runtime-update-command.service.js +87 -0
  140. package/dist/launcher/npm-runtime-update-source.service.d.ts +19 -0
  141. package/dist/launcher/npm-runtime-update-source.service.js +57 -0
  142. package/dist/launcher/npm-runtime-update-state.store.d.ts +17 -0
  143. package/dist/launcher/npm-runtime-update-state.store.js +92 -0
  144. package/dist/launcher/npm-runtime-update.manager.d.ts +42 -0
  145. package/dist/launcher/npm-runtime-update.manager.js +179 -0
  146. package/dist/launcher/npm-runtime-update.service.d.ts +54 -0
  147. package/dist/launcher/npm-runtime-update.service.js +183 -0
  148. package/dist/service-runtime.service.d.ts +91 -0
  149. package/dist/service-runtime.service.js +392 -0
  150. package/dist/shared/controllers/gateway.controller.d.ts +61 -0
  151. package/dist/shared/controllers/gateway.controller.js +318 -0
  152. package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +56 -0
  153. package/dist/shared/services/extensions/extension-lifecycle.service.js +143 -0
  154. package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +51 -0
  155. package/dist/shared/services/extensions/service-extension-runtime.service.js +338 -0
  156. package/dist/shared/services/gateway/cron-job-handler.service.d.ts +26 -0
  157. package/dist/shared/services/gateway/cron-job-handler.service.js +100 -0
  158. package/dist/shared/services/gateway/gateway-restart-wake.service.d.ts +12 -0
  159. package/dist/shared/services/gateway/gateway-restart-wake.service.js +91 -0
  160. package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +37 -0
  161. package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +218 -0
  162. package/dist/shared/services/gateway/managers/gateway-remote.manager.d.ts +20 -0
  163. package/dist/shared/services/gateway/managers/gateway-remote.manager.js +25 -0
  164. package/dist/shared/services/gateway/nextclaw-app.service.d.ts +22 -0
  165. package/dist/shared/services/gateway/nextclaw-app.service.js +53 -0
  166. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +89 -0
  167. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +337 -0
  168. package/dist/shared/services/gateway/service-bootstrap-status.d.ts +33 -0
  169. package/dist/shared/services/gateway/service-bootstrap-status.js +152 -0
  170. package/dist/shared/services/gateway/service-startup-support.service.d.ts +42 -0
  171. package/dist/shared/services/gateway/service-startup-support.service.js +96 -0
  172. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.d.ts +9 -0
  173. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js +10 -0
  174. package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts +31 -0
  175. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +99 -0
  176. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.d.ts +39 -0
  177. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.js +67 -0
  178. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.d.ts +24 -0
  179. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.js +117 -0
  180. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.d.ts +6 -0
  181. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +96 -0
  182. package/dist/shared/services/restart/restart-coordinator.service.d.ts +30 -0
  183. package/dist/shared/services/restart/restart-coordinator.service.js +51 -0
  184. package/dist/shared/services/restart/restart-sentinel.service.d.ts +39 -0
  185. package/dist/shared/services/restart/restart-sentinel.service.js +88 -0
  186. package/dist/shared/services/restart/runtime-restart-request.service.d.ts +24 -0
  187. package/dist/shared/services/restart/runtime-restart-request.service.js +42 -0
  188. package/dist/shared/services/runtime/runtime-command.service.d.ts +37 -0
  189. package/dist/shared/services/runtime/runtime-command.service.js +163 -0
  190. package/dist/shared/services/runtime/runtime-config-init.service.d.ts +4 -0
  191. package/dist/shared/services/runtime/runtime-config-init.service.js +10 -0
  192. package/dist/shared/services/runtime/service-managed-startup.service.d.ts +146 -0
  193. package/dist/shared/services/runtime/service-managed-startup.service.js +426 -0
  194. package/dist/shared/services/runtime/service-remote-runtime.service.d.ts +53 -0
  195. package/dist/shared/services/runtime/service-remote-runtime.service.js +173 -0
  196. package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +12 -0
  197. package/dist/shared/services/runtime/utils/skills-loader.utils.js +9 -0
  198. package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +14 -0
  199. package/dist/shared/services/session/service-deferred-ncp-agent.service.js +85 -0
  200. package/dist/shared/services/ui/companion-runtime.service.d.ts +33 -0
  201. package/dist/shared/services/ui/companion-runtime.service.js +145 -0
  202. package/dist/shared/services/ui/local-ui-discovery.service.d.ts +19 -0
  203. package/dist/shared/services/ui/local-ui-discovery.service.js +41 -0
  204. package/dist/shared/services/ui/npm-runtime-update-host.service.d.ts +40 -0
  205. package/dist/shared/services/ui/npm-runtime-update-host.service.js +181 -0
  206. package/dist/shared/services/ui/runtime-control-host.service.d.ts +28 -0
  207. package/dist/shared/services/ui/runtime-control-host.service.js +89 -0
  208. package/dist/shared/services/ui/service-remote-access.service.d.ts +25 -0
  209. package/dist/shared/services/ui/service-remote-access.service.js +38 -0
  210. package/dist/shared/services/ui/ui-bridge-api.service.d.ts +16 -0
  211. package/dist/shared/services/ui/ui-bridge-api.service.js +43 -0
  212. package/dist/shared/services/workspace/workspace-manager.service.d.ts +19 -0
  213. package/dist/shared/services/workspace/workspace-manager.service.js +135 -0
  214. package/dist/shared/stores/companion-runtime.store.d.ts +15 -0
  215. package/dist/shared/stores/companion-runtime.store.js +27 -0
  216. package/dist/shared/stores/local-ui-runtime.store.d.ts +25 -0
  217. package/dist/shared/stores/local-ui-runtime.store.js +54 -0
  218. package/dist/shared/stores/managed-service-state.store.d.ts +28 -0
  219. package/dist/shared/stores/managed-service-state.store.js +38 -0
  220. package/dist/shared/stores/pending-restart.store.d.ts +21 -0
  221. package/dist/shared/stores/pending-restart.store.js +35 -0
  222. package/dist/shared/types/cli.types.d.ts +295 -0
  223. package/dist/shared/types/cli.types.js +1 -0
  224. package/dist/shared/utils/cli.utils.d.ts +34 -0
  225. package/dist/shared/utils/cli.utils.js +262 -0
  226. package/dist/shared/utils/config-path.d.ts +15 -0
  227. package/dist/shared/utils/config-path.js +167 -0
  228. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.d.ts +16 -0
  229. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.js +46 -0
  230. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts +9 -0
  231. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js +33 -0
  232. package/dist/shared/utils/package/package-manifest.utils.d.ts +8 -0
  233. package/dist/shared/utils/package/package-manifest.utils.js +48 -0
  234. package/dist/shared/utils/runtime-helpers.d.ts +14 -0
  235. package/dist/shared/utils/runtime-helpers.js +26 -0
  236. package/dist/shared/utils/service-port-probe.utils.d.ts +41 -0
  237. package/dist/shared/utils/service-port-probe.utils.js +164 -0
  238. package/dist/shared/utils/startup-trace.d.ts +7 -0
  239. package/dist/shared/utils/startup-trace.js +37 -0
  240. package/dist/shared/utils/top-level-nextclaw-command-env.utils.d.ts +4 -0
  241. package/dist/shared/utils/top-level-nextclaw-command-env.utils.js +10 -0
  242. package/package.json +68 -0
@@ -0,0 +1,405 @@
1
+ import { HostAutostartRuntimeService } from "./host-autostart-runtime.service.js";
2
+ import { spawn } from "node:child_process";
3
+ import { dirname, resolve } from "node:path";
4
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ //#region src/commands/service/services/autostart/macos-launch-agent-autostart.service.ts
7
+ const DEFAULT_LAUNCH_AGENT_LABEL = "io.nextclaw.host-agent";
8
+ const SUPPORTED_PLATFORM = "darwin";
9
+ var MacosLaunchAgentAutostartService = class {
10
+ platform;
11
+ env;
12
+ getHomeDir;
13
+ getUid;
14
+ pathExists;
15
+ ensureDir;
16
+ writeFile;
17
+ removeFile;
18
+ runCommandImpl;
19
+ runtimeService;
20
+ constructor(options = {}) {
21
+ this.platform = options.platform ?? process.platform;
22
+ this.env = options.env ?? process.env;
23
+ this.getHomeDir = options.getHomeDir ?? homedir;
24
+ this.getUid = options.getUid ?? (() => process.getuid?.() ?? Number(this.env.UID ?? 0));
25
+ this.pathExists = options.existsSync ?? existsSync;
26
+ this.ensureDir = options.mkdirSync ?? mkdirSync;
27
+ this.writeFile = options.writeFileSync ?? writeFileSync;
28
+ this.removeFile = options.rmSync ?? rmSync;
29
+ this.runCommandImpl = options.runCommand ?? defaultRunCommand;
30
+ this.runtimeService = options.runtimeService ?? new HostAutostartRuntimeService();
31
+ }
32
+ install = async (scope, options = {}) => {
33
+ const plan = this.buildPlan();
34
+ if (!this.isSupported()) return this.createUnsupportedInstallResult(scope, Boolean(options.dryRun));
35
+ if (scope === "system") return this.createUnsupportedInstallResult(scope, Boolean(options.dryRun), "macOS launch agent currently supports --user only.");
36
+ const actions = [
37
+ `write launch agent plist ${plan.resourcePath}`,
38
+ `if the GUI login domain is active, run ${this.formatCommand("launchctl", [
39
+ "bootstrap",
40
+ plan.guiDomain,
41
+ plan.resourcePath
42
+ ])}`,
43
+ `if the GUI login domain is active, run ${this.formatCommand("launchctl", ["enable", plan.serviceTarget])}`,
44
+ `if the GUI login domain is active, run ${this.formatCommand("launchctl", [
45
+ "kickstart",
46
+ "-k",
47
+ plan.serviceTarget
48
+ ])}`
49
+ ];
50
+ try {
51
+ if (!options.dryRun) {
52
+ this.ensureDir(dirname(plan.resourcePath), { recursive: true });
53
+ this.ensureDir(dirname(plan.stdoutPath), { recursive: true });
54
+ this.writeFile(plan.resourcePath, plan.plistContent);
55
+ if (await this.hasGuiDomain(plan.guiDomain)) {
56
+ await this.runTolerantCommand({
57
+ command: "launchctl",
58
+ args: ["bootout", plan.serviceTarget]
59
+ });
60
+ await this.runCheckedCommand({
61
+ command: "launchctl",
62
+ args: [
63
+ "bootstrap",
64
+ plan.guiDomain,
65
+ plan.resourcePath
66
+ ]
67
+ });
68
+ await this.runCheckedCommand({
69
+ command: "launchctl",
70
+ args: ["enable", plan.serviceTarget]
71
+ });
72
+ await this.runCheckedCommand({
73
+ command: "launchctl",
74
+ args: [
75
+ "kickstart",
76
+ "-k",
77
+ plan.serviceTarget
78
+ ]
79
+ });
80
+ }
81
+ }
82
+ } catch (error) {
83
+ return {
84
+ ok: false,
85
+ dryRun: Boolean(options.dryRun),
86
+ scope,
87
+ hostOwner: plan.hostOwner,
88
+ resourceName: plan.resourceName,
89
+ resourcePath: plan.resourcePath,
90
+ homeDir: plan.homeDir,
91
+ command: plan.command,
92
+ logHint: plan.logHint,
93
+ actions,
94
+ reasonIfUnavailable: error instanceof Error ? error.message : "launch agent install failed."
95
+ };
96
+ }
97
+ return {
98
+ ok: true,
99
+ dryRun: Boolean(options.dryRun),
100
+ scope,
101
+ hostOwner: plan.hostOwner,
102
+ resourceName: plan.resourceName,
103
+ resourcePath: plan.resourcePath,
104
+ homeDir: plan.homeDir,
105
+ command: plan.command,
106
+ logHint: plan.logHint,
107
+ actions,
108
+ reasonIfUnavailable: null
109
+ };
110
+ };
111
+ uninstall = async (scope, options = {}) => {
112
+ const plan = this.buildPlan();
113
+ if (!this.isSupported()) return this.createUnsupportedUninstallResult(scope, Boolean(options.dryRun));
114
+ if (scope === "system") return this.createUnsupportedUninstallResult(scope, Boolean(options.dryRun), "macOS launch agent currently supports --user only.");
115
+ const installed = this.pathExists(plan.resourcePath);
116
+ const actions = [`if the GUI login domain is active, run ${this.formatCommand("launchctl", ["bootout", plan.serviceTarget])}`, `remove launch agent plist ${plan.resourcePath}`];
117
+ if (!installed) return {
118
+ ok: true,
119
+ dryRun: Boolean(options.dryRun),
120
+ scope,
121
+ hostOwner: plan.hostOwner,
122
+ resourceName: plan.resourceName,
123
+ resourcePath: plan.resourcePath,
124
+ removed: false,
125
+ logHint: plan.logHint,
126
+ actions: ["no installed launch agent plist found"],
127
+ reasonIfUnavailable: null
128
+ };
129
+ try {
130
+ if (!options.dryRun) {
131
+ if (await this.hasGuiDomain(plan.guiDomain)) await this.runTolerantCommand({
132
+ command: "launchctl",
133
+ args: ["bootout", plan.serviceTarget]
134
+ });
135
+ this.removeFile(plan.resourcePath, { force: true });
136
+ }
137
+ } catch (error) {
138
+ return {
139
+ ok: false,
140
+ dryRun: Boolean(options.dryRun),
141
+ scope,
142
+ hostOwner: plan.hostOwner,
143
+ resourceName: plan.resourceName,
144
+ resourcePath: plan.resourcePath,
145
+ removed: false,
146
+ logHint: plan.logHint,
147
+ actions,
148
+ reasonIfUnavailable: error instanceof Error ? error.message : "launch agent uninstall failed."
149
+ };
150
+ }
151
+ return {
152
+ ok: true,
153
+ dryRun: Boolean(options.dryRun),
154
+ scope,
155
+ hostOwner: plan.hostOwner,
156
+ resourceName: plan.resourceName,
157
+ resourcePath: plan.resourcePath,
158
+ removed: true,
159
+ logHint: plan.logHint,
160
+ actions,
161
+ reasonIfUnavailable: null
162
+ };
163
+ };
164
+ status = async (requestedScope) => {
165
+ const plan = this.buildPlan();
166
+ if (!this.isSupported()) return this.createUnsupportedStatus();
167
+ if (requestedScope === "system") return this.createUnsupportedStatus("macOS launch agent currently supports --user only.");
168
+ const installed = this.pathExists(plan.resourcePath);
169
+ const enabled = installed ? await this.readEnabledState(plan.guiDomain, plan.resourceName) : false;
170
+ const guiDomainAvailable = await this.hasGuiDomain(plan.guiDomain);
171
+ return {
172
+ supported: true,
173
+ installed,
174
+ enabled,
175
+ active: installed && guiDomainAvailable ? (await this.runCommandImpl("launchctl", ["print", plan.serviceTarget])).code === 0 : false,
176
+ scope: "user",
177
+ hostOwner: plan.hostOwner,
178
+ resourceName: plan.resourceName,
179
+ resourcePath: plan.resourcePath,
180
+ homeDir: plan.homeDir,
181
+ command: plan.command,
182
+ logHint: plan.logHint,
183
+ reasonIfUnavailable: null
184
+ };
185
+ };
186
+ doctor = async (requestedScope) => {
187
+ const status = await this.status(requestedScope);
188
+ const plan = this.buildPlan();
189
+ const checks = [];
190
+ const guiDomainAvailable = await this.hasGuiDomain(plan.guiDomain);
191
+ checks.push({
192
+ name: "platform",
193
+ status: status.supported ? "pass" : "fail",
194
+ detail: status.supported ? "macOS supported" : status.reasonIfUnavailable ?? "unsupported platform"
195
+ });
196
+ checks.push({
197
+ name: "plist-file",
198
+ status: status.installed ? "pass" : "warn",
199
+ detail: plan.resourcePath
200
+ });
201
+ checks.push({
202
+ name: "gui-domain",
203
+ status: guiDomainAvailable ? "pass" : "warn",
204
+ detail: guiDomainAvailable ? plan.guiDomain : "GUI login domain is not active; the agent will load on next login."
205
+ });
206
+ checks.push({
207
+ name: "exec-path",
208
+ status: this.pathExists(plan.launch.command) ? "pass" : "fail",
209
+ detail: plan.launch.command
210
+ });
211
+ checks.push({
212
+ name: "home-dir",
213
+ status: this.pathExists(plan.homeDir) ? "pass" : "warn",
214
+ detail: plan.homeDir
215
+ });
216
+ if (status.installed) {
217
+ checks.push({
218
+ name: "enabled",
219
+ status: status.enabled === false ? "warn" : "pass",
220
+ detail: status.enabled === false ? "launch agent is disabled" : "launch agent enabled"
221
+ });
222
+ checks.push({
223
+ name: "active",
224
+ status: status.active ? "pass" : "warn",
225
+ detail: status.active ? "launch agent active" : "launch agent not active in the current GUI session"
226
+ });
227
+ }
228
+ return {
229
+ status,
230
+ checks,
231
+ exitCode: checks.some((check) => check.status === "fail" || check.status === "warn") ? 1 : 0
232
+ };
233
+ };
234
+ isSupported = () => {
235
+ return this.platform === SUPPORTED_PLATFORM;
236
+ };
237
+ createUnsupportedStatus = (reason = "launch agent autostart currently supports macOS only.") => {
238
+ return {
239
+ supported: false,
240
+ installed: false,
241
+ enabled: null,
242
+ active: null,
243
+ scope: null,
244
+ hostOwner: null,
245
+ resourceName: null,
246
+ resourcePath: null,
247
+ homeDir: null,
248
+ command: null,
249
+ logHint: null,
250
+ reasonIfUnavailable: reason
251
+ };
252
+ };
253
+ createUnsupportedInstallResult = (scope, dryRun, reason = "launch agent autostart currently supports macOS only.") => {
254
+ const plan = this.buildPlan();
255
+ return {
256
+ ok: false,
257
+ dryRun,
258
+ scope,
259
+ hostOwner: plan.hostOwner,
260
+ resourceName: plan.resourceName,
261
+ resourcePath: plan.resourcePath,
262
+ homeDir: plan.homeDir,
263
+ command: plan.command,
264
+ logHint: plan.logHint,
265
+ actions: [],
266
+ reasonIfUnavailable: reason
267
+ };
268
+ };
269
+ createUnsupportedUninstallResult = (scope, dryRun, reason = "launch agent autostart currently supports macOS only.") => {
270
+ const plan = this.buildPlan();
271
+ return {
272
+ ok: false,
273
+ dryRun,
274
+ scope,
275
+ hostOwner: plan.hostOwner,
276
+ resourceName: plan.resourceName,
277
+ resourcePath: plan.resourcePath,
278
+ removed: false,
279
+ logHint: plan.logHint,
280
+ actions: [],
281
+ reasonIfUnavailable: reason
282
+ };
283
+ };
284
+ buildPlan = () => {
285
+ const launch = this.runtimeService.resolveForegroundServeLaunch();
286
+ const homeDir = launch.homeDir;
287
+ const resourceName = DEFAULT_LAUNCH_AGENT_LABEL;
288
+ const resourcePath = resolve(this.getHomeDir(), "Library", "LaunchAgents", `${resourceName}.plist`);
289
+ const stdoutPath = resolve(homeDir, "logs", "host-autostart", "macos-launch-agent.stdout.log");
290
+ const stderrPath = resolve(homeDir, "logs", "host-autostart", "macos-launch-agent.stderr.log");
291
+ const guiDomain = `gui/${this.getUid()}`;
292
+ return {
293
+ launch,
294
+ homeDir,
295
+ hostOwner: "launchd-launch-agent",
296
+ resourceName,
297
+ resourcePath,
298
+ stdoutPath,
299
+ stderrPath,
300
+ guiDomain,
301
+ serviceTarget: `${guiDomain}/${resourceName}`,
302
+ command: this.formatCommand(launch.command, launch.args),
303
+ logHint: `tail -f ${this.escapeShellValue(stdoutPath)} ${this.escapeShellValue(stderrPath)}`,
304
+ plistContent: this.renderPlist({
305
+ label: resourceName,
306
+ launch,
307
+ homeDir,
308
+ stdoutPath,
309
+ stderrPath
310
+ })
311
+ };
312
+ };
313
+ renderPlist = (params) => {
314
+ const { label, launch, homeDir, stdoutPath, stderrPath } = params;
315
+ return [
316
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
317
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">",
318
+ "<plist version=\"1.0\">",
319
+ "<dict>",
320
+ ` <key>Label</key><string>${this.escapeXml(label)}</string>`,
321
+ " <key>ProgramArguments</key>",
322
+ " <array>",
323
+ ...[launch.command, ...launch.args].map((value) => ` <string>${this.escapeXml(value)}</string>`),
324
+ " </array>",
325
+ ` <key>WorkingDirectory</key><string>${this.escapeXml(homeDir)}</string>`,
326
+ " <key>EnvironmentVariables</key>",
327
+ " <dict>",
328
+ " <key>NEXTCLAW_HOME</key>",
329
+ ` <string>${this.escapeXml(homeDir)}</string>`,
330
+ " </dict>",
331
+ " <key>RunAtLoad</key><true/>",
332
+ " <key>KeepAlive</key><false/>",
333
+ ` <key>StandardOutPath</key><string>${this.escapeXml(stdoutPath)}</string>`,
334
+ ` <key>StandardErrorPath</key><string>${this.escapeXml(stderrPath)}</string>`,
335
+ "</dict>",
336
+ "</plist>",
337
+ ""
338
+ ].join("\n");
339
+ };
340
+ escapeXml = (value) => {
341
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
342
+ };
343
+ escapeShellValue = (value) => {
344
+ return `'${value.replace(/'/g, "'\\''")}'`;
345
+ };
346
+ formatCommand = (command, args) => {
347
+ return [command, ...args].map((value) => this.escapeShellValue(value)).join(" ");
348
+ };
349
+ hasGuiDomain = async (guiDomain) => {
350
+ return (await this.runCommandImpl("launchctl", ["print", guiDomain])).code === 0;
351
+ };
352
+ readEnabledState = async (guiDomain, label) => {
353
+ const result = await this.runCommandImpl("launchctl", ["print-disabled", guiDomain]);
354
+ if (result.code !== 0) return null;
355
+ const matched = result.stdout.match(new RegExp(`"${this.escapeRegExp(label)}"\\s*=>\\s*(enabled|disabled)`));
356
+ if (!matched) return true;
357
+ return matched[1] === "enabled";
358
+ };
359
+ escapeRegExp = (value) => {
360
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
361
+ };
362
+ runCheckedCommand = async ({ command, args }) => {
363
+ const result = await this.runCommandImpl(command, args);
364
+ if (result.code === 0) return;
365
+ const detail = result.stderr || result.stdout || `exit code ${result.code}`;
366
+ throw new Error(`Command failed: ${this.formatCommand(command, args)} (${detail})`);
367
+ };
368
+ runTolerantCommand = async ({ command, args }) => {
369
+ await this.runCommandImpl(command, args);
370
+ };
371
+ };
372
+ const defaultRunCommand = async (command, args) => {
373
+ return await new Promise((resolvePromise, rejectPromise) => {
374
+ const child = spawn(command, args, {
375
+ env: process.env,
376
+ stdio: [
377
+ "ignore",
378
+ "pipe",
379
+ "pipe"
380
+ ]
381
+ });
382
+ let stdout = "";
383
+ let stderr = "";
384
+ child.stdout?.setEncoding("utf-8");
385
+ child.stderr?.setEncoding("utf-8");
386
+ child.stdout?.on("data", (chunk) => {
387
+ stdout += chunk;
388
+ });
389
+ child.stderr?.on("data", (chunk) => {
390
+ stderr += chunk;
391
+ });
392
+ child.on("error", (error) => {
393
+ rejectPromise(error);
394
+ });
395
+ child.on("close", (code) => {
396
+ resolvePromise({
397
+ code: code ?? 1,
398
+ stdout: stdout.trim(),
399
+ stderr: stderr.trim()
400
+ });
401
+ });
402
+ });
403
+ };
404
+ //#endregion
405
+ export { MacosLaunchAgentAutostartService };
@@ -0,0 +1,54 @@
1
+ import { HostAutostartDoctorReport, HostAutostartInstallResult, HostAutostartRunCommand, HostAutostartScope, HostAutostartStatus, HostAutostartUninstallResult } from "../../types/autostart/host-autostart.types.js";
2
+ import { HostAutostartRuntimeService } from "./host-autostart-runtime.service.js";
3
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+
5
+ //#region src/commands/service/services/autostart/windows-task-autostart.service.d.ts
6
+ type WindowsTaskAutostartServiceOptions = {
7
+ platform?: NodeJS.Platform;
8
+ existsSync?: (path: string) => boolean;
9
+ mkdirSync?: typeof mkdirSync;
10
+ writeFileSync?: typeof writeFileSync;
11
+ rmSync?: typeof rmSync;
12
+ runCommand?: HostAutostartRunCommand;
13
+ runtimeService?: HostAutostartRuntimeService;
14
+ };
15
+ declare class WindowsTaskAutostartService {
16
+ private readonly platform;
17
+ private readonly pathExists;
18
+ private readonly ensureDir;
19
+ private readonly writeFile;
20
+ private readonly removeFile;
21
+ private readonly runCommandImpl;
22
+ private readonly runtimeService;
23
+ constructor(options?: WindowsTaskAutostartServiceOptions);
24
+ install: (scope: HostAutostartScope, options?: {
25
+ dryRun?: boolean;
26
+ }) => Promise<HostAutostartInstallResult>;
27
+ uninstall: (scope: HostAutostartScope, options?: {
28
+ dryRun?: boolean;
29
+ }) => Promise<HostAutostartUninstallResult>;
30
+ status: (requestedScope?: HostAutostartScope) => Promise<HostAutostartStatus>;
31
+ doctor: (requestedScope?: HostAutostartScope) => Promise<HostAutostartDoctorReport>;
32
+ private isSupported;
33
+ private createUnsupportedStatus;
34
+ private createUnsupportedInstallResult;
35
+ private createUnsupportedUninstallResult;
36
+ private createPlatformCheck;
37
+ private createTaskCheck;
38
+ private createLauncherScriptCheck;
39
+ private createExecPathCheck;
40
+ private createHomeDirCheck;
41
+ private createInstalledDoctorChecks;
42
+ private createLastTaskResultCheck;
43
+ private buildPlan;
44
+ private renderLauncher;
45
+ private escapeBatchValue;
46
+ private renderInstallScript;
47
+ private renderUninstallScript;
48
+ private readTaskInfo;
49
+ private renderStatusScript;
50
+ private runCheckedPowerShell;
51
+ private runPowerShell;
52
+ }
53
+ //#endregion
54
+ export { WindowsTaskAutostartService };