svharness 0.8.0

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 (134) hide show
  1. package/README.md +531 -0
  2. package/bin/cli.js +3 -0
  3. package/dist/adapters/_frontmatter.js +24 -0
  4. package/dist/adapters/claude-code.js +12 -0
  5. package/dist/adapters/codechat.js +12 -0
  6. package/dist/adapters/cursor.js +19 -0
  7. package/dist/adapters/generic.js +19 -0
  8. package/dist/adapters/index.js +26 -0
  9. package/dist/adapters/qoder.js +12 -0
  10. package/dist/commands/apply.js +272 -0
  11. package/dist/commands/init.js +420 -0
  12. package/dist/core/agent-injector.js +192 -0
  13. package/dist/core/next-steps.js +91 -0
  14. package/dist/core/render-meta.js +81 -0
  15. package/dist/core/repomix-pack.js +54 -0
  16. package/dist/core/scaffold.js +93 -0
  17. package/dist/core/state.js +80 -0
  18. package/dist/index.js +239 -0
  19. package/dist/types.js +5 -0
  20. package/dist/utils/baseline-copy.js +591 -0
  21. package/dist/utils/baseline-defaults.js +106 -0
  22. package/dist/utils/logger.js +56 -0
  23. package/dist/utils/validate-args.js +132 -0
  24. package/dist/utils/version.js +23 -0
  25. package/dist/wiki/abort.js +30 -0
  26. package/dist/wiki/config.js +79 -0
  27. package/dist/wiki/defaults.js +16 -0
  28. package/dist/wiki/envLoader.js +78 -0
  29. package/dist/wiki/index.js +29 -0
  30. package/dist/wiki/openaiCompat.js +219 -0
  31. package/dist/wiki/repowikiCanonicalSections.js +67 -0
  32. package/dist/wiki/repowikiCheckpoint.js +106 -0
  33. package/dist/wiki/repowikiConfig.js +9 -0
  34. package/dist/wiki/repowikiGit.js +73 -0
  35. package/dist/wiki/repowikiIndexer.js +824 -0
  36. package/dist/wiki/repowikiMarkdownPost.js +123 -0
  37. package/dist/wiki/repowikiMetadataContent.js +64 -0
  38. package/dist/wiki/repowikiMetadataJson.js +15 -0
  39. package/dist/wiki/repowikiScanner.js +156 -0
  40. package/dist/wiki/repowikiStructureNav.js +286 -0
  41. package/dist/wiki/repowikiStructureNormalize.js +218 -0
  42. package/dist/wiki/wikiStructureXml.js +316 -0
  43. package/dist/wiki/wikiTasksWriter.js +127 -0
  44. package/package.json +57 -0
  45. package/templates/_shared/apply-skills/harness-apply-skills-main.md +91 -0
  46. package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +35 -0
  47. package/templates/_shared/build-rules/harness-build-rule-chinese-only.md +49 -0
  48. package/templates/_shared/build-rules/harness-build-rule-memory-write.md +31 -0
  49. package/templates/_shared/build-rules/harness-build-rule-orchestrator-flow.md +25 -0
  50. package/templates/_shared/build-rules/harness-build-rule-skills-tasks-output.md +35 -0
  51. package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +32 -0
  52. package/templates/_shared/build-rules/harness-build-rule-user-interaction.md +63 -0
  53. package/templates/_shared/build-skills/harness-build-skill-knowledge-builder.md +120 -0
  54. package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +87 -0
  55. package/templates/_shared/build-skills/harness-build-skill-spec-builder.md +85 -0
  56. package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +77 -0
  57. package/templates/_shared/meta/AGENTS.md.ejs +53 -0
  58. package/templates/_shared/meta/CHANGELOG.md.ejs +15 -0
  59. package/templates/_shared/meta/README.md.ejs +51 -0
  60. package/templates/_shared/meta/VERSION.ejs +1 -0
  61. package/templates/_shared/meta/harness.yaml.ejs +52 -0
  62. package/templates/_shared/skeleton/agent-env/memory/categories/.gitkeep +1 -0
  63. package/templates/_shared/skeleton/agent-env/memory/inbox/.gitkeep +1 -0
  64. package/templates/_shared/skeleton/agent-env/skills/.gitkeep +1 -0
  65. package/templates/_shared/skeleton/agent-env/tools/.gitkeep +1 -0
  66. package/templates/_shared/skeleton/assets/baseline/code/.gitkeep +1 -0
  67. package/templates/_shared/skeleton/assets/baseline/repomix/.gitkeep +1 -0
  68. package/templates/_shared/skeleton/assets/baseline/wiki/.gitkeep +1 -0
  69. package/templates/_shared/skeleton/assets/raw/.gitkeep +1 -0
  70. package/templates/_shared/skeleton/assets/requirements/.gitkeep +1 -0
  71. package/templates/_shared/skeleton/commands/install/.gitkeep +1 -0
  72. package/templates/_shared/skeleton/commands/update/.gitkeep +1 -0
  73. package/templates/_shared/skeleton/specs/behavior/schema.json +39 -0
  74. package/templates/_shared/skeleton/specs/interfaces/schema.json +38 -0
  75. package/templates/_shared/skeleton/specs/signals/schema.json +37 -0
  76. package/templates/_shared/skeleton/specs/ui/schema.json +44 -0
  77. package/templates/_shared/skeleton/tasks/templates/.gitkeep +0 -0
  78. package/templates/android-compose/skeleton/agent-env/rules/harness-compose-mandatory.mdc +49 -0
  79. package/templates/android-compose/skeleton/agent-env/rules/harness-coroutines-scope.mdc +52 -0
  80. package/templates/android-compose/skeleton/agent-env/rules/harness-hilt-injection.mdc +47 -0
  81. package/templates/android-compose/skeleton/agent-env/rules/harness-mvi-layering.mdc +58 -0
  82. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/SKILL.md +260 -0
  83. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/gradle-module-patterns.md +66 -0
  84. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/implementation-checklist.md +45 -0
  85. package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/udf-data-flow.md +80 -0
  86. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/SKILL.md +79 -0
  87. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/interact.md +83 -0
  88. package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/journeys.md +97 -0
  89. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/SKILL.md +162 -0
  90. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/canonical-sources.md +116 -0
  91. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/diagnostics.md +182 -0
  92. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/report-template.md +135 -0
  93. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/scoring.md +277 -0
  94. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/search-playbook.md +303 -0
  95. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/scripts/compose-reports.init.gradle +58 -0
  96. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-state/SKILL.md +196 -0
  97. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/SKILL.md +192 -0
  98. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/composable-api-guide.md +123 -0
  99. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/performance-recipes.md +97 -0
  100. package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/state-patterns.md +93 -0
  101. package/templates/android-compose/skeleton/agent-env/skills/harness-kotlin-coroutines/SKILL.md +167 -0
  102. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/SKILL.md +45 -0
  103. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/CONFIGURATION.md +44 -0
  104. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
  105. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
  106. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
  107. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +176 -0
  108. package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
  109. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/SKILL.md +87 -0
  110. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/analysis-of-the-project-and-layout.md +42 -0
  111. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +168 -0
  112. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +183 -0
  113. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/identify-optimal-xml-candidate.md +31 -0
  114. package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/xml-layout-migration.md +86 -0
  115. package/templates/android-xml/skeleton/agent-env/rules/seed-aidl-thread.md +29 -0
  116. package/templates/android-xml/skeleton/agent-env/rules/seed-lifecycle-awareness.md +32 -0
  117. package/templates/android-xml/skeleton/agent-env/rules/seed-mvc-layering.md +32 -0
  118. package/templates/android-xml/skeleton/agent-env/rules/seed-view-binding.md +33 -0
  119. package/templates/android-xml/skeleton/agent-env/rules/seed-xml-styling.md +27 -0
  120. package/templates/cpp/skeleton/agent-env/rules/seed-cmake-explicit-sources.md +31 -0
  121. package/templates/cpp/skeleton/agent-env/rules/seed-header-guards.md +34 -0
  122. package/templates/cpp/skeleton/agent-env/rules/seed-include-layering.md +39 -0
  123. package/templates/cpp/skeleton/agent-env/rules/seed-no-cyclic-deps.md +29 -0
  124. package/templates/cpp/skeleton/agent-env/rules/seed-raii.md +30 -0
  125. package/templates/python/skeleton/agent-env/rules/seed-context-managers.md +60 -0
  126. package/templates/python/skeleton/agent-env/rules/seed-docstrings.md +48 -0
  127. package/templates/python/skeleton/agent-env/rules/seed-import-order.md +49 -0
  128. package/templates/python/skeleton/agent-env/rules/seed-pep8-naming.md +45 -0
  129. package/templates/python/skeleton/agent-env/rules/seed-type-annotations.md +43 -0
  130. package/templates/web-react/skeleton/agent-env/rules/seed-controlled-component.md +43 -0
  131. package/templates/web-react/skeleton/agent-env/rules/seed-effect-cleanup.md +43 -0
  132. package/templates/web-react/skeleton/agent-env/rules/seed-hook-rules.md +42 -0
  133. package/templates/web-react/skeleton/agent-env/rules/seed-key-stability.md +39 -0
  134. package/templates/web-react/skeleton/agent-env/rules/seed-no-props-drilling.md +43 -0
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.markdownRelLinkToRepoFile = markdownRelLinkToRepoFile;
37
+ exports.splitSourcePathAndLineRef = splitSourcePathAndLineRef;
38
+ exports.markdownLineFragmentFromSuffix = markdownLineFragmentFromSuffix;
39
+ exports.linkifySourcesLinesInMarkdown = linkifySourcesLinesInMarkdown;
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * POSIX-style relative `href` from a generated wiki `.md` file to a repo file.
43
+ * Markdown viewers (VS Code preview, GitHub, mkdocs) resolve these against the
44
+ * source `.md` URI; append `markdownLineFragmentFromSuffix` so clicks jump to a line range.
45
+ */
46
+ function markdownRelLinkToRepoFile(mdAbsPath, repoRootFs, fileRelPosix) {
47
+ const norm = fileRelPosix.replace(/\\/g, "/").replace(/^\.\//, "").trim();
48
+ if (!norm)
49
+ return "";
50
+ const targetAbs = path.resolve(repoRootFs, norm);
51
+ const fromDir = path.dirname(mdAbsPath);
52
+ let rel = path.relative(fromDir, targetAbs);
53
+ rel = rel.split(/[/\\]/g).join("/");
54
+ return rel;
55
+ }
56
+ /** `path:line`, `path:10-20` — uses last `:` when the tail is numeric. */
57
+ function splitSourcePathAndLineRef(token) {
58
+ const t = token.trim().replace(/^`([^`]+)`$/, "$1").trim();
59
+ if (!t)
60
+ return { filePath: "", lineSuffix: "" };
61
+ const lastColon = t.lastIndexOf(":");
62
+ if (lastColon <= 0)
63
+ return { filePath: t, lineSuffix: "" };
64
+ const tail = t.slice(lastColon + 1);
65
+ if (/^\d+(?:-\d+)?$/.test(tail)) {
66
+ return { filePath: t.slice(0, lastColon), lineSuffix: `:${tail}` };
67
+ }
68
+ return { filePath: t, lineSuffix: "" };
69
+ }
70
+ /**
71
+ * `#L<n>` / `#L<a>-L<b>` line-range fragment. GitHub, GitLab and the VS Code
72
+ * built-in Markdown preview all honour this format.
73
+ */
74
+ function markdownLineFragmentFromSuffix(lineSuffix) {
75
+ if (!lineSuffix.startsWith(":"))
76
+ return "";
77
+ const inner = lineSuffix.slice(1).trim();
78
+ const range = /^(\d+)-(\d+)$/.exec(inner);
79
+ if (range) {
80
+ const a = range[1];
81
+ const b = range[2];
82
+ return `#L${a}-L${b}`;
83
+ }
84
+ const one = /^(\d+)$/.exec(inner);
85
+ return one ? `#L${one[1]}` : "";
86
+ }
87
+ /**
88
+ * Turns `Sources: a/b.kt:1-2, README.md` into markdown links with paths relative to the wiki page file.
89
+ */
90
+ function linkifySourcesLinesInMarkdown(md, mdAbsPath, repoRootFs) {
91
+ const lines = md.split(/\r?\n/);
92
+ /** Optional list marker; `Sources:`, `**Sources:**`, or closing-bold-before-colon `**Sources**:`. */
93
+ const lineRe = /^(\s*(?:[-*]\s+)?(?:\*\*Sources:\*\*|\*\*Sources\*\*:|Sources:)\s*)(.+)$/i;
94
+ const out = lines.map((line) => {
95
+ const m = line.match(lineRe);
96
+ if (!m)
97
+ return line;
98
+ const prefix = m[1];
99
+ const rest = m[2];
100
+ const parts = rest
101
+ .split(",")
102
+ .map((p) => p.trim())
103
+ .filter(Boolean);
104
+ const linked = parts
105
+ .map((part) => {
106
+ const { filePath, lineSuffix } = splitSourcePathAndLineRef(part);
107
+ if (!filePath)
108
+ return part;
109
+ let href = markdownRelLinkToRepoFile(mdAbsPath, repoRootFs, filePath);
110
+ if (!href)
111
+ return part;
112
+ const frag = markdownLineFragmentFromSuffix(lineSuffix);
113
+ if (frag)
114
+ href = `${href}${frag}`;
115
+ const base = path.posix.basename(filePath.replace(/\\/g, "/"));
116
+ const label = `${base}${lineSuffix}`;
117
+ return `[${label}](${href})`;
118
+ })
119
+ .join(", ");
120
+ return `${prefix}${linked}`;
121
+ });
122
+ return out.join("\n");
123
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.utf8TextToContentBase64 = utf8TextToContentBase64;
37
+ exports.collectContentBase64ByLang = collectContentBase64ByLang;
38
+ const fs = __importStar(require("fs/promises"));
39
+ const path = __importStar(require("path"));
40
+ /** Standard base64 of UTF-8 bytes (portable embedding of Markdown in JSON). */
41
+ function utf8TextToContentBase64(text) {
42
+ return Buffer.from(text, "utf8").toString("base64");
43
+ }
44
+ /**
45
+ * For each language folder, read generated Markdown at `wikiBase/<lang>/<rel>` and
46
+ * return page-id → base64 maps (same page ids as `metadata.files`).
47
+ */
48
+ async function collectContentBase64ByLang(options) {
49
+ const out = {};
50
+ for (const folder of options.langFolders) {
51
+ const byPage = {};
52
+ for (const pageId of options.pageIds) {
53
+ const rel = options.filesRelByPageId.get(pageId);
54
+ if (!rel) {
55
+ throw new Error(`[repowiki] Missing file mapping for page ${pageId}`);
56
+ }
57
+ const abs = path.join(options.wikiBase, folder, ...rel.split("/").filter(Boolean));
58
+ const text = await fs.readFile(abs, "utf8");
59
+ byPage[pageId] = utf8TextToContentBase64(text);
60
+ }
61
+ out[folder] = byPage;
62
+ }
63
+ return out;
64
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REPOWIKI_METADATA_SCHEMA_VERSION = exports.REPOWIKI_METADATA_SCHEMA_ID = void 0;
4
+ /**
5
+ * Shape of `<wikiRoot>/metadata.json` produced by `runRepowikiIndex`.
6
+ *
7
+ * `version` and `metadataSchemaVersion` are the same integer; bump both only on
8
+ * incompatible JSON changes. Markdown bodies appear only under `contentBase64ByLang`
9
+ * (standard base64 of UTF‑8) when embedding is enabled — there is no parallel plain-text
10
+ * `content` field to avoid duplicating large strings. Paths in `files` are relative to
11
+ * each folder named in `langFolders` (on disk: `<wikiBaseFs>/<lang>/<files[id]>`).
12
+ */
13
+ exports.REPOWIKI_METADATA_SCHEMA_ID = "deepwiki-open.repowiki";
14
+ /** Bumped with breaking changes to this file’s top-level keys or semantics. */
15
+ exports.REPOWIKI_METADATA_SCHEMA_VERSION = 2;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.readTextFileBounded = readTextFileBounded;
37
+ exports.collectRepoFileList = collectRepoFileList;
38
+ exports.tryReadFirstReadme = tryReadFirstReadme;
39
+ exports.bundleSourceContext = bundleSourceContext;
40
+ exports.summarizeTreeLines = summarizeTreeLines;
41
+ const fs = __importStar(require("fs/promises"));
42
+ const path = __importStar(require("path"));
43
+ const SKIP_DIR_NAMES = new Set([
44
+ ".git",
45
+ "node_modules",
46
+ ".venv",
47
+ ".venv-smoke",
48
+ "__pycache__",
49
+ "dist",
50
+ "out",
51
+ "build",
52
+ ".next",
53
+ "coverage",
54
+ ".turbo",
55
+ ".cache",
56
+ "target",
57
+ ".idea",
58
+ ]);
59
+ const SKIP_EXTENSIONS = new Set([
60
+ ".png",
61
+ ".jpg",
62
+ ".jpeg",
63
+ ".gif",
64
+ ".webp",
65
+ ".ico",
66
+ ".pdf",
67
+ ".zip",
68
+ ".tar",
69
+ ".gz",
70
+ ".7z",
71
+ ".woff",
72
+ ".woff2",
73
+ ".ttf",
74
+ ".eot",
75
+ ".mp4",
76
+ ".mp3",
77
+ ".wav",
78
+ ]);
79
+ const TEXT_MAX_FILE = 80_000;
80
+ const LIST_FILES_MAX_PARTS = 220;
81
+ async function readTextFileBounded(absPath, maxBytes = TEXT_MAX_FILE) {
82
+ try {
83
+ const buf = await fs.readFile(absPath);
84
+ if (buf.length > maxBytes) {
85
+ const slice = buf.subarray(0, maxBytes).toString("utf8");
86
+ return `${slice}\n\n…truncated (${buf.length} bytes total)`;
87
+ }
88
+ return buf.toString("utf8");
89
+ }
90
+ catch {
91
+ return undefined;
92
+ }
93
+ }
94
+ async function walkRelFiles(rootFs, relParts, sink) {
95
+ if (sink.length >= LIST_FILES_MAX_PARTS)
96
+ return;
97
+ const dirAbs = path.join(rootFs, ...relParts);
98
+ let entries;
99
+ try {
100
+ entries = await fs.readdir(dirAbs, { withFileTypes: true });
101
+ }
102
+ catch {
103
+ return;
104
+ }
105
+ for (const ent of entries) {
106
+ if (sink.length >= LIST_FILES_MAX_PARTS)
107
+ break;
108
+ if (SKIP_DIR_NAMES.has(ent.name))
109
+ continue;
110
+ if (ent.name.startsWith(".") && ent.name !== ".github")
111
+ continue;
112
+ const rel = [...relParts, ent.name];
113
+ if (ent.isDirectory()) {
114
+ await walkRelFiles(rootFs, rel, sink);
115
+ continue;
116
+ }
117
+ const ext = path.extname(ent.name).toLowerCase();
118
+ if (SKIP_EXTENSIONS.has(ext))
119
+ continue;
120
+ sink.push(rel.join("/"));
121
+ }
122
+ }
123
+ /** Flat list of relative paths for LLM prompt (POSIX-ish slashes). */
124
+ async function collectRepoFileList(repoRootFs) {
125
+ const acc = [];
126
+ await walkRelFiles(repoRootFs, [], acc);
127
+ return acc;
128
+ }
129
+ async function tryReadFirstReadme(repoRootFs) {
130
+ const names = ["README.md", "README.MD", "readme.md", "Readme.md", "README.rst"];
131
+ for (const n of names) {
132
+ const t = await readTextFileBounded(path.join(repoRootFs, n), 120_000);
133
+ if (t?.trim())
134
+ return t;
135
+ }
136
+ return "";
137
+ }
138
+ async function bundleSourceContext(repoRootFs, relativePaths, perFileBudget) {
139
+ const uniq = [...new Set(relativePaths)].slice(0, 16);
140
+ const chunks = [];
141
+ for (const rp of uniq) {
142
+ const safe = rp.replace(/^[/\\]+/, "");
143
+ const abs = path.join(repoRootFs, safe);
144
+ if (!abs.startsWith(path.resolve(repoRootFs)))
145
+ continue;
146
+ const body = await readTextFileBounded(abs, perFileBudget);
147
+ if (!body?.trim())
148
+ continue;
149
+ chunks.push(`<file path="${safe.replace(/"/g, "")}">\n${body}\n</file>`);
150
+ }
151
+ return chunks.join("\n\n");
152
+ }
153
+ function summarizeTreeLines(paths, maxLines = 200) {
154
+ const sorted = [...paths].sort();
155
+ return sorted.slice(0, maxLines).join("\n");
156
+ }
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.extractWikiOutlineTitle = extractWikiOutlineTitle;
37
+ exports.parseSectionGroups = parseSectionGroups;
38
+ exports.loadWikiNavigationFromMarkdownDir = loadWikiNavigationFromMarkdownDir;
39
+ exports.loadWikiNavigationFromDiskOnly = loadWikiNavigationFromDiskOnly;
40
+ exports.loadWikiNavigation = loadWikiNavigation;
41
+ const fsp = __importStar(require("fs/promises"));
42
+ const path = __importStar(require("path"));
43
+ const wikiStructureXml_1 = require("./wikiStructureXml");
44
+ const repowikiConfig_1 = require("./repowikiConfig");
45
+ function stripTags(s) {
46
+ return s.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
47
+ }
48
+ function xmlPlainText(s) {
49
+ return (0, wikiStructureXml_1.decodeXmlEntities)(stripTags(s));
50
+ }
51
+ /** First `<title>` after xml start — outline title. */
52
+ function extractWikiOutlineTitle(xml) {
53
+ const inner = xml.replace(/^\uFEFF/, "");
54
+ const m = inner.match(/<title>([\s\S]*?)<\/title>/i);
55
+ return m ? xmlPlainText(m[1]).slice(0, 200) : "";
56
+ }
57
+ function parseSectionBlocksFromInner(inner) {
58
+ const blocks = [];
59
+ let pos = 0;
60
+ while (pos < inner.length) {
61
+ const m = inner.slice(pos).match(/<section\b([^>]*)>/i);
62
+ if (!m || m.index === undefined)
63
+ break;
64
+ const absStart = pos + m.index;
65
+ const attrs = m[1] ?? "";
66
+ const openTagLen = m[0].length;
67
+ const contentStart = absStart + openTagLen;
68
+ let idx = contentStart;
69
+ let depth = 1;
70
+ while (idx < inner.length && depth > 0) {
71
+ const tail = inner.slice(idx);
72
+ const mo = tail.match(/<section\b[^>]*>/i);
73
+ const mc = tail.match(/<\/section>/i);
74
+ const io = mo?.index ?? -1;
75
+ const ic = mc?.index ?? -1;
76
+ if (ic === -1) {
77
+ blocks.push({ attr: attrs, body: inner.slice(contentStart) });
78
+ return blocks;
79
+ }
80
+ if (io !== -1 && io < ic) {
81
+ depth++;
82
+ idx += io + mo[0].length;
83
+ }
84
+ else {
85
+ depth--;
86
+ if (depth === 0) {
87
+ blocks.push({ attr: attrs, body: inner.slice(contentStart, idx + ic) });
88
+ pos = idx + ic + mc[0].length;
89
+ break;
90
+ }
91
+ idx += ic + mc[0].length;
92
+ }
93
+ }
94
+ if (depth > 0) {
95
+ return blocks;
96
+ }
97
+ }
98
+ return blocks;
99
+ }
100
+ function parseSectionGroups(structureXml) {
101
+ const body = structureXml.replace(/^\uFEFF/, "");
102
+ const inner = (0, wikiStructureXml_1.extractSectionsInnerXml)(body);
103
+ if (!inner.trim())
104
+ return [];
105
+ const out = [];
106
+ const blocks = parseSectionBlocksFromInner(inner);
107
+ for (let i = 0; i < blocks.length; i++) {
108
+ const { attr, body: block } = blocks[i];
109
+ const idM = attr.match(/\bid\s*=\s*"([^"]*)"/i);
110
+ const sid = (0, wikiStructureXml_1.sanitizeWikiOutlineId)(idM?.[1]?.trim() || `section-${out.length}`);
111
+ const titleM = block.match(/<title>([\s\S]*?)<\/title>/i);
112
+ const title = titleM ? xmlPlainText(titleM[1]) : sid;
113
+ const pageIds = [];
114
+ const refRe = /<page_ref>([\s\S]*?)<\/page_ref>/gi;
115
+ let rm;
116
+ while ((rm = refRe.exec(block)) !== null) {
117
+ const pid = (0, wikiStructureXml_1.sanitizeWikiOutlineId)(xmlPlainText(rm[1]));
118
+ if (pid)
119
+ pageIds.push(pid);
120
+ }
121
+ out.push({ id: sid, title, pageIds });
122
+ }
123
+ return out;
124
+ }
125
+ async function safeReadUtf8(abs) {
126
+ try {
127
+ return await fsp.readFile(abs, "utf8");
128
+ }
129
+ catch {
130
+ return "";
131
+ }
132
+ }
133
+ function humanizeMdFilenameStem(stem) {
134
+ const s = stem.replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
135
+ return s || stem;
136
+ }
137
+ async function collectMarkdownFilesRecursive(dirAbs) {
138
+ const out = [];
139
+ let ents;
140
+ try {
141
+ ents = await fsp.readdir(dirAbs, { withFileTypes: true });
142
+ }
143
+ catch {
144
+ return out;
145
+ }
146
+ for (const e of ents) {
147
+ const name = e.name;
148
+ const abs = path.join(dirAbs, name);
149
+ if (e.isDirectory()) {
150
+ out.push(...(await collectMarkdownFilesRecursive(abs)));
151
+ }
152
+ else if (e.isFile() && name.toLowerCase().endsWith(".md")) {
153
+ out.push(abs);
154
+ }
155
+ }
156
+ return out;
157
+ }
158
+ function relPosixFromLangDir(langDirAbs, fileAbs) {
159
+ return path.relative(langDirAbs, fileAbs).replace(/\\/g, "/");
160
+ }
161
+ async function loadWikiNavigationFromMarkdownDir(langDirAbs, wikiTitle) {
162
+ const absPaths = await collectMarkdownFilesRecursive(langDirAbs);
163
+ const files = absPaths.map((abs) => ({
164
+ abs,
165
+ relPosix: relPosixFromLangDir(langDirAbs, abs),
166
+ }));
167
+ if (!files.length) {
168
+ return { wikiTitle, groups: [] };
169
+ }
170
+ files.sort((a, b) => a.relPosix.localeCompare(b.relPosix));
171
+ const rootMd = files.filter((f) => !f.relPosix.includes("/"));
172
+ const nestedMd = files.filter((f) => f.relPosix.includes("/"));
173
+ if (rootMd.length === files.length) {
174
+ const leaves = rootMd.map((f) => {
175
+ const stem = f.relPosix.slice(0, -3);
176
+ return {
177
+ pageId: stem,
178
+ title: humanizeMdFilenameStem(stem),
179
+ absPath: f.abs,
180
+ };
181
+ });
182
+ return { wikiTitle, groups: [{ id: "root", title: "文档", pages: leaves }] };
183
+ }
184
+ const navGroups = [];
185
+ if (rootMd.length) {
186
+ const leaves = rootMd.map((f) => {
187
+ const stem = f.relPosix.slice(0, -3);
188
+ return {
189
+ pageId: stem,
190
+ title: humanizeMdFilenameStem(stem),
191
+ absPath: f.abs,
192
+ };
193
+ });
194
+ navGroups.push({ id: "root", title: "文档", pages: leaves });
195
+ }
196
+ const byFirst = new Map();
197
+ for (const f of nestedMd) {
198
+ const first = f.relPosix.split("/")[0];
199
+ const arr = byFirst.get(first) ?? [];
200
+ arr.push(f);
201
+ byFirst.set(first, arr);
202
+ }
203
+ for (const [first, groupFiles] of [...byFirst.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
204
+ const leaves = groupFiles.map((f) => {
205
+ const rest = f.relPosix.slice(first.length + 1);
206
+ const stemNoMd = rest.endsWith(".md") ? rest.slice(0, -3) : rest;
207
+ const pageId = f.relPosix.replace(/\.md$/i, "").replace(/\//g, "__");
208
+ return {
209
+ pageId,
210
+ title: humanizeMdFilenameStem(stemNoMd) || humanizeMdFilenameStem(first),
211
+ absPath: f.abs,
212
+ };
213
+ });
214
+ leaves.sort((a, b) => a.title.localeCompare(b.title));
215
+ navGroups.push({
216
+ id: `dir-${first}`,
217
+ title: humanizeMdFilenameStem(first) || first,
218
+ pages: leaves,
219
+ });
220
+ }
221
+ return { wikiTitle, groups: navGroups };
222
+ }
223
+ async function loadWikiNavigationFromDiskOnly(wikiRootAbs, langFolder) {
224
+ const structureRaw = await safeReadUtf8(path.join(wikiRootAbs, "structure.xml"));
225
+ const wikiTitle = extractWikiOutlineTitle(structureRaw) || "Repo Wiki";
226
+ const langDir = path.join(wikiRootAbs, langFolder);
227
+ return loadWikiNavigationFromMarkdownDir(langDir, wikiTitle);
228
+ }
229
+ async function loadWikiNavigation(wikiRootAbs, langFolder) {
230
+ const structureRaw = await safeReadUtf8(path.join(wikiRootAbs, "structure.xml"));
231
+ const langDir = path.join(wikiRootAbs, langFolder);
232
+ const meta = await (0, repowikiConfig_1.loadRepowikiMetadata)(wikiRootAbs);
233
+ const pageFiles = meta?.files;
234
+ let wikiTitle = extractWikiOutlineTitle(structureRaw) || "Repo Wiki";
235
+ const pages = (0, wikiStructureXml_1.parseWikiPages)(structureRaw);
236
+ if (!structureRaw.trim() || pages.length === 0) {
237
+ return loadWikiNavigationFromMarkdownDir(langDir, wikiTitle);
238
+ }
239
+ const pmap = new Map(pages.map((p) => [p.id, p]));
240
+ const buildLeaf = (pid) => {
241
+ const p = pmap.get(pid);
242
+ if (!p)
243
+ return undefined;
244
+ const rel = pageFiles?.[pid] ?? `${(0, wikiStructureXml_1.slugifyFileStem)(p.id)}.md`;
245
+ const relNorm = rel.replace(/\\/g, "/");
246
+ const segments = relNorm.split("/").filter(Boolean);
247
+ return {
248
+ pageId: p.id,
249
+ title: p.title || p.id,
250
+ absPath: path.join(langDir, ...segments),
251
+ };
252
+ };
253
+ const sectionGroups = parseSectionGroups(structureRaw);
254
+ if (sectionGroups.length === 0) {
255
+ const leaves = pages.map((pg) => buildLeaf(pg.id)).filter(Boolean);
256
+ return { wikiTitle, groups: [{ id: "root", title: "文档", pages: leaves }] };
257
+ }
258
+ const used = new Set();
259
+ const navGroups = [];
260
+ for (const g of sectionGroups) {
261
+ const leaves = [];
262
+ for (const pid of g.pageIds) {
263
+ const leaf = buildLeaf(pid);
264
+ if (leaf) {
265
+ leaves.push(leaf);
266
+ used.add(pid);
267
+ }
268
+ }
269
+ if (leaves.length) {
270
+ navGroups.push({ id: g.id, title: g.title, pages: leaves });
271
+ }
272
+ }
273
+ const orphans = pages.filter((p) => !used.has(p.id));
274
+ if (orphans.length > 0) {
275
+ navGroups.push({
276
+ id: "other",
277
+ title: "其他",
278
+ pages: orphans.map((pg) => buildLeaf(pg.id)).filter(Boolean),
279
+ });
280
+ }
281
+ if (navGroups.length === 0 && pages.length > 0) {
282
+ const leaves = pages.map((pg) => buildLeaf(pg.id)).filter(Boolean);
283
+ return { wikiTitle, groups: [{ id: "root", title: "文档", pages: leaves }] };
284
+ }
285
+ return { wikiTitle, groups: navGroups };
286
+ }