@aigne/doc-smith 0.9.10 → 0.9.11-beta
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/CHANGELOG.md +12 -0
- package/README.md +189 -219
- package/README.zh.md +270 -0
- package/agents/bash-executor/index.mjs +347 -0
- package/agents/clear/ai/intent.md +142 -0
- package/agents/clear/choose-contents.mjs +13 -65
- package/agents/clear/clear-auth-tokens.mjs +17 -21
- package/agents/clear/clear-deployment-config.mjs +33 -24
- package/agents/clear/index.yaml +1 -9
- package/agents/content-checker/ai/intent.md +209 -0
- package/agents/content-checker/clean-invalid-docs.mjs +254 -0
- package/agents/content-checker/index.mjs +191 -0
- package/agents/content-checker/validate-content.mjs +983 -0
- package/agents/generate-images/generate-image.yaml +75 -0
- package/agents/generate-images/generate-summary.mjs +213 -0
- package/agents/generate-images/index.yaml +39 -0
- package/agents/generate-images/prepare-generation.mjs +286 -0
- package/agents/generate-images/prepare-image-generation.mjs +130 -0
- package/{prompts/detail/diagram/generate-image-system.md → agents/generate-images/prompts/system.md} +22 -56
- package/agents/generate-images/prompts/user.md +85 -0
- package/agents/generate-images/save-image-result.mjs +247 -0
- package/agents/generate-images/scan-image-slots.mjs +247 -0
- package/agents/localize/index.yaml +19 -42
- package/{prompts/translate → agents/localize/prompts}/translate-document.md +0 -139
- package/agents/localize/translate-documents/generate-summary.mjs +163 -0
- package/agents/localize/translate-documents/load-glossary.mjs +52 -0
- package/agents/localize/translate-documents/prepare-translation.mjs +249 -0
- package/agents/localize/translate-documents/save-translation.mjs +171 -0
- package/agents/localize/translate-documents/translate-document-to-language.mjs +209 -0
- package/agents/localize/translate-documents/translate-document.yaml +23 -0
- package/agents/localize/translate-documents/translate-to-languages.yaml +10 -0
- package/agents/localize/translate-images/check-image-translation.mjs +225 -0
- package/agents/localize/translate-images/detect-text/detect-and-update-shared.mjs +148 -0
- package/agents/localize/translate-images/detect-text/detect-image-text.yaml +44 -0
- package/agents/localize/translate-images/detect-text/detect-images-text.yaml +21 -0
- package/agents/localize/translate-images/detect-text/prompts/detect-image-text-system.md +43 -0
- package/agents/localize/translate-images/detect-text/prompts/detect-image-text-user.md +14 -0
- package/agents/localize/translate-images/detect-text/save-text-detection.mjs +105 -0
- package/agents/localize/translate-images/prepare-image-input.mjs +124 -0
- package/agents/localize/translate-images/save-image-translation.mjs +172 -0
- package/agents/localize/translate-images/scan-doc-images.mjs +165 -0
- package/agents/localize/translate-images/translate-doc-images.yaml +24 -0
- package/agents/localize/{translate-diagram.yaml → translate-images/translate-image.yaml} +25 -14
- package/agents/publish/ai/intent.md +182 -0
- package/agents/publish/check.mjs +107 -0
- package/agents/publish/index.yaml +9 -14
- package/agents/publish/publish-docs.mjs +81 -61
- package/agents/publish/translate-meta.mjs +79 -58
- package/agents/save-document/index.mjs +260 -0
- package/agents/structure-checker/index.mjs +307 -0
- package/agents/structure-checker/validate-structure.mjs +477 -0
- package/agents/update-image/analyze-feedback.yaml +37 -0
- package/agents/update-image/index.yaml +78 -0
- package/agents/update-image/load-existing-image.mjs +211 -0
- package/agents/update-image/prompts/analyze-feedback-system.md +43 -0
- package/agents/update-image/prompts/analyze-feedback-user.md +15 -0
- package/aigne.yaml +26 -139
- package/package.json +16 -48
- package/scripts/README.md +90 -0
- package/scripts/install.sh +86 -0
- package/scripts/uninstall.sh +52 -0
- package/skills/doc-smith/SKILL.md +285 -0
- package/skills/doc-smith/ai/intent/sources-improve.md +290 -0
- package/skills/doc-smith/references/changeset-guide.md +171 -0
- package/skills/doc-smith/references/document-content-guide.md +214 -0
- package/skills/doc-smith/references/document-structure-schema.md +138 -0
- package/skills/doc-smith/references/patch-guide.md +96 -0
- package/skills/doc-smith/references/structure-confirmation-guide.md +133 -0
- package/skills/doc-smith/references/structure-planning-guide.md +149 -0
- package/skills/doc-smith/references/update-workflow.md +108 -0
- package/skills/doc-smith/references/user-intent-guide.md +175 -0
- package/skills/doc-smith/references/workspace-initialization.md +376 -0
- package/skills/doc-smith-docs-detail/SKILL.md +356 -0
- package/skills/doc-smith-docs-detail/ai/intent.md +271 -0
- package/skills-entry/doc-smith/ai/intent.md +260 -0
- package/skills-entry/doc-smith/index.mjs +66 -0
- package/skills-entry/doc-smith/prompt.md +57 -0
- package/skills-entry/doc-smith/utils.mjs +27 -0
- package/skills-entry/doc-smith-docs-detail/batch.yaml +56 -0
- package/skills-entry/doc-smith-docs-detail/index.mjs +95 -0
- package/skills-entry/doc-smith-docs-detail/prompt.md +64 -0
- package/utils/afs-factory.mjs +183 -0
- package/utils/agent-constants.mjs +97 -0
- package/utils/{auth-utils.mjs → auth.mjs} +6 -9
- package/{agents/utils/update-branding.mjs → utils/branding.mjs} +3 -4
- package/utils/config.mjs +261 -0
- package/utils/constants.mjs +32 -0
- package/utils/deploy.mjs +3 -3
- package/utils/docs-converter.mjs +454 -0
- package/utils/docs.mjs +212 -0
- package/utils/document-paths.mjs +172 -0
- package/utils/files.mjs +74 -0
- package/utils/git.mjs +65 -0
- package/utils/{blocklet.mjs → http.mjs} +18 -0
- package/utils/image-slots.mjs +57 -0
- package/utils/image-utils.mjs +114 -0
- package/utils/project.mjs +95 -0
- package/utils/sources-path-resolver.mjs +76 -0
- package/utils/{upload-files.mjs → upload.mjs} +3 -3
- package/utils/workspace.mjs +371 -0
- package/agents/chat/chat-system.md +0 -38
- package/agents/chat/index.mjs +0 -59
- package/agents/chat/skills/generate-document.yaml +0 -15
- package/agents/chat/skills/list-documents.mjs +0 -15
- package/agents/chat/skills/update-document.yaml +0 -24
- package/agents/clear/clear-document-config.mjs +0 -36
- package/agents/clear/clear-document-structure.mjs +0 -102
- package/agents/clear/clear-generated-docs.mjs +0 -142
- package/agents/clear/clear-media-description.mjs +0 -129
- package/agents/create/aggregate-document-structure.mjs +0 -21
- package/agents/create/analyze-diagram-type-llm.yaml +0 -159
- package/agents/create/analyze-diagram-type.mjs +0 -455
- package/agents/create/check-document-structure.yaml +0 -30
- package/agents/create/check-need-generate-structure.mjs +0 -138
- package/agents/create/document-structure-tools/add-document.mjs +0 -85
- package/agents/create/document-structure-tools/delete-document.mjs +0 -116
- package/agents/create/document-structure-tools/move-document.mjs +0 -109
- package/agents/create/document-structure-tools/update-document.mjs +0 -84
- package/agents/create/generate-diagram-image.yaml +0 -91
- package/agents/create/generate-structure.yaml +0 -106
- package/agents/create/index.yaml +0 -45
- package/agents/create/refine-document-structure.yaml +0 -12
- package/agents/create/replace-d2-with-image.mjs +0 -610
- package/agents/create/update-document-structure.yaml +0 -54
- package/agents/create/user-add-document/add-documents-to-structure.mjs +0 -90
- package/agents/create/user-add-document/find-documents-to-add-links.yaml +0 -47
- package/agents/create/user-add-document/index.yaml +0 -46
- package/agents/create/user-add-document/prepare-documents-to-translate.mjs +0 -22
- package/agents/create/user-add-document/print-add-document-summary.mjs +0 -63
- package/agents/create/user-add-document/review-documents-with-new-links.mjs +0 -110
- package/agents/create/user-remove-document/find-documents-with-invalid-links.mjs +0 -78
- package/agents/create/user-remove-document/index.yaml +0 -40
- package/agents/create/user-remove-document/prepare-documents-to-translate.mjs +0 -22
- package/agents/create/user-remove-document/print-remove-document-summary.mjs +0 -53
- package/agents/create/user-remove-document/remove-documents-from-structure.mjs +0 -99
- package/agents/create/user-remove-document/review-documents-with-invalid-links.mjs +0 -115
- package/agents/create/user-review-document-structure.mjs +0 -139
- package/agents/create/utils/init-current-content.mjs +0 -34
- package/agents/create/utils/merge-document-structures.mjs +0 -36
- package/agents/evaluate/code-snippet.mjs +0 -97
- package/agents/evaluate/document-structure.yaml +0 -67
- package/agents/evaluate/document.yaml +0 -82
- package/agents/evaluate/generate-report.mjs +0 -85
- package/agents/evaluate/index.yaml +0 -46
- package/agents/history/index.yaml +0 -6
- package/agents/history/view.mjs +0 -78
- package/agents/init/check.mjs +0 -16
- package/agents/init/index.mjs +0 -643
- package/agents/init/validate.mjs +0 -16
- package/agents/localize/choose-language.mjs +0 -107
- package/agents/localize/record-translation-history.mjs +0 -23
- package/agents/localize/save-doc-translation-or-skip.mjs +0 -18
- package/agents/localize/set-review-content.mjs +0 -58
- package/agents/localize/translate-document-wrapper.mjs +0 -34
- package/agents/localize/translate-document.yaml +0 -24
- package/agents/localize/translate-multilingual.yaml +0 -57
- package/agents/localize/translate-or-skip-diagram.mjs +0 -52
- package/agents/media/batch-generate-media-description.yaml +0 -46
- package/agents/media/generate-media-description.yaml +0 -50
- package/agents/media/load-media-description.mjs +0 -454
- package/agents/prefs/index.mjs +0 -203
- package/agents/schema/document-structure-item.yaml +0 -26
- package/agents/schema/document-structure-refine-item.yaml +0 -23
- package/agents/schema/document-structure.yaml +0 -29
- package/agents/update/batch-generate-document.yaml +0 -27
- package/agents/update/batch-update-document.yaml +0 -7
- package/agents/update/check-diagram-flag.mjs +0 -116
- package/agents/update/check-document.mjs +0 -162
- package/agents/update/check-generate-diagram.mjs +0 -106
- package/agents/update/check-update-is-single.mjs +0 -53
- package/agents/update/document-tools/update-document-content.mjs +0 -303
- package/agents/update/generate-diagram.yaml +0 -80
- package/agents/update/generate-document.yaml +0 -70
- package/agents/update/handle-document-update.yaml +0 -103
- package/agents/update/index.yaml +0 -69
- package/agents/update/pre-check-generate-diagram.yaml +0 -44
- package/agents/update/save-and-translate-document.mjs +0 -80
- package/agents/update/update-document-detail.yaml +0 -71
- package/agents/update/update-single/update-single-document-detail.mjs +0 -322
- package/agents/update/update-single-document.yaml +0 -7
- package/agents/update/user-review-document.mjs +0 -272
- package/agents/utils/action-success.mjs +0 -16
- package/agents/utils/analyze-document-feedback-intent.yaml +0 -32
- package/agents/utils/analyze-feedback-intent.mjs +0 -253
- package/agents/utils/analyze-structure-feedback-intent.yaml +0 -29
- package/agents/utils/check-detail-result.mjs +0 -51
- package/agents/utils/check-feedback-refiner.mjs +0 -81
- package/agents/utils/choose-docs.mjs +0 -251
- package/agents/utils/document-icon-generate.yaml +0 -52
- package/agents/utils/document-title-streamline.yaml +0 -48
- package/agents/utils/ensure-document-icons.mjs +0 -129
- package/agents/utils/exit.mjs +0 -6
- package/agents/utils/feedback-refiner.yaml +0 -50
- package/agents/utils/find-item-by-path.mjs +0 -114
- package/agents/utils/find-user-preferences-by-path.mjs +0 -37
- package/agents/utils/format-document-structure.mjs +0 -35
- package/agents/utils/generate-document-or-skip.mjs +0 -41
- package/agents/utils/handle-diagram-operations.mjs +0 -263
- package/agents/utils/load-all-document-content.mjs +0 -30
- package/agents/utils/load-document-all-content.mjs +0 -96
- package/agents/utils/load-sources.mjs +0 -405
- package/agents/utils/map-reasoning-effort-level.mjs +0 -15
- package/agents/utils/post-generate.mjs +0 -133
- package/agents/utils/read-current-document-content.mjs +0 -46
- package/agents/utils/save-doc-translation.mjs +0 -30
- package/agents/utils/save-doc.mjs +0 -54
- package/agents/utils/save-output.mjs +0 -26
- package/agents/utils/save-sidebar.mjs +0 -38
- package/agents/utils/skip-if-content-exists.mjs +0 -27
- package/agents/utils/streamline-document-titles-if-needed.mjs +0 -88
- package/agents/utils/transform-detail-data-sources.mjs +0 -45
- package/assets/report-template/report.html +0 -198
- package/docs-mcp/analyze-content-relevance.yaml +0 -50
- package/docs-mcp/analyze-docs-relevance.yaml +0 -59
- package/docs-mcp/docs-search.yaml +0 -42
- package/docs-mcp/get-docs-detail.mjs +0 -41
- package/docs-mcp/get-docs-structure.mjs +0 -16
- package/docs-mcp/read-doc-content.mjs +0 -119
- package/prompts/common/document/content-rules-core.md +0 -20
- package/prompts/common/document/markdown-syntax-rules.md +0 -65
- package/prompts/common/document/media-file-list-usage-rules.md +0 -18
- package/prompts/common/document/openapi-usage-rules.md +0 -189
- package/prompts/common/document/role-and-personality.md +0 -16
- package/prompts/common/document/user-preferences.md +0 -9
- package/prompts/common/document-structure/conflict-resolution-guidance.md +0 -16
- package/prompts/common/document-structure/document-icon-generate.md +0 -116
- package/prompts/common/document-structure/document-structure-rules.md +0 -43
- package/prompts/common/document-structure/document-title-streamline.md +0 -86
- package/prompts/common/document-structure/glossary.md +0 -7
- package/prompts/common/document-structure/intj-traits.md +0 -5
- package/prompts/common/document-structure/openapi-usage-rules.md +0 -28
- package/prompts/common/document-structure/output-constraints.md +0 -18
- package/prompts/common/document-structure/user-locale-rules.md +0 -10
- package/prompts/common/document-structure/user-preferences.md +0 -9
- package/prompts/detail/custom/admonition-usage-rules.md +0 -94
- package/prompts/detail/custom/code-block-usage-rules.md +0 -163
- package/prompts/detail/custom/custom-components/x-card-usage-rules.md +0 -63
- package/prompts/detail/custom/custom-components/x-cards-usage-rules.md +0 -83
- package/prompts/detail/custom/custom-components/x-field-desc-usage-rules.md +0 -120
- package/prompts/detail/custom/custom-components/x-field-group-usage-rules.md +0 -80
- package/prompts/detail/custom/custom-components/x-field-usage-rules.md +0 -189
- package/prompts/detail/custom/custom-components-usage-rules.md +0 -18
- package/prompts/detail/diagram/generate-image-user.md +0 -81
- package/prompts/detail/diagram/guide.md +0 -29
- package/prompts/detail/diagram/official-examples.md +0 -712
- package/prompts/detail/diagram/pre-check.md +0 -23
- package/prompts/detail/diagram/role-and-personality.md +0 -2
- package/prompts/detail/diagram/rules.md +0 -46
- package/prompts/detail/diagram/system-prompt.md +0 -1139
- package/prompts/detail/diagram/user-prompt.md +0 -43
- package/prompts/detail/generate/detail-example.md +0 -457
- package/prompts/detail/generate/document-rules.md +0 -45
- package/prompts/detail/generate/system-prompt.md +0 -61
- package/prompts/detail/generate/user-prompt.md +0 -99
- package/prompts/detail/jsx/rules.md +0 -6
- package/prompts/detail/update/system-prompt.md +0 -121
- package/prompts/detail/update/user-prompt.md +0 -41
- package/prompts/evaluate/document-structure.md +0 -93
- package/prompts/evaluate/document.md +0 -149
- package/prompts/media/media-description/system-prompt.md +0 -43
- package/prompts/media/media-description/user-prompt.md +0 -17
- package/prompts/structure/check-document-structure.md +0 -93
- package/prompts/structure/document-rules.md +0 -21
- package/prompts/structure/find-documents-to-add-links.md +0 -52
- package/prompts/structure/generate/system-prompt.md +0 -13
- package/prompts/structure/generate/user-prompt.md +0 -137
- package/prompts/structure/review/structure-review-system.md +0 -81
- package/prompts/structure/structure-example.md +0 -89
- package/prompts/structure/structure-getting-started.md +0 -10
- package/prompts/structure/update/system-prompt.md +0 -93
- package/prompts/structure/update/user-prompt.md +0 -43
- package/prompts/translate/admonition.md +0 -20
- package/prompts/translate/code-block.md +0 -33
- package/prompts/utils/analyze-document-feedback-intent.md +0 -54
- package/prompts/utils/analyze-structure-feedback-intent.md +0 -43
- package/prompts/utils/feedback-refiner.md +0 -105
- package/types/document-schema.mjs +0 -55
- package/types/document-structure-schema.mjs +0 -261
- package/utils/check-document-has-diagram.mjs +0 -95
- package/utils/conflict-detector.mjs +0 -149
- package/utils/constants/index.mjs +0 -620
- package/utils/constants/linter.mjs +0 -102
- package/utils/d2-utils.mjs +0 -205
- package/utils/debug.mjs +0 -3
- package/utils/delete-diagram-images.mjs +0 -99
- package/utils/diagram-version-utils.mjs +0 -14
- package/utils/docs-finder-utils.mjs +0 -548
- package/utils/evaluate/report-utils.mjs +0 -132
- package/utils/extract-api.mjs +0 -32
- package/utils/file-utils.mjs +0 -960
- package/utils/history-utils.mjs +0 -203
- package/utils/icon-map.mjs +0 -26
- package/utils/image-compress.mjs +0 -154
- package/utils/kroki-utils.mjs +0 -173
- package/utils/linter/index.mjs +0 -50
- package/utils/load-config.mjs +0 -78
- package/utils/markdown/index.mjs +0 -26
- package/utils/markdown-checker.mjs +0 -694
- package/utils/mermaid-validator.mjs +0 -140
- package/utils/mermaid-worker-pool.mjs +0 -250
- package/utils/mermaid-worker.mjs +0 -233
- package/utils/openapi/index.mjs +0 -28
- package/utils/preferences-utils.mjs +0 -175
- package/utils/request.mjs +0 -10
- package/utils/sync-diagram-to-translations.mjs +0 -272
- package/utils/translate-diagram-images.mjs +0 -807
- package/utils/utils.mjs +0 -1354
- /package/{prompts/translate → agents/localize/prompts}/glossary.md +0 -0
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { parse, stringify } from "yaml";
|
|
6
|
-
import { getMediaDescriptionCachePath } from "../../utils/file-utils.mjs";
|
|
7
|
-
import { compressImage } from "../../utils/image-compress.mjs";
|
|
8
|
-
import sharp from "sharp";
|
|
9
|
-
import { debug } from "../../utils/debug.mjs";
|
|
10
|
-
import { DOC_SMITH_DIR, TMP_DIR } from "../../utils/constants/index.mjs";
|
|
11
|
-
import { ensureTmpDir } from "../../utils/d2-utils.mjs";
|
|
12
|
-
import pMap from "p-map";
|
|
13
|
-
|
|
14
|
-
const SIZE_THRESHOLD = 10 * 1024 * 1024; // 10MB
|
|
15
|
-
const SVG_SIZE_THRESHOLD = 50 * 1024; // 50KB for SVG files
|
|
16
|
-
const MAX_IMAGE_SIZE = 1 * 1024 * 1024; // 1MB
|
|
17
|
-
const MAX_IMAGE_RESOLUTION = 2048; // 2K
|
|
18
|
-
|
|
19
|
-
// Supported MIME types for Gemini AI
|
|
20
|
-
const SUPPORTED_IMAGE_TYPES = new Set([
|
|
21
|
-
"image/png",
|
|
22
|
-
"image/jpeg",
|
|
23
|
-
"image/webp",
|
|
24
|
-
"image/heic",
|
|
25
|
-
"image/heif",
|
|
26
|
-
]);
|
|
27
|
-
|
|
28
|
-
const SUPPORTED_SVG_TYPES = new Set(["image/svg+xml"]);
|
|
29
|
-
|
|
30
|
-
const SUPPORTED_VIDEO_TYPES = new Set([
|
|
31
|
-
"video/mp4",
|
|
32
|
-
"video/mpeg",
|
|
33
|
-
"video/mov",
|
|
34
|
-
"video/avi",
|
|
35
|
-
"video/x-flv",
|
|
36
|
-
"video/mpg",
|
|
37
|
-
"video/webm",
|
|
38
|
-
"video/wmv",
|
|
39
|
-
"video/3gpp",
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Calculate hash for a media file
|
|
44
|
-
* For files < 10MB: use file content
|
|
45
|
-
* For files >= 10MB: use path + size + mtime to avoid memory issues
|
|
46
|
-
* @param {string} absolutePath - The absolute path to the media file
|
|
47
|
-
* @returns {Promise<string>} - The hash of the file
|
|
48
|
-
*/
|
|
49
|
-
async function calculateMediaHash(absolutePath) {
|
|
50
|
-
const stats = await stat(absolutePath);
|
|
51
|
-
|
|
52
|
-
if (stats.size < SIZE_THRESHOLD) {
|
|
53
|
-
// Small file: use full content
|
|
54
|
-
const content = await readFile(absolutePath);
|
|
55
|
-
return createHash("sha256").update(content).digest("hex");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Large file: use path + size + mtime
|
|
59
|
-
const hashInput = `${absolutePath}:${stats.size}:${stats.mtimeMs}`;
|
|
60
|
-
return createHash("sha256").update(hashInput).digest("hex");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Load media descriptions from cache and generate new ones if needed
|
|
65
|
-
* @param {Object} input - Input parameters
|
|
66
|
-
* @param {Array} input.mediaFiles - Array of media file objects from load-sources
|
|
67
|
-
* @param {string} input.docsDir - Base directory for documentation
|
|
68
|
-
* @param {Object} options - Agent options
|
|
69
|
-
* @returns {Promise<Object>} - Updated assetsContent with media descriptions
|
|
70
|
-
*/
|
|
71
|
-
export default async function loadMediaDescription(input, options) {
|
|
72
|
-
const { mediaFiles = [], docsDir } = input;
|
|
73
|
-
|
|
74
|
-
// Filter to get image, video and svg files with supported MIME types
|
|
75
|
-
const mediaFilesToProcess = mediaFiles.filter((file) => {
|
|
76
|
-
if (file.type === "image") {
|
|
77
|
-
return SUPPORTED_IMAGE_TYPES.has(file.mimeType) || SUPPORTED_SVG_TYPES.has(file.mimeType);
|
|
78
|
-
}
|
|
79
|
-
if (file.type === "video") {
|
|
80
|
-
return SUPPORTED_VIDEO_TYPES.has(file.mimeType);
|
|
81
|
-
}
|
|
82
|
-
return false;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Path to media description cache file
|
|
86
|
-
const cacheFilePath = getMediaDescriptionCachePath();
|
|
87
|
-
|
|
88
|
-
// Load existing cache
|
|
89
|
-
let cache = {};
|
|
90
|
-
if (existsSync(cacheFilePath)) {
|
|
91
|
-
try {
|
|
92
|
-
const cacheContent = await readFile(cacheFilePath, "utf8");
|
|
93
|
-
const parsedCache = parse(cacheContent);
|
|
94
|
-
cache = parsedCache?.descriptions || {};
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.warn("Failed to read media description cache:", error.message);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Find media files without descriptions
|
|
101
|
-
const mediaToDescribe = [];
|
|
102
|
-
const mediaHashMap = new Map();
|
|
103
|
-
|
|
104
|
-
const absoluteDocsDir = path.resolve(process.cwd(), docsDir);
|
|
105
|
-
|
|
106
|
-
// Only process media files that need AI description
|
|
107
|
-
for (const mediaFile of mediaFilesToProcess) {
|
|
108
|
-
// Convert relative path to absolute path for consistent hashing
|
|
109
|
-
// mediaFiles.path is relative to docsDir
|
|
110
|
-
const absolutePath = path.join(absoluteDocsDir, mediaFile.path);
|
|
111
|
-
const mediaHash = await calculateMediaHash(absolutePath);
|
|
112
|
-
mediaHashMap.set(mediaFile.path, mediaHash);
|
|
113
|
-
|
|
114
|
-
if (!cache[mediaHash]) {
|
|
115
|
-
const isSvg = SUPPORTED_SVG_TYPES.has(mediaFile.mimeType);
|
|
116
|
-
|
|
117
|
-
if (isSvg) {
|
|
118
|
-
// For SVG files, check size and read content
|
|
119
|
-
try {
|
|
120
|
-
const stats = await stat(absolutePath);
|
|
121
|
-
if (stats.size > SVG_SIZE_THRESHOLD) {
|
|
122
|
-
console.warn(
|
|
123
|
-
`SVG file ${mediaFile.path} exceeds ${SVG_SIZE_THRESHOLD / 1024}KB limit, skipping`,
|
|
124
|
-
);
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const svgContent = await readFile(absolutePath, "utf8");
|
|
129
|
-
mediaToDescribe.push({
|
|
130
|
-
...mediaFile,
|
|
131
|
-
hash: mediaHash,
|
|
132
|
-
path: mediaFile.path,
|
|
133
|
-
svgContent,
|
|
134
|
-
});
|
|
135
|
-
} catch (error) {
|
|
136
|
-
console.warn(`Failed to read SVG file ${mediaFile.path}:`, error.message);
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
// For non-SVG media files, check if compression is needed
|
|
140
|
-
let finalImagePath = absolutePath;
|
|
141
|
-
let shouldCompress = false;
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
// Check file size and dimensions
|
|
145
|
-
const fileStats = await stat(absolutePath);
|
|
146
|
-
const fileSize = fileStats.size;
|
|
147
|
-
|
|
148
|
-
// Get image dimensions
|
|
149
|
-
const metadata = await sharp(absolutePath).metadata();
|
|
150
|
-
const { width, height } = metadata;
|
|
151
|
-
|
|
152
|
-
// Determine if compression is needed
|
|
153
|
-
// Compression rules:
|
|
154
|
-
// 1. Only compress files larger than 1MB
|
|
155
|
-
// 2. Compressed file must have resolution <= 2K and size < 1MB
|
|
156
|
-
// 3. Files <= 1MB are never compressed, regardless of resolution
|
|
157
|
-
const exceedsSize = fileSize > MAX_IMAGE_SIZE;
|
|
158
|
-
|
|
159
|
-
// Only compress if file size > 1MB
|
|
160
|
-
// For files <= 1MB, skip compression regardless of resolution
|
|
161
|
-
if (exceedsSize) {
|
|
162
|
-
// Create temporary compressed file path in temp directory with same relative structure
|
|
163
|
-
// Example: docs/assets/images/photo.jpg -> .aigne/doc-smith/.tmp/docs/assets/images/photo.compressed.jpg
|
|
164
|
-
await ensureTmpDir();
|
|
165
|
-
const tmpBaseDir = path.join(process.cwd(), DOC_SMITH_DIR, TMP_DIR);
|
|
166
|
-
|
|
167
|
-
// Get relative path from docsDir to maintain structure
|
|
168
|
-
// mediaFile.path is already relative to docsDir (e.g., "assets/images/photo.jpg")
|
|
169
|
-
const relativePath = mediaFile.path;
|
|
170
|
-
const relativeDir = path.dirname(relativePath);
|
|
171
|
-
const fileName = path.basename(relativePath, path.extname(relativePath));
|
|
172
|
-
const fileExt = path.extname(relativePath);
|
|
173
|
-
|
|
174
|
-
// Normalize docsDir to handle both relative and absolute paths
|
|
175
|
-
// If docsDir is absolute, extract the relative part from cwd
|
|
176
|
-
let normalizedDocsDir = docsDir;
|
|
177
|
-
if (path.isAbsolute(docsDir)) {
|
|
178
|
-
const cwd = process.cwd();
|
|
179
|
-
if (docsDir.startsWith(cwd)) {
|
|
180
|
-
normalizedDocsDir = path.relative(cwd, docsDir);
|
|
181
|
-
} else {
|
|
182
|
-
// If docsDir is outside cwd, use just the basename
|
|
183
|
-
normalizedDocsDir = path.basename(docsDir);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Create temp directory structure matching the relative path
|
|
188
|
-
// Structure: .aigne/doc-smith/.tmp/{docsDir}/{relativeDir}
|
|
189
|
-
const tempDir = path.join(tmpBaseDir, normalizedDocsDir, relativeDir);
|
|
190
|
-
await mkdir(tempDir, { recursive: true });
|
|
191
|
-
|
|
192
|
-
// Create compressed file path
|
|
193
|
-
const tempFileName = `${fileName}.compressed${fileExt}`;
|
|
194
|
-
const tempPath = path.join(tempDir, tempFileName);
|
|
195
|
-
|
|
196
|
-
// Check if compressed file already exists in cache directory
|
|
197
|
-
if (existsSync(tempPath)) {
|
|
198
|
-
debug(`Compressed file already exists for ${mediaFile.path}, skipping compression`);
|
|
199
|
-
finalImagePath = tempPath;
|
|
200
|
-
shouldCompress = true;
|
|
201
|
-
} else {
|
|
202
|
-
shouldCompress = true;
|
|
203
|
-
debug(
|
|
204
|
-
`Compressing image ${mediaFile.path} (size: ${(fileSize / 1024 / 1024).toFixed(2)}MB, resolution: ${width}x${height})`,
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
// Compress image with constraints
|
|
208
|
-
// For files > 1MB: compress to resolution <= 2K and size < 1MB
|
|
209
|
-
finalImagePath = await compressImage(absolutePath, {
|
|
210
|
-
maxWidth: MAX_IMAGE_RESOLUTION, // Always limit to 2K
|
|
211
|
-
maxHeight: MAX_IMAGE_RESOLUTION, // Always limit to 2K
|
|
212
|
-
maxSizeBytes: MAX_IMAGE_SIZE, // Always limit to 1MB
|
|
213
|
-
outputPath: tempPath,
|
|
214
|
-
quality: 70, // Start with good quality
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// Verify compressed file size
|
|
218
|
-
const compressedStats = await stat(finalImagePath);
|
|
219
|
-
if (compressedStats.size > MAX_IMAGE_SIZE) {
|
|
220
|
-
console.warn(
|
|
221
|
-
`Compressed image ${mediaFile.path} still exceeds ${MAX_IMAGE_SIZE / 1024 / 1024}MB (${(compressedStats.size / 1024 / 1024).toFixed(2)}MB), using compressed version anyway`,
|
|
222
|
-
);
|
|
223
|
-
} else {
|
|
224
|
-
debug(
|
|
225
|
-
`✅ Image compressed: ${mediaFile.path} -> ${(compressedStats.size / 1024 / 1024).toFixed(2)}MB`,
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
} else {
|
|
230
|
-
debug(
|
|
231
|
-
`Image ${mediaFile.path} is <= 1MB (size: ${(fileSize / 1024 / 1024).toFixed(2)}MB, resolution: ${width}x${height}), skipping compression`,
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
} catch (error) {
|
|
235
|
-
console.warn(`Failed to compress image ${mediaFile.path}:`, error.message);
|
|
236
|
-
// Use original path if compression fails
|
|
237
|
-
finalImagePath = absolutePath;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// For non-SVG media files, use mediaFile field
|
|
241
|
-
mediaToDescribe.push({
|
|
242
|
-
...mediaFile,
|
|
243
|
-
hash: mediaHash,
|
|
244
|
-
path: mediaFile.path,
|
|
245
|
-
mediaFile: [
|
|
246
|
-
{
|
|
247
|
-
type: "local",
|
|
248
|
-
path: finalImagePath,
|
|
249
|
-
filename: mediaFile.name,
|
|
250
|
-
mimeType: mediaFile.mimeType,
|
|
251
|
-
},
|
|
252
|
-
],
|
|
253
|
-
_compressed: shouldCompress, // Track if compression was applied for cleanup
|
|
254
|
-
_originalPath: shouldCompress ? absolutePath : undefined, // Store original path for cleanup
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Generate descriptions for media files without cache - batch processing with incremental save
|
|
261
|
-
const newDescriptions = {};
|
|
262
|
-
const results = []; // Track all results for accurate counting
|
|
263
|
-
|
|
264
|
-
if (mediaToDescribe.length > 0) {
|
|
265
|
-
// Ensure cache directory exists
|
|
266
|
-
await mkdir(path.dirname(cacheFilePath), { recursive: true });
|
|
267
|
-
|
|
268
|
-
// Create a write lock queue to ensure thread-safe cache updates
|
|
269
|
-
let writeQueue = Promise.resolve();
|
|
270
|
-
// Keep in-memory cache in sync to avoid unnecessary file reads
|
|
271
|
-
const inMemoryCache = { ...cache };
|
|
272
|
-
|
|
273
|
-
// Helper function to save cache with lock
|
|
274
|
-
// Optimized: Use in-memory cache to reduce file I/O
|
|
275
|
-
const saveCacheWithLock = async (newEntry) => {
|
|
276
|
-
// Add to write queue to ensure sequential writes
|
|
277
|
-
writeQueue = writeQueue
|
|
278
|
-
.then(async () => {
|
|
279
|
-
try {
|
|
280
|
-
// Merge new entry into in-memory cache
|
|
281
|
-
Object.assign(inMemoryCache, newEntry);
|
|
282
|
-
|
|
283
|
-
// Save to disk
|
|
284
|
-
const cacheYaml = stringify({
|
|
285
|
-
descriptions: inMemoryCache,
|
|
286
|
-
lastUpdated: new Date().toISOString(),
|
|
287
|
-
});
|
|
288
|
-
await writeFile(cacheFilePath, cacheYaml, "utf8");
|
|
289
|
-
// Only update in-memory cache after successful write
|
|
290
|
-
return true;
|
|
291
|
-
} catch (error) {
|
|
292
|
-
// Rollback: remove the entry from in-memory cache if write failed
|
|
293
|
-
for (const key of Object.keys(newEntry)) {
|
|
294
|
-
delete inMemoryCache[key];
|
|
295
|
-
}
|
|
296
|
-
console.error(`Failed to save cache: ${error.message}`);
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
})
|
|
300
|
-
.catch(() => {
|
|
301
|
-
// Don't let one write failure break the queue
|
|
302
|
-
// Error is already logged above
|
|
303
|
-
return false;
|
|
304
|
-
});
|
|
305
|
-
await writeQueue;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
// Process media files concurrently with incremental save
|
|
309
|
-
// Use pMap for concurrent processing with controlled concurrency
|
|
310
|
-
const CONCURRENCY = 5; // Process 5 files concurrently
|
|
311
|
-
|
|
312
|
-
await pMap(
|
|
313
|
-
mediaToDescribe,
|
|
314
|
-
async (mediaItem, index) => {
|
|
315
|
-
const result = { success: false, path: mediaItem.path, error: null };
|
|
316
|
-
|
|
317
|
-
try {
|
|
318
|
-
// Generate description for single media file
|
|
319
|
-
// Note: If compression was applied, mediaItem.mediaFile[0].path points to compressed file
|
|
320
|
-
// This compressed file is used for upload, but cache uses original file hash and path
|
|
321
|
-
const agentResult = await options.context.invoke(
|
|
322
|
-
options.context.agents["generateMediaDescription"],
|
|
323
|
-
mediaItem,
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
// Check if description was generated successfully
|
|
327
|
-
// Note: agentResult.hash and agentResult.path come from the agent, but we need to ensure
|
|
328
|
-
// we use the original file path and hash for caching, not the compressed file path
|
|
329
|
-
if (agentResult?.hash && agentResult?.description) {
|
|
330
|
-
// Use original file path and hash for cache entry
|
|
331
|
-
// The compressed file is only used for upload, but cache should reference original file
|
|
332
|
-
const originalPath = mediaItem.path;
|
|
333
|
-
const originalHash = mediaItem.hash;
|
|
334
|
-
|
|
335
|
-
const descriptionEntry = {
|
|
336
|
-
path: originalPath, // Use original file path, not compressed file path
|
|
337
|
-
description: agentResult.description,
|
|
338
|
-
generatedAt: new Date().toISOString(),
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
// Immediately save to cache using lock mechanism
|
|
342
|
-
await saveCacheWithLock({ [originalHash]: descriptionEntry });
|
|
343
|
-
|
|
344
|
-
// Track in memory for summary
|
|
345
|
-
newDescriptions[originalHash] = descriptionEntry;
|
|
346
|
-
result.success = true;
|
|
347
|
-
|
|
348
|
-
debug(
|
|
349
|
-
`✅ Generated and saved description for ${mediaItem.path} (${index + 1}/${mediaToDescribe.length})`,
|
|
350
|
-
);
|
|
351
|
-
} else {
|
|
352
|
-
result.error = "No description in result";
|
|
353
|
-
console.warn(
|
|
354
|
-
`Failed to generate description for ${mediaItem.path}: No description in result`,
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
} catch (error) {
|
|
358
|
-
result.error = error.message;
|
|
359
|
-
console.error(`Failed to generate description for ${mediaItem.path}:`, error.message);
|
|
360
|
-
// Continue processing other files even if one fails
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
results.push(result);
|
|
364
|
-
return result;
|
|
365
|
-
},
|
|
366
|
-
{ concurrency: CONCURRENCY },
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
// Calculate accurate counts from results
|
|
370
|
-
const successCount = results.filter((r) => r.success).length;
|
|
371
|
-
const errorCount = results.filter((r) => !r.success).length;
|
|
372
|
-
|
|
373
|
-
// Update cache reference to in-memory cache
|
|
374
|
-
Object.assign(cache, inMemoryCache);
|
|
375
|
-
|
|
376
|
-
// Log summary
|
|
377
|
-
if (successCount > 0) {
|
|
378
|
-
console.log(
|
|
379
|
-
`Generated descriptions for ${successCount} media files (${errorCount} errors, ${mediaToDescribe.length - successCount - errorCount} skipped)`,
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
if (errorCount > 0) {
|
|
383
|
-
console.warn(
|
|
384
|
-
`⚠️ Failed to generate descriptions for ${errorCount} media files. Completed descriptions have been saved.`,
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Build enhanced assetsContent with descriptions
|
|
390
|
-
let enhancedAssetsContent;
|
|
391
|
-
|
|
392
|
-
if (mediaFiles.length > 0) {
|
|
393
|
-
enhancedAssetsContent = "# Available Media Assets for Documentation\n\n";
|
|
394
|
-
const assets = mediaFiles.map((x) => {
|
|
395
|
-
const mediaHash = mediaHashMap.get(x.path);
|
|
396
|
-
const description = cache[mediaHash]?.description;
|
|
397
|
-
const result = {
|
|
398
|
-
name: x.name,
|
|
399
|
-
path: x.path,
|
|
400
|
-
};
|
|
401
|
-
if (description) {
|
|
402
|
-
result.description = description;
|
|
403
|
-
}
|
|
404
|
-
return result;
|
|
405
|
-
});
|
|
406
|
-
enhancedAssetsContent += stringify(assets);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return {
|
|
410
|
-
...input,
|
|
411
|
-
assetsContent: enhancedAssetsContent,
|
|
412
|
-
mediaFiles,
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
loadMediaDescription.input_schema = {
|
|
417
|
-
type: "object",
|
|
418
|
-
properties: {
|
|
419
|
-
mediaFiles: {
|
|
420
|
-
type: "array",
|
|
421
|
-
items: {
|
|
422
|
-
type: "object",
|
|
423
|
-
properties: {
|
|
424
|
-
name: { type: "string" },
|
|
425
|
-
path: { type: "string" },
|
|
426
|
-
type: { type: "string" },
|
|
427
|
-
width: { type: "number" },
|
|
428
|
-
height: { type: "number" },
|
|
429
|
-
mimeType: { type: "string" },
|
|
430
|
-
},
|
|
431
|
-
},
|
|
432
|
-
description: "Array of media file objects (images/videos)",
|
|
433
|
-
},
|
|
434
|
-
docsDir: {
|
|
435
|
-
type: "string",
|
|
436
|
-
description: "Base directory for documentation",
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
required: ["mediaFiles", "docsDir"],
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
loadMediaDescription.output_schema = {
|
|
443
|
-
type: "object",
|
|
444
|
-
properties: {
|
|
445
|
-
assetsContent: {
|
|
446
|
-
type: "string",
|
|
447
|
-
description: "Enhanced assets content with media descriptions",
|
|
448
|
-
},
|
|
449
|
-
mediaFiles: {
|
|
450
|
-
type: "array",
|
|
451
|
-
description: "Array of media file objects",
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
};
|
package/agents/prefs/index.mjs
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { readPreferences, removeRule, writePreferences } from "../../utils/preferences-utils.mjs";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* List all user preferences with formatted display
|
|
5
|
-
* @returns {Object} Result with formatted message
|
|
6
|
-
*/
|
|
7
|
-
function listPreferences() {
|
|
8
|
-
const preferences = readPreferences();
|
|
9
|
-
|
|
10
|
-
if (preferences.rules.length === 0) {
|
|
11
|
-
return { message: "No saved preferences found." };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let message = "# User Preferences\n\n";
|
|
15
|
-
|
|
16
|
-
// Add format explanation
|
|
17
|
-
message += "**Format explanation:**\n";
|
|
18
|
-
message += "- 🟢 = Active preference, ⚪ = Inactive preference\n";
|
|
19
|
-
message += "- [scope] = Preference scope (global, structure, document, translation)\n";
|
|
20
|
-
message += "- ID = Unique preference identifier\n";
|
|
21
|
-
message += "- Paths = Specific file paths (if applicable)\n\n";
|
|
22
|
-
|
|
23
|
-
preferences.rules.forEach((rule) => {
|
|
24
|
-
const status = rule.active ? "🟢" : "⚪";
|
|
25
|
-
const pathsInfo = rule.paths ? ` | Paths: ${rule.paths.join(", ")}` : "";
|
|
26
|
-
|
|
27
|
-
// First line: status, scope, ID and paths info
|
|
28
|
-
message += `${status} [${rule.scope}] ${rule.id}${pathsInfo}\n`;
|
|
29
|
-
|
|
30
|
-
// Second line: rule content (truncated if too long)
|
|
31
|
-
const maxRuleLength = 120;
|
|
32
|
-
const ruleText =
|
|
33
|
-
rule.rule.length > maxRuleLength ? `${rule.rule.substring(0, maxRuleLength)}...` : rule.rule;
|
|
34
|
-
message += ` ${ruleText}\n `;
|
|
35
|
-
|
|
36
|
-
// Add blank line after each record
|
|
37
|
-
message += `\n`;
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return { message };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Remove preferences by IDs or interactive selection
|
|
45
|
-
* @param {string[]} id - Array of preference IDs to remove
|
|
46
|
-
* @param {Object} options - Options with prompts interface
|
|
47
|
-
* @returns {Object} Result with success message
|
|
48
|
-
*/
|
|
49
|
-
async function removePreferences(id, options) {
|
|
50
|
-
const preferences = readPreferences();
|
|
51
|
-
let targetIds = id;
|
|
52
|
-
|
|
53
|
-
if (!targetIds || targetIds.length === 0) {
|
|
54
|
-
// Interactive selection
|
|
55
|
-
if (preferences.rules.length === 0) {
|
|
56
|
-
return { message: "No preferences available to remove." };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const choices = preferences.rules.map((rule) => ({
|
|
60
|
-
name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
|
|
61
|
-
value: rule.id,
|
|
62
|
-
description: `ID: ${rule.id}`,
|
|
63
|
-
}));
|
|
64
|
-
|
|
65
|
-
targetIds = await options.prompts.checkbox({
|
|
66
|
-
message: "Choose preferences to delete:",
|
|
67
|
-
choices,
|
|
68
|
-
validate: (answer) => {
|
|
69
|
-
if (answer.length === 0) {
|
|
70
|
-
return "Please choose at least one preference to delete";
|
|
71
|
-
}
|
|
72
|
-
return true;
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (!targetIds || targetIds.length === 0) {
|
|
77
|
-
return { message: "No preferences selected for deletion." };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Process the target IDs
|
|
82
|
-
const results = [];
|
|
83
|
-
for (const ruleId of targetIds) {
|
|
84
|
-
const success = removeRule(ruleId);
|
|
85
|
-
results.push({ id: ruleId, success });
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const successCount = results.filter((r) => r.success).length;
|
|
89
|
-
const failedCount = targetIds.length - successCount;
|
|
90
|
-
const message =
|
|
91
|
-
failedCount > 0
|
|
92
|
-
? `Successfully removed ${successCount} preferences, ${failedCount} failed.`
|
|
93
|
-
: `Successfully removed ${successCount} preferences.`;
|
|
94
|
-
|
|
95
|
-
return { message };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Toggle preferences active status by IDs or interactive selection
|
|
100
|
-
* @param {string[]} id - Array of preference IDs to toggle
|
|
101
|
-
* @param {Object} options - Options with prompts interface
|
|
102
|
-
* @returns {Object} Result with success message
|
|
103
|
-
*/
|
|
104
|
-
async function togglePreferences(id, options) {
|
|
105
|
-
const preferences = readPreferences();
|
|
106
|
-
let targetIds = id;
|
|
107
|
-
|
|
108
|
-
if (!targetIds || targetIds.length === 0) {
|
|
109
|
-
// Interactive selection
|
|
110
|
-
if (preferences.rules.length === 0) {
|
|
111
|
-
return { message: "No preferences available to toggle." };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const choices = preferences.rules.map((rule) => ({
|
|
115
|
-
name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
|
|
116
|
-
value: rule.id,
|
|
117
|
-
description: `ID: ${rule.id}`,
|
|
118
|
-
}));
|
|
119
|
-
|
|
120
|
-
targetIds = await options.prompts.checkbox({
|
|
121
|
-
message: "Choose preferences to enable/disable:",
|
|
122
|
-
choices,
|
|
123
|
-
validate: (answer) => {
|
|
124
|
-
if (answer.length === 0) {
|
|
125
|
-
return "Please choose at least one preference to toggle";
|
|
126
|
-
}
|
|
127
|
-
return true;
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
if (!targetIds || targetIds.length === 0) {
|
|
132
|
-
return { message: "No preferences selected to toggle." };
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Process the target IDs
|
|
137
|
-
const results = [];
|
|
138
|
-
const prefs = readPreferences();
|
|
139
|
-
|
|
140
|
-
for (const ruleId of targetIds) {
|
|
141
|
-
const rule = prefs.rules.find((r) => r.id === ruleId);
|
|
142
|
-
if (rule) {
|
|
143
|
-
rule.active = !rule.active;
|
|
144
|
-
results.push({ id: ruleId, success: true, newStatus: rule.active });
|
|
145
|
-
} else {
|
|
146
|
-
results.push({ id: ruleId, success: false, error: "Rule not found" });
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
writePreferences(prefs);
|
|
151
|
-
|
|
152
|
-
const successCount = results.filter((r) => r.success).length;
|
|
153
|
-
const failedCount = targetIds.length - successCount;
|
|
154
|
-
const message =
|
|
155
|
-
failedCount > 0
|
|
156
|
-
? `Successfully toggled ${successCount} preferences, ${failedCount} failed.`
|
|
157
|
-
: `Successfully toggled ${successCount} preferences.`;
|
|
158
|
-
|
|
159
|
-
return { message };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export default async function prefs({ list, remove, toggle, id }, options) {
|
|
163
|
-
if (list) {
|
|
164
|
-
return listPreferences();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (remove) {
|
|
168
|
-
return await removePreferences(id, options);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (toggle) {
|
|
172
|
-
return await togglePreferences(id, options);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return { message: "Please choose an action: --list, --remove, or --toggle." };
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
prefs.input_schema = {
|
|
179
|
-
type: "object",
|
|
180
|
-
properties: {
|
|
181
|
-
list: {
|
|
182
|
-
type: "boolean",
|
|
183
|
-
description: "Show all saved preferences",
|
|
184
|
-
},
|
|
185
|
-
remove: {
|
|
186
|
-
type: "boolean",
|
|
187
|
-
description: "Delete saved preferences",
|
|
188
|
-
},
|
|
189
|
-
toggle: {
|
|
190
|
-
type: "boolean",
|
|
191
|
-
description: "Enable/disable preferences",
|
|
192
|
-
},
|
|
193
|
-
id: {
|
|
194
|
-
type: "array",
|
|
195
|
-
items: {
|
|
196
|
-
type: "string",
|
|
197
|
-
},
|
|
198
|
-
description: "Specific preference IDs to work with",
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
prefs.description = "Manage your saved documentation preferences";
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
type: object
|
|
2
|
-
description: Document structure item representing a node in the document hierarchy
|
|
3
|
-
properties:
|
|
4
|
-
title:
|
|
5
|
-
type: string
|
|
6
|
-
description:
|
|
7
|
-
type: string
|
|
8
|
-
path:
|
|
9
|
-
type: string
|
|
10
|
-
description: Path in URL format, cannot be empty, cannot contain spaces or special characters, must start with /, no need to include language level, e.g., /zh/about should return /about
|
|
11
|
-
parentPath:
|
|
12
|
-
type: string
|
|
13
|
-
description: Parent node path, if null indicates it is a top-level node
|
|
14
|
-
sourceIds:
|
|
15
|
-
type: array
|
|
16
|
-
description: Associated sourceId from `<data_sources>` for subsequent translation and content generation, must come from sourceId in `<data_sources>`, cannot have fake ids, **cannot be empty**
|
|
17
|
-
items:
|
|
18
|
-
type: string
|
|
19
|
-
icon:
|
|
20
|
-
type: string
|
|
21
|
-
description: Lucide icon name for root-level documents (just support lucide:icon-name, not support other icon collections)
|
|
22
|
-
required:
|
|
23
|
-
- title
|
|
24
|
-
- description
|
|
25
|
-
- path
|
|
26
|
-
- sourceIds
|