specweave 1.0.355 → 1.0.357
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/bin/specweave.js +21 -1
- package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/duplicate-detector.js +18 -2
- package/dist/plugins/specweave-github/lib/duplicate-detector.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +10 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts +17 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js +85 -0
- package/dist/plugins/specweave-jira/lib/jira-status-sync.js.map +1 -1
- package/dist/src/adapters/agents-md-generator.js +1 -1
- package/dist/src/adapters/agents-md-generator.js.map +1 -1
- package/dist/src/adapters/claude/adapter.d.ts +3 -4
- package/dist/src/adapters/claude/adapter.d.ts.map +1 -1
- package/dist/src/adapters/claude/adapter.js +3 -4
- package/dist/src/adapters/claude/adapter.js.map +1 -1
- package/dist/src/adapters/claude-md-generator.js +2 -2
- package/dist/src/adapters/claude-md-generator.js.map +1 -1
- package/dist/src/cli/commands/check-discipline.d.ts.map +1 -1
- package/dist/src/cli/commands/check-discipline.js +2 -1
- package/dist/src/cli/commands/check-discipline.js.map +1 -1
- package/dist/src/cli/commands/create-increment.d.ts.map +1 -1
- package/dist/src/cli/commands/create-increment.js +4 -1
- package/dist/src/cli/commands/create-increment.js.map +1 -1
- package/dist/src/cli/commands/health.d.ts +34 -0
- package/dist/src/cli/commands/health.d.ts.map +1 -0
- package/dist/src/cli/commands/health.js +349 -0
- package/dist/src/cli/commands/health.js.map +1 -0
- package/dist/src/cli/commands/migrate-to-umbrella.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-to-umbrella.js +38 -0
- package/dist/src/cli/commands/migrate-to-umbrella.js.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.d.ts +3 -2
- package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.js +3 -8
- package/dist/src/cli/commands/refresh-plugins.js.map +1 -1
- package/dist/src/cli/commands/save.js +1 -1
- package/dist/src/cli/commands/save.js.map +1 -1
- package/dist/src/cli/commands/sync-living-docs.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-living-docs.js +2 -1
- package/dist/src/cli/commands/sync-living-docs.js.map +1 -1
- package/dist/src/cli/commands/sync-progress.d.ts.map +1 -1
- package/dist/src/cli/commands/sync-progress.js +208 -8
- package/dist/src/cli/commands/sync-progress.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts.map +1 -1
- package/dist/src/cli/commands/update.js +35 -4
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/core/ac-progress-sync.d.ts.map +1 -1
- package/dist/src/core/ac-progress-sync.js +13 -4
- package/dist/src/core/ac-progress-sync.js.map +1 -1
- package/dist/src/core/config/types.d.ts +33 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/doctor/checkers/increments-checker.js +2 -2
- package/dist/src/core/doctor/checkers/increments-checker.js.map +1 -1
- package/dist/src/core/doctor/checkers/installation-health-checker.d.ts +14 -15
- package/dist/src/core/doctor/checkers/installation-health-checker.d.ts.map +1 -1
- package/dist/src/core/doctor/checkers/installation-health-checker.js +78 -148
- package/dist/src/core/doctor/checkers/installation-health-checker.js.map +1 -1
- package/dist/src/core/hooks/LifecycleHookDispatcher.d.ts.map +1 -1
- package/dist/src/core/hooks/LifecycleHookDispatcher.js +6 -1
- package/dist/src/core/hooks/LifecycleHookDispatcher.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +8 -7
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/increment/increment-reopener.d.ts.map +1 -1
- package/dist/src/core/increment/increment-reopener.js +5 -4
- package/dist/src/core/increment/increment-reopener.js.map +1 -1
- package/dist/src/core/increment/metadata-manager.d.ts +5 -6
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +12 -13
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/spec-frontmatter-updater.d.ts.map +1 -1
- package/dist/src/core/increment/spec-frontmatter-updater.js +3 -2
- package/dist/src/core/increment/spec-frontmatter-updater.js.map +1 -1
- package/dist/src/core/increment/status-auto-transition.d.ts.map +1 -1
- package/dist/src/core/increment/status-auto-transition.js +5 -4
- package/dist/src/core/increment/status-auto-transition.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +3 -2
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/increment/status-commands.d.ts.map +1 -1
- package/dist/src/core/increment/status-commands.js +4 -3
- package/dist/src/core/increment/status-commands.js.map +1 -1
- package/dist/src/core/increment/template-creator.d.ts.map +1 -1
- package/dist/src/core/increment/template-creator.js +49 -5
- package/dist/src/core/increment/template-creator.js.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +2 -2
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.js +32 -16
- package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +16 -6
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/migration/consolidation-engine.d.ts +59 -0
- package/dist/src/core/migration/consolidation-engine.d.ts.map +1 -0
- package/dist/src/core/migration/consolidation-engine.js +177 -0
- package/dist/src/core/migration/consolidation-engine.js.map +1 -0
- package/dist/src/core/migration/types.d.ts +2 -0
- package/dist/src/core/migration/types.d.ts.map +1 -1
- package/dist/src/core/project/project-resolution.d.ts.map +1 -1
- package/dist/src/core/project/project-resolution.js +20 -2
- package/dist/src/core/project/project-resolution.js.map +1 -1
- package/dist/src/generators/spec/spec-parser.js +2 -2
- package/dist/src/generators/spec/spec-parser.js.map +1 -1
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +83 -30
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/sync/external-issue-auto-creator.d.ts +6 -2
- package/dist/src/sync/external-issue-auto-creator.d.ts.map +1 -1
- package/dist/src/sync/external-issue-auto-creator.js +75 -19
- package/dist/src/sync/external-issue-auto-creator.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +20 -4
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/sync/sync-target-resolver.d.ts +36 -0
- package/dist/src/sync/sync-target-resolver.d.ts.map +1 -0
- package/dist/src/sync/sync-target-resolver.js +72 -0
- package/dist/src/sync/sync-target-resolver.js.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.js +4 -4
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
- package/dist/src/utils/find-project-root.d.ts +26 -0
- package/dist/src/utils/find-project-root.d.ts.map +1 -1
- package/dist/src/utils/find-project-root.js +78 -0
- package/dist/src/utils/find-project-root.js.map +1 -1
- package/dist/src/utils/multi-project-detector.js +1 -1
- package/dist/src/utils/multi-project-detector.js.map +1 -1
- package/dist/src/utils/plugin-copier.d.ts +28 -47
- package/dist/src/utils/plugin-copier.d.ts.map +1 -1
- package/dist/src/utils/plugin-copier.js +85 -155
- package/dist/src/utils/plugin-copier.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/PLUGIN.md +1 -0
- package/plugins/specweave/hooks/stop-auto-v5.sh +26 -17
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +5 -6
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +12 -13
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/lib/vendor/core/increment/status-auto-transition.js +5 -4
- package/plugins/specweave/lib/vendor/core/increment/status-auto-transition.js.map +1 -1
- package/plugins/specweave/skills/auto/SKILL.md +15 -1
- package/plugins/specweave/skills/brainstorm/SKILL.md +619 -0
- package/plugins/specweave/skills/do/SKILL.md +3 -3
- package/plugins/specweave/skills/increment/SKILL.md +3 -3
- package/plugins/specweave/skills/team-build/SKILL.md +1 -1
- package/plugins/specweave/skills/team-lead/SKILL.md +7 -5
- package/plugins/specweave/skills/validate/SKILL.md +1 -1
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-docs/PLUGIN.md +1 -1
- package/plugins/specweave-github/lib/duplicate-detector.js +21 -1
- package/plugins/specweave-github/lib/duplicate-detector.ts +18 -2
- package/plugins/specweave-github/lib/github-feature-sync.js +17 -0
- package/plugins/specweave-github/lib/github-feature-sync.ts +11 -0
- package/plugins/specweave-jira/lib/jira-status-sync.js +75 -0
- package/plugins/specweave-jira/lib/jira-status-sync.ts +91 -1
- package/src/templates/CLAUDE.md.template +3 -1
- package/dist/src/utils/claude-plugin-cli.d.ts +0 -32
- package/dist/src/utils/claude-plugin-cli.d.ts.map +0 -1
- package/dist/src/utils/claude-plugin-cli.js +0 -74
- package/dist/src/utils/claude-plugin-cli.js.map +0 -1
- package/plugins/specweave/hooks/.specweave/logs/auto-iterations.log +0 -1
- package/plugins/specweave/hooks/.specweave/logs/auto-stop-reasons.log +0 -1
- package/plugins/specweave/skills/.specweave/logs/reflect/auto-reflect.log +0 -15
- package/plugins/specweave/skills/.specweave/logs/reflect/reflect.log +0 -3
- package/plugins/specweave/skills/.specweave/logs/stop-auto.log +0 -1
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -180
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -1266
- package/plugins/specweave-github/lib/enhanced-github-sync.js +0 -249
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +0 -150
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1260
|
@@ -5,7 +5,7 @@ hooks:
|
|
|
5
5
|
- matcher: TeamCreate
|
|
6
6
|
hooks:
|
|
7
7
|
- type: command
|
|
8
|
-
command: bash
|
|
8
|
+
command: bash -c 'W="${CLAUDE_PLUGIN_ROOT}/hooks/universal/fail-fast-wrapper.sh"; S="${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/increment-existence-guard.sh"; [[ -x "$W" ]] && exec "$W" "$S" || (cat >/dev/null && printf "{\"decision\":\"allow\"}")'
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Team Lead
|
|
@@ -439,7 +439,7 @@ SendMessage({
|
|
|
439
439
|
SendMessage({
|
|
440
440
|
type: "message",
|
|
441
441
|
recipient: "team-lead",
|
|
442
|
-
content: "COMPLETION: All 8 tasks done. Tests passing (24/24).
|
|
442
|
+
content: "COMPLETION: All 8 tasks done. Tests passing (24/24). Ready for team-lead closure.",
|
|
443
443
|
summary: "Frontend agent completed all tasks"
|
|
444
444
|
});
|
|
445
445
|
```
|
|
@@ -563,12 +563,14 @@ Orchestrator Final Check:
|
|
|
563
563
|
|
|
564
564
|
Agents can get stuck in extended thinking if their context overflows. The team-lead MUST monitor for stuck agents.
|
|
565
565
|
|
|
566
|
-
###
|
|
566
|
+
### Stuck Detection Rules
|
|
567
|
+
|
|
568
|
+
**Note**: Claude Code has no built-in timers. These are best-effort heuristics applied when the team-lead regains control (e.g., after processing other agent messages).
|
|
567
569
|
|
|
568
570
|
| Condition | Action |
|
|
569
571
|
|-----------|--------|
|
|
570
|
-
| Agent
|
|
571
|
-
|
|
|
572
|
+
| Agent has not messaged since team-lead's last turn | Send `STATUS_CHECK` message to agent |
|
|
573
|
+
| Agent does not respond to STATUS_CHECK on next team-lead turn | Declare agent stuck |
|
|
572
574
|
| Agent stuck | Log warning, proceed with other agents, handle stuck agent's increment manually in team-merge |
|
|
573
575
|
| All agents stuck | STOP team, report to user |
|
|
574
576
|
|
|
@@ -5,7 +5,7 @@ hooks:
|
|
|
5
5
|
Stop:
|
|
6
6
|
- hooks:
|
|
7
7
|
- type: command
|
|
8
|
-
command: bash
|
|
8
|
+
command: bash -c 'W="${CLAUDE_PLUGIN_ROOT}/hooks/universal/fail-fast-wrapper.sh"; S="${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/spec-validation-guard.sh"; [[ -x "$W" ]] && exec "$W" "$S" || (cat >/dev/null && printf "{\"decision\":\"approve\"}")'
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Validate Increment
|
|
@@ -14,7 +14,7 @@ Complete documentation ecosystem for technical writers, product teams, and devel
|
|
|
14
14
|
|-------|-------------|
|
|
15
15
|
| technical-writing | Expert in API documentation, README files, tutorials, changelog management, and developer documentation with style guides and OpenAPI/Swagger support |
|
|
16
16
|
| docusaurus | Docusaurus 3.x framework expert for MDX authoring, theming, versioning, and internationalization |
|
|
17
|
-
| spec-driven-brainstorming |
|
|
17
|
+
| spec-driven-brainstorming | DEPRECATED: Use `/sw:brainstorm` (core plugin). Multi-perspective ideation with cognitive lenses |
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
@@ -272,6 +272,26 @@ The original issue (#${keepIssueNumber}) should be used for tracking instead.
|
|
|
272
272
|
\u2501\u2501\u2501 PHASE 2: CREATION \u2501\u2501\u2501`);
|
|
273
273
|
console.log(` Creating new GitHub issue...`);
|
|
274
274
|
try {
|
|
275
|
+
const safeLabels = labels.filter((l) => /^[a-zA-Z0-9:_\- ]+$/.test(l));
|
|
276
|
+
if (repo) {
|
|
277
|
+
for (const label of safeLabels) {
|
|
278
|
+
try {
|
|
279
|
+
execFileSync("gh", [
|
|
280
|
+
"label",
|
|
281
|
+
"create",
|
|
282
|
+
label,
|
|
283
|
+
"--repo",
|
|
284
|
+
repo,
|
|
285
|
+
"--color",
|
|
286
|
+
"ededed",
|
|
287
|
+
"--description",
|
|
288
|
+
"SpecWeave auto-label",
|
|
289
|
+
"--force"
|
|
290
|
+
], { encoding: "utf-8", env: getGhEnv() });
|
|
291
|
+
} catch {
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
275
295
|
const args = [
|
|
276
296
|
"issue",
|
|
277
297
|
"create",
|
|
@@ -283,7 +303,7 @@ The original issue (#${keepIssueNumber}) should be used for tracking instead.
|
|
|
283
303
|
if (repo) {
|
|
284
304
|
args.push("--repo", repo);
|
|
285
305
|
}
|
|
286
|
-
|
|
306
|
+
safeLabels.forEach((label) => {
|
|
287
307
|
args.push("--label", label);
|
|
288
308
|
});
|
|
289
309
|
if (milestone) {
|
|
@@ -419,6 +419,22 @@ The original issue (#${keepIssueNumber}) should be used for tracking instead.
|
|
|
419
419
|
console.log(` Creating new GitHub issue...`);
|
|
420
420
|
|
|
421
421
|
try {
|
|
422
|
+
// Ensure all labels exist in target repo before creating issue
|
|
423
|
+
// Sanitize labels: only allow alphanumeric, hyphens, colons, spaces
|
|
424
|
+
const safeLabels = labels.filter(l => /^[a-zA-Z0-9:_\- ]+$/.test(l));
|
|
425
|
+
if (repo) {
|
|
426
|
+
for (const label of safeLabels) {
|
|
427
|
+
try {
|
|
428
|
+
execFileSync('gh', [
|
|
429
|
+
'label', 'create', label, '--repo', repo,
|
|
430
|
+
'--color', 'ededed', '--description', 'SpecWeave auto-label', '--force'
|
|
431
|
+
], { encoding: 'utf-8', env: getGhEnv() });
|
|
432
|
+
} catch {
|
|
433
|
+
// Label creation failure is non-fatal
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
422
438
|
const args = [
|
|
423
439
|
'issue',
|
|
424
440
|
'create',
|
|
@@ -430,8 +446,8 @@ The original issue (#${keepIssueNumber}) should be used for tracking instead.
|
|
|
430
446
|
args.push('--repo', repo);
|
|
431
447
|
}
|
|
432
448
|
|
|
433
|
-
// Add labels
|
|
434
|
-
|
|
449
|
+
// Add sanitized labels
|
|
450
|
+
safeLabels.forEach(label => {
|
|
435
451
|
args.push('--label', label);
|
|
436
452
|
});
|
|
437
453
|
|
|
@@ -622,9 +622,26 @@ Created: ${featureData.created}`;
|
|
|
622
622
|
* - Prevents premature closure on creation
|
|
623
623
|
*/
|
|
624
624
|
async createUserStoryIssue(issueContent, milestoneTitle, userStoryPath) {
|
|
625
|
+
const repoSlug = `${this.client.getOwner()}/${this.client.getRepo()}`;
|
|
626
|
+
for (const label of issueContent.labels) {
|
|
627
|
+
await execFileNoThrow("gh", [
|
|
628
|
+
"label",
|
|
629
|
+
"create",
|
|
630
|
+
label,
|
|
631
|
+
"--repo",
|
|
632
|
+
repoSlug,
|
|
633
|
+
"--color",
|
|
634
|
+
"ededed",
|
|
635
|
+
"--description",
|
|
636
|
+
"SpecWeave auto-label",
|
|
637
|
+
"--force"
|
|
638
|
+
], { env: this.getGhEnv() });
|
|
639
|
+
}
|
|
625
640
|
const result = await execFileNoThrow("gh", [
|
|
626
641
|
"issue",
|
|
627
642
|
"create",
|
|
643
|
+
"--repo",
|
|
644
|
+
repoSlug,
|
|
628
645
|
"--title",
|
|
629
646
|
issueContent.title,
|
|
630
647
|
"--body",
|
|
@@ -907,10 +907,21 @@ export class GitHubFeatureSync {
|
|
|
907
907
|
milestoneTitle: string,
|
|
908
908
|
userStoryPath: string
|
|
909
909
|
): Promise<number> {
|
|
910
|
+
// Step 0: Ensure all required labels exist in the target repo
|
|
911
|
+
const repoSlug = `${this.client.getOwner()}/${this.client.getRepo()}`;
|
|
912
|
+
for (const label of issueContent.labels) {
|
|
913
|
+
await execFileNoThrow('gh', [
|
|
914
|
+
'label', 'create', label, '--repo', repoSlug,
|
|
915
|
+
'--color', 'ededed', '--description', 'SpecWeave auto-label', '--force'
|
|
916
|
+
], { env: this.getGhEnv() });
|
|
917
|
+
}
|
|
918
|
+
|
|
910
919
|
// Step 1: Create issue (always open initially - gh CLI limitation)
|
|
911
920
|
const result = await execFileNoThrow('gh', [
|
|
912
921
|
'issue',
|
|
913
922
|
'create',
|
|
923
|
+
'--repo',
|
|
924
|
+
repoSlug,
|
|
914
925
|
'--title',
|
|
915
926
|
issueContent.title,
|
|
916
927
|
'--body',
|
|
@@ -92,6 +92,81 @@ _Synced from SpecWeave_`;
|
|
|
92
92
|
body
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Post AC progress comment with proper ADF formatting and dedup.
|
|
97
|
+
*
|
|
98
|
+
* Builds native ADF with:
|
|
99
|
+
* - Bold header showing completion percentage
|
|
100
|
+
* - Bullet list with checkmark/cross emojis per AC
|
|
101
|
+
* - Fingerprint marker to prevent duplicate comments
|
|
102
|
+
*
|
|
103
|
+
* @param issueKey - JIRA issue key (e.g., PROJ-123)
|
|
104
|
+
* @param acStates - Array of AC states with id, description, completed
|
|
105
|
+
* @returns true if comment was posted, false if skipped (duplicate)
|
|
106
|
+
*/
|
|
107
|
+
async postProgressComment(issueKey, acStates) {
|
|
108
|
+
const total = acStates.length;
|
|
109
|
+
const completed = acStates.filter((ac) => ac.completed).length;
|
|
110
|
+
const percentage = Math.round(completed / total * 100);
|
|
111
|
+
const fingerprint = `sw-progress:${completed}/${total}`;
|
|
112
|
+
try {
|
|
113
|
+
const commentsResp = await this.client.get(`/issue/${issueKey}/comment`, {
|
|
114
|
+
params: { orderBy: "-created", maxResults: 1 }
|
|
115
|
+
});
|
|
116
|
+
const lastComment = commentsResp.data?.comments?.[0];
|
|
117
|
+
if (lastComment) {
|
|
118
|
+
const lastText = extractAdfText(lastComment.body);
|
|
119
|
+
if (lastText.includes(fingerprint)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
const listItems = acStates.map((ac) => ({
|
|
126
|
+
type: "listItem",
|
|
127
|
+
content: [{
|
|
128
|
+
type: "paragraph",
|
|
129
|
+
content: [
|
|
130
|
+
{ type: "text", text: `${ac.completed ? "\u2705" : "\u274C"} ${ac.id}: ${ac.description}` }
|
|
131
|
+
]
|
|
132
|
+
}]
|
|
133
|
+
}));
|
|
134
|
+
const body = {
|
|
135
|
+
type: "doc",
|
|
136
|
+
version: 1,
|
|
137
|
+
content: [
|
|
138
|
+
{
|
|
139
|
+
type: "heading",
|
|
140
|
+
attrs: { level: 3 },
|
|
141
|
+
content: [{ type: "text", text: `Progress: ${completed}/${total} ACs (${percentage}%)` }]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
type: "bulletList",
|
|
145
|
+
content: listItems
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "paragraph",
|
|
149
|
+
content: [
|
|
150
|
+
{ type: "text", text: `${fingerprint} | Synced from SpecWeave`, marks: [{ type: "em" }] }
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
await this.client.post(`/issue/${issueKey}/comment`, { body });
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function extractAdfText(adf) {
|
|
160
|
+
if (!adf) return "";
|
|
161
|
+
if (typeof adf === "string") return adf;
|
|
162
|
+
let text = "";
|
|
163
|
+
if (adf.text) text += adf.text;
|
|
164
|
+
if (Array.isArray(adf.content)) {
|
|
165
|
+
for (const child of adf.content) {
|
|
166
|
+
text += extractAdfText(child);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return text;
|
|
95
170
|
}
|
|
96
171
|
export {
|
|
97
172
|
JiraStatusSync
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import axios, { AxiosInstance } from 'axios';
|
|
15
15
|
import { detectDeploymentType, getApiBaseUrl } from './jira-deployment-detector.js';
|
|
16
|
-
import { toCommentBody } from './content-format-adapter.js';
|
|
16
|
+
import { toCommentBody, type AdfDocument, type AdfNode } from './content-format-adapter.js';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* External status representation (JIRA-specific)
|
|
@@ -160,4 +160,94 @@ export class JiraStatusSync {
|
|
|
160
160
|
body
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Post AC progress comment with proper ADF formatting and dedup.
|
|
166
|
+
*
|
|
167
|
+
* Builds native ADF with:
|
|
168
|
+
* - Bold header showing completion percentage
|
|
169
|
+
* - Bullet list with checkmark/cross emojis per AC
|
|
170
|
+
* - Fingerprint marker to prevent duplicate comments
|
|
171
|
+
*
|
|
172
|
+
* @param issueKey - JIRA issue key (e.g., PROJ-123)
|
|
173
|
+
* @param acStates - Array of AC states with id, description, completed
|
|
174
|
+
* @returns true if comment was posted, false if skipped (duplicate)
|
|
175
|
+
*/
|
|
176
|
+
async postProgressComment(
|
|
177
|
+
issueKey: string,
|
|
178
|
+
acStates: Array<{ id: string; description: string; completed: boolean }>,
|
|
179
|
+
): Promise<boolean> {
|
|
180
|
+
const total = acStates.length;
|
|
181
|
+
const completed = acStates.filter(ac => ac.completed).length;
|
|
182
|
+
const percentage = Math.round((completed / total) * 100);
|
|
183
|
+
const fingerprint = `sw-progress:${completed}/${total}`;
|
|
184
|
+
|
|
185
|
+
// Dedup: check last comment for same fingerprint
|
|
186
|
+
try {
|
|
187
|
+
const commentsResp = await this.client.get(`/issue/${issueKey}/comment`, {
|
|
188
|
+
params: { orderBy: '-created', maxResults: 1 },
|
|
189
|
+
});
|
|
190
|
+
const lastComment = commentsResp.data?.comments?.[0];
|
|
191
|
+
if (lastComment) {
|
|
192
|
+
const lastText = extractAdfText(lastComment.body);
|
|
193
|
+
if (lastText.includes(fingerprint)) {
|
|
194
|
+
return false; // Already posted for this state
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
// If comment fetch fails, proceed with posting
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Build ADF body directly — ✅ for done, ❌ for pending
|
|
202
|
+
const listItems: AdfNode[] = acStates.map(ac => ({
|
|
203
|
+
type: 'listItem',
|
|
204
|
+
content: [{
|
|
205
|
+
type: 'paragraph',
|
|
206
|
+
content: [
|
|
207
|
+
{ type: 'text', text: `${ac.completed ? '\u2705' : '\u274C'} ${ac.id}: ${ac.description}` },
|
|
208
|
+
],
|
|
209
|
+
}],
|
|
210
|
+
}));
|
|
211
|
+
|
|
212
|
+
const body: AdfDocument = {
|
|
213
|
+
type: 'doc',
|
|
214
|
+
version: 1,
|
|
215
|
+
content: [
|
|
216
|
+
{
|
|
217
|
+
type: 'heading',
|
|
218
|
+
attrs: { level: 3 },
|
|
219
|
+
content: [{ type: 'text', text: `Progress: ${completed}/${total} ACs (${percentage}%)` }],
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
type: 'bulletList',
|
|
223
|
+
content: listItems,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
type: 'paragraph',
|
|
227
|
+
content: [
|
|
228
|
+
{ type: 'text', text: `${fingerprint} | Synced from SpecWeave`, marks: [{ type: 'em' }] },
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
await this.client.post(`/issue/${issueKey}/comment`, { body });
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Extract plain text from an ADF document (for dedup comparison).
|
|
241
|
+
*/
|
|
242
|
+
function extractAdfText(adf: any): string {
|
|
243
|
+
if (!adf) return '';
|
|
244
|
+
if (typeof adf === 'string') return adf;
|
|
245
|
+
let text = '';
|
|
246
|
+
if (adf.text) text += adf.text;
|
|
247
|
+
if (Array.isArray(adf.content)) {
|
|
248
|
+
for (const child of adf.content) {
|
|
249
|
+
text += extractAdfText(child);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return text;
|
|
163
253
|
}
|
|
@@ -64,7 +64,9 @@ SpecWeave auto-detects product descriptions and routes to `/sw:increment`:
|
|
|
64
64
|
|
|
65
65
|
**Signals** (5+ = auto-route): Project name | Features list (3+) | Tech stack | Timeline/MVP | Problem statement | Business model
|
|
66
66
|
|
|
67
|
-
**Opt-out phrases**: "
|
|
67
|
+
**Opt-out phrases**: "Don't plan yet" | "Quick discussion" | "Let's explore ideas"
|
|
68
|
+
|
|
69
|
+
**Brainstorm routing**: "Just brainstorm first" | "brainstorm" | "ideate" | "what are our options" → routes to `/sw:brainstorm`
|
|
68
70
|
|
|
69
71
|
**NOT opt-out phrases**: "simple" | "quick" | "basic" | "small" — these still require `/sw:increment`
|
|
70
72
|
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Plugin CLI Integration
|
|
3
|
-
*
|
|
4
|
-
* Registers SpecWeave plugins with Claude Code's plugin system via the
|
|
5
|
-
* `claude` CLI binary. This makes plugins appear in the `/plugin Installed`
|
|
6
|
-
* UI alongside marketplace metadata.
|
|
7
|
-
*
|
|
8
|
-
* All operations are non-fatal — failures are logged (in DEBUG mode) but
|
|
9
|
-
* never block the primary plugin installation to ~/.claude/commands/.
|
|
10
|
-
*
|
|
11
|
-
* @since 1.0.290
|
|
12
|
-
*/
|
|
13
|
-
export interface CliRegistrationResult {
|
|
14
|
-
/** True if marketplace was registered successfully */
|
|
15
|
-
marketplaceRegistered: boolean;
|
|
16
|
-
/** Plugin names that were successfully installed via CLI */
|
|
17
|
-
installedPlugins: string[];
|
|
18
|
-
/** Plugin names that failed CLI installation */
|
|
19
|
-
failedPlugins: string[];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Register SpecWeave marketplace and install plugins via Claude CLI.
|
|
23
|
-
*
|
|
24
|
-
* Steps:
|
|
25
|
-
* 1. Validates specweaveRoot contains .claude-plugin/marketplace.json
|
|
26
|
-
* 2. Runs `claude plugin marketplace add <specweaveRoot>`
|
|
27
|
-
* 3. Runs `claude plugin install <name>@specweave` for each plugin
|
|
28
|
-
*
|
|
29
|
-
* Entirely non-fatal. Returns a result with success/failure per plugin.
|
|
30
|
-
*/
|
|
31
|
-
export declare function registerPluginsWithClaudeCli(specweaveRoot: string, pluginNames: string[]): CliRegistrationResult;
|
|
32
|
-
//# sourceMappingURL=claude-plugin-cli.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claude-plugin-cli.d.ts","sourceRoot":"","sources":["../../../src/utils/claude-plugin-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gDAAgD;IAChD,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,qBAAqB,CA6CvB"}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Plugin CLI Integration
|
|
3
|
-
*
|
|
4
|
-
* Registers SpecWeave plugins with Claude Code's plugin system via the
|
|
5
|
-
* `claude` CLI binary. This makes plugins appear in the `/plugin Installed`
|
|
6
|
-
* UI alongside marketplace metadata.
|
|
7
|
-
*
|
|
8
|
-
* All operations are non-fatal — failures are logged (in DEBUG mode) but
|
|
9
|
-
* never block the primary plugin installation to ~/.claude/commands/.
|
|
10
|
-
*
|
|
11
|
-
* @since 1.0.290
|
|
12
|
-
*/
|
|
13
|
-
import { existsSync } from 'node:fs';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
-
import { execFileNoThrowSync } from './execFileNoThrow.js';
|
|
16
|
-
import { getPluginScope, getScopeArgs } from '../core/types/plugin-scope.js';
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
// Core
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
/**
|
|
21
|
-
* Register SpecWeave marketplace and install plugins via Claude CLI.
|
|
22
|
-
*
|
|
23
|
-
* Steps:
|
|
24
|
-
* 1. Validates specweaveRoot contains .claude-plugin/marketplace.json
|
|
25
|
-
* 2. Runs `claude plugin marketplace add <specweaveRoot>`
|
|
26
|
-
* 3. Runs `claude plugin install <name>@specweave` for each plugin
|
|
27
|
-
*
|
|
28
|
-
* Entirely non-fatal. Returns a result with success/failure per plugin.
|
|
29
|
-
*/
|
|
30
|
-
export function registerPluginsWithClaudeCli(specweaveRoot, pluginNames) {
|
|
31
|
-
const result = {
|
|
32
|
-
marketplaceRegistered: false,
|
|
33
|
-
installedPlugins: [],
|
|
34
|
-
failedPlugins: [],
|
|
35
|
-
};
|
|
36
|
-
if (pluginNames.length === 0)
|
|
37
|
-
return result;
|
|
38
|
-
// Validate marketplace exists at path
|
|
39
|
-
const marketplacePath = join(specweaveRoot, '.claude-plugin', 'marketplace.json');
|
|
40
|
-
if (!existsSync(marketplacePath)) {
|
|
41
|
-
if (process.env.DEBUG) {
|
|
42
|
-
console.warn(`[DEBUG] Skipping Claude CLI registration: no marketplace.json at ${marketplacePath}`);
|
|
43
|
-
}
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
// Register marketplace
|
|
47
|
-
const addResult = execFileNoThrowSync('claude', ['plugin', 'marketplace', 'add', specweaveRoot]);
|
|
48
|
-
if (addResult.success || addResult.exitCode === 0) {
|
|
49
|
-
result.marketplaceRegistered = true;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
if (process.env.DEBUG) {
|
|
53
|
-
console.warn(`[DEBUG] claude plugin marketplace add failed (exit ${addResult.exitCode}): ${addResult.stderr}`);
|
|
54
|
-
}
|
|
55
|
-
// Don't bail — install may still work if marketplace was already registered
|
|
56
|
-
}
|
|
57
|
-
// Install each plugin with correct scope
|
|
58
|
-
for (const name of pluginNames) {
|
|
59
|
-
const scope = getPluginScope(name, 'specweave');
|
|
60
|
-
const scopeArgs = getScopeArgs(scope);
|
|
61
|
-
const installResult = execFileNoThrowSync('claude', ['plugin', 'install', `${name}@specweave`, ...scopeArgs]);
|
|
62
|
-
if (installResult.success || installResult.exitCode === 0) {
|
|
63
|
-
result.installedPlugins.push(name);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
result.failedPlugins.push(name);
|
|
67
|
-
if (process.env.DEBUG) {
|
|
68
|
-
console.warn(`[DEBUG] claude plugin install ${name}@specweave failed (exit ${installResult.exitCode}): ${installResult.stderr}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=claude-plugin-cli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"claude-plugin-cli.js","sourceRoot":"","sources":["../../../src/utils/claude-plugin-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAe7E,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,4BAA4B,CAC1C,aAAqB,EACrB,WAAqB;IAErB,MAAM,MAAM,GAA0B;QACpC,qBAAqB,EAAE,KAAK;QAC5B,gBAAgB,EAAE,EAAE;QACpB,aAAa,EAAE,EAAE;KAClB,CAAC;IAEF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAE5C,sCAAsC;IACtC,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IAClF,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,oEAAoE,eAAe,EAAE,CAAC,CAAC;QACtG,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uBAAuB;IACvB,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC;IACjG,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,CAAC,qBAAqB,GAAG,IAAI,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,sDAAsD,SAAS,CAAC,QAAQ,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;QACjH,CAAC;QACD,4EAA4E;IAC9E,CAAC;IAED,yCAAyC;IACzC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,aAAa,GAAG,mBAAmB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;QAC9G,IAAI,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC,iCAAiC,IAAI,2BAA2B,aAAa,CAAC,QAAQ,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;YACnI,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"timestamp":"2026-01-04T16:11:43Z","event":"session_stop","reason":"No auto session active","details":"approve_called:main","success":false,"iteration":0,"increment":"none"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"timestamp":"2026-01-04T16:11:43Z","sessionId":"unknown","reason":"No auto session active","details":"approve_called:main","success":false,"iteration":0,"increment":"none","testsRun":false,"testsPassed":0,"testsFailed":0}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ran": false,
|
|
3
|
-
"inputSummary": {
|
|
4
|
-
"transcriptLines": 266
|
|
5
|
-
},
|
|
6
|
-
"extracted": {
|
|
7
|
-
"skillLearnings": []
|
|
8
|
-
},
|
|
9
|
-
"written": {
|
|
10
|
-
"learningsAdded": 0,
|
|
11
|
-
"learningsSkippedDuplicate": 0
|
|
12
|
-
},
|
|
13
|
-
"durationMs": 1.4448749999999997,
|
|
14
|
-
"reason": "CLAUDE.md not found in project"
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[2026-02-03T22:03:06Z] APPROVE: No increments directory
|