claude-autopm 2.8.1 → 2.8.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.
- package/README.md +116 -8
- package/bin/autopm.js +2 -0
- package/bin/commands/plugin.js +395 -0
- package/bin/commands/team.js +184 -10
- package/install/install.js +223 -4
- package/lib/plugins/PluginManager.js +1328 -0
- package/lib/plugins/PluginManager.old.js +400 -0
- package/package.json +4 -1
- package/scripts/publish-plugins.sh +166 -0
- package/autopm/.claude/agents/cloud/README.md +0 -55
- package/autopm/.claude/agents/cloud/aws-cloud-architect.md +0 -521
- package/autopm/.claude/agents/cloud/azure-cloud-architect.md +0 -436
- package/autopm/.claude/agents/cloud/gcp-cloud-architect.md +0 -385
- package/autopm/.claude/agents/cloud/gcp-cloud-functions-engineer.md +0 -306
- package/autopm/.claude/agents/cloud/gemini-api-expert.md +0 -880
- package/autopm/.claude/agents/cloud/kubernetes-orchestrator.md +0 -566
- package/autopm/.claude/agents/cloud/openai-python-expert.md +0 -1087
- package/autopm/.claude/agents/cloud/terraform-infrastructure-expert.md +0 -454
- package/autopm/.claude/agents/core/agent-manager.md +0 -296
- package/autopm/.claude/agents/core/code-analyzer.md +0 -131
- package/autopm/.claude/agents/core/file-analyzer.md +0 -162
- package/autopm/.claude/agents/core/test-runner.md +0 -200
- package/autopm/.claude/agents/data/airflow-orchestration-expert.md +0 -52
- package/autopm/.claude/agents/data/kedro-pipeline-expert.md +0 -50
- package/autopm/.claude/agents/data/langgraph-workflow-expert.md +0 -520
- package/autopm/.claude/agents/databases/README.md +0 -50
- package/autopm/.claude/agents/databases/bigquery-expert.md +0 -392
- package/autopm/.claude/agents/databases/cosmosdb-expert.md +0 -368
- package/autopm/.claude/agents/databases/mongodb-expert.md +0 -398
- package/autopm/.claude/agents/databases/postgresql-expert.md +0 -321
- package/autopm/.claude/agents/databases/redis-expert.md +0 -52
- package/autopm/.claude/agents/devops/README.md +0 -52
- package/autopm/.claude/agents/devops/azure-devops-specialist.md +0 -308
- package/autopm/.claude/agents/devops/docker-containerization-expert.md +0 -298
- package/autopm/.claude/agents/devops/github-operations-specialist.md +0 -335
- package/autopm/.claude/agents/devops/mcp-context-manager.md +0 -319
- package/autopm/.claude/agents/devops/observability-engineer.md +0 -574
- package/autopm/.claude/agents/devops/ssh-operations-expert.md +0 -1093
- package/autopm/.claude/agents/devops/traefik-proxy-expert.md +0 -444
- package/autopm/.claude/agents/frameworks/README.md +0 -64
- package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +0 -360
- package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +0 -254
- package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +0 -217
- package/autopm/.claude/agents/frameworks/react-ui-expert.md +0 -226
- package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +0 -770
- package/autopm/.claude/agents/frameworks/ux-design-expert.md +0 -244
- package/autopm/.claude/agents/integration/message-queue-engineer.md +0 -794
- package/autopm/.claude/agents/languages/README.md +0 -50
- package/autopm/.claude/agents/languages/bash-scripting-expert.md +0 -541
- package/autopm/.claude/agents/languages/javascript-frontend-engineer.md +0 -197
- package/autopm/.claude/agents/languages/nodejs-backend-engineer.md +0 -226
- package/autopm/.claude/agents/languages/python-backend-engineer.md +0 -214
- package/autopm/.claude/agents/languages/python-backend-expert.md +0 -289
- package/autopm/.claude/agents/testing/frontend-testing-engineer.md +0 -395
- package/autopm/.claude/commands/ai/langgraph-workflow.md +0 -65
- package/autopm/.claude/commands/ai/openai-chat.md +0 -65
- package/autopm/.claude/commands/azure/COMMANDS.md +0 -107
- package/autopm/.claude/commands/azure/COMMAND_MAPPING.md +0 -252
- package/autopm/.claude/commands/azure/INTEGRATION_FIX.md +0 -103
- package/autopm/.claude/commands/azure/README.md +0 -246
- package/autopm/.claude/commands/azure/active-work.md +0 -198
- package/autopm/.claude/commands/azure/aliases.md +0 -143
- package/autopm/.claude/commands/azure/blocked-items.md +0 -287
- package/autopm/.claude/commands/azure/clean.md +0 -93
- package/autopm/.claude/commands/azure/docs-query.md +0 -48
- package/autopm/.claude/commands/azure/feature-decompose.md +0 -380
- package/autopm/.claude/commands/azure/feature-list.md +0 -61
- package/autopm/.claude/commands/azure/feature-new.md +0 -115
- package/autopm/.claude/commands/azure/feature-show.md +0 -205
- package/autopm/.claude/commands/azure/feature-start.md +0 -130
- package/autopm/.claude/commands/azure/fix-integration-example.md +0 -93
- package/autopm/.claude/commands/azure/help.md +0 -150
- package/autopm/.claude/commands/azure/import-us.md +0 -269
- package/autopm/.claude/commands/azure/init.md +0 -211
- package/autopm/.claude/commands/azure/next-task.md +0 -262
- package/autopm/.claude/commands/azure/search.md +0 -160
- package/autopm/.claude/commands/azure/sprint-status.md +0 -235
- package/autopm/.claude/commands/azure/standup.md +0 -260
- package/autopm/.claude/commands/azure/sync-all.md +0 -99
- package/autopm/.claude/commands/azure/task-analyze.md +0 -186
- package/autopm/.claude/commands/azure/task-close.md +0 -329
- package/autopm/.claude/commands/azure/task-edit.md +0 -145
- package/autopm/.claude/commands/azure/task-list.md +0 -263
- package/autopm/.claude/commands/azure/task-new.md +0 -84
- package/autopm/.claude/commands/azure/task-reopen.md +0 -79
- package/autopm/.claude/commands/azure/task-show.md +0 -126
- package/autopm/.claude/commands/azure/task-start.md +0 -301
- package/autopm/.claude/commands/azure/task-status.md +0 -65
- package/autopm/.claude/commands/azure/task-sync.md +0 -67
- package/autopm/.claude/commands/azure/us-edit.md +0 -164
- package/autopm/.claude/commands/azure/us-list.md +0 -202
- package/autopm/.claude/commands/azure/us-new.md +0 -265
- package/autopm/.claude/commands/azure/us-parse.md +0 -253
- package/autopm/.claude/commands/azure/us-show.md +0 -188
- package/autopm/.claude/commands/azure/us-status.md +0 -320
- package/autopm/.claude/commands/azure/validate.md +0 -86
- package/autopm/.claude/commands/azure/work-item-sync.md +0 -47
- package/autopm/.claude/commands/cloud/infra-deploy.md +0 -38
- package/autopm/.claude/commands/github/workflow-create.md +0 -42
- package/autopm/.claude/commands/infrastructure/ssh-security.md +0 -65
- package/autopm/.claude/commands/infrastructure/traefik-setup.md +0 -65
- package/autopm/.claude/commands/kubernetes/deploy.md +0 -37
- package/autopm/.claude/commands/playwright/test-scaffold.md +0 -38
- package/autopm/.claude/commands/pm/blocked.md +0 -28
- package/autopm/.claude/commands/pm/clean.md +0 -119
- package/autopm/.claude/commands/pm/context-create.md +0 -136
- package/autopm/.claude/commands/pm/context-prime.md +0 -170
- package/autopm/.claude/commands/pm/context-update.md +0 -292
- package/autopm/.claude/commands/pm/context.md +0 -28
- package/autopm/.claude/commands/pm/epic-close.md +0 -86
- package/autopm/.claude/commands/pm/epic-decompose.md +0 -370
- package/autopm/.claude/commands/pm/epic-edit.md +0 -83
- package/autopm/.claude/commands/pm/epic-list.md +0 -30
- package/autopm/.claude/commands/pm/epic-merge.md +0 -222
- package/autopm/.claude/commands/pm/epic-oneshot.md +0 -119
- package/autopm/.claude/commands/pm/epic-refresh.md +0 -119
- package/autopm/.claude/commands/pm/epic-show.md +0 -28
- package/autopm/.claude/commands/pm/epic-split.md +0 -120
- package/autopm/.claude/commands/pm/epic-start.md +0 -195
- package/autopm/.claude/commands/pm/epic-status.md +0 -28
- package/autopm/.claude/commands/pm/epic-sync-modular.md +0 -338
- package/autopm/.claude/commands/pm/epic-sync-original.md +0 -473
- package/autopm/.claude/commands/pm/epic-sync.md +0 -486
- package/autopm/.claude/commands/pm/help.md +0 -28
- package/autopm/.claude/commands/pm/import.md +0 -115
- package/autopm/.claude/commands/pm/in-progress.md +0 -28
- package/autopm/.claude/commands/pm/init.md +0 -28
- package/autopm/.claude/commands/pm/issue-analyze.md +0 -202
- package/autopm/.claude/commands/pm/issue-close.md +0 -119
- package/autopm/.claude/commands/pm/issue-edit.md +0 -93
- package/autopm/.claude/commands/pm/issue-reopen.md +0 -87
- package/autopm/.claude/commands/pm/issue-show.md +0 -41
- package/autopm/.claude/commands/pm/issue-start.md +0 -234
- package/autopm/.claude/commands/pm/issue-status.md +0 -95
- package/autopm/.claude/commands/pm/issue-sync.md +0 -411
- package/autopm/.claude/commands/pm/next.md +0 -28
- package/autopm/.claude/commands/pm/prd-edit.md +0 -82
- package/autopm/.claude/commands/pm/prd-list.md +0 -28
- package/autopm/.claude/commands/pm/prd-new.md +0 -55
- package/autopm/.claude/commands/pm/prd-parse.md +0 -42
- package/autopm/.claude/commands/pm/prd-status.md +0 -28
- package/autopm/.claude/commands/pm/search.md +0 -28
- package/autopm/.claude/commands/pm/standup.md +0 -28
- package/autopm/.claude/commands/pm/status.md +0 -28
- package/autopm/.claude/commands/pm/sync.md +0 -99
- package/autopm/.claude/commands/pm/test-reference-update.md +0 -151
- package/autopm/.claude/commands/pm/validate.md +0 -28
- package/autopm/.claude/commands/pm/what-next.md +0 -28
- package/autopm/.claude/commands/python/api-scaffold.md +0 -50
- package/autopm/.claude/commands/python/docs-query.md +0 -48
- package/autopm/.claude/commands/react/app-scaffold.md +0 -50
- package/autopm/.claude/commands/testing/prime.md +0 -314
- package/autopm/.claude/commands/testing/run.md +0 -125
- package/autopm/.claude/commands/ui/bootstrap-scaffold.md +0 -65
- package/autopm/.claude/commands/ui/tailwind-system.md +0 -64
- package/autopm/.claude/rules/ai-integration-patterns.md +0 -219
- package/autopm/.claude/rules/ci-cd-kubernetes-strategy.md +0 -25
- package/autopm/.claude/rules/database-management-strategy.md +0 -17
- package/autopm/.claude/rules/database-pipeline.md +0 -94
- package/autopm/.claude/rules/devops-troubleshooting-playbook.md +0 -450
- package/autopm/.claude/rules/docker-first-development.md +0 -404
- package/autopm/.claude/rules/infrastructure-pipeline.md +0 -128
- package/autopm/.claude/rules/performance-guidelines.md +0 -403
- package/autopm/.claude/rules/ui-development-standards.md +0 -281
- package/autopm/.claude/rules/ui-framework-rules.md +0 -151
- package/autopm/.claude/rules/ux-design-rules.md +0 -209
- package/autopm/.claude/rules/visual-testing.md +0 -223
- package/autopm/.claude/scripts/azure/README.md +0 -192
- package/autopm/.claude/scripts/azure/active-work.js +0 -524
- package/autopm/.claude/scripts/azure/active-work.sh +0 -20
- package/autopm/.claude/scripts/azure/blocked.js +0 -520
- package/autopm/.claude/scripts/azure/blocked.sh +0 -20
- package/autopm/.claude/scripts/azure/daily.js +0 -533
- package/autopm/.claude/scripts/azure/daily.sh +0 -20
- package/autopm/.claude/scripts/azure/dashboard.js +0 -970
- package/autopm/.claude/scripts/azure/dashboard.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-list.js +0 -254
- package/autopm/.claude/scripts/azure/feature-list.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-show.js +0 -7
- package/autopm/.claude/scripts/azure/feature-show.sh +0 -20
- package/autopm/.claude/scripts/azure/feature-status.js +0 -604
- package/autopm/.claude/scripts/azure/feature-status.sh +0 -20
- package/autopm/.claude/scripts/azure/help.js +0 -342
- package/autopm/.claude/scripts/azure/help.sh +0 -20
- package/autopm/.claude/scripts/azure/next-task.js +0 -508
- package/autopm/.claude/scripts/azure/next-task.sh +0 -20
- package/autopm/.claude/scripts/azure/search.js +0 -469
- package/autopm/.claude/scripts/azure/search.sh +0 -20
- package/autopm/.claude/scripts/azure/setup.js +0 -745
- package/autopm/.claude/scripts/azure/setup.sh +0 -20
- package/autopm/.claude/scripts/azure/sprint-report.js +0 -1012
- package/autopm/.claude/scripts/azure/sprint-report.sh +0 -20
- package/autopm/.claude/scripts/azure/sync.js +0 -563
- package/autopm/.claude/scripts/azure/sync.sh +0 -20
- package/autopm/.claude/scripts/azure/us-list.js +0 -210
- package/autopm/.claude/scripts/azure/us-list.sh +0 -20
- package/autopm/.claude/scripts/azure/us-status.js +0 -238
- package/autopm/.claude/scripts/azure/us-status.sh +0 -20
- package/autopm/.claude/scripts/azure/validate.js +0 -626
- package/autopm/.claude/scripts/azure/validate.sh +0 -20
- package/autopm/.claude/scripts/azure/wrapper-template.sh +0 -20
- package/autopm/.claude/scripts/github/dependency-tracker.js +0 -554
- package/autopm/.claude/scripts/github/dependency-validator.js +0 -545
- package/autopm/.claude/scripts/github/dependency-visualizer.js +0 -477
- package/autopm/.claude/scripts/pm/analytics.js +0 -425
- package/autopm/.claude/scripts/pm/blocked.js +0 -164
- package/autopm/.claude/scripts/pm/blocked.sh +0 -78
- package/autopm/.claude/scripts/pm/clean.js +0 -464
- package/autopm/.claude/scripts/pm/context-create.js +0 -216
- package/autopm/.claude/scripts/pm/context-prime.js +0 -335
- package/autopm/.claude/scripts/pm/context-update.js +0 -344
- package/autopm/.claude/scripts/pm/context.js +0 -338
- package/autopm/.claude/scripts/pm/epic-close.js +0 -347
- package/autopm/.claude/scripts/pm/epic-edit.js +0 -382
- package/autopm/.claude/scripts/pm/epic-list.js +0 -273
- package/autopm/.claude/scripts/pm/epic-list.sh +0 -109
- package/autopm/.claude/scripts/pm/epic-show.js +0 -291
- package/autopm/.claude/scripts/pm/epic-show.sh +0 -105
- package/autopm/.claude/scripts/pm/epic-split.js +0 -522
- package/autopm/.claude/scripts/pm/epic-start/epic-start.js +0 -183
- package/autopm/.claude/scripts/pm/epic-start/epic-start.sh +0 -94
- package/autopm/.claude/scripts/pm/epic-status.js +0 -291
- package/autopm/.claude/scripts/pm/epic-status.sh +0 -104
- package/autopm/.claude/scripts/pm/epic-sync/README.md +0 -208
- package/autopm/.claude/scripts/pm/epic-sync/create-epic-issue.sh +0 -77
- package/autopm/.claude/scripts/pm/epic-sync/create-task-issues.sh +0 -86
- package/autopm/.claude/scripts/pm/epic-sync/update-epic-file.sh +0 -79
- package/autopm/.claude/scripts/pm/epic-sync/update-references.sh +0 -89
- package/autopm/.claude/scripts/pm/epic-sync.sh +0 -137
- package/autopm/.claude/scripts/pm/help.js +0 -92
- package/autopm/.claude/scripts/pm/help.sh +0 -90
- package/autopm/.claude/scripts/pm/in-progress.js +0 -178
- package/autopm/.claude/scripts/pm/in-progress.sh +0 -93
- package/autopm/.claude/scripts/pm/init.js +0 -321
- package/autopm/.claude/scripts/pm/init.sh +0 -178
- package/autopm/.claude/scripts/pm/issue-close.js +0 -232
- package/autopm/.claude/scripts/pm/issue-edit.js +0 -310
- package/autopm/.claude/scripts/pm/issue-show.js +0 -272
- package/autopm/.claude/scripts/pm/issue-start.js +0 -181
- package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +0 -468
- package/autopm/.claude/scripts/pm/issue-sync/gather-updates.sh +0 -460
- package/autopm/.claude/scripts/pm/issue-sync/post-comment.sh +0 -330
- package/autopm/.claude/scripts/pm/issue-sync/preflight-validation.sh +0 -348
- package/autopm/.claude/scripts/pm/issue-sync/update-frontmatter.sh +0 -387
- package/autopm/.claude/scripts/pm/lib/README.md +0 -85
- package/autopm/.claude/scripts/pm/lib/epic-discovery.js +0 -119
- package/autopm/.claude/scripts/pm/lib/logger.js +0 -78
- package/autopm/.claude/scripts/pm/next.js +0 -189
- package/autopm/.claude/scripts/pm/next.sh +0 -72
- package/autopm/.claude/scripts/pm/optimize.js +0 -407
- package/autopm/.claude/scripts/pm/pr-create.js +0 -337
- package/autopm/.claude/scripts/pm/pr-list.js +0 -257
- package/autopm/.claude/scripts/pm/prd-list.js +0 -242
- package/autopm/.claude/scripts/pm/prd-list.sh +0 -103
- package/autopm/.claude/scripts/pm/prd-new.js +0 -684
- package/autopm/.claude/scripts/pm/prd-parse.js +0 -547
- package/autopm/.claude/scripts/pm/prd-status.js +0 -152
- package/autopm/.claude/scripts/pm/prd-status.sh +0 -63
- package/autopm/.claude/scripts/pm/release.js +0 -460
- package/autopm/.claude/scripts/pm/search.js +0 -192
- package/autopm/.claude/scripts/pm/search.sh +0 -89
- package/autopm/.claude/scripts/pm/standup.js +0 -362
- package/autopm/.claude/scripts/pm/standup.sh +0 -95
- package/autopm/.claude/scripts/pm/status.js +0 -148
- package/autopm/.claude/scripts/pm/status.sh +0 -59
- package/autopm/.claude/scripts/pm/sync-batch.js +0 -337
- package/autopm/.claude/scripts/pm/sync.js +0 -343
- package/autopm/.claude/scripts/pm/template-list.js +0 -141
- package/autopm/.claude/scripts/pm/template-new.js +0 -366
- package/autopm/.claude/scripts/pm/validate.js +0 -274
- package/autopm/.claude/scripts/pm/validate.sh +0 -106
- package/autopm/.claude/scripts/pm/what-next.js +0 -660
- package/bin/node/azure-feature-show.js +0 -7
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Template New - Create custom template
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* autopm template:new prd my-custom-template
|
|
7
|
-
* autopm template:new epic my-sprint-template
|
|
8
|
-
* autopm template:new task my-task-template
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const { execSync } = require('child_process');
|
|
14
|
-
|
|
15
|
-
// Dynamically resolve template engine path
|
|
16
|
-
let TemplateEngine;
|
|
17
|
-
try {
|
|
18
|
-
// Try from project root (where lib/ is installed)
|
|
19
|
-
TemplateEngine = require(path.join(process.cwd(), 'lib', 'template-engine'));
|
|
20
|
-
} catch (err) {
|
|
21
|
-
try {
|
|
22
|
-
// Try relative path from .claude/scripts/pm/ (during development)
|
|
23
|
-
TemplateEngine = require(path.join(__dirname, '..', '..', '..', '..', 'lib', 'template-engine'));
|
|
24
|
-
} catch (err2) {
|
|
25
|
-
// Fallback: try from AutoPM global installation
|
|
26
|
-
try {
|
|
27
|
-
let npmRoot;
|
|
28
|
-
try {
|
|
29
|
-
// Check if npm is available
|
|
30
|
-
execSync('npm --version', { stdio: 'ignore' });
|
|
31
|
-
} catch (npmErr) {
|
|
32
|
-
throw new Error('npm is not available in your environment. Please install npm and try again.');
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim();
|
|
36
|
-
} catch (rootErr) {
|
|
37
|
-
throw new Error('Failed to execute "npm root -g": ' + rootErr.message);
|
|
38
|
-
}
|
|
39
|
-
if (!npmRoot || !fs.existsSync(npmRoot)) {
|
|
40
|
-
throw new Error('The npm global root directory could not be determined or does not exist: "' + npmRoot + '"');
|
|
41
|
-
}
|
|
42
|
-
TemplateEngine = require(path.join(npmRoot, 'claude-autopm', 'lib', 'template-engine'));
|
|
43
|
-
} catch (err3) {
|
|
44
|
-
throw new Error('Cannot find template-engine module. Please ensure lib/ directory is installed. Details: ' + err3.message);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
class TemplateCreator {
|
|
50
|
-
constructor() {
|
|
51
|
-
this.templateEngine = new TemplateEngine();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get base template for type
|
|
56
|
-
*/
|
|
57
|
-
getBaseTemplate(type) {
|
|
58
|
-
const templates = {
|
|
59
|
-
prd: `---
|
|
60
|
-
id: {{id}}
|
|
61
|
-
title: {{title}}
|
|
62
|
-
type: prd
|
|
63
|
-
status: draft
|
|
64
|
-
priority: {{priority}}
|
|
65
|
-
created: {{timestamp}}
|
|
66
|
-
author: {{author}}
|
|
67
|
-
timeline: {{timeline}}
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
# PRD: {{title}}
|
|
71
|
-
|
|
72
|
-
## Executive Summary
|
|
73
|
-
|
|
74
|
-
{{executive_summary}}
|
|
75
|
-
|
|
76
|
-
## Problem Statement
|
|
77
|
-
|
|
78
|
-
### Background
|
|
79
|
-
{{problem_background}}
|
|
80
|
-
|
|
81
|
-
### Current State
|
|
82
|
-
{{current_state}}
|
|
83
|
-
|
|
84
|
-
### Desired State
|
|
85
|
-
{{desired_state}}
|
|
86
|
-
|
|
87
|
-
## Target Users
|
|
88
|
-
|
|
89
|
-
{{target_users}}
|
|
90
|
-
|
|
91
|
-
## Key Features
|
|
92
|
-
|
|
93
|
-
### Must Have (P0)
|
|
94
|
-
{{#if must_have_features}}
|
|
95
|
-
{{#each must_have_features}}
|
|
96
|
-
- [ ] {{this}}
|
|
97
|
-
{{/each}}
|
|
98
|
-
{{/if}}
|
|
99
|
-
|
|
100
|
-
### Should Have (P1)
|
|
101
|
-
{{#if should_have_features}}
|
|
102
|
-
{{#each should_have_features}}
|
|
103
|
-
- [ ] {{this}}
|
|
104
|
-
{{/each}}
|
|
105
|
-
{{/if}}
|
|
106
|
-
|
|
107
|
-
## Success Metrics
|
|
108
|
-
|
|
109
|
-
{{success_metrics}}
|
|
110
|
-
|
|
111
|
-
## Technical Requirements
|
|
112
|
-
|
|
113
|
-
{{technical_requirements}}
|
|
114
|
-
|
|
115
|
-
## Implementation Plan
|
|
116
|
-
|
|
117
|
-
### Phase 1: Design (Week 1)
|
|
118
|
-
- [ ] Requirements finalized
|
|
119
|
-
- [ ] Technical design review
|
|
120
|
-
- [ ] Development environment setup
|
|
121
|
-
|
|
122
|
-
### Phase 2: Development (Week 2-3)
|
|
123
|
-
- [ ] Implement core features
|
|
124
|
-
- [ ] Write tests (TDD)
|
|
125
|
-
- [ ] Code review
|
|
126
|
-
|
|
127
|
-
### Phase 3: Testing (Week 4)
|
|
128
|
-
- [ ] Integration testing
|
|
129
|
-
- [ ] User acceptance testing
|
|
130
|
-
- [ ] Performance testing
|
|
131
|
-
|
|
132
|
-
### Phase 4: Release (Week 5)
|
|
133
|
-
- [ ] Documentation
|
|
134
|
-
- [ ] Deployment
|
|
135
|
-
- [ ] Monitoring setup
|
|
136
|
-
|
|
137
|
-
## Risks and Mitigation
|
|
138
|
-
|
|
139
|
-
{{risks_and_mitigation}}
|
|
140
|
-
|
|
141
|
-
## Open Questions
|
|
142
|
-
|
|
143
|
-
- [ ] {{open_question_1}}
|
|
144
|
-
- [ ] {{open_question_2}}
|
|
145
|
-
|
|
146
|
-
## Appendix
|
|
147
|
-
|
|
148
|
-
### Changelog
|
|
149
|
-
- {{timestamp}}: Initial PRD created by {{author}}
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
*Custom PRD Template*
|
|
154
|
-
`,
|
|
155
|
-
epic: `---
|
|
156
|
-
id: {{id}}
|
|
157
|
-
title: {{title}}
|
|
158
|
-
type: epic
|
|
159
|
-
status: planning
|
|
160
|
-
priority: {{priority}}
|
|
161
|
-
created: {{timestamp}}
|
|
162
|
-
author: {{author}}
|
|
163
|
-
start_date: {{start_date}}
|
|
164
|
-
end_date: {{end_date}}
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
# Epic: {{title}}
|
|
168
|
-
|
|
169
|
-
## Overview
|
|
170
|
-
|
|
171
|
-
{{overview}}
|
|
172
|
-
|
|
173
|
-
## Goals
|
|
174
|
-
|
|
175
|
-
{{#each goals}}
|
|
176
|
-
- {{this}}
|
|
177
|
-
{{/each}}
|
|
178
|
-
|
|
179
|
-
## User Stories
|
|
180
|
-
|
|
181
|
-
{{#each user_stories}}
|
|
182
|
-
- As a {{role}}, I want to {{action}}, so that {{benefit}}
|
|
183
|
-
{{/each}}
|
|
184
|
-
|
|
185
|
-
## Tasks
|
|
186
|
-
|
|
187
|
-
{{#each tasks}}
|
|
188
|
-
- [ ] {{this}}
|
|
189
|
-
{{/each}}
|
|
190
|
-
|
|
191
|
-
## Success Criteria
|
|
192
|
-
|
|
193
|
-
{{success_criteria}}
|
|
194
|
-
|
|
195
|
-
## Dependencies
|
|
196
|
-
|
|
197
|
-
{{dependencies}}
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
*Custom Epic Template*
|
|
202
|
-
`,
|
|
203
|
-
task: `---
|
|
204
|
-
id: {{id}}
|
|
205
|
-
title: {{title}}
|
|
206
|
-
type: task
|
|
207
|
-
status: todo
|
|
208
|
-
priority: {{priority}}
|
|
209
|
-
created: {{timestamp}}
|
|
210
|
-
author: {{author}}
|
|
211
|
-
assigned_to: {{assigned_to}}
|
|
212
|
-
estimated_hours: {{estimated_hours}}
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
# Task: {{title}}
|
|
216
|
-
|
|
217
|
-
## Description
|
|
218
|
-
|
|
219
|
-
{{description}}
|
|
220
|
-
|
|
221
|
-
## Acceptance Criteria
|
|
222
|
-
|
|
223
|
-
{{#each acceptance_criteria}}
|
|
224
|
-
- [ ] {{this}}
|
|
225
|
-
{{/each}}
|
|
226
|
-
|
|
227
|
-
## Technical Details
|
|
228
|
-
|
|
229
|
-
{{technical_details}}
|
|
230
|
-
|
|
231
|
-
## Testing
|
|
232
|
-
|
|
233
|
-
{{testing_notes}}
|
|
234
|
-
|
|
235
|
-
## Notes
|
|
236
|
-
|
|
237
|
-
{{notes}}
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
*Custom Task Template*
|
|
242
|
-
`
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
return templates[type] || templates.prd;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Create new template
|
|
250
|
-
*/
|
|
251
|
-
create(type, name) {
|
|
252
|
-
console.log(`\n📝 Creating Custom Template`);
|
|
253
|
-
console.log(`${'═'.repeat(50)}\n`);
|
|
254
|
-
|
|
255
|
-
// Validate type
|
|
256
|
-
const validTypes = ['prd', 'epic', 'task'];
|
|
257
|
-
if (!validTypes.includes(type)) {
|
|
258
|
-
console.error(`❌ Invalid type: ${type}`);
|
|
259
|
-
console.log(`Valid types: ${validTypes.join(', ')}`);
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Ensure template directory exists
|
|
264
|
-
const typeDir = type === 'prd' ? 'prds' : type === 'epic' ? 'epics' : 'tasks';
|
|
265
|
-
this.templateEngine.ensureTemplateDir(typeDir);
|
|
266
|
-
|
|
267
|
-
const templatePath = path.join('.claude', 'templates', typeDir, `${name}.md`);
|
|
268
|
-
|
|
269
|
-
// Check if template already exists
|
|
270
|
-
if (fs.existsSync(templatePath)) {
|
|
271
|
-
console.error(`❌ Template already exists: ${templatePath}`);
|
|
272
|
-
console.log(`💡 Edit file directly or choose a different name`);
|
|
273
|
-
return false;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Get base template
|
|
277
|
-
const baseTemplate = this.getBaseTemplate(type);
|
|
278
|
-
|
|
279
|
-
// Write template file
|
|
280
|
-
fs.writeFileSync(templatePath, baseTemplate);
|
|
281
|
-
|
|
282
|
-
console.log(`✅ Template created: ${templatePath}`);
|
|
283
|
-
console.log(`\n📋 Template Structure:`);
|
|
284
|
-
console.log(` - Frontmatter: Define metadata variables`);
|
|
285
|
-
console.log(` - Variables: Use {{variable_name}} for substitution`);
|
|
286
|
-
console.log(` - Conditionals: {{#if var}}...{{/if}}`);
|
|
287
|
-
console.log(` - Loops: {{#each items}}...{{/each}}`);
|
|
288
|
-
|
|
289
|
-
console.log(`\n🛠️ Next Steps:`);
|
|
290
|
-
console.log(` 1. Edit template: nano ${templatePath}`);
|
|
291
|
-
console.log(` 2. Add custom variables and sections`);
|
|
292
|
-
console.log(` 3. Test template: autopm ${type}:new --template ${name} "Test"`);
|
|
293
|
-
|
|
294
|
-
// Try to open in editor
|
|
295
|
-
this.openInEditor(templatePath);
|
|
296
|
-
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Open template in editor
|
|
302
|
-
*/
|
|
303
|
-
openInEditor(templatePath) {
|
|
304
|
-
const editors = ['code', 'nano', 'vim', 'vi'];
|
|
305
|
-
|
|
306
|
-
for (const editor of editors) {
|
|
307
|
-
try {
|
|
308
|
-
// Check if editor exists
|
|
309
|
-
execSync(`which ${editor}`, { stdio: 'ignore' });
|
|
310
|
-
|
|
311
|
-
console.log(`\n📝 Opening in ${editor}...`);
|
|
312
|
-
console.log(` Edit the template, save, and exit`);
|
|
313
|
-
|
|
314
|
-
// Open editor (blocking)
|
|
315
|
-
execSync(`${editor} ${templatePath}`, { stdio: 'inherit' });
|
|
316
|
-
|
|
317
|
-
// Validate template after editing
|
|
318
|
-
const content = fs.readFileSync(templatePath, 'utf8');
|
|
319
|
-
const validation = this.templateEngine.validate(content);
|
|
320
|
-
|
|
321
|
-
if (!validation.valid) {
|
|
322
|
-
console.log(`\n⚠️ Template validation warnings:`);
|
|
323
|
-
validation.errors.forEach(err => console.log(` - ${err}`));
|
|
324
|
-
console.log(`\n💡 These are suggestions. Template will still work.`);
|
|
325
|
-
} else {
|
|
326
|
-
console.log(`\n✅ Template is valid!`);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return true;
|
|
330
|
-
} catch (err) {
|
|
331
|
-
// Editor not found, try next
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// No editor found
|
|
337
|
-
console.log(`\n💡 Edit manually: ${templatePath}`);
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
run(args) {
|
|
342
|
-
if (args.length < 2) {
|
|
343
|
-
console.error('❌ Usage: autopm template:new <type> <name>');
|
|
344
|
-
console.log('\nExamples:');
|
|
345
|
-
console.log(' autopm template:new prd my-custom-prd');
|
|
346
|
-
console.log(' autopm template:new epic my-sprint');
|
|
347
|
-
console.log(' autopm template:new task my-development-task');
|
|
348
|
-
console.log('\nTypes: prd, epic, task');
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const type = args[0];
|
|
353
|
-
const name = args[1];
|
|
354
|
-
|
|
355
|
-
const success = this.create(type, name);
|
|
356
|
-
process.exit(success ? 0 : 1);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Main execution
|
|
361
|
-
if (require.main === module) {
|
|
362
|
-
const creator = new TemplateCreator();
|
|
363
|
-
creator.run(process.argv.slice(2));
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
module.exports = TemplateCreator;
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* PM System Validation Script (Node.js version)
|
|
6
|
-
* Migrated from bash script with 100% backward compatibility
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
async function validate() {
|
|
10
|
-
const result = {
|
|
11
|
-
errors: 0,
|
|
12
|
-
warnings: 0,
|
|
13
|
-
invalidFiles: 0,
|
|
14
|
-
messages: [],
|
|
15
|
-
exitCode: 0
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Helper function to add messages
|
|
19
|
-
function addMessage(message) {
|
|
20
|
-
result.messages.push(message);
|
|
21
|
-
// Only log if running as CLI
|
|
22
|
-
if (require.main === module) {
|
|
23
|
-
console.log(message);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Header
|
|
28
|
-
addMessage('Validating PM System...');
|
|
29
|
-
addMessage('');
|
|
30
|
-
addMessage('');
|
|
31
|
-
addMessage('🔍 Validating PM System');
|
|
32
|
-
addMessage('=======================');
|
|
33
|
-
addMessage('');
|
|
34
|
-
|
|
35
|
-
// Check directory structure
|
|
36
|
-
addMessage('📁 Directory Structure:');
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
if (fs.existsSync('.claude') && fs.statSync('.claude').isDirectory()) {
|
|
40
|
-
addMessage(' ✅ .claude directory exists');
|
|
41
|
-
} else {
|
|
42
|
-
addMessage(' ❌ .claude directory missing');
|
|
43
|
-
result.errors++;
|
|
44
|
-
}
|
|
45
|
-
} catch (err) {
|
|
46
|
-
addMessage(' ❌ .claude directory missing');
|
|
47
|
-
result.errors++;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Check optional directories
|
|
51
|
-
const optionalDirs = [
|
|
52
|
-
{ path: '.claude/prds', name: 'PRDs directory' },
|
|
53
|
-
{ path: '.claude/epics', name: 'Epics directory' },
|
|
54
|
-
{ path: '.claude/rules', name: 'Rules directory' }
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
for (const dir of optionalDirs) {
|
|
58
|
-
try {
|
|
59
|
-
if (fs.existsSync(dir.path) && fs.statSync(dir.path).isDirectory()) {
|
|
60
|
-
addMessage(` ✅ ${dir.name} exists`);
|
|
61
|
-
} else {
|
|
62
|
-
addMessage(` ⚠️ ${dir.name} missing`);
|
|
63
|
-
result.warnings++;
|
|
64
|
-
}
|
|
65
|
-
} catch (err) {
|
|
66
|
-
addMessage(` ⚠️ ${dir.name} missing`);
|
|
67
|
-
result.warnings++;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
addMessage('');
|
|
72
|
-
|
|
73
|
-
// Check for data integrity
|
|
74
|
-
addMessage('🗂️ Data Integrity:');
|
|
75
|
-
|
|
76
|
-
// Check epics have epic.md files
|
|
77
|
-
try {
|
|
78
|
-
if (fs.existsSync('.claude/epics')) {
|
|
79
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
80
|
-
.filter(dirent => dirent.isDirectory())
|
|
81
|
-
.map(dirent => dirent.name);
|
|
82
|
-
|
|
83
|
-
for (const epicDir of epicDirs) {
|
|
84
|
-
const epicPath = path.join('.claude/epics', epicDir);
|
|
85
|
-
const epicFilePath = path.join(epicPath, 'epic.md');
|
|
86
|
-
|
|
87
|
-
if (!fs.existsSync(epicFilePath)) {
|
|
88
|
-
addMessage(` ⚠️ Missing epic.md in ${epicDir}`);
|
|
89
|
-
result.warnings++;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
} catch (err) {
|
|
94
|
-
// Silently handle directory read errors
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Check for orphaned task files
|
|
98
|
-
try {
|
|
99
|
-
const orphanedFiles = [];
|
|
100
|
-
|
|
101
|
-
function findOrphanedFiles(dir) {
|
|
102
|
-
if (!fs.existsSync(dir)) return;
|
|
103
|
-
|
|
104
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
105
|
-
|
|
106
|
-
for (const item of items) {
|
|
107
|
-
const fullPath = path.join(dir, item.name);
|
|
108
|
-
|
|
109
|
-
if (item.isDirectory()) {
|
|
110
|
-
// Skip epic directories
|
|
111
|
-
if (fullPath.includes('.claude/epics/')) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
findOrphanedFiles(fullPath);
|
|
115
|
-
} else if (item.isFile() && /^[0-9].*\.md$/.test(item.name)) {
|
|
116
|
-
// Check if this is a numbered task file outside of epics
|
|
117
|
-
if (!fullPath.includes('.claude/epics/')) {
|
|
118
|
-
orphanedFiles.push(fullPath);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
findOrphanedFiles('.claude');
|
|
125
|
-
|
|
126
|
-
if (orphanedFiles.length > 0) {
|
|
127
|
-
addMessage(` ⚠️ Found ${orphanedFiles.length} orphaned task files`);
|
|
128
|
-
result.warnings++;
|
|
129
|
-
}
|
|
130
|
-
} catch (err) {
|
|
131
|
-
// Silently handle file system errors
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Reference check
|
|
135
|
-
addMessage('');
|
|
136
|
-
addMessage('🔗 Reference Check:');
|
|
137
|
-
|
|
138
|
-
let hasValidReferences = true;
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
if (fs.existsSync('.claude/epics')) {
|
|
142
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
143
|
-
.filter(dirent => dirent.isDirectory())
|
|
144
|
-
.map(dirent => dirent.name);
|
|
145
|
-
|
|
146
|
-
for (const epicDir of epicDirs) {
|
|
147
|
-
const epicPath = path.join('.claude/epics', epicDir);
|
|
148
|
-
|
|
149
|
-
if (!fs.existsSync(epicPath)) continue;
|
|
150
|
-
|
|
151
|
-
const files = fs.readdirSync(epicPath, { withFileTypes: true })
|
|
152
|
-
.filter(dirent => dirent.isFile() && /^[0-9].*\.md$/.test(dirent.name))
|
|
153
|
-
.map(dirent => dirent.name);
|
|
154
|
-
|
|
155
|
-
for (const taskFile of files) {
|
|
156
|
-
const taskPath = path.join(epicPath, taskFile);
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const content = fs.readFileSync(taskPath, 'utf8');
|
|
160
|
-
|
|
161
|
-
// Look for depends_on line
|
|
162
|
-
const dependsOnMatch = content.match(/^depends_on:\s*\[(.*?)\]/m);
|
|
163
|
-
|
|
164
|
-
if (dependsOnMatch && dependsOnMatch[1].trim()) {
|
|
165
|
-
const deps = dependsOnMatch[1]
|
|
166
|
-
.split(',')
|
|
167
|
-
.map(dep => dep.trim())
|
|
168
|
-
.filter(dep => dep.length > 0);
|
|
169
|
-
|
|
170
|
-
for (const dep of deps) {
|
|
171
|
-
const depPath = path.join(epicPath, `${dep}.md`);
|
|
172
|
-
|
|
173
|
-
if (!fs.existsSync(depPath)) {
|
|
174
|
-
const taskName = path.basename(taskFile, '.md');
|
|
175
|
-
addMessage(` ⚠️ Task ${taskName} references missing task: ${dep}`);
|
|
176
|
-
result.warnings++;
|
|
177
|
-
hasValidReferences = false;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
} catch (err) {
|
|
182
|
-
// Skip files that can't be read
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} catch (err) {
|
|
188
|
-
// Silently handle directory errors
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (hasValidReferences) {
|
|
192
|
-
addMessage(' ✅ All references valid');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Frontmatter validation
|
|
196
|
-
addMessage('');
|
|
197
|
-
addMessage('📝 Frontmatter Validation:');
|
|
198
|
-
|
|
199
|
-
let invalidFrontmatter = 0;
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
function checkFrontmatter(dir, relativePath = '') {
|
|
203
|
-
if (!fs.existsSync(dir)) return;
|
|
204
|
-
|
|
205
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
206
|
-
|
|
207
|
-
for (const item of items) {
|
|
208
|
-
const fullPath = path.join(dir, item.name);
|
|
209
|
-
const relPath = relativePath ? path.join(relativePath, item.name) : item.name;
|
|
210
|
-
|
|
211
|
-
if (item.isDirectory()) {
|
|
212
|
-
checkFrontmatter(fullPath, relPath);
|
|
213
|
-
} else if (item.isFile() && item.name.endsWith('.md')) {
|
|
214
|
-
// Only check files in epics and prds directories
|
|
215
|
-
if (fullPath.includes('.claude/epics/') || fullPath.includes('.claude/prds/')) {
|
|
216
|
-
try {
|
|
217
|
-
const content = fs.readFileSync(fullPath, 'utf8');
|
|
218
|
-
|
|
219
|
-
if (!content.startsWith('---')) {
|
|
220
|
-
addMessage(` ⚠️ Missing frontmatter: ${item.name}`);
|
|
221
|
-
invalidFrontmatter++;
|
|
222
|
-
}
|
|
223
|
-
} catch (err) {
|
|
224
|
-
// Skip files that can't be read
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
checkFrontmatter('.claude');
|
|
232
|
-
|
|
233
|
-
if (invalidFrontmatter === 0) {
|
|
234
|
-
addMessage(' ✅ All files have frontmatter');
|
|
235
|
-
}
|
|
236
|
-
} catch (err) {
|
|
237
|
-
// Silently handle file system errors
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
result.invalidFiles = invalidFrontmatter;
|
|
241
|
-
|
|
242
|
-
// Summary
|
|
243
|
-
addMessage('');
|
|
244
|
-
addMessage('📊 Validation Summary:');
|
|
245
|
-
addMessage(` Errors: ${result.errors}`);
|
|
246
|
-
addMessage(` Warnings: ${result.warnings}`);
|
|
247
|
-
addMessage(` Invalid files: ${result.invalidFiles}`);
|
|
248
|
-
|
|
249
|
-
if (result.errors === 0 && result.warnings === 0 && result.invalidFiles === 0) {
|
|
250
|
-
addMessage('');
|
|
251
|
-
addMessage('✅ System is healthy!');
|
|
252
|
-
} else {
|
|
253
|
-
addMessage('');
|
|
254
|
-
addMessage('💡 Run /pm:clean to fix some issues automatically');
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Always exit with 0 (matching bash behavior)
|
|
258
|
-
result.exitCode = 0;
|
|
259
|
-
|
|
260
|
-
return result;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Export for use as module
|
|
264
|
-
module.exports = validate;
|
|
265
|
-
|
|
266
|
-
// CLI execution
|
|
267
|
-
if (require.main === module) {
|
|
268
|
-
validate().then(result => {
|
|
269
|
-
process.exit(result.exitCode);
|
|
270
|
-
}).catch(err => {
|
|
271
|
-
console.error('Validation failed:', err.message);
|
|
272
|
-
process.exit(1);
|
|
273
|
-
});
|
|
274
|
-
}
|