claude-autopm 2.7.0 → 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 +307 -56
- package/autopm/.claude/.env +158 -0
- package/autopm/.claude/settings.local.json +9 -0
- package/bin/autopm.js +11 -2
- package/bin/commands/epic.js +23 -3
- package/bin/commands/plugin.js +395 -0
- package/bin/commands/team.js +184 -10
- package/install/install.js +223 -4
- package/lib/cli/commands/issue.js +360 -20
- package/lib/plugins/PluginManager.js +1328 -0
- package/lib/plugins/PluginManager.old.js +400 -0
- package/lib/providers/AzureDevOpsProvider.js +575 -0
- package/lib/providers/GitHubProvider.js +475 -0
- package/lib/services/EpicService.js +1092 -3
- package/lib/services/IssueService.js +991 -0
- package/package.json +9 -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,192 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PM Search Script - Node.js Implementation
|
|
5
|
-
*
|
|
6
|
-
* Migrated from search.sh to provide search functionality across PM content
|
|
7
|
-
* Maintains full compatibility with the original bash implementation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const path = require('path');
|
|
12
|
-
|
|
13
|
-
function searchContent(query) {
|
|
14
|
-
if (!query || query.trim() === '') {
|
|
15
|
-
throw new Error('❌ Please provide a search query\nUsage: /pm:search <query>');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const results = {
|
|
19
|
-
prds: [],
|
|
20
|
-
epics: [],
|
|
21
|
-
tasks: [],
|
|
22
|
-
total: 0
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Search in PRDs
|
|
26
|
-
if (fs.existsSync('.claude/prds')) {
|
|
27
|
-
try {
|
|
28
|
-
const prdFiles = fs.readdirSync('.claude/prds').filter(file => file.endsWith('.md'));
|
|
29
|
-
|
|
30
|
-
for (const file of prdFiles) {
|
|
31
|
-
const filePath = path.join('.claude/prds', file);
|
|
32
|
-
try {
|
|
33
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
34
|
-
const matches = (content.toLowerCase().match(new RegExp(query.toLowerCase(), 'g')) || []).length;
|
|
35
|
-
|
|
36
|
-
if (matches > 0) {
|
|
37
|
-
results.prds.push({
|
|
38
|
-
name: path.basename(file, '.md'),
|
|
39
|
-
matches: matches
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
// Skip files that can't be read
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} catch (error) {
|
|
48
|
-
// Directory doesn't exist or can't be read
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Search in Epics
|
|
53
|
-
if (fs.existsSync('.claude/epics')) {
|
|
54
|
-
try {
|
|
55
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
56
|
-
.filter(dirent => dirent.isDirectory())
|
|
57
|
-
.map(dirent => dirent.name);
|
|
58
|
-
|
|
59
|
-
for (const epicDir of epicDirs) {
|
|
60
|
-
const epicFilePath = path.join('.claude/epics', epicDir, 'epic.md');
|
|
61
|
-
|
|
62
|
-
if (fs.existsSync(epicFilePath)) {
|
|
63
|
-
try {
|
|
64
|
-
const content = fs.readFileSync(epicFilePath, 'utf8');
|
|
65
|
-
const matches = (content.toLowerCase().match(new RegExp(query.toLowerCase(), 'g')) || []).length;
|
|
66
|
-
|
|
67
|
-
if (matches > 0) {
|
|
68
|
-
results.epics.push({
|
|
69
|
-
name: epicDir,
|
|
70
|
-
matches: matches
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
// Skip files that can't be read
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
// Directory doesn't exist or can't be read
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Search in Tasks (limit to 10 results)
|
|
85
|
-
if (fs.existsSync('.claude/epics')) {
|
|
86
|
-
try {
|
|
87
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
88
|
-
.filter(dirent => dirent.isDirectory())
|
|
89
|
-
.map(dirent => dirent.name);
|
|
90
|
-
|
|
91
|
-
for (const epicDir of epicDirs) {
|
|
92
|
-
const epicPath = path.join('.claude/epics', epicDir);
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
const files = fs.readdirSync(epicPath)
|
|
96
|
-
.filter(file => /^\d+\.md$/.test(file));
|
|
97
|
-
|
|
98
|
-
for (const file of files) {
|
|
99
|
-
if (results.tasks.length >= 10) break;
|
|
100
|
-
|
|
101
|
-
const taskFilePath = path.join(epicPath, file);
|
|
102
|
-
try {
|
|
103
|
-
const content = fs.readFileSync(taskFilePath, 'utf8');
|
|
104
|
-
|
|
105
|
-
if (content.toLowerCase().includes(query.toLowerCase())) {
|
|
106
|
-
results.tasks.push({
|
|
107
|
-
taskNum: path.basename(file, '.md'),
|
|
108
|
-
epicName: epicDir
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
} catch (error) {
|
|
112
|
-
// Skip files that can't be read
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
} catch (error) {
|
|
117
|
-
// Epic directory can't be read
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (results.tasks.length >= 10) break;
|
|
122
|
-
}
|
|
123
|
-
} catch (error) {
|
|
124
|
-
// Directory doesn't exist or can't be read
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Calculate total matches
|
|
129
|
-
results.total = results.prds.length + results.epics.length + results.tasks.length;
|
|
130
|
-
|
|
131
|
-
return results;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function formatSearchResults(query, results) {
|
|
135
|
-
let output = `Searching for '${query}'...\n\n\n`;
|
|
136
|
-
output += `🔍 Search results for: '${query}'\n`;
|
|
137
|
-
output += `================================\n\n`;
|
|
138
|
-
|
|
139
|
-
// PRDs section
|
|
140
|
-
output += `📄 PRDs:\n`;
|
|
141
|
-
if (results.prds.length > 0) {
|
|
142
|
-
for (const prd of results.prds) {
|
|
143
|
-
output += ` • ${prd.name} (${prd.matches} matches)\n`;
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
output += ` No matches\n`;
|
|
147
|
-
}
|
|
148
|
-
output += `\n`;
|
|
149
|
-
|
|
150
|
-
// Epics section
|
|
151
|
-
output += `📚 Epics:\n`;
|
|
152
|
-
if (results.epics.length > 0) {
|
|
153
|
-
for (const epic of results.epics) {
|
|
154
|
-
output += ` • ${epic.name} (${epic.matches} matches)\n`;
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
output += ` No matches\n`;
|
|
158
|
-
}
|
|
159
|
-
output += `\n`;
|
|
160
|
-
|
|
161
|
-
// Tasks section
|
|
162
|
-
output += `📝 Tasks:\n`;
|
|
163
|
-
if (results.tasks.length > 0) {
|
|
164
|
-
for (const task of results.tasks) {
|
|
165
|
-
output += ` • Task #${task.taskNum} in ${task.epicName}\n`;
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
output += ` No matches\n`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Summary
|
|
172
|
-
output += `\n📊 Total files with matches: ${results.total}\n`;
|
|
173
|
-
|
|
174
|
-
return output;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// CommonJS export for testing
|
|
178
|
-
module.exports = { searchContent, formatSearchResults };
|
|
179
|
-
|
|
180
|
-
// CLI execution
|
|
181
|
-
if (require.main === module) {
|
|
182
|
-
const query = process.argv[2];
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
const results = searchContent(query);
|
|
186
|
-
console.log(formatSearchResults(query, results));
|
|
187
|
-
process.exit(0);
|
|
188
|
-
} catch (error) {
|
|
189
|
-
console.error(error.message);
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# PM Search Script - Wrapper for Node.js implementation
|
|
4
|
-
# This wrapper maintains backward compatibility while delegating to the Node.js version
|
|
5
|
-
|
|
6
|
-
# Get the directory of this script
|
|
7
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
-
|
|
9
|
-
# Check if Node.js is available
|
|
10
|
-
if command -v node >/dev/null 2>&1; then
|
|
11
|
-
# Use the Node.js implementation
|
|
12
|
-
node "$SCRIPT_DIR/search.js" "$@"
|
|
13
|
-
exit $?
|
|
14
|
-
else
|
|
15
|
-
# Fallback to the original bash implementation if Node.js is not available
|
|
16
|
-
echo "⚠️ Node.js not found, falling back to bash implementation"
|
|
17
|
-
echo ""
|
|
18
|
-
|
|
19
|
-
# Original bash implementation (preserved for fallback)
|
|
20
|
-
query="$1"
|
|
21
|
-
|
|
22
|
-
if [ -z "$query" ]; then
|
|
23
|
-
echo "❌ Please provide a search query"
|
|
24
|
-
echo "Usage: /pm:search <query>"
|
|
25
|
-
exit 1
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
echo "Searching for '$query'..."
|
|
29
|
-
echo ""
|
|
30
|
-
echo ""
|
|
31
|
-
|
|
32
|
-
echo "🔍 Search results for: '$query'"
|
|
33
|
-
echo "================================"
|
|
34
|
-
echo ""
|
|
35
|
-
|
|
36
|
-
# Search in PRDs
|
|
37
|
-
if [ -d ".claude/prds" ]; then
|
|
38
|
-
echo "📄 PRDs:"
|
|
39
|
-
results=$(grep -l -i "$query" .claude/prds/*.md 2>/dev/null)
|
|
40
|
-
if [ -n "$results" ]; then
|
|
41
|
-
for file in $results; do
|
|
42
|
-
name=$(basename "$file" .md)
|
|
43
|
-
matches=$(grep -c -i "$query" "$file")
|
|
44
|
-
echo " • $name ($matches matches)"
|
|
45
|
-
done
|
|
46
|
-
else
|
|
47
|
-
echo " No matches"
|
|
48
|
-
fi
|
|
49
|
-
echo ""
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
# Search in Epics
|
|
53
|
-
if [ -d ".claude/epics" ]; then
|
|
54
|
-
echo "📚 Epics:"
|
|
55
|
-
results=$(find .claude/epics -name "epic.md" -exec grep -l -i "$query" {} \; 2>/dev/null)
|
|
56
|
-
if [ -n "$results" ]; then
|
|
57
|
-
for file in $results; do
|
|
58
|
-
epic_name=$(basename $(dirname "$file"))
|
|
59
|
-
matches=$(grep -c -i "$query" "$file")
|
|
60
|
-
echo " • $epic_name ($matches matches)"
|
|
61
|
-
done
|
|
62
|
-
else
|
|
63
|
-
echo " No matches"
|
|
64
|
-
fi
|
|
65
|
-
echo ""
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
# Search in Tasks
|
|
69
|
-
if [ -d ".claude/epics" ]; then
|
|
70
|
-
echo "📝 Tasks:"
|
|
71
|
-
results=$(find .claude/epics -name "[0-9]*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | head -10)
|
|
72
|
-
if [ -n "$results" ]; then
|
|
73
|
-
for file in $results; do
|
|
74
|
-
epic_name=$(basename $(dirname "$file"))
|
|
75
|
-
task_num=$(basename "$file" .md)
|
|
76
|
-
echo " • Task #$task_num in $epic_name"
|
|
77
|
-
done
|
|
78
|
-
else
|
|
79
|
-
echo " No matches"
|
|
80
|
-
fi
|
|
81
|
-
fi
|
|
82
|
-
|
|
83
|
-
# Summary
|
|
84
|
-
total=$(find .claude -name "*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | wc -l)
|
|
85
|
-
echo ""
|
|
86
|
-
echo "📊 Total files with matches: $total"
|
|
87
|
-
|
|
88
|
-
exit 0
|
|
89
|
-
fi
|
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* PM Standup Script (Node.js version)
|
|
6
|
-
* Migrated from bash script with 100% backward compatibility
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
async function standup() {
|
|
10
|
-
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
|
|
11
|
-
|
|
12
|
-
const result = {
|
|
13
|
-
date: today,
|
|
14
|
-
activity: { prdCount: 0, epicCount: 0, taskCount: 0, updateCount: 0 },
|
|
15
|
-
inProgress: [],
|
|
16
|
-
nextTasks: [],
|
|
17
|
-
stats: { totalTasks: 0, openTasks: 0, closedTasks: 0 },
|
|
18
|
-
messages: []
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// Helper function to add messages
|
|
22
|
-
function addMessage(message) {
|
|
23
|
-
result.messages.push(message);
|
|
24
|
-
// Only log if running as CLI
|
|
25
|
-
if (require.main === module) {
|
|
26
|
-
console.log(message);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Header messages to match bash output exactly
|
|
31
|
-
addMessage(`📅 Daily Standup - ${today}`);
|
|
32
|
-
addMessage('================================');
|
|
33
|
-
addMessage('');
|
|
34
|
-
|
|
35
|
-
addMessage('Getting status...');
|
|
36
|
-
addMessage('');
|
|
37
|
-
addMessage('');
|
|
38
|
-
|
|
39
|
-
addMessage('📝 Today\'s Activity:');
|
|
40
|
-
addMessage('====================');
|
|
41
|
-
addMessage('');
|
|
42
|
-
|
|
43
|
-
// Find files modified today
|
|
44
|
-
try {
|
|
45
|
-
const recentFiles = await findRecentFiles('.claude');
|
|
46
|
-
|
|
47
|
-
// Count by type
|
|
48
|
-
for (const filePath of recentFiles) {
|
|
49
|
-
if (filePath.includes('/prds/')) {
|
|
50
|
-
result.activity.prdCount++;
|
|
51
|
-
} else if (filePath.endsWith('/epic.md')) {
|
|
52
|
-
result.activity.epicCount++;
|
|
53
|
-
} else if (/\/\d+\.md$/.test(filePath)) {
|
|
54
|
-
result.activity.taskCount++;
|
|
55
|
-
} else if (filePath.includes('/updates/')) {
|
|
56
|
-
result.activity.updateCount++;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Display activity counts
|
|
61
|
-
if (result.activity.prdCount > 0) {
|
|
62
|
-
addMessage(` • Modified ${result.activity.prdCount} PRD(s)`);
|
|
63
|
-
}
|
|
64
|
-
if (result.activity.epicCount > 0) {
|
|
65
|
-
addMessage(` • Updated ${result.activity.epicCount} epic(s)`);
|
|
66
|
-
}
|
|
67
|
-
if (result.activity.taskCount > 0) {
|
|
68
|
-
addMessage(` • Worked on ${result.activity.taskCount} task(s)`);
|
|
69
|
-
}
|
|
70
|
-
if (result.activity.updateCount > 0) {
|
|
71
|
-
addMessage(` • Posted ${result.activity.updateCount} progress update(s)`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (recentFiles.length === 0) {
|
|
75
|
-
addMessage(' No activity recorded today');
|
|
76
|
-
}
|
|
77
|
-
} catch (err) {
|
|
78
|
-
addMessage(' No activity recorded today');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
addMessage('');
|
|
82
|
-
addMessage('🔄 Currently In Progress:');
|
|
83
|
-
|
|
84
|
-
// Show active work items
|
|
85
|
-
try {
|
|
86
|
-
const inProgressItems = await findInProgressTasks();
|
|
87
|
-
result.inProgress = inProgressItems;
|
|
88
|
-
|
|
89
|
-
for (const item of inProgressItems) {
|
|
90
|
-
addMessage(` • Issue #${item.issueNum} (${item.epicName}) - ${item.completion || '0%'} complete`);
|
|
91
|
-
}
|
|
92
|
-
} catch (err) {
|
|
93
|
-
// Silently handle errors
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
addMessage('');
|
|
97
|
-
addMessage('⏭️ Next Available Tasks:');
|
|
98
|
-
|
|
99
|
-
// Show top 3 available tasks
|
|
100
|
-
try {
|
|
101
|
-
const availableTasks = await findAvailableTasks(3);
|
|
102
|
-
result.nextTasks = availableTasks;
|
|
103
|
-
|
|
104
|
-
for (const task of availableTasks) {
|
|
105
|
-
addMessage(` • #${task.taskNum} - ${task.name}`);
|
|
106
|
-
}
|
|
107
|
-
} catch (err) {
|
|
108
|
-
// Silently handle errors
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
addMessage('');
|
|
112
|
-
addMessage('📊 Quick Stats:');
|
|
113
|
-
|
|
114
|
-
// Calculate task statistics
|
|
115
|
-
try {
|
|
116
|
-
const stats = await calculateTaskStats();
|
|
117
|
-
result.stats = stats;
|
|
118
|
-
|
|
119
|
-
addMessage(` Tasks: ${stats.openTasks} open, ${stats.closedTasks} closed, ${stats.totalTasks} total`);
|
|
120
|
-
} catch (err) {
|
|
121
|
-
addMessage(' Tasks: 0 open, 0 closed, 0 total');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Helper function to find files modified today
|
|
128
|
-
async function findRecentFiles(directory) {
|
|
129
|
-
const files = [];
|
|
130
|
-
|
|
131
|
-
if (!fs.existsSync(directory)) {
|
|
132
|
-
return files;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000);
|
|
136
|
-
|
|
137
|
-
function scanDirectory(dir) {
|
|
138
|
-
try {
|
|
139
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
140
|
-
|
|
141
|
-
for (const item of items) {
|
|
142
|
-
const fullPath = path.join(dir, item.name);
|
|
143
|
-
|
|
144
|
-
if (item.isDirectory()) {
|
|
145
|
-
scanDirectory(fullPath);
|
|
146
|
-
} else if (item.isFile() && item.name.endsWith('.md')) {
|
|
147
|
-
try {
|
|
148
|
-
const stats = fs.statSync(fullPath);
|
|
149
|
-
if (stats.mtime.getTime() > oneDayAgo) {
|
|
150
|
-
files.push(fullPath);
|
|
151
|
-
}
|
|
152
|
-
} catch (err) {
|
|
153
|
-
// Skip files we can't stat
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
} catch (err) {
|
|
158
|
-
// Skip directories we can't read
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
scanDirectory(directory);
|
|
163
|
-
return files;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Helper function to find tasks currently in progress
|
|
167
|
-
async function findInProgressTasks() {
|
|
168
|
-
const inProgress = [];
|
|
169
|
-
|
|
170
|
-
if (!fs.existsSync('.claude/epics')) {
|
|
171
|
-
return inProgress;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
176
|
-
.filter(dirent => dirent.isDirectory())
|
|
177
|
-
.map(dirent => dirent.name);
|
|
178
|
-
|
|
179
|
-
for (const epicName of epicDirs) {
|
|
180
|
-
const updatesDir = path.join('.claude/epics', epicName, 'updates');
|
|
181
|
-
|
|
182
|
-
if (fs.existsSync(updatesDir)) {
|
|
183
|
-
try {
|
|
184
|
-
const updateDirs = fs.readdirSync(updatesDir, { withFileTypes: true })
|
|
185
|
-
.filter(dirent => dirent.isDirectory())
|
|
186
|
-
.map(dirent => dirent.name);
|
|
187
|
-
|
|
188
|
-
for (const issueNum of updateDirs) {
|
|
189
|
-
const progressFile = path.join(updatesDir, issueNum, 'progress.md');
|
|
190
|
-
|
|
191
|
-
if (fs.existsSync(progressFile)) {
|
|
192
|
-
try {
|
|
193
|
-
const content = fs.readFileSync(progressFile, 'utf8');
|
|
194
|
-
const completionMatch = content.match(/^completion:\s*(.+)$/m);
|
|
195
|
-
const completion = completionMatch ? completionMatch[1].trim() : '0%';
|
|
196
|
-
|
|
197
|
-
inProgress.push({
|
|
198
|
-
issueNum,
|
|
199
|
-
epicName,
|
|
200
|
-
completion
|
|
201
|
-
});
|
|
202
|
-
} catch (err) {
|
|
203
|
-
// Skip files we can't read
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} catch (err) {
|
|
208
|
-
// Skip directories we can't read
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
} catch (err) {
|
|
213
|
-
// Silently handle errors
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return inProgress;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Helper function to find next available tasks
|
|
220
|
-
async function findAvailableTasks(limit = 3) {
|
|
221
|
-
const availableTasks = [];
|
|
222
|
-
|
|
223
|
-
if (!fs.existsSync('.claude/epics')) {
|
|
224
|
-
return availableTasks;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
229
|
-
.filter(dirent => dirent.isDirectory())
|
|
230
|
-
.map(dirent => dirent.name);
|
|
231
|
-
|
|
232
|
-
for (const epicName of epicDirs) {
|
|
233
|
-
const epicPath = path.join('.claude/epics', epicName);
|
|
234
|
-
|
|
235
|
-
if (availableTasks.length >= limit) {
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
const taskFiles = fs.readdirSync(epicPath)
|
|
241
|
-
.filter(file => /^[0-9].*\.md$/.test(file))
|
|
242
|
-
.sort();
|
|
243
|
-
|
|
244
|
-
for (const taskFile of taskFiles) {
|
|
245
|
-
if (availableTasks.length >= limit) {
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const taskPath = path.join(epicPath, taskFile);
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
const content = fs.readFileSync(taskPath, 'utf8');
|
|
253
|
-
|
|
254
|
-
// Check if task is open
|
|
255
|
-
const statusMatch = content.match(/^status:\s*(.+)$/m);
|
|
256
|
-
const status = statusMatch ? statusMatch[1].trim() : '';
|
|
257
|
-
|
|
258
|
-
if (status !== 'open' && status !== '') {
|
|
259
|
-
continue; // Skip non-open tasks
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Check dependencies
|
|
263
|
-
const depsMatch = content.match(/^depends_on:\s*\[(.*?)\]/m);
|
|
264
|
-
const deps = depsMatch ? depsMatch[1].trim() : '';
|
|
265
|
-
|
|
266
|
-
// If no dependencies or empty, task is available
|
|
267
|
-
if (!deps || deps === '') {
|
|
268
|
-
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
269
|
-
const name = nameMatch ? nameMatch[1].trim() : 'Unnamed Task';
|
|
270
|
-
const taskNum = path.basename(taskFile, '.md');
|
|
271
|
-
|
|
272
|
-
availableTasks.push({
|
|
273
|
-
taskNum,
|
|
274
|
-
name,
|
|
275
|
-
epicName
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
} catch (err) {
|
|
279
|
-
// Skip files we can't read
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
} catch (err) {
|
|
283
|
-
// Skip directories we can't read
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
} catch (err) {
|
|
287
|
-
// Silently handle errors
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return availableTasks;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Helper function to calculate task statistics
|
|
294
|
-
async function calculateTaskStats() {
|
|
295
|
-
const stats = { totalTasks: 0, openTasks: 0, closedTasks: 0 };
|
|
296
|
-
|
|
297
|
-
if (!fs.existsSync('.claude/epics')) {
|
|
298
|
-
return stats;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
const epicDirs = fs.readdirSync('.claude/epics', { withFileTypes: true })
|
|
303
|
-
.filter(dirent => dirent.isDirectory())
|
|
304
|
-
.map(dirent => dirent.name);
|
|
305
|
-
|
|
306
|
-
for (const epicName of epicDirs) {
|
|
307
|
-
const epicPath = path.join('.claude/epics', epicName);
|
|
308
|
-
|
|
309
|
-
try {
|
|
310
|
-
const taskFiles = fs.readdirSync(epicPath)
|
|
311
|
-
.filter(file => /^[0-9].*\.md$/.test(file));
|
|
312
|
-
|
|
313
|
-
for (const taskFile of taskFiles) {
|
|
314
|
-
stats.totalTasks++;
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
const taskPath = path.join(epicPath, taskFile);
|
|
318
|
-
const content = fs.readFileSync(taskPath, 'utf8');
|
|
319
|
-
|
|
320
|
-
// Check status line
|
|
321
|
-
const statusMatch = content.match(/^status:\s*(.+)$/m);
|
|
322
|
-
const status = statusMatch ? statusMatch[1].trim() : '';
|
|
323
|
-
|
|
324
|
-
if (status === 'closed') {
|
|
325
|
-
stats.closedTasks++;
|
|
326
|
-
} else {
|
|
327
|
-
stats.openTasks++;
|
|
328
|
-
}
|
|
329
|
-
} catch (err) {
|
|
330
|
-
// If we can't read the file, count as open
|
|
331
|
-
stats.openTasks++;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
} catch (err) {
|
|
335
|
-
// Skip directories we can't read
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
} catch (err) {
|
|
339
|
-
// Silently handle errors
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return stats;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Export for use as module
|
|
346
|
-
module.exports = {
|
|
347
|
-
standup,
|
|
348
|
-
findRecentFiles,
|
|
349
|
-
findInProgressTasks,
|
|
350
|
-
findAvailableTasks,
|
|
351
|
-
calculateTaskStats
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
// CLI execution
|
|
355
|
-
if (require.main === module) {
|
|
356
|
-
module.exports.standup().then(result => {
|
|
357
|
-
process.exit(0);
|
|
358
|
-
}).catch(err => {
|
|
359
|
-
console.error('Standup failed:', err.message);
|
|
360
|
-
process.exit(1);
|
|
361
|
-
});
|
|
362
|
-
}
|