specweave 1.0.235 ā 1.0.239
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 +89 -193
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts +37 -0
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js +176 -0
- package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-batch-sync.d.ts +36 -0
- package/dist/plugins/specweave-github/lib/github-batch-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-batch-sync.js +115 -0
- package/dist/plugins/specweave-github/lib/github-batch-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-board-resolver-v2.d.ts +37 -0
- package/dist/plugins/specweave-github/lib/github-board-resolver-v2.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-board-resolver-v2.js +56 -0
- package/dist/plugins/specweave-github/lib/github-board-resolver-v2.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-conflict-resolver.d.ts +68 -0
- package/dist/plugins/specweave-github/lib/github-conflict-resolver.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-conflict-resolver.js +102 -0
- package/dist/plugins/specweave-github/lib/github-conflict-resolver.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-cross-repo-sync.d.ts +64 -0
- package/dist/plugins/specweave-github/lib/github-cross-repo-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-cross-repo-sync.js +162 -0
- package/dist/plugins/specweave-github/lib/github-cross-repo-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-field-sync.d.ts +50 -0
- package/dist/plugins/specweave-github/lib/github-field-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-field-sync.js +107 -0
- package/dist/plugins/specweave-github/lib/github-field-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-graphql-client.d.ts +53 -0
- package/dist/plugins/specweave-github/lib/github-graphql-client.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-graphql-client.js +138 -0
- package/dist/plugins/specweave-github/lib/github-graphql-client.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-generator.d.ts +40 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-generator.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-generator.js +50 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-generator.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-parser.d.ts +30 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-parser.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-parser.js +75 -0
- package/dist/plugins/specweave-github/lib/github-issue-body-parser.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-pull-sync.d.ts +94 -0
- package/dist/plugins/specweave-github/lib/github-pull-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-pull-sync.js +232 -0
- package/dist/plugins/specweave-github/lib/github-pull-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-push-sync.d.ts +50 -0
- package/dist/plugins/specweave-github/lib/github-push-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-push-sync.js +114 -0
- package/dist/plugins/specweave-github/lib/github-push-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-rate-limiter.d.ts +53 -0
- package/dist/plugins/specweave-github/lib/github-rate-limiter.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-rate-limiter.js +109 -0
- package/dist/plugins/specweave-github/lib/github-rate-limiter.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.d.ts +21 -0
- package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.js +161 -0
- package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-sync-orchestrator.d.ts +46 -0
- package/dist/plugins/specweave-github/lib/github-sync-orchestrator.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-sync-orchestrator.js +99 -0
- package/dist/plugins/specweave-github/lib/github-sync-orchestrator.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-us-auto-closer.d.ts +43 -0
- package/dist/plugins/specweave-github/lib/github-us-auto-closer.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-us-auto-closer.js +153 -0
- package/dist/plugins/specweave-github/lib/github-us-auto-closer.js.map +1 -0
- package/dist/plugins/specweave-github/lib/index.d.ts +1 -4
- package/dist/plugins/specweave-github/lib/index.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/index.js +1 -4
- package/dist/plugins/specweave-github/lib/index.js.map +1 -1
- package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts +7 -0
- package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.js +15 -0
- package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.js.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-detector.d.ts +10 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-detector.js +36 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-detector.js.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-runner.d.ts +25 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-runner.d.ts.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-runner.js +57 -0
- package/dist/plugins/specweave-testing/lib/playwright-cli-runner.js.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-routing.d.ts +7 -0
- package/dist/plugins/specweave-testing/lib/playwright-routing.d.ts.map +1 -0
- package/dist/plugins/specweave-testing/lib/playwright-routing.js +17 -0
- package/dist/plugins/specweave-testing/lib/playwright-routing.js.map +1 -0
- package/dist/src/cli/commands/auto.d.ts.map +1 -1
- package/dist/src/cli/commands/auto.js +1 -2
- package/dist/src/cli/commands/auto.js.map +1 -1
- package/dist/src/cli/commands/cancel-auto.js +1 -2
- package/dist/src/cli/commands/cancel-auto.js.map +1 -1
- package/dist/src/cli/commands/living-docs.js +2 -2
- package/dist/src/cli/commands/living-docs.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts.map +1 -1
- package/dist/src/cli/commands/update.js +1 -2
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/core/config/types.d.ts +8 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js +3 -0
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/types/sync-profile.d.ts +72 -0
- package/dist/src/core/types/sync-profile.d.ts.map +1 -1
- package/dist/src/core/types/sync-profile.js +6 -0
- package/dist/src/core/types/sync-profile.js.map +1 -1
- package/package.json +2 -2
- package/plugins/specweave/hooks/hooks.json +2 -2
- package/plugins/specweave/hooks/startup-health-check.sh +1 -1
- package/plugins/specweave/hooks/stop-auto-v5.sh +166 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +10 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +21 -1
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +1 -1
- package/plugins/specweave/skills/auto/SKILL.md +71 -251
- package/plugins/specweave/skills/team-build/SKILL.md +370 -0
- package/plugins/specweave/skills/team-merge/SKILL.md +123 -0
- package/plugins/specweave/skills/team-orchestrate/SKILL.md +800 -0
- package/plugins/specweave/skills/team-status/SKILL.md +89 -0
- package/plugins/specweave-github/MULTI-PROJECT-SYNC-ARCHITECTURE.md +94 -8
- package/plugins/specweave-github/commands/sync.md +17 -3
- package/plugins/specweave-github/hooks/github-ac-sync-handler.sh +255 -0
- package/plugins/specweave-github/hooks/github-auto-create-handler.sh +455 -0
- package/plugins/specweave-github/lib/github-ac-comment-poster.js +150 -0
- package/plugins/specweave-github/lib/github-ac-comment-poster.ts +245 -0
- package/plugins/specweave-github/lib/github-batch-sync.js +93 -0
- package/plugins/specweave-github/lib/github-batch-sync.ts +152 -0
- package/plugins/specweave-github/lib/github-board-resolver-v2.js +47 -0
- package/plugins/specweave-github/lib/github-board-resolver-v2.ts +73 -0
- package/plugins/specweave-github/lib/github-conflict-resolver.js +90 -0
- package/plugins/specweave-github/lib/github-conflict-resolver.ts +154 -0
- package/plugins/specweave-github/lib/github-cross-repo-sync.js +168 -0
- package/plugins/specweave-github/lib/github-cross-repo-sync.ts +252 -0
- package/plugins/specweave-github/lib/github-field-sync.js +116 -0
- package/plugins/specweave-github/lib/github-field-sync.ts +165 -0
- package/plugins/specweave-github/lib/github-graphql-client.js +129 -0
- package/plugins/specweave-github/lib/github-graphql-client.ts +181 -0
- package/plugins/specweave-github/lib/github-issue-body-generator.js +30 -0
- package/plugins/specweave-github/lib/github-issue-body-generator.ts +76 -0
- package/plugins/specweave-github/lib/github-issue-body-parser.js +55 -0
- package/plugins/specweave-github/lib/github-issue-body-parser.ts +92 -0
- package/plugins/specweave-github/lib/github-pull-sync.js +185 -0
- package/plugins/specweave-github/lib/github-pull-sync.ts +343 -0
- package/plugins/specweave-github/lib/github-push-sync.js +119 -0
- package/plugins/specweave-github/lib/github-push-sync.ts +174 -0
- package/plugins/specweave-github/lib/github-rate-limiter.js +96 -0
- package/plugins/specweave-github/lib/github-rate-limiter.ts +143 -0
- package/plugins/specweave-github/lib/github-spec-frontmatter-updater.js +117 -0
- package/plugins/specweave-github/lib/github-spec-frontmatter-updater.ts +180 -0
- package/plugins/specweave-github/lib/github-sync-orchestrator.js +84 -0
- package/plugins/specweave-github/lib/github-sync-orchestrator.ts +156 -0
- package/plugins/specweave-github/lib/github-us-auto-closer.js +134 -0
- package/plugins/specweave-github/lib/github-us-auto-closer.ts +226 -0
- package/plugins/specweave-github/lib/index.js +1 -7
- package/plugins/specweave-github/lib/index.ts +1 -4
- package/plugins/specweave-github/skills/github-sync/SKILL.md +76 -4
- package/plugins/specweave-testing/commands/e2e-setup.md +18 -0
- package/plugins/specweave-testing/commands/ui-automate.md +2 -0
- package/plugins/specweave-testing/commands/ui-inspect.md +8 -0
- package/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts +6 -0
- package/plugins/specweave-testing/lib/playwright-ci-defaults.js +14 -0
- package/plugins/specweave-testing/lib/playwright-ci-defaults.ts +24 -0
- package/plugins/specweave-testing/lib/playwright-cli-detector.js +33 -0
- package/plugins/specweave-testing/lib/playwright-cli-detector.ts +48 -0
- package/plugins/specweave-testing/lib/playwright-cli-runner.js +58 -0
- package/plugins/specweave-testing/lib/playwright-cli-runner.ts +80 -0
- package/plugins/specweave-testing/lib/playwright-routing.js +16 -0
- package/plugins/specweave-testing/lib/playwright-routing.ts +38 -0
- package/plugins/specweave-testing/skills/e2e-testing/SKILL.md +38 -0
- package/src/templates/CLAUDE.md.template +7 -0
- package/src/templates/config.json.template +9 -1
- package/dist/plugins/specweave-github/lib/subtask-sync.d.ts +0 -51
- package/dist/plugins/specweave-github/lib/subtask-sync.d.ts.map +0 -1
- package/dist/plugins/specweave-github/lib/subtask-sync.js +0 -147
- package/dist/plugins/specweave-github/lib/subtask-sync.js.map +0 -1
- package/dist/plugins/specweave-github/lib/task-parser.d.ts +0 -37
- package/dist/plugins/specweave-github/lib/task-parser.d.ts.map +0 -1
- package/dist/plugins/specweave-github/lib/task-parser.js +0 -211
- package/dist/plugins/specweave-github/lib/task-parser.js.map +0 -1
- package/dist/plugins/specweave-github/lib/task-sync.d.ts +0 -56
- package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +0 -1
- package/dist/plugins/specweave-github/lib/task-sync.js +0 -375
- package/dist/plugins/specweave-github/lib/task-sync.js.map +0 -1
- package/plugins/specweave/hooks/validate-completion-conditions.sh +0 -474
- package/plugins/specweave-github/lib/subtask-sync.d.ts +0 -51
- package/plugins/specweave-github/lib/subtask-sync.d.ts.map +0 -1
- package/plugins/specweave-github/lib/subtask-sync.js +0 -154
- package/plugins/specweave-github/lib/subtask-sync.js.map +0 -1
- package/plugins/specweave-github/lib/subtask-sync.ts +0 -225
- package/plugins/specweave-github/lib/task-parser.d.js +0 -0
- package/plugins/specweave-github/lib/task-parser.d.ts +0 -37
- package/plugins/specweave-github/lib/task-parser.d.ts.map +0 -1
- package/plugins/specweave-github/lib/task-parser.js +0 -195
- package/plugins/specweave-github/lib/task-parser.js.map +0 -1
- package/plugins/specweave-github/lib/task-parser.ts +0 -246
- package/plugins/specweave-github/lib/task-sync.d.js +0 -0
- package/plugins/specweave-github/lib/task-sync.d.ts +0 -51
- package/plugins/specweave-github/lib/task-sync.d.ts.map +0 -1
- package/plugins/specweave-github/lib/task-sync.js +0 -415
- package/plugins/specweave-github/lib/task-sync.js.map +0 -1
- package/plugins/specweave-github/lib/task-sync.ts +0 -451
- package/plugins/specweave-github/skills/github-issue-tracker/SKILL.md +0 -496
- /package/plugins/specweave/hooks/{stop-auto.sh ā _archive/stop-auto-v4-legacy.sh} +0 -0
- /package/plugins/{specweave-github/lib/subtask-sync.d.js ā specweave-testing/lib/playwright-ci-defaults.d.js} +0 -0
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Task-level GitHub synchronization
|
|
3
|
-
* Orchestrates syncing tasks.md to GitHub issues
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as fs from 'fs';
|
|
7
|
-
import * as path from 'path';
|
|
8
|
-
import * as yaml from 'js-yaml';
|
|
9
|
-
import { GitHubClient } from './github-client';
|
|
10
|
-
import { TaskParser } from './task-parser';
|
|
11
|
-
import { Task, IncrementMetadata, SyncResult, GitHubSyncOptions } from './types';
|
|
12
|
-
|
|
13
|
-
export class TaskSync {
|
|
14
|
-
private client: GitHubClient;
|
|
15
|
-
private incrementPath: string;
|
|
16
|
-
|
|
17
|
-
constructor(incrementPath: string, repo?: string) {
|
|
18
|
-
this.incrementPath = incrementPath;
|
|
19
|
-
this.client = new GitHubClient(repo);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Sync all tasks to GitHub (main entry point)
|
|
24
|
-
*/
|
|
25
|
-
async syncTasks(options: GitHubSyncOptions = {}): Promise<SyncResult> {
|
|
26
|
-
const {
|
|
27
|
-
force = false,
|
|
28
|
-
dryRun = false,
|
|
29
|
-
batchDelay = 6000,
|
|
30
|
-
batchSize = 10,
|
|
31
|
-
milestoneDays = 2, // SpecWeave default: 2 days (AI velocity)
|
|
32
|
-
projectName,
|
|
33
|
-
fastMode = false
|
|
34
|
-
} = options;
|
|
35
|
-
|
|
36
|
-
console.log(`\nš Syncing increment to GitHub...`);
|
|
37
|
-
|
|
38
|
-
// 1. Check prerequisites
|
|
39
|
-
const ghCheck = GitHubClient.checkGitHubCLI();
|
|
40
|
-
if (!ghCheck.installed || !ghCheck.authenticated) {
|
|
41
|
-
throw new Error(ghCheck.error || 'GitHub CLI check failed');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 2. Load increment metadata
|
|
45
|
-
const metadata = this.loadIncrementMetadata();
|
|
46
|
-
console.log(`š¦ Increment: ${metadata.id} - ${metadata.title}`);
|
|
47
|
-
|
|
48
|
-
// 3. Parse tasks
|
|
49
|
-
const tasks = TaskParser.parseTasksFile(this.incrementPath);
|
|
50
|
-
console.log(`š Found ${tasks.length} tasks`);
|
|
51
|
-
|
|
52
|
-
if (dryRun) {
|
|
53
|
-
console.log(`\nš DRY RUN MODE - No changes will be made`);
|
|
54
|
-
this.printDryRunSummary(tasks, metadata);
|
|
55
|
-
return {
|
|
56
|
-
epic: {} as any,
|
|
57
|
-
tasks: [],
|
|
58
|
-
errors: []
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 4. Check if already synced (and force not set)
|
|
63
|
-
if (metadata.github?.epic_issue && !force) {
|
|
64
|
-
console.log(`\nā ļø Increment already synced to GitHub (epic #${metadata.github.epic_issue})`);
|
|
65
|
-
console.log(` Use --force to re-sync (WARNING: will create duplicate issues)`);
|
|
66
|
-
throw new Error('Already synced. Use --force to override.');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const errors: Array<{ taskId?: string; error: string }> = [];
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
// 5. Create or get milestone (with SpecWeave AI velocity: 1-2 days)
|
|
73
|
-
const milestoneTitle = this.getMilestoneTitle(metadata);
|
|
74
|
-
console.log(`\nš Creating milestone: ${milestoneTitle} (due in ${milestoneDays} days)`);
|
|
75
|
-
const milestone = await this.client.createOrGetMilestone(
|
|
76
|
-
milestoneTitle,
|
|
77
|
-
`Milestone for increment ${metadata.id}`,
|
|
78
|
-
milestoneDays
|
|
79
|
-
);
|
|
80
|
-
console.log(` ā
Milestone #${milestone.number}: ${milestone.title}`);
|
|
81
|
-
|
|
82
|
-
// 6. Create epic issue
|
|
83
|
-
console.log(`\nšÆ Creating epic issue for increment ${metadata.id}...`);
|
|
84
|
-
|
|
85
|
-
// Get issue prefix from metadata.json (with created date)
|
|
86
|
-
const issuePrefix = this.getIssuePrefix(metadata.id);
|
|
87
|
-
|
|
88
|
-
const epicBody = this.generateEpicBody(metadata, tasks);
|
|
89
|
-
const epic = await this.client.createEpicIssue(
|
|
90
|
-
`[${issuePrefix}] ${metadata.title}`,
|
|
91
|
-
epicBody,
|
|
92
|
-
milestone.title,
|
|
93
|
-
['increment', 'specweave', metadata.priority.toLowerCase()]
|
|
94
|
-
);
|
|
95
|
-
console.log(` ā
Epic issue #${epic.number}: ${epic.html_url}`);
|
|
96
|
-
|
|
97
|
-
// 7. Create task issues (with smart rate limiting)
|
|
98
|
-
// Fast mode: Skip delays for small increments (< 10 tasks) or when explicitly requested
|
|
99
|
-
const useFastMode = fastMode || tasks.length < 10;
|
|
100
|
-
const effectiveDelay = useFastMode ? 0 : batchDelay;
|
|
101
|
-
|
|
102
|
-
if (useFastMode) {
|
|
103
|
-
console.log(`\nš Creating ${tasks.length} task issues (fast mode - no rate limiting)...`);
|
|
104
|
-
} else {
|
|
105
|
-
console.log(`\nš Creating ${tasks.length} task issues (batch size: ${batchSize}, delay: ${effectiveDelay}ms)...`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const taskIssues: Array<{ taskId: string; issue: any }> = [];
|
|
109
|
-
const issueData = tasks.map(task => ({
|
|
110
|
-
title: `[${task.id}] ${task.title}`,
|
|
111
|
-
body: this.generateTaskBody(task),
|
|
112
|
-
labels: ['task', task.priority.toLowerCase(), ...(task.phase ? [this.slugify(task.phase)] : [])]
|
|
113
|
-
}));
|
|
114
|
-
|
|
115
|
-
const createdIssues = await this.client.batchCreateIssues(
|
|
116
|
-
issueData,
|
|
117
|
-
milestone.title,
|
|
118
|
-
epic.number,
|
|
119
|
-
{ batchSize, delayMs: effectiveDelay }
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
// TODO: GitHub Projects integration (if projectName provided)
|
|
123
|
-
// if (projectName) {
|
|
124
|
-
// await this.addIssuesToProject(projectName, [epic, ...createdIssues]);
|
|
125
|
-
// }
|
|
126
|
-
|
|
127
|
-
// Map issues to tasks
|
|
128
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
129
|
-
if (createdIssues[i]) {
|
|
130
|
-
taskIssues.push({
|
|
131
|
-
taskId: tasks[i].id,
|
|
132
|
-
issue: createdIssues[i]
|
|
133
|
-
});
|
|
134
|
-
console.log(` ā
#${createdIssues[i].number}: [${tasks[i].id}] ${tasks[i].title}`);
|
|
135
|
-
} else {
|
|
136
|
-
errors.push({
|
|
137
|
-
taskId: tasks[i].id,
|
|
138
|
-
error: 'Failed to create issue'
|
|
139
|
-
});
|
|
140
|
-
console.log(` ā [${tasks[i].id}] ${tasks[i].title} - Failed`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// 8. Update tasks.md with GitHub issue numbers
|
|
145
|
-
console.log(`\nš Updating tasks.md with GitHub issue numbers...`);
|
|
146
|
-
const taskIssueMap: Record<string, number> = {};
|
|
147
|
-
taskIssues.forEach(({ taskId, issue }) => {
|
|
148
|
-
taskIssueMap[taskId] = issue.number;
|
|
149
|
-
});
|
|
150
|
-
TaskParser.updateTasksWithGitHubIssues(this.incrementPath, taskIssueMap);
|
|
151
|
-
console.log(` ā
Updated tasks.md`);
|
|
152
|
-
|
|
153
|
-
// 9. Save sync mapping
|
|
154
|
-
console.log(`\nš¾ Saving sync mapping...`);
|
|
155
|
-
this.saveSyncMapping({
|
|
156
|
-
milestone: milestone.number,
|
|
157
|
-
epic_issue: epic.number,
|
|
158
|
-
task_issues: taskIssueMap,
|
|
159
|
-
last_sync: new Date().toISOString()
|
|
160
|
-
});
|
|
161
|
-
console.log(` ā
Saved to .github-sync.yaml`);
|
|
162
|
-
|
|
163
|
-
// 10. Update increment metadata
|
|
164
|
-
metadata.github = {
|
|
165
|
-
milestone: milestone.number,
|
|
166
|
-
epic_issue: epic.number,
|
|
167
|
-
task_issues: taskIssueMap,
|
|
168
|
-
last_sync: new Date().toISOString()
|
|
169
|
-
};
|
|
170
|
-
this.saveIncrementMetadata(metadata);
|
|
171
|
-
|
|
172
|
-
// Success summary
|
|
173
|
-
console.log(`\nš GitHub sync complete!`);
|
|
174
|
-
console.log(` š Milestone: #${milestone.number} ${milestone.title}`);
|
|
175
|
-
console.log(` šÆ Epic: #${epic.number} ${epic.html_url}`);
|
|
176
|
-
console.log(` š Tasks: #${createdIssues[0]?.number}-#${createdIssues[createdIssues.length - 1]?.number} (${createdIssues.length} issues)`);
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
milestone,
|
|
180
|
-
epic,
|
|
181
|
-
tasks: taskIssues,
|
|
182
|
-
errors
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
} catch (error: any) {
|
|
186
|
-
console.error(`\nā Sync failed:`, error.message);
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Generate epic issue body
|
|
193
|
-
*/
|
|
194
|
-
private generateEpicBody(metadata: IncrementMetadata, tasks: Task[]): string {
|
|
195
|
-
const specPath = path.join(this.incrementPath, 'spec.md');
|
|
196
|
-
let summary = 'No summary available';
|
|
197
|
-
|
|
198
|
-
if (fs.existsSync(specPath)) {
|
|
199
|
-
const specContent = fs.readFileSync(specPath, 'utf-8');
|
|
200
|
-
const summaryMatch = specContent.match(/## Executive Summary\s+(.+?)(?=\n##|$)/s);
|
|
201
|
-
summary = summaryMatch?.[1]?.trim() || summary;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Group tasks by phase
|
|
205
|
-
const phases = new Map<string, Task[]>();
|
|
206
|
-
tasks.forEach(task => {
|
|
207
|
-
const phase = task.phase || 'Other';
|
|
208
|
-
if (!phases.has(phase)) {
|
|
209
|
-
phases.set(phase, []);
|
|
210
|
-
}
|
|
211
|
-
phases.get(phase)!.push(task);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
let phaseChecklist = '';
|
|
215
|
-
for (const [phase, phaseTasks] of phases.entries()) {
|
|
216
|
-
phaseChecklist += `\n### ${phase}\n\n`;
|
|
217
|
-
phaseTasks.forEach(task => {
|
|
218
|
-
phaseChecklist += `- [ ] [${task.id}] ${task.title} (${task.estimate})\n`;
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// DEPRECATED: This method generates old [Increment XXX] format
|
|
223
|
-
// It will be blocked by github-client-v2.ts validation
|
|
224
|
-
// TODO: Remove task-sync.ts entirely - use living docs sync instead
|
|
225
|
-
return `# [Increment ${metadata.id}] ${metadata.title}
|
|
226
|
-
|
|
227
|
-
**Status**: ${metadata.status}
|
|
228
|
-
**Priority**: ${metadata.priority}
|
|
229
|
-
**Created**: ${new Date().toISOString().split('T')[0]}
|
|
230
|
-
|
|
231
|
-
## Summary
|
|
232
|
-
|
|
233
|
-
${summary}
|
|
234
|
-
|
|
235
|
-
## Tasks (${tasks.length} total)
|
|
236
|
-
${phaseChecklist}
|
|
237
|
-
|
|
238
|
-
## SpecWeave Increment
|
|
239
|
-
|
|
240
|
-
ā ļø **DEPRECATED FORMAT**: This issue was created using the old increment-based sync.
|
|
241
|
-
|
|
242
|
-
**Correct data flow**: Increment ā Living Docs ā GitHub
|
|
243
|
-
|
|
244
|
-
This epic tracks SpecWeave increment \`${metadata.id}\`.
|
|
245
|
-
|
|
246
|
-
- **Spec**: [\`spec.md\`](${this.getGitHubFileURL('spec.md')})
|
|
247
|
-
- **Plan**: [\`plan.md\`](${this.getGitHubFileURL('plan.md')})
|
|
248
|
-
- **Tasks**: [\`tasks.md\`](${this.getGitHubFileURL('tasks.md')})
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
š¤ Auto-synced by [SpecWeave](https://spec-weave.com)`;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Generate task issue body
|
|
257
|
-
*/
|
|
258
|
-
private generateTaskBody(task: Task): string {
|
|
259
|
-
let body = `**Priority**: ${task.priority}
|
|
260
|
-
**Estimate**: ${task.estimate}
|
|
261
|
-
**Phase**: ${task.phase || 'N/A'}
|
|
262
|
-
|
|
263
|
-
## Description
|
|
264
|
-
|
|
265
|
-
${task.description}
|
|
266
|
-
`;
|
|
267
|
-
|
|
268
|
-
if (task.subtasks && task.subtasks.length > 0) {
|
|
269
|
-
body += `\n## Subtasks\n\n`;
|
|
270
|
-
task.subtasks.forEach(subtask => {
|
|
271
|
-
const checked = subtask.completed ? 'x' : ' ';
|
|
272
|
-
body += `- [${checked}] ${subtask.id}: ${subtask.description} (${subtask.estimate})\n`;
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (task.filesToCreate && task.filesToCreate.length > 0) {
|
|
277
|
-
body += `\n## Files to Create\n\n`;
|
|
278
|
-
task.filesToCreate.forEach(file => {
|
|
279
|
-
body += `- \`${file}\`\n`;
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (task.filesToModify && task.filesToModify.length > 0) {
|
|
284
|
-
body += `\n## Files to Modify\n\n`;
|
|
285
|
-
task.filesToModify.forEach(file => {
|
|
286
|
-
body += `- \`${file}\`\n`;
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (task.implementation) {
|
|
291
|
-
body += `\n## Implementation\n\n\`\`\`typescript\n${task.implementation}\n\`\`\`\n`;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
|
|
295
|
-
body += `\n## Acceptance Criteria\n\n`;
|
|
296
|
-
task.acceptanceCriteria.forEach(criterion => {
|
|
297
|
-
body += `- ā
${criterion}\n`;
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (task.dependencies && task.dependencies.length > 0) {
|
|
302
|
-
body += `\n## Dependencies\n\nThis task depends on:\n`;
|
|
303
|
-
task.dependencies.forEach(dep => {
|
|
304
|
-
body += `- ${dep} (must complete first)\n`;
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (task.blocks && task.blocks.length > 0) {
|
|
309
|
-
body += `\n## Blocks\n\nThis task blocks:\n`;
|
|
310
|
-
task.blocks.forEach(blocked => {
|
|
311
|
-
body += `- ${blocked} (waiting on this)\n`;
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
body += `\n---\n\nš¤ Synced from SpecWeave increment \`${path.basename(this.incrementPath)}\`\n`;
|
|
316
|
-
body += `- **Tasks**: [\`tasks.md\`](${this.getGitHubFileURL('tasks.md')})\n`;
|
|
317
|
-
|
|
318
|
-
return body;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Load increment metadata
|
|
323
|
-
*/
|
|
324
|
-
private loadIncrementMetadata(): IncrementMetadata {
|
|
325
|
-
const metadataPath = path.join(this.incrementPath, '.metadata.yaml');
|
|
326
|
-
|
|
327
|
-
if (fs.existsSync(metadataPath)) {
|
|
328
|
-
const content = fs.readFileSync(metadataPath, 'utf-8');
|
|
329
|
-
return yaml.load(content) as IncrementMetadata;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Fallback: extract from directory name and spec
|
|
333
|
-
const incrementId = path.basename(this.incrementPath);
|
|
334
|
-
const specPath = path.join(this.incrementPath, 'spec.md');
|
|
335
|
-
let title = 'Unknown';
|
|
336
|
-
let priority: 'P0' | 'P1' | 'P2' | 'P3' = 'P1';
|
|
337
|
-
|
|
338
|
-
if (fs.existsSync(specPath)) {
|
|
339
|
-
const specContent = fs.readFileSync(specPath, 'utf-8');
|
|
340
|
-
const titleMatch = specContent.match(/\*\*Title\*\*:\s*(.+)/);
|
|
341
|
-
const priorityMatch = specContent.match(/\*\*Priority\*\*:\s*(P[0-3])/);
|
|
342
|
-
title = titleMatch?.[1]?.trim() || title;
|
|
343
|
-
priority = (priorityMatch?.[1] as any) || priority;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
return {
|
|
347
|
-
id: incrementId,
|
|
348
|
-
title,
|
|
349
|
-
priority,
|
|
350
|
-
status: 'planning'
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Save increment metadata
|
|
356
|
-
*/
|
|
357
|
-
private saveIncrementMetadata(metadata: IncrementMetadata): void {
|
|
358
|
-
const metadataPath = path.join(this.incrementPath, '.metadata.yaml');
|
|
359
|
-
fs.writeFileSync(metadataPath, yaml.dump(metadata), 'utf-8');
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Get issue prefix from metadata.json (with created date)
|
|
364
|
-
* Returns FS-YY-MM-DD format or fallback to FS-UNKNOWN
|
|
365
|
-
*/
|
|
366
|
-
private getIssuePrefix(incrementId: string): string {
|
|
367
|
-
const metadataJsonPath = path.join(this.incrementPath, 'metadata.json');
|
|
368
|
-
|
|
369
|
-
// Try to read metadata.json for created date
|
|
370
|
-
if (fs.existsSync(metadataJsonPath)) {
|
|
371
|
-
try {
|
|
372
|
-
const metadataContent = fs.readFileSync(metadataJsonPath, 'utf-8');
|
|
373
|
-
const metadata = JSON.parse(metadataContent);
|
|
374
|
-
|
|
375
|
-
if (metadata.created) {
|
|
376
|
-
// Extract YY-MM-DD from date (e.g., "2025-11-12T12:46:00Z" -> "25-11-12")
|
|
377
|
-
const dateMatch = metadata.created.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
378
|
-
if (dateMatch) {
|
|
379
|
-
const year = dateMatch[1].slice(2); // "2025" -> "25"
|
|
380
|
-
const month = dateMatch[2]; // "11"
|
|
381
|
-
const day = dateMatch[3]; // "12"
|
|
382
|
-
return `FS-${year}-${month}-${day}`;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
} catch (error) {
|
|
386
|
-
console.warn(`ā ļø Could not parse metadata.json: ${error}`);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Fallback: use increment number if available
|
|
391
|
-
const incrementNumber = incrementId.match(/^(\d+)/)?.[1];
|
|
392
|
-
if (incrementNumber) {
|
|
393
|
-
return `FS-${incrementNumber}`;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return 'FS-UNKNOWN';
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Save sync mapping
|
|
401
|
-
*/
|
|
402
|
-
private saveSyncMapping(githubData: any): void {
|
|
403
|
-
const syncPath = path.join(this.incrementPath, '.github-sync.yaml');
|
|
404
|
-
fs.writeFileSync(syncPath, yaml.dump(githubData), 'utf-8');
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Get milestone title from metadata
|
|
409
|
-
*/
|
|
410
|
-
private getMilestoneTitle(metadata: IncrementMetadata): string {
|
|
411
|
-
return metadata.version ? `v${metadata.version}` : `Increment ${metadata.id}`;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Get GitHub file URL
|
|
416
|
-
*/
|
|
417
|
-
private getGitHubFileURL(filename: string): string {
|
|
418
|
-
try {
|
|
419
|
-
const remote = this.client['detectRepo']();
|
|
420
|
-
const incrementId = path.basename(this.incrementPath);
|
|
421
|
-
return `https://github.com/${remote}/blob/develop/.specweave/increments/${incrementId}/${filename}`;
|
|
422
|
-
} catch {
|
|
423
|
-
return `#`;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Convert string to slug
|
|
429
|
-
*/
|
|
430
|
-
private slugify(str: string): string {
|
|
431
|
-
return str
|
|
432
|
-
.toLowerCase()
|
|
433
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
434
|
-
.replace(/^-|-$/g, '');
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Print dry run summary
|
|
439
|
-
*/
|
|
440
|
-
private printDryRunSummary(tasks: Task[], metadata: IncrementMetadata): void {
|
|
441
|
-
const issuePrefix = this.getIssuePrefix(metadata.id);
|
|
442
|
-
console.log(`\nš Dry Run Summary:`);
|
|
443
|
-
console.log(` Milestone: ${this.getMilestoneTitle(metadata)}`);
|
|
444
|
-
console.log(` Epic: [${issuePrefix}] ${metadata.title}`);
|
|
445
|
-
console.log(` Task Issues: ${tasks.length}`);
|
|
446
|
-
console.log(`\nš Would create:`);
|
|
447
|
-
tasks.forEach((task, i) => {
|
|
448
|
-
console.log(` ${i + 1}. [${task.id}] ${task.title} (${task.estimate})`);
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
}
|