From 4b11fd25e7bfb8672c432030cba99dc9a644d928 Mon Sep 17 00:00:00 2001 From: Artur Jankowski Date: Fri, 13 Mar 2026 15:20:09 +0100 Subject: [PATCH 1/2] fix: normalize inquirer signal-exit compatibility on Windows --- LICENSE-THIRD-PARTY.txt | 37 ++++---- package.json | 1 + src/box-command.js | 2 +- src/commands/ai/ask.js | 4 +- src/commands/ai/extract-structured.js | 4 +- src/commands/ai/extract.js | 4 +- src/commands/configure/environments/delete.js | 2 +- .../configure/environments/set-current.js | 2 +- src/commands/files/upload.js | 29 ++++-- src/commands/files/versions/upload.js | 5 +- src/commands/login.js | 7 +- src/commands/logout.js | 2 +- src/commands/search.js | 4 +- src/inquirer.js | 39 ++++++++ src/modules/upload.js | 21 ++--- test/commands/files.test.js | 6 +- test/commands/search.test.js | 21 +++-- test/inquirer.test.js | 94 +++++++++++++++++++ 18 files changed, 224 insertions(+), 60 deletions(-) create mode 100644 src/inquirer.js create mode 100644 test/inquirer.test.js diff --git a/LICENSE-THIRD-PARTY.txt b/LICENSE-THIRD-PARTY.txt index be688d81..1064a668 100644 --- a/LICENSE-THIRD-PARTY.txt +++ b/LICENSE-THIRD-PARTY.txt @@ -279,11 +279,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------- -The following npm package may be included in this product: +The following npm packages may be included in this product: - statuses@2.0.1 + - statuses@2.0.2 -This package contains the following license: +These packages each contain the following license: The MIT License (MIT) @@ -371,11 +372,12 @@ THE SOFTWARE. ----------- -The following npm package may be included in this product: +The following npm packages may be included in this product: - http-errors@2.0.0 + - http-errors@2.0.1 -This package contains the following license: +These packages each contain the following license: The MIT License (MIT) @@ -1931,7 +1933,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following npm packages may be included in this product: - - body-parser@1.20.3 + - body-parser@1.20.4 - type-is@1.6.18 These packages each contain the following license: @@ -2813,7 +2815,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The following npm packages may be included in this product: - - @cypress/request@3.0.9 + - @cypress/request@3.0.10 - aws-sign2@0.7.0 - forever-agent@0.6.1 - tunnel-agent@0.6.0 @@ -3136,12 +3138,11 @@ Apache-2.0 ----------- -The following npm packages may be included in this product: +The following npm package may be included in this product: - - qs@6.13.0 - - qs@6.14.0 + - qs@6.14.2 -These packages each contain the following license: +This package contains the following license: BSD 3-Clause License @@ -4147,7 +4148,7 @@ OTHER DEALINGS IN THE SOFTWARE. The following npm package may be included in this product: - - basic-ftp@5.0.5 + - basic-ftp@5.2.0 This package contains the following license: @@ -4858,7 +4859,7 @@ IN THE SOFTWARE. The following npm package may be included in this product: - - lodash@4.17.21 + - lodash@4.17.23 This package contains the following license: @@ -6719,7 +6720,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The following npm package may be included in this product: - - diff@4.0.2 + - diff@4.0.4 This package contains the following license: @@ -6906,8 +6907,8 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The following npm packages may be included in this product: - - minimatch@5.1.6 - - minimatch@9.0.5 + - minimatch@5.1.9 + - minimatch@9.0.9 These packages each contain the following license: @@ -7057,7 +7058,7 @@ The following npm packages may be included in this product: - ini@1.3.8 - isexe@2.0.0 - json-stringify-safe@5.0.1 - - minimatch@3.1.2 + - minimatch@3.1.5 - mute-stream@0.0.8 - mute-stream@2.0.0 - once@1.4.0 @@ -7445,7 +7446,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following npm package may be included in this product: - - raw-body@2.5.2 + - raw-body@2.5.3 This package contains the following license: @@ -8113,7 +8114,7 @@ THE SOFTWARE. The following npm package may be included in this product: - - ajv@6.12.6 + - ajv@6.14.0 This package contains the following license: diff --git a/package.json b/package.json index 4f22d064..52f2f210 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "nyc": "^17.1.0", "oclif": "^4.22.38", "prettier": "^3.6.2", + "signal-exit": "^4.1.0", "sinon": "^19.0.2", "standard-version": "^9.5.0", "typescript": "^5.7.2" diff --git a/src/box-command.js b/src/box-command.js index 2d1461b8..08b28e88 100644 --- a/src/box-command.js +++ b/src/box-command.js @@ -32,7 +32,7 @@ const BoxCLIError = require('./cli-error'); const CLITokenCache = require('./token-cache'); const utils = require('./util'); const pkg = require('../package.json'); -const inquirer = require('inquirer'); +const inquirer = require('./inquirer'); const { stringifyStream } = require('@discoveryjs/json-ext'); const progress = require('cli-progress'); let keytar = null; diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index 8a487c42..5d8ecbe7 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -90,7 +90,9 @@ AiAskCommand.flags = { try { return JSON.parse(input); } catch (error) { - throw new Error(`Error parsing AI agent JSON: ${error.message}`); + throw new Error( + `Error parsing AI agent JSON: ${error.message}` + ); } }, }), diff --git a/src/commands/ai/extract-structured.js b/src/commands/ai/extract-structured.js index 50f7daa0..bb025a95 100644 --- a/src/commands/ai/extract-structured.js +++ b/src/commands/ai/extract-structured.js @@ -206,7 +206,9 @@ AiExtractStructuredCommand.flags = { try { return JSON.parse(input); } catch (error) { - throw new Error(`Error parsing AI agent JSON: ${error.message}`); + throw new Error( + `Error parsing AI agent JSON: ${error.message}` + ); } }, }), diff --git a/src/commands/ai/extract.js b/src/commands/ai/extract.js index 6b60fa0e..9440e916 100644 --- a/src/commands/ai/extract.js +++ b/src/commands/ai/extract.js @@ -91,7 +91,9 @@ AiExtractCommand.flags = { try { return JSON.parse(input); } catch (error) { - throw new Error(`Error parsing AI agent JSON: ${error.message}`); + throw new Error( + `Error parsing AI agent JSON: ${error.message}` + ); } }, }), diff --git a/src/commands/configure/environments/delete.js b/src/commands/configure/environments/delete.js index 254c21b2..bd078ed3 100644 --- a/src/commands/configure/environments/delete.js +++ b/src/commands/configure/environments/delete.js @@ -3,7 +3,7 @@ const { Args } = require('@oclif/core'); const BoxCommand = require('../../../box-command'); const BoxCLIError = require('../../../cli-error'); -const inquirer = require('inquirer'); +const inquirer = require('../../../inquirer'); class EnvironmentsDeleteCommand extends BoxCommand { async run() { diff --git a/src/commands/configure/environments/set-current.js b/src/commands/configure/environments/set-current.js index 47ff9ffa..29f9c3d0 100644 --- a/src/commands/configure/environments/set-current.js +++ b/src/commands/configure/environments/set-current.js @@ -2,7 +2,7 @@ const { Args } = require('@oclif/core'); const BoxCommand = require('../../../box-command'); -const inquirer = require('inquirer'); +const inquirer = require('../../../inquirer'); class EnvironmentsSetCurrentCommand extends BoxCommand { async run() { diff --git a/src/commands/files/upload.js b/src/commands/files/upload.js index f4e17e7c..8ff9a620 100644 --- a/src/commands/files/upload.js +++ b/src/commands/files/upload.js @@ -5,14 +5,20 @@ const { Flags, Args } = require('@oclif/core'); const fs = require('node:fs'); const path = require('node:path'); const BoxCLIError = require('../../cli-error'); -const { createReadStream, uploadFile, uploadNewFileVersion } = require('../../modules/upload'); +const { + createReadStream, + uploadFile, + uploadNewFileVersion, +} = require('../../modules/upload'); const DEBUG = require('../../debug'); class FilesUploadCommand extends BoxCommand { async run() { const { flags, args } = await this.parse(FilesUploadCommand); if (!fs.existsSync(args.path)) { - throw new BoxCLIError(`File not found: ${args.path}. Please check the file path and try again.`); + throw new BoxCLIError( + `File not found: ${args.path}. Please check the file path and try again.` + ); } let size = fs.statSync(args.path).size; let folderID = flags['parent-id']; @@ -41,8 +47,16 @@ class FilesUploadCommand extends BoxCommand { const { statusCode, response } = error; const body = response?.body; - if (!flags.overwrite || statusCode !== 409 || body?.code !== 'item_name_in_use') { - if (!flags.overwrite && statusCode === 409 && body?.code === 'item_name_in_use') { + if ( + !flags.overwrite || + statusCode !== 409 || + body?.code !== 'item_name_in_use' + ) { + if ( + !flags.overwrite && + statusCode === 409 && + body?.code === 'item_name_in_use' + ) { throw new BoxCLIError( 'A file with the same name already exists in the destination folder. Use --overwrite to replace it with a new version.', error @@ -62,7 +76,9 @@ class FilesUploadCommand extends BoxCommand { ); } - DEBUG.output(`File already exists in folder; uploading as new version of file ${existingFileID}`); + DEBUG.output( + `File already exists in folder; uploading as new version of file ${existingFileID}` + ); // Re-create the stream since the first attempt consumed it const versionStream = createReadStream(args.path); @@ -79,7 +95,8 @@ class FilesUploadCommand extends BoxCommand { } } -FilesUploadCommand.description = 'Upload a file to a folder. Use --overwrite to automatically replace an existing file with the same name by uploading a new version'; +FilesUploadCommand.description = + 'Upload a file to a folder. Use --overwrite to automatically replace an existing file with the same name by uploading a new version'; FilesUploadCommand.examples = [ 'box files:upload /path/to/file.pdf --parent-id 22222', 'box files:upload /path/to/file.pdf --parent-id 22222 --overwrite', diff --git a/src/commands/files/versions/upload.js b/src/commands/files/versions/upload.js index 42c52071..2618433a 100644 --- a/src/commands/files/versions/upload.js +++ b/src/commands/files/versions/upload.js @@ -3,7 +3,10 @@ const BoxCommand = require('../../../box-command'); const { Flags, Args } = require('@oclif/core'); const fs = require('node:fs'); -const { createReadStream, uploadNewFileVersion } = require('../../../modules/upload'); +const { + createReadStream, + uploadNewFileVersion, +} = require('../../../modules/upload'); class FilesUploadVersionsCommand extends BoxCommand { async run() { diff --git a/src/commands/login.js b/src/commands/login.js index c7915d48..b4fc03ee 100644 --- a/src/commands/login.js +++ b/src/commands/login.js @@ -9,7 +9,7 @@ const CLITokenCache = require('../token-cache'); const package_ = require('../../package.json'); const chalk = require('chalk'); const express = require('express'); -const inquirer = require('inquirer'); +const inquirer = require('../inquirer'); const path = require('node:path'); const ora = require('ora'); const http = require('node:http'); @@ -89,7 +89,10 @@ async function promptForAuthMethod(inquirerModule) { trimmedChoice.length > CLIENT_ID_MIN_LENGTH && trimmedChoice.length < CLIENT_ID_MAX_LENGTH ) { - return promptForPlatformAppCredentials(inquirerModule, trimmedChoice); + return promptForPlatformAppCredentials( + inquirerModule, + trimmedChoice + ); } // Invalid input — repeat the prompt diff --git a/src/commands/logout.js b/src/commands/logout.js index c05a9557..e5117df3 100644 --- a/src/commands/logout.js +++ b/src/commands/logout.js @@ -4,7 +4,7 @@ const BoxCommand = require('../box-command'); const BoxSDK = require('box-node-sdk').default; const CLITokenCache = require('../token-cache'); const chalk = require('chalk'); -const inquirer = require('inquirer'); +const inquirer = require('../inquirer'); const pkg = require('../../package.json'); const { Flags } = require('@oclif/core'); diff --git a/src/commands/search.js b/src/commands/search.js index ba0888a2..f4aae14c 100644 --- a/src/commands/search.js +++ b/src/commands/search.js @@ -44,9 +44,7 @@ class SearchCommand extends BoxCommand { 'Run: box search --help for all available filters.', ].join(os.EOL); - throw new BoxCLIError( - missingQueryMessage - ); + throw new BoxCLIError(missingQueryMessage); } if (flags.all && (flags.limit || flags['max-items'])) { diff --git a/src/inquirer.js b/src/inquirer.js new file mode 100644 index 00000000..dada85ea --- /dev/null +++ b/src/inquirer.js @@ -0,0 +1,39 @@ +'use strict'; + +// restore-cursor@3 (used by inquirer@8) calls require('signal-exit') as a +// function, but signal-exit@4 exports an object with an onExit() method. +// +// Locally, npm nests signal-exit@3 under restore-cursor, so both versions +// coexist. In the standalone Windows build produced by oclif pack:win, module +// resolution ends up pointing restore-cursor to top-level signal-exit@4 +// (effectively like a flattened/deduped node_modules layout), which causes +// "signalExit is not a function" on Windows. +// +// Node's lookup order for require('signal-exit') from restore-cursor is: +// 1) restore-cursor/node_modules/signal-exit +// 2) parent node_modules/signal-exit +// If step (1) is absent in the packaged layout, step (2) resolves to v4. +// +// This started surfacing after dependency-tree changes included in v4.5.0 +// (notably commit 4f4254d), where top-level signal-exit moved to 4.1.0. +// +// This shim wraps the v4 object export as a callable function before inquirer +// (and its restore-cursor dependency) is loaded. + +const SIGNAL_EXIT_ID = 'signal-exit'; +const signalExit = require(SIGNAL_EXIT_ID); + +if ( + typeof signalExit !== 'function' && + typeof signalExit.onExit === 'function' +) { + const compatSignalExit = (...args) => signalExit.onExit(...args); + Object.assign(compatSignalExit, signalExit); + + const resolvedPath = require.resolve(SIGNAL_EXIT_ID); + if (require.cache[resolvedPath]) { + require.cache[resolvedPath].exports = compatSignalExit; + } +} + +module.exports = require('inquirer'); diff --git a/src/modules/upload.js b/src/modules/upload.js index bc4fdecb..20e3298c 100644 --- a/src/modules/upload.js +++ b/src/modules/upload.js @@ -25,22 +25,18 @@ function runChunkedUpload(uploader, size) { uploader.on('chunkUploaded', (chunk) => { bytesUploaded += chunk.part.size; progressBar.update(bytesUploaded, { - speed: Math.floor( - bytesUploaded / (Date.now() - startTime) / 1000 - ), + speed: Math.floor(bytesUploaded / (Date.now() - startTime) / 1000), }); }); return uploader.start(); } -async function uploadFile(client, { folderID, name, stream, size, fileAttributes }) { +async function uploadFile( + client, + { folderID, name, stream, size, fileAttributes } +) { if (size < CHUNKED_UPLOAD_FILE_SIZE) { - return client.files.uploadFile( - folderID, - name, - stream, - fileAttributes - ); + return client.files.uploadFile(folderID, name, stream, fileAttributes); } const uploader = await client.files.getChunkedUploader( folderID, @@ -52,7 +48,10 @@ async function uploadFile(client, { folderID, name, stream, size, fileAttributes return runChunkedUpload(uploader, size); } -async function uploadNewFileVersion(client, { fileID, stream, size, fileAttributes }) { +async function uploadNewFileVersion( + client, + { fileID, stream, size, fileAttributes } +) { if (size < CHUNKED_UPLOAD_FILE_SIZE) { return client.files.uploadNewFileVersion( fileID, diff --git a/test/commands/files.test.js b/test/commands/files.test.js index 8fdf2127..c3246682 100644 --- a/test/commands/files.test.js +++ b/test/commands/files.test.js @@ -1946,9 +1946,9 @@ describe('Files', function () { request_id: 'abc123', context_info: { conflicts: { - type: 'file', - id: existingFileId, - name: testFileName, + type: 'file', + id: existingFileId, + name: testFileName, }, }, }; diff --git a/test/commands/search.test.js b/test/commands/search.test.js index 40c09f40..91d09574 100644 --- a/test/commands/search.test.js +++ b/test/commands/search.test.js @@ -441,14 +441,17 @@ describe('Search', function () { test.stderr() .command(['search', '--no-color', '--token=test']) - .it('when query is missing and no metadata filters are provided', (context) => { - assert.equal( - context.stderr, - `Missing required argument: [QUERY]${os.EOL}` + - `Usage: box search "your search terms"${os.EOL}` + - `Example: box search "quarterly report" --type file${os.EOL}` + - `Run: box search --help for all available filters.${os.EOL}` - ); - }); + .it( + 'when query is missing and no metadata filters are provided', + (context) => { + assert.equal( + context.stderr, + `Missing required argument: [QUERY]${os.EOL}` + + `Usage: box search "your search terms"${os.EOL}` + + `Example: box search "quarterly report" --type file${os.EOL}` + + `Run: box search --help for all available filters.${os.EOL}` + ); + } + ); }); }); diff --git a/test/inquirer.test.js b/test/inquirer.test.js new file mode 100644 index 00000000..3aebe0f8 --- /dev/null +++ b/test/inquirer.test.js @@ -0,0 +1,94 @@ +'use strict'; + +const { assert } = require('chai'); +const sinon = require('sinon'); + +const handler = () => {}; + +// The shim in src/inquirer normalizes signal-exit across versions: +// newer versions export an object with onExit(), while older behavior expects +// a callable function. These tests assert both compatibility paths. +describe('inquirer compatibility shim', function () { + const MODULE_UNDER_TEST = '../src/inquirer'; + const signalExitPath = require.resolve('signal-exit'); + const inquirerPath = require.resolve('inquirer'); + + let originalSignalExitCacheEntry; + let originalInquirerCacheEntry; + + beforeEach(function () { + // Snapshot and reset module cache so each test can inject a custom + // signal-exit export and re-run the shim from a clean state. + originalSignalExitCacheEntry = require.cache[signalExitPath]; + originalInquirerCacheEntry = require.cache[inquirerPath]; + delete require.cache[require.resolve(MODULE_UNDER_TEST)]; + }); + + afterEach(function () { + if (originalSignalExitCacheEntry) { + require.cache[signalExitPath] = originalSignalExitCacheEntry; + } else { + delete require.cache[signalExitPath]; + } + + if (originalInquirerCacheEntry) { + require.cache[inquirerPath] = originalInquirerCacheEntry; + } else { + delete require.cache[inquirerPath]; + } + + delete require.cache[require.resolve(MODULE_UNDER_TEST)]; + }); + + it('should wrap object-style signal-exit export as callable function', function () { + // Simulate modern signal-exit shape (object export with onExit method). + const onExitStub = sinon.stub().returns('cleanup-callback'); + const signalExitObjectExport = { + onExit: onExitStub, + load: sinon.stub(), + unload: sinon.stub(), + }; + + require.cache[signalExitPath] = { + id: signalExitPath, + filename: signalExitPath, + loaded: true, + exports: signalExitObjectExport, + }; + + const shimmedInquirer = require(MODULE_UNDER_TEST); + const rawInquirer = require('inquirer'); + const patchedSignalExit = require('signal-exit'); + + // The shim should not replace inquirer itself; only signal-exit behavior. + assert.strictEqual(shimmedInquirer, rawInquirer); + assert.strictEqual(typeof patchedSignalExit, 'function'); + assert.strictEqual(patchedSignalExit.onExit, onExitStub); + + const result = patchedSignalExit(handler, { alwaysLast: true }); + assert.strictEqual(result, 'cleanup-callback'); + assert.isTrue( + onExitStub.calledOnceWithExactly(handler, { alwaysLast: true }) + ); + }); + + it('should preserve function-style signal-exit export', function () { + // If signal-exit is already callable, shim should leave it untouched. + const signalExitFunctionExport = sinon + .stub() + .returns('already-callable'); + + require.cache[signalExitPath] = { + id: signalExitPath, + filename: signalExitPath, + loaded: true, + exports: signalExitFunctionExport, + }; + + require(MODULE_UNDER_TEST); + const patchedSignalExit = require('signal-exit'); + + assert.strictEqual(patchedSignalExit, signalExitFunctionExport); + assert.strictEqual(patchedSignalExit(), 'already-callable'); + }); +}); From c53999bc4666609ed2e2c933c878beb1f76d6853 Mon Sep 17 00:00:00 2001 From: Artur Jankowski Date: Fri, 13 Mar 2026 19:37:07 +0100 Subject: [PATCH 2/2] docs: Update descriptions for ai commands --- README.md | 2 +- docs/ai.md | 20 +++++++++++--------- package.json | 3 ++- src/commands/ai/ask.js | 2 +- src/commands/ai/extract-structured.js | 2 +- src/commands/ai/extract.js | 2 +- src/commands/ai/text-gen.js | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c916e0a5..dccdf5f4 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ Avatar URL: 'https://app.box.com/api/avatar/large/77777' # Command Topics -* [`box ai`](docs/ai.md) - Sends an AI request to supported LLMs and returns an answer +* [`box ai`](docs/ai.md) - Sends a request to supported LLMs using Box AI. This is intended for direct use, not by AI agents. * [`box autocomplete`](docs/autocomplete.md) - Display autocomplete installation instructions * [`box collaboration-allowlist`](docs/collaboration-allowlist.md) - List collaboration allowlist entries * [`box collaborations`](docs/collaborations.md) - Manage collaborations diff --git a/docs/ai.md b/docs/ai.md index 990a3ee2..01c2dc08 100644 --- a/docs/ai.md +++ b/docs/ai.md @@ -1,7 +1,7 @@ `box ai` ======== -Sends an AI request to supported LLMs and returns an answer +Sends a request to supported LLMs using Box AI. This is intended for direct use, not by AI agents. * [`box ai:ask`](#box-aiask) * [`box ai:extract`](#box-aiextract) @@ -10,7 +10,7 @@ Sends an AI request to supported LLMs and returns an answer ## `box ai:ask` -Sends an AI request to supported LLMs and returns an answer +Sends a request to supported LLMs using Box AI. This is intended for direct use, not by AI agents. ``` USAGE @@ -39,7 +39,7 @@ FLAGS --save-to-file-path= Override default file path to save report DESCRIPTION - Sends an AI request to supported LLMs and returns an answer + Sends a request to supported LLMs using Box AI. This is intended for direct use, not by AI agents. EXAMPLES $ box ai:ask --items=id=12345,type=file --prompt "What is the status of this document?" @@ -49,7 +49,7 @@ _See code: [src/commands/ai/ask.js](https://github.com/box/boxcli/blob/v4.5.0/sr ## `box ai:extract` -Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs +Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs. This is intended for direct use, not by AI agents. ``` USAGE @@ -79,7 +79,8 @@ FLAGS --save-to-file-path= Override default file path to save report DESCRIPTION - Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs + Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs. This + is intended for direct use, not by AI agents. EXAMPLES $ box ai:extract --items=id=12345,type=file --prompt "firstName, lastName, location, yearOfBirth, company" @@ -91,7 +92,7 @@ _See code: [src/commands/ai/extract.js](https://github.com/box/boxcli/blob/v4.5. ## `box ai:extract-structured` -Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either a metadata template or a list of fields to ensure the structure. +Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either a metadata template or a list of fields to ensure the structure. This is intended for direct use, not by AI agents. ``` USAGE @@ -124,7 +125,7 @@ FLAGS DESCRIPTION Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either - a metadata template or a list of fields to ensure the structure. + a metadata template or a list of fields to ensure the structure. This is intended for direct use, not by AI agents. EXAMPLES $ box ai:extract-structured --items="id=12345,type=file" --fields "key=hobby,type=multiSelect,description=Person hobby,prompt=What is your hobby?,displayName=Hobby,options=Guitar;Books" @@ -136,7 +137,7 @@ _See code: [src/commands/ai/extract-structured.js](https://github.com/box/boxcli ## `box ai:text-gen` -Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. +Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. This is intended for direct use, not by AI agents. ``` USAGE @@ -165,7 +166,8 @@ FLAGS --save-to-file-path= Override default file path to save report DESCRIPTION - Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. + Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. This is + intended for direct use, not by AI agents. EXAMPLES $ box ai:text-gen --dialogue-history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?" diff --git a/package.json b/package.json index 52f2f210..028b5138 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@box/cli", - "description": "Official command line interface for the Box API. New here? Run 'box login -d' to sign in with your Box account in seconds. Already set up? Run 'box help' to explore all available commands.", + "description": "Official command line interface for the Box API.", "keywords": [ "box", "cli", @@ -88,6 +88,7 @@ "/src" ], "oclif": { + "description": "Official command line interface for the Box API. New here? Run 'box login -d' to sign in with your Box account in seconds. Already set up? Run 'box help' to explore all available commands.", "commands": "./src/commands", "bin": "box", "additionalHelpFlags": [ diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index 5d8ecbe7..abebf8a1 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -29,7 +29,7 @@ class AiAskCommand extends BoxCommand { } AiAskCommand.description = - 'Sends an AI request to supported LLMs and returns an answer'; + 'Sends a request to supported LLMs using Box AI. This is intended for direct use, not by AI agents.'; AiAskCommand.examples = [ 'box ai:ask --items=id=12345,type=file --prompt "What is the status of this document?"', ]; diff --git a/src/commands/ai/extract-structured.js b/src/commands/ai/extract-structured.js index bb025a95..c965ec94 100644 --- a/src/commands/ai/extract-structured.js +++ b/src/commands/ai/extract-structured.js @@ -41,7 +41,7 @@ class AiExtractStructuredCommand extends BoxCommand { } AiExtractStructuredCommand.description = - 'Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either a metadata template or a list of fields to ensure the structure.'; + 'Sends an AI request to supported Large Language Models (LLMs) and returns extracted metadata as a set of key-value pairs. For this request, you either need a metadata template or a list of fields you want to extract. Input is either a metadata template or a list of fields to ensure the structure. This is intended for direct use, not by AI agents.'; AiExtractStructuredCommand.examples = [ 'box ai:extract-structured --items="id=12345,type=file" --fields "key=hobby,type=multiSelect,description=Person hobby,prompt=What is your hobby?,displayName=Hobby,options=Guitar;Books"', 'box ai:extract-structured --items="id=12345,type=file" --metadata-template="type=metadata_template,scope=enterprise,template_key=test" --ai-agent \'{"type":"ai_agent_extract_structured","basic_text":{"model":"azure__openai__gpt_4o_mini","prompt_template":"Answer using the provided content"}}\'', diff --git a/src/commands/ai/extract.js b/src/commands/ai/extract.js index 9440e916..e85b8446 100644 --- a/src/commands/ai/extract.js +++ b/src/commands/ai/extract.js @@ -27,7 +27,7 @@ class AiExtractCommand extends BoxCommand { } AiExtractCommand.description = - 'Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs'; + 'Sends an AI request to supported Large Language Models (LLMs) and extracts metadata in form of key-value pairs. This is intended for direct use, not by AI agents.'; AiExtractCommand.examples = [ 'box ai:extract --items=id=12345,type=file --prompt "firstName, lastName, location, yearOfBirth, company"', 'box ai:extract --prompt "firstName, lastName, location, yearOfBirth, company" --items "id=12345,type=file" --ai-agent \'{"type":"ai_agent_extract","basic_text":{"model":"azure__openai__gpt_4o_mini"}}\'', diff --git a/src/commands/ai/text-gen.js b/src/commands/ai/text-gen.js index 4225cb71..c62bf0a4 100644 --- a/src/commands/ai/text-gen.js +++ b/src/commands/ai/text-gen.js @@ -26,7 +26,7 @@ class AiTextGenCommand extends BoxCommand { } AiTextGenCommand.description = - 'Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.'; + 'Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. This is intended for direct use, not by AI agents.'; AiTextGenCommand.examples = [ 'box ai:text-gen --dialogue-history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?"', ];