trinity-method-sdk 2.2.0 → 2.2.2

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.
@@ -18,13 +18,8 @@ export async function updateGitignore(spinner) {
18
18
  if (await fs.pathExists(gitignorePath)) {
19
19
  gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
20
20
  }
21
- // Trinity files to ignore (archive and templates are ephemeral/generated)
22
- const trinityIgnores = [
23
- '',
24
- '# Trinity Method SDK',
25
- '.claude/trinity/archive/',
26
- '.claude/trinity/templates/',
27
- ];
21
+ // Trinity files to ignore (entire .claude/ directory and all CLAUDE.md files)
22
+ const trinityIgnores = ['', '# Trinity Method SDK', '.claude/', '*CLAUDE.md'];
28
23
  // Check if Trinity section already exists
29
24
  if (!gitignoreContent.includes('# Trinity Method SDK')) {
30
25
  // Append Trinity ignores
@@ -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,132 @@
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 previous deployments */
10
+ const OLD_GITIGNORE_PATTERNS = [
11
+ 'trinity/',
12
+ 'TRINITY.md',
13
+ '.claude/trinity/archive/',
14
+ '.claude/trinity/templates/',
15
+ ];
16
+ /** Current gitignore patterns */
17
+ const CURRENT_GITIGNORE_PATTERNS = ['.claude/', '*CLAUDE.md'];
18
+ /**
19
+ * Detect if the project has a legacy (pre-2.2.0) Trinity deployment
20
+ * Legacy deployments use `trinity/` at root instead of `.claude/trinity/`
21
+ * @param spinner - ora spinner instance for status display
22
+ * @returns Legacy deployment info
23
+ */
24
+ export async function detectLegacyDeployment(spinner) {
25
+ spinner.start('Checking for legacy deployment...');
26
+ const hasLegacyDir = await fs.pathExists('trinity');
27
+ const hasLegacyVersion = await fs.pathExists('trinity/VERSION');
28
+ if (!hasLegacyDir) {
29
+ spinner.info('No legacy deployment detected');
30
+ return { isLegacy: false, legacyVersion: null };
31
+ }
32
+ let legacyVersion = null;
33
+ if (hasLegacyVersion) {
34
+ legacyVersion = (await fs.readFile('trinity/VERSION', 'utf8')).trim();
35
+ }
36
+ spinner.warn(`Legacy deployment detected (v${legacyVersion || 'unknown'})`);
37
+ return { isLegacy: true, legacyVersion };
38
+ }
39
+ /**
40
+ * Migrate legacy Trinity deployment from `trinity/` to `.claude/trinity/`
41
+ * Preserves user-managed knowledge base files during migration
42
+ * @param spinner - ora spinner instance for status display
43
+ */
44
+ export async function migrateLegacyDeployment(spinner) {
45
+ spinner.start('Migrating legacy deployment to .claude/trinity/...');
46
+ // Create new directory structure
47
+ await fs.ensureDir('.claude/trinity');
48
+ await fs.ensureDir('.claude/agents/leadership');
49
+ await fs.ensureDir('.claude/agents/deployment');
50
+ await fs.ensureDir('.claude/agents/audit');
51
+ await fs.ensureDir('.claude/agents/planning');
52
+ await fs.ensureDir('.claude/agents/aj-team');
53
+ await fs.ensureDir('.claude/commands');
54
+ // Move trinity/ contents to .claude/trinity/
55
+ const trinityContents = await fs.readdir('trinity');
56
+ for (const item of trinityContents) {
57
+ const srcPath = path.join('trinity', item);
58
+ const destPath = path.join('.claude/trinity', item);
59
+ // Don't overwrite if destination already exists (prefer new structure)
60
+ if (!(await fs.pathExists(destPath))) {
61
+ await fs.copy(srcPath, destPath);
62
+ }
63
+ }
64
+ // Remove old trinity/ directory
65
+ await fs.remove('trinity');
66
+ spinner.succeed('Legacy deployment migrated to .claude/trinity/');
67
+ }
68
+ /**
69
+ * Update .gitignore to replace old Trinity patterns with current ones
70
+ * Safe to run on any deployment — idempotent
71
+ * @param spinner - ora spinner instance for status display
72
+ * @returns True if gitignore was updated
73
+ */
74
+ export async function updateGitignoreForMigration(spinner) {
75
+ spinner.start('Updating .gitignore patterns...');
76
+ const gitignorePath = '.gitignore';
77
+ if (!(await fs.pathExists(gitignorePath))) {
78
+ spinner.info('No .gitignore found, skipping');
79
+ return false;
80
+ }
81
+ let content = await fs.readFile(gitignorePath, 'utf8');
82
+ const originalContent = content;
83
+ if (content.includes('# Trinity Method SDK')) {
84
+ // Remove the existing Trinity section entirely
85
+ const lines = content.split('\n');
86
+ const filteredLines = [];
87
+ let inTrinitySection = false;
88
+ for (const line of lines) {
89
+ if (line.trim() === '# Trinity Method SDK') {
90
+ inTrinitySection = true;
91
+ continue;
92
+ }
93
+ // End of Trinity section: next comment or blank line after non-Trinity content
94
+ if (inTrinitySection) {
95
+ const trimmed = line.trim();
96
+ // Still in Trinity section if line is empty, or matches known patterns
97
+ if (trimmed === '' ||
98
+ trimmed === 'trinity/' ||
99
+ trimmed === '*CLAUDE.md' ||
100
+ trimmed === 'TRINITY.md' ||
101
+ trimmed === '.claude/' ||
102
+ trimmed === '.claude/trinity/archive/' ||
103
+ trimmed === '.claude/trinity/templates/') {
104
+ continue;
105
+ }
106
+ // Non-Trinity line — we've left the section
107
+ inTrinitySection = false;
108
+ }
109
+ filteredLines.push(line);
110
+ }
111
+ content = filteredLines.join('\n');
112
+ }
113
+ // Remove any standalone old patterns that might exist outside the section
114
+ for (const pattern of OLD_GITIGNORE_PATTERNS) {
115
+ const regex = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'gm');
116
+ content = content.replace(regex, '');
117
+ }
118
+ // Clean up multiple blank lines
119
+ content = content.replace(/\n{3,}/g, '\n\n').trim();
120
+ // Append current Trinity section
121
+ const trinitySection = ['', '# Trinity Method SDK', ...CURRENT_GITIGNORE_PATTERNS].join('\n');
122
+ content = `${content}\n${trinitySection}\n`;
123
+ if (content === originalContent) {
124
+ spinner.info('.gitignore already up to date');
125
+ return false;
126
+ }
127
+ const validatedPath = validatePath(gitignorePath);
128
+ await fs.writeFile(validatedPath, content);
129
+ spinner.succeed('.gitignore patterns updated');
130
+ return true;
131
+ }
132
+ //# 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
- * @throws {UpdateError} If pre-flight checks fail
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<void>;
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
- * @throws {UpdateError} If pre-flight checks fail
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
- if (!trinityExists) {
28
- spinner.fail('Trinity Method not deployed');
29
- const { displayInfo } = await import('../../utils/errors.js');
30
- displayInfo('Trinity deployment appears incomplete');
31
- throw new UpdateError('Trinity Method not deployed in this project', {
32
- reason: 'trinity_directory_missing',
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
- spinner.succeed('Pre-flight checks passed');
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`));
@@ -9,5 +9,7 @@ export interface UpdateStats {
9
9
  knowledgeBaseUpdated: number;
10
10
  commandsUpdated: number;
11
11
  filesUpdated: number;
12
+ legacyMigrated: boolean;
13
+ gitignoreUpdated: boolean;
12
14
  }
13
15
  //# sourceMappingURL=types.d.ts.map
@@ -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(versionPath)) {
20
- currentVersion = (await fs.readFile(versionPath, 'utf8')).trim();
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();
@@ -17,17 +17,29 @@ End current Trinity Method session and prepare for commit.
17
17
 
18
18
  **STRICT ARCHIVING PROTOCOL:**
19
19
 
20
- a. **Archive Completed Work Orders:**
20
+ a. **Archive Completed Work Orders from sessions/:**
21
21
  - Read all files from `.claude/trinity/sessions/` matching `WO-*.md`
22
22
  - Move each to `.claude/trinity/archive/work-orders/YYYY-MM-DD/`
23
23
  - These were moved to sessions/ after completion per work order template
24
24
 
25
- b. **Archive Completed Investigations:**
25
+ b. **Archive Completed Work Orders from work-orders/:**
26
+ - Check `.claude/trinity/work-orders/` for any completed work orders
27
+ - Completed work orders have status marked as "COMPLETED" or "CLOSED"
28
+ - Move completed ones to `.claude/trinity/archive/work-orders/YYYY-MM-DD/`
29
+ - Leave active/in-progress work orders in place
30
+
31
+ c. **Archive Completed Investigations from sessions/:**
26
32
  - Read all files from `.claude/trinity/sessions/` matching `INV-*.md`
27
33
  - Move each to `.claude/trinity/archive/investigations/YYYY-MM-DD/`
28
34
  - These were moved to sessions/ after completion per investigation template
29
35
 
30
- c. **Archive ALL Reports:**
36
+ d. **Archive Completed Investigations from investigations/:**
37
+ - Check `.claude/trinity/investigations/` for any completed investigations
38
+ - Move completed ones to `.claude/trinity/archive/investigations/YYYY-MM-DD/`
39
+ - Also check `.claude/trinity/investigations/plans/` and archive any completed investigation plans
40
+ - Leave active/in-progress investigations in place
41
+
42
+ e. **Archive ALL Reports:**
31
43
  - Move ALL files from `.claude/trinity/reports/` to `.claude/trinity/archive/reports/YYYY-MM-DD/`
32
44
  - This includes:
33
45
  - Implementation completion reports
@@ -36,15 +48,26 @@ End current Trinity Method session and prepare for commit.
36
48
  - Any other session reports
37
49
  - **NO EXCEPTIONS:** Every file in reports/ must be archived
38
50
 
39
- d. **Archive Session Files:**
51
+ f. **Archive Plan Mode Files:**
52
+ - Move ALL files from `.claude/trinity/plans/` to `.claude/trinity/archive/sessions/YYYY-MM-DD/`
53
+ - These are created by Claude Code during plan mode sessions
54
+ - They are session artifacts and should be archived with session files
55
+
56
+ g. **Archive Session Files:**
40
57
  - Move ALL remaining files from `.claude/trinity/sessions/` to `.claude/trinity/archive/sessions/YYYY-MM-DD/`
41
58
  - Create session summary document in `.claude/trinity/archive/sessions/YYYY-MM-DD/SESSION-SUMMARY-{date}.md`
42
59
 
43
- e. **Verify Clean Slate:**
60
+ h. **Organize Loose Archive Files:**
61
+ - Check each `.claude/trinity/archive/` subdirectory (work-orders/, investigations/, reports/, sessions/)
62
+ - If any files exist directly in a subdirectory (not inside a YYYY-MM-DD/ date folder), move them into the appropriate `YYYY-MM-DD/` folder based on their modification date
63
+ - This ensures all archived files are properly organized in date folders
64
+
65
+ i. **Verify Clean Slate:**
44
66
  - **CRITICAL:** After archiving, `.claude/trinity/sessions/` MUST be empty
45
67
  - **CRITICAL:** After archiving, `.claude/trinity/reports/` MUST be empty
68
+ - **CRITICAL:** After archiving, `.claude/trinity/plans/` MUST be empty
46
69
  - If any files remain, archive them or report error
47
- - Next session MUST start with completely empty sessions/ and reports/ folders
70
+ - Next session MUST start with completely empty sessions/, reports/, and plans/ folders
48
71
 
49
72
  **Archive Structure:**
50
73
  ```
@@ -56,6 +79,7 @@ End current Trinity Method session and prepare for commit.
56
79
  ├── investigations/YYYY-MM-DD/
57
80
  │ ├── INV-001-*.md
58
81
  │ ├── INV-002-*.md
82
+ │ ├── INV-001-plan-*.md
59
83
  │ └── ...
60
84
  ├── reports/YYYY-MM-DD/
61
85
  │ ├── WO-001-IMPLEMENTATION-COMPLETE-*.md
@@ -64,6 +88,7 @@ End current Trinity Method session and prepare for commit.
64
88
  │ └── ...
65
89
  └── sessions/YYYY-MM-DD/
66
90
  ├── SESSION-SUMMARY-{date}.md
91
+ ├── [plan mode files]
67
92
  └── [any other session files]
68
93
  ```
69
94
 
@@ -71,8 +96,10 @@ End current Trinity Method session and prepare for commit.
71
96
  - Keep ONLY active/in-progress work orders in `.claude/trinity/work-orders/`
72
97
  - Keep ONLY active/in-progress investigations in `.claude/trinity/investigations/`
73
98
  - Do NOT archive incomplete work
74
- - Completed work is identified by presence in `.claude/trinity/sessions/` folder
99
+ - Completed work may exist in both `sessions/` AND their source directories (`work-orders/`, `investigations/`)
100
+ - The `plans/` directory is created by Claude Code during plan mode — always archive all contents
75
101
  - All reports are archived regardless of status
102
+ - Loose files in archive subdirectories should be organized into YYYY-MM-DD date folders
76
103
 
77
104
  2. **ALY analyzes session events:**
78
105
  - Review all work completed during session
@@ -87,6 +114,8 @@ End current Trinity Method session and prepare for commit.
87
114
  - Verify .claude/trinity/investigations/ contains only active investigations
88
115
  - Verify .claude/trinity/reports/ is empty
89
116
  - Verify .claude/trinity/sessions/ is empty
117
+ - Verify .claude/trinity/plans/ is empty
118
+ - Verify all files in .claude/trinity/archive/ subdirectories are in YYYY-MM-DD date folders
90
119
  - Ready for next session
91
120
 
92
121
  4. **Git commit instructions:**
@@ -32,6 +32,23 @@ Examples: WO-042-jwt-refresh-implementation.md
32
32
 
33
33
  ---
34
34
 
35
+ ## Work Order Numbering
36
+
37
+ **To determine the next WO number:**
38
+
39
+ 1. Scan `.claude/trinity/work-orders/` for files matching `WO-*.md`
40
+ 2. Scan `.claude/trinity/sessions/` for files matching `WO-*.md`
41
+ 3. From all matches in those two directories, extract the highest `XXX` number
42
+ 4. New WO number = highest + 1 (zero-padded to 3 digits)
43
+ 5. If NO work orders are found in either directory, start at `WO-001`
44
+
45
+ **IMPORTANT:**
46
+ - Do **NOT** scan `.claude/trinity/archive/` — archived WOs belong to past sessions
47
+ - Do **NOT** scan any other directories
48
+ - Each new session with no active or pending WOs starts fresh at WO-001
49
+
50
+ ---
51
+
35
52
  ## Direct Work Order Creation
36
53
 
37
54
  When `/trinity-workorder` is invoked, the agent will:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trinity-method-sdk",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "Trinity Method SDK - Investigation-first development methodology for any project",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",