@@ -3,13 +3,15 @@ import fs from "node:fs";
33import os from "node:os" ;
44import path from "node:path" ;
55import { Type } from "typebox" ;
6- import { beforeAll , describe , expect , it } from "vitest" ;
6+ import { beforeAll , describe , expect , it , vi } from "vitest" ;
77import { defineToolPlugin , getToolPluginMetadata } from "../plugin-sdk/tool-plugin.js" ;
8+ import { defaultRuntime } from "../runtime.js" ;
89import { VERSION } from "../version.js" ;
910import {
1011 buildToolPluginManifest ,
1112 buildToolPluginPackageManifest ,
1213 loadToolPlugin ,
14+ runPluginsBuildCommand ,
1315 runPluginsInitCommand ,
1416 validateToolPluginProject ,
1517} from "./plugins-authoring-command.js" ;
@@ -314,6 +316,68 @@ describe("plugin authoring commands", () => {
314316 expect ( loaded . metadata . tools . map ( ( tool ) => tool . name ) ) . toEqual ( [ "source_echo" ] ) ;
315317 } ) ;
316318
319+ it ( "finishes a build from an absolute root after the launch directory is removed" , async ( ) => {
320+ const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-plugin-deleted-cwd-build-" ) ) ;
321+ const packagePath = path . join ( tmpDir , "package.json" ) ;
322+ const entryPath = writeSourceToolPluginProject ( {
323+ tmpDir,
324+ packageName : "openclaw-plugin-deleted-cwd-build" ,
325+ pluginId : "deleted-cwd-build" ,
326+ toolName : "deleted_cwd_echo" ,
327+ } ) ;
328+ const originalCwd = process . cwd ( ) ;
329+ const originalWriteFileSync = fs . writeFileSync . bind ( fs ) ;
330+ let cwdRemoved = false ;
331+ const log = vi . spyOn ( defaultRuntime , "log" ) . mockImplementation ( ( ) => { } ) ;
332+ const cwd = vi . spyOn ( process , "cwd" ) . mockImplementation ( ( ) => {
333+ if ( cwdRemoved ) {
334+ throw new Error ( "ENOENT: no such file or directory, uv_cwd" ) ;
335+ }
336+ return originalCwd ;
337+ } ) ;
338+ const writeFileSync = vi
339+ . spyOn ( fs , "writeFileSync" )
340+ . mockImplementation ( ( file , data , options ) => {
341+ originalWriteFileSync ( file , data , options ) ;
342+ if ( file === packagePath ) {
343+ cwdRemoved = true ;
344+ }
345+ } ) ;
346+
347+ try {
348+ await runPluginsBuildCommand ( { root : tmpDir , entry : entryPath } ) ;
349+
350+ expect ( fs . existsSync ( path . join ( tmpDir , "openclaw.plugin.json" ) ) ) . toBe ( true ) ;
351+ expect ( log ) . toHaveBeenCalledWith ( `Wrote ${ path . join ( tmpDir , "openclaw.plugin.json" ) } ` ) ;
352+ expect ( log ) . toHaveBeenCalledWith ( `Updated ${ packagePath } ` ) ;
353+ } finally {
354+ writeFileSync . mockRestore ( ) ;
355+ cwd . mockRestore ( ) ;
356+ log . mockRestore ( ) ;
357+ fs . rmSync ( tmpDir , { force : true , recursive : true } ) ;
358+ }
359+ } ) ;
360+
361+ it ( "finishes init with an absolute directory after the launch directory is removed" , async ( ) => {
362+ const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-plugin-deleted-cwd-init-" ) ) ;
363+ const projectDir = path . join ( tmpDir , "demo" ) ;
364+ const log = vi . spyOn ( defaultRuntime , "log" ) . mockImplementation ( ( ) => { } ) ;
365+ const cwd = vi . spyOn ( process , "cwd" ) . mockImplementation ( ( ) => {
366+ throw new Error ( "ENOENT: no such file or directory, uv_cwd" ) ;
367+ } ) ;
368+
369+ try {
370+ await runPluginsInitCommand ( "demo" , { directory : projectDir } ) ;
371+
372+ expect ( fs . existsSync ( path . join ( projectDir , "package.json" ) ) ) . toBe ( true ) ;
373+ expect ( log ) . toHaveBeenCalledWith ( `Created ${ projectDir } ` ) ;
374+ } finally {
375+ cwd . mockRestore ( ) ;
376+ log . mockRestore ( ) ;
377+ fs . rmSync ( tmpDir , { force : true , recursive : true } ) ;
378+ }
379+ } ) ;
380+
317381 it ( "scaffolds a dist-entry tool plugin project" , async ( ) => {
318382 const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-plugin-init-" ) ) ;
319383 const projectDir = path . join ( tmpDir , "stock-quotes" ) ;
0 commit comments