Compare commits
1 Commits
task-maste
...
docs/auto-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2f9baccdd |
@@ -8,12 +8,12 @@
|
|||||||
],
|
],
|
||||||
"commit": false,
|
"commit": false,
|
||||||
"fixed": [],
|
"fixed": [],
|
||||||
|
"linked": [
|
||||||
|
["task-master-ai", "@tm/cli", "@tm/core"]
|
||||||
|
],
|
||||||
"access": "public",
|
"access": "public",
|
||||||
"baseBranch": "main",
|
"baseBranch": "main",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"docs",
|
"docs"
|
||||||
"@tm/cli",
|
|
||||||
"@tm/core",
|
|
||||||
"@tm/build-config"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
"task-master-ai": minor
|
|
||||||
---
|
|
||||||
|
|
||||||
Testing one more pre-release iteration
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"mode": "pre",
|
|
||||||
"tag": "rc",
|
|
||||||
"initialVersions": {
|
|
||||||
"task-master-ai": "0.26.0",
|
|
||||||
"@tm/cli": "0.26.0",
|
|
||||||
"docs": "0.0.2",
|
|
||||||
"extension": "0.24.2",
|
|
||||||
"@tm/build-config": "1.0.0",
|
|
||||||
"@tm/core": "0.26.0"
|
|
||||||
},
|
|
||||||
"changesets": [
|
|
||||||
"easy-deer-heal",
|
|
||||||
"moody-oranges-slide",
|
|
||||||
"odd-otters-tan",
|
|
||||||
"wild-ears-look"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
"task-master-ai": minor
|
|
||||||
---
|
|
||||||
|
|
||||||
@tm/cli: add auto-update functionality to every command
|
|
||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -92,9 +92,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
TM_PUBLIC_BASE_DOMAIN: ${{ secrets.TM_PUBLIC_BASE_DOMAIN }}
|
|
||||||
TM_PUBLIC_SUPABASE_URL: ${{ secrets.TM_PUBLIC_SUPABASE_URL }}
|
|
||||||
TM_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.TM_PUBLIC_SUPABASE_ANON_KEY }}
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|||||||
3
.github/workflows/pre-release.yml
vendored
3
.github/workflows/pre-release.yml
vendored
@@ -75,9 +75,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
TM_PUBLIC_BASE_DOMAIN: ${{ secrets.TM_PUBLIC_BASE_DOMAIN }}
|
|
||||||
TM_PUBLIC_SUPABASE_URL: ${{ secrets.TM_PUBLIC_SUPABASE_URL }}
|
|
||||||
TM_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.TM_PUBLIC_SUPABASE_ANON_KEY }}
|
|
||||||
|
|
||||||
- name: Create Release Candidate Pull Request or Publish Release Candidate to npm
|
- name: Create Release Candidate Pull Request or Publish Release Candidate to npm
|
||||||
uses: changesets/action@v1
|
uses: changesets/action@v1
|
||||||
|
|||||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: "npm"
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Cache node_modules
|
- name: Cache node_modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -46,9 +46,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
TM_PUBLIC_BASE_DOMAIN: ${{ secrets.TM_PUBLIC_BASE_DOMAIN }}
|
|
||||||
TM_PUBLIC_SUPABASE_URL: ${{ secrets.TM_PUBLIC_SUPABASE_URL }}
|
|
||||||
TM_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.TM_PUBLIC_SUPABASE_ANON_KEY }}
|
|
||||||
|
|
||||||
- name: Create Release Pull Request or Publish to npm
|
- name: Create Release Pull Request or Publish to npm
|
||||||
uses: changesets/action@v1
|
uses: changesets/action@v1
|
||||||
|
|||||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,28 +1,5 @@
|
|||||||
# task-master-ai
|
# task-master-ai
|
||||||
|
|
||||||
## 1.0.0-rc.2
|
|
||||||
|
|
||||||
### Major Changes
|
|
||||||
|
|
||||||
- [#1217](https://github.com/eyaltoledano/claude-task-master/pull/1217) [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - @tm/cli: add auto-update functionality to every command
|
|
||||||
|
|
||||||
## 0.27.0-rc.1
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [`255b9f0`](https://github.com/eyaltoledano/claude-task-master/commit/255b9f0334555b0063280abde701445cd62fa11b) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Testing one more pre-release iteration
|
|
||||||
|
|
||||||
## 0.27.0-rc.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213) [`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Test out the RC
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- Updated dependencies [[`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)]:
|
|
||||||
- @tm/cli@0.27.0-rc.0
|
|
||||||
|
|
||||||
## 0.26.0
|
## 0.26.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
# @tm/cli
|
# @tm/cli
|
||||||
|
|
||||||
## 0.27.0-rc.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#1213](https://github.com/eyaltoledano/claude-task-master/pull/1213) [`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - testing this stuff out to see how the release candidate works with monorepo
|
|
||||||
|
|
||||||
## 1.1.0-rc.0
|
## 1.1.0-rc.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tm/cli",
|
"name": "@tm/cli",
|
||||||
"version": "0.27.0-rc.0",
|
"version": "0.26.0",
|
||||||
"description": "Task Master CLI - Command line interface for task management",
|
"description": "Task Master CLI - Command line interface for task management",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -6,7 +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 ora, { Ora } from 'ora';
|
import ora from 'ora';
|
||||||
import {
|
import {
|
||||||
AuthManager,
|
AuthManager,
|
||||||
AuthenticationError,
|
AuthenticationError,
|
||||||
@@ -49,15 +49,8 @@ export class ContextCommand extends Command {
|
|||||||
this.addClearCommand();
|
this.addClearCommand();
|
||||||
this.addSetCommand();
|
this.addSetCommand();
|
||||||
|
|
||||||
// Accept optional positional argument for brief ID or Hamster URL
|
// Default action shows current context
|
||||||
this.argument('[briefOrUrl]', 'Brief ID or Hamster brief URL');
|
this.action(async () => {
|
||||||
|
|
||||||
// Default action: if an argument is provided, resolve and set context; else show
|
|
||||||
this.action(async (briefOrUrl?: string) => {
|
|
||||||
if (briefOrUrl && briefOrUrl.trim().length > 0) {
|
|
||||||
await this.executeSetFromBriefInput(briefOrUrl.trim());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.executeShow();
|
await this.executeShow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -448,142 +441,6 @@ export class ContextCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute setting context from a brief ID or Hamster URL
|
|
||||||
*/
|
|
||||||
private async executeSetFromBriefInput(briefOrUrl: string): Promise<void> {
|
|
||||||
let spinner: Ora | undefined;
|
|
||||||
try {
|
|
||||||
// Check authentication
|
|
||||||
if (!this.authManager.isAuthenticated()) {
|
|
||||||
ui.displayError('Not authenticated. Run "tm auth login" first.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
spinner = ora('Resolving brief...');
|
|
||||||
spinner.start();
|
|
||||||
|
|
||||||
// Extract brief ID
|
|
||||||
const briefId = this.extractBriefId(briefOrUrl);
|
|
||||||
if (!briefId) {
|
|
||||||
spinner.fail('Could not extract a brief ID from the provided input');
|
|
||||||
ui.displayError(
|
|
||||||
`Provide a valid brief ID or a Hamster brief URL, e.g. https://${process.env.TM_PUBLIC_BASE_DOMAIN}/home/hamster/briefs/<id>`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch brief and resolve its organization
|
|
||||||
const brief = await this.authManager.getBrief(briefId);
|
|
||||||
if (!brief) {
|
|
||||||
spinner.fail('Brief not found or you do not have access');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch org to get a friendly name (optional)
|
|
||||||
let orgName: string | undefined;
|
|
||||||
try {
|
|
||||||
const org = await this.authManager.getOrganization(brief.accountId);
|
|
||||||
orgName = org?.name;
|
|
||||||
} catch {
|
|
||||||
// Non-fatal if org lookup fails
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update context: set org and brief
|
|
||||||
const briefName = `Brief ${brief.id.slice(0, 8)}`;
|
|
||||||
await this.authManager.updateContext({
|
|
||||||
orgId: brief.accountId,
|
|
||||||
orgName,
|
|
||||||
briefId: brief.id,
|
|
||||||
briefName
|
|
||||||
});
|
|
||||||
|
|
||||||
spinner.succeed('Context set from brief');
|
|
||||||
console.log(
|
|
||||||
chalk.gray(
|
|
||||||
` Organization: ${orgName || brief.accountId}\n Brief: ${briefName}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setLastResult({
|
|
||||||
success: true,
|
|
||||||
action: 'set',
|
|
||||||
context: this.authManager.getContext() || undefined,
|
|
||||||
message: 'Context set from brief'
|
|
||||||
});
|
|
||||||
} catch (error: any) {
|
|
||||||
try {
|
|
||||||
if (spinner?.isSpinning) spinner.stop();
|
|
||||||
} catch {}
|
|
||||||
this.handleError(error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a brief ID from raw input (ID or Hamster URL)
|
|
||||||
*/
|
|
||||||
private extractBriefId(input: string): string | null {
|
|
||||||
const raw = input?.trim() ?? '';
|
|
||||||
if (!raw) return null;
|
|
||||||
|
|
||||||
const parseUrl = (s: string): URL | null => {
|
|
||||||
try {
|
|
||||||
return new URL(s);
|
|
||||||
} catch {}
|
|
||||||
try {
|
|
||||||
return new URL(`https://${s}`);
|
|
||||||
} catch {}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fromParts = (path: string): string | null => {
|
|
||||||
const parts = path.split('/').filter(Boolean);
|
|
||||||
const briefsIdx = parts.lastIndexOf('briefs');
|
|
||||||
const candidate =
|
|
||||||
briefsIdx >= 0 && parts.length > briefsIdx + 1
|
|
||||||
? parts[briefsIdx + 1]
|
|
||||||
: parts[parts.length - 1];
|
|
||||||
return candidate?.trim() || null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 1) URL (absolute or scheme‑less)
|
|
||||||
const url = parseUrl(raw);
|
|
||||||
if (url) {
|
|
||||||
const qId = url.searchParams.get('id') || url.searchParams.get('briefId');
|
|
||||||
const candidate = (qId || fromParts(url.pathname)) ?? null;
|
|
||||||
if (candidate) {
|
|
||||||
// Light sanity check; let API be the final validator
|
|
||||||
if (this.isLikelyId(candidate) || candidate.length >= 8)
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Looks like a path without scheme
|
|
||||||
if (raw.includes('/')) {
|
|
||||||
const candidate = fromParts(raw);
|
|
||||||
if (candidate && (this.isLikelyId(candidate) || candidate.length >= 8)) {
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) Fallback: raw token
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Heuristic to check if a string looks like a brief ID (UUID-like)
|
|
||||||
*/
|
|
||||||
private isLikelyId(value: string): boolean {
|
|
||||||
const uuidRegex =
|
|
||||||
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
||||||
const ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i; // ULID
|
|
||||||
const slugRegex = /^[A-Za-z0-9_-]{16,}$/; // general token
|
|
||||||
return (
|
|
||||||
uuidRegex.test(value) || ulidRegex.test(value) || slugRegex.test(value)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set context directly from options
|
* Set context directly from options
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,13 +13,6 @@ export { SetStatusCommand } from './commands/set-status.command.js';
|
|||||||
// UI utilities (for other commands to use)
|
// UI utilities (for other commands to use)
|
||||||
export * as ui from './utils/ui.js';
|
export * as ui from './utils/ui.js';
|
||||||
|
|
||||||
// Auto-update utilities
|
|
||||||
export {
|
|
||||||
checkForUpdate,
|
|
||||||
performAutoUpdate,
|
|
||||||
displayUpgradeNotification
|
|
||||||
} from './utils/auto-update.js';
|
|
||||||
|
|
||||||
// Re-export commonly used types from tm-core
|
// Re-export commonly used types from tm-core
|
||||||
export type {
|
export type {
|
||||||
Task,
|
Task,
|
||||||
|
|||||||
@@ -1,238 +0,0 @@
|
|||||||
/**
|
|
||||||
* @fileoverview Auto-update utilities for task-master-ai CLI
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { spawn } from 'child_process';
|
|
||||||
import https from 'https';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import ora from 'ora';
|
|
||||||
import boxen from 'boxen';
|
|
||||||
import packageJson from '../../../../package.json' with { type: 'json' };
|
|
||||||
|
|
||||||
export interface UpdateInfo {
|
|
||||||
currentVersion: string;
|
|
||||||
latestVersion: string;
|
|
||||||
needsUpdate: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current version from package.json
|
|
||||||
*/
|
|
||||||
function getCurrentVersion(): string {
|
|
||||||
try {
|
|
||||||
return packageJson.version;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Could not read package.json for version info');
|
|
||||||
return '0.0.0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare semantic versions with proper pre-release handling
|
|
||||||
* @param v1 - First version
|
|
||||||
* @param v2 - Second version
|
|
||||||
* @returns -1 if v1 < v2, 0 if v1 = v2, 1 if v1 > v2
|
|
||||||
*/
|
|
||||||
function compareVersions(v1: string, v2: string): number {
|
|
||||||
const toParts = (v: string) => {
|
|
||||||
const [core, pre = ''] = v.split('-', 2);
|
|
||||||
const nums = core.split('.').map((n) => Number.parseInt(n, 10) || 0);
|
|
||||||
return { nums, pre };
|
|
||||||
};
|
|
||||||
|
|
||||||
const a = toParts(v1);
|
|
||||||
const b = toParts(v2);
|
|
||||||
const len = Math.max(a.nums.length, b.nums.length);
|
|
||||||
|
|
||||||
// Compare numeric parts
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
const d = (a.nums[i] || 0) - (b.nums[i] || 0);
|
|
||||||
if (d !== 0) return d < 0 ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle pre-release comparison
|
|
||||||
if (a.pre && !b.pre) return -1; // prerelease < release
|
|
||||||
if (!a.pre && b.pre) return 1; // release > prerelease
|
|
||||||
if (a.pre === b.pre) return 0; // same or both empty
|
|
||||||
return a.pre < b.pre ? -1 : 1; // basic prerelease tie-break
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for newer version of task-master-ai
|
|
||||||
*/
|
|
||||||
export async function checkForUpdate(
|
|
||||||
currentVersionOverride?: string
|
|
||||||
): Promise<UpdateInfo> {
|
|
||||||
const currentVersion = currentVersionOverride || getCurrentVersion();
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const options = {
|
|
||||||
hostname: 'registry.npmjs.org',
|
|
||||||
path: '/task-master-ai',
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/vnd.npm.install-v1+json',
|
|
||||||
'User-Agent': `task-master-ai/${currentVersion}`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const req = https.request(options, (res) => {
|
|
||||||
let data = '';
|
|
||||||
|
|
||||||
res.on('data', (chunk) => {
|
|
||||||
data += chunk;
|
|
||||||
});
|
|
||||||
|
|
||||||
res.on('end', () => {
|
|
||||||
try {
|
|
||||||
if (res.statusCode !== 200)
|
|
||||||
throw new Error(`npm registry status ${res.statusCode}`);
|
|
||||||
const npmData = JSON.parse(data);
|
|
||||||
const latestVersion = npmData['dist-tags']?.latest || currentVersion;
|
|
||||||
|
|
||||||
const needsUpdate =
|
|
||||||
compareVersions(currentVersion, latestVersion) < 0;
|
|
||||||
|
|
||||||
resolve({
|
|
||||||
currentVersion,
|
|
||||||
latestVersion,
|
|
||||||
needsUpdate
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
resolve({
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: currentVersion,
|
|
||||||
needsUpdate: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('error', () => {
|
|
||||||
resolve({
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: currentVersion,
|
|
||||||
needsUpdate: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.setTimeout(3000, () => {
|
|
||||||
req.destroy();
|
|
||||||
resolve({
|
|
||||||
currentVersion,
|
|
||||||
latestVersion: currentVersion,
|
|
||||||
needsUpdate: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display upgrade notification message
|
|
||||||
*/
|
|
||||||
export function displayUpgradeNotification(
|
|
||||||
currentVersion: string,
|
|
||||||
latestVersion: string
|
|
||||||
) {
|
|
||||||
const message = boxen(
|
|
||||||
`${chalk.blue.bold('Update Available!')} ${chalk.dim(currentVersion)} → ${chalk.green(latestVersion)}\n\n` +
|
|
||||||
`Auto-updating to the latest version with new features and bug fixes...`,
|
|
||||||
{
|
|
||||||
padding: 1,
|
|
||||||
margin: { top: 1, bottom: 1 },
|
|
||||||
borderColor: 'yellow',
|
|
||||||
borderStyle: 'round'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically update task-master-ai to the latest version
|
|
||||||
*/
|
|
||||||
export async function performAutoUpdate(
|
|
||||||
latestVersion: string
|
|
||||||
): Promise<boolean> {
|
|
||||||
if (process.env.TASKMASTER_SKIP_AUTO_UPDATE === '1' || process.env.CI) {
|
|
||||||
console.log(
|
|
||||||
chalk.dim('Skipping auto-update (TASKMASTER_SKIP_AUTO_UPDATE/CI).')
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const spinner = ora({
|
|
||||||
text: chalk.blue(
|
|
||||||
`Updating task-master-ai to version ${chalk.green(latestVersion)}`
|
|
||||||
),
|
|
||||||
spinner: 'dots',
|
|
||||||
color: 'blue'
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const updateProcess = spawn(
|
|
||||||
'npm',
|
|
||||||
[
|
|
||||||
'install',
|
|
||||||
'-g',
|
|
||||||
`task-master-ai@${latestVersion}`,
|
|
||||||
'--no-fund',
|
|
||||||
'--no-audit',
|
|
||||||
'--loglevel=warn'
|
|
||||||
],
|
|
||||||
{
|
|
||||||
stdio: ['ignore', 'pipe', 'pipe']
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let errorOutput = '';
|
|
||||||
|
|
||||||
updateProcess.stdout.on('data', () => {
|
|
||||||
// Update spinner text with progress
|
|
||||||
spinner.text = chalk.blue(
|
|
||||||
`Installing task-master-ai@${latestVersion}...`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
updateProcess.stderr.on('data', (data) => {
|
|
||||||
errorOutput += data.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
updateProcess.on('close', (code) => {
|
|
||||||
if (code === 0) {
|
|
||||||
spinner.succeed(
|
|
||||||
chalk.green(
|
|
||||||
`Successfully updated to version ${chalk.bold(latestVersion)}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
chalk.dim('Please restart your command to use the new version.')
|
|
||||||
);
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
spinner.fail(chalk.red('Auto-update failed'));
|
|
||||||
console.log(
|
|
||||||
chalk.cyan(
|
|
||||||
`Please run manually: npm install -g task-master-ai@${latestVersion}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (errorOutput) {
|
|
||||||
console.log(chalk.dim(`Error: ${errorOutput.trim()}`));
|
|
||||||
}
|
|
||||||
resolve(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateProcess.on('error', (error) => {
|
|
||||||
spinner.fail(chalk.red('Auto-update failed'));
|
|
||||||
console.log(chalk.red('Error:'), error.message);
|
|
||||||
console.log(
|
|
||||||
chalk.cyan(
|
|
||||||
`Please run manually: npm install -g task-master-ai@${latestVersion}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
resolve(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -83,8 +83,6 @@ Taskmaster uses two primary methods for configuration:
|
|||||||
- `VERTEX_PROJECT_ID`: Your Google Cloud project ID for Vertex AI. Required when using the 'vertex' provider.
|
- `VERTEX_PROJECT_ID`: Your Google Cloud project ID for Vertex AI. Required when using the 'vertex' provider.
|
||||||
- `VERTEX_LOCATION`: Google Cloud region for Vertex AI (e.g., 'us-central1'). Default is 'us-central1'.
|
- `VERTEX_LOCATION`: Google Cloud region for Vertex AI (e.g., 'us-central1'). Default is 'us-central1'.
|
||||||
- `GOOGLE_APPLICATION_CREDENTIALS`: Path to service account credentials JSON file for Google Cloud auth (alternative to API key for Vertex AI).
|
- `GOOGLE_APPLICATION_CREDENTIALS`: Path to service account credentials JSON file for Google Cloud auth (alternative to API key for Vertex AI).
|
||||||
- **Optional Auto-Update Control:**
|
|
||||||
- `TASKMASTER_SKIP_AUTO_UPDATE`: Set to '1' to disable automatic updates. Also automatically disabled in CI environments (when `CI` environment variable is set).
|
|
||||||
|
|
||||||
**Important:** Settings like model ID selections (`main`, `research`, `fallback`), `maxTokens`, `temperature`, `logLevel`, `defaultSubtasks`, `defaultPriority`, and `projectName` are **managed in `.taskmaster/config.json`** (or `.taskmasterconfig` for unmigrated projects), not environment variables.
|
**Important:** Settings like model ID selections (`main`, `research`, `fallback`), `maxTokens`, `temperature`, `logLevel`, `defaultSubtasks`, `defaultPriority`, and `projectName` are **managed in `.taskmaster/config.json`** (or `.taskmasterconfig` for unmigrated projects), not environment variables.
|
||||||
|
|
||||||
|
|||||||
@@ -99,8 +99,30 @@ sidebarTitle: "CLI Commands"
|
|||||||
|
|
||||||
# Set status for subtasks
|
# Set status for subtasks
|
||||||
task-master set-status --id=1.1,1.2 --status=<status>
|
task-master set-status --id=1.1,1.2 --status=<status>
|
||||||
|
|
||||||
|
# Output in JSON format
|
||||||
|
task-master set-status --id=<id> --status=<status> --format=json
|
||||||
|
|
||||||
|
# Silent mode (suppress output)
|
||||||
|
task-master set-status --id=<id> --status=<status> --silent
|
||||||
|
|
||||||
|
# Specify project root directory
|
||||||
|
task-master set-status --id=<id> --status=<status> --project=/path/to/project
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Valid Status Values:**
|
||||||
|
- `pending` - Ready to work on
|
||||||
|
- `in-progress` - Currently being worked on
|
||||||
|
- `done` - Completed and verified
|
||||||
|
- `deferred` - Postponed
|
||||||
|
- `cancelled` - No longer needed
|
||||||
|
- `blocked` - Waiting on external factors
|
||||||
|
- `review` - Ready for review
|
||||||
|
|
||||||
|
**Output Formats:**
|
||||||
|
- `text` (default) - Human-readable colored output
|
||||||
|
- `json` - Machine-readable JSON format for programmatic usage
|
||||||
|
|
||||||
When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
|
When marking a task as "done", all of its subtasks will automatically be marked as "done" as well.
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
## 0.25.0-rc.0
|
|
||||||
|
|
||||||
### Minor Changes
|
|
||||||
|
|
||||||
- [#1201](https://github.com/eyaltoledano/claude-task-master/pull/1201) [`83af314`](https://github.com/eyaltoledano/claude-task-master/commit/83af314879fc0e563581161c60d2bd089899313e) Thanks [@losolosol](https://github.com/losolosol)! - Added a Start Build button to the VSCODE Task Properties Right Panel
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- Updated dependencies [[`137ef36`](https://github.com/eyaltoledano/claude-task-master/commit/137ef362789a9cdfdb1925e35e0438c1fa6c69ee)]:
|
|
||||||
- task-master-ai@0.27.0-rc.0
|
|
||||||
|
|
||||||
## 0.24.2
|
## 0.24.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"displayName": "TaskMaster",
|
"displayName": "TaskMaster",
|
||||||
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
|
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
|
||||||
"version": "0.25.0-rc.0",
|
"version": "0.24.2",
|
||||||
"publisher": "Hamster",
|
"publisher": "Hamster",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
44
output.txt
Normal file
44
output.txt
Normal file
File diff suppressed because one or more lines are too long
10
package-lock.json
generated
10
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "1.0.0-rc.2",
|
"version": "0.26.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "1.0.0-rc.2",
|
"version": "0.26.0",
|
||||||
"license": "MIT WITH Commons-Clause",
|
"license": "MIT WITH Commons-Clause",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
"@inquirer/search": "^3.0.15",
|
"@inquirer/search": "^3.0.15",
|
||||||
"@openrouter/ai-sdk-provider": "^0.4.5",
|
"@openrouter/ai-sdk-provider": "^0.4.5",
|
||||||
"@streamparser/json": "^0.0.22",
|
"@streamparser/json": "^0.0.22",
|
||||||
|
"@tm/cli": "*",
|
||||||
"ai": "^4.3.10",
|
"ai": "^4.3.10",
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
@@ -70,7 +71,6 @@
|
|||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@changesets/changelog-github": "^0.5.1",
|
"@changesets/changelog-github": "^0.5.1",
|
||||||
"@changesets/cli": "^2.28.1",
|
"@changesets/cli": "^2.28.1",
|
||||||
"@tm/cli": "*",
|
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/marked-terminal": "^6.1.1",
|
"@types/marked-terminal": "^6.1.1",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
},
|
},
|
||||||
"apps/cli": {
|
"apps/cli": {
|
||||||
"name": "@tm/cli",
|
"name": "@tm/cli",
|
||||||
"version": "0.27.0-rc.0",
|
"version": "0.26.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tm/core": "*",
|
"@tm/core": "*",
|
||||||
@@ -365,7 +365,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"apps/extension": {
|
"apps/extension": {
|
||||||
"version": "0.25.0-rc.0",
|
"version": "0.24.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"task-master-ai": "*"
|
"task-master-ai": "*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "task-master-ai",
|
"name": "task-master-ai",
|
||||||
"version": "0.27.0-rc.1",
|
"version": "0.26.0",
|
||||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -65,6 +65,7 @@
|
|||||||
"@inquirer/search": "^3.0.15",
|
"@inquirer/search": "^3.0.15",
|
||||||
"@openrouter/ai-sdk-provider": "^0.4.5",
|
"@openrouter/ai-sdk-provider": "^0.4.5",
|
||||||
"@streamparser/json": "^0.0.22",
|
"@streamparser/json": "^0.0.22",
|
||||||
|
"@tm/cli": "*",
|
||||||
"ai": "^4.3.10",
|
"ai": "^4.3.10",
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
@@ -120,7 +121,6 @@
|
|||||||
"whatwg-url": "^11.0.0"
|
"whatwg-url": "^11.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tm/cli": "*",
|
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@changesets/changelog-github": "^0.5.1",
|
"@changesets/changelog-github": "^0.5.1",
|
||||||
"@changesets/cli": "^2.28.1",
|
"@changesets/cli": "^2.28.1",
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ export class SupabaseTaskRepository {
|
|||||||
taskId: string,
|
taskId: string,
|
||||||
updates: Partial<Task>
|
updates: Partial<Task>
|
||||||
): Promise<Task> {
|
): Promise<Task> {
|
||||||
|
|
||||||
// Get the current context to determine briefId
|
// Get the current context to determine briefId
|
||||||
const authManager = AuthManager.getInstance();
|
const authManager = AuthManager.getInstance();
|
||||||
const context = authManager.getContext();
|
const context = authManager.getContext();
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ export class TaskService {
|
|||||||
newStatus: TaskStatus;
|
newStatus: TaskStatus;
|
||||||
taskId: string;
|
taskId: string;
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
// Ensure we have storage
|
// Ensure we have storage
|
||||||
if (!this.storage) {
|
if (!this.storage) {
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ export class ApiStorage implements IStorage {
|
|||||||
updates: Partial<Task>,
|
updates: Partial<Task>,
|
||||||
tag?: string
|
tag?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export class FileStorage implements IStorage {
|
|||||||
*/
|
*/
|
||||||
async loadTask(taskId: string, tag?: string): Promise<Task | null> {
|
async loadTask(taskId: string, tag?: string): Promise<Task | null> {
|
||||||
const tasks = await this.loadTasks(tag);
|
const tasks = await this.loadTasks(tag);
|
||||||
return tasks.find((task) => task.id === taskId) || null;
|
return tasks.find(task => task.id === taskId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import {
|
|||||||
ShowCommand,
|
ShowCommand,
|
||||||
AuthCommand,
|
AuthCommand,
|
||||||
ContextCommand,
|
ContextCommand,
|
||||||
SetStatusCommand,
|
SetStatusCommand
|
||||||
checkForUpdate,
|
|
||||||
performAutoUpdate,
|
|
||||||
displayUpgradeNotification
|
|
||||||
} from '@tm/cli';
|
} from '@tm/cli';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -85,7 +82,8 @@ import {
|
|||||||
isConfigFilePresent,
|
isConfigFilePresent,
|
||||||
getAvailableModels,
|
getAvailableModels,
|
||||||
getBaseUrlForRole,
|
getBaseUrlForRole,
|
||||||
getDefaultNumTasks
|
getDefaultNumTasks,
|
||||||
|
getDefaultSubtasks
|
||||||
} from './config-manager.js';
|
} from './config-manager.js';
|
||||||
|
|
||||||
import { CUSTOM_PROVIDERS } from '../../src/constants/providers.js';
|
import { CUSTOM_PROVIDERS } from '../../src/constants/providers.js';
|
||||||
@@ -5115,6 +5113,122 @@ function setupCLI() {
|
|||||||
return programInstance;
|
return programInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for newer version of task-master-ai
|
||||||
|
* @returns {Promise<{currentVersion: string, latestVersion: string, needsUpdate: boolean}>}
|
||||||
|
*/
|
||||||
|
async function checkForUpdate() {
|
||||||
|
// Get current version from package.json ONLY
|
||||||
|
const currentVersion = getTaskMasterVersion();
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// Get the latest version from npm registry
|
||||||
|
const options = {
|
||||||
|
hostname: 'registry.npmjs.org',
|
||||||
|
path: '/task-master-ai',
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/vnd.npm.install-v1+json' // Lightweight response
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = https.request(options, (res) => {
|
||||||
|
let data = '';
|
||||||
|
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const npmData = JSON.parse(data);
|
||||||
|
const latestVersion = npmData['dist-tags']?.latest || currentVersion;
|
||||||
|
|
||||||
|
// Compare versions
|
||||||
|
const needsUpdate =
|
||||||
|
compareVersions(currentVersion, latestVersion) < 0;
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
currentVersion,
|
||||||
|
latestVersion,
|
||||||
|
needsUpdate
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log('debug', `Error parsing npm response: ${error.message}`);
|
||||||
|
resolve({
|
||||||
|
currentVersion,
|
||||||
|
latestVersion: currentVersion,
|
||||||
|
needsUpdate: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (error) => {
|
||||||
|
log('debug', `Error checking for updates: ${error.message}`);
|
||||||
|
resolve({
|
||||||
|
currentVersion,
|
||||||
|
latestVersion: currentVersion,
|
||||||
|
needsUpdate: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set a timeout to avoid hanging if npm is slow
|
||||||
|
req.setTimeout(3000, () => {
|
||||||
|
req.abort();
|
||||||
|
log('debug', 'Update check timed out');
|
||||||
|
resolve({
|
||||||
|
currentVersion,
|
||||||
|
latestVersion: currentVersion,
|
||||||
|
needsUpdate: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare semantic versions
|
||||||
|
* @param {string} v1 - First version
|
||||||
|
* @param {string} v2 - Second version
|
||||||
|
* @returns {number} -1 if v1 < v2, 0 if v1 = v2, 1 if v1 > v2
|
||||||
|
*/
|
||||||
|
function compareVersions(v1, v2) {
|
||||||
|
const v1Parts = v1.split('.').map((p) => parseInt(p, 10));
|
||||||
|
const v2Parts = v2.split('.').map((p) => parseInt(p, 10));
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
|
||||||
|
const v1Part = v1Parts[i] || 0;
|
||||||
|
const v2Part = v2Parts[i] || 0;
|
||||||
|
|
||||||
|
if (v1Part < v2Part) return -1;
|
||||||
|
if (v1Part > v2Part) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display upgrade notification message
|
||||||
|
* @param {string} currentVersion - Current version
|
||||||
|
* @param {string} latestVersion - Latest version
|
||||||
|
*/
|
||||||
|
function displayUpgradeNotification(currentVersion, latestVersion) {
|
||||||
|
const message = boxen(
|
||||||
|
`${chalk.blue.bold('Update Available!')} ${chalk.dim(currentVersion)} → ${chalk.green(latestVersion)}\n\n` +
|
||||||
|
`Run ${chalk.cyan('npm i task-master-ai@latest -g')} to update to the latest version with new features and bug fixes.`,
|
||||||
|
{
|
||||||
|
padding: 1,
|
||||||
|
margin: { top: 1, bottom: 1 },
|
||||||
|
borderColor: 'yellow',
|
||||||
|
borderStyle: 'round'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse arguments and run the CLI
|
* Parse arguments and run the CLI
|
||||||
* @param {Array} argv - Command-line arguments
|
* @param {Array} argv - Command-line arguments
|
||||||
@@ -5133,8 +5247,7 @@ async function runCLI(argv = process.argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the update check in the background - don't await yet
|
// Start the update check in the background - don't await yet
|
||||||
const currentVersion = getTaskMasterVersion();
|
const updateCheckPromise = checkForUpdate();
|
||||||
const updateCheckPromise = checkForUpdate(currentVersion);
|
|
||||||
|
|
||||||
// Setup and parse
|
// Setup and parse
|
||||||
// NOTE: getConfig() might be called during setupCLI->registerCommands if commands need config
|
// NOTE: getConfig() might be called during setupCLI->registerCommands if commands need config
|
||||||
@@ -5145,18 +5258,10 @@ async function runCLI(argv = process.argv) {
|
|||||||
// After command execution, check if an update is available
|
// After command execution, check if an update is available
|
||||||
const updateInfo = await updateCheckPromise;
|
const updateInfo = await updateCheckPromise;
|
||||||
if (updateInfo.needsUpdate) {
|
if (updateInfo.needsUpdate) {
|
||||||
// Display the upgrade notification first
|
|
||||||
displayUpgradeNotification(
|
displayUpgradeNotification(
|
||||||
updateInfo.currentVersion,
|
updateInfo.currentVersion,
|
||||||
updateInfo.latestVersion
|
updateInfo.latestVersion
|
||||||
);
|
);
|
||||||
|
|
||||||
// Then automatically perform the update
|
|
||||||
const updateSuccess = await performAutoUpdate(updateInfo.latestVersion);
|
|
||||||
if (updateSuccess) {
|
|
||||||
// Exit gracefully after successful update
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if migration has occurred and show FYI notice once
|
// Check if migration has occurred and show FYI notice once
|
||||||
@@ -5280,4 +5385,11 @@ export function resolveComplexityReportPath({
|
|||||||
return tag !== 'master' ? base.replace('.json', `_${tag}.json`) : base;
|
return tag !== 'master' ? base.replace('.json', `_${tag}.json`) : base;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { registerCommands, setupCLI, runCLI };
|
export {
|
||||||
|
registerCommands,
|
||||||
|
setupCLI,
|
||||||
|
runCLI,
|
||||||
|
checkForUpdate,
|
||||||
|
compareVersions,
|
||||||
|
displayUpgradeNotification
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ describe('Complex Cross-Tag Scenarios', () => {
|
|||||||
// Create test directory
|
// Create test directory
|
||||||
testDir = fs.mkdtempSync(path.join(__dirname, 'test-'));
|
testDir = fs.mkdtempSync(path.join(__dirname, 'test-'));
|
||||||
process.chdir(testDir);
|
process.chdir(testDir);
|
||||||
// Keep integration timings deterministic
|
|
||||||
process.env.TASKMASTER_SKIP_AUTO_UPDATE = '1';
|
|
||||||
|
|
||||||
// Initialize task-master
|
// Initialize task-master
|
||||||
execSync(`node ${binPath} init --yes`, {
|
execSync(`node ${binPath} init --yes`, {
|
||||||
@@ -139,7 +137,6 @@ describe('Complex Cross-Tag Scenarios', () => {
|
|||||||
if (testDir && fs.existsSync(testDir)) {
|
if (testDir && fs.existsSync(testDir)) {
|
||||||
fs.rmSync(testDir, { recursive: true, force: true });
|
fs.rmSync(testDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
delete process.env.TASKMASTER_SKIP_AUTO_UPDATE;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Circular Dependency Detection', () => {
|
describe('Circular Dependency Detection', () => {
|
||||||
@@ -372,7 +369,7 @@ describe('Complex Cross-Tag Scenarios', () => {
|
|||||||
|
|
||||||
fs.writeFileSync(tasksPath, JSON.stringify(largeTaskSet, null, 2));
|
fs.writeFileSync(tasksPath, JSON.stringify(largeTaskSet, null, 2));
|
||||||
// Should complete within reasonable time
|
// Should complete within reasonable time
|
||||||
const timeout = process.env.CI ? 11000 : 6000;
|
const timeout = process.env.CI ? 10000 : 5000;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
execSync(
|
execSync(
|
||||||
`node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`,
|
`node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`,
|
||||||
|
|||||||
@@ -280,26 +280,8 @@ describe('Version comparison utility', () => {
|
|||||||
let compareVersions;
|
let compareVersions;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Import from @tm/cli instead of commands.js
|
const commandsModule = await import('../../scripts/modules/commands.js');
|
||||||
const { compareVersions: cv } = await import(
|
compareVersions = commandsModule.compareVersions;
|
||||||
'../../apps/cli/src/utils/auto-update.js'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create a local compareVersions function for testing
|
|
||||||
compareVersions = (v1, v2) => {
|
|
||||||
const v1Parts = v1.split('.').map((p) => parseInt(p, 10));
|
|
||||||
const v2Parts = v2.split('.').map((p) => parseInt(p, 10));
|
|
||||||
|
|
||||||
for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
|
|
||||||
const v1Part = v1Parts[i] || 0;
|
|
||||||
const v2Part = v2Parts[i] || 0;
|
|
||||||
|
|
||||||
if (v1Part < v2Part) return -1;
|
|
||||||
if (v1Part > v2Part) return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('compareVersions correctly compares semantic versions', () => {
|
test('compareVersions correctly compares semantic versions', () => {
|
||||||
@@ -321,9 +303,8 @@ describe('Update check functionality', () => {
|
|||||||
let consoleLogSpy;
|
let consoleLogSpy;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Import from @tm/cli instead of commands.js
|
const commandsModule = await import('../../scripts/modules/commands.js');
|
||||||
const cliModule = await import('../../apps/cli/src/utils/auto-update.js');
|
displayUpgradeNotification = commandsModule.displayUpgradeNotification;
|
||||||
displayUpgradeNotification = cliModule.displayUpgradeNotification;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export default defineConfig(
|
|||||||
},
|
},
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
copy: ['public'],
|
copy: ['public'],
|
||||||
ignoreWatch: ['node_modules', 'dist', 'tests'],
|
|
||||||
// Bundle only our workspace packages, keep npm dependencies external
|
// Bundle only our workspace packages, keep npm dependencies external
|
||||||
noExternal: [/^@tm\//],
|
noExternal: [/^@tm\//],
|
||||||
env: getBuildTimeEnvs()
|
env: getBuildTimeEnvs()
|
||||||
|
|||||||
Reference in New Issue
Block a user