specweave 0.30.12 → 0.30.14
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-plugin/marketplace.json +0 -11
- package/CLAUDE.md +1 -1
- package/bin/fix-marketplace-errors.sh +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +13 -0
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/ado-area-selector.d.ts.map +1 -1
- package/dist/src/cli/helpers/ado-area-selector.js +13 -0
- package/dist/src/cli/helpers/ado-area-selector.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 +7 -2
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts +7 -0
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js +33 -2
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js.map +1 -1
- package/dist/src/cli/workers/clone-worker.js +19 -3
- package/dist/src/cli/workers/clone-worker.js.map +1 -1
- package/dist/src/core/living-docs/board-matcher.d.ts +120 -0
- package/dist/src/core/living-docs/board-matcher.d.ts.map +1 -0
- package/dist/src/core/living-docs/board-matcher.js +466 -0
- package/dist/src/core/living-docs/board-matcher.js.map +1 -0
- package/dist/src/core/living-docs/foundation-builder.js +1 -1
- package/dist/src/core/living-docs/foundation-builder.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +19 -8
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +148 -52
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/suggestions-generator.js +1 -1
- package/dist/src/core/living-docs/suggestions-generator.js.map +1 -1
- package/dist/src/core/living-docs/umbrella-detector.d.ts +4 -0
- package/dist/src/core/living-docs/umbrella-detector.d.ts.map +1 -1
- package/dist/src/core/living-docs/umbrella-detector.js +20 -1
- package/dist/src/core/living-docs/umbrella-detector.js.map +1 -1
- package/dist/src/core/living-docs/workitem-matcher.js +5 -5
- package/dist/src/core/living-docs/workitem-matcher.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +4 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +4 -0
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/init/repo/types.d.ts +1 -1
- package/dist/src/living-docs/enterprise-analyzer.d.ts.map +1 -1
- package/dist/src/living-docs/enterprise-analyzer.js +70 -19
- package/dist/src/living-docs/enterprise-analyzer.js.map +1 -1
- package/dist/src/living-docs/epic-id-allocator.d.ts +4 -0
- package/dist/src/living-docs/epic-id-allocator.d.ts.map +1 -1
- package/dist/src/living-docs/epic-id-allocator.js +4 -0
- package/dist/src/living-docs/epic-id-allocator.js.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.d.ts +4 -0
- package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -1
- package/dist/src/living-docs/fs-id-allocator.js +4 -0
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -1
- package/dist/src/living-docs/smart-doc-organizer.d.ts +114 -0
- package/dist/src/living-docs/smart-doc-organizer.d.ts.map +1 -0
- package/dist/src/living-docs/smart-doc-organizer.js +535 -0
- package/dist/src/living-docs/smart-doc-organizer.js.map +1 -0
- package/package.json +13 -13
- package/plugins/PLUGINS-INDEX.md +2 -3
- package/plugins/specweave/commands/specweave-judge.md +265 -0
- package/plugins/specweave/commands/specweave-organize-docs.md +185 -0
- package/plugins/specweave/hooks/hooks.json +3 -3
- package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -0
- package/plugins/specweave/hooks/universal/hook-wrapper.sh +67 -0
- package/plugins/specweave-ado/commands/{specweave-ado-close-workitem.md → close.md} +9 -5
- package/plugins/specweave-ado/commands/{specweave-ado-create-workitem.md → create.md} +9 -5
- package/plugins/specweave-ado/commands/pull.md +459 -0
- package/plugins/specweave-ado/commands/push.md +361 -0
- package/plugins/specweave-ado/commands/{specweave-ado-status.md → status.md} +12 -0
- package/plugins/specweave-ado/commands/{specweave-ado-sync.md → sync.md} +64 -3
- package/plugins/specweave-ado/hooks/README.md +1 -1
- package/plugins/specweave-docs/commands/build.md +158 -0
- package/plugins/specweave-docs/commands/{docs-generate.md → generate.md} +10 -5
- package/plugins/specweave-docs/commands/health.md +268 -0
- package/plugins/specweave-docs/commands/{docs-init.md → init.md} +11 -6
- package/plugins/specweave-docs/commands/organize.md +184 -0
- package/plugins/specweave-docs/commands/preview.md +138 -0
- package/plugins/specweave-docs/skills/preview/SKILL.md +105 -0
- package/plugins/specweave-github/agents/user-story-updater/AGENT.md +1 -1
- package/plugins/specweave-github/commands/{specweave-github-close-issue.md → close.md} +2 -2
- package/plugins/specweave-github/commands/{specweave-github-create-issue.md → create.md} +2 -2
- package/plugins/specweave-github/commands/pull.md +142 -0
- package/plugins/specweave-github/commands/push.md +154 -0
- package/plugins/specweave-github/commands/{specweave-github-sync.md → sync.md} +19 -5
- package/plugins/specweave-github/commands/{specweave-github-update-user-story.md → update-user-story.md} +1 -1
- package/plugins/specweave-github/hooks/README.md +1 -1
- package/plugins/specweave-jira/commands/pull.md +164 -0
- package/plugins/specweave-jira/commands/push.md +170 -0
- package/plugins/specweave-jira/commands/{specweave-jira-sync.md → sync.md} +18 -3
- package/plugins/specweave-jira/hooks/README.md +1 -1
- package/plugins/specweave-kafka/README.md +20 -0
- package/plugins/specweave-kafka/benchmarks/kafka-throughput.benchmark.ts +551 -0
- package/plugins/specweave-kafka/examples/README.md +191 -0
- package/plugins/specweave-kafka/examples/avro-schema-registry/.env.example +8 -0
- package/plugins/specweave-kafka/examples/avro-schema-registry/README.md +69 -0
- package/plugins/specweave-kafka/examples/avro-schema-registry/consumer.js +37 -0
- package/plugins/specweave-kafka/examples/avro-schema-registry/package.json +14 -0
- package/plugins/specweave-kafka/examples/avro-schema-registry/producer.js +57 -0
- package/plugins/specweave-kafka/examples/exactly-once-semantics/.env.example +5 -0
- package/plugins/specweave-kafka/examples/exactly-once-semantics/README.md +30 -0
- package/plugins/specweave-kafka/examples/exactly-once-semantics/eos-pipeline.js +79 -0
- package/plugins/specweave-kafka/examples/exactly-once-semantics/package.json +11 -0
- package/plugins/specweave-kafka/examples/kafka-streams-app/.env.example +4 -0
- package/plugins/specweave-kafka/examples/kafka-streams-app/README.md +30 -0
- package/plugins/specweave-kafka/examples/kafka-streams-app/package.json +11 -0
- package/plugins/specweave-kafka/examples/kafka-streams-app/windowed-aggregation.js +66 -0
- package/plugins/specweave-kafka/examples/n8n-workflow/README.md +54 -0
- package/plugins/specweave-kafka/examples/n8n-workflow/docker-compose.yml +19 -0
- package/plugins/specweave-kafka/examples/n8n-workflow/kafka-to-slack.json +50 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/.env.example +15 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/README.md +183 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/consumer.js +60 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/docker-compose.yml +30 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/package.json +18 -0
- package/plugins/specweave-kafka/examples/simple-producer-consumer/producer.js +52 -0
- package/plugins/specweave-release/commands/specweave-release-npm.md +26 -239
- package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +0 -21
- package/plugins/specweave-docs-preview/commands/build.md +0 -489
- package/plugins/specweave-docs-preview/commands/preview.md +0 -355
- package/plugins/specweave-docs-preview/skills/docs-preview/SKILL.md +0 -386
- /package/plugins/specweave-ado/commands/{specweave-ado-clone-repos.md → clone.md} +0 -0
- /package/plugins/specweave-ado/commands/{specweave-ado-import-areas.md → import-areas.md} +0 -0
- /package/plugins/specweave-ado/commands/{specweave-ado-import-projects.md → import-projects.md} +0 -0
- /package/plugins/specweave-github/commands/{specweave-github-cleanup-duplicates.md → cleanup-duplicates.md} +0 -0
- /package/plugins/specweave-github/commands/{specweave-github-reconcile.md → reconcile.md} +0 -0
- /package/plugins/specweave-github/commands/{specweave-github-status.md → status.md} +0 -0
- /package/plugins/specweave-jira/commands/{specweave-jira-import-boards.md → import-boards.md} +0 -0
- /package/plugins/specweave-jira/commands/{specweave-jira-import-projects.md → import-projects-full.md} +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Documentation Organizer
|
|
3
|
+
*
|
|
4
|
+
* Intelligently organizes large documentation folders by:
|
|
5
|
+
* 1. Detecting themes from file content and titles
|
|
6
|
+
* 2. Generating themed category index files for navigation
|
|
7
|
+
* 3. Creating Docusaurus-compatible sidebar structures
|
|
8
|
+
* 4. Auto-organizing when folder exceeds threshold (default: 30 files)
|
|
9
|
+
*
|
|
10
|
+
* Philosophy: Generate indexes, don't move files (preserves URLs)
|
|
11
|
+
*/
|
|
12
|
+
import { Logger } from '../utils/logger.js';
|
|
13
|
+
export interface ThemeDefinition {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
keywords: string[];
|
|
17
|
+
icon: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ThemedFile {
|
|
20
|
+
path: string;
|
|
21
|
+
name: string;
|
|
22
|
+
title: string;
|
|
23
|
+
themes: string[];
|
|
24
|
+
primaryTheme: string;
|
|
25
|
+
lastModified: Date;
|
|
26
|
+
}
|
|
27
|
+
export interface ThemeCategory {
|
|
28
|
+
theme: ThemeDefinition;
|
|
29
|
+
files: ThemedFile[];
|
|
30
|
+
count: number;
|
|
31
|
+
}
|
|
32
|
+
export interface OrganizationPlan {
|
|
33
|
+
folder: string;
|
|
34
|
+
totalFiles: number;
|
|
35
|
+
themeCategories: ThemeCategory[];
|
|
36
|
+
uncategorized: ThemedFile[];
|
|
37
|
+
suggestedIndexes: string[];
|
|
38
|
+
needsOrganization: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface SmartDocOrganizerOptions {
|
|
41
|
+
projectPath: string;
|
|
42
|
+
logger?: Logger;
|
|
43
|
+
thresholdForOrganization?: number;
|
|
44
|
+
generateIndexes?: boolean;
|
|
45
|
+
dryRun?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Smart Documentation Organizer
|
|
49
|
+
*/
|
|
50
|
+
export declare class SmartDocOrganizer {
|
|
51
|
+
private projectPath;
|
|
52
|
+
private logger;
|
|
53
|
+
private threshold;
|
|
54
|
+
private generateIndexes;
|
|
55
|
+
private dryRun;
|
|
56
|
+
constructor(options: SmartDocOrganizerOptions);
|
|
57
|
+
/**
|
|
58
|
+
* Analyze a documentation folder and create organization plan
|
|
59
|
+
*/
|
|
60
|
+
analyzeFolder(folderPath: string): Promise<OrganizationPlan>;
|
|
61
|
+
/**
|
|
62
|
+
* Classify a file by detecting themes from content and filename
|
|
63
|
+
*/
|
|
64
|
+
private classifyFile;
|
|
65
|
+
/**
|
|
66
|
+
* Group files by their primary theme
|
|
67
|
+
*/
|
|
68
|
+
private groupByTheme;
|
|
69
|
+
/**
|
|
70
|
+
* Generate themed index files for Docusaurus navigation
|
|
71
|
+
*/
|
|
72
|
+
generateCategoryIndexes(plan: OrganizationPlan): Promise<string[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Generate main category index with links to themed indexes
|
|
75
|
+
*/
|
|
76
|
+
private generateMainCategoryIndex;
|
|
77
|
+
/**
|
|
78
|
+
* Generate themed index with all files in that category
|
|
79
|
+
*/
|
|
80
|
+
private generateThemeIndex;
|
|
81
|
+
/**
|
|
82
|
+
* Sub-group files by keyword for large categories
|
|
83
|
+
*/
|
|
84
|
+
private subGroupByKeyword;
|
|
85
|
+
/**
|
|
86
|
+
* Format string to title case, preserving known acronyms
|
|
87
|
+
*/
|
|
88
|
+
private formatTitle;
|
|
89
|
+
/**
|
|
90
|
+
* Update Docusaurus sidebar configuration
|
|
91
|
+
*/
|
|
92
|
+
updateDocusaurusSidebar(plans: OrganizationPlan[]): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Run full organization on internal docs
|
|
95
|
+
*/
|
|
96
|
+
organizeInternalDocs(): Promise<{
|
|
97
|
+
plans: OrganizationPlan[];
|
|
98
|
+
generatedFiles: string[];
|
|
99
|
+
summary: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Generate organization summary
|
|
103
|
+
*/
|
|
104
|
+
private generateSummary;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convenience function to organize docs
|
|
108
|
+
*/
|
|
109
|
+
export declare function organizeDocumentation(projectPath: string, options?: Partial<SmartDocOrganizerOptions>): Promise<{
|
|
110
|
+
plans: OrganizationPlan[];
|
|
111
|
+
generatedFiles: string[];
|
|
112
|
+
summary: string;
|
|
113
|
+
}>;
|
|
114
|
+
//# sourceMappingURL=smart-doc-organizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart-doc-organizer.d.ts","sourceRoot":"","sources":["../../../src/living-docs/smart-doc-organizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,MAAM,EAAiB,MAAM,oBAAoB,CAAC;AA8E3D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,MAAM,CAAU;gBAEZ,OAAO,EAAE,wBAAwB;IAQ7C;;OAEG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmDlE;;OAEG;YACW,YAAY;IAgE1B;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACG,uBAAuB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAqCxE;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA4DjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA6C1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACG,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA2CzE;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC;QACpC,KAAK,EAAE,gBAAgB,EAAE,CAAC;QAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IA2CF;;OAEG;IACH,OAAO,CAAC,eAAe;CAuCxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAC1C,OAAO,CAAC;IACT,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAOD"}
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Documentation Organizer
|
|
3
|
+
*
|
|
4
|
+
* Intelligently organizes large documentation folders by:
|
|
5
|
+
* 1. Detecting themes from file content and titles
|
|
6
|
+
* 2. Generating themed category index files for navigation
|
|
7
|
+
* 3. Creating Docusaurus-compatible sidebar structures
|
|
8
|
+
* 4. Auto-organizing when folder exceeds threshold (default: 30 files)
|
|
9
|
+
*
|
|
10
|
+
* Philosophy: Generate indexes, don't move files (preserves URLs)
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import { glob } from 'glob';
|
|
15
|
+
import { consoleLogger } from '../utils/logger.js';
|
|
16
|
+
// Theme definitions with keywords for detection
|
|
17
|
+
const THEME_DEFINITIONS = [
|
|
18
|
+
{
|
|
19
|
+
id: 'sync',
|
|
20
|
+
name: 'Synchronization & Integration',
|
|
21
|
+
keywords: ['sync', 'integration', 'bidirectional', 'import', 'export', 'pull', 'push'],
|
|
22
|
+
icon: '🔄',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'hooks',
|
|
26
|
+
name: 'Hooks & Events',
|
|
27
|
+
keywords: ['hook', 'event', 'trigger', 'callback', 'post-task', 'pre-tool', 'session'],
|
|
28
|
+
icon: '🪝',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'github',
|
|
32
|
+
name: 'GitHub Integration',
|
|
33
|
+
keywords: ['github', 'gh-', 'issue', 'pull-request', 'pr-', 'actions', 'workflow'],
|
|
34
|
+
icon: '🐙',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'external-tools',
|
|
38
|
+
name: 'External Tools (ADO, JIRA)',
|
|
39
|
+
keywords: ['jira', 'ado', 'azure-devops', 'external-tool', 'area-path', 'work-item', 'epic'],
|
|
40
|
+
icon: '🔌',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'testing',
|
|
44
|
+
name: 'Testing & Quality',
|
|
45
|
+
keywords: ['test', 'fixture', 'mock', 'coverage', 'tdd', 'isolation', 'assertion', 'qa'],
|
|
46
|
+
icon: '🧪',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'brownfield',
|
|
50
|
+
name: 'Brownfield & Migration',
|
|
51
|
+
keywords: ['brownfield', 'migration', 'legacy', 'onboard', 'existing', 'import'],
|
|
52
|
+
icon: '🏗️',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'architecture',
|
|
56
|
+
name: 'Core Architecture',
|
|
57
|
+
keywords: ['pattern', 'factory', 'abstraction', 'layer', 'modular', 'structure', 'design'],
|
|
58
|
+
icon: '🏛️',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'performance',
|
|
62
|
+
name: 'Performance & Optimization',
|
|
63
|
+
keywords: ['cache', 'performance', 'optimization', 'pagination', 'batch', 'lazy', 'ttl'],
|
|
64
|
+
icon: '⚡',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'security',
|
|
68
|
+
name: 'Security & Permissions',
|
|
69
|
+
keywords: ['permission', 'security', 'gate', 'auth', 'token', 'secret', 'credential'],
|
|
70
|
+
icon: '🔒',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'increments',
|
|
74
|
+
name: 'Increment Lifecycle',
|
|
75
|
+
keywords: ['increment', 'status', 'lifecycle', 'backlog', 'phase', 'workflow', 'completion'],
|
|
76
|
+
icon: '📦',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'config',
|
|
80
|
+
name: 'Configuration & Setup',
|
|
81
|
+
keywords: ['config', 'env', 'setup', 'init', 'setting', 'option', 'parameter'],
|
|
82
|
+
icon: '⚙️',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'docs',
|
|
86
|
+
name: 'Documentation & Living Docs',
|
|
87
|
+
keywords: ['doc', 'living', 'spec', 'readme', 'naming', 'convention', 'folder'],
|
|
88
|
+
icon: '📚',
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Smart Documentation Organizer
|
|
93
|
+
*/
|
|
94
|
+
export class SmartDocOrganizer {
|
|
95
|
+
constructor(options) {
|
|
96
|
+
this.projectPath = options.projectPath;
|
|
97
|
+
this.logger = options.logger ?? consoleLogger;
|
|
98
|
+
this.threshold = options.thresholdForOrganization ?? 30;
|
|
99
|
+
this.generateIndexes = options.generateIndexes ?? true;
|
|
100
|
+
this.dryRun = options.dryRun ?? false;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Analyze a documentation folder and create organization plan
|
|
104
|
+
*/
|
|
105
|
+
async analyzeFolder(folderPath) {
|
|
106
|
+
const absolutePath = path.isAbsolute(folderPath)
|
|
107
|
+
? folderPath
|
|
108
|
+
: path.join(this.projectPath, folderPath);
|
|
109
|
+
if (!fs.existsSync(absolutePath)) {
|
|
110
|
+
throw new Error(`Folder not found: ${absolutePath}`);
|
|
111
|
+
}
|
|
112
|
+
// Get all markdown files (exclude index files we generate)
|
|
113
|
+
const files = await glob('*.md', {
|
|
114
|
+
cwd: absolutePath,
|
|
115
|
+
nodir: true,
|
|
116
|
+
ignore: ['README.md', '_index-*.md', 'category-*.md'],
|
|
117
|
+
});
|
|
118
|
+
this.logger.info(`Analyzing ${files.length} files in ${folderPath}`);
|
|
119
|
+
// Classify each file by theme
|
|
120
|
+
const themedFiles = [];
|
|
121
|
+
for (const file of files) {
|
|
122
|
+
const fullPath = path.join(absolutePath, file);
|
|
123
|
+
const themed = await this.classifyFile(fullPath);
|
|
124
|
+
themedFiles.push(themed);
|
|
125
|
+
}
|
|
126
|
+
// Group by theme
|
|
127
|
+
const themeCategories = this.groupByTheme(themedFiles);
|
|
128
|
+
// Identify uncategorized files
|
|
129
|
+
const uncategorized = themedFiles.filter(f => f.primaryTheme === 'uncategorized');
|
|
130
|
+
// Determine if organization is needed
|
|
131
|
+
const needsOrganization = files.length > this.threshold;
|
|
132
|
+
// Generate suggested indexes
|
|
133
|
+
const suggestedIndexes = themeCategories
|
|
134
|
+
.filter(tc => tc.count >= 3) // Only suggest for themes with 3+ files
|
|
135
|
+
.map(tc => `_index-${tc.theme.id}.md`);
|
|
136
|
+
return {
|
|
137
|
+
folder: folderPath,
|
|
138
|
+
totalFiles: files.length,
|
|
139
|
+
themeCategories,
|
|
140
|
+
uncategorized,
|
|
141
|
+
suggestedIndexes,
|
|
142
|
+
needsOrganization,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Classify a file by detecting themes from content and filename
|
|
147
|
+
*/
|
|
148
|
+
async classifyFile(filePath) {
|
|
149
|
+
const fileName = path.basename(filePath, '.md');
|
|
150
|
+
const stats = fs.statSync(filePath);
|
|
151
|
+
let content = '';
|
|
152
|
+
let title = fileName;
|
|
153
|
+
try {
|
|
154
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
155
|
+
// Extract title from first heading
|
|
156
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
157
|
+
if (titleMatch) {
|
|
158
|
+
title = titleMatch[1].replace(/^ADR-\d+:\s*/, ''); // Remove ADR prefix
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Skip files that can't be read
|
|
163
|
+
}
|
|
164
|
+
// Combine filename and content for theme detection
|
|
165
|
+
const searchText = `${fileName} ${title} ${content}`.toLowerCase();
|
|
166
|
+
// Score each theme
|
|
167
|
+
const themeScores = [];
|
|
168
|
+
for (const theme of THEME_DEFINITIONS) {
|
|
169
|
+
let score = 0;
|
|
170
|
+
for (const keyword of theme.keywords) {
|
|
171
|
+
// Count keyword occurrences
|
|
172
|
+
const regex = new RegExp(keyword, 'gi');
|
|
173
|
+
const matches = searchText.match(regex);
|
|
174
|
+
if (matches) {
|
|
175
|
+
score += matches.length;
|
|
176
|
+
// Boost score if keyword in filename
|
|
177
|
+
if (fileName.toLowerCase().includes(keyword)) {
|
|
178
|
+
score += 5;
|
|
179
|
+
}
|
|
180
|
+
// Boost score if keyword in title
|
|
181
|
+
if (title.toLowerCase().includes(keyword)) {
|
|
182
|
+
score += 3;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (score > 0) {
|
|
187
|
+
themeScores.push({ theme, score });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Sort by score descending
|
|
191
|
+
themeScores.sort((a, b) => b.score - a.score);
|
|
192
|
+
// Get primary theme and all matching themes
|
|
193
|
+
const themes = themeScores.slice(0, 3).map(ts => ts.theme.id);
|
|
194
|
+
const primaryTheme = themes[0] ?? 'uncategorized';
|
|
195
|
+
return {
|
|
196
|
+
path: filePath,
|
|
197
|
+
name: fileName,
|
|
198
|
+
title,
|
|
199
|
+
themes,
|
|
200
|
+
primaryTheme,
|
|
201
|
+
lastModified: stats.mtime,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Group files by their primary theme
|
|
206
|
+
*/
|
|
207
|
+
groupByTheme(files) {
|
|
208
|
+
const themeMap = new Map();
|
|
209
|
+
for (const file of files) {
|
|
210
|
+
const theme = file.primaryTheme;
|
|
211
|
+
if (!themeMap.has(theme)) {
|
|
212
|
+
themeMap.set(theme, []);
|
|
213
|
+
}
|
|
214
|
+
themeMap.get(theme).push(file);
|
|
215
|
+
}
|
|
216
|
+
const categories = [];
|
|
217
|
+
for (const [themeId, themeFiles] of themeMap) {
|
|
218
|
+
if (themeId === 'uncategorized')
|
|
219
|
+
continue;
|
|
220
|
+
const themeDef = THEME_DEFINITIONS.find(t => t.id === themeId);
|
|
221
|
+
if (themeDef) {
|
|
222
|
+
categories.push({
|
|
223
|
+
theme: themeDef,
|
|
224
|
+
files: themeFiles.sort((a, b) => a.name.localeCompare(b.name)),
|
|
225
|
+
count: themeFiles.length,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Sort by count descending
|
|
230
|
+
return categories.sort((a, b) => b.count - a.count);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Generate themed index files for Docusaurus navigation
|
|
234
|
+
*/
|
|
235
|
+
async generateCategoryIndexes(plan) {
|
|
236
|
+
if (!plan.needsOrganization && !this.generateIndexes) {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
const generatedFiles = [];
|
|
240
|
+
const folderPath = path.isAbsolute(plan.folder)
|
|
241
|
+
? plan.folder
|
|
242
|
+
: path.join(this.projectPath, plan.folder);
|
|
243
|
+
// Generate main category index
|
|
244
|
+
const mainIndexPath = path.join(folderPath, '_categories.md');
|
|
245
|
+
const mainIndexContent = this.generateMainCategoryIndex(plan);
|
|
246
|
+
if (!this.dryRun) {
|
|
247
|
+
fs.writeFileSync(mainIndexPath, mainIndexContent);
|
|
248
|
+
this.logger.info(`Generated: ${mainIndexPath}`);
|
|
249
|
+
}
|
|
250
|
+
generatedFiles.push(mainIndexPath);
|
|
251
|
+
// Generate individual theme indexes
|
|
252
|
+
for (const category of plan.themeCategories) {
|
|
253
|
+
if (category.count < 3)
|
|
254
|
+
continue; // Skip themes with too few files
|
|
255
|
+
const indexPath = path.join(folderPath, `_index-${category.theme.id}.md`);
|
|
256
|
+
const indexContent = this.generateThemeIndex(category, plan.folder);
|
|
257
|
+
if (!this.dryRun) {
|
|
258
|
+
fs.writeFileSync(indexPath, indexContent);
|
|
259
|
+
this.logger.info(`Generated: ${indexPath}`);
|
|
260
|
+
}
|
|
261
|
+
generatedFiles.push(indexPath);
|
|
262
|
+
}
|
|
263
|
+
return generatedFiles;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Generate main category index with links to themed indexes
|
|
267
|
+
*/
|
|
268
|
+
generateMainCategoryIndex(plan) {
|
|
269
|
+
const lines = [];
|
|
270
|
+
const folderName = path.basename(plan.folder);
|
|
271
|
+
lines.push('---');
|
|
272
|
+
lines.push('sidebar_position: 1');
|
|
273
|
+
lines.push(`title: "${this.formatTitle(folderName)} by Category"`);
|
|
274
|
+
lines.push('---');
|
|
275
|
+
lines.push('');
|
|
276
|
+
lines.push(`# ${this.formatTitle(folderName)} by Category`);
|
|
277
|
+
lines.push('');
|
|
278
|
+
lines.push(`This folder contains **${plan.totalFiles}** documents organized into the following categories:`);
|
|
279
|
+
lines.push('');
|
|
280
|
+
// Category table
|
|
281
|
+
lines.push('| Category | Count | Description |');
|
|
282
|
+
lines.push('|----------|-------|-------------|');
|
|
283
|
+
for (const category of plan.themeCategories) {
|
|
284
|
+
if (category.count < 3)
|
|
285
|
+
continue;
|
|
286
|
+
const link = `[${category.theme.icon} ${category.theme.name}](./_index-${category.theme.id}.md)`;
|
|
287
|
+
lines.push(`| ${link} | ${category.count} | View all ${category.theme.name.toLowerCase()} documents |`);
|
|
288
|
+
}
|
|
289
|
+
// Uncategorized section
|
|
290
|
+
if (plan.uncategorized.length > 0) {
|
|
291
|
+
lines.push(`| 📄 Other | ${plan.uncategorized.length} | Documents not matching specific themes |`);
|
|
292
|
+
}
|
|
293
|
+
lines.push('');
|
|
294
|
+
lines.push('## Quick Stats');
|
|
295
|
+
lines.push('');
|
|
296
|
+
lines.push(`- **Total Documents**: ${plan.totalFiles}`);
|
|
297
|
+
lines.push(`- **Categorized**: ${plan.totalFiles - plan.uncategorized.length}`);
|
|
298
|
+
lines.push(`- **Categories**: ${plan.themeCategories.filter(c => c.count >= 3).length}`);
|
|
299
|
+
lines.push('');
|
|
300
|
+
// Recent documents
|
|
301
|
+
const allFiles = plan.themeCategories.flatMap(c => c.files);
|
|
302
|
+
const recent = allFiles
|
|
303
|
+
.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime())
|
|
304
|
+
.slice(0, 5);
|
|
305
|
+
if (recent.length > 0) {
|
|
306
|
+
lines.push('## Recently Updated');
|
|
307
|
+
lines.push('');
|
|
308
|
+
for (const file of recent) {
|
|
309
|
+
const themeDef = THEME_DEFINITIONS.find(t => t.id === file.primaryTheme);
|
|
310
|
+
const icon = themeDef?.icon ?? '📄';
|
|
311
|
+
lines.push(`- ${icon} [${file.title}](./${file.name}.md) - ${file.lastModified.toLocaleDateString()}`);
|
|
312
|
+
}
|
|
313
|
+
lines.push('');
|
|
314
|
+
}
|
|
315
|
+
lines.push('---');
|
|
316
|
+
lines.push('*Auto-generated by SmartDocOrganizer*');
|
|
317
|
+
return lines.join('\n');
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Generate themed index with all files in that category
|
|
321
|
+
*/
|
|
322
|
+
generateThemeIndex(category, folderPath) {
|
|
323
|
+
const lines = [];
|
|
324
|
+
lines.push('---');
|
|
325
|
+
lines.push('sidebar_position: 2');
|
|
326
|
+
lines.push(`title: "${category.theme.icon} ${category.theme.name}"`);
|
|
327
|
+
lines.push('---');
|
|
328
|
+
lines.push('');
|
|
329
|
+
lines.push(`# ${category.theme.icon} ${category.theme.name}`);
|
|
330
|
+
lines.push('');
|
|
331
|
+
lines.push(`**${category.count}** documents in this category.`);
|
|
332
|
+
lines.push('');
|
|
333
|
+
// Group by sub-theme if many files
|
|
334
|
+
if (category.count > 15) {
|
|
335
|
+
// Further sub-group by first keyword match
|
|
336
|
+
const subGroups = this.subGroupByKeyword(category.files, category.theme);
|
|
337
|
+
for (const [subGroup, files] of subGroups) {
|
|
338
|
+
if (files.length > 0) {
|
|
339
|
+
lines.push(`## ${subGroup}`);
|
|
340
|
+
lines.push('');
|
|
341
|
+
for (const file of files) {
|
|
342
|
+
lines.push(`- [${file.title}](./${file.name}.md)`);
|
|
343
|
+
}
|
|
344
|
+
lines.push('');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
// Simple list
|
|
350
|
+
lines.push('## Documents');
|
|
351
|
+
lines.push('');
|
|
352
|
+
for (const file of category.files) {
|
|
353
|
+
const date = file.lastModified.toLocaleDateString();
|
|
354
|
+
lines.push(`- [${file.title}](./${file.name}.md) *(${date})*`);
|
|
355
|
+
}
|
|
356
|
+
lines.push('');
|
|
357
|
+
}
|
|
358
|
+
lines.push('---');
|
|
359
|
+
lines.push(`[← Back to Categories](./_categories.md)`);
|
|
360
|
+
return lines.join('\n');
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Sub-group files by keyword for large categories
|
|
364
|
+
*/
|
|
365
|
+
subGroupByKeyword(files, theme) {
|
|
366
|
+
const groups = new Map();
|
|
367
|
+
// Initialize groups for main keywords
|
|
368
|
+
const mainKeywords = theme.keywords.slice(0, 4);
|
|
369
|
+
for (const kw of mainKeywords) {
|
|
370
|
+
groups.set(this.formatTitle(kw), []);
|
|
371
|
+
}
|
|
372
|
+
groups.set('Other', []);
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
const content = `${file.name} ${file.title}`.toLowerCase();
|
|
375
|
+
let assigned = false;
|
|
376
|
+
for (const kw of mainKeywords) {
|
|
377
|
+
if (content.includes(kw)) {
|
|
378
|
+
groups.get(this.formatTitle(kw)).push(file);
|
|
379
|
+
assigned = true;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (!assigned) {
|
|
384
|
+
groups.get('Other').push(file);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Remove empty groups
|
|
388
|
+
for (const [key, value] of groups) {
|
|
389
|
+
if (value.length === 0) {
|
|
390
|
+
groups.delete(key);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return groups;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Format string to title case, preserving known acronyms
|
|
397
|
+
*/
|
|
398
|
+
formatTitle(str) {
|
|
399
|
+
const acronyms = ['adr', 'api', 'cli', 'hld', 'tdd', 'ado', 'pr', 'ci', 'cd', 'url', 'jwt', 'iac', 'sla', 'slo'];
|
|
400
|
+
return str
|
|
401
|
+
.replace(/[-_]/g, ' ')
|
|
402
|
+
.split(' ')
|
|
403
|
+
.map(word => {
|
|
404
|
+
const lower = word.toLowerCase();
|
|
405
|
+
if (acronyms.includes(lower)) {
|
|
406
|
+
return word.toUpperCase();
|
|
407
|
+
}
|
|
408
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
409
|
+
})
|
|
410
|
+
.join(' ');
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Update Docusaurus sidebar configuration
|
|
414
|
+
*/
|
|
415
|
+
async updateDocusaurusSidebar(plans) {
|
|
416
|
+
const sidebarConfig = [];
|
|
417
|
+
for (const plan of plans) {
|
|
418
|
+
if (!plan.needsOrganization)
|
|
419
|
+
continue;
|
|
420
|
+
const folderName = path.basename(plan.folder);
|
|
421
|
+
const categoryItems = [];
|
|
422
|
+
// Add main categories index first
|
|
423
|
+
categoryItems.push({
|
|
424
|
+
type: 'doc',
|
|
425
|
+
id: `${folderName}/_categories`,
|
|
426
|
+
label: '📚 Browse by Category',
|
|
427
|
+
});
|
|
428
|
+
// Add theme-specific indexes
|
|
429
|
+
for (const category of plan.themeCategories) {
|
|
430
|
+
if (category.count < 3)
|
|
431
|
+
continue;
|
|
432
|
+
categoryItems.push({
|
|
433
|
+
type: 'doc',
|
|
434
|
+
id: `${folderName}/_index-${category.theme.id}`,
|
|
435
|
+
label: `${category.theme.icon} ${category.theme.name}`,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
// Add auto-generated items
|
|
439
|
+
categoryItems.push({
|
|
440
|
+
type: 'autogenerated',
|
|
441
|
+
dirName: folderName,
|
|
442
|
+
});
|
|
443
|
+
sidebarConfig.push({
|
|
444
|
+
type: 'category',
|
|
445
|
+
label: this.formatTitle(folderName),
|
|
446
|
+
items: categoryItems,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return JSON.stringify(sidebarConfig, null, 2);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Run full organization on internal docs
|
|
453
|
+
*/
|
|
454
|
+
async organizeInternalDocs() {
|
|
455
|
+
const internalDocsPath = path.join(this.projectPath, '.specweave/docs/internal');
|
|
456
|
+
if (!fs.existsSync(internalDocsPath)) {
|
|
457
|
+
throw new Error('No .specweave/docs/internal directory found');
|
|
458
|
+
}
|
|
459
|
+
const plans = [];
|
|
460
|
+
const generatedFiles = [];
|
|
461
|
+
// Analyze key folders that might need organization
|
|
462
|
+
const foldersToAnalyze = [
|
|
463
|
+
'architecture/adr',
|
|
464
|
+
'architecture/hld',
|
|
465
|
+
'architecture/concepts',
|
|
466
|
+
'delivery/guides',
|
|
467
|
+
'operations',
|
|
468
|
+
'governance',
|
|
469
|
+
];
|
|
470
|
+
for (const folder of foldersToAnalyze) {
|
|
471
|
+
const fullPath = path.join(internalDocsPath, folder);
|
|
472
|
+
if (!fs.existsSync(fullPath))
|
|
473
|
+
continue;
|
|
474
|
+
try {
|
|
475
|
+
const plan = await this.analyzeFolder(fullPath);
|
|
476
|
+
plans.push(plan);
|
|
477
|
+
if (plan.needsOrganization) {
|
|
478
|
+
const files = await this.generateCategoryIndexes(plan);
|
|
479
|
+
generatedFiles.push(...files);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch (err) {
|
|
483
|
+
this.logger.warn(`Failed to analyze ${folder}: ${err}`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
// Generate summary
|
|
487
|
+
const summary = this.generateSummary(plans, generatedFiles);
|
|
488
|
+
return { plans, generatedFiles, summary };
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Generate organization summary
|
|
492
|
+
*/
|
|
493
|
+
generateSummary(plans, generatedFiles) {
|
|
494
|
+
const lines = [];
|
|
495
|
+
lines.push('# Documentation Organization Summary');
|
|
496
|
+
lines.push('');
|
|
497
|
+
const needsOrg = plans.filter(p => p.needsOrganization);
|
|
498
|
+
const totalFiles = plans.reduce((sum, p) => sum + p.totalFiles, 0);
|
|
499
|
+
lines.push(`- **Folders Analyzed**: ${plans.length}`);
|
|
500
|
+
lines.push(`- **Total Documents**: ${totalFiles}`);
|
|
501
|
+
lines.push(`- **Folders Needing Organization**: ${needsOrg.length}`);
|
|
502
|
+
lines.push(`- **Index Files Generated**: ${generatedFiles.length}`);
|
|
503
|
+
lines.push('');
|
|
504
|
+
if (needsOrg.length > 0) {
|
|
505
|
+
lines.push('## Organized Folders');
|
|
506
|
+
lines.push('');
|
|
507
|
+
for (const plan of needsOrg) {
|
|
508
|
+
lines.push(`### ${plan.folder}`);
|
|
509
|
+
lines.push(`- Files: ${plan.totalFiles}`);
|
|
510
|
+
lines.push(`- Categories: ${plan.themeCategories.filter(c => c.count >= 3).length}`);
|
|
511
|
+
lines.push('- Top themes:');
|
|
512
|
+
for (const cat of plan.themeCategories.slice(0, 5)) {
|
|
513
|
+
lines.push(` - ${cat.theme.icon} ${cat.theme.name}: ${cat.count} files`);
|
|
514
|
+
}
|
|
515
|
+
lines.push('');
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
lines.push('## Next Steps');
|
|
519
|
+
lines.push('');
|
|
520
|
+
lines.push('Run `/specweave-docs:preview` to view the organized documentation.');
|
|
521
|
+
lines.push('');
|
|
522
|
+
return lines.join('\n');
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Convenience function to organize docs
|
|
527
|
+
*/
|
|
528
|
+
export async function organizeDocumentation(projectPath, options) {
|
|
529
|
+
const organizer = new SmartDocOrganizer({
|
|
530
|
+
projectPath,
|
|
531
|
+
...options,
|
|
532
|
+
});
|
|
533
|
+
return organizer.organizeInternalDocs();
|
|
534
|
+
}
|
|
535
|
+
//# sourceMappingURL=smart-doc-organizer.js.map
|