trinity-method-sdk 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/cli/commands/deploy/gitignore.js +1 -0
- package/dist/cli/commands/update/index.js +15 -1
- package/dist/cli/commands/update/migration.d.ts +31 -0
- package/dist/cli/commands/update/migration.js +130 -0
- package/dist/cli/commands/update/pre-flight.d.ts +7 -2
- package/dist/cli/commands/update/pre-flight.js +20 -19
- package/dist/cli/commands/update/summary.js +6 -0
- package/dist/cli/commands/update/types.d.ts +2 -0
- package/dist/cli/commands/update/version.js +6 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.2.1] - 2026-02-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Legacy deployment migration in update command** - `trinity update` now detects pre-2.2.0
|
|
15
|
+
`trinity/` deployments at project root and automatically migrates them to `.claude/trinity/`
|
|
16
|
+
(Issue #14)
|
|
17
|
+
- New `migration.ts` module with `detectLegacyDeployment()`, `migrateLegacyDeployment()`,
|
|
18
|
+
and `updateGitignoreForMigration()`
|
|
19
|
+
- Pre-flight checks updated to recognize legacy layouts instead of failing
|
|
20
|
+
- Version detection falls back to `trinity/VERSION` for legacy deployments
|
|
21
|
+
- User knowledge base files preserved during migration
|
|
22
|
+
- **Gitignore migration in update command** - `trinity update` now updates `.gitignore`
|
|
23
|
+
patterns on every run, replacing old `trinity/` entries with current `.claude/trinity/`
|
|
24
|
+
patterns (Issue #14)
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **Restored `*CLAUDE.md` to deploy gitignore patterns** - `trinity deploy` now adds
|
|
29
|
+
`*CLAUDE.md` back to `.gitignore`, preventing project-specific CLAUDE.md files from being
|
|
30
|
+
committed to version control (Issue #14)
|
|
31
|
+
- **depcheck false positive for `markdownlint-cli`** - Added `markdownlint-cli` to depcheck
|
|
32
|
+
ignores in CI workflow since it is used by npm scripts, not imported in code
|
|
33
|
+
- **Integration test timeout on Windows CI** - Bumped integration test timeout from 60s to
|
|
34
|
+
120s in `jest.config.js` for slow Windows runners
|
|
35
|
+
|
|
10
36
|
## [2.2.0] - 2026-02-24
|
|
11
37
|
|
|
12
38
|
### Added
|
|
@@ -24,6 +24,7 @@ export async function updateGitignore(spinner) {
|
|
|
24
24
|
'# Trinity Method SDK',
|
|
25
25
|
'.claude/trinity/archive/',
|
|
26
26
|
'.claude/trinity/templates/',
|
|
27
|
+
'*CLAUDE.md',
|
|
27
28
|
];
|
|
28
29
|
// Check if Trinity section already exists
|
|
29
30
|
if (!gitignoreContent.includes('# Trinity Method SDK')) {
|
|
@@ -10,6 +10,7 @@ import chalk from 'chalk';
|
|
|
10
10
|
import inquirer from 'inquirer';
|
|
11
11
|
import { runUpdatePreflightChecks } from './pre-flight.js';
|
|
12
12
|
import { detectInstalledSDKVersion } from './version.js';
|
|
13
|
+
import { detectLegacyDeployment, migrateLegacyDeployment, updateGitignoreForMigration, } from './migration.js';
|
|
13
14
|
import { createUpdateBackup, restoreUserContent, rollbackFromBackup, cleanupBackup, } from './backup.js';
|
|
14
15
|
import { updateAgents } from './agents.js';
|
|
15
16
|
import { updateCommands } from './commands.js';
|
|
@@ -34,10 +35,23 @@ export async function update(options) {
|
|
|
34
35
|
knowledgeBaseUpdated: 0,
|
|
35
36
|
commandsUpdated: 0,
|
|
36
37
|
filesUpdated: 0,
|
|
38
|
+
legacyMigrated: false,
|
|
39
|
+
gitignoreUpdated: false,
|
|
37
40
|
};
|
|
38
41
|
try {
|
|
39
42
|
// STEP 1: Pre-flight checks
|
|
40
|
-
await runUpdatePreflightChecks(spinner);
|
|
43
|
+
const preflight = await runUpdatePreflightChecks(spinner);
|
|
44
|
+
// STEP 1.5: Legacy migration (pre-2.2.0 trinity/ → .claude/trinity/)
|
|
45
|
+
if (preflight.needsLegacyMigration) {
|
|
46
|
+
const legacyInfo = await detectLegacyDeployment(spinner);
|
|
47
|
+
if (legacyInfo.isLegacy) {
|
|
48
|
+
await migrateLegacyDeployment(spinner);
|
|
49
|
+
stats.legacyMigrated = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// STEP 1.7: Update .gitignore patterns
|
|
53
|
+
const gitignoreChanged = await updateGitignoreForMigration(spinner);
|
|
54
|
+
stats.gitignoreUpdated = gitignoreChanged;
|
|
41
55
|
// STEP 2: Version check
|
|
42
56
|
const versionInfo = await detectInstalledSDKVersion(spinner);
|
|
43
57
|
if (versionInfo.isUpToDate && !options.force) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update Migration Module
|
|
3
|
+
* Handles legacy deployment detection and migration from pre-2.2.0 structure
|
|
4
|
+
* @module cli/commands/update/migration
|
|
5
|
+
*/
|
|
6
|
+
import { Ora } from 'ora';
|
|
7
|
+
export interface LegacyInfo {
|
|
8
|
+
isLegacy: boolean;
|
|
9
|
+
legacyVersion: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Detect if the project has a legacy (pre-2.2.0) Trinity deployment
|
|
13
|
+
* Legacy deployments use `trinity/` at root instead of `.claude/trinity/`
|
|
14
|
+
* @param spinner - ora spinner instance for status display
|
|
15
|
+
* @returns Legacy deployment info
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectLegacyDeployment(spinner: Ora): Promise<LegacyInfo>;
|
|
18
|
+
/**
|
|
19
|
+
* Migrate legacy Trinity deployment from `trinity/` to `.claude/trinity/`
|
|
20
|
+
* Preserves user-managed knowledge base files during migration
|
|
21
|
+
* @param spinner - ora spinner instance for status display
|
|
22
|
+
*/
|
|
23
|
+
export declare function migrateLegacyDeployment(spinner: Ora): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Update .gitignore to replace old Trinity patterns with current ones
|
|
26
|
+
* Safe to run on any deployment — idempotent
|
|
27
|
+
* @param spinner - ora spinner instance for status display
|
|
28
|
+
* @returns True if gitignore was updated
|
|
29
|
+
*/
|
|
30
|
+
export declare function updateGitignoreForMigration(spinner: Ora): Promise<boolean>;
|
|
31
|
+
//# sourceMappingURL=migration.d.ts.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update Migration Module
|
|
3
|
+
* Handles legacy deployment detection and migration from pre-2.2.0 structure
|
|
4
|
+
* @module cli/commands/update/migration
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { validatePath } from '../../utils/validate-path.js';
|
|
9
|
+
/** Old gitignore patterns from pre-2.2.0 deployments */
|
|
10
|
+
const OLD_GITIGNORE_PATTERNS = ['trinity/', '*CLAUDE.md', 'TRINITY.md'];
|
|
11
|
+
/** Current gitignore patterns */
|
|
12
|
+
const CURRENT_GITIGNORE_PATTERNS = [
|
|
13
|
+
'.claude/trinity/archive/',
|
|
14
|
+
'.claude/trinity/templates/',
|
|
15
|
+
'*CLAUDE.md',
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Detect if the project has a legacy (pre-2.2.0) Trinity deployment
|
|
19
|
+
* Legacy deployments use `trinity/` at root instead of `.claude/trinity/`
|
|
20
|
+
* @param spinner - ora spinner instance for status display
|
|
21
|
+
* @returns Legacy deployment info
|
|
22
|
+
*/
|
|
23
|
+
export async function detectLegacyDeployment(spinner) {
|
|
24
|
+
spinner.start('Checking for legacy deployment...');
|
|
25
|
+
const hasLegacyDir = await fs.pathExists('trinity');
|
|
26
|
+
const hasLegacyVersion = await fs.pathExists('trinity/VERSION');
|
|
27
|
+
if (!hasLegacyDir) {
|
|
28
|
+
spinner.info('No legacy deployment detected');
|
|
29
|
+
return { isLegacy: false, legacyVersion: null };
|
|
30
|
+
}
|
|
31
|
+
let legacyVersion = null;
|
|
32
|
+
if (hasLegacyVersion) {
|
|
33
|
+
legacyVersion = (await fs.readFile('trinity/VERSION', 'utf8')).trim();
|
|
34
|
+
}
|
|
35
|
+
spinner.warn(`Legacy deployment detected (v${legacyVersion || 'unknown'})`);
|
|
36
|
+
return { isLegacy: true, legacyVersion };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Migrate legacy Trinity deployment from `trinity/` to `.claude/trinity/`
|
|
40
|
+
* Preserves user-managed knowledge base files during migration
|
|
41
|
+
* @param spinner - ora spinner instance for status display
|
|
42
|
+
*/
|
|
43
|
+
export async function migrateLegacyDeployment(spinner) {
|
|
44
|
+
spinner.start('Migrating legacy deployment to .claude/trinity/...');
|
|
45
|
+
// Create new directory structure
|
|
46
|
+
await fs.ensureDir('.claude/trinity');
|
|
47
|
+
await fs.ensureDir('.claude/agents/leadership');
|
|
48
|
+
await fs.ensureDir('.claude/agents/deployment');
|
|
49
|
+
await fs.ensureDir('.claude/agents/audit');
|
|
50
|
+
await fs.ensureDir('.claude/agents/planning');
|
|
51
|
+
await fs.ensureDir('.claude/agents/aj-team');
|
|
52
|
+
await fs.ensureDir('.claude/commands');
|
|
53
|
+
// Move trinity/ contents to .claude/trinity/
|
|
54
|
+
const trinityContents = await fs.readdir('trinity');
|
|
55
|
+
for (const item of trinityContents) {
|
|
56
|
+
const srcPath = path.join('trinity', item);
|
|
57
|
+
const destPath = path.join('.claude/trinity', item);
|
|
58
|
+
// Don't overwrite if destination already exists (prefer new structure)
|
|
59
|
+
if (!(await fs.pathExists(destPath))) {
|
|
60
|
+
await fs.copy(srcPath, destPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Remove old trinity/ directory
|
|
64
|
+
await fs.remove('trinity');
|
|
65
|
+
spinner.succeed('Legacy deployment migrated to .claude/trinity/');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Update .gitignore to replace old Trinity patterns with current ones
|
|
69
|
+
* Safe to run on any deployment — idempotent
|
|
70
|
+
* @param spinner - ora spinner instance for status display
|
|
71
|
+
* @returns True if gitignore was updated
|
|
72
|
+
*/
|
|
73
|
+
export async function updateGitignoreForMigration(spinner) {
|
|
74
|
+
spinner.start('Updating .gitignore patterns...');
|
|
75
|
+
const gitignorePath = '.gitignore';
|
|
76
|
+
if (!(await fs.pathExists(gitignorePath))) {
|
|
77
|
+
spinner.info('No .gitignore found, skipping');
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
let content = await fs.readFile(gitignorePath, 'utf8');
|
|
81
|
+
const originalContent = content;
|
|
82
|
+
if (content.includes('# Trinity Method SDK')) {
|
|
83
|
+
// Remove the existing Trinity section entirely
|
|
84
|
+
const lines = content.split('\n');
|
|
85
|
+
const filteredLines = [];
|
|
86
|
+
let inTrinitySection = false;
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
if (line.trim() === '# Trinity Method SDK') {
|
|
89
|
+
inTrinitySection = true;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// End of Trinity section: next comment or blank line after non-Trinity content
|
|
93
|
+
if (inTrinitySection) {
|
|
94
|
+
const trimmed = line.trim();
|
|
95
|
+
// Still in Trinity section if line is empty, or matches known patterns
|
|
96
|
+
if (trimmed === '' ||
|
|
97
|
+
trimmed === 'trinity/' ||
|
|
98
|
+
trimmed === '*CLAUDE.md' ||
|
|
99
|
+
trimmed === 'TRINITY.md' ||
|
|
100
|
+
trimmed === '.claude/trinity/archive/' ||
|
|
101
|
+
trimmed === '.claude/trinity/templates/') {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Non-Trinity line — we've left the section
|
|
105
|
+
inTrinitySection = false;
|
|
106
|
+
}
|
|
107
|
+
filteredLines.push(line);
|
|
108
|
+
}
|
|
109
|
+
content = filteredLines.join('\n');
|
|
110
|
+
}
|
|
111
|
+
// Remove any standalone old patterns that might exist outside the section
|
|
112
|
+
for (const pattern of OLD_GITIGNORE_PATTERNS) {
|
|
113
|
+
const regex = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'gm');
|
|
114
|
+
content = content.replace(regex, '');
|
|
115
|
+
}
|
|
116
|
+
// Clean up multiple blank lines
|
|
117
|
+
content = content.replace(/\n{3,}/g, '\n\n').trim();
|
|
118
|
+
// Append current Trinity section
|
|
119
|
+
const trinitySection = ['', '# Trinity Method SDK', ...CURRENT_GITIGNORE_PATTERNS].join('\n');
|
|
120
|
+
content = `${content}\n${trinitySection}\n`;
|
|
121
|
+
if (content === originalContent) {
|
|
122
|
+
spinner.info('.gitignore already up to date');
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const validatedPath = validatePath(gitignorePath);
|
|
126
|
+
await fs.writeFile(validatedPath, content);
|
|
127
|
+
spinner.succeed('.gitignore patterns updated');
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -4,10 +4,15 @@
|
|
|
4
4
|
* @module cli/commands/update/pre-flight
|
|
5
5
|
*/
|
|
6
6
|
import { Ora } from 'ora';
|
|
7
|
+
export interface PreflightResult {
|
|
8
|
+
needsLegacyMigration: boolean;
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
11
|
* Run pre-flight checks to ensure Trinity Method is deployed
|
|
12
|
+
* Detects both current (.claude/trinity/) and legacy (trinity/) layouts
|
|
9
13
|
* @param spinner - ora spinner instance for status display
|
|
10
|
-
* @
|
|
14
|
+
* @returns Pre-flight result with migration flags
|
|
15
|
+
* @throws {UpdateError} If no Trinity deployment found at all
|
|
11
16
|
*/
|
|
12
|
-
export declare function runUpdatePreflightChecks(spinner: Ora): Promise<
|
|
17
|
+
export declare function runUpdatePreflightChecks(spinner: Ora): Promise<PreflightResult>;
|
|
13
18
|
//# sourceMappingURL=pre-flight.d.ts.map
|
|
@@ -7,31 +7,32 @@ import fs from 'fs-extra';
|
|
|
7
7
|
import { UpdateError } from '../../utils/error-classes.js';
|
|
8
8
|
/**
|
|
9
9
|
* Run pre-flight checks to ensure Trinity Method is deployed
|
|
10
|
+
* Detects both current (.claude/trinity/) and legacy (trinity/) layouts
|
|
10
11
|
* @param spinner - ora spinner instance for status display
|
|
11
|
-
* @
|
|
12
|
+
* @returns Pre-flight result with migration flags
|
|
13
|
+
* @throws {UpdateError} If no Trinity deployment found at all
|
|
12
14
|
*/
|
|
13
15
|
export async function runUpdatePreflightChecks(spinner) {
|
|
14
16
|
spinner.start('Running pre-flight checks...');
|
|
15
|
-
// Check .claude directory exists
|
|
16
17
|
const claudeExists = await fs.pathExists('.claude');
|
|
17
|
-
if (!claudeExists) {
|
|
18
|
-
spinner.fail('.claude directory not found');
|
|
19
|
-
const { displayInfo } = await import('../../utils/errors.js');
|
|
20
|
-
displayInfo('Use: trinity deploy to install');
|
|
21
|
-
throw new UpdateError('.claude directory not found', {
|
|
22
|
-
reason: 'claude_directory_missing',
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
// Check .claude/trinity directory exists
|
|
26
18
|
const trinityExists = await fs.pathExists('.claude/trinity');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
const legacyExists = await fs.pathExists('trinity');
|
|
20
|
+
// Current structure found — no migration needed
|
|
21
|
+
if (claudeExists && trinityExists) {
|
|
22
|
+
spinner.succeed('Pre-flight checks passed');
|
|
23
|
+
return { needsLegacyMigration: false };
|
|
24
|
+
}
|
|
25
|
+
// Legacy structure found — migration needed
|
|
26
|
+
if (legacyExists) {
|
|
27
|
+
spinner.succeed('Pre-flight checks passed (legacy deployment detected)');
|
|
28
|
+
return { needsLegacyMigration: true };
|
|
34
29
|
}
|
|
35
|
-
|
|
30
|
+
// Neither found — not deployed
|
|
31
|
+
spinner.fail('Trinity Method not deployed');
|
|
32
|
+
const { displayInfo } = await import('../../utils/errors.js');
|
|
33
|
+
displayInfo('Use: trinity deploy to install');
|
|
34
|
+
throw new UpdateError('Trinity Method not deployed in this project', {
|
|
35
|
+
reason: 'trinity_directory_missing',
|
|
36
|
+
});
|
|
36
37
|
}
|
|
37
38
|
//# sourceMappingURL=pre-flight.js.map
|
|
@@ -18,6 +18,12 @@ export function displayUpdateSummary(stats, oldVersion, newVersion) {
|
|
|
18
18
|
console.log(chalk.white(` Commands Updated: ${stats.commandsUpdated}`));
|
|
19
19
|
console.log(chalk.white(` Templates Updated: ${stats.templatesUpdated}`));
|
|
20
20
|
console.log(chalk.white(` Knowledge Base Updated: ${stats.knowledgeBaseUpdated}`));
|
|
21
|
+
if (stats.legacyMigrated) {
|
|
22
|
+
console.log(chalk.yellow(` Legacy Migration: trinity/ → .claude/trinity/`));
|
|
23
|
+
}
|
|
24
|
+
if (stats.gitignoreUpdated) {
|
|
25
|
+
console.log(chalk.white(` .gitignore: Updated`));
|
|
26
|
+
}
|
|
21
27
|
console.log(chalk.white(` Total Files Updated: ${stats.agentsUpdated + stats.commandsUpdated + stats.templatesUpdated + stats.knowledgeBaseUpdated}`));
|
|
22
28
|
console.log('');
|
|
23
29
|
console.log(chalk.gray(` Version: ${oldVersion} → ${newVersion}\n`));
|
|
@@ -13,11 +13,13 @@ import { getPackageJsonPath } from '../../utils/get-sdk-path.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export async function detectInstalledSDKVersion(spinner) {
|
|
15
15
|
spinner.start('Checking versions...');
|
|
16
|
-
// Read current version from trinity/VERSION
|
|
17
|
-
const versionPath = '.claude/trinity/VERSION';
|
|
16
|
+
// Read current version from .claude/trinity/VERSION (or legacy trinity/VERSION)
|
|
18
17
|
let currentVersion = '0.0.0';
|
|
19
|
-
if (await fs.pathExists(
|
|
20
|
-
currentVersion = (await fs.readFile(
|
|
18
|
+
if (await fs.pathExists('.claude/trinity/VERSION')) {
|
|
19
|
+
currentVersion = (await fs.readFile('.claude/trinity/VERSION', 'utf8')).trim();
|
|
20
|
+
}
|
|
21
|
+
else if (await fs.pathExists('trinity/VERSION')) {
|
|
22
|
+
currentVersion = (await fs.readFile('trinity/VERSION', 'utf8')).trim();
|
|
21
23
|
}
|
|
22
24
|
// Read latest version from SDK package.json
|
|
23
25
|
const sdkPkgPath = await getPackageJsonPath();
|