Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
★ Release Notes: 2026-01-29
★ Release Notes: 2026-02-25
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

Thanks for upgrading to the latest version of the ALKS CLI!

* Fixed metadata server path resolution issues and launch daemon loading (DE565327).
- Corrected paths for metadata-server.js, forever daemon root, and service files
- Fixed launch daemon plist to properly load pf rules as an anchor
- Improved daemon loading logic to ensure service starts even if files were previously installed
* Fixed favorites not being displayed correctly in certain scenarios.
* Added real-time search/filter to account selection prompt.
- Type to filter accounts by alias or account ID instead of scrolling
- Uses case-insensitive substring matching

Have feedback? https://github.com/Cox-Automotive/ALKS-CLI/issues

Expand Down
4,652 changes: 2,927 additions & 1,725 deletions npm-shrinkwrap.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "alks",
"version": "3.24.3",
"version": "3.24.4",
"description": "CLI for working with ALKS",
"main": "dist/src/bin/alks.js",
"scripts": {
Expand Down Expand Up @@ -54,6 +54,7 @@
"fuzzy": "^0.1.1",
"ini": "^2.0.0",
"inquirer": "^8.2.7",
"inquirer-autocomplete-prompt": "^2.0.1",
"lodash": "^4.17.21",
"lokijs": "^1.5.1",
"memoizee": "^0.4.15",
Expand Down
5 changes: 4 additions & 1 deletion src/lib/getStdErrPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { createPromptModule } from 'inquirer';
import AutocompletePrompt from 'inquirer-autocomplete-prompt';

export function getStdErrPrompt() {
return createPromptModule({ output: process.stderr });
const prompt = createPromptModule({ output: process.stderr });
prompt.registerPrompt('autocomplete', AutocompletePrompt);
return prompt;
}
32 changes: 28 additions & 4 deletions src/lib/promptForAlksAccountAndRole.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ describe('promptForAlksAccountAndRole', () => {
it('prompts the user with formatted role output', async () => {
await promptForAlksAccountAndRole({});

expect(mockPromptFn.mock.calls[0][0][0].choices).toStrictEqual([
const promptConfig = mockPromptFn.mock.calls[0][0][0];
const results = await promptConfig.source({}, undefined);
expect(results).toStrictEqual([
// favorites pulled to top after alphabetical sort
'clientstaging .. 678901234567/ALKSAdmin :: Admin',
'commontools .... 567890123456/ALKSReadOnly :: ReadOnly',
Expand Down Expand Up @@ -109,9 +111,31 @@ describe('promptForAlksAccountAndRole', () => {

it('should filter non-favorites if filterFavorites is true', async () => {
await promptForAlksAccountAndRole({ filterFavorites: true });
expect(mockPromptFn.mock.calls[0][0][0].choices.length).toBe(
mockFavorites.length
);
const promptConfig = mockPromptFn.mock.calls[0][0][0];
const results = await promptConfig.source({}, undefined);
expect(results.length).toBe(mockFavorites.length);
});

it('should return all choices when input is an empty string', async () => {
await promptForAlksAccountAndRole({});
const promptConfig = mockPromptFn.mock.calls[0][0][0];
const results = await promptConfig.source({}, '');
expect(results.length).toBe(mockAccounts.length);
});

it('should return only matching results when input is provided', async () => {
await promptForAlksAccountAndRole({});
const promptConfig = mockPromptFn.mock.calls[0][0][0];
const results = await promptConfig.source({}, 'devlabs');
expect(results.length).toBeGreaterThan(0);
expect(results.every((r: string) => r.includes('devlabs'))).toBe(true);
});

it('should return no results when input does not match any account', async () => {
await promptForAlksAccountAndRole({});
const promptConfig = mockPromptFn.mock.calls[0][0][0];
const results = await promptConfig.source({}, 'rafa');
expect(results.length).toBe(0);
});

it('should throw an error if no accounts are found', async () => {
Expand Down
21 changes: 18 additions & 3 deletions src/lib/promptForAlksAccountAndRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export interface AlksAccountPromptData {
type: string;
name: string;
message: string;
choices: string[];
source: (
answers: Record<string, unknown>,
input: string | undefined
) => Promise<string[]>;
pageSize: number;
default?: string;
}
Expand Down Expand Up @@ -69,11 +72,23 @@ export async function promptForAlksAccountAndRole(
throw new Error('No accounts found.');
}

const allChoices = indexedAlksAccounts.map((a) => a.formattedOutput);

const promptData: AlksAccountPromptData = {
type: 'list',
type: 'autocomplete',
name: 'alksAccount',
message: opts.prompt,
choices: indexedAlksAccounts.map((a) => a.formattedOutput), // Use the formatted output for choices
source: (
_answers: Record<string, unknown>,
input: string | undefined
): Promise<string[]> => {
if (!input) {
return Promise.resolve(allChoices);
}
return Promise.resolve(
allChoices.filter((c) => c.toLowerCase().includes(input.toLowerCase()))
);
},
pageSize: 15,
};

Expand Down
5 changes: 5 additions & 0 deletions src/types/inquirer-autocomplete-prompt.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module 'inquirer-autocomplete-prompt' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const AutocompletePrompt: any;
export default AutocompletePrompt;
}
Loading