specweave 0.28.34 → 0.28.42
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/CLAUDE.md +21 -0
- package/README.md +47 -33
- package/bin/specweave.js +2 -1
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +6 -6
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
- package/dist/src/cli/commands/archive.d.ts.map +1 -1
- package/dist/src/cli/commands/archive.js +2 -1
- package/dist/src/cli/commands/archive.js.map +1 -1
- package/dist/src/cli/commands/delete-feature.d.ts.map +1 -1
- package/dist/src/cli/commands/delete-feature.js +5 -4
- package/dist/src/cli/commands/delete-feature.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +33 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/ado-area-selector.d.ts +49 -0
- package/dist/src/cli/helpers/ado-area-selector.d.ts.map +1 -0
- package/dist/src/cli/helpers/ado-area-selector.js +161 -0
- package/dist/src/cli/helpers/ado-area-selector.js.map +1 -0
- package/dist/src/cli/helpers/init/config-detection.d.ts +5 -1
- package/dist/src/cli/helpers/init/config-detection.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/config-detection.js +50 -17
- package/dist/src/cli/helpers/init/config-detection.js.map +1 -1
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +32 -3
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.d.ts +2 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.js +34 -2
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -1
- package/dist/src/cli/helpers/init/types.d.ts +3 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts +10 -0
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +107 -22
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +30 -10
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.d.ts +1 -0
- package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.js.map +1 -1
- package/dist/src/core/feature-deleter/github-service.js +2 -2
- package/dist/src/core/feature-deleter/github-service.js.map +1 -1
- package/dist/src/core/increment/discipline-checker.js +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +56 -6
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +228 -77
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +75 -37
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts +6 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +54 -8
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +28 -17
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +2 -111
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +31 -389
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/file-utils.d.ts +30 -0
- package/dist/src/core/living-docs/sync-helpers/file-utils.d.ts.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/file-utils.js +107 -0
- package/dist/src/core/living-docs/sync-helpers/file-utils.js.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts +19 -0
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/generators.js +146 -0
- package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/index.d.ts +8 -0
- package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/index.js +11 -0
- package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +19 -0
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -0
- package/dist/src/core/living-docs/sync-helpers/parsers.js +94 -0
- package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -0
- package/dist/src/core/living-docs/types.d.ts +45 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/types/config.d.ts +1 -1
- package/dist/src/core/types/config.js +2 -2
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/validation/three-file-validator.js +8 -8
- package/dist/src/core/validation/three-file-validator.js.map +1 -1
- package/dist/src/generators/spec/spec-parser.d.ts.map +1 -1
- package/dist/src/generators/spec/spec-parser.js +4 -3
- package/dist/src/generators/spec/spec-parser.js.map +1 -1
- package/dist/src/generators/spec/task-parser.d.ts.map +1 -1
- package/dist/src/generators/spec/task-parser.js +11 -10
- package/dist/src/generators/spec/task-parser.js.map +1 -1
- package/dist/src/importers/ado-importer.d.ts.map +1 -1
- package/dist/src/importers/ado-importer.js +2 -0
- package/dist/src/importers/ado-importer.js.map +1 -1
- package/dist/src/importers/duplicate-detector.d.ts +5 -2
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -1
- package/dist/src/importers/duplicate-detector.js +8 -2
- package/dist/src/importers/duplicate-detector.js.map +1 -1
- package/dist/src/importers/github-importer.d.ts.map +1 -1
- package/dist/src/importers/github-importer.js +24 -1
- package/dist/src/importers/github-importer.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +27 -3
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.d.ts +5 -0
- package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.js +35 -6
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
- package/dist/src/utils/external-resource-validator.d.ts +5 -192
- package/dist/src/utils/external-resource-validator.d.ts.map +1 -1
- package/dist/src/utils/external-resource-validator.js +10 -1162
- package/dist/src/utils/external-resource-validator.js.map +1 -1
- package/dist/src/utils/feature-id-collision.d.ts +70 -0
- package/dist/src/utils/feature-id-collision.d.ts.map +1 -0
- package/dist/src/utils/feature-id-collision.js +142 -0
- package/dist/src/utils/feature-id-collision.js.map +1 -0
- package/dist/src/utils/validators/ado-validator.d.ts +86 -0
- package/dist/src/utils/validators/ado-validator.d.ts.map +1 -0
- package/dist/src/utils/validators/ado-validator.js +528 -0
- package/dist/src/utils/validators/ado-validator.js.map +1 -0
- package/dist/src/utils/validators/index.d.ts +11 -0
- package/dist/src/utils/validators/index.d.ts.map +1 -0
- package/dist/src/utils/validators/index.js +12 -0
- package/dist/src/utils/validators/index.js.map +1 -0
- package/dist/src/utils/validators/jira-validator.d.ts +70 -0
- package/dist/src/utils/validators/jira-validator.d.ts.map +1 -0
- package/dist/src/utils/validators/jira-validator.js +606 -0
- package/dist/src/utils/validators/jira-validator.js.map +1 -0
- package/dist/src/utils/validators/types.d.ts +82 -0
- package/dist/src/utils/validators/types.d.ts.map +1 -0
- package/dist/src/utils/validators/types.js +6 -0
- package/dist/src/utils/validators/types.js.map +1 -0
- package/package.json +3 -3
- package/plugins/specweave/.claude-plugin/plugin.json +7 -62
- package/plugins/specweave/commands/specweave-archive.md +3 -3
- package/plugins/specweave/commands/specweave-increment.md +18 -19
- package/plugins/specweave/hooks/hooks.json +3 -49
- package/plugins/specweave/hooks/hooks.json.bak +72 -0
- package/plugins/specweave/hooks/hooks.json.v1-backup +16 -0
- package/plugins/specweave/hooks/lib/update-status-line.sh +39 -15
- package/plugins/specweave/hooks/post-task-edit.sh +10 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +27 -8
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +44 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +24 -0
- package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +46 -0
- package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +54 -0
- package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +46 -0
- package/plugins/specweave/hooks/v2/handlers/status-update.sh +50 -0
- package/plugins/specweave/hooks/v2/hooks.json +16 -0
- package/plugins/specweave/hooks/v2/queue/dequeue.sh +30 -0
- package/plugins/specweave/hooks/v2/queue/enqueue.sh +41 -0
- package/plugins/specweave/hooks/v2/queue/processor.sh +72 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js +11 -10
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js.map +1 -1
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +20 -1262
- package/plugins/specweave-github/lib/user-story-issue-builder.js +4 -4
- package/plugins/specweave-github/lib/user-story-issue-builder.ts +6 -6
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +30 -1254
- package/src/templates/tasks.md.template +2 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
- package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
- package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
- package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
- package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for external resource validators
|
|
3
|
+
* @module utils/validators/types
|
|
4
|
+
*/
|
|
5
|
+
export interface JiraProject {
|
|
6
|
+
id: string;
|
|
7
|
+
key: string;
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
export interface JiraBoard {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
location?: {
|
|
15
|
+
projectKey?: string;
|
|
16
|
+
projectId?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface JiraValidationResult {
|
|
20
|
+
valid: boolean;
|
|
21
|
+
project: {
|
|
22
|
+
exists: boolean;
|
|
23
|
+
key?: string;
|
|
24
|
+
id?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
};
|
|
27
|
+
boards: {
|
|
28
|
+
valid: boolean;
|
|
29
|
+
existing: number[];
|
|
30
|
+
missing: string[];
|
|
31
|
+
created: Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
id: number;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
envUpdated: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface AzureDevOpsProject {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
state?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface AzureDevOpsTeam {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface AzureDevOpsAreaPath {
|
|
50
|
+
id: number;
|
|
51
|
+
name: string;
|
|
52
|
+
path: string;
|
|
53
|
+
hasChildren?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface AzureDevOpsProjectResult {
|
|
56
|
+
name: string;
|
|
57
|
+
id?: string;
|
|
58
|
+
exists: boolean;
|
|
59
|
+
created: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface AzureDevOpsAreaPathResult {
|
|
62
|
+
name: string;
|
|
63
|
+
project?: string;
|
|
64
|
+
exists: boolean;
|
|
65
|
+
created: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface AzureDevOpsTeamResult {
|
|
68
|
+
name: string;
|
|
69
|
+
id?: string;
|
|
70
|
+
project?: string;
|
|
71
|
+
exists: boolean;
|
|
72
|
+
created: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface AzureDevOpsValidationResult {
|
|
75
|
+
valid: boolean;
|
|
76
|
+
strategy?: string;
|
|
77
|
+
projects: AzureDevOpsProjectResult[];
|
|
78
|
+
teams: AzureDevOpsTeamResult[];
|
|
79
|
+
areaPaths: AzureDevOpsAreaPathResult[];
|
|
80
|
+
envUpdated: boolean;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/utils/validators/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE;QACP,MAAM,EAAE,OAAO,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,MAAM,EAAE;QACN,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9C,CAAC;IACF,UAAU,EAAE,OAAO,CAAC;CACrB;AAMD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,wBAAwB,EAAE,CAAC;IACrC,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,SAAS,EAAE,yBAAyB,EAAE,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/utils/validators/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.42",
|
|
4
4
|
"description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"docs:dev": "cd docs-site && npm start",
|
|
34
34
|
"docs:build": "cd docs-site && npm run build",
|
|
35
35
|
"docs:install": "cd docs-site && npm install --legacy-peer-deps",
|
|
36
|
-
"docs:internal": "
|
|
37
|
-
"docs:internal:build": "
|
|
36
|
+
"docs:internal": "cd docs-site && npm run start:internal",
|
|
37
|
+
"docs:internal:build": "cd docs-site && npm run build:internal",
|
|
38
38
|
"release:patch": "bash scripts/bump-version.sh patch",
|
|
39
39
|
"release:minor": "bash scripts/bump-version.sh minor",
|
|
40
40
|
"release:major": "bash scripts/bump-version.sh major",
|
|
@@ -20,82 +20,27 @@
|
|
|
20
20
|
"living-docs"
|
|
21
21
|
],
|
|
22
22
|
"hooks": {
|
|
23
|
-
"
|
|
23
|
+
"SessionStart": [
|
|
24
24
|
{
|
|
25
|
-
"matcher": "TodoWrite",
|
|
26
25
|
"hooks": [
|
|
27
26
|
{
|
|
28
27
|
"type": "command",
|
|
29
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/
|
|
30
|
-
"timeout": 2
|
|
31
|
-
|
|
32
|
-
]
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"matcher": "Edit",
|
|
36
|
-
"hooks": [
|
|
37
|
-
{
|
|
38
|
-
"type": "command",
|
|
39
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-edit-write-consolidated.sh",
|
|
40
|
-
"timeout": 1,
|
|
41
|
-
"description": "Consolidated pre-hook for Edit (v0.25.0)"
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"matcher": "Write",
|
|
47
|
-
"hooks": [
|
|
48
|
-
{
|
|
49
|
-
"type": "command",
|
|
50
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-edit-write-consolidated.sh",
|
|
51
|
-
"timeout": 1,
|
|
52
|
-
"description": "Consolidated pre-hook for Write (v0.25.0)"
|
|
28
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/session-start.sh",
|
|
29
|
+
"timeout": 2,
|
|
30
|
+
"description": "v2: Launch background event processor"
|
|
53
31
|
}
|
|
54
32
|
]
|
|
55
33
|
}
|
|
56
34
|
],
|
|
57
35
|
"PostToolUse": [
|
|
58
36
|
{
|
|
59
|
-
"matcher": "
|
|
60
|
-
"hooks": [
|
|
61
|
-
{
|
|
62
|
-
"type": "command",
|
|
63
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-completion.sh",
|
|
64
|
-
"timeout": 10
|
|
65
|
-
}
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"matcher": "Edit",
|
|
37
|
+
"matcher": "Edit|Write",
|
|
70
38
|
"hooks": [
|
|
71
39
|
{
|
|
72
40
|
"type": "command",
|
|
73
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-
|
|
74
|
-
"timeout": 5,
|
|
75
|
-
"description": "Consolidated post-hook for Edit (v0.25.0)"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"type": "command",
|
|
79
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-metadata-change.sh",
|
|
80
|
-
"timeout": 2,
|
|
81
|
-
"description": "Fast early-exit for non-metadata.json (v0.25.0)"
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
"matcher": "Write",
|
|
87
|
-
"hooks": [
|
|
88
|
-
{
|
|
89
|
-
"type": "command",
|
|
90
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-edit-write-consolidated.sh",
|
|
91
|
-
"timeout": 5,
|
|
92
|
-
"description": "Consolidated post-hook for Write (v0.25.0)"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"type": "command",
|
|
96
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-metadata-change.sh",
|
|
41
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/post-tool-use.sh",
|
|
97
42
|
"timeout": 2,
|
|
98
|
-
"description": "
|
|
43
|
+
"description": "v2: Single dispatcher for all PostToolUse events (<50ms)"
|
|
99
44
|
}
|
|
100
45
|
]
|
|
101
46
|
}
|
|
@@ -53,7 +53,7 @@ This command automatically synchronizes living docs by archiving features in:
|
|
|
53
53
|
|
|
54
54
|
- `<increment-ids>`: Specific increment IDs to archive (e.g., "1", "0001", "0031")
|
|
55
55
|
- `--older-than <days>`: Archive increments older than N days
|
|
56
|
-
- `--keep-last <n>`: Keep last N increments, archive the rest (**default:
|
|
56
|
+
- `--keep-last <n>`: Keep last N increments, archive the rest (**default: 5** when no other filters)
|
|
57
57
|
- `--pattern <regex>`: Archive increments matching pattern
|
|
58
58
|
- `--archive-completed`: Archive all completed increments (use with caution!)
|
|
59
59
|
- `--preserve-active`: Never archive active/paused increments (default: true)
|
|
@@ -61,11 +61,11 @@ This command automatically synchronizes living docs by archiving features in:
|
|
|
61
61
|
|
|
62
62
|
## CRITICAL SAFETY FEATURE
|
|
63
63
|
|
|
64
|
-
**Default `--keep-last
|
|
64
|
+
**Default `--keep-last 5`**: When called without any filtering options (no increment IDs, no pattern, no `--older-than`, no `--archive-completed`), the archiver **automatically defaults to `--keep-last 5`** to prevent accidentally archiving ALL increments.
|
|
65
65
|
|
|
66
66
|
This safety feature ensures:
|
|
67
67
|
- ✅ Running `/specweave:archive` without options won't archive everything
|
|
68
|
-
- ✅ Last
|
|
68
|
+
- ✅ Last 5 increments always remain visible for easy reference
|
|
69
69
|
- ✅ Explicit criteria required to archive recent work
|
|
70
70
|
|
|
71
71
|
## Archive Rules
|
|
@@ -149,11 +149,11 @@ import { MetadataManager } from '../core/metadata-manager';
|
|
|
149
149
|
import { ConfigManager } from '../core/config-manager';
|
|
150
150
|
import { IncrementType } from '../core/types';
|
|
151
151
|
|
|
152
|
-
// 1. Load config (defaults: maxActiveIncrements=1, hardCap=
|
|
152
|
+
// 1. Load config (defaults: maxActiveIncrements=1, hardCap=3, allowEmergencyInterrupt=true)
|
|
153
153
|
const config = ConfigManager.load();
|
|
154
154
|
const limits = config.limits || {
|
|
155
155
|
maxActiveIncrements: 1,
|
|
156
|
-
hardCap:
|
|
156
|
+
hardCap: 3,
|
|
157
157
|
allowEmergencyInterrupt: true,
|
|
158
158
|
typeBehaviors: {
|
|
159
159
|
canInterrupt: ['hotfix', 'bug']
|
|
@@ -167,32 +167,31 @@ const activeCount = active.length;
|
|
|
167
167
|
// 3. Ask user for increment type (or detect from title)
|
|
168
168
|
const incrementType = await promptForType(); // hotfix, feature, bug, change-request, refactor, experiment
|
|
169
169
|
|
|
170
|
-
// 4. HARD CAP
|
|
170
|
+
// 4. HARD CAP WARNING (negotiable - user decides!)
|
|
171
171
|
if (activeCount >= limits.hardCap) {
|
|
172
|
-
console.log(chalk.
|
|
173
|
-
console.log(chalk.
|
|
172
|
+
console.log(chalk.yellow.bold('\n⚠️ WIP LIMIT EXCEEDED\n'));
|
|
173
|
+
console.log(chalk.yellow(`You have ${activeCount} active increments (configured limit: ${limits.hardCap})\n`));
|
|
174
174
|
|
|
175
|
-
console.log(chalk.
|
|
175
|
+
console.log(chalk.dim('Active increments:'));
|
|
176
176
|
active.forEach(inc => {
|
|
177
177
|
console.log(chalk.dim(` • ${inc.id} [${inc.type}]`));
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
-
console.log(chalk.blue('\n💡
|
|
181
|
-
console.log(chalk.white('1️⃣ Complete an increment:'));
|
|
182
|
-
console.log(chalk.
|
|
183
|
-
console.log(chalk.white('
|
|
184
|
-
console.log(chalk.
|
|
185
|
-
console.log(chalk.white('3️⃣ Check status:'));
|
|
186
|
-
console.log(chalk.dim(' /specweave:status\n'));
|
|
180
|
+
console.log(chalk.blue('\n💡 Options:\n'));
|
|
181
|
+
console.log(chalk.white('1️⃣ Complete an increment: /specweave:done <id>'));
|
|
182
|
+
console.log(chalk.white('2️⃣ Pause an increment: /specweave:pause <id>'));
|
|
183
|
+
console.log(chalk.white('3️⃣ Increase limit: Edit .specweave/config.json limits.hardCap'));
|
|
184
|
+
console.log(chalk.white('4️⃣ Continue anyway (confirm below)\n'));
|
|
187
185
|
|
|
188
|
-
console.log(chalk.yellow('📝 Multiple hotfixes? Combine them into ONE increment!'));
|
|
189
|
-
console.log(chalk.dim(' Example: 0009-security-fixes (SQL + XSS + CSRF)\n'));
|
|
190
|
-
|
|
191
|
-
console.log(chalk.red.bold('⛔ This limit is enforced for your productivity.'));
|
|
192
186
|
console.log(chalk.dim('Research: 3+ concurrent tasks = 40% slower + more bugs\n'));
|
|
193
187
|
|
|
194
|
-
//
|
|
195
|
-
|
|
188
|
+
// ASK user instead of blocking
|
|
189
|
+
const proceed = await promptConfirm('Continue with new increment anyway?');
|
|
190
|
+
if (!proceed) {
|
|
191
|
+
console.log(chalk.dim('Cancelled. Complete or pause existing work first.'));
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
console.log(chalk.green('✓ Proceeding with new increment...\n'));
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
// 5. SOFT ENFORCEMENT (activeCount >= maxActiveIncrements)
|
|
@@ -5,65 +5,19 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start
|
|
9
|
-
}
|
|
10
|
-
]
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
"PreToolUse": [
|
|
14
|
-
{
|
|
15
|
-
"matcher": "Edit",
|
|
16
|
-
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/tasks\\.md",
|
|
17
|
-
"hooks": [
|
|
18
|
-
{
|
|
19
|
-
"type": "command",
|
|
20
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-task-completion-edit.sh"
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"UserPromptSubmit": [
|
|
26
|
-
{
|
|
27
|
-
"hooks": [
|
|
28
|
-
{
|
|
29
|
-
"type": "command",
|
|
30
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-command-deduplication.sh"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"type": "command",
|
|
34
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-submit.sh"
|
|
8
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/session-start.sh"
|
|
35
9
|
}
|
|
36
10
|
]
|
|
37
11
|
}
|
|
38
12
|
],
|
|
39
13
|
"PostToolUse": [
|
|
40
|
-
{
|
|
41
|
-
"matcher": "Write",
|
|
42
|
-
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/(spec|plan|tasks)\\.md",
|
|
43
|
-
"hooks": [
|
|
44
|
-
{
|
|
45
|
-
"type": "command",
|
|
46
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-increment-planning.sh"
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"matcher": "Edit",
|
|
52
|
-
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/(tasks|spec)\\.md",
|
|
53
|
-
"hooks": [
|
|
54
|
-
{
|
|
55
|
-
"type": "command",
|
|
56
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-edit.sh"
|
|
57
|
-
}
|
|
58
|
-
]
|
|
59
|
-
},
|
|
60
14
|
{
|
|
61
15
|
"matcher": "Edit|Write",
|
|
62
|
-
"matcher_content": "\\.specweave/increments/
|
|
16
|
+
"matcher_content": "\\.specweave/increments/",
|
|
63
17
|
"hooks": [
|
|
64
18
|
{
|
|
65
19
|
"type": "command",
|
|
66
|
-
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-
|
|
20
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/v2/dispatchers/post-tool-use.sh"
|
|
67
21
|
}
|
|
68
22
|
]
|
|
69
23
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-reconcile.sh"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"PreToolUse": [
|
|
14
|
+
{
|
|
15
|
+
"matcher": "Edit",
|
|
16
|
+
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/tasks\\.md",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-task-completion-edit.sh"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"UserPromptSubmit": [
|
|
26
|
+
{
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pre-command-deduplication.sh"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-submit.sh"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"PostToolUse": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": "Write",
|
|
42
|
+
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/(spec|plan|tasks)\\.md",
|
|
43
|
+
"hooks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-increment-planning.sh"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"matcher": "Edit",
|
|
52
|
+
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/(tasks|spec)\\.md",
|
|
53
|
+
"hooks": [
|
|
54
|
+
{
|
|
55
|
+
"type": "command",
|
|
56
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-edit.sh"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"matcher": "Edit|Write",
|
|
62
|
+
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/metadata\\.json",
|
|
63
|
+
"hooks": [
|
|
64
|
+
{
|
|
65
|
+
"type": "command",
|
|
66
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-metadata-change.sh"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit",
|
|
6
|
+
"matcher_content": "\\.specweave/increments/[0-9]{4}-.+/(tasks|spec)\\.md",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-edit.sh"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -87,39 +87,61 @@ if [[ ! -d "$INCREMENTS_DIR" ]]; then
|
|
|
87
87
|
fi
|
|
88
88
|
|
|
89
89
|
# ============================================================================
|
|
90
|
-
# ACQUIRE LOCK
|
|
90
|
+
# ACQUIRE LOCK (ATOMIC - mkdir pattern prevents TOCTOU race!)
|
|
91
91
|
# ============================================================================
|
|
92
92
|
mkdir -p "$STATE_DIR"
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
LOCK_DIR="$STATE_DIR/.status-update.lockdir"
|
|
94
|
+
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
|
95
|
+
# Lock exists - check if stale (>30s)
|
|
96
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
97
|
+
LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCK_DIR" 2>/dev/null || echo 0) ))
|
|
98
|
+
else
|
|
99
|
+
LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_DIR" 2>/dev/null || echo 0) ))
|
|
100
|
+
fi
|
|
101
|
+
if [[ $LOCK_AGE -lt 30 ]]; then
|
|
102
|
+
exit 0 # Another process holds lock
|
|
103
|
+
fi
|
|
104
|
+
# Stale lock - remove and retry
|
|
105
|
+
rm -rf "$LOCK_DIR"
|
|
106
|
+
mkdir "$LOCK_DIR" 2>/dev/null || exit 0
|
|
107
|
+
fi
|
|
108
|
+
echo $$ > "$LOCK_DIR/pid"
|
|
109
|
+
trap 'rm -rf "$LOCK_DIR"' EXIT
|
|
95
110
|
|
|
96
111
|
# ============================================================================
|
|
97
|
-
# FIND ACTIVE INCREMENTS (
|
|
112
|
+
# FIND ACTIVE INCREMENTS (uses metadata.json - SOURCE OF TRUTH!)
|
|
98
113
|
# ============================================================================
|
|
99
114
|
ACTIVE_FILES=""
|
|
100
115
|
OPEN_COUNT=0
|
|
101
116
|
OLDEST_DATE="9999-99-99"
|
|
102
117
|
CURRENT_INCREMENT=""
|
|
103
118
|
|
|
104
|
-
while IFS= read -r
|
|
105
|
-
[[ -z "$
|
|
119
|
+
while IFS= read -r metadata_file; do
|
|
120
|
+
[[ -z "$metadata_file" ]] && continue
|
|
106
121
|
|
|
107
|
-
#
|
|
108
|
-
if
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
# Extract status from metadata.json (jq if available, grep fallback)
|
|
123
|
+
if command -v jq >/dev/null 2>&1; then
|
|
124
|
+
status=$(jq -r '.status // "unknown"' "$metadata_file" 2>/dev/null || echo "unknown")
|
|
125
|
+
created=$(jq -r '.created // "9999-99-99"' "$metadata_file" 2>/dev/null || echo "9999-99-99")
|
|
126
|
+
else
|
|
127
|
+
status=$(grep -oP '"status"\s*:\s*"\K[^"]*' "$metadata_file" 2>/dev/null || echo "unknown")
|
|
128
|
+
created=$(grep -oP '"created"\s*:\s*"\K[^"]*' "$metadata_file" 2>/dev/null || echo "9999-99-99")
|
|
129
|
+
fi
|
|
111
130
|
|
|
112
|
-
|
|
113
|
-
|
|
131
|
+
# Check if active
|
|
132
|
+
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "in-progress" ]]; then
|
|
133
|
+
OPEN_COUNT=$((OPEN_COUNT + 1))
|
|
134
|
+
increment_id=$(basename "$(dirname "$metadata_file")")
|
|
114
135
|
|
|
115
136
|
if [[ "$created" < "$OLDEST_DATE" ]]; then
|
|
116
137
|
OLDEST_DATE="$created"
|
|
117
138
|
CURRENT_INCREMENT="$increment_id"
|
|
118
139
|
fi
|
|
119
140
|
|
|
141
|
+
spec_file="$(dirname "$metadata_file")/spec.md"
|
|
120
142
|
ACTIVE_FILES="$ACTIVE_FILES $spec_file"
|
|
121
143
|
fi
|
|
122
|
-
done < <(find "$INCREMENTS_DIR" -maxdepth 2 -name "
|
|
144
|
+
done < <(find "$INCREMENTS_DIR" -maxdepth 2 -name "metadata.json" -not -path "*/_archive/*" 2>/dev/null)
|
|
123
145
|
|
|
124
146
|
# No active increments?
|
|
125
147
|
if [[ -z "$CURRENT_INCREMENT" ]]; then
|
|
@@ -186,10 +208,12 @@ COMPLETED_ACS=${COMPLETED_ACS:-0}
|
|
|
186
208
|
OPEN_COUNT=${OPEN_COUNT:-0}
|
|
187
209
|
PERCENTAGE=${PERCENTAGE:-0}
|
|
188
210
|
|
|
189
|
-
# Generate JSON directly (
|
|
190
|
-
|
|
211
|
+
# Generate JSON directly (ATOMIC: write temp then mv to prevent partial reads!)
|
|
212
|
+
TEMP_CACHE="$CACHE_FILE.tmp.$$"
|
|
213
|
+
cat > "$TEMP_CACHE" << EOF
|
|
191
214
|
{"current":{"id":"$CURRENT_INCREMENT","name":"$CURRENT_INCREMENT","completed":$COMPLETED_TASKS,"total":$TOTAL_TASKS,"percentage":$PERCENTAGE,"acsCompleted":$COMPLETED_ACS,"acsTotal":$TOTAL_ACS},"openCount":$OPEN_COUNT,"lastUpdate":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
|
|
192
215
|
EOF
|
|
216
|
+
mv "$TEMP_CACHE" "$CACHE_FILE"
|
|
193
217
|
|
|
194
218
|
# Update mtime marker
|
|
195
219
|
touch "$MTIME_FILE"
|
|
@@ -32,6 +32,16 @@ if [[ -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
|
32
32
|
|
|
33
33
|
# Update status line
|
|
34
34
|
bash "$HOOK_DIR/lib/update-status-line.sh" 2>/dev/null || true
|
|
35
|
+
|
|
36
|
+
# CRASH PREVENTION: Check task count in active increments
|
|
37
|
+
for tasks_file in "$PROJECT_ROOT/.specweave/increments"/[0-9]*/tasks.md; do
|
|
38
|
+
[[ -f "$tasks_file" ]] || continue
|
|
39
|
+
task_count=$(grep -c "^### T-" "$tasks_file" 2>/dev/null || echo "0")
|
|
40
|
+
if [[ "$task_count" -gt 8 ]]; then
|
|
41
|
+
inc_name=$(basename "$(dirname "$tasks_file")")
|
|
42
|
+
echo "⚠️ CRASH RISK: $inc_name has $task_count tasks (max 8). Split increment!" >&2
|
|
43
|
+
fi
|
|
44
|
+
done
|
|
35
45
|
fi
|
|
36
46
|
|
|
37
47
|
exit 0
|
|
@@ -76,27 +76,46 @@ if [[ -d "$SPECWEAVE_DIR/increments" ]]; then
|
|
|
76
76
|
fi
|
|
77
77
|
|
|
78
78
|
# ==============================================================================
|
|
79
|
-
# DISCIPLINE VALIDATION:
|
|
79
|
+
# DISCIPLINE VALIDATION: Warn about WIP limits (configurable, not hard block!)
|
|
80
80
|
# ==============================================================================
|
|
81
81
|
|
|
82
82
|
if echo "$PROMPT" | grep -q "/specweave:increment"; then
|
|
83
|
-
#
|
|
84
|
-
|
|
83
|
+
# Read limits from config.json (respect user's settings!)
|
|
84
|
+
CONFIG_FILE="$SPECWEAVE_DIR/config.json"
|
|
85
|
+
SOFT_LIMIT=1
|
|
86
|
+
HARD_CAP=3
|
|
87
|
+
|
|
88
|
+
if [[ -f "$CONFIG_FILE" ]]; then
|
|
89
|
+
if command -v jq >/dev/null 2>&1; then
|
|
90
|
+
SOFT_LIMIT=$(jq -r '.limits.maxActiveIncrements // 1' "$CONFIG_FILE" 2>/dev/null || echo "1")
|
|
91
|
+
HARD_CAP=$(jq -r '.limits.hardCap // 3' "$CONFIG_FILE" 2>/dev/null || echo "3")
|
|
92
|
+
else
|
|
93
|
+
SOFT_LIMIT=$(grep -oP '"maxActiveIncrements"\s*:\s*\K[0-9]+' "$CONFIG_FILE" 2>/dev/null || echo "1")
|
|
94
|
+
HARD_CAP=$(grep -oP '"hardCap"\s*:\s*\K[0-9]+' "$CONFIG_FILE" 2>/dev/null || echo "3")
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Ensure valid numbers
|
|
99
|
+
[[ ! "$SOFT_LIMIT" =~ ^[0-9]+$ ]] && SOFT_LIMIT=1
|
|
100
|
+
[[ ! "$HARD_CAP" =~ ^[0-9]+$ ]] && HARD_CAP=3
|
|
101
|
+
|
|
102
|
+
# Above hard cap: strong warning but NOT a block (user decides!)
|
|
103
|
+
if [[ "$ACTIVE_COUNT" -ge "$HARD_CAP" ]]; then
|
|
85
104
|
cat <<EOF
|
|
86
105
|
{
|
|
87
|
-
"decision": "
|
|
88
|
-
"
|
|
106
|
+
"decision": "approve",
|
|
107
|
+
"systemMessage": "⚠️ WIP LIMIT EXCEEDED (${ACTIVE_COUNT}/${HARD_CAP})\n\nYou have $ACTIVE_COUNT active increments (configured maximum: $HARD_CAP)\n\nActive increments:\n$ACTIVE_LIST\n\n🧠 Research shows 3+ concurrent tasks = 40% slower + more bugs\n\n💡 Options:\n 1️⃣ Complete an increment: /specweave:done <id>\n 2️⃣ Pause an increment: /specweave:pause <id>\n 3️⃣ Increase limit: Edit .specweave/config.json limits.hardCap\n 4️⃣ Continue anyway (not recommended)\n\n📝 To proceed anyway, just confirm your intent."
|
|
89
108
|
}
|
|
90
109
|
EOF
|
|
91
110
|
exit 0
|
|
92
111
|
fi
|
|
93
112
|
|
|
94
|
-
#
|
|
95
|
-
if [[ "$ACTIVE_COUNT" -ge
|
|
113
|
+
# At soft limit: mild warning, approve
|
|
114
|
+
if [[ "$ACTIVE_COUNT" -ge "$SOFT_LIMIT" ]]; then
|
|
96
115
|
cat <<EOF
|
|
97
116
|
{
|
|
98
117
|
"decision": "approve",
|
|
99
|
-
"systemMessage": "⚠️ WIP LIMIT REACHED\n\nYou have $ACTIVE_COUNT active increment (recommended limit:
|
|
118
|
+
"systemMessage": "⚠️ WIP LIMIT REACHED (${ACTIVE_COUNT}/${SOFT_LIMIT})\n\nYou have $ACTIVE_COUNT active increment(s) (recommended limit: $SOFT_LIMIT)\n\nActive increments:\n$ACTIVE_LIST\n\n🧠 Focus Principle: Fewer active increments = maximum productivity\n\n💡 Consider:\n 1️⃣ Complete current work (recommended)\n 2️⃣ Pause current work (/specweave:pause)\n 3️⃣ Continue anyway\n\n⚠️ Emergency hotfix/bug? Use --type=hotfix or --type=bug"
|
|
100
119
|
}
|
|
101
120
|
EOF
|
|
102
121
|
exit 0
|