clavix 2.7.0 → 2.8.0
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/README.md +22 -8
- package/bin/clavix.js +12 -5
- package/dist/cli/commands/archive.d.ts +5 -4
- package/dist/cli/commands/archive.js +135 -161
- package/dist/cli/commands/config.d.ts +4 -4
- package/dist/cli/commands/config.js +66 -105
- package/dist/cli/commands/deep.d.ts +3 -3
- package/dist/cli/commands/deep.js +97 -103
- package/dist/cli/commands/execute.d.ts +4 -4
- package/dist/cli/commands/execute.js +57 -63
- package/dist/cli/commands/fast.d.ts +3 -3
- package/dist/cli/commands/fast.js +122 -128
- package/dist/cli/commands/implement.d.ts +4 -4
- package/dist/cli/commands/implement.js +84 -148
- package/dist/cli/commands/init.js +87 -126
- package/dist/cli/commands/list.d.ts +5 -5
- package/dist/cli/commands/list.js +72 -111
- package/dist/cli/commands/plan.d.ts +7 -7
- package/dist/cli/commands/plan.js +92 -131
- package/dist/cli/commands/prd.d.ts +4 -4
- package/dist/cli/commands/prd.js +76 -111
- package/dist/cli/commands/prompts/clear.d.ts +6 -6
- package/dist/cli/commands/prompts/clear.js +70 -76
- package/dist/cli/commands/prompts/list.js +37 -43
- package/dist/cli/commands/show.d.ts +4 -4
- package/dist/cli/commands/show.js +72 -111
- package/dist/cli/commands/start.d.ts +3 -3
- package/dist/cli/commands/start.js +63 -101
- package/dist/cli/commands/summarize.d.ts +4 -4
- package/dist/cli/commands/summarize.js +81 -120
- package/dist/cli/commands/task-complete.d.ts +4 -4
- package/dist/cli/commands/task-complete.js +86 -123
- package/dist/cli/commands/update.d.ts +3 -3
- package/dist/cli/commands/update.js +97 -130
- package/dist/cli/commands/version.js +13 -48
- package/dist/core/adapters/agents-md-generator.js +17 -50
- package/dist/core/adapters/amp-adapter.d.ts +1 -1
- package/dist/core/adapters/amp-adapter.js +13 -21
- package/dist/core/adapters/augment-adapter.d.ts +2 -2
- package/dist/core/adapters/augment-adapter.js +16 -56
- package/dist/core/adapters/base-adapter.d.ts +1 -1
- package/dist/core/adapters/base-adapter.js +11 -47
- package/dist/core/adapters/claude-code-adapter.d.ts +2 -2
- package/dist/core/adapters/claude-code-adapter.js +19 -60
- package/dist/core/adapters/cline-adapter.d.ts +1 -1
- package/dist/core/adapters/cline-adapter.js +13 -21
- package/dist/core/adapters/codebuddy-adapter.d.ts +2 -2
- package/dist/core/adapters/codebuddy-adapter.js +17 -57
- package/dist/core/adapters/codex-adapter.d.ts +2 -2
- package/dist/core/adapters/codex-adapter.js +16 -56
- package/dist/core/adapters/copilot-instructions-generator.js +18 -51
- package/dist/core/adapters/crush-adapter.d.ts +2 -2
- package/dist/core/adapters/crush-adapter.js +13 -20
- package/dist/core/adapters/cursor-adapter.d.ts +1 -1
- package/dist/core/adapters/cursor-adapter.js +12 -20
- package/dist/core/adapters/droid-adapter.d.ts +2 -2
- package/dist/core/adapters/droid-adapter.js +14 -21
- package/dist/core/adapters/gemini-adapter.d.ts +2 -2
- package/dist/core/adapters/gemini-adapter.js +16 -52
- package/dist/core/adapters/kilocode-adapter.d.ts +1 -1
- package/dist/core/adapters/kilocode-adapter.js +12 -20
- package/dist/core/adapters/octo-md-generator.js +17 -50
- package/dist/core/adapters/opencode-adapter.d.ts +2 -2
- package/dist/core/adapters/opencode-adapter.js +14 -21
- package/dist/core/adapters/qwen-adapter.d.ts +2 -2
- package/dist/core/adapters/qwen-adapter.js +16 -52
- package/dist/core/adapters/roocode-adapter.d.ts +2 -2
- package/dist/core/adapters/roocode-adapter.js +12 -19
- package/dist/core/adapters/warp-md-generator.js +17 -50
- package/dist/core/adapters/windsurf-adapter.d.ts +1 -1
- package/dist/core/adapters/windsurf-adapter.js +12 -20
- package/dist/core/agent-manager.d.ts +1 -1
- package/dist/core/agent-manager.js +34 -38
- package/dist/core/archive-manager.js +10 -46
- package/dist/core/config-manager.d.ts +2 -2
- package/dist/core/config-manager.js +3 -40
- package/dist/core/conversation-analyzer.d.ts +1 -1
- package/dist/core/conversation-analyzer.js +1 -5
- package/dist/core/doc-injector.js +23 -60
- package/dist/core/git-manager.js +11 -48
- package/dist/core/prd-generator.js +16 -51
- package/dist/core/prompt-manager.js +6 -42
- package/dist/core/prompt-optimizer.js +1 -5
- package/dist/core/question-engine.js +6 -45
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.js +11 -49
- package/dist/core/task-manager.d.ts +26 -0
- package/dist/core/task-manager.js +243 -101
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -12
- package/dist/templates/agents/agents.md +31 -2
- package/dist/templates/agents/copilot-instructions.md +1 -1
- package/dist/templates/agents/octo.md +20 -1
- package/dist/templates/agents/warp.md +1 -1
- package/dist/templates/slash-commands/_canonical/implement.md +33 -11
- package/dist/types/agent.js +1 -2
- package/dist/types/config.js +3 -8
- package/dist/types/errors.js +7 -13
- package/dist/types/session.js +1 -2
- package/dist/utils/agent-error-messages.js +1 -5
- package/dist/utils/error-utils.js +5 -12
- package/dist/utils/file-system.js +20 -57
- package/dist/utils/legacy-command-cleanup.d.ts +1 -1
- package/dist/utils/legacy-command-cleanup.js +9 -45
- package/dist/utils/template-loader.d.ts +1 -1
- package/dist/utils/template-loader.js +9 -41
- package/dist/utils/toml-templates.js +1 -4
- package/package.json +12 -7
- package/dist/core/adapters 2/agents-md-generator.d.ts +0 -26
- package/dist/core/adapters 2/agents-md-generator.js +0 -102
- package/dist/core/adapters 2/amp-adapter.d.ts +0 -27
- package/dist/core/adapters 2/amp-adapter.js +0 -42
- package/dist/core/adapters 2/augment-adapter.d.ts +0 -22
- package/dist/core/adapters 2/augment-adapter.js +0 -77
- package/dist/core/adapters 2/base-adapter.d.ts +0 -45
- package/dist/core/adapters 2/base-adapter.js +0 -142
- package/dist/core/adapters 2/claude-code-adapter.d.ts +0 -32
- package/dist/core/adapters 2/claude-code-adapter.js +0 -116
- package/dist/core/adapters 2/cline-adapter.d.ts +0 -34
- package/dist/core/adapters 2/cline-adapter.js +0 -52
- package/dist/core/adapters 2/codebuddy-adapter.d.ts +0 -24
- package/dist/core/adapters 2/codebuddy-adapter.js +0 -82
- package/dist/core/adapters 2/codex-adapter.d.ts +0 -24
- package/dist/core/adapters 2/codex-adapter.js +0 -79
- package/dist/core/adapters 2/copilot-instructions-generator.d.ts +0 -26
- package/dist/core/adapters 2/copilot-instructions-generator.js +0 -104
- package/dist/core/adapters 2/crush-adapter.d.ts +0 -35
- package/dist/core/adapters 2/crush-adapter.js +0 -49
- package/dist/core/adapters 2/cursor-adapter.d.ts +0 -25
- package/dist/core/adapters 2/cursor-adapter.js +0 -40
- package/dist/core/adapters 2/droid-adapter.d.ts +0 -33
- package/dist/core/adapters 2/droid-adapter.js +0 -57
- package/dist/core/adapters 2/gemini-adapter.d.ts +0 -27
- package/dist/core/adapters 2/gemini-adapter.js +0 -90
- package/dist/core/adapters 2/kilocode-adapter.d.ts +0 -34
- package/dist/core/adapters 2/kilocode-adapter.js +0 -49
- package/dist/core/adapters 2/octo-md-generator.d.ts +0 -26
- package/dist/core/adapters 2/octo-md-generator.js +0 -102
- package/dist/core/adapters 2/opencode-adapter.d.ts +0 -33
- package/dist/core/adapters 2/opencode-adapter.js +0 -56
- package/dist/core/adapters 2/qwen-adapter.d.ts +0 -27
- package/dist/core/adapters 2/qwen-adapter.js +0 -90
- package/dist/core/adapters 2/roocode-adapter.d.ts +0 -40
- package/dist/core/adapters 2/roocode-adapter.js +0 -68
- package/dist/core/adapters 2/warp-md-generator.d.ts +0 -17
- package/dist/core/adapters 2/warp-md-generator.js +0 -88
- package/dist/core/adapters 2/windsurf-adapter.d.ts +0 -34
- package/dist/core/adapters 2/windsurf-adapter.js +0 -49
- package/dist/core/agent-manager 2.js +0 -126
- package/dist/core/agent-manager.d 2.ts +0 -51
- package/dist/core/archive-manager 2.js +0 -338
- package/dist/core/archive-manager.d 2.ts +0 -100
- package/dist/core/conversation-analyzer.d 2.ts +0 -86
- package/dist/core/doc-injector 2.js +0 -236
- package/dist/core/doc-injector.d 2.ts +0 -51
- package/dist/core/git-manager 2.js +0 -214
- package/dist/core/git-manager.d 2.ts +0 -100
- package/dist/core/prompt-optimizer 2.js +0 -963
- package/dist/core/prompt-optimizer.d 2.ts +0 -268
- package/dist/core/question-engine 2.js +0 -395
- package/dist/core/question-engine.d 2.ts +0 -167
- package/dist/core/session-manager 2.js +0 -403
- package/dist/core/session-manager.d 2.ts +0 -139
- package/dist/core/task-manager 2.js +0 -689
- package/dist/core/task-manager.d 2.ts +0 -155
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ Provider paths and argument placeholders are listed in [docs/providers.md](docs/
|
|
|
26
26
|
|
|
27
27
|
## Quickstart
|
|
28
28
|
|
|
29
|
+
> **⚠️ v2.8.0 Breaking Change**: Clavix is now a pure ESM package. Requires **Node.js ≥ 16.0.0**. See [CHANGELOG.md](CHANGELOG.md#280---2025-11-17) for migration details.
|
|
30
|
+
|
|
29
31
|
### For AI Agents (Recommended)
|
|
30
32
|
|
|
31
33
|
Most Clavix users work through AI coding assistants:
|
|
@@ -94,21 +96,33 @@ clavix prd
|
|
|
94
96
|
- CLEAR Framework: [docs/clear-framework.md](docs/clear-framework.md)
|
|
95
97
|
- Guides: [docs/guides/](docs/guides/workflows.md)
|
|
96
98
|
|
|
97
|
-
##
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
### For End Users
|
|
102
|
+
- **Node.js ≥ 16.0.0** (required for ESM support)
|
|
103
|
+
- npm or yarn package manager
|
|
104
|
+
|
|
105
|
+
### For Contributors
|
|
106
|
+
- **Node.js ≥ 16.0.0** (pure ESM package since v2.8.0)
|
|
107
|
+
- Run tests: `npm test` (uses `--experimental-vm-modules` for Jest with ESM)
|
|
100
108
|
- Lint: `npm run lint`
|
|
101
|
-
- Build: `npm run build`
|
|
109
|
+
- Build: `npm run build` (TypeScript ES2020 modules)
|
|
110
|
+
|
|
111
|
+
**ESM Migration (v2.8.0+):**
|
|
112
|
+
- All source code uses ES modules (`import`/`export`)
|
|
113
|
+
- TypeScript configured with `NodeNext` module resolution
|
|
114
|
+
- All imports require `.js` file extensions
|
|
115
|
+
- See [ESM_MIGRATION_NOTES.md](ESM_MIGRATION_NOTES.md) for details
|
|
102
116
|
|
|
103
117
|
## License
|
|
104
118
|
MIT
|
|
105
119
|
|
|
106
120
|
## Star History
|
|
107
121
|
|
|
108
|
-
<a href="https://www.star-history.com/#
|
|
122
|
+
<a href="https://www.star-history.com/#ClavixDev/Clavix&type=date&legend=top-left">
|
|
109
123
|
<picture>
|
|
110
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=
|
|
111
|
-
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=
|
|
112
|
-
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=
|
|
124
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ClavixDev/Clavix&type=date&theme=dark&legend=top-left" />
|
|
125
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ClavixDev/Clavix&type=date&legend=top-left" />
|
|
126
|
+
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ClavixDev/Clavix&type=date&legend=top-left" />
|
|
113
127
|
</picture>
|
|
114
128
|
</a>
|
package/bin/clavix.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { run, handle, settings } from '@oclif/core';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
|
|
7
|
+
// Get the project root (one level up from bin/)
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const projectRoot = join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
// Disable debug mode unless explicitly requested
|
|
4
13
|
if (!process.env.DEBUG) {
|
|
5
|
-
|
|
14
|
+
settings.debug = false;
|
|
6
15
|
}
|
|
7
16
|
|
|
8
17
|
// Custom error handler to suppress stack traces
|
|
@@ -15,10 +24,8 @@ async function handleError(error) {
|
|
|
15
24
|
}
|
|
16
25
|
|
|
17
26
|
// For other errors, use default handler
|
|
18
|
-
const { handle } = require('@oclif/core');
|
|
19
27
|
return handle(error);
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
.run()
|
|
30
|
+
run(undefined, projectRoot)
|
|
24
31
|
.catch(handleError);
|
|
@@ -3,12 +3,13 @@ export default class Archive extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static args: {
|
|
6
|
-
project: import("@oclif/core/
|
|
6
|
+
project: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
7
|
};
|
|
8
8
|
static flags: {
|
|
9
|
-
list: import("@oclif/core/
|
|
10
|
-
force: import("@oclif/core/
|
|
11
|
-
|
|
9
|
+
list: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
restore: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
13
|
};
|
|
13
14
|
run(): Promise<void>;
|
|
14
15
|
/**
|
|
@@ -1,53 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
1
|
+
import { Command, Flags, Args } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { ArchiveManager } from '../../core/archive-manager.js';
|
|
5
|
+
export default class Archive extends Command {
|
|
6
|
+
static description = 'Archive completed PRD projects';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %> # Interactive selection',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> my-project # Archive specific project',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> --list # List archived projects',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> my-project --force # Force archive',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --restore my-project # Restore from archive',
|
|
13
|
+
];
|
|
14
|
+
static args = {
|
|
15
|
+
project: Args.string({
|
|
16
|
+
description: 'Name of the project to archive',
|
|
17
|
+
required: false,
|
|
18
|
+
}),
|
|
26
19
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
static flags = {
|
|
21
|
+
list: Flags.boolean({
|
|
22
|
+
char: 'l',
|
|
23
|
+
description: 'List archived projects',
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
force: Flags.boolean({
|
|
27
|
+
char: 'f',
|
|
28
|
+
description: 'Force archive even if tasks are incomplete',
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
31
|
+
yes: Flags.boolean({
|
|
32
|
+
char: 'y',
|
|
33
|
+
description: 'Skip all confirmation prompts (agent-friendly)',
|
|
34
|
+
default: false,
|
|
35
|
+
}),
|
|
36
|
+
restore: Flags.string({
|
|
37
|
+
char: 'r',
|
|
38
|
+
description: 'Restore an archived project',
|
|
39
|
+
}),
|
|
33
40
|
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
const core_1 = require("@oclif/core");
|
|
40
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
42
|
-
const archive_manager_1 = require("../../core/archive-manager");
|
|
43
|
-
class Archive extends core_1.Command {
|
|
44
41
|
async run() {
|
|
45
42
|
const { args, flags } = await this.parse(Archive);
|
|
46
|
-
const archiveManager = new
|
|
43
|
+
const archiveManager = new ArchiveManager();
|
|
47
44
|
try {
|
|
48
45
|
// Handle restore flag
|
|
49
46
|
if (flags.restore) {
|
|
50
|
-
await this.restoreProject(flags.restore, archiveManager);
|
|
47
|
+
await this.restoreProject(flags.restore, archiveManager, flags.yes);
|
|
51
48
|
return;
|
|
52
49
|
}
|
|
53
50
|
// Handle list flag
|
|
@@ -57,45 +54,45 @@ class Archive extends core_1.Command {
|
|
|
57
54
|
}
|
|
58
55
|
// Handle direct project archival
|
|
59
56
|
if (args.project) {
|
|
60
|
-
await this.archiveSpecificProject(args.project, flags.force, archiveManager);
|
|
57
|
+
await this.archiveSpecificProject(args.project, flags.force, flags.yes, archiveManager);
|
|
61
58
|
return;
|
|
62
59
|
}
|
|
63
60
|
// Interactive mode
|
|
64
|
-
await this.interactiveArchive(archiveManager);
|
|
61
|
+
await this.interactiveArchive(archiveManager, flags.yes);
|
|
65
62
|
}
|
|
66
63
|
catch (error) {
|
|
67
|
-
const { getErrorMessage } = await
|
|
68
|
-
this.error(
|
|
64
|
+
const { getErrorMessage } = await import('../../utils/error-utils.js');
|
|
65
|
+
this.error(chalk.red(`Archive failed: ${getErrorMessage(error)}`));
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
/**
|
|
72
69
|
* Interactive archive mode - show list of archivable projects
|
|
73
70
|
*/
|
|
74
|
-
async interactiveArchive(archiveManager) {
|
|
75
|
-
this.log(
|
|
71
|
+
async interactiveArchive(archiveManager, yes) {
|
|
72
|
+
this.log(chalk.bold.cyan('\n📦 Archive PRD Projects\n'));
|
|
76
73
|
// Get all archivable projects (100% tasks completed)
|
|
77
74
|
const archivableProjects = await archiveManager.getArchivablePrds();
|
|
78
75
|
if (archivableProjects.length === 0) {
|
|
79
|
-
this.log(
|
|
80
|
-
this.log(
|
|
81
|
-
this.log(
|
|
76
|
+
this.log(chalk.gray('No projects ready to archive.'));
|
|
77
|
+
this.log(chalk.gray('\nProjects can be archived when all tasks are completed.'));
|
|
78
|
+
this.log(chalk.gray('Use ') + chalk.cyan('clavix list --outputs') + chalk.gray(' to see all projects.'));
|
|
82
79
|
return;
|
|
83
80
|
}
|
|
84
81
|
// Show archivable projects
|
|
85
|
-
this.log(
|
|
82
|
+
this.log(chalk.green(`Found ${archivableProjects.length} project(s) ready to archive:\n`));
|
|
86
83
|
// Inquirer choices can be mixed types (choices + separators)
|
|
87
84
|
const choices = archivableProjects.map((project) => ({
|
|
88
85
|
name: `${project.name} (${project.taskStatus.completed} tasks completed)`,
|
|
89
86
|
value: project.name,
|
|
90
87
|
short: project.name,
|
|
91
88
|
}));
|
|
92
|
-
choices.push(new
|
|
89
|
+
choices.push(new inquirer.Separator());
|
|
93
90
|
choices.push({
|
|
94
|
-
name:
|
|
91
|
+
name: chalk.gray('Cancel'),
|
|
95
92
|
value: '__cancel__',
|
|
96
93
|
short: 'Cancel',
|
|
97
94
|
});
|
|
98
|
-
const { selectedProject } = await
|
|
95
|
+
const { selectedProject } = await inquirer.prompt([
|
|
99
96
|
{
|
|
100
97
|
type: 'list',
|
|
101
98
|
name: 'selectedProject',
|
|
@@ -105,101 +102,107 @@ class Archive extends core_1.Command {
|
|
|
105
102
|
},
|
|
106
103
|
]);
|
|
107
104
|
if (selectedProject === '__cancel__') {
|
|
108
|
-
this.log(
|
|
105
|
+
this.log(chalk.yellow('\n✗ Archive cancelled\n'));
|
|
109
106
|
return;
|
|
110
107
|
}
|
|
111
|
-
// Confirm archival
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
108
|
+
// Confirm archival (unless --yes)
|
|
109
|
+
if (!yes) {
|
|
110
|
+
const { confirm } = await inquirer.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'confirm',
|
|
113
|
+
name: 'confirm',
|
|
114
|
+
message: `Archive "${selectedProject}"? (This will move it to .clavix/outputs/archive/)`,
|
|
115
|
+
default: false,
|
|
116
|
+
},
|
|
117
|
+
]);
|
|
118
|
+
if (!confirm) {
|
|
119
|
+
this.log(chalk.yellow('\n✗ Archive cancelled\n'));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
123
122
|
}
|
|
124
123
|
// Archive the project
|
|
125
124
|
const result = await archiveManager.archiveProject(selectedProject);
|
|
126
125
|
if (result.success) {
|
|
127
|
-
this.log(
|
|
126
|
+
this.log(chalk.green(`\n✓ ${result.message}\n`));
|
|
128
127
|
}
|
|
129
128
|
else {
|
|
130
|
-
this.error(
|
|
129
|
+
this.error(chalk.red(`\n✗ ${result.message}\n`));
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
/**
|
|
134
133
|
* Archive a specific project by name
|
|
135
134
|
*/
|
|
136
|
-
async archiveSpecificProject(projectName, force, archiveManager) {
|
|
137
|
-
this.log(
|
|
135
|
+
async archiveSpecificProject(projectName, force, yes, archiveManager) {
|
|
136
|
+
this.log(chalk.cyan(`\nArchiving project: ${chalk.bold(projectName)}\n`));
|
|
138
137
|
// Check task status
|
|
139
138
|
const projectPath = `.clavix/outputs/${projectName}`;
|
|
140
139
|
const taskStatus = await archiveManager.checkTasksStatus(projectPath);
|
|
141
|
-
// If not forcing and tasks are incomplete, ask for confirmation
|
|
140
|
+
// If not forcing and tasks are incomplete, ask for confirmation (unless --yes)
|
|
142
141
|
if (!force && !taskStatus.allCompleted) {
|
|
143
142
|
if (!taskStatus.hasTasksFile) {
|
|
144
|
-
this.log(
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
143
|
+
this.log(chalk.yellow(`⚠ Project has no tasks.md file\n`));
|
|
144
|
+
if (!yes) {
|
|
145
|
+
const { proceed } = await inquirer.prompt([
|
|
146
|
+
{
|
|
147
|
+
type: 'confirm',
|
|
148
|
+
name: 'proceed',
|
|
149
|
+
message: 'Archive anyway?',
|
|
150
|
+
default: false,
|
|
151
|
+
},
|
|
152
|
+
]);
|
|
153
|
+
if (!proceed) {
|
|
154
|
+
this.log(chalk.yellow('\n✗ Archive cancelled\n'));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
else if (taskStatus.remaining > 0) {
|
|
159
|
-
this.log(
|
|
160
|
+
this.log(chalk.yellow(`⚠ Project has ${taskStatus.remaining} incomplete task(s):\n`));
|
|
160
161
|
// Show incomplete tasks
|
|
161
162
|
const incompleteTasks = await archiveManager.getIncompleteTasks(projectPath);
|
|
162
163
|
incompleteTasks.slice(0, 5).forEach((task) => {
|
|
163
|
-
this.log(
|
|
164
|
+
this.log(chalk.gray(` • ${task}`));
|
|
164
165
|
});
|
|
165
166
|
if (incompleteTasks.length > 5) {
|
|
166
|
-
this.log(
|
|
167
|
+
this.log(chalk.gray(` ... and ${incompleteTasks.length - 5} more\n`));
|
|
167
168
|
}
|
|
168
169
|
else {
|
|
169
170
|
this.log('');
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
if (!yes) {
|
|
173
|
+
const { proceed } = await inquirer.prompt([
|
|
174
|
+
{
|
|
175
|
+
type: 'confirm',
|
|
176
|
+
name: 'proceed',
|
|
177
|
+
message: 'Archive anyway?',
|
|
178
|
+
default: false,
|
|
179
|
+
},
|
|
180
|
+
]);
|
|
181
|
+
if (!proceed) {
|
|
182
|
+
this.log(chalk.yellow('\n✗ Archive cancelled\n'));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
182
185
|
}
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
// Archive the project
|
|
186
189
|
const result = await archiveManager.archiveProject(projectName, true);
|
|
187
190
|
if (result.success) {
|
|
188
|
-
this.log(
|
|
191
|
+
this.log(chalk.green(`✓ ${result.message}\n`));
|
|
189
192
|
}
|
|
190
193
|
else {
|
|
191
|
-
this.error(
|
|
194
|
+
this.error(chalk.red(`✗ ${result.message}\n`));
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
/**
|
|
195
198
|
* List all archived projects
|
|
196
199
|
*/
|
|
197
200
|
async listArchivedProjects(archiveManager) {
|
|
198
|
-
this.log(
|
|
201
|
+
this.log(chalk.bold.cyan('\n📦 Archived Projects\n'));
|
|
199
202
|
const archivedProjects = await archiveManager.listArchivedProjects();
|
|
200
203
|
if (archivedProjects.length === 0) {
|
|
201
|
-
this.log(
|
|
202
|
-
this.log(
|
|
204
|
+
this.log(chalk.gray('No archived projects found.'));
|
|
205
|
+
this.log(chalk.gray('\nUse ') + chalk.cyan('clavix archive') + chalk.gray(' to archive completed projects.\n'));
|
|
203
206
|
return;
|
|
204
207
|
}
|
|
205
208
|
// Display archived projects
|
|
@@ -209,40 +212,42 @@ class Archive extends core_1.Command {
|
|
|
209
212
|
? `${project.taskStatus.completed}/${project.taskStatus.total} tasks`
|
|
210
213
|
: 'no tasks';
|
|
211
214
|
const modified = project.modifiedTime.toLocaleDateString();
|
|
212
|
-
this.log(` ${statusIcon} ${
|
|
213
|
-
`\n ${
|
|
214
|
-
`${
|
|
215
|
-
`\n ${
|
|
215
|
+
this.log(` ${statusIcon} ${chalk.bold(project.name)}` +
|
|
216
|
+
`\n ${chalk.gray('Tasks:')} ${taskInfo} ${chalk.gray('│')} ` +
|
|
217
|
+
`${chalk.gray('Archived:')} ${modified}` +
|
|
218
|
+
`\n ${chalk.gray('Path:')} ${chalk.dim(project.path)}` +
|
|
216
219
|
(index < archivedProjects.length - 1 ? '\n' : ''));
|
|
217
220
|
});
|
|
218
221
|
this.log('');
|
|
219
|
-
this.log(
|
|
220
|
-
this.log(
|
|
222
|
+
this.log(chalk.gray(` Total: ${archivedProjects.length} archived project(s)`));
|
|
223
|
+
this.log(chalk.gray(` Use ${chalk.cyan('clavix archive --restore <project>')} to restore a project\n`));
|
|
221
224
|
}
|
|
222
225
|
/**
|
|
223
226
|
* Restore an archived project
|
|
224
227
|
*/
|
|
225
|
-
async restoreProject(projectName, archiveManager) {
|
|
226
|
-
this.log(
|
|
227
|
-
// Confirm restoration
|
|
228
|
-
|
|
229
|
-
{
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
228
|
+
async restoreProject(projectName, archiveManager, yes) {
|
|
229
|
+
this.log(chalk.cyan(`\nRestoring project: ${chalk.bold(projectName)}\n`));
|
|
230
|
+
// Confirm restoration (unless --yes)
|
|
231
|
+
if (!yes) {
|
|
232
|
+
const { confirm } = await inquirer.prompt([
|
|
233
|
+
{
|
|
234
|
+
type: 'confirm',
|
|
235
|
+
name: 'confirm',
|
|
236
|
+
message: `Restore "${projectName}" from archive?`,
|
|
237
|
+
default: false,
|
|
238
|
+
},
|
|
239
|
+
]);
|
|
240
|
+
if (!confirm) {
|
|
241
|
+
this.log(chalk.yellow('\n✗ Restore cancelled\n'));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
239
244
|
}
|
|
240
245
|
const result = await archiveManager.restoreProject(projectName);
|
|
241
246
|
if (result.success) {
|
|
242
|
-
this.log(
|
|
247
|
+
this.log(chalk.green(`✓ ${result.message}\n`));
|
|
243
248
|
}
|
|
244
249
|
else {
|
|
245
|
-
this.error(
|
|
250
|
+
this.error(chalk.red(`✗ ${result.message}\n`));
|
|
246
251
|
}
|
|
247
252
|
}
|
|
248
253
|
/**
|
|
@@ -253,40 +258,9 @@ class Archive extends core_1.Command {
|
|
|
253
258
|
const taskInfo = project.taskStatus.hasTasksFile
|
|
254
259
|
? `${project.taskStatus.completed}/${project.taskStatus.total} tasks (${Math.round(project.taskStatus.percentage)}%)`
|
|
255
260
|
: 'no tasks';
|
|
256
|
-
this.log(` ${statusIcon} ${
|
|
257
|
-
`\n ${
|
|
258
|
-
`\n ${
|
|
261
|
+
this.log(` ${statusIcon} ${chalk.bold(project.name)}` +
|
|
262
|
+
`\n ${chalk.gray('Tasks:')} ${taskInfo}` +
|
|
263
|
+
`\n ${chalk.gray('Modified:')} ${project.modifiedTime.toLocaleDateString()}`);
|
|
259
264
|
}
|
|
260
265
|
}
|
|
261
|
-
Archive.description = 'Archive completed PRD projects';
|
|
262
|
-
Archive.examples = [
|
|
263
|
-
'<%= config.bin %> <%= command.id %> # Interactive selection',
|
|
264
|
-
'<%= config.bin %> <%= command.id %> my-project # Archive specific project',
|
|
265
|
-
'<%= config.bin %> <%= command.id %> --list # List archived projects',
|
|
266
|
-
'<%= config.bin %> <%= command.id %> my-project --force # Force archive',
|
|
267
|
-
'<%= config.bin %> <%= command.id %> --restore my-project # Restore from archive',
|
|
268
|
-
];
|
|
269
|
-
Archive.args = {
|
|
270
|
-
project: core_1.Args.string({
|
|
271
|
-
description: 'Name of the project to archive',
|
|
272
|
-
required: false,
|
|
273
|
-
}),
|
|
274
|
-
};
|
|
275
|
-
Archive.flags = {
|
|
276
|
-
list: core_1.Flags.boolean({
|
|
277
|
-
char: 'l',
|
|
278
|
-
description: 'List archived projects',
|
|
279
|
-
default: false,
|
|
280
|
-
}),
|
|
281
|
-
force: core_1.Flags.boolean({
|
|
282
|
-
char: 'f',
|
|
283
|
-
description: 'Force archive even if tasks are incomplete',
|
|
284
|
-
default: false,
|
|
285
|
-
}),
|
|
286
|
-
restore: core_1.Flags.string({
|
|
287
|
-
char: 'r',
|
|
288
|
-
description: 'Restore an archived project',
|
|
289
|
-
}),
|
|
290
|
-
};
|
|
291
|
-
exports.default = Archive;
|
|
292
266
|
//# sourceMappingURL=archive.js.map
|
|
@@ -3,12 +3,12 @@ export default class Config extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static args: {
|
|
6
|
-
action: import("@oclif/core/
|
|
7
|
-
key: import("@oclif/core/
|
|
8
|
-
value: import("@oclif/core/
|
|
6
|
+
action: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
key: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
value: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
9
9
|
};
|
|
10
10
|
static flags: {
|
|
11
|
-
global: import("@oclif/core/
|
|
11
|
+
global: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
12
|
};
|
|
13
13
|
run(): Promise<void>;
|
|
14
14
|
private showInteractiveMenu;
|