@spekn/cli 1.0.0 → 1.0.1

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 (154) hide show
  1. package/README.md +58 -0
  2. package/dist/main.js +3707 -611
  3. package/dist/tui/index.mjs +2 -2
  4. package/package.json +29 -12
  5. package/dist/__tests__/export-cli.test.d.ts +0 -1
  6. package/dist/__tests__/export-cli.test.js +0 -70
  7. package/dist/__tests__/tui-args-policy.test.d.ts +0 -1
  8. package/dist/__tests__/tui-args-policy.test.js +0 -50
  9. package/dist/acp-S2MHZOAD.mjs +0 -23
  10. package/dist/acp-UCCI44JY.mjs +0 -25
  11. package/dist/auth/credentials-store.d.ts +0 -2
  12. package/dist/auth/credentials-store.js +0 -5
  13. package/dist/auth/device-flow.d.ts +0 -36
  14. package/dist/auth/device-flow.js +0 -189
  15. package/dist/auth/jwt.d.ts +0 -1
  16. package/dist/auth/jwt.js +0 -6
  17. package/dist/auth/session.d.ts +0 -67
  18. package/dist/auth/session.js +0 -86
  19. package/dist/auth-login.d.ts +0 -34
  20. package/dist/auth-login.js +0 -202
  21. package/dist/auth-logout.d.ts +0 -25
  22. package/dist/auth-logout.js +0 -115
  23. package/dist/auth-status.d.ts +0 -24
  24. package/dist/auth-status.js +0 -109
  25. package/dist/backlog-generate.d.ts +0 -11
  26. package/dist/backlog-generate.js +0 -308
  27. package/dist/backlog-health.d.ts +0 -11
  28. package/dist/backlog-health.js +0 -287
  29. package/dist/bridge-login.d.ts +0 -40
  30. package/dist/bridge-login.js +0 -277
  31. package/dist/chunk-3PAYRI4G.mjs +0 -2428
  32. package/dist/chunk-M4CS3A25.mjs +0 -2426
  33. package/dist/commands/auth/login.d.ts +0 -30
  34. package/dist/commands/auth/login.js +0 -164
  35. package/dist/commands/auth/logout.d.ts +0 -25
  36. package/dist/commands/auth/logout.js +0 -115
  37. package/dist/commands/auth/status.d.ts +0 -24
  38. package/dist/commands/auth/status.js +0 -109
  39. package/dist/commands/backlog/generate.d.ts +0 -11
  40. package/dist/commands/backlog/generate.js +0 -308
  41. package/dist/commands/backlog/health.d.ts +0 -11
  42. package/dist/commands/backlog/health.js +0 -287
  43. package/dist/commands/bridge/login.d.ts +0 -36
  44. package/dist/commands/bridge/login.js +0 -258
  45. package/dist/commands/export.d.ts +0 -35
  46. package/dist/commands/export.js +0 -485
  47. package/dist/commands/marketplace-export.d.ts +0 -21
  48. package/dist/commands/marketplace-export.js +0 -214
  49. package/dist/commands/project-clean.d.ts +0 -1
  50. package/dist/commands/project-clean.js +0 -126
  51. package/dist/commands/repo/common.d.ts +0 -105
  52. package/dist/commands/repo/common.js +0 -775
  53. package/dist/commands/repo/detach.d.ts +0 -2
  54. package/dist/commands/repo/detach.js +0 -120
  55. package/dist/commands/repo/register.d.ts +0 -21
  56. package/dist/commands/repo/register.js +0 -175
  57. package/dist/commands/repo/sync.d.ts +0 -22
  58. package/dist/commands/repo/sync.js +0 -873
  59. package/dist/commands/skills-import-local.d.ts +0 -16
  60. package/dist/commands/skills-import-local.js +0 -352
  61. package/dist/commands/spec/drift-check.d.ts +0 -3
  62. package/dist/commands/spec/drift-check.js +0 -186
  63. package/dist/commands/spec/frontmatter.d.ts +0 -11
  64. package/dist/commands/spec/frontmatter.js +0 -219
  65. package/dist/commands/spec/lint.d.ts +0 -11
  66. package/dist/commands/spec/lint.js +0 -499
  67. package/dist/commands/spec/parse.d.ts +0 -11
  68. package/dist/commands/spec/parse.js +0 -162
  69. package/dist/export.d.ts +0 -35
  70. package/dist/export.js +0 -485
  71. package/dist/main.d.ts +0 -1
  72. package/dist/marketplace-export.d.ts +0 -21
  73. package/dist/marketplace-export.js +0 -214
  74. package/dist/project-clean.d.ts +0 -1
  75. package/dist/project-clean.js +0 -126
  76. package/dist/project-context.d.ts +0 -99
  77. package/dist/project-context.js +0 -376
  78. package/dist/repo-common.d.ts +0 -101
  79. package/dist/repo-common.js +0 -671
  80. package/dist/repo-detach.d.ts +0 -2
  81. package/dist/repo-detach.js +0 -102
  82. package/dist/repo-ingest.d.ts +0 -29
  83. package/dist/repo-ingest.js +0 -305
  84. package/dist/repo-register.d.ts +0 -21
  85. package/dist/repo-register.js +0 -175
  86. package/dist/repo-sync.d.ts +0 -16
  87. package/dist/repo-sync.js +0 -152
  88. package/dist/resources/prompt-loader.d.ts +0 -1
  89. package/dist/resources/prompt-loader.js +0 -62
  90. package/dist/skills-import-local.d.ts +0 -16
  91. package/dist/skills-import-local.js +0 -352
  92. package/dist/spec-drift-check.d.ts +0 -3
  93. package/dist/spec-drift-check.js +0 -186
  94. package/dist/spec-frontmatter.d.ts +0 -11
  95. package/dist/spec-frontmatter.js +0 -219
  96. package/dist/spec-lint.d.ts +0 -11
  97. package/dist/spec-lint.js +0 -499
  98. package/dist/spec-parse.d.ts +0 -11
  99. package/dist/spec-parse.js +0 -162
  100. package/dist/stubs/dotenv.d.ts +0 -5
  101. package/dist/stubs/dotenv.js +0 -6
  102. package/dist/stubs/typeorm.d.ts +0 -22
  103. package/dist/stubs/typeorm.js +0 -28
  104. package/dist/tui/app.d.ts +0 -7
  105. package/dist/tui/app.js +0 -122
  106. package/dist/tui/args.d.ts +0 -8
  107. package/dist/tui/args.js +0 -57
  108. package/dist/tui/capabilities/policy.d.ts +0 -7
  109. package/dist/tui/capabilities/policy.js +0 -64
  110. package/dist/tui/components/frame.d.ts +0 -8
  111. package/dist/tui/components/frame.js +0 -8
  112. package/dist/tui/components/status-bar.d.ts +0 -8
  113. package/dist/tui/components/status-bar.js +0 -8
  114. package/dist/tui/index.d.ts +0 -2
  115. package/dist/tui/index.js +0 -23
  116. package/dist/tui/keymap/use-global-keymap.d.ts +0 -19
  117. package/dist/tui/keymap/use-global-keymap.js +0 -82
  118. package/dist/tui/navigation/nav-items.d.ts +0 -3
  119. package/dist/tui/navigation/nav-items.js +0 -18
  120. package/dist/tui/screens/bridge.d.ts +0 -8
  121. package/dist/tui/screens/bridge.js +0 -19
  122. package/dist/tui/screens/decisions.d.ts +0 -5
  123. package/dist/tui/screens/decisions.js +0 -28
  124. package/dist/tui/screens/export.d.ts +0 -5
  125. package/dist/tui/screens/export.js +0 -16
  126. package/dist/tui/screens/home.d.ts +0 -5
  127. package/dist/tui/screens/home.js +0 -33
  128. package/dist/tui/screens/locked.d.ts +0 -5
  129. package/dist/tui/screens/locked.js +0 -9
  130. package/dist/tui/screens/specs.d.ts +0 -5
  131. package/dist/tui/screens/specs.js +0 -31
  132. package/dist/tui/services/client.d.ts +0 -1
  133. package/dist/tui/services/client.js +0 -18
  134. package/dist/tui/services/context-service.d.ts +0 -19
  135. package/dist/tui/services/context-service.js +0 -246
  136. package/dist/tui/shared-enums.d.ts +0 -16
  137. package/dist/tui/shared-enums.js +0 -19
  138. package/dist/tui/state/use-app-state.d.ts +0 -35
  139. package/dist/tui/state/use-app-state.js +0 -177
  140. package/dist/tui/types.d.ts +0 -77
  141. package/dist/tui/types.js +0 -2
  142. package/dist/tui-bundle.d.ts +0 -1
  143. package/dist/tui-bundle.js +0 -5
  144. package/dist/tui-entry.mjs +0 -1407
  145. package/dist/utils/cli-runtime.d.ts +0 -5
  146. package/dist/utils/cli-runtime.js +0 -22
  147. package/dist/utils/help-error.d.ts +0 -7
  148. package/dist/utils/help-error.js +0 -14
  149. package/dist/utils/interaction.d.ts +0 -19
  150. package/dist/utils/interaction.js +0 -93
  151. package/dist/utils/structured-log.d.ts +0 -7
  152. package/dist/utils/structured-log.js +0 -112
  153. package/dist/utils/trpc-url.d.ts +0 -4
  154. package/dist/utils/trpc-url.js +0 -15
@@ -1,499 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- /**
4
- * spec-lint CLI Tool
5
- *
6
- * Validate specification markdown quality and structure.
7
- *
8
- * Usage: npm run spec-lint <spec-file-path>
9
- * Example: npm run spec-lint specs/DECISIONS.md
10
- */
11
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- var desc = Object.getOwnPropertyDescriptor(m, k);
14
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
- desc = { enumerable: true, get: function() { return m[k]; } };
16
- }
17
- Object.defineProperty(o, k2, desc);
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || (function () {
28
- var ownKeys = function(o) {
29
- ownKeys = Object.getOwnPropertyNames || function (o) {
30
- var ar = [];
31
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
- return ar;
33
- };
34
- return ownKeys(o);
35
- };
36
- return function (mod) {
37
- if (mod && mod.__esModule) return mod;
38
- var result = {};
39
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
- __setModuleDefault(result, mod);
41
- return result;
42
- };
43
- })();
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.main = main;
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- const agents_1 = require("@spekn/agents");
49
- const shared_1 = require("@spekn/shared");
50
- const cli_runtime_1 = require("../../utils/cli-runtime");
51
- function parseArgs(args) {
52
- const options = {};
53
- let filePath;
54
- for (let i = 0; i < args.length; i++) {
55
- const arg = args[i];
56
- if (arg === "--verbose" || arg === "-v") {
57
- options.verbose = true;
58
- }
59
- else if (arg === "--fix" || arg === "-f") {
60
- options.fix = true;
61
- }
62
- else if (!arg.startsWith("-")) {
63
- filePath = arg;
64
- }
65
- }
66
- if (!filePath) {
67
- throw new Error("missing required argument: <spec-file-path>");
68
- }
69
- return { filePath, options };
70
- }
71
- function printHelp() {
72
- console.log(`
73
- spec-lint - Validate specification markdown quality
74
-
75
- USAGE:
76
- npm run spec-lint <spec-file-path> [OPTIONS]
77
-
78
- ARGUMENTS:
79
- <spec-file-path> Path to the specification markdown file
80
-
81
- OPTIONS:
82
- -v, --verbose Show detailed output and suggestions
83
- -f, --fix Auto-fix deterministic anchor formatting issues
84
- -h, --help Show this help message
85
-
86
- LINTING RULES:
87
- frontmatter-required Specification has valid YAML frontmatter
88
- anchor-naming Anchors follow naming convention (lowercase, dots)
89
- anchor-duplicates No duplicate anchors
90
- anchor-acceptance All anchors have acceptance criteria
91
- dependency-valid Dependencies reference valid anchors
92
- markdown-quality Basic markdown quality checks
93
-
94
- EXAMPLES:
95
- npm run spec-lint specs/SPECIFICATION.md
96
- npm run spec-lint specs/DECISIONS.md --verbose
97
- `);
98
- }
99
- function escapeRegExp(value) {
100
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
101
- }
102
- function normalizeAnchorForFix(anchor) {
103
- return anchor
104
- .trim()
105
- .toLowerCase()
106
- .replace(/\s+/g, "-")
107
- .replace(/[^a-z0-9._-]/g, "-")
108
- .replace(/\.\./g, ".")
109
- .replace(/^\./, "")
110
- .replace(/\.$/, "");
111
- }
112
- function applyDeterministicFixes(content) {
113
- const anchors = (0, agents_1.extractAnchors)(content);
114
- const uniqueAnchors = Array.from(new Set(anchors.map((a) => a.anchor)));
115
- let nextContent = content;
116
- let fixesApplied = 0;
117
- const replaceWithCount = (input, pattern, replacement) => {
118
- let count = 0;
119
- const output = input.replace(pattern, () => {
120
- count += 1;
121
- return replacement;
122
- });
123
- return { output, count };
124
- };
125
- for (const anchor of uniqueAnchors) {
126
- const normalized = normalizeAnchorForFix(anchor);
127
- if (!normalized || normalized === anchor) {
128
- continue;
129
- }
130
- const escaped = escapeRegExp(anchor);
131
- const bracket = replaceWithCount(nextContent, new RegExp(`\\[${escaped}\\]`, "g"), `[${normalized}]`);
132
- nextContent = bracket.output;
133
- fixesApplied += bracket.count;
134
- const prefixed = replaceWithCount(nextContent, new RegExp(`spec:${escaped}\\b`, "gi"), `spec:${normalized}`);
135
- nextContent = prefixed.output;
136
- fixesApplied += prefixed.count;
137
- const hashDeps = replaceWithCount(nextContent, new RegExp(`#${escaped}\\b`, "g"), `#${normalized}`);
138
- nextContent = hashDeps.output;
139
- fixesApplied += hashDeps.count;
140
- }
141
- return { content: nextContent, fixesApplied };
142
- }
143
- function checkAnchorNaming(anchors) {
144
- const issues = [];
145
- anchors.forEach((anchor) => {
146
- // Check lowercase
147
- if (anchor.anchor !== anchor.anchor.toLowerCase()) {
148
- issues.push({
149
- severity: "error",
150
- rule: "anchor-naming",
151
- message: "Anchor should be lowercase",
152
- anchor: anchor.anchor,
153
- line: anchor.lineNumber,
154
- suggestion: anchor.anchor.toLowerCase(),
155
- });
156
- }
157
- // Check valid characters (only lowercase letters, numbers, dots, hyphens)
158
- if (!anchor.anchor.match(/^[a-z0-9._-]+$/)) {
159
- issues.push({
160
- severity: "error",
161
- rule: "anchor-naming",
162
- message: "Anchor contains invalid characters (only a-z, 0-9, ., -, _ allowed)",
163
- anchor: anchor.anchor,
164
- line: anchor.lineNumber,
165
- });
166
- }
167
- // Check for double dots or leading/trailing dots
168
- if (anchor.anchor.match(/\.\./)) {
169
- issues.push({
170
- severity: "warning",
171
- rule: "anchor-naming",
172
- message: "Anchor contains consecutive dots",
173
- anchor: anchor.anchor,
174
- line: anchor.lineNumber,
175
- });
176
- }
177
- if (anchor.anchor.startsWith(".") || anchor.anchor.endsWith(".")) {
178
- issues.push({
179
- severity: "warning",
180
- rule: "anchor-naming",
181
- message: "Anchor should not start or end with a dot",
182
- anchor: anchor.anchor,
183
- line: anchor.lineNumber,
184
- });
185
- }
186
- // Recommend dot notation for hierarchical anchors
187
- if (anchor.anchor.includes("_") && !anchor.anchor.includes(".")) {
188
- issues.push({
189
- severity: "info",
190
- rule: "anchor-naming",
191
- message: "Consider using dot notation for hierarchical structure",
192
- anchor: anchor.anchor,
193
- line: anchor.lineNumber,
194
- suggestion: anchor.anchor.replace(/_/g, "."),
195
- });
196
- }
197
- });
198
- return issues;
199
- }
200
- function checkDuplicateAnchors(anchors) {
201
- const issues = [];
202
- const anchorMap = new Map();
203
- anchors.forEach((anchor) => {
204
- const normalized = anchor.anchor.toLowerCase();
205
- if (!anchorMap.has(normalized)) {
206
- anchorMap.set(normalized, []);
207
- }
208
- anchorMap.get(normalized).push(anchor.lineNumber);
209
- });
210
- anchorMap.forEach((lines, anchor) => {
211
- if (lines.length > 1) {
212
- issues.push({
213
- severity: "error",
214
- rule: "anchor-duplicates",
215
- message: `Duplicate anchor found on lines: ${lines.join(", ")}`,
216
- anchor,
217
- });
218
- }
219
- });
220
- return issues;
221
- }
222
- function checkAcceptanceCriteria(content, anchors) {
223
- const issues = [];
224
- anchors.forEach((anchor) => {
225
- const anchorContent = (0, agents_1.extractAnchorContent)(anchor.anchor, content);
226
- if (!anchorContent)
227
- return;
228
- // Check for acceptance criteria section
229
- const hasAcceptanceCriteria = anchorContent.match(/\*\*Acceptance Criteria\*\*:|##\s*Acceptance Criteria|###\s*Acceptance Criteria/i);
230
- if (!hasAcceptanceCriteria) {
231
- issues.push({
232
- severity: "warning",
233
- rule: "anchor-acceptance",
234
- message: "Anchor lacks explicit acceptance criteria section",
235
- anchor: anchor.anchor,
236
- line: anchor.lineNumber,
237
- });
238
- }
239
- });
240
- return issues;
241
- }
242
- function checkDependencyValidity(content, anchors) {
243
- const issues = [];
244
- const validAnchors = (0, agents_1.getValidAnchors)(content);
245
- anchors.forEach((anchor) => {
246
- const anchorContent = (0, agents_1.extractAnchorContent)(anchor.anchor, content);
247
- if (!anchorContent)
248
- return;
249
- // Look for dependency references
250
- const dependencyMatch = anchorContent.match(/\*\*Dependencies\*\*:([^\n]+)/i);
251
- if (dependencyMatch) {
252
- const dependencyText = dependencyMatch[1];
253
- const dependencyAnchors = dependencyText.match(/#[a-z0-9._-]+/gi);
254
- if (dependencyAnchors) {
255
- dependencyAnchors.forEach((dep) => {
256
- const depNormalized = dep.replace(/^#/, "").toLowerCase();
257
- const isValid = validAnchors.some((valid) => valid.toLowerCase() === depNormalized);
258
- if (!isValid) {
259
- issues.push({
260
- severity: "error",
261
- rule: "dependency-valid",
262
- message: `Dependency references non-existent anchor: ${dep}`,
263
- anchor: anchor.anchor,
264
- line: anchor.lineNumber,
265
- });
266
- }
267
- });
268
- }
269
- }
270
- });
271
- return issues;
272
- }
273
- function checkMarkdownQuality(content) {
274
- const issues = [];
275
- const lines = content.split("\n");
276
- lines.forEach((line, index) => {
277
- const lineNumber = index + 1;
278
- // Check for trailing whitespace
279
- if (line.endsWith(" ") || line.endsWith("\t")) {
280
- issues.push({
281
- severity: "info",
282
- rule: "markdown-quality",
283
- message: "Line has trailing whitespace",
284
- line: lineNumber,
285
- });
286
- }
287
- // Check for inconsistent heading markers
288
- const headingMatch = line.match(/^(#{1,6})\s/);
289
- if (headingMatch && line.includes("#", headingMatch[1].length + 1)) {
290
- const afterHeading = line.substring(headingMatch[0].length);
291
- if (!afterHeading.startsWith("#")) {
292
- // Check if there's a # not at the start (could be an anchor)
293
- if (afterHeading.includes("#") &&
294
- !afterHeading.match(/^#[a-z0-9._-]+/i)) {
295
- issues.push({
296
- severity: "warning",
297
- rule: "markdown-quality",
298
- message: "Unexpected # character in heading",
299
- line: lineNumber,
300
- });
301
- }
302
- }
303
- }
304
- });
305
- return issues;
306
- }
307
- function checkFrontmatter(content) {
308
- const issues = [];
309
- const result = (0, shared_1.parseSpecificationFrontmatter)(content);
310
- if (!result.hasFrontmatter) {
311
- issues.push({
312
- severity: "error",
313
- rule: "frontmatter-required",
314
- message: "Specification is missing required YAML frontmatter (delimited by --- markers)",
315
- });
316
- return issues;
317
- }
318
- if (result.errors?.length) {
319
- for (const error of result.errors) {
320
- issues.push({
321
- severity: "error",
322
- rule: "frontmatter-required",
323
- message: `Frontmatter validation error: ${error}`,
324
- });
325
- }
326
- return issues;
327
- }
328
- const fm = result.frontmatter;
329
- if (!fm)
330
- return issues;
331
- // Check hint lengths
332
- if (fm.hints) {
333
- for (const [layer, hints] of Object.entries(fm.hints)) {
334
- if (!hints)
335
- continue;
336
- for (let i = 0; i < hints.length; i++) {
337
- if (hints[i].length > shared_1.HINT_MAX_LENGTH) {
338
- issues.push({
339
- severity: "error",
340
- rule: "frontmatter-required",
341
- message: `Hint hints.${layer}[${i}] exceeds ${shared_1.HINT_MAX_LENGTH} character limit (${hints[i].length} chars)`,
342
- });
343
- }
344
- }
345
- }
346
- }
347
- // Check type-specific properties match declared type
348
- const typeSpecific = ["capability", "architectural", "workflow", "operational"];
349
- const present = typeSpecific.filter((t) => fm[t]);
350
- if (present.length > 1) {
351
- issues.push({
352
- severity: "error",
353
- rule: "frontmatter-required",
354
- message: `Multiple type-specific properties found (${present.join(", ")}). Only one is allowed.`,
355
- });
356
- }
357
- if (present.length === 1 && present[0] !== fm.type) {
358
- issues.push({
359
- severity: "warning",
360
- rule: "frontmatter-required",
361
- message: `Type-specific property "${present[0]}" does not match declared type "${fm.type}"`,
362
- });
363
- }
364
- return issues;
365
- }
366
- function main(argv) {
367
- const args = argv ?? process.argv.slice(2);
368
- if ((0, cli_runtime_1.hasHelpFlag)(args)) {
369
- printHelp();
370
- return 0;
371
- }
372
- let filePath;
373
- let options;
374
- try {
375
- ({ filePath, options } = parseArgs(args));
376
- }
377
- catch {
378
- console.error("Error: Missing required argument <spec-file-path>");
379
- printHelp();
380
- return 1;
381
- }
382
- // Resolve file path
383
- const resolvedPath = path.resolve(process.cwd(), filePath);
384
- // Check if file exists
385
- if (!fs.existsSync(resolvedPath)) {
386
- console.error(`Error: File not found: ${resolvedPath}`);
387
- return 1;
388
- }
389
- // Read file content
390
- let content;
391
- try {
392
- content = fs.readFileSync(resolvedPath, "utf-8");
393
- }
394
- catch (error) {
395
- console.error(`Error reading file: ${(0, cli_runtime_1.errorMessage)(error)}`);
396
- return 1;
397
- }
398
- let fixSummary = null;
399
- if (options.fix) {
400
- const fixed = applyDeterministicFixes(content);
401
- const fileModified = fixed.content !== content;
402
- if (fileModified) {
403
- fs.writeFileSync(resolvedPath, fixed.content, "utf-8");
404
- content = fixed.content;
405
- }
406
- fixSummary = {
407
- attempted: true,
408
- fixesApplied: fixed.fixesApplied,
409
- fileModified,
410
- };
411
- }
412
- // Extract anchors
413
- const anchors = (0, agents_1.extractAnchors)(content);
414
- console.log(`\nLinting ${path.basename(filePath)}...`);
415
- console.log(`Found ${anchors.length} anchor(s)\n`);
416
- // Run all lint checks
417
- const issues = [
418
- ...checkFrontmatter(content),
419
- ...checkAnchorNaming(anchors),
420
- ...checkDuplicateAnchors(anchors),
421
- ...checkAcceptanceCriteria(content, anchors),
422
- ...checkDependencyValidity(content, anchors),
423
- ...checkMarkdownQuality(content),
424
- ];
425
- // Group issues by severity
426
- const errors = issues.filter((i) => i.severity === "error");
427
- const warnings = issues.filter((i) => i.severity === "warning");
428
- const infos = issues.filter((i) => i.severity === "info");
429
- // Display results
430
- if (issues.length === 0) {
431
- console.log("✓ No issues found. Specification is clean!\n");
432
- return 0;
433
- }
434
- if (errors.length > 0) {
435
- console.log(`\n❌ Errors (${errors.length}):\n`);
436
- errors.forEach((issue, index) => {
437
- console.log(`${index + 1}. [${issue.rule}] ${issue.message}`);
438
- if (issue.anchor)
439
- console.log(` Anchor: ${issue.anchor}`);
440
- if (issue.line)
441
- console.log(` Line: ${issue.line}`);
442
- if (issue.suggestion && options.verbose)
443
- console.log(` Suggestion: ${issue.suggestion}`);
444
- console.log();
445
- });
446
- }
447
- if (warnings.length > 0) {
448
- console.log(`\n⚠️ Warnings (${warnings.length}):\n`);
449
- warnings.forEach((issue, index) => {
450
- console.log(`${index + 1}. [${issue.rule}] ${issue.message}`);
451
- if (issue.anchor)
452
- console.log(` Anchor: ${issue.anchor}`);
453
- if (issue.line)
454
- console.log(` Line: ${issue.line}`);
455
- if (issue.suggestion && options.verbose)
456
- console.log(` Suggestion: ${issue.suggestion}`);
457
- console.log();
458
- });
459
- }
460
- if (infos.length > 0 && options.verbose) {
461
- console.log(`\nℹ️ Info (${infos.length}):\n`);
462
- infos.forEach((issue, index) => {
463
- console.log(`${index + 1}. [${issue.rule}] ${issue.message}`);
464
- if (issue.anchor)
465
- console.log(` Anchor: ${issue.anchor}`);
466
- if (issue.line)
467
- console.log(` Line: ${issue.line}`);
468
- if (issue.suggestion)
469
- console.log(` Suggestion: ${issue.suggestion}`);
470
- console.log();
471
- });
472
- }
473
- // Summary
474
- console.log("Summary:");
475
- console.log(` Errors: ${errors.length}`);
476
- console.log(` Warnings: ${warnings.length}`);
477
- console.log(` Info: ${infos.length}`);
478
- if (fixSummary?.attempted) {
479
- console.log(` Fixes applied: ${fixSummary.fixesApplied}`);
480
- console.log(` File modified: ${fixSummary.fileModified ? "yes" : "no"}`);
481
- }
482
- console.log();
483
- // Exit with error code if there are errors
484
- if (errors.length > 0) {
485
- console.log("❌ Linting failed due to errors.\n");
486
- return 1;
487
- }
488
- else if (warnings.length > 0) {
489
- console.log("⚠️ Linting passed with warnings.\n");
490
- return 0;
491
- }
492
- else {
493
- console.log("✓ Linting passed.\n");
494
- return 0;
495
- }
496
- }
497
- if (require.main === module) {
498
- void (0, cli_runtime_1.runCliMain)(main, { errorPrefix: "spec-lint failed" });
499
- }
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * spec-parse CLI Tool
4
- *
5
- * Parse specification markdown and extract all valid anchors.
6
- *
7
- * Usage: npm run spec-parse <spec-file-path>
8
- * Example: npm run spec-parse specs/SPECIFICATION.md
9
- */
10
- declare function main(argv?: string[]): number;
11
- export { main };
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- /**
4
- * spec-parse CLI Tool
5
- *
6
- * Parse specification markdown and extract all valid anchors.
7
- *
8
- * Usage: npm run spec-parse <spec-file-path>
9
- * Example: npm run spec-parse specs/SPECIFICATION.md
10
- */
11
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- var desc = Object.getOwnPropertyDescriptor(m, k);
14
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
- desc = { enumerable: true, get: function() { return m[k]; } };
16
- }
17
- Object.defineProperty(o, k2, desc);
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || (function () {
28
- var ownKeys = function(o) {
29
- ownKeys = Object.getOwnPropertyNames || function (o) {
30
- var ar = [];
31
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
- return ar;
33
- };
34
- return ownKeys(o);
35
- };
36
- return function (mod) {
37
- if (mod && mod.__esModule) return mod;
38
- var result = {};
39
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
- __setModuleDefault(result, mod);
41
- return result;
42
- };
43
- })();
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.main = main;
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- const agents_1 = require("@spekn/agents");
49
- const cli_runtime_1 = require("../../utils/cli-runtime");
50
- function parseArgs(args) {
51
- const options = {};
52
- let filePath;
53
- for (let i = 0; i < args.length; i++) {
54
- const arg = args[i];
55
- if (arg === "--verbose" || arg === "-v") {
56
- options.verbose = true;
57
- }
58
- else if (arg === "--json" || arg === "-j") {
59
- options.json = true;
60
- }
61
- else if (!arg.startsWith("-")) {
62
- filePath = arg;
63
- }
64
- }
65
- if (!filePath) {
66
- throw new Error("missing required argument: <spec-file-path>");
67
- }
68
- return { filePath, options };
69
- }
70
- function printHelp() {
71
- console.log(`
72
- spec-parse - Parse specification markdown and extract anchors
73
-
74
- USAGE:
75
- npm run spec-parse <spec-file-path> [OPTIONS]
76
-
77
- ARGUMENTS:
78
- <spec-file-path> Path to the specification markdown file
79
-
80
- OPTIONS:
81
- -v, --verbose Show detailed output
82
- -j, --json Output in JSON format
83
- -h, --help Show this help message
84
-
85
- EXAMPLES:
86
- npm run spec-parse specs/SPECIFICATION.md
87
- npm run spec-parse specs/WORKFLOW.md --json
88
- npm run spec-parse specs/DECISIONS.md --verbose
89
- `);
90
- }
91
- function main(argv) {
92
- const args = argv ?? process.argv.slice(2);
93
- if ((0, cli_runtime_1.hasHelpFlag)(args)) {
94
- printHelp();
95
- return 0;
96
- }
97
- let filePath;
98
- let options;
99
- try {
100
- ({ filePath, options } = parseArgs(args));
101
- }
102
- catch {
103
- console.error("Error: Missing required argument <spec-file-path>");
104
- printHelp();
105
- return 1;
106
- }
107
- // Resolve file path
108
- const resolvedPath = path.resolve(process.cwd(), filePath);
109
- // Check if file exists
110
- if (!fs.existsSync(resolvedPath)) {
111
- console.error(`Error: File not found: ${resolvedPath}`);
112
- return 1;
113
- }
114
- // Read file content
115
- let content;
116
- try {
117
- content = fs.readFileSync(resolvedPath, "utf-8");
118
- }
119
- catch (error) {
120
- console.error(`Error reading file: ${(0, cli_runtime_1.errorMessage)(error)}`);
121
- return 1;
122
- }
123
- // Extract anchors
124
- const anchors = (0, agents_1.extractAnchors)(content);
125
- if (anchors.length === 0) {
126
- console.log("No anchors found in the specification.");
127
- return 0;
128
- }
129
- // Output results
130
- if (options.json) {
131
- console.log(JSON.stringify(anchors, null, 2));
132
- }
133
- else {
134
- console.log(`\nFound ${anchors.length} anchor(s) in ${path.basename(filePath)}:\n`);
135
- // Create table data
136
- const tableData = anchors.map((anchor) => ({
137
- Anchor: anchor.anchor,
138
- Level: "H" + anchor.level,
139
- Line: anchor.lineNumber,
140
- Heading: options.verbose
141
- ? anchor.headingText
142
- : anchor.headingText.substring(0, 60) +
143
- (anchor.headingText.length > 60 ? "..." : ""),
144
- }));
145
- // Print table
146
- console.table(tableData);
147
- if (options.verbose) {
148
- console.log("\nAnchor Details:");
149
- anchors.forEach((anchor, index) => {
150
- console.log(`\n${index + 1}. ${anchor.anchor}`);
151
- console.log(` Level: ${anchor.level}`);
152
- console.log(` Line: ${anchor.lineNumber}`);
153
- console.log(` Heading: ${anchor.headingText}`);
154
- });
155
- }
156
- console.log(`\nTotal: ${anchors.length} anchor(s)\n`);
157
- }
158
- return 0;
159
- }
160
- if (require.main === module) {
161
- void (0, cli_runtime_1.runCliMain)(main, { errorPrefix: "spec-parse failed" });
162
- }