feat: show brief title when listing brief instead of uuid

- add search for brief selection
This commit is contained in:
Ralph Khreish
2025-10-15 16:22:03 +02:00
parent 218b68a31e
commit c8228e913b
5 changed files with 193 additions and 29 deletions

View File

@@ -8,7 +8,10 @@
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },
"files": ["dist", "README.md"], "files": [
"dist",
"README.md"
],
"scripts": { "scripts": {
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"lint": "biome check src", "lint": "biome check src",
@@ -22,6 +25,7 @@
"test:ci": "vitest run --coverage --reporter=dot" "test:ci": "vitest run --coverage --reporter=dot"
}, },
"dependencies": { "dependencies": {
"@inquirer/search": "^3.2.0",
"@tm/core": "*", "@tm/core": "*",
"boxen": "^8.0.1", "boxen": "^8.0.1",
"chalk": "5.6.2", "chalk": "5.6.2",
@@ -41,12 +45,19 @@
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
}, },
"keywords": ["task-master", "cli", "task-management", "productivity"], "keywords": [
"task-master",
"cli",
"task-management",
"productivity"
],
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"typesVersions": { "typesVersions": {
"*": { "*": {
"*": ["src/*"] "*": [
"src/*"
]
} }
}, },
"version": "" "version": ""

View File

@@ -6,6 +6,7 @@
import { Command } from 'commander'; import { Command } from 'commander';
import chalk from 'chalk'; import chalk from 'chalk';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import search from '@inquirer/search';
import ora, { Ora } from 'ora'; import ora, { Ora } from 'ora';
import { import {
AuthManager, AuthManager,
@@ -156,10 +157,14 @@ export class ContextCommand extends Command {
if (context.briefName || context.briefId) { if (context.briefName || context.briefId) {
console.log(chalk.green('\n✓ Brief')); console.log(chalk.green('\n✓ Brief'));
if (context.briefName) { if (context.briefName && context.briefId) {
const shortId = context.briefId.slice(0, 8);
console.log(
chalk.white(` ${context.briefName} `) + chalk.gray(`(${shortId})`)
);
} else if (context.briefName) {
console.log(chalk.white(` ${context.briefName}`)); console.log(chalk.white(` ${context.briefName}`));
} } else if (context.briefId) {
if (context.briefId) {
console.log(chalk.gray(` ID: ${context.briefId}`)); console.log(chalk.gray(` ID: ${context.briefId}`));
} }
} }
@@ -324,25 +329,53 @@ export class ContextCommand extends Command {
}; };
} }
// Prompt for selection // Prompt for selection with search
const { selectedBrief } = await inquirer.prompt([ const selectedBrief = await search<(typeof briefs)[0] | null>({
{ message: 'Search for a brief:',
type: 'list', source: async (input) => {
name: 'selectedBrief', const searchTerm = input?.toLowerCase() || '';
message: 'Select a brief:',
choices: [ // Static option for no brief
{ name: '(No brief - organization level)', value: null }, const noBriefOption = {
...briefs.map((brief) => ({ name: '(No brief - organization level)',
name: `Brief ${brief.id} (${new Date(brief.createdAt).toLocaleDateString()})`, value: null as any,
value: brief description: 'Clear brief selection'
})) };
]
// Filter and map brief options
const briefOptions = briefs
.filter((brief) => {
if (!searchTerm) return true;
const title = brief.document?.title || '';
const shortId = brief.id.slice(0, 8);
// Search by title first, then by UUID
return (
title.toLowerCase().includes(searchTerm) ||
brief.id.toLowerCase().includes(searchTerm) ||
shortId.toLowerCase().includes(searchTerm)
);
})
.map((brief) => {
const title =
brief.document?.title || `Brief ${brief.id.slice(0, 8)}`;
const shortId = brief.id.slice(0, 8);
return {
name: `${title} ${chalk.gray(`(${shortId})`)}`,
value: brief
};
});
return [noBriefOption, ...briefOptions];
} }
]); });
if (selectedBrief) { if (selectedBrief) {
// Update context with brief // Update context with brief
const briefName = `Brief ${selectedBrief.id.slice(0, 8)}`; const briefName =
selectedBrief.document?.title ||
`Brief ${selectedBrief.id.slice(0, 8)}`;
this.authManager.updateContext({ this.authManager.updateContext({
briefId: selectedBrief.id, briefId: selectedBrief.id,
briefName: briefName briefName: briefName
@@ -354,7 +387,7 @@ export class ContextCommand extends Command {
success: true, success: true,
action: 'select-brief', action: 'select-brief',
context: this.authManager.getContext() || undefined, context: this.authManager.getContext() || undefined,
message: `Selected brief: ${selectedBrief.name}` message: `Selected brief: ${selectedBrief.document?.title}`
}; };
} else { } else {
// Clear brief selection // Clear brief selection
@@ -490,7 +523,8 @@ export class ContextCommand extends Command {
} }
// Update context: set org and brief // Update context: set org and brief
const briefName = `Brief ${brief.id.slice(0, 8)}`; const briefName =
brief.document?.title || `Brief ${brief.id.slice(0, 8)}`;
this.authManager.updateContext({ this.authManager.updateContext({
orgId: brief.accountId, orgId: brief.accountId,
orgName, orgName,

86
package-lock.json generated
View File

@@ -104,6 +104,7 @@
"name": "@tm/cli", "name": "@tm/cli",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@inquirer/search": "^3.2.0",
"@tm/core": "*", "@tm/core": "*",
"boxen": "^8.0.1", "boxen": "^8.0.1",
"chalk": "5.6.2", "chalk": "5.6.2",
@@ -124,6 +125,91 @@
"node": ">=18.0.0" "node": ">=18.0.0"
} }
}, },
"apps/cli/node_modules/@inquirer/ansi": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz",
"integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"apps/cli/node_modules/@inquirer/figures": {
"version": "1.0.14",
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz",
"integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"apps/cli/node_modules/@inquirer/search": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz",
"integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==",
"license": "MIT",
"dependencies": {
"@inquirer/core": "^10.3.0",
"@inquirer/figures": "^1.0.14",
"@inquirer/type": "^3.0.9",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
}
}
},
"apps/cli/node_modules/@inquirer/search/node_modules/@inquirer/core": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz",
"integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==",
"license": "MIT",
"dependencies": {
"@inquirer/ansi": "^1.0.1",
"@inquirer/figures": "^1.0.14",
"@inquirer/type": "^3.0.9",
"cli-width": "^4.1.0",
"mute-stream": "^2.0.0",
"signal-exit": "^4.1.0",
"wrap-ansi": "^6.2.0",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
}
}
},
"apps/cli/node_modules/@inquirer/search/node_modules/@inquirer/type": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz",
"integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
}
}
},
"apps/docs": { "apps/docs": {
"version": "0.0.6", "version": "0.0.6",
"devDependencies": { "devDependencies": {

View File

@@ -27,6 +27,12 @@ export interface Brief {
status: string; status: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
document?: {
id: string;
title: string;
document_name: string;
description?: string;
};
} }
/** /**
@@ -171,7 +177,12 @@ export class OrganizationService {
document_id, document_id,
status, status,
created_at, created_at,
updated_at updated_at,
document:document_id (
id,
document_name,
title
)
`) `)
.eq('account_id', orgId); .eq('account_id', orgId);
@@ -196,7 +207,14 @@ export class OrganizationService {
documentId: brief.document_id, documentId: brief.document_id,
status: brief.status, status: brief.status,
createdAt: brief.created_at, createdAt: brief.created_at,
updatedAt: brief.updated_at updatedAt: brief.updated_at,
document: brief.document
? {
id: brief.document.id,
document_name: brief.document.document_name,
title: brief.document.title
}
: undefined
})); }));
} catch (error) { } catch (error) {
if (error instanceof TaskMasterError) { if (error instanceof TaskMasterError) {
@@ -224,7 +242,13 @@ export class OrganizationService {
document_id, document_id,
status, status,
created_at, created_at,
updated_at updated_at,
document:document_id (
id,
document_name,
title,
description
)
`) `)
.eq('id', briefId) .eq('id', briefId)
.single(); .single();
@@ -253,7 +277,15 @@ export class OrganizationService {
documentId: briefData.document_id, documentId: briefData.document_id,
status: briefData.status, status: briefData.status,
createdAt: briefData.created_at, createdAt: briefData.created_at,
updatedAt: briefData.updated_at updatedAt: briefData.updated_at,
document: briefData.document
? {
id: briefData.document.id,
document_name: briefData.document.document_name,
title: briefData.document.title,
description: briefData.document.description
}
: undefined
}; };
} catch (error) { } catch (error) {
if (error instanceof TaskMasterError) { if (error instanceof TaskMasterError) {

View File

@@ -82,8 +82,8 @@ export class StorageFactory {
apiAccessToken: credentials.token, apiAccessToken: credentials.token,
apiEndpoint: apiEndpoint:
config.storage?.apiEndpoint || config.storage?.apiEndpoint ||
process.env.TM_PUBLIC_BASE_DOMAIN || process.env.TM_BASE_DOMAIN ||
'https://tryhamster.com/api' process.env.TM_PUBLIC_BASE_DOMAIN
}; };
config.storage = nextStorage; config.storage = nextStorage;
} }
@@ -112,6 +112,7 @@ export class StorageFactory {
apiAccessToken: credentials.token, apiAccessToken: credentials.token,
apiEndpoint: apiEndpoint:
config.storage?.apiEndpoint || config.storage?.apiEndpoint ||
process.env.TM_BASE_DOMAIN ||
process.env.TM_PUBLIC_BASE_DOMAIN || process.env.TM_PUBLIC_BASE_DOMAIN ||
'https://tryhamster.com/api' 'https://tryhamster.com/api'
}; };