specweave 3.0.14 → 3.0.16

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.
Files changed (159) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/README.md +17 -0
  3. package/bin/specweave.js +25 -7
  4. package/dist/dashboard/assets/{index-DS3yH-sX.css → index-BFPKNEDz.css} +1 -1
  5. package/dist/dashboard/index.html +2 -2
  6. package/dist/plugins/specweave/lib/integrations/github/github-client-v2.js +2 -2
  7. package/dist/plugins/specweave/lib/integrations/github/github-client-v2.js.map +1 -1
  8. package/dist/src/cli/commands/auto-status.d.ts +0 -10
  9. package/dist/src/cli/commands/auto-status.d.ts.map +1 -1
  10. package/dist/src/cli/commands/auto-status.js +3 -2
  11. package/dist/src/cli/commands/auto-status.js.map +1 -1
  12. package/dist/src/cli/commands/auto.d.ts +0 -17
  13. package/dist/src/cli/commands/auto.d.ts.map +1 -1
  14. package/dist/src/cli/commands/auto.js +8 -14
  15. package/dist/src/cli/commands/auto.js.map +1 -1
  16. package/dist/src/cli/commands/get.d.ts +4 -0
  17. package/dist/src/cli/commands/get.d.ts.map +1 -1
  18. package/dist/src/cli/commands/get.js +15 -33
  19. package/dist/src/cli/commands/get.js.map +1 -1
  20. package/dist/src/cli/commands/qa.js +2 -2
  21. package/dist/src/cli/commands/qa.js.map +1 -1
  22. package/dist/src/cli/commands/save.js +1 -1
  23. package/dist/src/cli/commands/save.js.map +1 -1
  24. package/dist/src/cli/commands/sync-progress.d.ts +0 -10
  25. package/dist/src/cli/commands/sync-progress.d.ts.map +1 -1
  26. package/dist/src/cli/commands/sync-progress.js +21 -27
  27. package/dist/src/cli/commands/sync-progress.js.map +1 -1
  28. package/dist/src/cli/commands/task.js +1 -1
  29. package/dist/src/cli/commands/task.js.map +1 -1
  30. package/dist/src/cli/commands/update.js +1 -1
  31. package/dist/src/cli/commands/update.js.map +1 -1
  32. package/dist/src/cli/helpers/get/register-repo.d.ts +1 -11
  33. package/dist/src/cli/helpers/get/register-repo.d.ts.map +1 -1
  34. package/dist/src/cli/helpers/get/register-repo.js +6 -85
  35. package/dist/src/cli/helpers/get/register-repo.js.map +1 -1
  36. package/dist/src/cli/helpers/get/source-parser.d.ts +1 -1
  37. package/dist/src/cli/helpers/get/source-parser.d.ts.map +1 -1
  38. package/dist/src/cli/helpers/get/source-parser.js +4 -4
  39. package/dist/src/cli/helpers/get/source-parser.js.map +1 -1
  40. package/dist/src/cli/helpers/init/path-utils.d.ts +1 -1
  41. package/dist/src/cli/helpers/init/path-utils.d.ts.map +1 -1
  42. package/dist/src/cli/helpers/init/path-utils.js +44 -2
  43. package/dist/src/cli/helpers/init/path-utils.js.map +1 -1
  44. package/dist/src/cli/helpers/init/types.d.ts +1 -0
  45. package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
  46. package/dist/src/core/ac-test-validator-cli.js +1 -1
  47. package/dist/src/core/ac-test-validator-cli.js.map +1 -1
  48. package/dist/src/core/config/types.d.ts +3 -1
  49. package/dist/src/core/config/types.d.ts.map +1 -1
  50. package/dist/src/core/config/types.js.map +1 -1
  51. package/dist/src/core/doctor/checkers/increments-checker.js +2 -2
  52. package/dist/src/core/doctor/checkers/increments-checker.js.map +1 -1
  53. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -1
  54. package/dist/src/core/hooks/handlers/hook-router.js +5 -7
  55. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -1
  56. package/dist/src/core/hooks/handlers/stop.d.ts.map +1 -1
  57. package/dist/src/core/hooks/handlers/stop.js +17 -14
  58. package/dist/src/core/hooks/handlers/stop.js.map +1 -1
  59. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -1
  60. package/dist/src/core/hooks/handlers/utils.js +7 -15
  61. package/dist/src/core/hooks/handlers/utils.js.map +1 -1
  62. package/dist/src/core/increment/duplicate-detector.d.ts +0 -8
  63. package/dist/src/core/increment/duplicate-detector.d.ts.map +1 -1
  64. package/dist/src/core/increment/duplicate-detector.js +15 -11
  65. package/dist/src/core/increment/duplicate-detector.js.map +1 -1
  66. package/dist/src/core/increment/increment-archiver.d.ts +0 -6
  67. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  68. package/dist/src/core/increment/increment-archiver.js +10 -5
  69. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  70. package/dist/src/core/increment/increment-utils.d.ts +6 -6
  71. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  72. package/dist/src/core/increment/increment-utils.js +26 -27
  73. package/dist/src/core/increment/increment-utils.js.map +1 -1
  74. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  75. package/dist/src/core/increment/metadata-manager.js +19 -6
  76. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  77. package/dist/src/core/increment/number-reservation.d.ts +16 -0
  78. package/dist/src/core/increment/number-reservation.d.ts.map +1 -0
  79. package/dist/src/core/increment/number-reservation.js +125 -0
  80. package/dist/src/core/increment/number-reservation.js.map +1 -0
  81. package/dist/src/core/increment/template-creator.d.ts.map +1 -1
  82. package/dist/src/core/increment/template-creator.js +12 -44
  83. package/dist/src/core/increment/template-creator.js.map +1 -1
  84. package/dist/src/core/living-docs/feature-archiver.js +3 -3
  85. package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
  86. package/dist/src/core/living-docs/feature-consistency-validator.js +1 -1
  87. package/dist/src/core/living-docs/feature-consistency-validator.js.map +1 -1
  88. package/dist/src/core/living-docs/feature-id-manager.js +2 -2
  89. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  90. package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
  91. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  92. package/dist/src/core/living-docs/living-docs-sync.js +1 -1
  93. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  94. package/dist/src/core/qa/qa-runner.d.ts +0 -6
  95. package/dist/src/core/qa/qa-runner.d.ts.map +1 -1
  96. package/dist/src/core/qa/qa-runner.js +8 -10
  97. package/dist/src/core/qa/qa-runner.js.map +1 -1
  98. package/dist/src/core/session/handoff-all.d.ts +2 -2
  99. package/dist/src/core/session/handoff-all.d.ts.map +1 -1
  100. package/dist/src/core/session/handoff-all.js +5 -3
  101. package/dist/src/core/session/handoff-all.js.map +1 -1
  102. package/dist/src/core/session/handoff-list.d.ts +0 -19
  103. package/dist/src/core/session/handoff-list.d.ts.map +1 -1
  104. package/dist/src/core/session/handoff-list.js +7 -4
  105. package/dist/src/core/session/handoff-list.js.map +1 -1
  106. package/dist/src/core/session/handoff-remote.d.ts +0 -19
  107. package/dist/src/core/session/handoff-remote.d.ts.map +1 -1
  108. package/dist/src/core/session/handoff-remote.js +3 -3
  109. package/dist/src/core/session/handoff-remote.js.map +1 -1
  110. package/dist/src/core/session/nested-repos.d.ts.map +1 -1
  111. package/dist/src/core/session/nested-repos.js +7 -1
  112. package/dist/src/core/session/nested-repos.js.map +1 -1
  113. package/dist/src/core/specs/spec-metadata-manager.js +1 -1
  114. package/dist/src/core/specs/spec-metadata-manager.js.map +1 -1
  115. package/dist/src/core/specs/spec-parser.js +1 -1
  116. package/dist/src/core/specs/spec-parser.js.map +1 -1
  117. package/dist/src/core/tasks/resolve-increment.d.ts.map +1 -1
  118. package/dist/src/core/tasks/resolve-increment.js +3 -2
  119. package/dist/src/core/tasks/resolve-increment.js.map +1 -1
  120. package/dist/src/core/types/increment-metadata.d.ts +2 -0
  121. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  122. package/dist/src/core/types/increment-metadata.js.map +1 -1
  123. package/dist/src/core/workspace/adoption.d.ts +21 -0
  124. package/dist/src/core/workspace/adoption.d.ts.map +1 -0
  125. package/dist/src/core/workspace/adoption.js +187 -0
  126. package/dist/src/core/workspace/adoption.js.map +1 -0
  127. package/dist/src/core/workspace/context.d.ts +21 -0
  128. package/dist/src/core/workspace/context.d.ts.map +1 -0
  129. package/dist/src/core/workspace/context.js +105 -0
  130. package/dist/src/core/workspace/context.js.map +1 -0
  131. package/dist/src/importers/item-converter.js +1 -1
  132. package/dist/src/importers/item-converter.js.map +1 -1
  133. package/dist/src/sync/github-reconciler.js +2 -2
  134. package/dist/src/sync/github-reconciler.js.map +1 -1
  135. package/dist/src/utils/external-tool-drift-detector.js +1 -1
  136. package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
  137. package/dist/src/utils/feature-id-collision.js +1 -1
  138. package/dist/src/utils/feature-id-collision.js.map +1 -1
  139. package/dist/src/utils/find-project-root.d.ts.map +1 -1
  140. package/dist/src/utils/find-project-root.js +16 -36
  141. package/dist/src/utils/find-project-root.js.map +1 -1
  142. package/dist/src/utils/increment-id-validator.d.ts +27 -67
  143. package/dist/src/utils/increment-id-validator.d.ts.map +1 -1
  144. package/dist/src/utils/increment-id-validator.js +57 -106
  145. package/dist/src/utils/increment-id-validator.js.map +1 -1
  146. package/dist/src/utils/resolve-increment-id.d.ts +0 -22
  147. package/dist/src/utils/resolve-increment-id.d.ts.map +1 -1
  148. package/dist/src/utils/resolve-increment-id.js +17 -41
  149. package/dist/src/utils/resolve-increment-id.js.map +1 -1
  150. package/package.json +2 -1
  151. package/plugins/specweave/.claude-plugin/plugin.json +1 -1
  152. package/plugins/specweave/lib/integrations/github/github-client-v2.js +2 -2
  153. package/plugins/specweave/lib/integrations/github/github-client-v2.ts +2 -2
  154. package/src/core/schemas/specweave-config.schema.json +1130 -0
  155. package/src/core/schemas/sync.schema.json +687 -0
  156. package/src/core/schemas/workspace.schema.json +209 -0
  157. package/src/templates/AGENTS.md.template +8 -7
  158. package/src/templates/git-hooks/pre-commit.template +4 -4
  159. /package/dist/dashboard/assets/{index-DAwyYXiu.js → index-DVaY9gOX.js} +0 -0
@@ -0,0 +1,209 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "description": "Unified workspace configuration (v3.0). Replaces umbrella, multiProject, and projectMappings.",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string",
8
+ "description": "Workspace display name",
9
+ "minLength": 1,
10
+ "maxLength": 256
11
+ },
12
+ "rootRepo": {
13
+ "type": "object",
14
+ "description": "Sync targets for the root/umbrella repo itself",
15
+ "properties": {
16
+ "github": {
17
+ "type": "object",
18
+ "properties": {
19
+ "owner": {
20
+ "type": "string",
21
+ "minLength": 1
22
+ },
23
+ "repo": {
24
+ "type": "string",
25
+ "minLength": 1
26
+ },
27
+ "direction": {
28
+ "type": "string",
29
+ "enum": [
30
+ "import",
31
+ "export",
32
+ "bidirectional"
33
+ ]
34
+ }
35
+ },
36
+ "required": [
37
+ "owner",
38
+ "repo"
39
+ ],
40
+ "additionalProperties": false
41
+ },
42
+ "jira": {
43
+ "type": "object",
44
+ "properties": {
45
+ "projectKey": {
46
+ "type": "string",
47
+ "minLength": 1
48
+ },
49
+ "domain": {
50
+ "type": "string"
51
+ }
52
+ },
53
+ "required": [
54
+ "projectKey"
55
+ ],
56
+ "additionalProperties": false
57
+ },
58
+ "ado": {
59
+ "type": "object",
60
+ "properties": {
61
+ "organization": {
62
+ "type": "string"
63
+ },
64
+ "project": {
65
+ "type": "string",
66
+ "minLength": 1
67
+ }
68
+ },
69
+ "required": [
70
+ "project"
71
+ ],
72
+ "additionalProperties": false
73
+ }
74
+ },
75
+ "additionalProperties": false
76
+ },
77
+ "repos": {
78
+ "type": "array",
79
+ "description": "All repos in this workspace",
80
+ "items": {
81
+ "type": "object",
82
+ "description": "A repository within the workspace",
83
+ "properties": {
84
+ "id": {
85
+ "type": "string",
86
+ "description": "Stable workspace identifier; adopted repositories include the source owner",
87
+ "pattern": "^[a-z0-9-]+$",
88
+ "minLength": 1,
89
+ "maxLength": 64
90
+ },
91
+ "path": {
92
+ "type": "string",
93
+ "description": "Path to repo (relative or absolute)"
94
+ },
95
+ "identity": {
96
+ "type": "string",
97
+ "description": "Credential-free canonical origin host/owner/repository; checkout path remains distinct"
98
+ },
99
+ "prefix": {
100
+ "type": "string",
101
+ "description": "User story prefix for US-{PREFIX}-001 format",
102
+ "minLength": 1,
103
+ "maxLength": 10
104
+ },
105
+ "name": {
106
+ "type": "string",
107
+ "description": "Display name (defaults to id)",
108
+ "maxLength": 128
109
+ },
110
+ "techStack": {
111
+ "type": "array",
112
+ "description": "Tech stack keywords",
113
+ "items": {
114
+ "type": "string"
115
+ }
116
+ },
117
+ "role": {
118
+ "type": "string",
119
+ "description": "Repository role",
120
+ "enum": [
121
+ "frontend",
122
+ "backend",
123
+ "mobile",
124
+ "infra",
125
+ "shared",
126
+ "other"
127
+ ]
128
+ },
129
+ "sync": {
130
+ "type": "object",
131
+ "description": "Sync targets for this repo",
132
+ "properties": {
133
+ "github": {
134
+ "type": "object",
135
+ "properties": {
136
+ "owner": {
137
+ "type": "string",
138
+ "minLength": 1
139
+ },
140
+ "repo": {
141
+ "type": "string",
142
+ "minLength": 1
143
+ },
144
+ "direction": {
145
+ "type": "string",
146
+ "enum": [
147
+ "import",
148
+ "export",
149
+ "bidirectional"
150
+ ]
151
+ }
152
+ },
153
+ "required": [
154
+ "owner",
155
+ "repo"
156
+ ],
157
+ "additionalProperties": false
158
+ },
159
+ "jira": {
160
+ "type": "object",
161
+ "properties": {
162
+ "projectKey": {
163
+ "type": "string",
164
+ "minLength": 1
165
+ },
166
+ "domain": {
167
+ "type": "string"
168
+ }
169
+ },
170
+ "required": [
171
+ "projectKey"
172
+ ],
173
+ "additionalProperties": false
174
+ },
175
+ "ado": {
176
+ "type": "object",
177
+ "properties": {
178
+ "organization": {
179
+ "type": "string"
180
+ },
181
+ "project": {
182
+ "type": "string",
183
+ "minLength": 1
184
+ }
185
+ },
186
+ "required": [
187
+ "project"
188
+ ],
189
+ "additionalProperties": false
190
+ }
191
+ },
192
+ "additionalProperties": false
193
+ }
194
+ },
195
+ "required": [
196
+ "id",
197
+ "path",
198
+ "prefix"
199
+ ],
200
+ "additionalProperties": false
201
+ }
202
+ }
203
+ },
204
+ "required": [
205
+ "name",
206
+ "repos"
207
+ ],
208
+ "additionalProperties": false
209
+ }
@@ -1,28 +1,29 @@
1
1
  <!-- SECTION:header required -->
2
2
  # {PROJECT_NAME}
3
3
 
4
- This project uses SpecWeave. Work is planned in increments: `.specweave/increments/NNNN-slug/spec.md` holds Problem, Scope, Acceptance Criteria, Approach and Tasks, and `ledger.jsonl` beside it records who claimed and finished what. Start every session with `specweave pickup`.
4
+ This project uses SpecWeave. Plan increments in `.specweave/increments/NNNN-slug/spec.md`: Problem, Scope, Acceptance Criteria, Approach and Tasks. Adjacent `ledger.jsonl` records claims and completions. Start sessions with `specweave pickup`.
5
5
  <!-- /SECTION -->
6
6
 
7
7
  <!-- SECTION:loop required -->
8
8
  ## The loop
9
9
 
10
- 1. `specweave pickup`: brings in the latest handoff, then prints the open increment, the next task with its acceptance criteria, claims held by others, branch state, notes and project memory.
11
- 2. New work that needs acceptance criteria or a handoff: `specweave create-increment "title"`, then fill in spec.md. If an open increment already owns the files, add ACs and tasks to it instead of opening another. Small self-contained fixes need no increment.
10
+ 1. `specweave pickup`: applies the latest handoff and prints the open increment, next task and ACs, other claims, branch state, notes and project memory.
11
+ 2. New work needing ACs or handoff: `specweave create-increment "title"`, then fill spec.md. If an open increment owns the files, add ACs and tasks there. Small fixes need no increment.
12
12
  3. `specweave task claim T-NN`, edit only that task's Files, commit as `NNNN: what changed`, then `specweave task done T-NN --run "<its Test>"`.
13
13
  4. `specweave verify`, a review in a fresh session for anything that ships, then `specweave complete NNNN`.
14
- 5. Stopping for any reason (out of tokens, switching tool or account): `specweave handoff --reason "<why>"`.
14
+ 5. Before stopping or switching tools/accounts: `specweave handoff --reason "<why>"`.
15
15
 
16
- **Handoff.** When the user says "hand off", "out of tokens" or "switching accounts", or a "[Usage limit reached" note appears (outside SpecWeave Studio), run `specweave handoff --reason "<why>"` and tell the user to say "pick up" in the other tool. A "[Usage limit approaching" note or a usage heads-up is not a stop: say so in one line and keep working. When the user says "pick up", run `specweave pickup` and continue with the task it names; "pick up <id or title>" passes it on. Of several it takes the newest: say which.
16
+ **Handoff.** When the user says "hand off", "out of tokens" or "switching accounts", or "[Usage limit reached" appears (outside SpecWeave Studio), run `specweave handoff --reason "<why>"`; tell them to say "pick up" in the other tool. "[Usage limit approaching" or usage heads-ups mean keep working; say so. When the user says "pick up", run `specweave pickup`; continue its task, passing any given id/title. Take the newest handoff if several; say which.
17
17
 
18
- Tasks live in spec.md as `### T-01 Title` followed by `- AC: AC-01 | Files: src/a.ts, tests/e2e/a.test.ts | Test: npm test -- e2e/a`. An AC is met when the tasks covering it are done. Leave a message for whoever works on an increment next with `specweave note "<text>"`. Each step is a skill in `.agents/skills/sw-*` and `.claude/skills/sw-*`; other tools: `npx vskill install anton-abyzov/specweave/sw-do`.
18
+ Tasks in spec.md: `### T-01 Title`, then `- AC: AC-01 | Files: src/a.ts, tests/e2e/a.test.ts | Test: npm test -- e2e/a`. An AC is met when its tasks are done. Leave notes with `specweave note "<text>"`. Skills: `.agents/skills/sw-*` and `.claude/skills/sw-*`; other tools: `npx vskill install anton-abyzov/specweave/sw-do`.
19
19
  <!-- /SECTION -->
20
20
 
21
21
  <!-- SECTION:rules required -->
22
22
  ## Rules
23
23
 
24
+ - Use headless Chrome/Playwright CLI for browser tests and automation: `headless: true`, `PWDEBUG=0`, `PLAYWRIGHT_HTML_OPEN=never`, HTML reports `open: 'never'`. Save captures to files; propagate to subagents. Before opening an essential visible browser, ask the user and wait for explicit approval. Headless failure is not approval.
24
25
  - A task is done when its Test exits 0 and you have seen the real output. A Test checks the AC as users would (CLI, HTTP, UI, API); add unit tests only when asked or when config or conventions require them. Never skip, weaken or delete a test to pass, and never set a status by hand.
25
- - One agent per branch and worktree: `git worktree add ../NNNN-<agent> -b inc/NNNN-<agent>`. A claim older than 2h is stale. On a merge conflict in `ledger.jsonl` keep every line from both sides.
26
+ - One agent per branch/worktree: `git worktree add ../NNNN-<agent> -b inc/NNNN-<agent>`. Claims older than 2h are stale. Merge `ledger.jsonl` conflicts keeping every line from both sides.
26
27
  - Decisions that must outlive this session go in spec.md Approach, or as one file per fact in `.specweave/memory/` with a line in its `MEMORY.md` index. Memory is committed, so every tool and account sees it.
27
28
  - Check a secret exists without printing it; never commit `.env*`.
28
29
  - Without the CLI, append ledger lines yourself, one JSON object per line, UTF-8, LF: `{"t":"T-01","e":"claim","by":"<tool>@<host>","at":"<ISO time>"}` (`e` is claim, done, release, skip or block; `done` needs `"evidence":"<commit sha>"`, `skip` needs `"note":"<why>"`).
@@ -129,14 +129,14 @@ ALLOWED_INCREMENT_ROOT_FILES="{{ALLOWED_INCREMENT_ROOT_FILES}}"
129
129
  echo "2️⃣ Checking increment folder cleanliness..."
130
130
 
131
131
  # Get staged files in increment directories
132
- STAGED_INCREMENT_FILES=$(git diff --cached --name-only --diff-filter=AM | grep -E '\.specweave/increments/[0-9]{4}-' || true)
132
+ STAGED_INCREMENT_FILES=$(git diff --cached --name-only --diff-filter=AM | grep -E '\.specweave/increments/[0-9]{3,}[A-Za-z]?-' || true)
133
133
 
134
134
  if [ -n "$STAGED_INCREMENT_FILES" ]; then
135
135
  POLLUTION_FOUND=0
136
136
 
137
137
  for file in $STAGED_INCREMENT_FILES; do
138
138
  # Extract increment directory and relative path within it
139
- increment_dir=$(echo "$file" | grep -oE '\.specweave/increments/[0-9]{4}-[^/]+' || true)
139
+ increment_dir=$(echo "$file" | grep -oE '\.specweave/increments/[0-9]{3,}[A-Za-z]?-[^/]+' || true)
140
140
  if [ -n "$increment_dir" ]; then
141
141
  # Get path relative to increment directory
142
142
  relative_path=$(echo "$file" | sed "s|^$increment_dir/||")
@@ -200,8 +200,8 @@ if [ -d ".specweave/increments" ]; then
200
200
  # Get all increment IDs across ALL directories (including _archive, _paused, etc.)
201
201
  # -name filters on the directory's OWN basename, so `0001-slug/reports`
202
202
  # (depth 2) is NOT counted as a second `0001` while `_archive/0002-slug` is.
203
- ALL_IDS=$(find .specweave/increments -maxdepth 2 -type d -name '[0-9][0-9][0-9][0-9]-*' | \
204
- sed 's|.*/||' | cut -c1-4 | \
203
+ ALL_IDS=$(find .specweave/increments -maxdepth 2 -type d -name '[0-9]*-*' | \
204
+ sed 's|.*/||' | grep -E '^[0-9]{3,}[A-Za-z]?-' | sed -E 's/^([0-9]+)[A-Za-z]?-.*/\1/; s/^0+//; s/^$/0/' | \
205
205
  sort)
206
206
 
207
207
  # Check for duplicates